letmaik / pyvirtualcam

🎥 Send frames to a virtual camera from Python
GNU General Public License v2.0
452 stars 49 forks source link

"No v4l2 loopback device found" after using pyvirtualcam once with `exclusive_caps=1` #61

Open MasinAD opened 3 years ago

MasinAD commented 3 years ago

Describe the bug After running a script using pyvirtualcam the next run causes this error:

RuntimeError: 'v4l2loopback' backend: No v4l2 loopback device found at /dev/video[0-99]. Did you run 'modprobe v4l2loopback'? See also pyvirtualcam's documentation.

Only after unloading and reloading the kernel module I can run another script using pyvirtualcam.

To Reproduce Every single sample code causes this error.

#!/usr/bin/env python3
import pyvirtualcam
import numpy as np

with pyvirtualcam.Camera(width=1280, height=720, fps=20) as cam:
    print(f'Using virtual camera: {cam.device}')
    frame = np.zeros((cam.height, cam.width, 3), np.uint8)  # RGB
    while True:
        frame[:] = cam.frames_sent % 255  # grayscale animation
        cam.send(frame)
        cam.sleep_until_next_frame()

I even rewrote a script to not use the with statement and call cam.close() (and even cam._backend.close()) directly.

letmaik commented 3 years ago

I'm unable to reproduce this on Ubuntu 18.04 (kernel 4.15.0-143) using the same v4l2loopback version with/without running ffplay /dev/video0. Do you see the issue even without having an app connected to the cam? If it only happens with an app, which one is it?

letmaik commented 3 years ago

Also, if you choose a specific device you will see a better error message, for example:

with pyvirtualcam.Camera(width=1280, height=720, fps=20, device="/dev/video0") as cam:

This must match the device created by v4l2loopback obviously.

MasinAD commented 3 years ago

Thanks for your quick response.

This issue occurs even without any consumer connected at any point. I just started a script and quit it (Ctrl+c) and then tried to restart it, resulting in above error.

I also tried specifying the device to use which resulted in this error:

RuntimeError: 'v4l2loopback' backend: Device /dev/video10 is not a video output device.

Until now I didn't try connecting another producer after having run a pyvirtualcam script. I just tried with OBS, and OBS can connect to the loopback device. I even added another v4l2 source in OBS and selected my loopback device, and it worked.

Yesterday, I tried the virtualvideo module which uses ffmpeg for accessing the loopback device. I just tried running their showFish.py sample after having used pyvirtualcam and it worked, too.

Neither dmesg -w nor journalctl -f show any messages related to v4l2.

Basically, it looks like pyvirtualcam leaves the loopback device in a state that makes it unaccessible for pyvirtualcam again but not for any other application.

I attached straces of the same script file working and failing. pyvirtualcam_working.trace.txt pyvirtualcam_failed.trace.txt Beginning at line 3736 the execution diverges. The working case shows:

ioctl(5, VIDIOC_QUERYCAP, {driver="v4l2 loopback", card="Overlay", bus_info="platform:v4l2loopback-000", version=KERNEL_VERSION(5, 12, 7), capabilities=V4L2_CAP_VIDEO_OUTPUT|V4L2_CAP_VIDEO_M2M|V4L2_CAP_EXT_PIX_FORMAT|V4L2_CAP_READWRITE|V4L2_CAP_STREAMING|V4L2_CAP_DEVICE_CAPS, device_caps=V4L2_CAP_VIDEO_OUTPUT|V4L2_CAP_VIDEO_M2M|V4L2_CAP_EXT_PIX_FORMAT|V4L2_CAP_READWRITE|V4L2_CAP_STREAMING}) = 0

while in the failing case it shows:

ioctl(5, VIDIOC_QUERYCAP, {driver="v4l2 loopback", card="Overlay", bus_info="platform:v4l2loopback-000", version=KERNEL_VERSION(5, 12, 7), capabilities=V4L2_CAP_VIDEO_M2M|V4L2_CAP_EXT_PIX_FORMAT|V4L2_CAP_READWRITE|V4L2_CAP_STREAMING|V4L2_CAP_DEVICE_CAPS, device_caps=V4L2_CAP_VIDEO_M2M|V4L2_CAP_EXT_PIX_FORMAT|V4L2_CAP_READWRITE|V4L2_CAP_STREAMING}) = 0

Interestingly, pyvirtualcam doesn't detect V4L2_CAP_VIDEO_OUTPUT capability anymore. Which, concidentally, is the same that v4l2-ctl detects (before):

[masin@luna webcam]$ v4l2-ctl -d /dev/video10 -D
Driver Info:
    Driver name      : v4l2 loopback
    Card type        : Overlay
    Bus info         : platform:v4l2loopback-000
    Driver version   : 5.12.7
    Capabilities     : 0x85208002
        Video Output
        Video Memory-to-Memory
        Read/Write
        Streaming
        Extended Pix Format
        Device Capabilities
    Device Caps      : 0x05208002
        Video Output
        Video Memory-to-Memory
        Read/Write
        Streaming
        Extended Pix Format

(after):

[masin@luna webcam]$ v4l2-ctl -d /dev/video10 -D
Driver Info:
    Driver name      : v4l2 loopback
    Card type        : Overlay
    Bus info         : platform:v4l2loopback-000
    Driver version   : 5.12.7
    Capabilities     : 0x85208000
        Video Memory-to-Memory
        Read/Write
        Streaming
        Extended Pix Format
        Device Capabilities
    Device Caps      : 0x05208000
        Video Memory-to-Memory
        Read/Write
        Streaming
        Extended Pix Format

I am not especially apt in reading straces but in the working case's trace log there's an "Inappropriate ioctl for device" in line 3824. I can't tell if that's important or somewhere in its vicinity.

letmaik commented 3 years ago

Not exactly sure what's going on. How do you create the device? Are you using exclusive_caps=1 by any chance? Even if, it should still work...

MasinAD commented 3 years ago
sudo modprobe -r v4l2loopback && sudo modprobe v4l2loopback devices=1 video_nr=10 card_label="Overlay" exclusive_caps=1 max_buffers=2

If I remove exclusive_caps=1 I don't have to unload and reload the kernel module anymore. Thanks a lot! That solves my immediate problem.

There's still the question why every other application but pyvirtualcam isn't bothered by having the loopback device been used before. But that's more out of curiosity than urgency.

letmaik commented 3 years ago

On my end I still can't reproduce it with the same modprobe line you've given, with exclusive_caps=1.

For me, before running the pyvirtualcam script, v4l2-ctl shows "Video Output". While running it, it shows "Video Capture". After exiting the script with ctrl-c it has "Video Output" again. This is what exclusive_caps=1 does. And if you leave it out, then it always advertises both capture and output. In your case, the weird thing is that you see neither after the script exits, which is something that shouldn't be possible.

datarocks-mk commented 2 years ago

I do face the same issue on gentoo linux (pyvirtualcam==0.8.0).

datarocks-mk commented 2 years ago

After modprobe, befor using: Driver Info: Driver name : v4l2 loopback Card type : Webcam Bus info : platform:v4l2loopback-000 Driver version : 5.10.61 Capabilities : 0x85208002 Video Output Video Memory-to-Memory Read/Write Streaming Extended Pix Format Device Capabilities Device Caps : 0x05208002 Video Output Video Memory-to-Memory Read/Write Streaming Extended Pix Format

After terminating: Driver Info: Driver name : v4l2 loopback Card type : Webcam Bus info : platform:v4l2loopback-000 Driver version : 5.10.61 Capabilities : 0x85208000 Video Memory-to-Memory Read/Write Streaming Extended Pix Format Device Capabilities Device Caps : 0x05208000 Video Memory-to-Memory Read/Write Streaming Extended Pix Format

Hirosam1 commented 1 year ago

I am using Ubuntu 20.04.4 LTS x86_64 with pyvirtualcam at v0.9.1 and face the same problem. The program throws an exception when it can't detect the device as output ( if v4l2_capability hasn't V4L2_CAP_VIDEO_OUTPUT) when using case exlusive_caps=1. Removing the throw where it checks this capability circumvents the issue.

Since in my case exlusive_caps=1 is essential, I will temporarily create a fork where I ignore whenever the OUTPUT flag fails.

If there is any other additional information that you need to recreate the issue, please ask me : )

jedreky commented 1 year ago

I'm experiencing a very similar (perhaps, identical?) problem. If I load v4l2 by running:

modprobe v4l2loopback devices=1 video_nr=9

I can only start pyvirtualcamera once. The second time I do it, I get the following error:

Traceback (most recent call last): File "/home/jedrek/alternatywy/projects/Playground/VirtualCamera/cam_test.py", line 4, in <module> with pyvirtualcam.Camera(width=1280, height=720, fps=20, device="/dev/video9") as cam: File "/home/jedrek/alternatywy/projects/Playground/venv/lib/python3.10/site-packages/pyvirtualcam/camera.py", line 219, in __init__ raise RuntimeError('\n'.join(errors)) RuntimeError: 'v4l2loopback' backend: std::exception

One workaround is to load the module with exclusive_caps=0, then everything is fine and I can start it multiple times (but I don't see the camera in Chrome).

Details of my system: Linux version 5.18.12-1-default (geeko@buildhost) (gcc (SUSE Linux) 12.1.1 20220721 [revision 4f15d2234608e82159d030dadb17af678cfad626], GNU ld (GNU Binutils; openSUSE Tumbleweed) 2.38.20220525-6) #1 SMP PREEMPT_DYNAMIC Fri Jul 15 12:08:33 UTC 2022 (3198c22)

I'm using Python 3.10.4.

henryruhs commented 10 months ago

Same issue for me under Ubuntu 22

with pyvirtualcam.Camera(width = 640, height = 480, fps = 25) as camera:
  File "/home/henry/PycharmProjects/facefusion/venv/lib/python3.10/site-packages/pyvirtualcam/camera.py", line 219, in __init__
    raise RuntimeError('\n'.join(errors))
RuntimeError: 'v4l2loopback' backend: std::exception
sbab commented 9 months ago

Similar issue for me running Ubuntu 22.04.3 LTS:

This is the code I'm running, it's the basic greyscale animation with a SIGINT handler for a graceful exit (which I thought was the issue...):

main.py ```python import signal import pyvirtualcam import numpy as np GLOBAL_SIGINT_RECEIVED = False def onSigint(sig, frame): global GLOBAL_SIGINT_RECEIVED GLOBAL_SIGINT_RECEIVED = True signal.signal(signal.SIGINT, onSigint) with pyvirtualcam.Camera(width=1280, height=720, fps=20, device="/dev/video0") as cam: print(f'Using virtual camera: {cam.device}') frame = np.zeros((cam.height, cam.width, 3), np.uint8) # RGB while True: frame[:] = cam.frames_sent * 4 % 255 # grayscale animation cam.send(frame) cam.sleep_until_next_frame() if (GLOBAL_SIGINT_RECEIVED) : break ```

This is the output of v4l2-ctl --all -d /dev/video0 when I create the device with before and after the first run of my program:

Output of v4l2-ctl BEFORE running the code, WITH exclusive_caps=1 ``` Driver Info: Driver name : v4l2 loopback Card type : Dummy video device (0x0000) Bus info : platform:v4l2loopback-000 Driver version : 6.2.16 Capabilities : 0x85200002 Video Output Read/Write Streaming Extended Pix Format Device Capabilities Device Caps : 0x05200002 Video Output Read/Write Streaming Extended Pix Format Priority: 2 Video output: 0 (loopback in) Format Video Output: Width/Height : 0/0 Pixel Format : 'BGR4' (32-bit BGRA/X 8-8-8-8) Field : None Bytes per Line : 0 Size Image : 0 Colorspace : sRGB Transfer Function : Default (maps to sRGB) YCbCr/HSV Encoding: Default (maps to ITU-R 601) Quantization : Default (maps to Full Range) Flags : Streaming Parameters Video Capture: Frames per second: 30.000 (30/1) Read buffers : 2 Streaming Parameters Video Output: Frames per second: 30.000 (30/1) Write buffers : 2 User Controls keep_format 0x0098f900 (bool) : default=0 value=0 sustain_framerate 0x0098f901 (bool) : default=0 value=0 timeout 0x0098f902 (int) : min=0 max=100000 step=1 default=0 value=0 timeout_image_io 0x0098f903 (bool) : default=0 value=0 ```
Output of v4l2-ctl AFTER running the code, WITH exclusive_caps=1 ``` Driver Info: Driver name : v4l2 loopback Card type : Dummy video device (0x0000) Bus info : platform:v4l2loopback-000 Driver version : 6.2.16 Capabilities : 0x85200000 Read/Write Streaming Extended Pix Format Device Capabilities Device Caps : 0x05200000 Read/Write Streaming Extended Pix Format Priority: 2 User Controls keep_format 0x0098f900 (bool) : default=0 value=0 sustain_framerate 0x0098f901 (bool) : default=0 value=0 timeout 0x0098f902 (int) : min=0 max=100000 step=1 default=0 value=0 timeout_image_io 0x0098f903 (bool) : default=0 value=0 ```

This is the exception raised by my program:

Screenshot from 2023-09-26 02-26-22

And this is the output i have creating the device without exclusive_caps=1, before and after running the code:

Output of v4l2-ctl BEFORE running the code, WITHOUT exclusive_caps=1 ``` Driver Info: Driver name : v4l2 loopback Card type : Dummy video device (0x0000) Bus info : platform:v4l2loopback-000 Driver version : 6.2.16 Capabilities : 0x85200003 Video Capture Video Output Read/Write Streaming Extended Pix Format Device Capabilities Device Caps : 0x05200003 Video Capture Video Output Read/Write Streaming Extended Pix Format Priority: 2 Video input : 0 (loopback: ok) Video output: 0 (loopback in) Format Video Output: Width/Height : 0/0 Pixel Format : 'BGR4' (32-bit BGRA/X 8-8-8-8) Field : None Bytes per Line : 0 Size Image : 0 Colorspace : sRGB Transfer Function : Default (maps to sRGB) YCbCr/HSV Encoding: Default (maps to ITU-R 601) Quantization : Default (maps to Full Range) Flags : Streaming Parameters Video Capture: Frames per second: 30.000 (30/1) Read buffers : 2 Streaming Parameters Video Output: Frames per second: 30.000 (30/1) Write buffers : 2 User Controls keep_format 0x0098f900 (bool) : default=0 value=0 sustain_framerate 0x0098f901 (bool) : default=0 value=0 timeout 0x0098f902 (int) : min=0 max=100000 step=1 default=0 value=0 timeout_image_io 0x0098f903 (bool) : default=0 value=0 ```
Output of v4l2-ctl AFTER running the code, WITHOUT exclusive_caps=1 ``` Driver Info: Driver name : v4l2 loopback Card type : Dummy video device (0x0000) Bus info : platform:v4l2loopback-000 Driver version : 6.2.16 Capabilities : 0x85200003 Video Capture Video Output Read/Write Streaming Extended Pix Format Device Capabilities Device Caps : 0x05200003 Video Capture Video Output Read/Write Streaming Extended Pix Format Priority: 2 Video input : 0 (loopback: ok) Video output: 0 (loopback in) Format Video Output: Width/Height : 1280/720 Pixel Format : 'YU12' (Planar YUV 4:2:0) Field : None Bytes per Line : 1280 Size Image : 1382400 Colorspace : sRGB Transfer Function : Default (maps to sRGB) YCbCr/HSV Encoding: Default (maps to ITU-R 601) Quantization : Default (maps to Limited Range) Flags : Streaming Parameters Video Capture: Frames per second: 30.000 (30/1) Read buffers : 2 Streaming Parameters Video Output: Frames per second: 30.000 (30/1) Write buffers : 2 User Controls keep_format 0x0098f900 (bool) : default=0 value=0 sustain_framerate 0x0098f901 (bool) : default=0 value=0 timeout 0x0098f902 (int) : min=0 max=100000 step=1 default=0 value=0 timeout_image_io 0x0098f903 (bool) : default=0 value=0 ```
1805214 commented 5 months ago

The first execution of the same camera is normal, but the execution after ctrl+c is abnormal.image

GermanWarez commented 4 months ago

Fix: Stop the video stream before closing the device, e.g: ioctl(vcam->device, VIDIOC_STREAMOFF, &parm) Source: https://github.com/obsproject/obs-studio/pull/7078

A fix might be to insert this before 'close(_camera_fd);':

        struct v4l2_streamparm parm = {0};
        parm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
        if (ioctl(_camera_fd, VIDIOC_STREAMOFF, &parm) < 0) {
            fprintf(stderr, "Failed to stop streaming on video device: %s\n", strerror(errno));
        }

Maybe as an extra function, as the close() is used 3 times.

letmaik commented 4 months ago

@GermanWarez Are you able to test this and create a PR if it works?

GermanWarez commented 4 months ago

@letmaik I could add a test that would be executed by github actions, that should fail without the fix and pass with the extra line. But I have no linux device to test. Would be sufficient to accept a PR?

TODO: Add ioctl to set both VIDIOC_STREAMON and VIDIOC_STREAMOFF, using the fix for obs as reference.

kde-baskets-user commented 1 week ago

I hit the same issue. Wait, nobody tested the PR since March?