Use legacy camera with "quirky" udev rules in container

Hello!

I’m trying to use a legacy cam in a container with its custom Gstreamer source/driver “tcambin”/“tcamsrc”. I also have a different model from the same company: cam2 that I got into the container without any problems. To clarify: I can see both cameras with ls -l /dev/video* on the container! I can play both via gst-launch-1.0 v4l2src device=/dev/videoX | ... in the container but I want to play them via gst-launch-1.0 tcambin serial=0751XXXX | .. which only works for cam2. The tiscamera package seems to behave weird and cannot find the camera, even though I mounted almost everything (Dockerfile at the end of post). Serial number is used to address cams in tcam-ctrl and tcamsrc.

To get the legacy cam working on the host Ubuntu 20.04.5LTS I had to add an environment variable in addition to the normal software:

wget https://github.com/TheImagingSource/tiscamera/releases/download/v-tiscamera-1.0.0/tiscamera_1.0.0.4005_amd64_ubuntu_2004.deb && \
	sudo apt install ./tiscamera_1.0.0.4005_amd64_ubuntu_2004.deb -y && \
	sudo echo "TCAM_DISABLE_DEVICE_BLACKLIST=1" >> /etc/environment

I also had to copy their custom udev rules and uncomment the legacy lines like this:

# This file assures that The Imaging Source USB cameras are correctly recognized

# if no driver has claimed the interface yet, load uvcvideo
ACTION=="add", SUBSYSTEM=="usb", \
               ATTRS{idVendor}=="199e", ATTRS{idProduct}=="8101", \
               RUN+="/sbin/modprobe -b uvcvideo"

# add the imaging source VID and PID to the list of devices supported by uvcvideo
ACTION=="add", SUBSYSTEM=="drivers", \
               ENV{DEVPATH}=="/bus/usb/drivers/uvcvideo", \
               RUN+="/bin/sh -c 'echo 199e 8101 > /sys/bus/driver/uvcvideo'"

# Second action with different sysfs path.
# The API changed at one point so this path has been added.
ACTION=="add", SUBSYSTEM=="drivers", \
               ENV{DEVPATH}=="/bus/usb/drivers/uvcvideo", \
               RUN+="/bin/sh -c 'echo 199e 8101 > /sys/bus/usb/drivers/uvcvideo/new_id'"

# give users permission to interact with cameras
SUBSYSTEM=="usb", ATTRS{idVendor}=="199e", \
                  GROUP="video", MODE="0666", TAG+="uaccess", TAG+="udev-acl"

#######
# UVC Extension Units
# When manually editing this file for uasge in you system replace the following strings
# with the absolute paths of tcam-uvc-extension-loader and the location of the uvc extensions
#
@TCAM_INSTALL_BIN@ /usr/bin/
@TCAM_INSTALL_UVC_EXTENSION@ /usr/share/theimagingsource/tiscamera/uvc-extension/

sadly I have to reboot after this, as…

sudo udevadm control --reload-rules
sudo udevadm trigger

…does still not yield both cams with:

tcam-ctrl -l

After these steps the DFK41AU02 cam can be found with that command on the host. Thus it can be used in a Gstreamer pipeline: gst-launch-1.0 tcambin serial=0751XXXX | ...
→ What do I have to do to get this working in a container?
I tried to add this to the pre-existing Dockerfile:

RUN cd /tmp && wget https://github.com/TheImagingSource/tiscamera/releases/download/v-tiscamera-1.0.0/tiscamera_1.0.0.4005_amd64_ubuntu_2004.deb && \
	sudo apt install ./tiscamera_1.0.0.4005_amd64_ubuntu_2004.deb -y
RUN sudo apt update && sudo apt install -y udev
ENV UDEV=on
RUN sudo echo "TCAM_DISABLE_DEVICE_BLACKLIST=1" >> /etc/environment
COPY 80-theimagingsource-cameras.rules /etc/udev/rules.d/80-theimagingsource-cameras.rules
# maybe this is the problem? next layer and stuff...
RUN sudo udevadm control --reload-rules || echo "done"
RUN sudo udevadm trigger

I have to install the tiscamera “driver” but I tried without UDEV and rules and still the same.
If I try to do apply rules in one layer (which is not sufficient even on the host, only restart makes the cam visible via tcam-ctrl -l):

RUN --mount=type=bind,target=/etc/udev/rules.d/80-theimagingsource-cameras.rules,source=80-theimagingsource-cameras.rules,rw \
sudo udevadm control --reload-rules && sudo udevadm trigger

with DOCKER_BUILDKIT=1 prefix the build process fails with exit code 100 at the apt-get update stage, because it can’t find:

Err:1 http://archive.ubuntu.com/ubuntu focal InRelease
#5 0.372   Temporary failure resolving 'archive.ubuntu.com'

my adoptions to run_docker_from_local_build.sh:

docker run \
    -it --rm \
    --volume=$XSOCK:$XSOCK:rw \
    --volume=$XAUTH:$XAUTH:rw \
    --volume=$HOST_DIR:$SHARED_DIR:rw \
    --volume=/dev:/dev \
    --volume=/run/dbus:/run/dbus \
    --volume=/run/udev/control:/run/udev/control \
    --volume=/sys/bus:/sys/bus \
    --volume=/bus/usb/drivers:/bus/usb/drivers \
    --env="XAUTHORITY=${XAUTH}" \
    --env="DISPLAY=${DISPLAY}" \
    --privileged \
    --net=host \
    --cap-add=ALL \
    --name "fhtw_ros" \
    sensors/ros-noetic:latest bash \

I just don’t know what else to try? The udev rules run some modules that are not available in the container… so IDK if installing them is smart…

Thank you kind reader for comming this far! Here, I wish you enjoy this cookie: :cookie:

Although I have never tried to use a camera inside a container, this is what I noticed:

  • You are trying to use udev inside a container. I don’t think that would work. The udev rules should do their job during the boot before your container can start.
  • Even if it could work, you should have systemd running in your container which is usually not the case.
  • You didn’t mention any problem with this, but you use “sudo” in the Dockerfile. When you are working with containers, you don’t need sudo. You can easily change the user by using the USER instruction
    RUN # it will run as root by default
    USER myuser
    RUN # it will run as myuser
    USER root
    RUN # it will run as root
    
    Since docker containers usually don’t have sudo, it will not work in every Dockerfile.

Note that containers are not virtual machines. You should think of them as isolated processes. When you want to work with something closer to the kernel, it is better to do that on the host. “On the host” just means “not in a container” since every process in a container is basically on the host. It just cannot see everything around it except those that are in the same isolated environment (container)

Thank you for your reply @rimelek!

I still cannot wrap my head around what I have to do to make the tiscamera sw-package find the camera from inside! That’s why I tried udev rules also on the inside. But as you enlighten me, it seems futile and I’ll focus on making every goddamn thing on the computer available to the container.

Will try that in about two weeks. For now I wasted enough time on that challenge.

Cheers,
Martin