@@ -15,6 +15,7 @@ struct virtualcam_data {
15
15
obs_output_t * output ;
16
16
int device ;
17
17
uint32_t frame_size ;
18
+ bool use_caps_workaround ;
18
19
};
19
20
20
21
static const char * virtualcam_name (void * unused )
@@ -110,11 +111,54 @@ static void *virtualcam_create(obs_data_t *settings, obs_output_t *output)
110
111
return vcam ;
111
112
}
112
113
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
+
113
156
static bool try_connect (void * data , const char * device )
114
157
{
158
+ static bool use_caps_workaround = false;
115
159
struct virtualcam_data * vcam = (struct virtualcam_data * )data ;
116
- struct v4l2_format format ;
117
160
struct v4l2_capability capability ;
161
+ struct v4l2_format format ;
118
162
struct v4l2_streamparm parm ;
119
163
120
164
uint32_t width = obs_output_get_width (vcam -> output );
@@ -130,6 +174,14 @@ static bool try_connect(void *data, const char *device)
130
174
if (ioctl (vcam -> device , VIDIOC_QUERYCAP , & capability ) < 0 )
131
175
goto fail_close_device ;
132
176
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
+
133
185
format .type = V4L2_BUF_TYPE_VIDEO_OUTPUT ;
134
186
135
187
if (ioctl (vcam -> device , VIDIOC_G_FMT , & format ) < 0 )
@@ -165,7 +217,7 @@ static bool try_connect(void *data, const char *device)
165
217
memset (& parm , 0 , sizeof (parm ));
166
218
parm .type = V4L2_BUF_TYPE_VIDEO_OUTPUT ;
167
219
168
- if (ioctl (vcam -> device , VIDIOC_STREAMON , & parm ) < 0 ) {
220
+ if (vcam -> use_caps_workaround && ioctl (vcam -> device , VIDIOC_STREAMON , & format . type ) < 0 ) {
169
221
blog (LOG_ERROR , "Failed to start streaming on '%s' (%s)" , device , strerror (errno ));
170
222
goto fail_close_device ;
171
223
}
@@ -238,10 +290,9 @@ static void virtualcam_stop(void *data, uint64_t ts)
238
290
struct virtualcam_data * vcam = (struct virtualcam_data * )data ;
239
291
obs_output_end_data_capture (vcam -> output );
240
292
241
- struct v4l2_streamparm parm = {0 };
242
- parm .type = V4L2_BUF_TYPE_VIDEO_OUTPUT ;
293
+ uint32_t buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT ;
243
294
244
- if (ioctl (vcam -> device , VIDIOC_STREAMOFF , & parm ) < 0 ) {
295
+ if (vcam -> use_caps_workaround && ioctl (vcam -> device , VIDIOC_STREAMOFF , buf_type ) < 0 ) {
245
296
blog (LOG_WARNING , "Failed to stop streaming on video device %d (%s)" , vcam -> device , strerror (errno ));
246
297
}
247
298
0 commit comments