Only renderers should ever need to care about this.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/dsoundrender.c | 6 +++--- dlls/strmbase/renderer.c | 10 +++++----- dlls/strmbase/transform.c | 3 --- dlls/winegstreamer/gstdemux.c | 5 ----- dlls/wineqtdecoder/qtsplitter.c | 1 - include/wine/strmbase.h | 2 +- 6 files changed, 9 insertions(+), 18 deletions(-)
diff --git a/dlls/quartz/dsoundrender.c b/dlls/quartz/dsoundrender.c index b6eb7ba2587..d3c382f1663 100644 --- a/dlls/quartz/dsoundrender.c +++ b/dlls/quartz/dsoundrender.c @@ -158,10 +158,10 @@ static HRESULT DSoundRender_GetWritePos(DSoundRenderImpl *This, DWORD *ret_write if (This->renderer.filter.pClock == &This->IReferenceClock_iface) { max_lag = min_lag; cur = This->play_time + time_from_pos(This, playpos); - cur -= This->renderer.filter.rtStreamStart; + cur -= This->renderer.stream_start; } else if (This->renderer.filter.pClock) { IReferenceClock_GetTime(This->renderer.filter.pClock, &cur); - cur -= This->renderer.filter.rtStreamStart; + cur -= This->renderer.stream_start; } else write_at = -1;
@@ -384,7 +384,7 @@ static HRESULT WINAPI DSoundRender_DoRenderSample(BaseRenderer *iface, IMediaSam REFERENCE_TIME jitter, now = 0; Quality q; IReferenceClock_GetTime(This->renderer.filter.pClock, &now); - jitter = now - This->renderer.filter.rtStreamStart - tStart; + jitter = now - This->renderer.stream_start - tStart; if (jitter <= -DSoundRenderer_Max_Fill) jitter += DSoundRenderer_Max_Fill; else if (jitter < 0) diff --git a/dlls/strmbase/renderer.c b/dlls/strmbase/renderer.c index 25534154e95..7d8420e73c1 100644 --- a/dlls/strmbase/renderer.c +++ b/dlls/strmbase/renderer.c @@ -363,11 +363,11 @@ HRESULT WINAPI BaseRendererImpl_Receive(BaseRenderer *This, IMediaSample * pSamp
IReferenceClock_GetTime(This->filter.pClock, &now);
- if (now - This->filter.rtStreamStart - start <= -10000) + if (now - This->stream_start - start <= -10000) { HANDLE handles[2] = {This->advise_event, This->flush_event};
- IReferenceClock_AdviseTime(This->filter.pClock, This->filter.rtStreamStart, + IReferenceClock_AdviseTime(This->filter.pClock, This->stream_start, start, (HEVENT)This->advise_event, &cookie);
LeaveCriticalSection(&This->csRenderLock); @@ -429,7 +429,7 @@ HRESULT WINAPI BaseRendererImpl_Run(IBaseFilter * iface, REFERENCE_TIME tStart) TRACE("(%p)->(%s)\n", This, wine_dbgstr_longlong(tStart));
EnterCriticalSection(&This->csRenderLock); - This->filter.rtStreamStart = tStart; + This->stream_start = tStart; if (This->filter.state == State_Running) goto out;
@@ -440,7 +440,7 @@ HRESULT WINAPI BaseRendererImpl_Run(IBaseFilter * iface, REFERENCE_TIME tStart) This->sink.end_of_stream = FALSE; }
- QualityControlRender_Start(This->qcimpl, This->filter.rtStreamStart); + QualityControlRender_Start(This->qcimpl, This->stream_start); if (This->sink.pin.peer && This->pFuncsTable->renderer_start_stream) This->pFuncsTable->renderer_start_stream(This); if (This->filter.state == State_Stopped) @@ -547,7 +547,7 @@ HRESULT WINAPI BaseRendererImpl_BeginFlush(BaseRenderer* iface) HRESULT WINAPI BaseRendererImpl_EndFlush(BaseRenderer* iface) { TRACE("(%p)\n", iface); - QualityControlRender_Start(iface->qcimpl, iface->filter.rtStreamStart); + QualityControlRender_Start(iface->qcimpl, iface->stream_start); RendererPosPassThru_ResetMediaTime(iface->pPosition); ResetEvent(iface->flush_event); return S_OK; diff --git a/dlls/strmbase/transform.c b/dlls/strmbase/transform.c index 77de1227dd9..abf5ed34b3c 100644 --- a/dlls/strmbase/transform.c +++ b/dlls/strmbase/transform.c @@ -268,10 +268,7 @@ static HRESULT WINAPI TransformFilterImpl_Run(IBaseFilter *iface, REFERENCE_TIME }
if (SUCCEEDED(hr)) - { - This->filter.rtStreamStart = tStart; This->filter.state = State_Running; - } } LeaveCriticalSection(&This->csReceive);
diff --git a/dlls/winegstreamer/gstdemux.c b/dlls/winegstreamer/gstdemux.c index 66b7114c520..4a685b1bd5a 100644 --- a/dlls/winegstreamer/gstdemux.c +++ b/dlls/winegstreamer/gstdemux.c @@ -1406,10 +1406,6 @@ static HRESULT WINAPI GST_Run(IBaseFilter *iface, REFERENCE_TIME tStart) if (!This->container) return VFW_E_NOT_CONNECTED;
- EnterCriticalSection(&This->filter.csFilter); - This->filter.rtStreamStart = tStart; - LeaveCriticalSection(&This->filter.csFilter); - gst_element_get_state(This->container, &now, NULL, -1); if (now == GST_STATE_PLAYING) return S_OK; @@ -1423,7 +1419,6 @@ static HRESULT WINAPI GST_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
EnterCriticalSection(&This->filter.csFilter); gst_element_set_state(This->container, GST_STATE_PLAYING); - This->filter.rtStreamStart = tStart;
for (i = 0; i < This->cStreams; i++) { hr = BaseOutputPinImpl_Active(&This->ppPins[i]->pin); diff --git a/dlls/wineqtdecoder/qtsplitter.c b/dlls/wineqtdecoder/qtsplitter.c index 218ed5dad70..99539e5c895 100644 --- a/dlls/wineqtdecoder/qtsplitter.c +++ b/dlls/wineqtdecoder/qtsplitter.c @@ -753,7 +753,6 @@ static HRESULT WINAPI QT_Run(IBaseFilter *iface, REFERENCE_TIME tStart) TRACE("(%s)\n", wine_dbgstr_longlong(tStart));
EnterCriticalSection(&This->csReceive); - This->filter.rtStreamStart = tStart;
if (This->pVideo_Pin) hr = BaseOutputPinImpl_Active(&This->pVideo_Pin->pin); diff --git a/include/wine/strmbase.h b/include/wine/strmbase.h index 5eaf204f471..99d680a365b 100644 --- a/include/wine/strmbase.h +++ b/include/wine/strmbase.h @@ -155,7 +155,6 @@ struct strmbase_filter CRITICAL_SECTION csFilter;
FILTER_STATE state; - REFERENCE_TIME rtStreamStart; IReferenceClock * pClock; FILTER_INFO filterInfo; CLSID clsid; @@ -538,6 +537,7 @@ typedef struct BaseRendererTag * to immediately unblock the streaming thread. */ HANDLE flush_event; IMediaSample *pMediaSample; + REFERENCE_TIME stream_start;
IQualityControl *pQSink; struct QualityControlImpl *qcimpl;
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- v2: fix tests v3: actually fix tests
dlls/quartz/tests/vmr7.c | 266 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 266 insertions(+)
diff --git a/dlls/quartz/tests/vmr7.c b/dlls/quartz/tests/vmr7.c index 53f979601e9..c0d2574d16f 100644 --- a/dlls/quartz/tests/vmr7.c +++ b/dlls/quartz/tests/vmr7.c @@ -22,6 +22,7 @@ #include "dshow.h" #include "d3d9.h" #include "vmr9.h" +#include "wine/strmbase.h" #include "wine/test.h"
static IBaseFilter *create_vmr7(DWORD mode) @@ -57,6 +58,21 @@ static HRESULT set_mixing_mode(IBaseFilter *filter) return hr; }
+static inline BOOL compare_media_types(const AM_MEDIA_TYPE *a, const AM_MEDIA_TYPE *b) +{ + return !memcmp(a, b, offsetof(AM_MEDIA_TYPE, pbFormat)) + && !memcmp(a->pbFormat, b->pbFormat, a->cbFormat); +} + +static IFilterGraph2 *create_graph(void) +{ + IFilterGraph2 *ret; + HRESULT hr; + hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (void **)&ret); + ok(hr == S_OK, "Failed to create FilterGraph: %#x\n", hr); + return ret; +} + static ULONG get_refcount(void *iface) { IUnknown *unknown = iface; @@ -832,6 +848,255 @@ static void test_unconnected_filter_state(void) ok(!ref, "Got outstanding refcount %d.\n", ref); }
+struct testfilter +{ + struct strmbase_filter filter; + struct strmbase_source source; +}; + +static const IBaseFilterVtbl testfilter_vtbl = +{ + BaseFilterImpl_QueryInterface, + BaseFilterImpl_AddRef, + BaseFilterImpl_Release, + BaseFilterImpl_GetClassID, + BaseFilterImpl_Stop, + BaseFilterImpl_Pause, + BaseFilterImpl_Run, + BaseFilterImpl_GetState, + BaseFilterImpl_SetSyncSource, + BaseFilterImpl_GetSyncSource, + BaseFilterImpl_EnumPins, + BaseFilterImpl_FindPin, + BaseFilterImpl_QueryFilterInfo, + BaseFilterImpl_JoinFilterGraph, + BaseFilterImpl_QueryVendorInfo, +}; + +static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface) +{ + return CONTAINING_RECORD(iface, struct testfilter, filter); +} + +static IPin *testfilter_get_pin(struct strmbase_filter *iface, unsigned int index) +{ + struct testfilter *filter = impl_from_strmbase_filter(iface); + if (!index) + return &filter->source.pin.IPin_iface; + return NULL; +} + +static void testfilter_destroy(struct strmbase_filter *iface) +{ + struct testfilter *filter = impl_from_strmbase_filter(iface); + strmbase_source_cleanup(&filter->source); + strmbase_filter_cleanup(&filter->filter); +} + +static const struct strmbase_filter_ops testfilter_ops = +{ + .filter_get_pin = testfilter_get_pin, + .filter_destroy = testfilter_destroy, +}; + +static const IPinVtbl testsource_vtbl = +{ + BasePinImpl_QueryInterface, + BasePinImpl_AddRef, + BasePinImpl_Release, + BaseOutputPinImpl_Connect, + BaseOutputPinImpl_ReceiveConnection, + BasePinImpl_Disconnect, + BasePinImpl_ConnectedTo, + BasePinImpl_ConnectionMediaType, + BasePinImpl_QueryPinInfo, + BasePinImpl_QueryDirection, + BasePinImpl_QueryId, + BasePinImpl_QueryAccept, + BasePinImpl_EnumMediaTypes, + BasePinImpl_QueryInternalConnections, + BaseOutputPinImpl_EndOfStream, + BaseOutputPinImpl_BeginFlush, + BaseOutputPinImpl_EndFlush, + BasePinImpl_NewSegment, +}; + +static HRESULT testsource_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt) +{ + return S_OK; +} + +static HRESULT WINAPI testsource_AttemptConnection(struct strmbase_source *iface, + IPin *peer, const AM_MEDIA_TYPE *mt) +{ + HRESULT hr; + + iface->pin.peer = peer; + IPin_AddRef(peer); + CopyMediaType(&iface->pin.mtCurrent, mt); + + if (FAILED(hr = IPin_ReceiveConnection(peer, &iface->pin.IPin_iface, mt))) + { + ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr); + IPin_Release(peer); + iface->pin.peer = NULL; + FreeMediaType(&iface->pin.mtCurrent); + } + + return hr; +} + +static const struct strmbase_source_ops testsource_ops = +{ + .base.pin_query_accept = testsource_query_accept, + .base.pin_get_media_type = strmbase_pin_get_media_type, + .pfnAttemptConnection = testsource_AttemptConnection, +}; + +static void testfilter_init(struct testfilter *filter) +{ + static const GUID clsid = {0xabacab}; + strmbase_filter_init(&filter->filter, &testfilter_vtbl, NULL, &clsid, &testfilter_ops); + strmbase_source_init(&filter->source, &testsource_vtbl, &filter->filter, L"", &testsource_ops); +} + +static void test_connect_pin(void) +{ + VIDEOINFOHEADER vih = + { + .bmiHeader.biSize = sizeof(BITMAPINFOHEADER), + .bmiHeader.biWidth = 32, + .bmiHeader.biHeight = 16, + .bmiHeader.biPlanes = 1, + .bmiHeader.biCompression = BI_RGB, + }; + AM_MEDIA_TYPE req_mt = + { + .majortype = MEDIATYPE_Video, + .subtype = MEDIASUBTYPE_WAVE, + .formattype = FORMAT_VideoInfo, + .cbFormat = sizeof(vih), + .pbFormat = (BYTE *)&vih, + }; + IBaseFilter *filter = create_vmr7(VMRMode_Windowed); + IFilterGraph2 *graph = create_graph(); + struct testfilter source; + AM_MEDIA_TYPE mt; + IPin *pin, *peer; + unsigned int i; + HRESULT hr; + ULONG ref; + + static const GUID *subtype_tests[] = + { + &MEDIASUBTYPE_RGB565, + &MEDIASUBTYPE_RGB24, + &MEDIASUBTYPE_RGB32, + &MEDIASUBTYPE_WAVE, + }; + + testfilter_init(&source); + + IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL); + IFilterGraph2_AddFilter(graph, filter, NULL); + + IBaseFilter_FindPin(filter, L"VMR Input0", &pin); + + vih.bmiHeader.biBitCount = 16; + hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt); + todo_wine ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr); + if (hr == S_OK) + { + IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface); + IFilterGraph2_Disconnect(graph, pin); + } + vih.bmiHeader.biBitCount = 32; + hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt); + if (hr == VFW_E_TYPE_NOT_ACCEPTED) /* w7u */ + { + vih.bmiHeader.biBitCount = 24; + hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt); + } + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IFilterGraph2_Disconnect(graph, pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + for (i = 0; i < ARRAY_SIZE(subtype_tests); ++i) + { + req_mt.subtype = *subtype_tests[i]; + hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt); + ok(hr == S_OK, "Got hr %#x for subtype %s.\n", hr, wine_dbgstr_guid(subtype_tests[i])); + + hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IFilterGraph2_Disconnect(graph, pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + } + + req_mt.formattype = FORMAT_None; + hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt); + ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr); + req_mt.formattype = GUID_NULL; + hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt); + ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr); + req_mt.formattype = FORMAT_VideoInfo; + + req_mt.subtype = MEDIASUBTYPE_RGB8; + hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt); + todo_wine ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr); + if (hr == S_OK) + { + IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface); + IFilterGraph2_Disconnect(graph, pin); + } + req_mt.subtype = MEDIASUBTYPE_RGB32; + + peer = (IPin *)0xdeadbeef; + hr = IPin_ConnectedTo(pin, &peer); + ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr); + ok(!peer, "Got peer %p.\n", peer); + + hr = IPin_ConnectionMediaType(pin, &mt); + ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr); + + hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IPin_ConnectedTo(pin, &peer); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(peer == &source.source.pin.IPin_iface, "Got peer %p.\n", peer); + IPin_Release(peer); + + hr = IPin_ConnectionMediaType(pin, &mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(compare_media_types(&mt, &req_mt), "Media types didn't match.\n"); + + hr = IFilterGraph2_Disconnect(graph, pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IFilterGraph2_Disconnect(graph, pin); + todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr); + ok(source.source.pin.peer == pin, "Got peer %p.\n", peer); + IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface); + + peer = (IPin *)0xdeadbeef; + hr = IPin_ConnectedTo(pin, &peer); + ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr); + ok(!peer, "Got peer %p.\n", peer); + + hr = IPin_ConnectionMediaType(pin, &mt); + ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr); + + IPin_Release(pin); + ref = IFilterGraph2_Release(graph); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IBaseFilter_Release(&source.filter.IBaseFilter_iface); + ok(!ref, "Got outstanding refcount %d.\n", ref); +} + START_TEST(vmr7) { CoInitialize(NULL); @@ -845,6 +1110,7 @@ START_TEST(vmr7) test_media_types(); test_enum_media_types(); test_unconnected_filter_state(); + test_connect_pin();
CoUninitialize(); }
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/tests/vmr9.c | 261 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 261 insertions(+)
diff --git a/dlls/quartz/tests/vmr9.c b/dlls/quartz/tests/vmr9.c index 80bb9303780..f65ddc2278e 100644 --- a/dlls/quartz/tests/vmr9.c +++ b/dlls/quartz/tests/vmr9.c @@ -22,6 +22,7 @@ #include "dshow.h" #include "d3d9.h" #include "vmr9.h" +#include "wine/strmbase.h" #include "wine/test.h"
static IBaseFilter *create_vmr9(DWORD mode) @@ -42,6 +43,21 @@ static IBaseFilter *create_vmr9(DWORD mode) return filter; }
+static inline BOOL compare_media_types(const AM_MEDIA_TYPE *a, const AM_MEDIA_TYPE *b) +{ + return !memcmp(a, b, offsetof(AM_MEDIA_TYPE, pbFormat)) + && !memcmp(a->pbFormat, b->pbFormat, a->cbFormat); +} + +static IFilterGraph2 *create_graph(void) +{ + IFilterGraph2 *ret; + HRESULT hr; + hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (void **)&ret); + ok(hr == S_OK, "Failed to create FilterGraph: %#x\n", hr); + return ret; +} + static ULONG get_refcount(void *iface) { IUnknown *unknown = iface; @@ -836,6 +852,250 @@ static void test_unconnected_filter_state(void) ok(!ref, "Got outstanding refcount %d.\n", ref); }
+struct testfilter +{ + struct strmbase_filter filter; + struct strmbase_source source; +}; + +static const IBaseFilterVtbl testfilter_vtbl = +{ + BaseFilterImpl_QueryInterface, + BaseFilterImpl_AddRef, + BaseFilterImpl_Release, + BaseFilterImpl_GetClassID, + BaseFilterImpl_Stop, + BaseFilterImpl_Pause, + BaseFilterImpl_Run, + BaseFilterImpl_GetState, + BaseFilterImpl_SetSyncSource, + BaseFilterImpl_GetSyncSource, + BaseFilterImpl_EnumPins, + BaseFilterImpl_FindPin, + BaseFilterImpl_QueryFilterInfo, + BaseFilterImpl_JoinFilterGraph, + BaseFilterImpl_QueryVendorInfo, +}; + +static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface) +{ + return CONTAINING_RECORD(iface, struct testfilter, filter); +} + +static IPin *testfilter_get_pin(struct strmbase_filter *iface, unsigned int index) +{ + struct testfilter *filter = impl_from_strmbase_filter(iface); + if (!index) + return &filter->source.pin.IPin_iface; + return NULL; +} + +static void testfilter_destroy(struct strmbase_filter *iface) +{ + struct testfilter *filter = impl_from_strmbase_filter(iface); + strmbase_source_cleanup(&filter->source); + strmbase_filter_cleanup(&filter->filter); +} + +static const struct strmbase_filter_ops testfilter_ops = +{ + .filter_get_pin = testfilter_get_pin, + .filter_destroy = testfilter_destroy, +}; + +static const IPinVtbl testsource_vtbl = +{ + BasePinImpl_QueryInterface, + BasePinImpl_AddRef, + BasePinImpl_Release, + BaseOutputPinImpl_Connect, + BaseOutputPinImpl_ReceiveConnection, + BasePinImpl_Disconnect, + BasePinImpl_ConnectedTo, + BasePinImpl_ConnectionMediaType, + BasePinImpl_QueryPinInfo, + BasePinImpl_QueryDirection, + BasePinImpl_QueryId, + BasePinImpl_QueryAccept, + BasePinImpl_EnumMediaTypes, + BasePinImpl_QueryInternalConnections, + BaseOutputPinImpl_EndOfStream, + BaseOutputPinImpl_BeginFlush, + BaseOutputPinImpl_EndFlush, + BasePinImpl_NewSegment, +}; + +static HRESULT testsource_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt) +{ + return S_OK; +} + +static HRESULT WINAPI testsource_AttemptConnection(struct strmbase_source *iface, + IPin *peer, const AM_MEDIA_TYPE *mt) +{ + HRESULT hr; + + iface->pin.peer = peer; + IPin_AddRef(peer); + CopyMediaType(&iface->pin.mtCurrent, mt); + + if (FAILED(hr = IPin_ReceiveConnection(peer, &iface->pin.IPin_iface, mt))) + { + ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr); + IPin_Release(peer); + iface->pin.peer = NULL; + FreeMediaType(&iface->pin.mtCurrent); + } + + return hr; +} + +static const struct strmbase_source_ops testsource_ops = +{ + .base.pin_query_accept = testsource_query_accept, + .base.pin_get_media_type = strmbase_pin_get_media_type, + .pfnAttemptConnection = testsource_AttemptConnection, +}; + +static void testfilter_init(struct testfilter *filter) +{ + static const GUID clsid = {0xabacab}; + strmbase_filter_init(&filter->filter, &testfilter_vtbl, NULL, &clsid, &testfilter_ops); + strmbase_source_init(&filter->source, &testsource_vtbl, &filter->filter, L"", &testsource_ops); +} + +static void test_connect_pin(void) +{ + VIDEOINFOHEADER vih = + { + .bmiHeader.biSize = sizeof(BITMAPINFOHEADER), + .bmiHeader.biBitCount = 32, + .bmiHeader.biWidth = 32, + .bmiHeader.biHeight = 16, + .bmiHeader.biPlanes = 1, + .bmiHeader.biCompression = BI_RGB, + }; + AM_MEDIA_TYPE req_mt = + { + .majortype = MEDIATYPE_Video, + .formattype = FORMAT_VideoInfo, + .cbFormat = sizeof(vih), + .pbFormat = (BYTE *)&vih, + }; + IBaseFilter *filter = create_vmr9(VMR9Mode_Windowed); + IFilterGraph2 *graph = create_graph(); + struct testfilter source; + unsigned int i, j; + AM_MEDIA_TYPE mt; + IPin *pin, *peer; + HRESULT hr; + ULONG ref; + + static const GUID *subtype_tests[] = + { + &MEDIASUBTYPE_RGB555, + &MEDIASUBTYPE_RGB565, + &MEDIASUBTYPE_RGB24, + &MEDIASUBTYPE_RGB32, + }; + static const WORD bpp_tests[] = {15, 16, 24, 32}; + + testfilter_init(&source); + + IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL); + IFilterGraph2_AddFilter(graph, filter, NULL); + + IBaseFilter_FindPin(filter, L"VMR Input0", &pin); + + for (i = 0; i < ARRAY_SIZE(subtype_tests); ++i) + { + req_mt.subtype = *subtype_tests[i]; + + for (j = 0; j < ARRAY_SIZE(bpp_tests); ++j) + { + vih.bmiHeader.biBitCount = bpp_tests[j]; + + hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt); + ok(hr == S_OK, "Got hr %#x for subtype %s and bpp %u.\n", hr, + wine_dbgstr_guid(subtype_tests[i]), bpp_tests[j]); + + hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IFilterGraph2_Disconnect(graph, pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + } + } + + req_mt.formattype = FORMAT_None; + hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt); + ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr); + req_mt.formattype = GUID_NULL; + hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt); + ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr); + req_mt.formattype = FORMAT_VideoInfo; + + req_mt.subtype = MEDIASUBTYPE_RGB8; + hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt); + todo_wine ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr); + if (hr == S_OK) + { + IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface); + IFilterGraph2_Disconnect(graph, pin); + } + req_mt.subtype = MEDIASUBTYPE_WAVE; + hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt); + todo_wine ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr); + if (hr == S_OK) + { + IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface); + IFilterGraph2_Disconnect(graph, pin); + } + req_mt.subtype = MEDIASUBTYPE_RGB32; + + peer = (IPin *)0xdeadbeef; + hr = IPin_ConnectedTo(pin, &peer); + ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr); + ok(!peer, "Got peer %p.\n", peer); + + hr = IPin_ConnectionMediaType(pin, &mt); + ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr); + + hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IPin_ConnectedTo(pin, &peer); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(peer == &source.source.pin.IPin_iface, "Got peer %p.\n", peer); + IPin_Release(peer); + + hr = IPin_ConnectionMediaType(pin, &mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(compare_media_types(&mt, &req_mt), "Media types didn't match.\n"); + + hr = IFilterGraph2_Disconnect(graph, pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IFilterGraph2_Disconnect(graph, pin); + todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr); + ok(source.source.pin.peer == pin, "Got peer %p.\n", source.source.pin.peer); + IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface); + + peer = (IPin *)0xdeadbeef; + hr = IPin_ConnectedTo(pin, &peer); + ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr); + ok(!peer, "Got peer %p.\n", peer); + + hr = IPin_ConnectionMediaType(pin, &mt); + ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr); + + IPin_Release(pin); + ref = IFilterGraph2_Release(graph); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IBaseFilter_Release(&source.filter.IBaseFilter_iface); + ok(!ref, "Got outstanding refcount %d.\n", ref); +} + START_TEST(vmr9) { IBaseFilter *filter; @@ -860,6 +1120,7 @@ START_TEST(vmr9) test_media_types(); test_enum_media_types(); test_unconnected_filter_state(); + test_connect_pin();
CoUninitialize(); }
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/tests/vmr7.c | 6 +- dlls/quartz/tests/vmr9.c | 6 +- dlls/quartz/vmr9.c | 117 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 6 deletions(-)
diff --git a/dlls/quartz/tests/vmr7.c b/dlls/quartz/tests/vmr7.c index c0d2574d16f..0228e0c249f 100644 --- a/dlls/quartz/tests/vmr7.c +++ b/dlls/quartz/tests/vmr7.c @@ -248,7 +248,7 @@ static void test_interfaces(void) IBaseFilter_FindPin(filter, sink_id, &pin);
check_interface(pin, &IID_IMemInputPin, TRUE); - todo_wine check_interface(pin, &IID_IOverlay, TRUE); + check_interface(pin, &IID_IOverlay, TRUE); check_interface(pin, &IID_IPin, TRUE); todo_wine check_interface(pin, &IID_IQualityControl, TRUE); check_interface(pin, &IID_IUnknown, TRUE); @@ -278,7 +278,7 @@ static void test_interfaces(void) IBaseFilter_FindPin(filter, sink_id, &pin);
check_interface(pin, &IID_IMemInputPin, TRUE); - todo_wine check_interface(pin, &IID_IOverlay, TRUE); + check_interface(pin, &IID_IOverlay, TRUE); check_interface(pin, &IID_IPin, TRUE); todo_wine check_interface(pin, &IID_IQualityControl, TRUE); check_interface(pin, &IID_IUnknown, TRUE); @@ -307,7 +307,7 @@ static void test_interfaces(void) IBaseFilter_FindPin(filter, sink_id, &pin);
check_interface(pin, &IID_IMemInputPin, TRUE); - todo_wine check_interface(pin, &IID_IOverlay, TRUE); + check_interface(pin, &IID_IOverlay, TRUE); check_interface(pin, &IID_IPin, TRUE); todo_wine check_interface(pin, &IID_IQualityControl, TRUE); check_interface(pin, &IID_IUnknown, TRUE); diff --git a/dlls/quartz/tests/vmr9.c b/dlls/quartz/tests/vmr9.c index f65ddc2278e..d3001727d4d 100644 --- a/dlls/quartz/tests/vmr9.c +++ b/dlls/quartz/tests/vmr9.c @@ -241,7 +241,7 @@ static void test_interfaces(void) IBaseFilter_FindPin(filter, sink_id, &pin);
check_interface(pin, &IID_IMemInputPin, TRUE); - todo_wine check_interface(pin, &IID_IOverlay, TRUE); + check_interface(pin, &IID_IOverlay, TRUE); check_interface(pin, &IID_IPin, TRUE); todo_wine check_interface(pin, &IID_IQualityControl, TRUE); check_interface(pin, &IID_IUnknown, TRUE); @@ -271,7 +271,7 @@ static void test_interfaces(void) IBaseFilter_FindPin(filter, sink_id, &pin);
check_interface(pin, &IID_IMemInputPin, TRUE); - todo_wine check_interface(pin, &IID_IOverlay, TRUE); + check_interface(pin, &IID_IOverlay, TRUE); check_interface(pin, &IID_IPin, TRUE); todo_wine check_interface(pin, &IID_IQualityControl, TRUE); check_interface(pin, &IID_IUnknown, TRUE); @@ -300,7 +300,7 @@ static void test_interfaces(void) IBaseFilter_FindPin(filter, sink_id, &pin);
check_interface(pin, &IID_IMemInputPin, TRUE); - todo_wine check_interface(pin, &IID_IOverlay, TRUE); + check_interface(pin, &IID_IOverlay, TRUE); check_interface(pin, &IID_IPin, TRUE); todo_wine check_interface(pin, &IID_IQualityControl, TRUE); check_interface(pin, &IID_IUnknown, TRUE); diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index cc7ef69810c..5a1d248ddeb 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -56,6 +56,8 @@ struct quartz_vmr IVMRWindowlessControl IVMRWindowlessControl_iface; IVMRWindowlessControl9 IVMRWindowlessControl9_iface;
+ IOverlay IOverlay_iface; + IVMRSurfaceAllocatorEx9 *allocator; IVMRImagePresenter9 *presenter; BOOL allocator_is_ex; @@ -550,6 +552,19 @@ static HRESULT vmr_query_interface(BaseRenderer *iface, REFIID iid, void **out) return S_OK; }
+static HRESULT vmr_pin_query_interface(BaseRenderer *iface, REFIID iid, void **out) +{ + struct quartz_vmr *filter = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface); + + if (IsEqualGUID(iid, &IID_IOverlay)) + *out = &filter->IOverlay_iface; + else + return E_NOINTERFACE; + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + static const BaseRendererFuncTable BaseFuncTable = { .pfnCheckMediaType = VMR9_CheckMediaType, @@ -561,6 +576,7 @@ static const BaseRendererFuncTable BaseFuncTable = .pfnBreakConnect = VMR9_BreakConnect, .renderer_destroy = vmr_destroy, .renderer_query_interface = vmr_query_interface, + .renderer_pin_query_interface = vmr_pin_query_interface, };
static LPWSTR WINAPI VMR9_GetClassWindowStyles(BaseWindow *This, DWORD *pClassStyles, DWORD *pWindowStyles, DWORD *pWindowStylesEx) @@ -2112,6 +2128,106 @@ static const IVMRSurfaceAllocatorNotify9Vtbl VMR9_SurfaceAllocatorNotify_Vtbl = VMR9SurfaceAllocatorNotify_NotifyEvent };
+static inline struct quartz_vmr *impl_from_IOverlay(IOverlay *iface) +{ + return CONTAINING_RECORD(iface, struct quartz_vmr, IOverlay_iface); +} + +static HRESULT WINAPI overlay_QueryInterface(IOverlay *iface, REFIID iid, void **out) +{ + struct quartz_vmr *filter = impl_from_IOverlay(iface); + return IPin_QueryInterface(&filter->renderer.sink.pin.IPin_iface, iid, out); +} + +static ULONG WINAPI overlay_AddRef(IOverlay *iface) +{ + struct quartz_vmr *filter = impl_from_IOverlay(iface); + return IPin_AddRef(&filter->renderer.sink.pin.IPin_iface); +} + +static ULONG WINAPI overlay_Release(IOverlay *iface) +{ + struct quartz_vmr *filter = impl_from_IOverlay(iface); + return IPin_Release(&filter->renderer.sink.pin.IPin_iface); +} + +static HRESULT WINAPI overlay_GetPalette(IOverlay *iface, DWORD *count, PALETTEENTRY **palette) +{ + FIXME("iface %p, count %p, palette %p, stub!\n", iface, count, palette); + return E_NOTIMPL; +} + +static HRESULT WINAPI overlay_SetPalette(IOverlay *iface, DWORD count, PALETTEENTRY *palette) +{ + FIXME("iface %p, count %u, palette %p, stub!\n", iface, count, palette); + return E_NOTIMPL; +} + +static HRESULT WINAPI overlay_GetDefaultColorKey(IOverlay *iface, COLORKEY *key) +{ + FIXME("iface %p, key %p, stub!\n", iface, key); + return E_NOTIMPL; +} + +static HRESULT WINAPI overlay_GetColorKey(IOverlay *iface, COLORKEY *key) +{ + FIXME("iface %p, key %p, stub!\n", iface, key); + return E_NOTIMPL; +} + +static HRESULT WINAPI overlay_SetColorKey(IOverlay *iface, COLORKEY *key) +{ + FIXME("iface %p, key %p, stub!\n", iface, key); + return E_NOTIMPL; +} + +static HRESULT WINAPI overlay_GetWindowHandle(IOverlay *iface, HWND *window) +{ + FIXME("iface %p, window %p, stub!\n", iface, window); + return E_NOTIMPL; +} + +static HRESULT WINAPI overlay_GetClipList(IOverlay *iface, RECT *source, RECT *dest, RGNDATA **region) +{ + FIXME("iface %p, source %p, dest %p, region %p, stub!\n", iface, source, dest, region); + return E_NOTIMPL; +} + +static HRESULT WINAPI overlay_GetVideoPosition(IOverlay *iface, RECT *source, RECT *dest) +{ + FIXME("iface %p, source %p, dest %p, stub!\n", iface, source, dest); + return E_NOTIMPL; +} + +static HRESULT WINAPI overlay_Advise(IOverlay *iface, IOverlayNotify *sink, DWORD flags) +{ + FIXME("iface %p, sink %p, flags %#x, stub!\n", iface, sink, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI overlay_Unadvise(IOverlay *iface) +{ + FIXME("iface %p, stub!\n", iface); + return E_NOTIMPL; +} + +static const IOverlayVtbl overlay_vtbl = +{ + overlay_QueryInterface, + overlay_AddRef, + overlay_Release, + overlay_GetPalette, + overlay_SetPalette, + overlay_GetDefaultColorKey, + overlay_GetColorKey, + overlay_SetColorKey, + overlay_GetWindowHandle, + overlay_GetClipList, + overlay_GetVideoPosition, + overlay_Advise, + overlay_Unadvise, +}; + static HRESULT vmr_create(IUnknown *outer, void **out, const CLSID *clsid) { static const WCHAR sink_name[] = {'V','M','R',' ','I','n','p','u','t','0',0}; @@ -2149,6 +2265,7 @@ static HRESULT vmr_create(IUnknown *outer, void **out, const CLSID *clsid) pVMR->IVMRSurfaceAllocatorNotify9_iface.lpVtbl = &VMR9_SurfaceAllocatorNotify_Vtbl; pVMR->IVMRWindowlessControl_iface.lpVtbl = &VMR7_WindowlessControl_Vtbl; pVMR->IVMRWindowlessControl9_iface.lpVtbl = &VMR9_WindowlessControl_Vtbl; + pVMR->IOverlay_iface.lpVtbl = &overlay_vtbl;
hr = strmbase_renderer_init(&pVMR->renderer, &VMR_Vtbl, outer, clsid, sink_name, &BaseFuncTable); if (FAILED(hr))
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/tests/vmr7.c | 26 ++++++++++++++++++++++++++ dlls/quartz/tests/vmr9.c | 26 ++++++++++++++++++++++++++ dlls/quartz/vmr9.c | 8 ++++++-- 3 files changed, 58 insertions(+), 2 deletions(-)
diff --git a/dlls/quartz/tests/vmr7.c b/dlls/quartz/tests/vmr7.c index 0228e0c249f..0d72689078f 100644 --- a/dlls/quartz/tests/vmr7.c +++ b/dlls/quartz/tests/vmr7.c @@ -1097,6 +1097,31 @@ static void test_connect_pin(void) ok(!ref, "Got outstanding refcount %d.\n", ref); }
+static void test_overlay(void) +{ + IBaseFilter *filter = create_vmr7(0); + IOverlay *overlay; + HRESULT hr; + ULONG ref; + IPin *pin; + HWND hwnd; + + IBaseFilter_FindPin(filter, L"VMR Input0", &pin); + + hr = IPin_QueryInterface(pin, &IID_IOverlay, (void **)&overlay); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hwnd = (HWND)0xdeadbeef; + hr = IOverlay_GetWindowHandle(overlay, &hwnd); + ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(hwnd && hwnd != (HWND)0xdeadbeef, "Got invalid window %p.\n", hwnd); + + IOverlay_Release(overlay); + IPin_Release(pin); + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %d.\n", ref); +} + START_TEST(vmr7) { CoInitialize(NULL); @@ -1111,6 +1136,7 @@ START_TEST(vmr7) test_enum_media_types(); test_unconnected_filter_state(); test_connect_pin(); + test_overlay();
CoUninitialize(); } diff --git a/dlls/quartz/tests/vmr9.c b/dlls/quartz/tests/vmr9.c index d3001727d4d..928484ccb6a 100644 --- a/dlls/quartz/tests/vmr9.c +++ b/dlls/quartz/tests/vmr9.c @@ -1096,6 +1096,31 @@ static void test_connect_pin(void) ok(!ref, "Got outstanding refcount %d.\n", ref); }
+static void test_overlay(void) +{ + IBaseFilter *filter = create_vmr9(0); + IOverlay *overlay; + HRESULT hr; + ULONG ref; + IPin *pin; + HWND hwnd; + + IBaseFilter_FindPin(filter, L"VMR Input0", &pin); + + hr = IPin_QueryInterface(pin, &IID_IOverlay, (void **)&overlay); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hwnd = (HWND)0xdeadbeef; + hr = IOverlay_GetWindowHandle(overlay, &hwnd); + ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(hwnd && hwnd != (HWND)0xdeadbeef, "Got invalid window %p.\n", hwnd); + + IOverlay_Release(overlay); + IPin_Release(pin); + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %d.\n", ref); +} + START_TEST(vmr9) { IBaseFilter *filter; @@ -1121,6 +1146,7 @@ START_TEST(vmr9) test_enum_media_types(); test_unconnected_filter_state(); test_connect_pin(); + test_overlay();
CoUninitialize(); } diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index 5a1d248ddeb..600e75945a8 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -2183,8 +2183,12 @@ static HRESULT WINAPI overlay_SetColorKey(IOverlay *iface, COLORKEY *key)
static HRESULT WINAPI overlay_GetWindowHandle(IOverlay *iface, HWND *window) { - FIXME("iface %p, window %p, stub!\n", iface, window); - return E_NOTIMPL; + struct quartz_vmr *filter = impl_from_IOverlay(iface); + + TRACE("filter %p, window %p.\n", filter, window); + + *window = filter->baseControlWindow.baseWindow.hWnd; + return S_OK; }
static HRESULT WINAPI overlay_GetClipList(IOverlay *iface, RECT *source, RECT *dest, RGNDATA **region)