Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/evr.c | 333 +++++++++++++++++++++++++++------------------ dlls/mf/tests/mf.c | 8 +- 2 files changed, 208 insertions(+), 133 deletions(-)
diff --git a/dlls/mf/evr.c b/dlls/mf/evr.c index c5b2ceecd67..e90cf686f26 100644 --- a/dlls/mf/evr.c +++ b/dlls/mf/evr.c @@ -854,12 +854,195 @@ static ULONG WINAPI video_renderer_Release(IMFVideoRenderer *iface) return IMFMediaSink_Release(&renderer->IMFMediaSink_iface); }
+static HRESULT video_renderer_create_mixer(IMFAttributes *attributes, IMFTransform **out) +{ + unsigned int flags = 0; + IMFActivate *activate; + CLSID clsid; + HRESULT hr; + + if (attributes && SUCCEEDED(hr = IMFAttributes_GetUnknown(attributes, &MF_ACTIVATE_CUSTOM_VIDEO_MIXER_ACTIVATE, + &IID_IMFActivate, (void **)&activate))) + { + IMFAttributes_GetUINT32(attributes, &MF_ACTIVATE_CUSTOM_VIDEO_MIXER_FLAGS, &flags); + hr = IMFActivate_ActivateObject(activate, &IID_IMFTransform, (void **)out); + IMFActivate_Release(activate); + if (SUCCEEDED(hr) || !(flags & MF_ACTIVATE_CUSTOM_MIXER_ALLOWFAIL)) + return hr; + } + + if (!attributes || FAILED(IMFAttributes_GetGUID(attributes, &MF_ACTIVATE_CUSTOM_VIDEO_MIXER_CLSID, &clsid))) + memcpy(&clsid, &CLSID_MFVideoMixer9, sizeof(clsid)); + + return CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)out); +} + +static HRESULT video_renderer_create_presenter(IMFAttributes *attributes, IMFVideoPresenter **out) +{ + unsigned int flags = 0; + IMFActivate *activate; + CLSID clsid; + HRESULT hr; + + if (attributes && SUCCEEDED(IMFAttributes_GetUnknown(attributes, &MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_ACTIVATE, + &IID_IMFActivate, (void **)&activate))) + { + IMFAttributes_GetUINT32(attributes, &MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_FLAGS, &flags); + hr = IMFActivate_ActivateObject(activate, &IID_IMFVideoPresenter, (void **)out); + IMFActivate_Release(activate); + if (SUCCEEDED(hr) || !(flags & MF_ACTIVATE_CUSTOM_PRESENTER_ALLOWFAIL)) + return hr; + } + + if (!attributes || FAILED(IMFAttributes_GetGUID(attributes, &MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_CLSID, &clsid))) + memcpy(&clsid, &CLSID_MFVideoPresenter9, sizeof(clsid)); + + return CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFVideoPresenter, (void **)out); +} + +static HRESULT video_renderer_configure_mixer(struct video_renderer *renderer) +{ + IMFTopologyServiceLookupClient *lookup_client; + HRESULT hr; + + if (SUCCEEDED(hr = IMFTransform_QueryInterface(renderer->mixer, &IID_IMFTopologyServiceLookupClient, + (void **)&lookup_client))) + { + renderer->flags |= EVR_INIT_SERVICES; + if (SUCCEEDED(hr = IMFTopologyServiceLookupClient_InitServicePointers(lookup_client, + &renderer->IMFTopologyServiceLookup_iface))) + { + renderer->flags |= EVR_MIXER_INITED_SERVICES; + } + renderer->flags &= ~EVR_INIT_SERVICES; + IMFTopologyServiceLookupClient_Release(lookup_client); + } + + if (SUCCEEDED(hr)) + { + unsigned int input_count, output_count; + unsigned int *ids, *oids; + size_t i; + + /* Create stream sinks for inputs that mixer already has by default. */ + if (SUCCEEDED(IMFTransform_GetStreamCount(renderer->mixer, &input_count, &output_count))) + { + ids = heap_calloc(input_count, sizeof(*ids)); + oids = heap_calloc(output_count, sizeof(*oids)); + + if (ids && oids) + { + if (SUCCEEDED(IMFTransform_GetStreamIDs(renderer->mixer, input_count, ids, output_count, oids))) + { + for (i = 0; i < input_count; ++i) + { + video_renderer_add_stream(renderer, ids[i], NULL); + } + } + + } + + heap_free(ids); + heap_free(oids); + } + } + + return hr; +} + +static HRESULT video_renderer_configure_presenter(struct video_renderer *renderer) +{ + IMFTopologyServiceLookupClient *lookup_client; + HRESULT hr; + + if (SUCCEEDED(hr = IMFVideoPresenter_QueryInterface(renderer->presenter, &IID_IMFTopologyServiceLookupClient, + (void **)&lookup_client))) + { + renderer->flags |= EVR_INIT_SERVICES; + if (SUCCEEDED(hr = IMFTopologyServiceLookupClient_InitServicePointers(lookup_client, + &renderer->IMFTopologyServiceLookup_iface))) + { + renderer->flags |= EVR_PRESENTER_INITED_SERVICES; + } + renderer->flags &= ~EVR_INIT_SERVICES; + IMFTopologyServiceLookupClient_Release(lookup_client); + } + + return hr; +} + +static HRESULT video_renderer_initialize(struct video_renderer *renderer, IMFTransform *mixer, + IMFVideoPresenter *presenter) +{ + HRESULT hr; + + if (renderer->mixer) + { + IMFTransform_Release(renderer->mixer); + renderer->mixer = NULL; + } + + if (renderer->presenter) + { + IMFVideoPresenter_Release(renderer->presenter); + renderer->presenter = NULL; + } + + renderer->mixer = mixer; + IMFTransform_AddRef(renderer->mixer); + + renderer->presenter = presenter; + IMFVideoPresenter_AddRef(renderer->presenter); + + if (SUCCEEDED(hr = video_renderer_configure_mixer(renderer))) + hr = video_renderer_configure_presenter(renderer); + + return hr; +} + static HRESULT WINAPI video_renderer_InitializeRenderer(IMFVideoRenderer *iface, IMFTransform *mixer, IMFVideoPresenter *presenter) { - FIXME("%p, %p, %p.\n", iface, mixer, presenter); + struct video_renderer *renderer = impl_from_IMFVideoRenderer(iface); + HRESULT hr;
- return E_NOTIMPL; + TRACE("%p, %p, %p.\n", iface, mixer, presenter); + + if (mixer) + IMFTransform_AddRef(mixer); + else if (FAILED(hr = video_renderer_create_mixer(NULL, &mixer))) + { + WARN("Failed to create default mixer object, hr %#x.\n", hr); + return hr; + } + + if (presenter) + IMFVideoPresenter_AddRef(presenter); + else if (FAILED(hr = video_renderer_create_presenter(NULL, &presenter))) + { + WARN("Failed to create default presenter, hr %#x.\n", hr); + IMFTransform_Release(mixer); + return hr; + } + + EnterCriticalSection(&renderer->cs); + + if (renderer->flags & EVR_SHUT_DOWN) + hr = MF_E_SHUTDOWN; + else + { + /* FIXME: check clock state */ + /* FIXME: check that streams are not initialized */ + + hr = video_renderer_initialize(renderer, mixer, presenter); + } + + LeaveCriticalSection(&renderer->cs); + + IMFTransform_Release(mixer); + IMFVideoPresenter_Release(presenter); + + return hr; }
static const IMFVideoRendererVtbl video_renderer_vtbl = @@ -1191,128 +1374,11 @@ static const IMediaEventSinkVtbl media_event_sink_vtbl = video_renderer_event_sink_Notify, };
-static HRESULT video_renderer_create_mixer(struct video_renderer *renderer, IMFAttributes *attributes, - IMFTransform **out) -{ - IMFTopologyServiceLookupClient *lookup_client; - unsigned int flags = 0; - IMFActivate *activate; - CLSID clsid; - HRESULT hr; - - if (SUCCEEDED(hr = IMFAttributes_GetUnknown(attributes, &MF_ACTIVATE_CUSTOM_VIDEO_MIXER_ACTIVATE, - &IID_IMFActivate, (void **)&activate))) - { - IMFAttributes_GetUINT32(attributes, &MF_ACTIVATE_CUSTOM_VIDEO_MIXER_FLAGS, &flags); - hr = IMFActivate_ActivateObject(activate, &IID_IMFTransform, (void **)out); - IMFActivate_Release(activate); - if (FAILED(hr) && !(flags & MF_ACTIVATE_CUSTOM_MIXER_ALLOWFAIL)) - return hr; - } - - /* Activation object failed, use class activation. */ - if (FAILED(hr)) - { - if (FAILED(IMFAttributes_GetGUID(attributes, &MF_ACTIVATE_CUSTOM_VIDEO_MIXER_CLSID, &clsid))) - memcpy(&clsid, &CLSID_MFVideoMixer9, sizeof(clsid)); - hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)out); - } - - if (FAILED(hr)) - { - WARN("Failed to create a mixer object, hr %#x.\n", hr); - return hr; - } - - if (SUCCEEDED(hr = IMFTransform_QueryInterface(*out, &IID_IMFTopologyServiceLookupClient, - (void **)&lookup_client))) - { - renderer->flags |= EVR_INIT_SERVICES; - if (SUCCEEDED(hr = IMFTopologyServiceLookupClient_InitServicePointers(lookup_client, - &renderer->IMFTopologyServiceLookup_iface))) - { - renderer->flags |= EVR_MIXER_INITED_SERVICES; - } - renderer->flags &= ~EVR_INIT_SERVICES; - IMFTopologyServiceLookupClient_Release(lookup_client); - } - - if (SUCCEEDED(hr)) - { - unsigned int input_count, output_count; - unsigned int *ids, *oids; - size_t i; - - /* Create stream sinks for inputs that mixer already has by default. */ - if (SUCCEEDED(IMFTransform_GetStreamCount(*out, &input_count, &output_count))) - { - ids = heap_calloc(input_count, sizeof(*ids)); - oids = heap_calloc(output_count, sizeof(*oids)); - - if (ids && oids) - { - if (SUCCEEDED(IMFTransform_GetStreamIDs(*out, input_count, ids, output_count, oids))) - { - for (i = 0; i < input_count; ++i) - { - video_renderer_add_stream(renderer, ids[i], NULL); - } - } - - } - - heap_free(ids); - heap_free(oids); - } - } - - return hr; -} - -static HRESULT video_renderer_create_presenter(struct video_renderer *renderer, IMFAttributes *attributes, - IMFVideoPresenter **out) -{ - IMFTopologyServiceLookupClient *lookup_client; - unsigned int flags = 0; - IMFActivate *activate; - CLSID clsid; - HRESULT hr; - - if (SUCCEEDED(IMFAttributes_GetUnknown(attributes, &MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_ACTIVATE, - &IID_IMFActivate, (void **)&activate))) - { - IMFAttributes_GetUINT32(attributes, &MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_FLAGS, &flags); - hr = IMFActivate_ActivateObject(activate, &IID_IMFVideoPresenter, (void **)out); - IMFActivate_Release(activate); - if (FAILED(hr) && !(flags & MF_ACTIVATE_CUSTOM_PRESENTER_ALLOWFAIL)) - return hr; - } - - if (FAILED(IMFAttributes_GetGUID(attributes, &MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_CLSID, &clsid))) - memcpy(&clsid, &CLSID_MFVideoPresenter9, sizeof(clsid)); - - if (SUCCEEDED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFVideoPresenter, (void **)out))) - { - if (SUCCEEDED(hr = IMFVideoPresenter_QueryInterface(*out, &IID_IMFTopologyServiceLookupClient, - (void **)&lookup_client))) - { - renderer->flags |= EVR_INIT_SERVICES; - if (SUCCEEDED(hr = IMFTopologyServiceLookupClient_InitServicePointers(lookup_client, - &renderer->IMFTopologyServiceLookup_iface))) - { - renderer->flags |= EVR_PRESENTER_INITED_SERVICES; - } - renderer->flags &= ~EVR_INIT_SERVICES; - IMFTopologyServiceLookupClient_Release(lookup_client); - } - } - - return hr; -} - static HRESULT evr_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj) { struct video_renderer *object; + IMFVideoPresenter *presenter; + IMFTransform *mixer; HRESULT hr;
TRACE("%p, %p, %p.\n", attributes, user_context, obj); @@ -1335,18 +1401,30 @@ static HRESULT evr_create_object(IMFAttributes *attributes, void *user_context, goto failed;
/* Create mixer and presenter. */ - if (FAILED(hr = video_renderer_create_mixer(object, attributes, &object->mixer))) + if (FAILED(hr = video_renderer_create_mixer(attributes, &mixer))) + goto failed; + + if (FAILED(hr = video_renderer_create_presenter(attributes, &presenter))) goto failed;
- if (FAILED(hr = video_renderer_create_presenter(object, attributes, &object->presenter))) + if (FAILED(hr = video_renderer_initialize(object, mixer, presenter))) goto failed;
+ IMFTransform_Release(mixer); + IMFVideoPresenter_Release(presenter); + *obj = (IUnknown *)&object->IMFMediaSink_iface;
return S_OK;
failed:
+ if (mixer) + IMFTransform_Release(mixer); + + if (presenter) + IMFVideoPresenter_Release(presenter); + video_renderer_release_services(object); IMFMediaSink_Release(&object->IMFMediaSink_iface);
@@ -1394,7 +1472,6 @@ HRESULT WINAPI MFCreateVideoRendererActivate(HWND hwnd, IMFActivate **activate) */ HRESULT WINAPI MFCreateVideoRenderer(REFIID riid, void **renderer) { - IMFAttributes *attributes; IUnknown *obj; HRESULT hr;
@@ -1402,13 +1479,7 @@ HRESULT WINAPI MFCreateVideoRenderer(REFIID riid, void **renderer)
*renderer = NULL;
- if (FAILED(hr = MFCreateAttributes(&attributes, 0))) - return hr; - - hr = evr_create_object(attributes, NULL, &obj); - IMFAttributes_Release(attributes); - - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr = evr_create_object(NULL, NULL, &obj))) { hr = IUnknown_QueryInterface(obj, riid, renderer); IUnknown_Release(obj); diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 0bc297cc69c..88cfa8d7625 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -3253,9 +3253,13 @@ static void test_evr(void) hr = CoInitialize(NULL); ok(hr == S_OK, "Failed to initialize, hr %#x.\n", hr);
- hr = MFCreateVideoRenderer(&IID_IUnknown, (void **)&unk); + hr = MFCreateVideoRenderer(&IID_IMFVideoRenderer, (void **)&video_renderer); ok(hr == S_OK, "Unexpected hr %#x.\n", hr); - IUnknown_Release(unk); + + hr = IMFVideoRenderer_InitializeRenderer(video_renderer, NULL, NULL); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + IMFVideoRenderer_Release(video_renderer);
hr = MFCreateVideoRendererActivate(NULL, NULL); ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/evr.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
diff --git a/dlls/mf/evr.c b/dlls/mf/evr.c index e90cf686f26..dc2b20ddf76 100644 --- a/dlls/mf/evr.c +++ b/dlls/mf/evr.c @@ -21,6 +21,9 @@ #include "mf_private.h" #include "uuids.h" #include "evr.h" +#include "d3d9.h" +#include "initguid.h" +#include "dxva2api.h"
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
@@ -903,6 +906,7 @@ static HRESULT video_renderer_create_presenter(IMFAttributes *attributes, IMFVid static HRESULT video_renderer_configure_mixer(struct video_renderer *renderer) { IMFTopologyServiceLookupClient *lookup_client; + IMFAttributes *attributes; HRESULT hr;
if (SUCCEEDED(hr = IMFTransform_QueryInterface(renderer->mixer, &IID_IMFTopologyServiceLookupClient, @@ -947,6 +951,24 @@ static HRESULT video_renderer_configure_mixer(struct video_renderer *renderer) } }
+ /* Set device manager that presenter should have created. */ + if (SUCCEEDED(IMFTransform_QueryInterface(renderer->mixer, &IID_IMFAttributes, (void **)&attributes))) + { + IDirect3DDeviceManager9 *device_manager; + unsigned int value; + + if (SUCCEEDED(IMFAttributes_GetUINT32(attributes, &MF_SA_D3D_AWARE, &value)) && value) + { + if (SUCCEEDED(MFGetService((IUnknown *)renderer->presenter, &MR_VIDEO_ACCELERATION_SERVICE, + &IID_IDirect3DDeviceManager9, (void **)&device_manager))) + { + IMFTransform_ProcessMessage(renderer->mixer, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)device_manager); + IDirect3DDeviceManager9_Release(device_manager); + } + } + IMFAttributes_Release(attributes); + } + return hr; }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/evr.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+)
diff --git a/dlls/mf/evr.c b/dlls/mf/evr.c index dc2b20ddf76..af5c5d31038 100644 --- a/dlls/mf/evr.c +++ b/dlls/mf/evr.c @@ -41,6 +41,7 @@ struct video_stream { IMFStreamSink IMFStreamSink_iface; IMFMediaTypeHandler IMFMediaTypeHandler_iface; + IMFGetService IMFGetService_iface; LONG refcount; unsigned int id; struct video_renderer *parent; @@ -123,6 +124,11 @@ static struct video_stream *impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler *i return CONTAINING_RECORD(iface, struct video_stream, IMFMediaTypeHandler_iface); }
+static struct video_stream *impl_from_stream_IMFGetService(IMFGetService *iface) +{ + return CONTAINING_RECORD(iface, struct video_stream, IMFGetService_iface); +} + static void video_renderer_release_services(struct video_renderer *renderer) { IMFTopologyServiceLookupClient *lookup_client; @@ -162,6 +168,10 @@ static HRESULT WINAPI video_stream_sink_QueryInterface(IMFStreamSink *iface, REF { *obj = &stream->IMFMediaTypeHandler_iface; } + else if (IsEqualIID(riid, &IID_IMFGetService)) + { + *obj = &stream->IMFGetService_iface; + }
if (*obj) { @@ -415,6 +425,39 @@ static const IMFMediaTypeHandlerVtbl video_stream_type_handler_vtbl = video_stream_typehandler_GetMajorType, };
+static HRESULT WINAPI video_stream_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj) +{ + struct video_stream *stream = impl_from_stream_IMFGetService(iface); + return IMFStreamSink_QueryInterface(&stream->IMFStreamSink_iface, riid, obj); +} + +static ULONG WINAPI video_stream_get_service_AddRef(IMFGetService *iface) +{ + struct video_stream *stream = impl_from_stream_IMFGetService(iface); + return IMFStreamSink_AddRef(&stream->IMFStreamSink_iface); +} + +static ULONG WINAPI video_stream_get_service_Release(IMFGetService *iface) +{ + struct video_stream *stream = impl_from_stream_IMFGetService(iface); + return IMFStreamSink_Release(&stream->IMFStreamSink_iface); +} + +static HRESULT WINAPI video_stream_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj) +{ + FIXME("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj); + + return E_NOTIMPL; +} + +static const IMFGetServiceVtbl video_stream_get_service_vtbl = +{ + video_stream_get_service_QueryInterface, + video_stream_get_service_AddRef, + video_stream_get_service_Release, + video_stream_get_service_GetService, +}; + static HRESULT video_renderer_stream_create(struct video_renderer *renderer, unsigned int id, struct video_stream **ret) { @@ -426,6 +469,7 @@ static HRESULT video_renderer_stream_create(struct video_renderer *renderer, uns
stream->IMFStreamSink_iface.lpVtbl = &video_stream_sink_vtbl; stream->IMFMediaTypeHandler_iface.lpVtbl = &video_stream_type_handler_vtbl; + stream->IMFGetService_iface.lpVtbl = &video_stream_get_service_vtbl; stream->refcount = 1;
if (FAILED(hr = MFCreateEventQueue(&stream->event_queue)))
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/Makefile.in | 1 + dlls/mf/evr.c | 27 +++++++++++++++++++++++++-- dlls/mf/tests/mf.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 66 insertions(+), 4 deletions(-)
diff --git a/dlls/mf/Makefile.in b/dlls/mf/Makefile.in index b64cdb4a64d..f1d0571d143 100644 --- a/dlls/mf/Makefile.in +++ b/dlls/mf/Makefile.in @@ -1,6 +1,7 @@ MODULE = mf.dll IMPORTLIB = mf IMPORTS = advapi32 mfplat ole32 uuid mfuuid strmiids +DELAYIMPORTS = evr
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/mf/evr.c b/dlls/mf/evr.c index af5c5d31038..ac3f17fa585 100644 --- a/dlls/mf/evr.c +++ b/dlls/mf/evr.c @@ -46,6 +46,7 @@ struct video_stream unsigned int id; struct video_renderer *parent; IMFMediaEventQueue *event_queue; + IMFVideoSampleAllocator *allocator; };
struct video_renderer @@ -203,6 +204,8 @@ static ULONG WINAPI video_stream_sink_Release(IMFStreamSink *iface) { if (stream->event_queue) IMFMediaEventQueue_Release(stream->event_queue); + if (stream->allocator) + IMFVideoSampleAllocator_Release(stream->allocator); heap_free(stream); }
@@ -445,7 +448,18 @@ static ULONG WINAPI video_stream_get_service_Release(IMFGetService *iface)
static HRESULT WINAPI video_stream_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj) { - FIXME("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj); + struct video_stream *stream = impl_from_stream_IMFGetService(iface); + + TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj); + + if (IsEqualGUID(service, &MR_VIDEO_ACCELERATION_SERVICE)) + { + if (IsEqualIID(riid, &IID_IMFVideoSampleAllocator)) + return IMFVideoSampleAllocator_QueryInterface(stream->allocator, riid, obj); + return E_NOINTERFACE; + } + + FIXME("Unsupported service %s.\n", debugstr_guid(service));
return E_NOTIMPL; } @@ -473,7 +487,10 @@ static HRESULT video_renderer_stream_create(struct video_renderer *renderer, uns stream->refcount = 1;
if (FAILED(hr = MFCreateEventQueue(&stream->event_queue))) - return hr; + goto failed; + + if (FAILED(hr = MFCreateVideoSampleAllocator(&IID_IMFVideoSampleAllocator, (void **)&stream->allocator))) + goto failed;
stream->parent = renderer; IMFMediaSink_AddRef(&stream->parent->IMFMediaSink_iface); @@ -482,6 +499,12 @@ static HRESULT video_renderer_stream_create(struct video_renderer *renderer, uns *ret = stream;
return S_OK; + +failed: + + IMFStreamSink_Release(&stream->IMFStreamSink_iface); + + return hr; }
static HRESULT WINAPI video_renderer_sink_QueryInterface(IMFMediaSink *iface, REFIID riid, void **obj) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 88cfa8d7625..bd6e66a5132 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -3235,16 +3235,20 @@ todo_wine
static void test_evr(void) { + IMFVideoSampleAllocatorCallback *allocator_callback; + IMFStreamSink *stream_sink, *stream_sink2; IMFMediaEventGenerator *ev_generator; + IMFVideoSampleAllocator *allocator; IMFMediaTypeHandler *type_handler; IMFVideoRenderer *video_renderer; IMFClockStateSink *clock_sink; IMFMediaSinkPreroll *preroll; IMFMediaSink *sink, *sink2; - IMFStreamSink *stream_sink; IMFActivate *activate; DWORD flags, count; + LONG sample_count; IMFGetService *gs; + IMFSample *sample; IUnknown *unk; UINT64 value; HRESULT hr; @@ -3292,9 +3296,43 @@ static void test_evr(void) ok(hr == S_OK, "Unexpected hr %#x.\n", hr); ok(IsEqualGUID(&guid, &MFMediaType_Video), "Unexpected type %s.\n", wine_dbgstr_guid(&guid));
- IMFStreamSink_Release(stream_sink); IMFMediaTypeHandler_Release(type_handler);
+ /* Stream uses an allocator. */ + hr = MFGetService((IUnknown *)stream_sink, &MR_VIDEO_ACCELERATION_SERVICE, &IID_IMFVideoSampleAllocator, + (void **)&allocator); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocator_QueryInterface(allocator, &IID_IMFVideoSampleAllocatorCallback, (void **)&allocator_callback); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + sample_count = 0; + hr = IMFVideoSampleAllocatorCallback_GetFreeSampleCount(allocator_callback, &sample_count); +todo_wine + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!sample_count, "Unexpected sample count %d.\n", sample_count); + + hr = IMFVideoSampleAllocator_AllocateSample(allocator, &sample); +todo_wine + ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr); + + IMFVideoSampleAllocatorCallback_Release(allocator_callback); + IMFVideoSampleAllocator_Release(allocator); + + /* Same test for a substream. */ + hr = IMFMediaSink_AddStreamSink(sink, 1, NULL, &stream_sink2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = MFGetService((IUnknown *)stream_sink2, &MR_VIDEO_ACCELERATION_SERVICE, &IID_IMFVideoSampleAllocator, + (void **)&allocator); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + IMFVideoSampleAllocator_Release(allocator); + + hr = IMFMediaSink_RemoveStreamSink(sink, 1); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + IMFStreamSink_Release(stream_sink2); + hr = IMFMediaSink_GetCharacteristics(sink, &flags); ok(hr == S_OK, "Unexpected hr %#x.\n", hr); ok(flags == (MEDIASINK_CAN_PREROLL | MEDIASINK_CLOCK_REQUIRED), "Unexpected flags %#x.\n", flags);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/evr/sample.c | 21 +++++++++++++++++-- dlls/evr/tests/evr.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 2 deletions(-)
diff --git a/dlls/evr/sample.c b/dlls/evr/sample.c index f371d920762..31e3ff43334 100644 --- a/dlls/evr/sample.c +++ b/dlls/evr/sample.c @@ -30,6 +30,9 @@ struct sample_allocator IMFVideoSampleAllocator IMFVideoSampleAllocator_iface; IMFVideoSampleAllocatorCallback IMFVideoSampleAllocatorCallback_iface; LONG refcount; + + IMFVideoSampleAllocatorNotify *callback; + CRITICAL_SECTION cs; };
static struct sample_allocator *impl_from_IMFVideoSampleAllocator(IMFVideoSampleAllocator *iface) @@ -87,6 +90,9 @@ static ULONG WINAPI sample_allocator_Release(IMFVideoSampleAllocator *iface)
if (!refcount) { + if (allocator->callback) + IMFVideoSampleAllocatorNotify_Release(allocator->callback); + DeleteCriticalSection(&allocator->cs); heap_free(allocator); }
@@ -156,9 +162,19 @@ static ULONG WINAPI sample_allocator_callback_Release(IMFVideoSampleAllocatorCal static HRESULT WINAPI sample_allocator_callback_SetCallback(IMFVideoSampleAllocatorCallback *iface, IMFVideoSampleAllocatorNotify *callback) { - FIXME("%p, %p.\n", iface, callback); + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
- return E_NOTIMPL; + TRACE("%p, %p.\n", iface, callback); + + EnterCriticalSection(&allocator->cs); + if (allocator->callback) + IMFVideoSampleAllocatorNotify_Release(allocator->callback); + allocator->callback = callback; + if (allocator->callback) + IMFVideoSampleAllocatorNotify_AddRef(allocator->callback); + LeaveCriticalSection(&allocator->cs); + + return S_OK; }
static HRESULT WINAPI sample_allocator_callback_GetFreeSampleCount(IMFVideoSampleAllocatorCallback *iface, @@ -191,6 +207,7 @@ HRESULT WINAPI MFCreateVideoSampleAllocator(REFIID riid, void **obj) object->IMFVideoSampleAllocator_iface.lpVtbl = &sample_allocator_vtbl; object->IMFVideoSampleAllocatorCallback_iface.lpVtbl = &sample_allocator_callback_vtbl; object->refcount = 1; + InitializeCriticalSection(&object->cs);
hr = IMFVideoSampleAllocator_QueryInterface(&object->IMFVideoSampleAllocator_iface, riid, obj); IMFVideoSampleAllocator_Release(&object->IMFVideoSampleAllocator_iface); diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c index 3ae36d9b5df..3951b813a02 100644 --- a/dlls/evr/tests/evr.c +++ b/dlls/evr/tests/evr.c @@ -1147,8 +1147,47 @@ static void test_MFCreateVideoMixerAndPresenter(void) IUnknown_Release(presenter); }
+static HRESULT WINAPI test_notify_callback_QueryInterface(IMFVideoSampleAllocatorNotify *iface, + REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorNotify) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFVideoSampleAllocatorNotify_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_notify_callback_AddRef(IMFVideoSampleAllocatorNotify *iface) +{ + return 2; +} + +static ULONG WINAPI test_notify_callback_Release(IMFVideoSampleAllocatorNotify *iface) +{ + return 1; +} + +static HRESULT WINAPI test_notify_callback_NotifyRelease(IMFVideoSampleAllocatorNotify *iface) +{ + return E_NOTIMPL; +} + +static const IMFVideoSampleAllocatorNotifyVtbl test_notify_callback_vtbl = +{ + test_notify_callback_QueryInterface, + test_notify_callback_AddRef, + test_notify_callback_Release, + test_notify_callback_NotifyRelease, +}; + static void test_MFCreateVideoSampleAllocator(void) { + IMFVideoSampleAllocatorNotify test_notify = { &test_notify_callback_vtbl }; IMFVideoSampleAllocatorCallback *allocator_cb; IMFVideoSampleAllocator *allocator; IMFVideoMediaType *video_type; @@ -1171,6 +1210,15 @@ static void test_MFCreateVideoSampleAllocator(void) hr = IMFVideoSampleAllocator_QueryInterface(allocator, &IID_IMFVideoSampleAllocatorCallback, (void **)&allocator_cb); ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ hr = IMFVideoSampleAllocatorCallback_SetCallback(allocator_cb, NULL); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocatorCallback_SetCallback(allocator_cb, &test_notify); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocatorCallback_SetCallback(allocator_cb, NULL); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + count = 10; hr = IMFVideoSampleAllocatorCallback_GetFreeSampleCount(allocator_cb, &count); todo_wine {
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/evr/sample.c | 12 ++++++++++-- dlls/evr/tests/evr.c | 14 ++++++++------ dlls/mf/tests/mf.c | 1 - 3 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/dlls/evr/sample.c b/dlls/evr/sample.c index 31e3ff43334..2887a37e8d9 100644 --- a/dlls/evr/sample.c +++ b/dlls/evr/sample.c @@ -32,6 +32,7 @@ struct sample_allocator LONG refcount;
IMFVideoSampleAllocatorNotify *callback; + unsigned int free_samples; CRITICAL_SECTION cs; };
@@ -180,9 +181,16 @@ static HRESULT WINAPI sample_allocator_callback_SetCallback(IMFVideoSampleAlloca static HRESULT WINAPI sample_allocator_callback_GetFreeSampleCount(IMFVideoSampleAllocatorCallback *iface, LONG *count) { - FIXME("%p, %p.\n", iface, count); + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
- return E_NOTIMPL; + TRACE("%p, %p.\n", iface, count); + + EnterCriticalSection(&allocator->cs); + if (count) + *count = allocator->free_samples; + LeaveCriticalSection(&allocator->cs); + + return S_OK; }
static const IMFVideoSampleAllocatorCallbackVtbl sample_allocator_callback_vtbl = diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c index 3951b813a02..7ad011d2a09 100644 --- a/dlls/evr/tests/evr.c +++ b/dlls/evr/tests/evr.c @@ -1219,12 +1219,14 @@ static void test_MFCreateVideoSampleAllocator(void) hr = IMFVideoSampleAllocatorCallback_SetCallback(allocator_cb, NULL); ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ hr = IMFVideoSampleAllocatorCallback_GetFreeSampleCount(allocator_cb, NULL); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + count = 10; hr = IMFVideoSampleAllocatorCallback_GetFreeSampleCount(allocator_cb, &count); -todo_wine { ok(hr == S_OK, "Unexpected hr %#x.\n", hr); ok(!count, "Unexpected count %d.\n", count); -} + hr = IMFVideoSampleAllocator_UninitializeSampleAllocator(allocator); todo_wine ok(hr == S_OK, "Unexpected hr %#x.\n", hr); @@ -1256,10 +1258,10 @@ todo_wine ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IMFVideoSampleAllocatorCallback_GetFreeSampleCount(allocator_cb, &count); -todo_wine { ok(hr == S_OK, "Unexpected hr %#x.\n", hr); +todo_wine ok(count == 1, "Unexpected count %d.\n", count); -} + sample = NULL; hr = IMFVideoSampleAllocator_AllocateSample(allocator, &sample); todo_wine @@ -1279,10 +1281,10 @@ todo_wine ok(get_refcount(sample) == 3, "Unexpected refcount %u.\n", get_refcount(sample));
hr = IMFVideoSampleAllocatorCallback_GetFreeSampleCount(allocator_cb, &count); -todo_wine { ok(hr == S_OK, "Unexpected hr %#x.\n", hr); +todo_wine ok(count == 4, "Unexpected count %d.\n", count); -} + if (sample) { hr = IMFSample_QueryInterface(sample, &IID_IMFDesiredSample, (void **)&unk); diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index bd6e66a5132..a63c353a4b5 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -3308,7 +3308,6 @@ static void test_evr(void)
sample_count = 0; hr = IMFVideoSampleAllocatorCallback_GetFreeSampleCount(allocator_callback, &sample_count); -todo_wine ok(hr == S_OK, "Unexpected hr %#x.\n", hr); ok(!sample_count, "Unexpected sample count %d.\n", sample_count);