From: Elizabeth Figura <zfigura(a)codeweavers.com> Based on a patch by Jiangyi Chen. --- dlls/qcap/qcap_private.h | 11 +++++++ dlls/qcap/tests/videocapture.c | 50 ++++++++++++++++++++++++++++ dlls/qcap/v4l.c | 59 ++++++++++++++++++++++++++++++++++ dlls/qcap/vfwcapture.c | 28 +++++++++++++--- 4 files changed, 143 insertions(+), 5 deletions(-) diff --git a/dlls/qcap/qcap_private.h b/dlls/qcap/qcap_private.h index c1fb7877781..9f771a7fac4 100644 --- a/dlls/qcap/qcap_private.h +++ b/dlls/qcap/qcap_private.h @@ -97,6 +97,16 @@ struct get_caps_count_params int *count; }; +struct get_frame_intervals_params +{ + video_capture_device_t device; + unsigned int caps_index; + unsigned int width; + unsigned int height; + unsigned int *count; + LONGLONG *intervals; +}; + struct get_prop_range_params { video_capture_device_t device; @@ -141,6 +151,7 @@ enum unix_funcs unix_get_media_type, unix_get_caps, unix_get_caps_count, + unix_get_frame_intervals, unix_get_prop_range, unix_get_prop, unix_set_prop, diff --git a/dlls/qcap/tests/videocapture.c b/dlls/qcap/tests/videocapture.c index f60ecee0180..13fd45b618c 100644 --- a/dlls/qcap/tests/videocapture.c +++ b/dlls/qcap/tests/videocapture.c @@ -311,6 +311,55 @@ static void test_pin_interfaces(IPin *pin) check_interface(pin, &IID_IStreamBuilder, FALSE); } +static void test_frame_rate_list(IBaseFilter *filter, IPin *pin) +{ + IAMStreamConfig *stream_config; + VIDEO_STREAM_CONFIG_CAPS vscc; + IAMVideoControl *control; + AM_MEDIA_TYPE *format; + LONGLONG *rates; + LONG rate_count; + SIZE dimensions; + int count, size; + HRESULT hr; + + IPin_QueryInterface(pin, &IID_IAMStreamConfig, (void **)&stream_config); + IBaseFilter_QueryInterface(filter, &IID_IAMVideoControl, (void **)&control); + + hr = IAMStreamConfig_GetNumberOfCapabilities(stream_config, &count, &size); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(count != 0xdeadbeef, "Got wrong count: %d.\n", count); + ok(size == sizeof(VIDEO_STREAM_CONFIG_CAPS), "Got wrong size: %d.\n", size); + + dimensions.cx = dimensions.cy = 0; + + for (int i = 0; i < count; ++i) + { + hr = IAMStreamConfig_GetStreamCaps(stream_config, i, &format, (BYTE *)&vscc); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + if (0) + { + /* The documentation says the rates can be NULL, but it crashes. */ + IAMVideoControl_GetFrameRateList(control, pin, i, vscc.MinOutputSize, &rate_count, NULL); + } + + rate_count = 0; + hr = IAMVideoControl_GetFrameRateList(control, pin, i, vscc.MinOutputSize, &rate_count, &rates); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + for (LONG j = 0; j < rate_count; ++j) + ok(rates[j] >= vscc.MinFrameInterval && rates[j] <= vscc.MaxFrameInterval, + "Got unexpected rates[%ld] %I64d, min %I64d, max %I64d.\n", + j, rates[j], vscc.MinFrameInterval, vscc.MaxFrameInterval); + CoTaskMemFree(rates); + + DeleteMediaType(format); + } + + IAMStreamConfig_Release(stream_config); + IAMVideoControl_Release(control); +} + static void test_pins(IBaseFilter *filter) { IEnumPins *enum_pins; @@ -329,6 +378,7 @@ static void test_pins(IBaseFilter *filter) test_pin_interfaces(pin); test_media_types(pin); test_stream_config(pin); + test_frame_rate_list(filter, pin); } IPin_Release(pin); } diff --git a/dlls/qcap/v4l.c b/dlls/qcap/v4l.c index 482a0f1d803..44f643d68ab 100644 --- a/dlls/qcap/v4l.c +++ b/dlls/qcap/v4l.c @@ -29,6 +29,7 @@ #include <limits.h> #include <stdarg.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <fcntl.h> @@ -428,6 +429,37 @@ static NTSTATUS v4l_device_get_caps_count( void *args ) return S_OK; } +static NTSTATUS v4l_device_get_frame_intervals( void *args ) +{ + const struct get_frame_intervals_params *params = args; + struct video_capture_device *device = get_device(params->device); + + struct v4l2_frmivalenum frmival = + { + .pixel_format = device->caps[params->caps_index].pixelformat, + .width = params->width, + .height = params->height, + }; + __u32 count = 0; + + for (frmival.index = 0; xioctl(device->fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival) != -1; ++frmival.index) + { + if (frmival.type == V4L2_FRMIVAL_TYPE_DISCRETE) + { + if (params->intervals) + params->intervals[count] = TICKSPERSEC * frmival.discrete.numerator / frmival.discrete.denominator; + ++count; + } + else if (frmival.type == V4L2_FRMIVAL_TYPE_STEPWISE || frmival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) + { + FIXME("Unhandled type %u.\n", frmival.type); + } + } + + *params->count = count; + return S_OK; +} + static NTSTATUS v4l_device_create( void *args ) { const struct create_params *params = args; @@ -619,6 +651,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = v4l_device_get_media_type, v4l_device_get_caps, v4l_device_get_caps_count, + v4l_device_get_frame_intervals, v4l_device_get_prop_range, v4l_device_get_prop, v4l_device_set_prop, @@ -810,6 +843,31 @@ static NTSTATUS wow64_v4l_device_get_caps_count( void *args ) return v4l_device_get_caps_count( ¶ms ); } +static NTSTATUS wow64_v4l_device_get_frame_intervals( void *args ) +{ + struct + { + video_capture_device_t device; + unsigned int caps_index; + unsigned int width; + unsigned int height; + PTR32 count; + PTR32 intervals; + } const *params32 = args; + + struct get_frame_intervals_params params = + { + params32->device, + params32->caps_index, + params32->width, + params32->height, + ULongToPtr(params32->count), + ULongToPtr(params32->intervals), + }; + + return v4l_device_get_frame_intervals( ¶ms ); +} + static NTSTATUS wow64_v4l_device_get_prop_range( void *args ) { struct @@ -886,6 +944,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = wow64_v4l_device_get_media_type, wow64_v4l_device_get_caps, wow64_v4l_device_get_caps_count, + wow64_v4l_device_get_frame_intervals, wow64_v4l_device_get_prop_range, wow64_v4l_device_get_prop, v4l_device_set_prop, diff --git a/dlls/qcap/vfwcapture.c b/dlls/qcap/vfwcapture.c index bf3ded9223c..97f79c9f521 100644 --- a/dlls/qcap/vfwcapture.c +++ b/dlls/qcap/vfwcapture.c @@ -857,15 +857,33 @@ static HRESULT WINAPI video_control_GetMaxAvailableFrameRate(IAMVideoControl *if return E_NOTIMPL; } -static HRESULT WINAPI video_control_GetFrameRateList(IAMVideoControl *iface, IPin *pin, LONG index, - SIZE dimensions, LONG *list_size, LONGLONG **frame_rate) +/* Despite the name this function actually returns a list of frame intervals. */ +static HRESULT WINAPI video_control_GetFrameRateList(IAMVideoControl *iface, IPin *pin, + LONG index, SIZE dimensions, LONG *ret_count, LONGLONG **ret_intervals) { struct vfw_capture *filter = impl_from_IAMVideoControl(iface); + struct get_frame_intervals_params params; + unsigned int count; - FIXME("filter %p, pin %p, index %ld, dimensions (%ldx%ld), list size %p, frame rate %p, stub.\n", - filter, pin, index, dimensions.cx, dimensions.cy, list_size, frame_rate); + TRACE("filter %p, pin %p, index %ld, dimensions (%ldx%ld), ret_count %p, ret_intervals %p.\n", + filter, pin, index, dimensions.cx, dimensions.cy, ret_count, ret_intervals); - return E_NOTIMPL; + params.device = filter->device; + params.caps_index = index; + params.width = dimensions.cx; + params.height = dimensions.cy; + params.intervals = NULL; + params.count = &count; + V4L_CALL( get_frame_intervals, ¶ms ); + + if (!(params.intervals = CoTaskMemAlloc(count * sizeof(LONGLONG)))) + return E_OUTOFMEMORY; + + V4L_CALL( get_frame_intervals, ¶ms ); + + *ret_intervals = params.intervals; + *ret_count = count; + return S_OK; } static const IAMVideoControlVtbl IAMVideoControl_VTable = -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9689