Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
-- v2: evr/filter: Implement media type testing for QueryAccept(). evr/filter: Add IMFTopologyServiceLookup stub. evr/filter: Add IMediaEventSink stub.
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/evr/evr.c | 42 ++++++++++++++++++++++++++++++++++++++++++ dlls/evr/tests/evr.c | 14 +++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-)
diff --git a/dlls/evr/evr.c b/dlls/evr/evr.c index 2251cb5522e..97cc2e27915 100644 --- a/dlls/evr/evr.c +++ b/dlls/evr/evr.c @@ -37,6 +37,7 @@ struct evr IAMFilterMiscFlags IAMFilterMiscFlags_iface; IMFGetService IMFGetService_iface; IMFVideoRenderer IMFVideoRenderer_iface; + IMediaEventSink IMediaEventSink_iface;
IMFTransform *mixer; IMFVideoPresenter *presenter; @@ -111,6 +112,8 @@ static HRESULT evr_query_interface(struct strmbase_renderer *iface, REFIID iid, *out = &filter->IMFGetService_iface; else if (IsEqualGUID(iid, &IID_IMFVideoRenderer)) *out = &filter->IMFVideoRenderer_iface; + else if (IsEqualGUID(iid, &IID_IMediaEventSink)) + *out = &filter->IMediaEventSink_iface; else return E_NOINTERFACE;
@@ -348,6 +351,44 @@ static const IMFVideoRendererVtbl filter_video_renderer_vtbl = filter_video_renderer_InitializeRenderer, };
+static struct evr *impl_from_IMediaEventSink(IMediaEventSink *iface) +{ + return CONTAINING_RECORD(iface, struct evr, IMediaEventSink_iface); +} + +static HRESULT WINAPI filter_media_event_sink_QueryInterface(IMediaEventSink *iface, REFIID riid, void **obj) +{ + struct evr *filter = impl_from_IMediaEventSink(iface); + return IUnknown_QueryInterface(filter->renderer.filter.outer_unk, riid, obj); +} + +static ULONG WINAPI filter_media_event_sink_AddRef(IMediaEventSink *iface) +{ + struct evr *filter = impl_from_IMediaEventSink(iface); + return IUnknown_AddRef(filter->renderer.filter.outer_unk); +} + +static ULONG WINAPI filter_media_event_sink_Release(IMediaEventSink *iface) +{ + struct evr *filter = impl_from_IMediaEventSink(iface); + return IUnknown_Release(filter->renderer.filter.outer_unk); +} + +static HRESULT WINAPI filter_media_event_sink_Notify(IMediaEventSink *iface, LONG event, LONG_PTR param1, LONG_PTR param2) +{ + FIXME("iface %p, event %ld, param1 %Id, param2 %Id.\n", iface, event, param1, param2); + + return E_NOTIMPL; +} + +static const IMediaEventSinkVtbl filter_media_event_sink_vtbl = +{ + filter_media_event_sink_QueryInterface, + filter_media_event_sink_AddRef, + filter_media_event_sink_Release, + filter_media_event_sink_Notify, +}; + HRESULT evr_filter_create(IUnknown *outer, void **out) { struct evr *object; @@ -361,6 +402,7 @@ HRESULT evr_filter_create(IUnknown *outer, void **out) object->IAMFilterMiscFlags_iface.lpVtbl = &filter_misc_flags_vtbl; object->IMFGetService_iface.lpVtbl = &filter_get_service_vtbl; object->IMFVideoRenderer_iface.lpVtbl = &filter_video_renderer_vtbl; + object->IMediaEventSink_iface.lpVtbl = &filter_media_event_sink_vtbl;
TRACE("Created EVR %p.\n", object); *out = &object->renderer.filter.IUnknown_inner; diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c index 28a472a8a7f..30f7ba81ee9 100644 --- a/dlls/evr/tests/evr.c +++ b/dlls/evr/tests/evr.c @@ -273,7 +273,9 @@ static void check_service_interface_(unsigned int line, void *iface_ptr, REFGUID
static void test_interfaces(void) { - IBaseFilter *filter = create_evr(); + IBaseFilter *filter = create_evr(), *filter2; + IUnknown *unk; + HRESULT hr; ULONG ref;
check_interface(filter, &IID_IAMFilterMiscFlags, TRUE); @@ -284,6 +286,7 @@ static void test_interfaces(void) check_interface(filter, &IID_IMediaFilter, TRUE); check_interface(filter, &IID_IMediaPosition, TRUE); check_interface(filter, &IID_IMediaSeeking, TRUE); + check_interface(filter, &IID_IMediaEventSink, TRUE); check_interface(filter, &IID_IPersist, TRUE); check_interface(filter, &IID_IUnknown, TRUE);
@@ -296,6 +299,15 @@ static void test_interfaces(void) check_interface(filter, &IID_IReferenceClock, FALSE); check_interface(filter, &IID_IVideoWindow, FALSE);
+ /* The scope of IMediaEventSink */ + hr = IBaseFilter_QueryInterface(filter, &IID_IMediaEventSink, (void **)&unk); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IUnknown_QueryInterface(unk, &IID_IBaseFilter, (void **)&filter2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(filter == filter2, "Unexpected pointer.\n"); + IBaseFilter_Release(filter2); + IUnknown_Release(unk); + ref = IBaseFilter_Release(filter); ok(!ref, "Got unexpected refcount %ld.\n", ref); }
On 8/29/22 09:39, Nikolay Sivov wrote:
@@ -296,6 +299,15 @@ static void test_interfaces(void) check_interface(filter, &IID_IReferenceClock, FALSE); check_interface(filter, &IID_IVideoWindow, FALSE);
- /* The scope of IMediaEventSink */
- hr = IBaseFilter_QueryInterface(filter, &IID_IMediaEventSink, (void **)&unk);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = IUnknown_QueryInterface(unk, &IID_IBaseFilter, (void **)&filter2);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(filter == filter2, "Unexpected pointer.\n");
- IBaseFilter_Release(filter2);
- IUnknown_Release(unk);
}ref = IBaseFilter_Release(filter); ok(!ref, "Got unexpected refcount %ld.\n", ref);
Somewhat out of curiosity, why this test?
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/evr/evr.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ dlls/evr/tests/evr.c | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+)
diff --git a/dlls/evr/evr.c b/dlls/evr/evr.c index 97cc2e27915..734f9621555 100644 --- a/dlls/evr/evr.c +++ b/dlls/evr/evr.c @@ -24,6 +24,7 @@
#include "evr_private.h" #include "d3d9.h" +#include "mferror.h"
#include "initguid.h" #include "dxva2api.h" @@ -38,6 +39,7 @@ struct evr IMFGetService IMFGetService_iface; IMFVideoRenderer IMFVideoRenderer_iface; IMediaEventSink IMediaEventSink_iface; + IMFTopologyServiceLookup IMFTopologyServiceLookup_iface;
IMFTransform *mixer; IMFVideoPresenter *presenter; @@ -114,6 +116,8 @@ static HRESULT evr_query_interface(struct strmbase_renderer *iface, REFIID iid, *out = &filter->IMFVideoRenderer_iface; else if (IsEqualGUID(iid, &IID_IMediaEventSink)) *out = &filter->IMediaEventSink_iface; + else if (IsEqualGUID(iid, &IID_IMFTopologyServiceLookup)) + *out = &filter->IMFTopologyServiceLookup_iface; else return E_NOINTERFACE;
@@ -389,6 +393,46 @@ static const IMediaEventSinkVtbl filter_media_event_sink_vtbl = filter_media_event_sink_Notify, };
+static struct evr *impl_from_IMFTopologyServiceLookup(IMFTopologyServiceLookup *iface) +{ + return CONTAINING_RECORD(iface, struct evr, IMFTopologyServiceLookup_iface); +} + +static HRESULT WINAPI filter_service_lookup_QueryInterface(IMFTopologyServiceLookup *iface, REFIID riid, void **obj) +{ + struct evr *filter = impl_from_IMFTopologyServiceLookup(iface); + return IUnknown_QueryInterface(filter->renderer.filter.outer_unk, riid, obj); +} + +static ULONG WINAPI filter_service_lookup_AddRef(IMFTopologyServiceLookup *iface) +{ + struct evr *filter = impl_from_IMFTopologyServiceLookup(iface); + return IUnknown_AddRef(filter->renderer.filter.outer_unk); +} + +static ULONG WINAPI filter_service_lookup_Release(IMFTopologyServiceLookup *iface) +{ + struct evr *filter = impl_from_IMFTopologyServiceLookup(iface); + return IUnknown_Release(filter->renderer.filter.outer_unk); +} + +static HRESULT WINAPI filter_service_lookup_LookupService(IMFTopologyServiceLookup *iface, MF_SERVICE_LOOKUP_TYPE lookup_type, + DWORD index, REFGUID service, REFIID riid, void **objects, DWORD *num_objects) +{ + FIXME("iface %p, lookup_type %d, index %lu, service %s, riid %s, objects %p, num_objects %p.\n", + iface, lookup_type, index, debugstr_guid(service), debugstr_guid(riid), objects, num_objects); + + return MF_E_NOTACCEPTING; +} + +static const IMFTopologyServiceLookupVtbl filter_service_lookup_vtbl = +{ + filter_service_lookup_QueryInterface, + filter_service_lookup_AddRef, + filter_service_lookup_Release, + filter_service_lookup_LookupService, +}; + HRESULT evr_filter_create(IUnknown *outer, void **out) { struct evr *object; @@ -403,6 +447,7 @@ HRESULT evr_filter_create(IUnknown *outer, void **out) object->IMFGetService_iface.lpVtbl = &filter_get_service_vtbl; object->IMFVideoRenderer_iface.lpVtbl = &filter_video_renderer_vtbl; object->IMediaEventSink_iface.lpVtbl = &filter_media_event_sink_vtbl; + object->IMFTopologyServiceLookup_iface.lpVtbl = &filter_service_lookup_vtbl;
TRACE("Created EVR %p.\n", object); *out = &object->renderer.filter.IUnknown_inner; diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c index 30f7ba81ee9..b632323ebb5 100644 --- a/dlls/evr/tests/evr.c +++ b/dlls/evr/tests/evr.c @@ -603,6 +603,40 @@ static void test_display_control(void) ok(!ref, "Got outstanding refcount %ld.\n", ref); }
+static void test_service_lookup(void) +{ + IBaseFilter *filter = create_evr(); + IMFTopologyServiceLookup *service_lookup; + IUnknown *unk; + DWORD count; + HRESULT hr; + ULONG ref; + + hr = IBaseFilter_QueryInterface(filter, &IID_IMFTopologyServiceLookup, (void **)&service_lookup); + if (FAILED(hr)) + { + win_skip("IMFTopologyServiceLookup is not exposed.\n"); + IBaseFilter_Release(filter); + return; + } + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFTopologyServiceLookup_QueryInterface(service_lookup, &IID_IBaseFilter, (void **)&unk); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(unk == (IUnknown *)filter, "Unexpected pointer.\n"); + IUnknown_Release(unk); + + count = 1; + hr = IMFTopologyServiceLookup_LookupService(service_lookup, MF_SERVICE_LOOKUP_GLOBAL, 0, + &MR_VIDEO_RENDER_SERVICE, &IID_IMediaEventSink, (void **)&unk, &count); + ok(hr == MF_E_NOTACCEPTING, "Unexpected hr %#lx.\n", hr); + + IMFTopologyServiceLookup_Release(service_lookup); + + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %ld.\n", ref); +} + static IMFMediaType * create_video_type(const GUID *subtype) { IMFMediaType *video_type; @@ -3276,6 +3310,7 @@ START_TEST(evr) test_unconnected_eos(); test_misc_flags(); test_display_control(); + test_service_lookup();
test_default_mixer(); test_default_mixer_type_negotiation();
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/evr/evr.c | 163 +++++++++++++++++++++++++++++++++++++++++-- dlls/evr/tests/evr.c | 54 ++++++++++++++ 2 files changed, 213 insertions(+), 4 deletions(-)
diff --git a/dlls/evr/evr.c b/dlls/evr/evr.c index 734f9621555..2f0eeb6a22d 100644 --- a/dlls/evr/evr.c +++ b/dlls/evr/evr.c @@ -25,12 +25,20 @@ #include "evr_private.h" #include "d3d9.h" #include "mferror.h" +#include "mfapi.h"
#include "initguid.h" #include "dxva2api.h"
WINE_DEFAULT_DEBUG_CHANNEL(evr);
+enum evr_flags +{ + EVR_INIT_SERVICES = 0x1, /* Currently in InitServices() call. */ + EVR_MIXER_INITED_SERVICES = 0x2, + EVR_PRESENTER_INITED_SERVICES = 0x4, +}; + struct evr { struct strmbase_renderer renderer; @@ -43,6 +51,7 @@ struct evr
IMFTransform *mixer; IMFVideoPresenter *presenter; + unsigned int flags; };
static void evr_uninitialize(struct evr *filter) @@ -125,6 +134,96 @@ static HRESULT evr_query_interface(struct strmbase_renderer *iface, REFIID iid, return S_OK; }
+static BOOL evr_is_mixer_d3d_aware(const struct evr *filter) +{ + IMFAttributes *attributes; + unsigned int value = 0; + BOOL ret; + + if (FAILED(IMFTransform_QueryInterface(filter->mixer, &IID_IMFAttributes, (void **)&attributes))) + return FALSE; + + ret = SUCCEEDED(IMFAttributes_GetUINT32(attributes, &MF_SA_D3D_AWARE, &value)) && value; + IMFAttributes_Release(attributes); + return ret; +} + +static HRESULT evr_init_services(struct evr *filter) +{ + IMFTopologyServiceLookupClient *lookup_client; + HRESULT hr; + + if (SUCCEEDED(hr = IMFTransform_QueryInterface(filter->mixer, &IID_IMFTopologyServiceLookupClient, + (void **)&lookup_client))) + { + filter->flags |= EVR_INIT_SERVICES; + if (SUCCEEDED(hr = IMFTopologyServiceLookupClient_InitServicePointers(lookup_client, + &filter->IMFTopologyServiceLookup_iface))) + { + filter->flags |= EVR_MIXER_INITED_SERVICES; + } + filter->flags &= ~EVR_INIT_SERVICES; + IMFTopologyServiceLookupClient_Release(lookup_client); + } + + if (FAILED(hr)) return hr; + + /* Set device manager that presenter should have created. */ + if (evr_is_mixer_d3d_aware(filter)) + { + IUnknown *device_manager; + IMFGetService *gs; + + if (SUCCEEDED(IUnknown_QueryInterface(filter->presenter, &IID_IMFGetService, (void **)&gs))) + { + if (SUCCEEDED(IMFGetService_GetService(gs, &MR_VIDEO_RENDER_SERVICE, &IID_IDirect3DDeviceManager9, + (void **)&device_manager))) + { + IMFTransform_ProcessMessage(filter->mixer, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)device_manager); + IUnknown_Release(device_manager); + } + + IMFGetService_Release(gs); + } + } + + if (SUCCEEDED(hr = IMFVideoPresenter_QueryInterface(filter->presenter, &IID_IMFTopologyServiceLookupClient, + (void **)&lookup_client))) + { + filter->flags |= EVR_INIT_SERVICES; + if (SUCCEEDED(hr = IMFTopologyServiceLookupClient_InitServicePointers(lookup_client, + &filter->IMFTopologyServiceLookup_iface))) + { + filter->flags |= EVR_PRESENTER_INITED_SERVICES; + } + filter->flags &= ~EVR_INIT_SERVICES; + IMFTopologyServiceLookupClient_Release(lookup_client); + } + + return hr; +} + +static void evr_release_services(struct evr *filter) +{ + IMFTopologyServiceLookupClient *lookup_client; + + if (filter->flags & EVR_MIXER_INITED_SERVICES && SUCCEEDED(IMFTransform_QueryInterface(filter->mixer, + &IID_IMFTopologyServiceLookupClient, (void **)&lookup_client))) + { + IMFTopologyServiceLookupClient_ReleaseServicePointers(lookup_client); + IMFTopologyServiceLookupClient_Release(lookup_client); + filter->flags &= ~EVR_MIXER_INITED_SERVICES; + } + + if (filter->flags & EVR_PRESENTER_INITED_SERVICES && SUCCEEDED(IMFVideoPresenter_QueryInterface(filter->presenter, + &IID_IMFTopologyServiceLookupClient, (void **)&lookup_client))) + { + IMFTopologyServiceLookupClient_ReleaseServicePointers(lookup_client); + IMFTopologyServiceLookupClient_Release(lookup_client); + filter->flags &= ~EVR_PRESENTER_INITED_SERVICES; + } +} + static void evr_destroy(struct strmbase_renderer *iface) { struct evr *filter = impl_from_strmbase_renderer(iface); @@ -142,8 +241,37 @@ static HRESULT evr_render(struct strmbase_renderer *iface, IMediaSample *sample)
static HRESULT evr_query_accept(struct strmbase_renderer *iface, const AM_MEDIA_TYPE *mt) { - FIXME("Not implemented.\n"); - return E_NOTIMPL; + struct evr *filter = impl_from_strmbase_renderer(iface); + IMFMediaType *media_type; + HRESULT hr = S_OK; + + EnterCriticalSection(&filter->renderer.filter.filter_cs); + + if (!filter->presenter) + hr = evr_initialize(filter, NULL, NULL); + + if (SUCCEEDED(hr)) + hr = evr_init_services(filter); + + if (SUCCEEDED(hr)) + hr = MFCreateMediaType(&media_type); + + if (SUCCEEDED(hr)) + { + if (SUCCEEDED(hr = MFInitMediaTypeFromAMMediaType(media_type, mt))) + { + /* TODO: some pin -> mixer input mapping is necessary to test the substreams. */ + hr = IMFTransform_SetInputType(filter->mixer, 0, media_type, MFT_SET_TYPE_TEST_ONLY); + } + + IMFMediaType_Release(media_type); + + evr_release_services(filter); + } + + LeaveCriticalSection(&filter->renderer.filter.filter_cs); + + return hr; }
static const struct strmbase_renderer_ops renderer_ops = @@ -419,10 +547,37 @@ static ULONG WINAPI filter_service_lookup_Release(IMFTopologyServiceLookup *ifac static HRESULT WINAPI filter_service_lookup_LookupService(IMFTopologyServiceLookup *iface, MF_SERVICE_LOOKUP_TYPE lookup_type, DWORD index, REFGUID service, REFIID riid, void **objects, DWORD *num_objects) { - FIXME("iface %p, lookup_type %d, index %lu, service %s, riid %s, objects %p, num_objects %p.\n", + struct evr *filter = impl_from_IMFTopologyServiceLookup(iface); + HRESULT hr = S_OK; + + TRACE("iface %p, lookup_type %d, index %lu, service %s, riid %s, objects %p, num_objects %p.\n", iface, lookup_type, index, debugstr_guid(service), debugstr_guid(riid), objects, num_objects);
- return MF_E_NOTACCEPTING; + EnterCriticalSection(&filter->renderer.filter.filter_cs); + + if (!(filter->flags & EVR_INIT_SERVICES)) + hr = MF_E_NOTACCEPTING; + else if (IsEqualGUID(service, &MR_VIDEO_RENDER_SERVICE)) + { + if (IsEqualIID(riid, &IID_IMediaEventSink)) + { + *objects = &filter->IMediaEventSink_iface; + IUnknown_AddRef((IUnknown *)*objects); + } + } + else if (IsEqualGUID(service, &MR_VIDEO_MIXER_SERVICE)) + { + hr = IMFTransform_QueryInterface(filter->mixer, riid, objects); + } + else + { + WARN("Unsupported service %s.\n", debugstr_guid(service)); + hr = MF_E_UNSUPPORTED_SERVICE; + } + + LeaveCriticalSection(&filter->renderer.filter.filter_cs); + + return hr; }
static const IMFTopologyServiceLookupVtbl filter_service_lookup_vtbl = diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c index b632323ebb5..acfb92f2ea5 100644 --- a/dlls/evr/tests/evr.c +++ b/dlls/evr/tests/evr.c @@ -637,6 +637,59 @@ static void test_service_lookup(void) ok(!ref, "Got outstanding refcount %ld.\n", ref); }
+static void test_query_accept(void) +{ + IBaseFilter *filter = create_evr(); + AM_MEDIA_TYPE req_mt = {{0}}; + VIDEOINFOHEADER vih = + { + {0}, {0}, 0, 0, 0, + {sizeof(BITMAPINFOHEADER), 32, 24, 1, 0, 0xdeadbeef} + }; + unsigned int i; + HRESULT hr; + ULONG ref; + IPin *pin; + + static const GUID *subtype_tests[] = + { + &MEDIASUBTYPE_RGB32, + &MEDIASUBTYPE_YUY2, + }; + + static const GUID *unsupported_subtype_tests[] = + { + &MEDIASUBTYPE_RGB8, + }; + + IBaseFilter_FindPin(filter, L"EVR Input0", &pin); + + req_mt.majortype = MEDIATYPE_Video; + req_mt.formattype = FORMAT_VideoInfo; + req_mt.cbFormat = sizeof(VIDEOINFOHEADER); + req_mt.pbFormat = (BYTE *)&vih; + + for (i = 0; i < ARRAY_SIZE(subtype_tests); ++i) + { + memcpy(&req_mt.subtype, subtype_tests[i], sizeof(GUID)); + hr = IPin_QueryAccept(pin, &req_mt); + todo_wine_if(i) + ok(hr == S_OK, "Got hr %#lx.\n", hr); + } + + for (i = 0; i < ARRAY_SIZE(unsupported_subtype_tests); ++i) + { + memcpy(&req_mt.subtype, unsupported_subtype_tests[i], sizeof(GUID)); + hr = IPin_QueryAccept(pin, &req_mt); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + } + + IPin_Release(pin); + + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %ld.\n", ref); +} + static IMFMediaType * create_video_type(const GUID *subtype) { IMFMediaType *video_type; @@ -3311,6 +3364,7 @@ START_TEST(evr) test_misc_flags(); test_display_control(); test_service_lookup(); + test_query_accept();
test_default_mixer(); test_default_mixer_type_negotiation();
This merge request was approved by Zebediah Figura.