hacksider/Deep-Live-Cam · critical · RuntimeError

Failed to open camera

Error message

Failed to open camera

What it means

RuntimeError raised in VideoCapture.start (modules/video_capture.py) when every backend attempt fails to open the device: on Windows each (device id, backend, params) combination threw or failed isOpened; on Linux cv2.VideoCapture('/dev/video<N>') failed; on other platforms the default-open failed. It means OpenCV could not obtain a capture handle at all — the device is busy, absent, permission-denied, or not supported by the backend used.

Source

Thrown at modules/video_capture.py:80

                    (self.device_index, cv2.CAP_MSMF),
                    (self.device_index, cv2.CAP_ANY),
                ]

                for dev_id, backend in capture_methods:
                    try:
                        self.cap = cv2.VideoCapture(dev_id, backend, open_params)
                        if self.cap.isOpened():
                            break
                        self.cap.release()
                    except Exception:
                        continue
            elif platform.system() == "Linux":
                self.cap = cv2.VideoCapture(f"/dev/video{self.device_index}")
            else:
                self.cap = cv2.VideoCapture(self.device_index)

            if not self.cap or not self.cap.isOpened():
                raise RuntimeError("Failed to open camera")

            # Belt-and-braces: also set via cap.set() for backends that honor
            # post-open changes (MSMF, V4L2). DSHOW ignores these, but the
            # construction params above already handled it.
            if platform.system() != "Windows":
                self.cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*'MJPG'))
                self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
                self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
                self.cap.set(cv2.CAP_PROP_FPS, fps)

            # Read back resolution (usually reliable)
            self.actual_width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            self.actual_height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

            # CAP_PROP_FPS is unreliable on DirectShow — often reports 30
            # even when the camera delivers 60.  Measure empirically by
            # timing a burst of frames.
            reported_fps = self.cap.get(cv2.CAP_PROP_FPS)

View on GitHub (pinned to 987f6b392b)

Solutions

  1. Confirm nothing else holds the camera (close other conferencing/recording apps; kill stale processes) and retry.
  2. On Linux: check the node exists and you have access — ls -l /dev/video*, add user to the video group (sudo usermod -aG video $USER, re-login), and verify with v4l2-ctl --list-devices that you target a capture-capable node, not a metadata node.
  3. Verify the index/enumeration again right before start() (device may have disconnected after construction) and prefer selecting by device name.
  4. For packaging (Snap/Flatpak/Docker), grant camera device access or run outside the sandbox; in Docker map /dev/video* into the container.
  5. If all else fails, test the camera outside the app (e.g. cv2.VideoCapture(0) in a REPL, or cheese/guvcview) to isolate app vs system.

Example fix

# before
cap = VideoCapture(device_index=0)
if not cap.start():
    pass  # error swallowed, later frames fail confusingly

# after
cap = VideoCapture(device_index=0)
try:
    cap.start()
except RuntimeError as e:
    print(f"Camera unavailable: {e}; is another app using it?")
    # fall back to a file source or exit cleanly
Defensive patterns

Strategy: fallback

Validate before calling

# Linux: confirm the node exists, is capture-capable, and is readable/writable
import os, subprocess
node = f"/dev/video{device_index}"
if not os.path.exists(node):
    raise SystemExit(f"{node} does not exist; list nodes with: v4l2-ctl --list-devices")
if not os.access(node, os.R_OK | os.W_OK):
    raise SystemExit(f"No permission on {node}; add user to 'video' group and re-login")

Try / catch

try:
    cap.start()
except RuntimeError as e:
    if "Failed to open camera" in str(e):
        # device busy/absent: retry once after releasing, else fall back to file input
        cap = None
        source = fallback_video_path  # e.g. a recorded clip for testing
    else:
        raise

Prevention

When it happens

Trigger: Device already occupied by another process (Zoom/OBS/browser using the webcam, or a previous run that didn't release()); on Linux, /dev/videoN missing (wrong index — many cameras register multiple /dev/video nodes and only some capture), udev permission denied (user not in the video group), or the camera is a metadata-only node; on Windows, DSHOW/MSMF backend mismatch with the driver; headless machines with no camera at all; passing a device_index that passed construction-time checks but went invalid before start().

Common situations: Linux permission issues (no rw on /dev/video*); index confusion from multiple /dev/video nodes per UVC camera; another app holding the camera exclusively; camera suspended by USB autosuspend; Snap/Flatpak packaging lacking device access; CI/headless runs where /dev/video doesn't exist.

Related errors


AI-assisted analysis of hacksider/Deep-Live-Cam@987f6b392b (2026-08-14). Data as JSON: /api/errors/5da95bdffd605572. Report an issue: GitHub.