Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/evr/Makefile.in | 3 +- dlls/evr/evr.spec | 2 +- dlls/evr/evr_classes.idl | 7 ++ dlls/evr/evr_private.h | 23 +++++ dlls/evr/main.c | 1 + dlls/evr/presenter.c | 218 +++++++++++++++++++++++++++++++++++++++ dlls/evr/tests/evr.c | 35 +++++++ include/evr.idl | 1 + 8 files changed, 288 insertions(+), 2 deletions(-) create mode 100644 dlls/evr/presenter.c
diff --git a/dlls/evr/Makefile.in b/dlls/evr/Makefile.in index 5671511f6ae..daaf9cc872a 100644 --- a/dlls/evr/Makefile.in +++ b/dlls/evr/Makefile.in @@ -8,6 +8,7 @@ EXTRADLLFLAGS = -mno-cygwin C_SRCS = \ evr.c \ main.c \ - mixer.c + mixer.c \ + presenter.c
IDL_SRCS = evr_classes.idl diff --git a/dlls/evr/evr.spec b/dlls/evr/evr.spec index 214f2b81d85..e46cb04f644 100644 --- a/dlls/evr/evr.spec +++ b/dlls/evr/evr.spec @@ -17,7 +17,7 @@ @ stub MFCreateVideoMixerAndPresenter @ stub MFCreateVideoOTA @ stub MFCreateVideoPresenter2 -@ stub MFCreateVideoPresenter +@ stdcall MFCreateVideoPresenter(ptr ptr ptr ptr) @ stub MFCreateVideoSampleAllocator @ stdcall MFCreateVideoSampleFromSurface(ptr ptr) @ stub MFGetPlaneSize diff --git a/dlls/evr/evr_classes.idl b/dlls/evr/evr_classes.idl index 31f0d34fe75..1885a34d77f 100644 --- a/dlls/evr/evr_classes.idl +++ b/dlls/evr/evr_classes.idl @@ -31,3 +31,10 @@ coclass EnhancedVideoRenderer { interface IBaseFilter; } uuid(e474e05a-ab65-4f6a-827c-218b1baaf31f) ] coclass MFVideoMixer9 { interface IMFTransform; } + +[ + helpstring("MF Video Presenter"), + threading(both), + uuid(98455561-5136-4d28-ab08-4cee40ea2781) +] +coclass MFVideoPresenter9 { interface IMFVideoPresenter; } diff --git a/dlls/evr/evr_private.h b/dlls/evr/evr_private.h index 5698eb0c21e..7ae83140579 100644 --- a/dlls/evr/evr_private.h +++ b/dlls/evr/evr_private.h @@ -22,8 +22,31 @@ #include "dshow.h" #include "evr.h" #include "wine/strmbase.h" +#include "wine/debug.h" + +static inline const char *debugstr_time(LONGLONG time) +{ + ULONGLONG abstime = time >= 0 ? time : -time; + unsigned int i = 0, j = 0; + char buffer[23], rev[23]; + + while (abstime || i <= 8) + { + buffer[i++] = '0' + (abstime % 10); + abstime /= 10; + if (i == 7) buffer[i++] = '.'; + } + if (time < 0) buffer[i++] = '-'; + + while (i--) rev[j++] = buffer[i]; + while (rev[j-1] == '0' && rev[j-2] != '.') --j; + rev[j] = 0; + + return wine_dbg_sprintf("%s", rev); +}
HRESULT evr_filter_create(IUnknown *outer_unk, void **ppv) DECLSPEC_HIDDEN; HRESULT evr_mixer_create(IUnknown *outer_unk, void **ppv) DECLSPEC_HIDDEN; +HRESULT evr_presenter_create(IUnknown *outer_unk, void **ppv) DECLSPEC_HIDDEN;
#endif /* __EVR_PRIVATE_INCLUDED__ */ diff --git a/dlls/evr/main.c b/dlls/evr/main.c index 85c81f13604..2c6db8430ba 100644 --- a/dlls/evr/main.c +++ b/dlls/evr/main.c @@ -72,6 +72,7 @@ static const struct object_creation_info object_creation[] = { { &CLSID_EnhancedVideoRenderer, evr_filter_create }, { &CLSID_MFVideoMixer9, evr_mixer_create }, + { &CLSID_MFVideoPresenter9, evr_presenter_create }, };
static HRESULT WINAPI classfactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj) diff --git a/dlls/evr/presenter.c b/dlls/evr/presenter.c new file mode 100644 index 00000000000..234c1f076ca --- /dev/null +++ b/dlls/evr/presenter.c @@ -0,0 +1,218 @@ +/* + * Copyright 2020 Nikolay Sivov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS + +#include "evr.h" +#include "d3d9.h" +#include "mfapi.h" +#include "mferror.h" + +#include "evr_classes.h" +#include "evr_private.h" + +#include "wine/debug.h" +#include "wine/heap.h" + +WINE_DEFAULT_DEBUG_CHANNEL(evr); + +struct video_presenter +{ + IMFVideoPresenter IMFVideoPresenter_iface; + IUnknown IUnknown_inner; + IUnknown *outer_unk; + LONG refcount; +}; + +static struct video_presenter *impl_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct video_presenter, IUnknown_inner); +} + +static struct video_presenter *impl_from_IMFVideoPresenter(IMFVideoPresenter *iface) +{ + return CONTAINING_RECORD(iface, struct video_presenter, IMFVideoPresenter_iface); +} + +static HRESULT WINAPI video_presenter_inner_QueryInterface(IUnknown *iface, REFIID riid, void **obj) +{ + struct video_presenter *presenter = impl_from_IUnknown(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + } + else if (IsEqualIID(riid, &IID_IMFClockStateSink) + || IsEqualIID(riid, &IID_IMFVideoPresenter)) + { + *obj = &presenter->IMFVideoPresenter_iface; + } + else + { + WARN("Unimplemented interface %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*obj); + return S_OK; +} + +static ULONG WINAPI video_presenter_inner_AddRef(IUnknown *iface) +{ + struct video_presenter *presenter = impl_from_IUnknown(iface); + ULONG refcount = InterlockedIncrement(&presenter->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI video_presenter_inner_Release(IUnknown *iface) +{ + struct video_presenter *presenter = impl_from_IUnknown(iface); + ULONG refcount = InterlockedDecrement(&presenter->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + { + heap_free(presenter); + } + + return refcount; +} + +static const IUnknownVtbl video_presenter_inner_vtbl = +{ + video_presenter_inner_QueryInterface, + video_presenter_inner_AddRef, + video_presenter_inner_Release, +}; + +static HRESULT WINAPI video_presenter_QueryInterface(IMFVideoPresenter *iface, REFIID riid, void **obj) +{ + struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface); + return IUnknown_QueryInterface(presenter->outer_unk, riid, obj); +} + +static ULONG WINAPI video_presenter_AddRef(IMFVideoPresenter *iface) +{ + struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface); + return IUnknown_AddRef(presenter->outer_unk); +} + +static ULONG WINAPI video_presenter_Release(IMFVideoPresenter *iface) +{ + struct video_presenter *presenter = impl_from_IMFVideoPresenter(iface); + return IUnknown_Release(presenter->outer_unk); +} + +static HRESULT WINAPI video_presenter_OnClockStart(IMFVideoPresenter *iface, MFTIME systime, LONGLONG offset) +{ + FIXME("%p, %s, %s.\n", iface, debugstr_time(systime), wine_dbgstr_longlong(offset)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI video_presenter_OnClockStop(IMFVideoPresenter *iface, MFTIME systime) +{ + FIXME("%p, %s.\n", iface, debugstr_time(systime)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI video_presenter_OnClockPause(IMFVideoPresenter *iface, MFTIME systime) +{ + FIXME("%p, %s.\n", iface, debugstr_time(systime)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI video_presenter_OnClockRestart(IMFVideoPresenter *iface, MFTIME systime) +{ + FIXME("%p, %s.\n", iface, debugstr_time(systime)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI video_presenter_OnClockSetRate(IMFVideoPresenter *iface, MFTIME systime, float rate) +{ + FIXME("%p, %s, %f.\n", iface, debugstr_time(systime), rate); + + return E_NOTIMPL; +} + +static HRESULT WINAPI video_presenter_ProcessMessage(IMFVideoPresenter *iface, MFVP_MESSAGE_TYPE message, ULONG_PTR param) +{ + FIXME("%p, %d, %lu.\n", iface, message, param); + + return E_NOTIMPL; +} + +static HRESULT WINAPI video_presenter_GetCurrentMediaType(IMFVideoPresenter *iface, IMFVideoMediaType **media_type) +{ + FIXME("%p, %p.\n", iface, media_type); + + return E_NOTIMPL; +} + +static const IMFVideoPresenterVtbl video_presenter_vtbl = +{ + video_presenter_QueryInterface, + video_presenter_AddRef, + video_presenter_Release, + video_presenter_OnClockStart, + video_presenter_OnClockStop, + video_presenter_OnClockPause, + video_presenter_OnClockRestart, + video_presenter_OnClockSetRate, + video_presenter_ProcessMessage, + video_presenter_GetCurrentMediaType, +}; + +HRESULT WINAPI MFCreateVideoPresenter(IUnknown *owner, REFIID riid_device, REFIID riid, void **obj) +{ + TRACE("%p, %s, %s, %p.\n", owner, debugstr_guid(riid_device), debugstr_guid(riid), obj); + + *obj = NULL; + + if (!IsEqualIID(riid_device, &IID_IDirect3DDevice9)) + return E_INVALIDARG; + + return CoCreateInstance(&CLSID_MFVideoPresenter9, owner, CLSCTX_INPROC_SERVER, riid, obj); +} + +HRESULT evr_presenter_create(IUnknown *outer, void **out) +{ + struct video_presenter *object; + + if (!(object = heap_alloc(sizeof(*object)))) + return E_OUTOFMEMORY; + + object->IMFVideoPresenter_iface.lpVtbl = &video_presenter_vtbl; + object->IUnknown_inner.lpVtbl = &video_presenter_inner_vtbl; + object->outer_unk = outer ? outer : &object->IUnknown_inner; + object->refcount = 1; + + *out = &object->IUnknown_inner; + + return S_OK; +} diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c index 70fc6b18e2f..6805a7ae2b7 100644 --- a/dlls/evr/tests/evr.c +++ b/dlls/evr/tests/evr.c @@ -117,6 +117,7 @@ static IUnknown test_outer = {&outer_vtbl}; static void test_aggregation(void) { IBaseFilter *filter, *filter2; + IMFVideoPresenter *presenter; IUnknown *unk, *unk2; HRESULT hr; ULONG ref; @@ -171,6 +172,25 @@ static void test_aggregation(void) ref = IUnknown_Release(unk); ok(!ref, "Got unexpected refcount %d.\n", ref); ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref); + + /* Default presenter. */ + presenter = (void *)0xdeadbeef; + hr = CoCreateInstance(&CLSID_MFVideoPresenter9, &test_outer, CLSCTX_INPROC_SERVER, &IID_IMFVideoPresenter, + (void **)&presenter); + ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr); + ok(!presenter, "Got interface %p.\n", presenter); + + hr = CoCreateInstance(&CLSID_MFVideoPresenter9, &test_outer, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&unk); + ok(hr == S_OK || broken(hr == E_FAIL) /* WinXP */, "Unexpected hr %#x.\n", hr); + if (SUCCEEDED(hr)) + { + ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref); + ok(unk != &test_outer, "Returned IUnknown should not be outer IUnknown.\n"); + ref = get_refcount(unk); + ok(ref == 1, "Got unexpected refcount %d.\n", ref); + + IUnknown_Release(unk); + } }
#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c) @@ -846,6 +866,20 @@ done: DestroyWindow(window); }
+static void test_default_presenter(void) +{ + IMFVideoPresenter *presenter; + HRESULT hr; + + hr = MFCreateVideoPresenter(NULL, &IID_IMFVideoPresenter, &IID_IMFVideoPresenter, (void **)&presenter); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = MFCreateVideoPresenter(NULL, &IID_IDirect3DDevice9, &IID_IMFVideoPresenter, (void **)&presenter); + ok(hr == S_OK || broken(hr == E_FAIL) /* WinXP */, "Failed to create default presenter, hr %#x.\n", hr); + if (SUCCEEDED(hr)) + IMFVideoPresenter_Release(presenter); +} + START_TEST(evr) { CoInitialize(NULL); @@ -860,6 +894,7 @@ START_TEST(evr) test_default_mixer(); test_default_mixer_type_negotiation(); test_surface_sample(); + test_default_presenter();
CoUninitialize(); } diff --git a/include/evr.idl b/include/evr.idl index 4599e298790..5a623c2c29c 100644 --- a/include/evr.idl +++ b/include/evr.idl @@ -225,4 +225,5 @@ cpp_quote("DEFINE_GUID(MR_BUFFER_SERVICE, 0xa562248c, 0x9ac6, 0x4ffc, 0x9f, 0xba cpp_quote("DEFINE_GUID(VIDEO_ZOOM_RECT, 0x7aaa1638, 0x1b7f, 0x4c93, 0xbd, 0x89, 0x5b, 0x9c, 0x9f, 0xb6, 0xfc, 0xf0);")
cpp_quote("HRESULT WINAPI MFCreateVideoMixer(IUnknown *owner, REFIID riid_device, REFIID riid, void **obj);") +cpp_quote("HRESULT WINAPI MFCreateVideoPresenter(IUnknown *owner, REFIID riid_device, REFIID riid, void **obj);") cpp_quote("HRESULT WINAPI MFCreateVideoSampleFromSurface(IUnknown *surface, IMFSample **sample);")