mpromonet / v4l2rtspserver

RTSP Server for V4L2 device capture supporting HEVC/H264/JPEG/VP8/VP9
The Unlicense
1.86k stars 428 forks source link

Unable to stream RTSP from Fedora Coreos podman container #292

Closed s-fairchild closed 1 year ago

s-fairchild commented 1 year ago

Describe the bug I'm unable to stream rtsp unicast from a container running in Fedora Coreos 36 using podman. Tailing the logs the stream appears to begin then immediately stop, on the client app the stream fails to start. I've tested with VLC on my desktop and ipcam ISO app. The camera and command line arguments work in Arch Linux, and Fedora Server 36 running in podman and outside of a container.

Logs shown with -vv log verbosity

Oct 22 18:37:07 kore v4l2rtspserver[16220]: handleCmd_SETUP:SETUP rtsp://10.50.0.2:8554/custom_url RTSP/1.0
Oct 22 18:37:07 kore v4l2rtspserver[16220]: CSeq: 0
Oct 22 18:37:07 kore podman[16136]: [INFO] /v4lhandleCmd_SETUP:SETUP rtsp://10.50.0.2:8554/custom_url RTSP/1.0
Oct 22 18:37:07 kore podman[16136]: CSeq: 0
Oct 22 18:37:07 kore podman[16136]: Transport: RTP/AVP;unicast;client_port=9382-9383
Oct 22 18:37:07 kore podman[16136]: 
Oct 22 18:37:07 kore v4l2rtspserver[16220]: Transport: RTP/AVP;unicast;client_port=9382-9383
Oct 22 18:37:07 kore v4l2rtspserver[16220]: 
Oct 22 18:37:11 kore v4l2rtspserver[16220]: [INFO] /v4l2rtspserver/src/V4L2DeviceSource.cpp:29
Oct 22 18:37:11 kore v4l2rtspserver[16220]:         intv_sec:1666463810 fps:11 bandwidth:4017kbps

Troubleshooting steps taken

  1. Set selinux to permissive mode
  2. Run container in --privilege mode
  3. Add --cap-add ALL
  4. Tested with and without authentication
  5. Tested with port mapping and --net=host
  6. No firewall is running to block network activity No changes occurred with the above, other than audio streaming won't work without additional capabilities.

To Reproduce Steps to reproduce the behavior: Create a butane config and ignition file following the Fedora coreos documentation Create Fedora Coreos machine (libvirt works well) with this systemd unit:

    - name: v4l2rtspserver.service
      enabled: true
      contents: |
        [Unit]
        Description=V4L2 RTSP Server
        After=network.target
        BindsTo=dev-video0.device
        After=dev-video0.device

        [Service]
        Type=simple
        Restart=always
        RestartSec=30
        ExecStartPre=-/bin/podman kill v4l2rtspserver
        ExecStartPre=-/bin/podman rm v4l2rtspserver
        ExecStart=podman run \
            --name v4l2rtspserver \
            --pull newer \
            --privileged \
            --secret v4l2rtspserver,type=env,target=SECRET \
            --secret v4l2rtspserver_url,type=env,target=URL \
            --device /dev/video0:/dev/video0 \
            --device /dev/snd:/dev/snd \
            -p 8554:8554 \
            docker.io/mpromonet/v4l2rtspserver:latest-amd64 \
            -S1 \
            -R home -U user:"${SECRET}" \
            -C1 -A48000 -aS16_LE \
            -u "${URL}" \
            /dev/video0,hw:CARD=Camera,DEV=0
        ExecStop=/bin/podman stop v4l2rtspserver

        [Install]
        WantedBy=multi-user.target

Expected behavior RTSP stream to start and play video on clients.

Screenshots If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

Smartphone (please complete the following information):

Additional context Add any other context about the problem here. v4l2rtspserver_logs.txt

mpromonet commented 1 year ago

Hi,

Capture seems working, probably UDP packet are lost. Did you try using RTP over TCP ?

Best Regards, Michel.

P.S. I suppose /dev/vidoe0 in the command line is a error here ?

s-fairchild commented 1 year ago

@mpromonet Hello, thanks for your quick reply.

yes /dev/vidoe0 was a typo, was supposed to be /dev/video0,hw:CARD=Camera,DEV=0.

It looks like there were two issues.

  1. Variables being passed to v4l2rtspserver appear to be using the users env rather than the containers. Switching to file secrets and command substitution using -u "$(cat /run/secrets/url)" also fails. Execing into the container I can see the process didn't get the variable output as -u is empty
    /usr/local/bin/v4l2rtspserver -S2 -p 80 -C1 -A48000 -aS16_LE -u  /dev/video0,hw:CARD=Camera,DEV=0
  2. Syntax for passing the video device appears to matter Using a mapping like --device /dev/video0:/dev/video0 silently fails, but --device /dev/video0 works. Using symbolic links is also odd, I'll add my working example using symbolic links incase this is helpful for others in the future.

Trying to use a sym link as the video device argument fails, but if it's mapped to /dev/videoX it works. Not sure why but that also tripped me up.

podman run \
            --name v4l2rtspserver \
            --pull newer \
            --device /dev/v4l/by-id/usb-HD_Camera_Manufacturer_HD_USB_Camera_2020101401-video-index0:/dev/video0 \
            --device /dev/snd:/dev/snd \
            -p 8554:8554 \
            docker.io/mpromonet/v4l2rtspserver:latest-amd64 \
            -S1 \
            -C1 -A48000 -aS16_LE \
            -u ${URL} \
            /dev/video0,hw:CARD=Camera,DEV=0
s-fairchild commented 1 year ago

Here's my final solution to get podman secret env variables working. --cap-add and --privileged aren't required.

        [Unit]
        Description=V4L2 RTSP Server
        After=network.target

        [Service]
        Type=simple
        Restart=always
        RestartSec=30
        ExecStartPre=-/bin/podman kill v4l2rtspserver
        ExecStartPre=-/bin/podman rm v4l2rtspserver
        ExecStart=podman run \
                    --name v4l2rtspserver \
                    --pull newer \
                    --secret v4l2rtspserver,type=env,target=SECRET \
                    --secret v4l2rtspserver_url,type=env,target=URL \
                    --device /dev/v4l/by-id/usb-HD_Camera_Manufacturer_HD_USB_Camera_2020101401-video-index0:/dev/video0 \
                    --device /dev/snd:/dev/snd \
                    -v /var/usrlocal/bin/start_v4l2rtspserver.sh:/usr/local/bin/start_v4l2rtspserver.sh \
                    -p 8554:8554 \
                    --entrypoint "/bin/bash" \
                    docker.io/mpromonet/v4l2rtspserver:latest-amd64 \
                    -c "/usr/local/bin/start_v4l2rtspserver.sh"
        ExecStop=/bin/podman stop v4l2rtspserver

        [Install]
        WantedBy=multi-user.target
#!/bin/bash
# Mounted inside v4l2rtspserver container and executed by bash entrypoint

/usr/local/bin/v4l2rtspserver \
    -S1 \
    -R home -U user:"${SECRET}" \
    -C1 -A48000 -aS16_LE \
    -u "${URL}" \
    /dev/video0,hw:CARD=Camera,DEV=0