From f143af50a35f77880babf817899a33e4579b1dd3 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Mon, 29 Aug 2022 15:36:47 +0300 Subject: [PATCH] evr/filter: Implement media type testing for QueryAccept(). Signed-off-by: Nikolay Sivov --- 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();