From: Paul Gofman pgofman@codeweavers.com
--- dlls/qcap/qcap_private.h | 6 ++++++ dlls/qcap/tests/videocapture.c | 7 +------ dlls/qcap/v4l.c | 30 ++++++++++++++++++++++++++---- dlls/qcap/vfwcapture.c | 8 ++++++++ 4 files changed, 41 insertions(+), 10 deletions(-)
diff --git a/dlls/qcap/qcap_private.h b/dlls/qcap/qcap_private.h index c9119b6a52e..d0acd9e3bd7 100644 --- a/dlls/qcap/qcap_private.h +++ b/dlls/qcap/qcap_private.h @@ -47,6 +47,11 @@ struct create_params video_capture_device_t *device; };
+struct start_params +{ + video_capture_device_t device; +}; + struct destroy_params { video_capture_device_t device; @@ -130,6 +135,7 @@ struct read_frame_params enum unix_funcs { unix_create, + unix_start, unix_destroy, unix_check_format, unix_set_format, diff --git a/dlls/qcap/tests/videocapture.c b/dlls/qcap/tests/videocapture.c index a7f6eea666a..92a89316a43 100644 --- a/dlls/qcap/tests/videocapture.c +++ b/dlls/qcap/tests/videocapture.c @@ -667,12 +667,7 @@ static void test_multiple_objects(IMoniker *moniker) hr = IMoniker_BindToObject(moniker, NULL, NULL, &IID_IBaseFilter, (void **)&filter); ok(hr == S_OK, "got %#lx.\n", hr); hr = IMoniker_BindToObject(moniker, NULL, NULL, &IID_IBaseFilter, (void **)&filter2); - todo_wine ok(hr == S_OK, "got %#lx.\n", hr); - if (FAILED(hr)) - { - IBaseFilter_Release(filter); - return; - } + ok(hr == S_OK, "got %#lx.\n", hr); ok(filter != filter2, "got same objects.\n");
hr = IBaseFilter_EnumPins(filter, &enum_pins); diff --git a/dlls/qcap/v4l.c b/dlls/qcap/v4l.c index 134c3eca9e1..d91a15fbfa3 100644 --- a/dlls/qcap/v4l.c +++ b/dlls/qcap/v4l.c @@ -93,6 +93,8 @@ struct video_capture_device const struct caps *current_caps; struct caps *caps; LONG caps_count; + struct v4l2_format device_format; + BOOL started;
int image_size, image_pitch; BYTE *image_data; @@ -162,7 +164,7 @@ static NTSTATUS v4l_device_check_format( void *args ) return E_FAIL; }
-static HRESULT set_caps(struct video_capture_device *device, const struct caps *caps) +static HRESULT set_caps(struct video_capture_device *device, const struct caps *caps, BOOL try) { struct v4l2_format format = {0}; LONG width, height, image_size; @@ -182,7 +184,7 @@ static HRESULT set_caps(struct video_capture_device *device, const struct caps * format.fmt.pix.pixelformat = caps->pixelformat; format.fmt.pix.width = width; format.fmt.pix.height = height; - if (xioctl(device->fd, VIDIOC_S_FMT, &format) == -1 + if (xioctl(device->fd, try ? VIDIOC_TRY_FMT : VIDIOC_S_FMT, &format) == -1 || format.fmt.pix.pixelformat != caps->pixelformat || format.fmt.pix.width != width || format.fmt.pix.height != height) @@ -192,6 +194,8 @@ static HRESULT set_caps(struct video_capture_device *device, const struct caps * return VFW_E_TYPE_NOT_ACCEPTED; }
+ device->started = !try; + device->device_format = format; device->current_caps = caps; device->image_size = image_size; device->image_pitch = width * caps->video_info.bmiHeader.biBitCount / 8; @@ -213,7 +217,7 @@ static NTSTATUS v4l_device_set_format( void *args ) if (device->current_caps == caps) return S_OK;
- return set_caps(device, caps); + return set_caps(device, caps, FALSE); }
static NTSTATUS v4l_device_get_format( void *args ) @@ -550,7 +554,7 @@ static NTSTATUS v4l_device_create( void *args ) for (i = 0; i < device->caps_count; ++i) device->caps[i].media_type.pbFormat = (BYTE *)&device->caps[i].video_info;
- if (FAILED(hr = set_caps(device, &device->caps[0]))) + if (FAILED(hr = set_caps(device, &device->caps[0], TRUE))) { if (hr == VFW_E_TYPE_NOT_ACCEPTED && !have_libv4l2) ERR_(winediag)("You may need libv4l2 to use this device.\n"); @@ -569,6 +573,22 @@ error: return E_FAIL; }
+static NTSTATUS v4l_device_start( void *args ) +{ + const struct start_params *params = args; + struct video_capture_device *device = get_device(params->device); + + if (device->started) return S_OK; + + if (xioctl(device->fd, VIDIOC_S_FMT, &device->device_format) == -1) + { + ERR("Failed to set pixel format: %s.\n", strerror(errno)); + return E_FAIL; + } + device->started = TRUE; + return S_OK; +} + static NTSTATUS v4l_device_destroy( void *args ) { const struct destroy_params *params = args; @@ -580,6 +600,7 @@ static NTSTATUS v4l_device_destroy( void *args ) const unixlib_entry_t __wine_unix_call_funcs[] = { v4l_device_create, + v4l_device_start, v4l_device_destroy, v4l_device_check_format, v4l_device_set_format, @@ -846,6 +867,7 @@ static NTSTATUS wow64_v4l_device_read_frame( void *args ) const unixlib_entry_t __wine_unix_call_wow64_funcs[] = { wow64_v4l_device_create, + v4l_device_start, v4l_device_destroy, wow64_v4l_device_check_format, wow64_v4l_device_set_format, diff --git a/dlls/qcap/vfwcapture.c b/dlls/qcap/vfwcapture.c index 0899b228ec2..dba9f2f8288 100644 --- a/dlls/qcap/vfwcapture.c +++ b/dlls/qcap/vfwcapture.c @@ -195,6 +195,7 @@ static DWORD WINAPI stream_thread(void *arg) static HRESULT vfw_capture_init_stream(struct strmbase_filter *iface) { struct vfw_capture *filter = impl_from_strmbase_filter(iface); + struct start_params params; HRESULT hr;
if (!filter->source.pin.peer) @@ -203,6 +204,13 @@ static HRESULT vfw_capture_init_stream(struct strmbase_filter *iface) if (FAILED(hr = IMemAllocator_Commit(filter->source.pAllocator))) ERR("Failed to commit allocator, hr %#lx.\n", hr);
+ params.device = filter->device; + if (FAILED(hr = V4L_CALL( start, ¶ms ))) + { + ERR("start stream failed.\n"); + return hr; + } + EnterCriticalSection(&filter->state_cs); filter->state = State_Paused; LeaveCriticalSection(&filter->state_cs);