File 11906.patch of Package obs-studio

113
 
1
From 52d57cf70ca70f55378112f6eeb5708fb7680a6b Mon Sep 17 00:00:00 2001
2
From: stephematician <steph.fn.contact@proton.me>
3
Date: Wed, 19 Mar 2025 13:59:21 +1100
4
Subject: [PATCH] linux-v4l2: Fix virtual camera start failure
5
6
Add function that tries to reset v4l2loopback output for module versions
7
from 0.12.5 to 0.12.7. If successful, then set flag that STREAMON and
8
STREAMOFF are necessary each time the device is opened/closed.
9
---
10
 plugins/linux-v4l2/v4l2-output.c | 57 ++++++++++++++++++++++++++++++--
11
 1 file changed, 54 insertions(+), 3 deletions(-)
12
13
diff --git a/plugins/linux-v4l2/v4l2-output.c b/plugins/linux-v4l2/v4l2-output.c
14
index 366fc474f69d4e..d5e4e0f6ad57fb 100644
15
--- a/plugins/linux-v4l2/v4l2-output.c
16
+++ b/plugins/linux-v4l2/v4l2-output.c
17
@@ -15,6 +15,7 @@ struct virtualcam_data {
18
    obs_output_t *output;
19
    int device;
20
    uint32_t frame_size;
21
+   bool use_caps_workaround;
22
 };
23
 
24
 static const char *virtualcam_name(void *unused)
25
@@ -110,11 +111,54 @@ static void *virtualcam_create(obs_data_t *settings, obs_output_t *output)
26
    return vcam;
27
 }
28
 
29
+bool try_reset_output_caps(const char *device)
30
+{
31
+   struct v4l2_capability capability;
32
+   struct v4l2_format format;
33
+   int fd;
34
+
35
+   blog(LOG_INFO, "Attempting to reset output capability of '%s'", device);
36
+
37
+   fd = open(device, O_RDWR);
38
+   if (fd < 0)
39
+       return false;
40
+
41
+   format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
42
+   if (ioctl(fd, VIDIOC_G_FMT, &format) < 0)
43
+       goto reset_fail_close_fd;
44
+
45
+   if (ioctl(fd, VIDIOC_S_FMT, &format) < 0)
46
+       goto reset_fail_close_fd;
47
+
48
+   if (ioctl(fd, VIDIOC_STREAMON, &format.type) < 0)
49
+       goto reset_fail_close_fd;
50
+
51
+   if (ioctl(fd, VIDIOC_STREAMOFF, &format.type) < 0)
52
+       goto reset_fail_close_fd;
53
+
54
+   close(fd);
55
+
56
+   fd = open(device, O_RDWR);
57
+   if (fd < 0)
58
+       return false;
59
+
60
+   if (ioctl(fd, VIDIOC_QUERYCAP, &capability) < 0)
61
+       goto reset_fail_close_fd;
62
+
63
+   close(fd);
64
+   return (capability.device_caps & V4L2_CAP_VIDEO_OUTPUT) != 0;
65
+
66
+reset_fail_close_fd:
67
+   close(fd);
68
+   return false;
69
+}
70
+
71
 static bool try_connect(void *data, const char *device)
72
 {
73
+   static bool use_caps_workaround = false;
74
    struct virtualcam_data *vcam = (struct virtualcam_data *)data;
75
-   struct v4l2_format format;
76
    struct v4l2_capability capability;
77
+   struct v4l2_format format;
78
    struct v4l2_streamparm parm;
79
 
80
    uint32_t width = obs_output_get_width(vcam->output);
81
@@ -130,6 +174,13 @@ static bool try_connect(void *data, const char *device)
82
    if (ioctl(vcam->device, VIDIOC_QUERYCAP, &capability) < 0)
83
        goto fail_close_device;
84
 
85
+   if (!use_caps_workaround && !(capability.device_caps & V4L2_CAP_VIDEO_OUTPUT)) {
86
+       if (!try_reset_output_caps(device))
87
+           goto fail_close_device;
88
+       use_caps_workaround = true;
89
+   }
90
+   vcam->use_caps_workaround = use_caps_workaround;
91
+
92
    format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
93
 
94
    if (ioctl(vcam->device, VIDIOC_G_FMT, &format) < 0)
95
@@ -165,7 +216,7 @@ static bool try_connect(void *data, const char *device)
96
    memset(&parm, 0, sizeof(parm));
97
    parm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
98
 
99
-   if (ioctl(vcam->device, VIDIOC_STREAMON, &parm) < 0) {
100
+   if (vcam->use_caps_workaround && ioctl(vcam->device, VIDIOC_STREAMON, &parm.type) < 0) {
101
        blog(LOG_ERROR, "Failed to start streaming on '%s' (%s)", device, strerror(errno));
102
        goto fail_close_device;
103
    }
104
@@ -241,7 +292,7 @@ static void virtualcam_stop(void *data, uint64_t ts)
105
    struct v4l2_streamparm parm = {0};
106
    parm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
107
 
108
-   if (ioctl(vcam->device, VIDIOC_STREAMOFF, &parm) < 0) {
109
+   if (vcam->use_caps_workaround && ioctl(vcam->device, VIDIOC_STREAMOFF, &parm) < 0) {
110
        blog(LOG_WARNING, "Failed to stop streaming on video device %d (%s)", vcam->device, strerror(errno));
111
    }
112
 
113