From: Charlotte Pabst cpabst@codeweavers.com
--- dlls/mf/tests/mf.c | 346 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 346 insertions(+)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 36e953d10e8..9e7b5a5bdfe 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -1481,11 +1481,16 @@ static struct test_media_stream *create_test_stream(DWORD stream_index, IMFMedia return stream; }
+DEFINE_EXPECT(test_source_rate_control_SetRate); + #define TEST_SOURCE_NUM_STREAMS 3
struct test_source { IMFMediaSource IMFMediaSource_iface; + IMFGetService IMFGetService_iface; + IMFRateSupport IMFRateSupport_iface; + IMFRateControl IMFRateControl_iface; IMFMediaEventQueue *event_queue; IMFPresentationDescriptor *pd; struct test_media_stream *streams[TEST_SOURCE_NUM_STREAMS]; @@ -1493,6 +1498,9 @@ struct test_source unsigned stream_count; CRITICAL_SECTION cs; BOOL seekable; + BOOL thinnable; + BOOL thin; + float rate; LONG refcount; };
@@ -1503,12 +1511,20 @@ static struct test_source *impl_test_source_from_IMFMediaSource(IMFMediaSource *
static HRESULT WINAPI test_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out) { + struct test_source *source = impl_test_source_from_IMFMediaSource(iface); + if (IsEqualIID(riid, &IID_IMFMediaSource) || IsEqualIID(riid, &IID_IMFMediaEventGenerator) || IsEqualIID(riid, &IID_IUnknown)) { *out = iface; } + else if (IsEqualIID(riid, &IID_IMFGetService)) + { + IMFGetService_AddRef(&source->IMFGetService_iface); + *out = &source->IMFGetService_iface; + return S_OK; + } else { *out = NULL; @@ -1788,6 +1804,173 @@ static const IMFMediaSourceVtbl test_source_vtbl = test_source_Shutdown, };
+static struct test_source *impl_test_source_from_IMFGetService(IMFGetService *iface) +{ + return CONTAINING_RECORD(iface, struct test_source, IMFGetService_iface); +} + +static HRESULT WINAPI test_source_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj) +{ + struct test_source *source = impl_test_source_from_IMFGetService(iface); + return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj); +} + +static ULONG WINAPI test_source_get_service_AddRef(IMFGetService *iface) +{ + struct test_source *source = impl_test_source_from_IMFGetService(iface); + return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); +} + +static ULONG WINAPI test_source_get_service_Release(IMFGetService *iface) +{ + struct test_source *source = impl_test_source_from_IMFGetService(iface); + return IMFMediaSource_Release(&source->IMFMediaSource_iface); +} + +static HRESULT WINAPI test_source_get_service_GetService(IMFGetService *iface, REFGUID service, + REFIID riid, void **obj) +{ + struct test_source *source = impl_test_source_from_IMFGetService(iface); + + if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE)) + { + if (IsEqualIID(riid, &IID_IMFRateSupport)) + { + IMFRateSupport_AddRef(&source->IMFRateSupport_iface); + *obj = &source->IMFRateSupport_iface; + return S_OK; + } + if (IsEqualIID(riid, &IID_IMFRateControl)) + { + IMFRateControl_AddRef(&source->IMFRateControl_iface); + *obj = &source->IMFRateControl_iface; + return S_OK; + } + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static const IMFGetServiceVtbl test_source_get_service_vtbl = +{ + test_source_get_service_QueryInterface, + test_source_get_service_AddRef, + test_source_get_service_Release, + test_source_get_service_GetService, +}; + +static struct test_source *impl_test_source_from_IMFRateSupport(IMFRateSupport *iface) +{ + return CONTAINING_RECORD(iface, struct test_source, IMFRateSupport_iface); +} + +static HRESULT WINAPI test_source_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj) +{ + struct test_source *source = impl_test_source_from_IMFRateSupport(iface); + return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj); +} + +static ULONG WINAPI test_source_rate_support_AddRef(IMFRateSupport *iface) +{ + struct test_source *source = impl_test_source_from_IMFRateSupport(iface); + return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); +} + +static ULONG WINAPI test_source_rate_support_Release(IMFRateSupport *iface) +{ + struct test_source *source = impl_test_source_from_IMFRateSupport(iface); + return IMFMediaSource_Release(&source->IMFMediaSource_iface); +} + +static HRESULT WINAPI test_source_rate_support_GetSlowestRate(IMFRateSupport *iface, + MFRATE_DIRECTION direction, BOOL thin, float *rate) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_source_rate_support_GetFastestRate(IMFRateSupport *iface, + MFRATE_DIRECTION direction, BOOL thin, float *rate) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_source_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, + float rate, float *nearest_rate) +{ + if (nearest_rate) *nearest_rate = rate; + return S_OK; +} + +static const IMFRateSupportVtbl test_source_rate_support_vtbl = +{ + test_source_rate_support_QueryInterface, + test_source_rate_support_AddRef, + test_source_rate_support_Release, + test_source_rate_support_GetSlowestRate, + test_source_rate_support_GetFastestRate, + test_source_rate_support_IsRateSupported, +}; + +static struct test_source *impl_test_source_from_IMFRateControl(IMFRateControl *iface) +{ + return CONTAINING_RECORD(iface, struct test_source, IMFRateControl_iface); +} + +static HRESULT WINAPI test_source_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj) +{ + struct test_source *source = impl_test_source_from_IMFRateControl(iface); + return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj); +} + +static ULONG WINAPI test_source_rate_control_AddRef(IMFRateControl *iface) +{ + struct test_source *source = impl_test_source_from_IMFRateControl(iface); + return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); +} + +static ULONG WINAPI test_source_rate_control_Release(IMFRateControl *iface) +{ + struct test_source *source = impl_test_source_from_IMFRateControl(iface); + return IMFMediaSource_Release(&source->IMFMediaSource_iface); +} + +static HRESULT WINAPI test_source_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate) +{ + struct test_source *source = impl_test_source_from_IMFRateControl(iface); + HRESULT hr; + CHECK_EXPECT(test_source_rate_control_SetRate); + if (thin && !source->thinnable) + return MF_E_THINNING_UNSUPPORTED; + EnterCriticalSection(&source->cs); + source->thin = thin; + source->rate = rate; + LeaveCriticalSection(&source->cs); + hr = IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceRateChanged, &GUID_NULL, S_OK, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + return S_OK; +} + +static HRESULT WINAPI test_source_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate) +{ + struct test_source *source = impl_test_source_from_IMFRateControl(iface); + EnterCriticalSection(&source->cs); + *rate = source->rate; + if (thin) + *thin = source->thin; + LeaveCriticalSection(&source->cs); + return S_OK; +} + +static const IMFRateControlVtbl test_source_rate_control_vtbl = +{ + test_source_rate_control_QueryInterface, + test_source_rate_control_AddRef, + test_source_rate_control_Release, + test_source_rate_control_SetRate, + test_source_rate_control_GetRate, +}; + static IMFMediaSource *create_test_source(BOOL seekable) { struct test_source *source; @@ -1795,9 +1978,15 @@ static IMFMediaSource *create_test_source(BOOL seekable)
source = calloc(1, sizeof(*source)); source->IMFMediaSource_iface.lpVtbl = &test_source_vtbl; + source->IMFGetService_iface.lpVtbl = &test_source_get_service_vtbl; + source->IMFRateSupport_iface.lpVtbl = &test_source_rate_support_vtbl; + source->IMFRateControl_iface.lpVtbl = &test_source_rate_control_vtbl; source->refcount = 1; source->stream_count = 1; source->seekable = seekable; + source->thinnable = FALSE; + source->thin = FALSE; + source->rate = 1.0; MFCreateEventQueue(&source->event_queue); InitializeCriticalSection(&source->cs); for (i = 0; i < source->stream_count; ++i) @@ -6802,6 +6991,163 @@ static void test_media_session_Close(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); }
+static void test_media_session_thinning(void) +{ + media_type_desc video_rgb32_desc = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + }; + IMFRateControl *rate_control, *source_rate_control; + IMFMediaSession *session; + IMFAsyncCallback *callback; + IMFMediaSource *source; + IMFTopology *topology; + IMFMediaType *output_type; + IMFActivate *sink_activate; + struct test_source *source_impl; + struct test_grabber_callback *grabber_callback; + PROPVARIANT propvar; + HRESULT hr; + float rate; + BOOL thin; + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Startup failure, hr %#lx.\n", hr); + + callback = create_test_callback(TRUE); + + source = create_test_source(FALSE); + source_impl = impl_test_source_from_IMFMediaSource(source); + + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Failed to create media session, hr %#lx.\n", hr); + + hr = MFGetService((IUnknown *)session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateControl, (void **)&rate_control); + ok(hr == S_OK, "Failed to get rate control interface, hr %#lx.\n", hr); + hr = MFGetService((IUnknown *) source, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateControl, (void **)&source_rate_control); + ok(hr == S_OK, "Failed to get rate control interface, hr %#lx.\n", hr); + + grabber_callback = impl_from_IMFSampleGrabberSinkCallback(create_test_grabber_callback()); + hr = MFCreateMediaType(&output_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_media_type(output_type, video_rgb32_desc, -1); + hr = MFCreateSampleGrabberSinkActivate(output_type, &grabber_callback->IMFSampleGrabberSinkCallback_iface, &sink_activate); + ok(hr == S_OK, "Failed to create grabber sink, hr %#lx.\n", hr); + IMFMediaType_Release(output_type); + + topology = create_test_topology(source, sink_activate, NULL); + hr = IMFMediaSession_SetTopology(session, 0, topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFTopology_Release(topology); + IMFSampleGrabberSinkCallback_Release(&grabber_callback->IMFSampleGrabberSinkCallback_iface); + IMFActivate_Release(sink_activate); + + propvar.vt = VT_EMPTY; + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event_until_blocking(session, callback, MESessionStarted, 5000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* thinning unsupported, try enable thinning */ + + source_impl->thinnable = FALSE; + + SET_EXPECT(test_source_rate_control_SetRate); + + hr = IMFRateControl_SetRate(rate_control, TRUE, 2.0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event_until_blocking(session, callback, MESessionRateChanged, 1000, &propvar); + ok(hr == MF_E_THINNING_UNSUPPORTED, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + PropVariantClear(&propvar); + + CHECK_CALLED(test_source_rate_control_SetRate); + + hr = IMFRateControl_GetRate(rate_control, &thin, &rate); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(thin == FALSE, "got thin %d\n", !!thin); + ok(rate == 1.0, "got rate %f\n", rate); + + hr = IMFRateControl_GetRate(source_rate_control, &thin, &rate); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(thin == FALSE, "got source thin %d\n", !!thin); + ok(rate == 1.0, "got source rate %f\n", rate); + + /* thinning supported, enable thinning */ + + source_impl->thinnable = TRUE; + + SET_EXPECT(test_source_rate_control_SetRate); + + hr = IMFRateControl_SetRate(rate_control, TRUE, 2.0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event_until_blocking(session, callback, MESessionRateChanged, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_R4, "got vt %u\n", propvar.vt); + ok(propvar.fltVal == 2.0, "got fltVal %f\n", propvar.fltVal); + PropVariantClear(&propvar); + + CHECK_CALLED(test_source_rate_control_SetRate); + + hr = IMFRateControl_GetRate(rate_control, &thin, &rate); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(thin == TRUE, "got thin %d\n", !!thin); + ok(rate == 2.0, "got rate %f\n", rate); + + hr = IMFRateControl_GetRate(source_rate_control, &thin, &rate); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(thin == TRUE, "got source thin %d\n", !!thin); + ok(rate == 2.0, "got source rate %f\n", rate); + + /* disable thinning */ + + SET_EXPECT(test_source_rate_control_SetRate); + + hr = IMFRateControl_SetRate(rate_control, FALSE, 3.0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event_until_blocking(session, callback, MESessionRateChanged, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_R4, "got vt %u\n", propvar.vt); + ok(propvar.fltVal == 3.0, "got fltVal %f\n", propvar.fltVal); + PropVariantClear(&propvar); + + CHECK_CALLED(test_source_rate_control_SetRate); + + hr = IMFRateControl_GetRate(rate_control, &thin, &rate); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(thin == FALSE, "got thin %d\n", !!thin); + ok(rate == 3.0, "got rate %f\n", rate); + + hr = IMFRateControl_GetRate(source_rate_control, &thin, &rate); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(thin == FALSE, "got source thin %d\n", !!thin); + ok(rate == 3.0, "got source rate %f\n", rate); + + CLEAR_CALLED(test_source_rate_control_SetRate); + + hr = IMFMediaSession_Stop(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSession_Close(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionClosed, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSource_Shutdown(source); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IMFAsyncCallback_Release(callback); + IMFMediaSource_Release(source); + IMFRateControl_Release(rate_control); + IMFRateControl_Release(source_rate_control); + IMFMediaSession_Release(session); + + hr = MFShutdown(); + ok(hr == S_OK, "Shutdown failure, hr %#lx.\n", hr); +} + START_TEST(mf) { init_functions();