cv2.VideoCapture(0) not working inside Docker on macOS (Apple Silicon / M1), but works locally

muktadirdocker
Sat, 03 May 2025 16:25:31 +0000
General

Hi all,

I’m currently working on a Python application using OpenCV (cv2) on macOS (Apple Silicon M1). The app captures video from the default webcam using:

import cv2

cap = cv2.VideoCapture(0)

if not cap.isOpened():
    print("Cannot open camera")
    exit()

Here is my docker build file

FROM --platform=amd64 python:3.12-slim-bullseye

RUN apt-get update && apt-get install -y --no-install-recommends \
	libgl1 \
	libglib2.0-0 \
	v4l-utils \
	libv4l-dev \
	libgl1-mesa-glx \
	&& rm -rf /var/lib/apt/lists/*

COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv

WORKDIR /app

COPY . /app

RUN uv sync --frozen --no-cache

EXPOSE 9000

CMD ["/app/.venv/bin/fastapi", "run", "app/main.py", "--port", "9000"]

Here is my docker compose file:

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    image: muktadirdocker/klassy-python-backend:latest
    container_name: klassy-python-container
    ports:
      - "9000:9000"
    devices:
      - "/dev/video0:/dev/video0"
    group_add:
      - "video"
    volumes:
      - "/dev:/dev:ro"
    privileged: true
    restart: unless-stopped

Here is my Docker container logs:

Searching for package file structure from directories with


__init__.py files


Importing from /app




module 📁 app


├── 🐍 __init__.py


└── 🐍 main.py




code Importing the FastAPI app object from the module with the following


code:




from app.main import app




app Using import string: app.main:app




server Server started at http://0.0.0.0:9000⁠


server Documentation at http://0.0.0.0:9000/docs⁠




Logs:




INFO: Created TensorFlow Lite XNNPACK delegate for CPU.


WARNING: All log messages before absl::InitializeLog() is called are written to STDERR


W0000 00:00:1746288955.743384 30 inference_feedback_manager.cc:114] Feedback manager requires a model with a single signature inference. Disabling support for feedback tensors.


INFO Started server process [1]


INFO Waiting for application startup.


INFO Application startup complete.


INFO Uvicorn running on http://0.0.0.0:9000⁠ (Press CTRL+C to quit)


W0000 00:00:1746288955.825012 30 inference_feedback_manager.cc:114] Feedback manager requires a model with a single signature inference. Disabling support for feedback tensors.


INFO 192.168.65.1:58227 - "GET /api/lipcolor/stream HTTP/1.1" 200


[ WARN:0@6.414] global cap_v4l.cpp:913 open VIDEOIO(V4L2:/dev/video0): can't open camera by index


[ERROR:0@6.416] global obsensor_uvc_stream_channel.cpp:158 getStreamChannelGroup Camera index out of range


Error: Could not open camera.

What I’ve tried:

Adding --device=/dev/video0:/dev/video0 to docker run — doesn’t work on macOS since Docker Desktop uses a Linux VM and doesn’t expose macOS hardware devices like /dev/video0.

Tried privileged mode, mounting /dev, etc. — again, no luck (since the container doesn’t actually run natively on macOS).

I understand this would work on a native Linux system, where /dev/video0 is available and can be passed into the container.

7 posts - 4 participants