Skip to content

Commit 12c6feb

Browse files
stephematicianRytoEX
authored andcommitted
linux-v4l2: Fix virtual camera start failure
Add function that tries to reset v4l2loopback output for module versions from 0.12.5 to 0.12.7. If successful, then set flag that STREAMON and STREAMOFF are necessary each time the device is opened/closed.
1 parent 7cae57d commit 12c6feb

File tree

1 file changed

+56
-5
lines changed

1 file changed

+56
-5
lines changed

plugins/linux-v4l2/v4l2-output.c

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ struct virtualcam_data {
1515
obs_output_t *output;
1616
int device;
1717
uint32_t frame_size;
18+
bool use_caps_workaround;
1819
};
1920

2021
static const char *virtualcam_name(void *unused)
@@ -110,11 +111,54 @@ static void *virtualcam_create(obs_data_t *settings, obs_output_t *output)
110111
return vcam;
111112
}
112113

114+
bool try_reset_output_caps(const char *device)
115+
{
116+
struct v4l2_capability capability;
117+
struct v4l2_format format;
118+
int fd;
119+
120+
blog(LOG_INFO, "Attempting to reset output capability of '%s'", device);
121+
122+
fd = open(device, O_RDWR);
123+
if (fd < 0)
124+
return false;
125+
126+
format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
127+
if (ioctl(fd, VIDIOC_G_FMT, &format) < 0)
128+
goto fail_close_reset_caps_fd;
129+
130+
if (ioctl(fd, VIDIOC_S_FMT, &format) < 0)
131+
goto fail_close_reset_caps_fd;
132+
133+
if (ioctl(fd, VIDIOC_STREAMON, &format.type) < 0)
134+
goto fail_close_reset_caps_fd;
135+
136+
if (ioctl(fd, VIDIOC_STREAMOFF, &format.type) < 0)
137+
goto fail_close_reset_caps_fd;
138+
139+
close(fd);
140+
141+
fd = open(device, O_RDWR);
142+
if (fd < 0)
143+
return false;
144+
145+
if (ioctl(fd, VIDIOC_QUERYCAP, &capability) < 0)
146+
goto fail_close_reset_caps_fd;
147+
148+
close(fd);
149+
return (capability.device_caps & V4L2_CAP_VIDEO_OUTPUT) != 0;
150+
151+
fail_close_reset_caps_fd:
152+
close(fd);
153+
return false;
154+
}
155+
113156
static bool try_connect(void *data, const char *device)
114157
{
158+
static bool use_caps_workaround = false;
115159
struct virtualcam_data *vcam = (struct virtualcam_data *)data;
116-
struct v4l2_format format;
117160
struct v4l2_capability capability;
161+
struct v4l2_format format;
118162
struct v4l2_streamparm parm;
119163

120164
uint32_t width = obs_output_get_width(vcam->output);
@@ -130,6 +174,14 @@ static bool try_connect(void *data, const char *device)
130174
if (ioctl(vcam->device, VIDIOC_QUERYCAP, &capability) < 0)
131175
goto fail_close_device;
132176

177+
if (!use_caps_workaround && !(capability.device_caps & V4L2_CAP_VIDEO_OUTPUT)) {
178+
if (!try_reset_output_caps(device))
179+
goto fail_close_device;
180+
181+
use_caps_workaround = true;
182+
}
183+
vcam->use_caps_workaround = use_caps_workaround;
184+
133185
format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
134186

135187
if (ioctl(vcam->device, VIDIOC_G_FMT, &format) < 0)
@@ -165,7 +217,7 @@ static bool try_connect(void *data, const char *device)
165217
memset(&parm, 0, sizeof(parm));
166218
parm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
167219

168-
if (ioctl(vcam->device, VIDIOC_STREAMON, &parm) < 0) {
220+
if (vcam->use_caps_workaround && ioctl(vcam->device, VIDIOC_STREAMON, &format.type) < 0) {
169221
blog(LOG_ERROR, "Failed to start streaming on '%s' (%s)", device, strerror(errno));
170222
goto fail_close_device;
171223
}
@@ -238,10 +290,9 @@ static void virtualcam_stop(void *data, uint64_t ts)
238290
struct virtualcam_data *vcam = (struct virtualcam_data *)data;
239291
obs_output_end_data_capture(vcam->output);
240292

241-
struct v4l2_streamparm parm = {0};
242-
parm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
293+
uint32_t buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
243294

244-
if (ioctl(vcam->device, VIDIOC_STREAMOFF, &parm) < 0) {
295+
if (vcam->use_caps_workaround && ioctl(vcam->device, VIDIOC_STREAMOFF, buf_type) < 0) {
245296
blog(LOG_WARNING, "Failed to stop streaming on video device %d (%s)", vcam->device, strerror(errno));
246297
}
247298

0 commit comments

Comments
 (0)