Can't open camera by index on LXC container

Hi, I am new to LXC/LXD containers and I can’t access the webcam.

I am running Ubuntu 18.04 on the host and Ubuntu 20.04 inside LXC container. My goal is to run ROS2 (which requires Ubuntu 20.04) inside an LXC container, then use it to connect to two dynamixel servo motors and a USB Logitech webcam. I have also installed miniconda inside the container so that I can install OpenCV and dlib. I am also using conda virtual environment inside the container.

All the mentioned software works fine. Now I need to access the webcam with OpenCV using a code I use everyday on my host machine, but inside the container I always get this error:

[ WARN:0] global ../modules/videoio/src/cap_v4l.cpp (893) open VIDEOIO(V4L2:/dev/video0): can't open camera by index
Traceback (most recent call last):
  File "gaze_example.py", line 17, in <module>
    gaze.refresh(frame)
  File "/home/ubuntu/dev_ws/src/py_pubsub/py_pubsub/gaze_tracking/gaze_tracking.py", line 63, in refresh
    self._analyze()
  File "/home/ubuntu/dev_ws/src/py_pubsub/py_pubsub/gaze_tracking/gaze_tracking.py", line 44, in _analyze
    frame = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY)
cv2.error: OpenCV(4.5.1) ../modules/imgproc/src/color.cpp:182: error: (-215:Assertion failed) !_src.empty() in function 'cvtColor'

I already tried lxc config device add rosfoxy video0 unix-char path=/dev/video0 with video0 , video1 and video2 and still getting the same error.

When this problem is fixed, I also would like to know how to access the servo motors USB interface from within the container.

Would you please advise what to do?

Thanks in advance.

Hi!

There are several ways to access resources from the host inside a container. These are listed at the Device types at https://linuxcontainers.org/lxd/docs/master/instances#device-types
The three main options are unix-char, unix-hotplug and usb.

When testing, you would need to find a simple utility or some way in general that can verify that the device is accessible. Try that on the host to verify it works, then try in the container. If it works in the container, try last in the Coda virtual environment.

In the example with OpenCV it is not clear whether the problem is with the software or with the device initialization.

Hi Simos, Thanks for your reply!

Your answer makes sense, here is what I did:

  1. Test cheese on host for testing webcam and it works just fine. Then installed cheese inside the container, but device not found

  2. Did lxc config device add rosfoxy logitech usb vendorid=046d productid=082b resulted in
    Device logitech added to rosfoxy. Then when testing cheese inside the container I still get Device not found with this error:

ubuntu@rosfoxy:~$ cheese

(cheese:1384): dbind-WARNING **: 16:58:12.570: Couldn't connect to accessibility bus: Failed to connect to socket /tmp/dbus-XODPuIJGfl: Connection refused
libGL error: MESA-LOADER: failed to retrieve device information
libGL error: Version 4 or later of flush extension not found
libGL error: failed to load driver: i915
libGL error: failed to open /dev/dri/card1: No such file or directory
libGL error: failed to load driver: i965
** Message: 16:58:13.109: cheese-application.vala:214: Error during camera setup: No device found


(cheese:1384): cheese-CRITICAL **: 16:58:13.119: cheese_camera_device_get_name: assertion 'CHEESE_IS_CAMERA_DEVICE (device)' failed

(cheese:1384): GLib-CRITICAL **: 16:58:13.119: g_variant_new_string: assertion 'string != NULL' failed

(cheese:1384): GLib-CRITICAL **: 16:58:13.119: g_variant_ref_sink: assertion 'value != NULL' failed

(cheese:1384): GLib-GIO-CRITICAL **: 16:58:13.119: g_settings_schema_key_type_check: assertion 'value != NULL' failed

(cheese:1384): GLib-CRITICAL **: 16:58:13.119: g_variant_get_type_string: assertion 'value != NULL' failed

(cheese:1384): GLib-GIO-CRITICAL **: 16:58:13.119: g_settings_set_value: key 'camera' in 'org.gnome.Cheese' expects type 's', but a GVariant of type '(null)' was given

(cheese:1384): GLib-CRITICAL **: 16:58:13.119: g_variant_unref: assertion 'value != NULL' failed

** (cheese:1384): CRITICAL **: 16:58:13.119: cheese_preferences_dialog_setup_resolutions_for_device: assertion 'device != NULL' failed
  1. I then tried lxc profile device add ros logitech usb vendorid=046d productid=082b which results in
    Device logitech added to ros. Then when testing cheese inside the container I still get Device not found.

Is there something I did wrong?
Thanks again.

This part is related to GL support in the container. You would first need to be able to run a simpler application, such as glxgears or glxinfo.

Having said that, the rest of the errors are with the camera device itself.
I have not tested these and I do not know what how best to resolve them.
Specifically, I am not sure which device files have to be made available in the container.
As a hint during research, you would try to web search for terms like use webcam in docker.
In addition, I would also try to use a plain UVC application, such as guvcview or uvccapture.

Thanks Simos for the insightful tips!

Just FYI here is what I have done so far:

  1. Tested glxgears on host, works fine with this output (glxinfo also works):
Running synchronized to the vertical refresh.  The framerate should be
approximately the same as the monitor refresh rate.
358 frames in 5.0 seconds = 71.595 FPS
302 frames in 5.0 seconds = 60.265 FPS
302 frames in 5.0 seconds = 60.257 FPS
302 frames in 5.0 seconds = 60.261 FPS
302 frames in 5.0 seconds = 60.265 FPS
302 frames in 5.0 seconds = 60.260 FPS
302 frames in 5.0 seconds = 60.260 FPS

  1. Tested glxgears on container, it works fine but with this output (glxinfo also works) :
libGL error: MESA-LOADER: failed to retrieve device information
libGL error: Version 4 or later of flush extension not found
libGL error: failed to load driver: i915
libGL error: failed to open /dev/dri/card0: No such file or directory
libGL error: failed to load driver: i965
3073 frames in 5.0 seconds = 614.256 FPS
5238 frames in 5.0 seconds = 1047.546 FPS
3766 frames in 5.0 seconds = 753.186 FPS
4214 frames in 5.0 seconds = 842.731 FPS
4926 frames in 5.0 seconds = 985.092 FPS
6007 frames in 5.0 seconds = 1201.399 FPS
5694 frames in 5.0 seconds = 1138.660 FPS
5347 frames in 5.0 seconds = 1069.249 FPS
5507 frames in 5.0 seconds = 1101.395 FPS
4921 frames in 5.0 seconds = 984.167 FPS
4795 frames in 5.0 seconds = 958.934 FPS
  1. Tested guvcview on host, works fine.
  2. Tested guvcview on container, doesn’t work, gives:
V4L2_CORE: ERROR opening V4L2 interface for /dev/video2
V4L2_CORE: ERROR opening V4L2 interface for /dev/video3
V4L2_CORE: ERROR opening V4L2 interface for /dev/video0
V4L2_CORE: ERROR opening V4L2 interface for /dev/video1
GUVCVIEW: version 2.0.6
GUVCVIEW: couldn't open /home/ubuntu//.config/guvcview2/video0 for read: No such file or directory
V4L2_CORE: ERROR opening V4L interface: Permission denied
GUVCVIEW (1): Guvcview error
	 no video device found

(guvcview:1526): dbind-WARNING **: 19:29:55.201: Couldn't connect to accessibility bus: Failed to connect to socket /tmp/dbus-EhmzLUeJ8h: Connection refused

(guvcview:1526): Gtk-WARNING **: 19:29:55.307: Theme parsing error: <data>:1:17: not a number

(guvcview:1526): Gtk-WARNING **: 19:29:55.307: Theme parsing error: <data>:1:31: Using Pango syntax for the font: style property is deprecated; please use CSS syntax

(guvcview:1526): Gtk-WARNING **: 19:29:55.307: Theme parsing error: <data>:1:17: not a number

(guvcview:1526): Gtk-WARNING **: 19:29:55.307: Theme parsing error: <data>:1:32: Using Pango syntax for the font: style property is deprecated; please use CSS syntax

Still looking into webcam in docker but with not much luck. Will post again if I figured out how to fix this issue.

I gave this a try, with a UVC device (V4L2-compatible).

I launched a GUI container. That got me GPU acceleration working, though this is not a requirement to get the camera working. I use lxc config device to add the camera. The container’s non-root account does not belong by default to the video group, therefore for me ease of use, I add the device to the ubuntu group in the container.

$ lxc launch ubuntu: mycontainer --profile default --profile x11  # my tutorial for GUI containers
$ lxc config device add mycontainer video0 unix-char path=/dev/video0 gid=1000
Device video0 added to mycontainer
$ lxc ubuntu mycontainer   # my 'lxc alias' to get a shell into an Ubuntu container as non-root.
ubuntu@mycontainer:~$ sudo apt install v4l2-utils
...
ubuntu@mycontainer:~$ v4l2-ctl --all
Driver Info:
	Driver name      : uvcvideo
...
ubuntu@mycontainer:~$ sudo apt install guvcview
...
ubuntu@mycontainer:~$ guvcview
...worked for me...

Thanks Simos for trying it yourself. As I am new to all this, I can’t say that I understand each and every word.

When I started rosfoxy container I used a custom profile named ros by following this video. Here it is:

config:
  environment.DISPLAY: :0
  raw.idmap: both 1000 1000
  user.user-data: |
    #cloud-config
    runcmd:
      - "apt-key adv --fetch-keys 'https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc'"
      - "apt-add-repository 'http://packages.ros.org/ros/ubuntu'"
      - "apt-add-repository 'http://packages.ros.org/ros2/ubuntu'"
description: ROS
devices:
  X0:
    path: /tmp/.X11-unix/X0
    source: /tmp/.X11-unix/X0
    type: disk
  eth0:
    nictype: bridged
    parent: lxdbr0
    type: nic
  logitech:
    productid: 082b
    type: usb
    vendorid: 046d
  root:
    path: /
    pool: default
    type: disk
name: ros
used_by:
- /1.0/instances/rosfoxy

The logitech part was added when I used this command lxc profile device add ros logitech usb vendorid=046d productid=082b

But I have never added gid=1000 when using lxc config device add rosfoxy video0 unix-char path=/dev/video0. So I went ahead and tried:

hany@hany-asus:~$ lxc config device add rosfoxy video0 unix-char path=/dev/video0 gid=1000
Error: The device already exists
hany@hany-asus:~$ lxc config device remove rosfoxy video0 unix-char path=/dev/video0 
Error: The device doesn't exist
hany@hany-asus:~$ lxc config device remove rosfoxy video1 unix-char path=/dev/video1 
Error: The device doesn't exist
hany@hany-asus:~$ lxc config device remove rosfoxy video2 unix-char path=/dev/video2 
Error: The device doesn't exist
hany@hany-asus:~$ lxc config device remove rosfoxy video3 unix-char path=/dev/video3 
Error: The device doesn't exist
hany@hany-asus:~$ lxc config device add rosfoxy video0 unix-char path=/dev/video0 gid=1000
Error: The device already exists
hany@hany-asus:~$ lxc config device add rosfoxy video2 unix-char path=/dev/video2 gid=1000
Error: The device already exists

Then from inside the container I tried

(base) ubuntu@rosfoxy:~$ v4l2-ctl --all
Failed to open /dev/video0: Permission denied

But when I added sudo I got:

(base) ubuntu@rosfoxy:~$ sudo v4l2-ctl --all
Driver Info:
	Driver name      : uvcvideo
	Card type        : Webcam C170: Webcam C170
	Bus info         : usb-0000:00:14.0-1
	Driver version   : 5.4.86
	Capabilities     : 0x84a00001
		Video Capture
		Metadata Capture
		Streaming
		Extended Pix Format
		Device Capabilities
	Device Caps      : 0x04200001
		Video Capture
		Streaming
		Extended Pix Format
Priority: 2
Video input : 0 (Camera 1: ok)
Format Video Capture:
...

Which seems to me that the webcam is detected!

but guvcview still returns

(base) ubuntu@rosfoxy:~$ guvcview
V4L2_CORE: ERROR opening V4L2 interface for /dev/video0
V4L2_CORE: ERROR opening V4L2 interface for /dev/video1
V4L2_CORE: ERROR opening V4L2 interface for /dev/video2
V4L2_CORE: ERROR opening V4L2 interface for /dev/video3
GUVCVIEW: version 2.0.6
GUVCVIEW: couldn't open /home/ubuntu//.config/guvcview2/video0 for read: No such file or directory
V4L2_CORE: ERROR opening V4L interface: Permission denied
GUVCVIEW (1): Guvcview error
	 no video device found

and sudo guvcview returns

(base) ubuntu@rosfoxy:~$ sudo guvcview
V4L2_CORE: ERROR opening V4L2 interface for /dev/video3
GUVCVIEW: version 2.0.6
GUVCVIEW: couldn't open /root/.config/guvcview2/video0 for read: No such file or directory
V4L2_CORE: (UVCIOC_CTRL_MAP) Error: No such file or directory
V4L2_CORE: (UVCIOC_CTRL_MAP) Error: No such file or directory
V4L2_CORE: (UVCIOC_CTRL_MAP) Error: No such file or directory
V4L2_CORE: (UVCIOC_CTRL_MAP) Error: No such file or directory
V4L2_CORE: (UVCIOC_CTRL_MAP) Error: No such file or directory
V4L2_CORE: (UVCIOC_CTRL_MAP) Error: No such file or directory
V4L2_CORE: (UVCIOC_CTRL_MAP) Error: No such file or directory
V4L2_CORE: (UVCIOC_CTRL_MAP) Error: No such file or directory
V4L2_CORE: (UVCIOC_CTRL_MAP) Error: No such file or directory
ALSA lib confmisc.c:767:(parse_card) cannot find card '0'
ALSA lib conf.c:4732:(_snd_config_evaluate) function snd_func_card_driver returned error: No such file or directory
ALSA lib confmisc.c:392:(snd_func_concat) error evaluating strings
ALSA lib conf.c:4732:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
ALSA lib confmisc.c:1246:(snd_func_refer) error evaluating name
ALSA lib conf.c:4732:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5220:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM sysdefault
ALSA lib confmisc.c:767:(parse_card) cannot find card '0'
ALSA lib conf.c:4732:(_snd_config_evaluate) function snd_func_card_driver returned error: No such file or directory
ALSA lib confmisc.c:392:(snd_func_concat) error evaluating strings
ALSA lib conf.c:4732:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
ALSA lib confmisc.c:1246:(snd_func_refer) error evaluating name
ALSA lib conf.c:4732:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5220:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM sysdefault
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.front
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround21
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround21
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround40
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround41
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround50
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround51
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround71
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.iec958
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.iec958
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.iec958
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.hdmi
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.hdmi
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.modem
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.modem
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.phoneline
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.phoneline
ALSA lib pcm_hw.c:1829:(_snd_pcm_hw_open) Invalid value for card
ALSA lib pcm_hw.c:1829:(_snd_pcm_hw_open) Invalid value for card
ALSA lib pcm_hw.c:1829:(_snd_pcm_hw_open) Invalid value for card
ALSA lib pcm_hw.c:1829:(_snd_pcm_hw_open) Invalid value for card
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
ALSA lib pcm_oss.c:377:(_snd_pcm_oss_open) Unknown field port
ALSA lib pcm_oss.c:377:(_snd_pcm_oss_open) Unknown field port
ALSA lib pulse.c:242:(pulse_connect) PulseAudio: Unable to connect: Connection refused

ALSA lib pulse.c:242:(pulse_connect) PulseAudio: Unable to connect: Connection refused

ALSA lib pcm_hw.c:1829:(_snd_pcm_hw_open) Invalid value for card
ALSA lib pcm_hw.c:1829:(_snd_pcm_hw_open) Invalid value for card
ALSA lib pcm_hw.c:1829:(_snd_pcm_hw_open) Invalid value for card
ALSA lib pcm_hw.c:1829:(_snd_pcm_hw_open) Invalid value for card
ALSA lib pcm_usb_stream.c:486:(_snd_pcm_usb_stream_open) Invalid type for card
ALSA lib pcm_usb_stream.c:486:(_snd_pcm_usb_stream_open) Invalid type for card
ALSA lib confmisc.c:767:(parse_card) cannot find card '0'
ALSA lib conf.c:4732:(_snd_config_evaluate) function snd_func_card_driver returned error: No such file or directory
ALSA lib confmisc.c:392:(snd_func_concat) error evaluating strings
ALSA lib conf.c:4732:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
ALSA lib confmisc.c:1246:(snd_func_refer) error evaluating name
ALSA lib conf.c:4732:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5220:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM default
ALSA lib confmisc.c:767:(parse_card) cannot find card '0'
ALSA lib conf.c:4732:(_snd_config_evaluate) function snd_func_card_driver returned error: No such file or directory
ALSA lib confmisc.c:392:(snd_func_concat) error evaluating strings
ALSA lib conf.c:4732:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
ALSA lib confmisc.c:1246:(snd_func_refer) error evaluating name
ALSA lib conf.c:4732:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5220:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM default
ALSA lib confmisc.c:767:(parse_card) cannot find card '0'
ALSA lib conf.c:4732:(_snd_config_evaluate) function snd_func_card_driver returned error: No such file or directory
ALSA lib confmisc.c:392:(snd_func_concat) error evaluating strings
ALSA lib conf.c:4732:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
ALSA lib confmisc.c:1246:(snd_func_refer) error evaluating name
ALSA lib conf.c:4732:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5220:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM dmix
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
Segmentation fault

also

(py38) ubuntu@rosfoxy:~$ python -c "import cv2;print(cv2.VideoCapture(0).isOpened())"
[ WARN:0] global ../modules/videoio/src/cap_v4l.cpp (893) open VIDEOIO(V4L2:/dev/video0): can't open camera by index
False

I wonder why it is so complicated :confused:

The errors that you get, stem from the fact that your non-root user in the container (user account ubuntu) has no access to the /dev/video0 device. Because on the host this device belongs to group video and your desktop user on the host is a member of this video group (access allowed).

But when you add the /dev/video0 device into the container without specifying group information or file permissions, the default is to apply the group root (no access, unless you add sudo).

There are all sorts of workarounds but I think the cleaner solution is to specify a group to the /dev/video0 in the container so that the non-root account in the container can access the webcam freely.

If you want a quick workaround, you can just run the following command in the container that changes the permissions of the device to make it accessible to the non-root account. You may have to reapply the command when you reconnect the camera or restart the container.

sudo chown root:ubuntu /dev/video0

That’s what you are trying to do with this command. But The device already exists, which means that you have to remove it first, before adding it again where you specify the GID.

hany@hany-asus:~$ lxc config device add rosfoxy video0 unix-char path=/dev/video0 gid=1000
Error: The device already exists
hany@hany-asus:~$ lxc config device remove rosfoxy video0
hany@hany-asus:~$ lxc config device add rosfoxy video0 unix-char path=/dev/video0 gid=1000
1 Like

Thanks a million Simos! it works now!!

So my mistake was in this line lxc config device remove rosfoxy video0 unix-char path=/dev/video0 I shouldn’t have added unix-char path=/dev/video0

I also tested it with the connected motors by adding lxc config device add rosfoxy ttyUSB0 unix-char path=/dev/ttyUSB0 gid=1000 and now I can control the dynamixel servos.

I also started a question here, if you want you can write an answer there and I will accept it.

Thanks again!