Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/qcap/tests/smartteefilter.c | 268 ++++++++++++++++++++++++++++++- 1 file changed, 264 insertions(+), 4 deletions(-)
diff --git a/dlls/qcap/tests/smartteefilter.c b/dlls/qcap/tests/smartteefilter.c index 1019fd3c1ba..bd51743de76 100644 --- a/dlls/qcap/tests/smartteefilter.c +++ b/dlls/qcap/tests/smartteefilter.c @@ -2278,6 +2278,9 @@ struct testfilter struct strmbase_sink sink; const AM_MEDIA_TYPE *sink_mt; AM_MEDIA_TYPE source_mt; + HANDLE sample_event, eos_event, segment_event; + BOOL preview; + unsigned int got_begin_flush, got_end_flush; };
static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface) @@ -2298,6 +2301,9 @@ static struct strmbase_pin *testfilter_get_pin(struct strmbase_filter *iface, un static void testfilter_destroy(struct strmbase_filter *iface) { struct testfilter *filter = impl_from_strmbase_filter(iface); + CloseHandle(filter->sample_event); + CloseHandle(filter->eos_event); + CloseHandle(filter->segment_event); strmbase_source_cleanup(&filter->source); strmbase_sink_cleanup(&filter->sink); strmbase_filter_cleanup(&filter->filter); @@ -2327,7 +2333,9 @@ static HRESULT testsource_get_media_type(struct strmbase_pin *iface, unsigned in
static void test_sink_allocator(IPin *pin) { - ALLOCATOR_PROPERTIES req_props = {1, 5000, 1, 0}, ret_props; + /* FIXME: We shouldn't need more than one sample, but Wine currently uses + * the same allocator for all three pins. */ + ALLOCATOR_PROPERTIES req_props = {3, 256, 1, 0}, ret_props; IMemAllocator *req_allocator, *ret_allocator; IMemInputPin *input; HRESULT hr; @@ -2359,9 +2367,6 @@ static void test_sink_allocator(IPin *pin) hr = IMemAllocator_SetProperties(req_allocator, &req_props, &ret_props); ok(hr == S_OK, "Got hr %#x.\n", hr);
- hr = IMemAllocator_Commit(req_allocator); - ok(hr == S_OK, "Got hr %#x.\n", hr); - IMemAllocator_Release(req_allocator); IMemInputPin_Release(input); } @@ -2429,6 +2434,88 @@ static HRESULT testsink_get_media_type(struct strmbase_pin *iface, unsigned int
static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample *sample) { + struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter); + REFERENCE_TIME start, stop; + BYTE *data, expect[200]; + LONG size, i; + HRESULT hr; + + size = IMediaSample_GetSize(sample); + ok(size == 256, "Got size %u.\n", size); + size = IMediaSample_GetActualDataLength(sample); + ok(size == 200, "Got valid size %u.\n", size); + + hr = IMediaSample_GetPointer(sample, &data); + ok(hr == S_OK, "Got hr %#x.\n", hr); + for (i = 0; i < size; ++i) + expect[i] = i; + ok(!memcmp(data, expect, size), "Data didn't match.\n"); + + hr = IMediaSample_GetTime(sample, &start, &stop); + if (filter->preview) + { + ok(hr == VFW_E_SAMPLE_TIME_NOT_SET, "Got hr %#x.\n", hr); + } + else + { + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(start == 30000, "Got start time %s.\n", wine_dbgstr_longlong(start)); + ok(stop == 40000, "Got stop time %s.\n", wine_dbgstr_longlong(stop)); + } + + hr = IMediaSample_GetMediaTime(sample, &start, &stop); + if (filter->preview) + { + todo_wine ok(hr == VFW_E_MEDIA_TIME_NOT_SET, "Got hr %#x.\n", hr); + } + else + { + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(start == 10000, "Got start time %s.\n", wine_dbgstr_longlong(start)); + ok(stop == 20000, "Got stop time %s.\n", wine_dbgstr_longlong(stop)); + } + + hr = IMediaSample_IsDiscontinuity(sample); + todo_wine_if (filter->preview) ok(hr == filter->preview ? S_FALSE : S_OK, "Got hr %#x.\n", hr); + hr = IMediaSample_IsPreroll(sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaSample_IsSyncPoint(sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + SetEvent(filter->sample_event); + + return S_OK; +} + +static HRESULT testsink_new_segment(struct strmbase_sink *iface, + REFERENCE_TIME start, REFERENCE_TIME stop, double rate) +{ + struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter); + ok(start == 10000, "Got start %s.\n", wine_dbgstr_longlong(start)); + ok(stop == 20000, "Got stop %s.\n", wine_dbgstr_longlong(stop)); + ok(rate == 1.0, "Got rate %.16e.\n", rate); + SetEvent(filter->segment_event); + return S_OK; +} + +static HRESULT testsink_eos(struct strmbase_sink *iface) +{ + struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter); + SetEvent(filter->eos_event); + return S_OK; +} + +static HRESULT testsink_begin_flush(struct strmbase_sink *iface) +{ + struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter); + ++filter->got_begin_flush; + return S_OK; +} + +static HRESULT testsink_end_flush(struct strmbase_sink *iface) +{ + struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter); + ++filter->got_end_flush; return S_OK; }
@@ -2438,6 +2525,10 @@ static const struct strmbase_sink_ops testsink_ops = .base.pin_query_accept = testsink_query_accept, .base.pin_get_media_type = testsink_get_media_type, .pfnReceive = testsink_Receive, + .sink_new_segment = testsink_new_segment, + .sink_eos = testsink_eos, + .sink_begin_flush = testsink_begin_flush, + .sink_end_flush = testsink_end_flush, };
static void testfilter_init(struct testfilter *filter) @@ -2447,6 +2538,9 @@ static void testfilter_init(struct testfilter *filter) strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops); strmbase_source_init(&filter->source, &filter->filter, L"source", &testsource_ops); strmbase_sink_init(&filter->sink, &filter->filter, L"sink", &testsink_ops, NULL); + filter->sample_event = CreateEventW(NULL, FALSE, FALSE, NULL); + filter->segment_event = CreateEventW(NULL, FALSE, FALSE, NULL); + filter->eos_event = CreateEventW(NULL, FALSE, FALSE, NULL); }
static void test_source_media_types(AM_MEDIA_TYPE req_mt, const AM_MEDIA_TYPE *source_mt, IPin *source) @@ -2791,6 +2885,171 @@ static void test_connect_pin(void) ok(!ref, "Got outstanding refcount %d.\n", ref); }
+static void test_streaming(void) +{ + static const AM_MEDIA_TYPE req_mt = + { + .majortype = {0x111}, + .subtype = {0x222}, + .formattype = {0x333}, + }; + IBaseFilter *filter = create_smart_tee(); + struct testfilter testsource, testsink1, testsink2; + IPin *sink, *capture, *preview; + REFERENCE_TIME start, stop; + IMemAllocator *allocator; + IMediaControl *control; + IFilterGraph2 *graph; + IMediaSample *sample; + IMemInputPin *input; + LONG size, i; + HRESULT hr; + BYTE *data; + ULONG ref; + + testfilter_init(&testsource); + testfilter_init(&testsink1); + testfilter_init(&testsink2); + testsink2.preview = TRUE; + CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, + &IID_IFilterGraph2, (void **)&graph); + IFilterGraph2_AddFilter(graph, &testsource.filter.IBaseFilter_iface, L"source"); + IFilterGraph2_AddFilter(graph, &testsink1.filter.IBaseFilter_iface, L"sink1"); + IFilterGraph2_AddFilter(graph, &testsink2.filter.IBaseFilter_iface, L"sink2"); + IFilterGraph2_AddFilter(graph, filter, L"sample grabber"); + IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control); + IBaseFilter_FindPin(filter, L"Input", &sink); + IPin_QueryInterface(sink, &IID_IMemInputPin, (void **)&input); + IBaseFilter_FindPin(filter, L"Capture", &capture); + IBaseFilter_FindPin(filter, L"Preview", &preview); + + hr = IFilterGraph2_ConnectDirect(graph, &testsource.source.pin.IPin_iface, sink, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IFilterGraph2_ConnectDirect(graph, capture, &testsink1.sink.pin.IPin_iface, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IFilterGraph2_ConnectDirect(graph, preview, &testsink2.sink.pin.IPin_iface, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMemInputPin_ReceiveCanBlock(input); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMemInputPin_GetAllocator(input, &allocator); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0); + ok(hr == VFW_E_NOT_COMMITTED, "Got hr %#x.\n", hr); + + hr = IMediaControl_Pause(control); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr != S_OK) + { + IMemAllocator_Commit(allocator); + hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#x.\n", hr); + } + + hr = IMediaSample_GetPointer(sample, &data); + ok(hr == S_OK, "Got hr %#x.\n", hr); + size = IMediaSample_GetSize(sample); + ok(size == 256, "Got size %d.\n", size); + for (i = 0; i < 200; ++i) + data[i] = i; + hr = IMediaSample_SetActualDataLength(sample, 200); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + start = 10000; + stop = 20000; + hr = IMediaSample_SetMediaTime(sample, &start, &stop); + ok(hr == S_OK, "Got hr %#x.\n", hr); + start = 30000; + stop = 40000; + hr = IMediaSample_SetTime(sample, &start, &stop); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaSample_SetDiscontinuity(sample, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaSample_SetPreroll(sample, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaSample_SetSyncPoint(sample, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(!WaitForSingleObject(testsink1.sample_event, 1000), "Wait timed out.\n"); + ok(!WaitForSingleObject(testsink2.sample_event, 1000), "Wait timed out.\n"); + + hr = IPin_NewSegment(sink, 10000, 20000, 1.0); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(!WaitForSingleObject(testsink1.segment_event, 1000), "Wait timed out.\n"); + ok(!WaitForSingleObject(testsink2.segment_event, 1000), "Wait timed out.\n"); + + hr = IPin_EndOfStream(sink); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(!WaitForSingleObject(testsink1.eos_event, 1000), "Wait timed out.\n"); + ok(!WaitForSingleObject(testsink2.eos_event, 1000), "Wait timed out.\n"); + + hr = IPin_EndOfStream(sink); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(!WaitForSingleObject(testsink1.eos_event, 1000), "Wait timed out.\n"); + ok(!WaitForSingleObject(testsink2.eos_event, 1000), "Wait timed out.\n"); + + ok(!testsink1.got_begin_flush, "Got %u calls to IPin::BeginFlush().\n", testsink1.got_begin_flush); + ok(!testsink2.got_begin_flush, "Got %u calls to IPin::BeginFlush().\n", testsink2.got_begin_flush); + hr = IPin_BeginFlush(sink); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(testsink1.got_begin_flush == 1, "Got %u calls to IPin::BeginFlush().\n", testsink1.got_begin_flush); + ok(testsink2.got_begin_flush == 1, "Got %u calls to IPin::BeginFlush().\n", testsink2.got_begin_flush); + + hr = IMemInputPin_Receive(input, sample); + todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr); + + hr = IPin_EndOfStream(sink); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + /* No EOS events are sent downstream, however. */ + + ok(!testsink1.got_end_flush, "Got %u calls to IPin::EndFlush().\n", testsink1.got_end_flush); + ok(!testsink2.got_end_flush, "Got %u calls to IPin::EndFlush().\n", testsink2.got_end_flush); + hr = IPin_EndFlush(sink); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(testsink1.got_end_flush == 1, "Got %u calls to IPin::EndFlush().\n", testsink1.got_end_flush); + ok(testsink2.got_end_flush == 1, "Got %u calls to IPin::EndFlush().\n", testsink2.got_end_flush); + + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(!WaitForSingleObject(testsink1.sample_event, 1000), "Wait timed out.\n"); + ok(!WaitForSingleObject(testsink2.sample_event, 1000), "Wait timed out.\n"); + + hr = IMediaControl_Stop(control); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMemInputPin_Receive(input, sample); + todo_wine ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr); + + hr = IPin_EndOfStream(sink); + ok(hr == S_OK, "Got hr %#x.\n", hr); + /* No EOS events are sent downstream, however. */ + + IMediaSample_Release(sample); + IMemAllocator_Release(allocator); + IMemInputPin_Release(input); + IPin_Release(sink); + IPin_Release(capture); + IPin_Release(preview); + IMediaControl_Release(control); + 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(&testsource.filter.IBaseFilter_iface); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IBaseFilter_Release(&testsink1.filter.IBaseFilter_iface); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IBaseFilter_Release(&testsink2.filter.IBaseFilter_iface); + ok(!ref, "Got outstanding refcount %d.\n", ref); +} + START_TEST(smartteefilter) { CoInitialize(NULL); @@ -2805,6 +3064,7 @@ START_TEST(smartteefilter) test_enum_media_types(); test_unconnected_filter_state(); test_connect_pin(); + test_streaming();
test_smart_tee_filter();
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/qcap/tests/smartteefilter.c | 1653 ------------------------------ 1 file changed, 1653 deletions(-)
diff --git a/dlls/qcap/tests/smartteefilter.c b/dlls/qcap/tests/smartteefilter.c index bd51743de76..df741ba1284 100644 --- a/dlls/qcap/tests/smartteefilter.c +++ b/dlls/qcap/tests/smartteefilter.c @@ -563,1657 +563,6 @@ static void test_enum_media_types(void) ok(!ref, "Got outstanding refcount %d.\n", ref); }
-typedef struct { - IBaseFilter IBaseFilter_iface; - LONG ref; - BOOL isCapture; - DWORD receiveThreadId; - IPin IPin_iface; - IMemInputPin IMemInputPin_iface; - IMemAllocator *allocator; - IBaseFilter *nullRenderer; - IPin *nullRendererPin; - IMemInputPin *nullRendererMemInputPin; -} SinkFilter; - -typedef struct { - IEnumPins IEnumPins_iface; - LONG ref; - ULONG index; - SinkFilter *filter; -} SinkEnumPins; - -static SinkEnumPins* create_SinkEnumPins(SinkFilter *filter); - -static inline SinkFilter* impl_from_SinkFilter_IBaseFilter(IBaseFilter *iface) -{ - return CONTAINING_RECORD(iface, SinkFilter, IBaseFilter_iface); -} - -static inline SinkFilter* impl_from_SinkFilter_IPin(IPin *iface) -{ - return CONTAINING_RECORD(iface, SinkFilter, IPin_iface); -} - -static inline SinkFilter* impl_from_SinkFilter_IMemInputPin(IMemInputPin *iface) -{ - return CONTAINING_RECORD(iface, SinkFilter, IMemInputPin_iface); -} - -static inline SinkEnumPins* impl_from_SinkFilter_IEnumPins(IEnumPins *iface) -{ - return CONTAINING_RECORD(iface, SinkEnumPins, IEnumPins_iface); -} - -static HRESULT WINAPI SinkFilter_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppv) -{ - SinkFilter *This = impl_from_SinkFilter_IBaseFilter(iface); - if(IsEqualIID(riid, &IID_IUnknown)) { - *ppv = &This->IBaseFilter_iface; - } else if(IsEqualIID(riid, &IID_IPersist)) { - *ppv = &This->IBaseFilter_iface; - } else if(IsEqualIID(riid, &IID_IMediaFilter)) { - *ppv = &This->IBaseFilter_iface; - } else if(IsEqualIID(riid, &IID_IBaseFilter)) { - *ppv = &This->IBaseFilter_iface; - } else { - trace("no interface for %s\n", wine_dbgstr_guid(riid)); - *ppv = NULL; - return E_NOINTERFACE; - } - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; -} - -static ULONG WINAPI SinkFilter_AddRef(IBaseFilter *iface) -{ - SinkFilter *This = impl_from_SinkFilter_IBaseFilter(iface); - return InterlockedIncrement(&This->ref); -} - -static ULONG WINAPI SinkFilter_Release(IBaseFilter *iface) -{ - SinkFilter *This = impl_from_SinkFilter_IBaseFilter(iface); - ULONG ref = InterlockedDecrement(&This->ref); - if(!ref) { - if (This->allocator) - IMemAllocator_Release(This->allocator); - IMemInputPin_Release(This->nullRendererMemInputPin); - IPin_Release(This->nullRendererPin); - IBaseFilter_Release(This->nullRenderer); - CoTaskMemFree(This); - } - return ref; -} - -static HRESULT WINAPI SinkFilter_GetClassID(IBaseFilter *iface, CLSID *pClassID) -{ - SinkFilter *This = impl_from_SinkFilter_IBaseFilter(iface); - return IBaseFilter_GetClassID(This->nullRenderer, pClassID); -} - -static HRESULT WINAPI SinkFilter_Stop(IBaseFilter *iface) -{ - SinkFilter *This = impl_from_SinkFilter_IBaseFilter(iface); - return IBaseFilter_Stop(This->nullRenderer); -} - -static HRESULT WINAPI SinkFilter_Pause(IBaseFilter *iface) -{ - SinkFilter *This = impl_from_SinkFilter_IBaseFilter(iface); - return IBaseFilter_Pause(This->nullRenderer); -} - -static HRESULT WINAPI SinkFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart) -{ - SinkFilter *This = impl_from_SinkFilter_IBaseFilter(iface); - return IBaseFilter_Run(This->nullRenderer, tStart); -} - -static HRESULT WINAPI SinkFilter_GetState(IBaseFilter *iface, DWORD dwMilliSecsTimeout, FILTER_STATE *state) -{ - SinkFilter *This = impl_from_SinkFilter_IBaseFilter(iface); - return IBaseFilter_GetState(This->nullRenderer, dwMilliSecsTimeout, state); -} - -static HRESULT WINAPI SinkFilter_SetSyncSource(IBaseFilter *iface, IReferenceClock *pClock) -{ - SinkFilter *This = impl_from_SinkFilter_IBaseFilter(iface); - return IBaseFilter_SetSyncSource(This->nullRenderer, pClock); -} - -static HRESULT WINAPI SinkFilter_GetSyncSource(IBaseFilter *iface, IReferenceClock **ppClock) -{ - SinkFilter *This = impl_from_SinkFilter_IBaseFilter(iface); - return IBaseFilter_GetSyncSource(This->nullRenderer, ppClock); -} - -static HRESULT WINAPI SinkFilter_EnumPins(IBaseFilter *iface, IEnumPins **ppEnum) -{ - SinkFilter *This = impl_from_SinkFilter_IBaseFilter(iface); - SinkEnumPins *sinkEnumPins = create_SinkEnumPins(This); - if (sinkEnumPins) { - *ppEnum = &sinkEnumPins->IEnumPins_iface; - return S_OK; - } - else - return E_OUTOFMEMORY; -} - -static HRESULT WINAPI SinkFilter_FindPin(IBaseFilter *iface, LPCWSTR id, IPin **ppPin) -{ - SinkFilter *This = impl_from_SinkFilter_IBaseFilter(iface); - HRESULT hr = IBaseFilter_FindPin(This->nullRenderer, id, ppPin); - if (SUCCEEDED(hr)) { - IPin_Release(*ppPin); - *ppPin = &This->IPin_iface; - IPin_AddRef(&This->IPin_iface); - } - return hr; -} - -static HRESULT WINAPI SinkFilter_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *pInfo) -{ - SinkFilter *This = impl_from_SinkFilter_IBaseFilter(iface); - return IBaseFilter_QueryFilterInfo(This->nullRenderer, pInfo); -} - -static HRESULT WINAPI SinkFilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *pGraph, LPCWSTR pName) -{ - SinkFilter *This = impl_from_SinkFilter_IBaseFilter(iface); - return IBaseFilter_JoinFilterGraph(This->nullRenderer, pGraph, pName); -} - -static HRESULT WINAPI SinkFilter_QueryVendorInfo(IBaseFilter *iface, LPWSTR *pVendorInfo) -{ - SinkFilter *This = impl_from_SinkFilter_IBaseFilter(iface); - return IBaseFilter_QueryVendorInfo(This->nullRenderer, pVendorInfo); -} - -static const IBaseFilterVtbl SinkFilterVtbl = { - SinkFilter_QueryInterface, - SinkFilter_AddRef, - SinkFilter_Release, - SinkFilter_GetClassID, - SinkFilter_Stop, - SinkFilter_Pause, - SinkFilter_Run, - SinkFilter_GetState, - SinkFilter_SetSyncSource, - SinkFilter_GetSyncSource, - SinkFilter_EnumPins, - SinkFilter_FindPin, - SinkFilter_QueryFilterInfo, - SinkFilter_JoinFilterGraph, - SinkFilter_QueryVendorInfo -}; - -static HRESULT WINAPI SinkEnumPins_QueryInterface(IEnumPins *iface, REFIID riid, void **ppv) -{ - SinkEnumPins *This = impl_from_SinkFilter_IEnumPins(iface); - if(IsEqualIID(riid, &IID_IUnknown)) { - *ppv = &This->IEnumPins_iface; - } else if(IsEqualIID(riid, &IID_IEnumPins)) { - *ppv = &This->IEnumPins_iface; - } else { - trace("no interface for %s\n", wine_dbgstr_guid(riid)); - *ppv = NULL; - return E_NOINTERFACE; - } - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; -} - -static ULONG WINAPI SinkEnumPins_AddRef(IEnumPins *iface) -{ - SinkEnumPins *This = impl_from_SinkFilter_IEnumPins(iface); - return InterlockedIncrement(&This->ref); -} - -static ULONG WINAPI SinkEnumPins_Release(IEnumPins *iface) -{ - SinkEnumPins *This = impl_from_SinkFilter_IEnumPins(iface); - ULONG ref; - ref = InterlockedDecrement(&This->ref); - if (ref == 0) - { - IBaseFilter_Release(&This->filter->IBaseFilter_iface); - CoTaskMemFree(This); - } - return ref; -} - -static HRESULT WINAPI SinkEnumPins_Next(IEnumPins *iface, ULONG cPins, IPin **ppPins, ULONG *pcFetched) -{ - SinkEnumPins *This = impl_from_SinkFilter_IEnumPins(iface); - if (!ppPins) - return E_POINTER; - if (cPins > 1 && !pcFetched) - return E_INVALIDARG; - if (pcFetched) - *pcFetched = 0; - if (cPins == 0) - return S_OK; - if (This->index == 0) { - ppPins[0] = &This->filter->IPin_iface; - IPin_AddRef(&This->filter->IPin_iface); - ++This->index; - if (pcFetched) - *pcFetched = 1; - return S_OK; - } - return S_FALSE; -} - -static HRESULT WINAPI SinkEnumPins_Skip(IEnumPins *iface, ULONG cPins) -{ - SinkEnumPins *This = impl_from_SinkFilter_IEnumPins(iface); - if (This->index + cPins >= 1) - return S_FALSE; - This->index += cPins; - return S_OK; -} - -static HRESULT WINAPI SinkEnumPins_Reset(IEnumPins *iface) -{ - SinkEnumPins *This = impl_from_SinkFilter_IEnumPins(iface); - This->index = 0; - return S_OK; -} - -static HRESULT WINAPI SinkEnumPins_Clone(IEnumPins *iface, IEnumPins **ppEnum) -{ - SinkEnumPins *This = impl_from_SinkFilter_IEnumPins(iface); - SinkEnumPins *clone = create_SinkEnumPins(This->filter); - if (clone == NULL) - return E_OUTOFMEMORY; - clone->index = This->index; - *ppEnum = &clone->IEnumPins_iface; - return S_OK; -} - -static const IEnumPinsVtbl SinkEnumPinsVtbl = { - SinkEnumPins_QueryInterface, - SinkEnumPins_AddRef, - SinkEnumPins_Release, - SinkEnumPins_Next, - SinkEnumPins_Skip, - SinkEnumPins_Reset, - SinkEnumPins_Clone -}; - -static SinkEnumPins* create_SinkEnumPins(SinkFilter *filter) -{ - SinkEnumPins *This; - This = CoTaskMemAlloc(sizeof(*This)); - if (This == NULL) { - return NULL; - } - This->IEnumPins_iface.lpVtbl = &SinkEnumPinsVtbl; - This->ref = 1; - This->index = 0; - This->filter = filter; - IBaseFilter_AddRef(&filter->IBaseFilter_iface); - return This; -} - -static HRESULT WINAPI SinkPin_QueryInterface(IPin *iface, REFIID riid, void **ppv) -{ - SinkFilter *This = impl_from_SinkFilter_IPin(iface); - if(IsEqualIID(riid, &IID_IUnknown)) { - *ppv = &This->IPin_iface; - } else if(IsEqualIID(riid, &IID_IPin)) { - *ppv = &This->IPin_iface; - } else if(IsEqualIID(riid, &IID_IMemInputPin)) { - *ppv = &This->IMemInputPin_iface; - } else { - trace("no interface for %s\n", wine_dbgstr_guid(riid)); - *ppv = NULL; - return E_NOINTERFACE; - } - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; -} - -static ULONG WINAPI SinkPin_AddRef(IPin *iface) -{ - SinkFilter *This = impl_from_SinkFilter_IPin(iface); - return IBaseFilter_AddRef(&This->IBaseFilter_iface); -} - -static ULONG WINAPI SinkPin_Release(IPin *iface) -{ - SinkFilter *This = impl_from_SinkFilter_IPin(iface); - return IBaseFilter_Release(&This->IBaseFilter_iface); -} - -static HRESULT WINAPI SinkPin_Connect(IPin *iface, IPin *pReceivePin, const AM_MEDIA_TYPE *pmt) -{ - SinkFilter *This = impl_from_SinkFilter_IPin(iface); - return IPin_Connect(This->nullRendererPin, pReceivePin, pmt); -} - -static HRESULT WINAPI SinkPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *pmt) -{ - SinkFilter *This = impl_from_SinkFilter_IPin(iface); - return IPin_ReceiveConnection(This->nullRendererPin, connector, pmt); -} - -static HRESULT WINAPI SinkPin_Disconnect(IPin *iface) -{ - SinkFilter *This = impl_from_SinkFilter_IPin(iface); - return IPin_Disconnect(This->nullRendererPin); -} - -static HRESULT WINAPI SinkPin_ConnectedTo(IPin *iface, IPin **pPin) -{ - SinkFilter *This = impl_from_SinkFilter_IPin(iface); - return IPin_ConnectedTo(This->nullRendererPin, pPin); -} - -static HRESULT WINAPI SinkPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *pmt) -{ - SinkFilter *This = impl_from_SinkFilter_IPin(iface); - return IPin_ConnectionMediaType(This->nullRendererPin, pmt); -} - -static HRESULT WINAPI SinkPin_QueryPinInfo(IPin *iface, PIN_INFO *pInfo) -{ - SinkFilter *This = impl_from_SinkFilter_IPin(iface); - HRESULT hr = IPin_QueryPinInfo(This->nullRendererPin, pInfo); - if (SUCCEEDED(hr)) { - IBaseFilter_Release(pInfo->pFilter); - pInfo->pFilter = &This->IBaseFilter_iface; - IBaseFilter_AddRef(&This->IBaseFilter_iface); - } - return hr; -} - -static HRESULT WINAPI SinkPin_QueryDirection(IPin *iface, PIN_DIRECTION *pPinDir) -{ - SinkFilter *This = impl_from_SinkFilter_IPin(iface); - return IPin_QueryDirection(This->nullRendererPin, pPinDir); -} - -static HRESULT WINAPI SinkPin_QueryId(IPin *iface, LPWSTR *id) -{ - SinkFilter *This = impl_from_SinkFilter_IPin(iface); - return IPin_QueryId(This->nullRendererPin, id); -} - -static HRESULT WINAPI SinkPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt) -{ - SinkFilter *This = impl_from_SinkFilter_IPin(iface); - return IPin_QueryAccept(This->nullRendererPin, pmt); -} - -static HRESULT WINAPI SinkPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **ppEnum) -{ - SinkFilter *This = impl_from_SinkFilter_IPin(iface); - return IPin_EnumMediaTypes(This->nullRendererPin, ppEnum); -} - -static HRESULT WINAPI SinkPin_QueryInternalConnections(IPin *iface, IPin **apPin, ULONG *nPin) -{ - SinkFilter *This = impl_from_SinkFilter_IPin(iface); - return IPin_QueryInternalConnections(This->nullRendererPin, apPin, nPin); -} - -static HRESULT WINAPI SinkPin_EndOfStream(IPin *iface) -{ - SinkFilter *This = impl_from_SinkFilter_IPin(iface); - return IPin_EndOfStream(This->nullRendererPin); -} - -static HRESULT WINAPI SinkPin_BeginFlush(IPin *iface) -{ - SinkFilter *This = impl_from_SinkFilter_IPin(iface); - return IPin_BeginFlush(This->nullRendererPin); -} - -static HRESULT WINAPI SinkPin_EndFlush(IPin *iface) -{ - SinkFilter *This = impl_from_SinkFilter_IPin(iface); - return IPin_EndFlush(This->nullRendererPin); -} - -static HRESULT WINAPI SinkPin_NewSegment(IPin *iface, REFERENCE_TIME tStart, - REFERENCE_TIME tStop, double dRate) -{ - SinkFilter *This = impl_from_SinkFilter_IPin(iface); - return IPin_NewSegment(This->nullRendererPin, tStart, tStop, dRate); -} - -static const IPinVtbl SinkPinVtbl = { - SinkPin_QueryInterface, - SinkPin_AddRef, - SinkPin_Release, - SinkPin_Connect, - SinkPin_ReceiveConnection, - SinkPin_Disconnect, - SinkPin_ConnectedTo, - SinkPin_ConnectionMediaType, - SinkPin_QueryPinInfo, - SinkPin_QueryDirection, - SinkPin_QueryId, - SinkPin_QueryAccept, - SinkPin_EnumMediaTypes, - SinkPin_QueryInternalConnections, - SinkPin_EndOfStream, - SinkPin_BeginFlush, - SinkPin_EndFlush, - SinkPin_NewSegment -}; - -static HRESULT WINAPI SinkMemInputPin_QueryInterface(IMemInputPin *iface, REFIID riid, void **ppv) -{ - SinkFilter *This = impl_from_SinkFilter_IMemInputPin(iface); - return IPin_QueryInterface(&This->IPin_iface, riid, ppv); -} - -static ULONG WINAPI SinkMemInputPin_AddRef(IMemInputPin *iface) -{ - SinkFilter *This = impl_from_SinkFilter_IMemInputPin(iface); - return IBaseFilter_AddRef(&This->IBaseFilter_iface); -} - -static ULONG WINAPI SinkMemInputPin_Release(IMemInputPin *iface) -{ - SinkFilter *This = impl_from_SinkFilter_IMemInputPin(iface); - return IBaseFilter_Release(&This->IBaseFilter_iface); -} - -static HRESULT WINAPI SinkMemInputPin_GetAllocator(IMemInputPin *iface, IMemAllocator **ppAllocator) -{ - SinkFilter *This = impl_from_SinkFilter_IMemInputPin(iface); - ok(0, "SmartTeeFilter never calls IMemInputPin_GetAllocator()\n"); - return IMemInputPin_GetAllocator(This->nullRendererMemInputPin, ppAllocator); -} - -static HRESULT WINAPI SinkMemInputPin_NotifyAllocator(IMemInputPin *iface, IMemAllocator *pAllocator, - BOOL bReadOnly) -{ - SinkFilter *This = impl_from_SinkFilter_IMemInputPin(iface); - This->allocator = pAllocator; - IMemAllocator_AddRef(This->allocator); - ok(bReadOnly, "bReadOnly isn't supposed to be FALSE\n"); - return IMemInputPin_NotifyAllocator(This->nullRendererMemInputPin, pAllocator, bReadOnly); -} - -static HRESULT WINAPI SinkMemInputPin_GetAllocatorRequirements(IMemInputPin *iface, - ALLOCATOR_PROPERTIES *pProps) -{ - SinkFilter *This = impl_from_SinkFilter_IMemInputPin(iface); - ok(0, "SmartTeeFilter never calls IMemInputPin_GetAllocatorRequirements()\n"); - return IMemInputPin_GetAllocatorRequirements(This->nullRendererMemInputPin, pProps); -} - -static HRESULT WINAPI SinkMemInputPin_Receive(IMemInputPin *iface, IMediaSample *pSample) -{ - LONG samplesProcessed; - todo_wine ok(0, "SmartTeeFilter never calls IMemInputPin_Receive(), only IMemInputPin_ReceiveMultiple()\n"); - return IMemInputPin_ReceiveMultiple(iface, &pSample, 1, &samplesProcessed); -} - -static HRESULT WINAPI SinkMemInputPin_ReceiveMultiple(IMemInputPin *iface, IMediaSample **pSamples, - LONG nSamples, LONG *nSamplesProcessed) -{ - SinkFilter *This = impl_from_SinkFilter_IMemInputPin(iface); - IMediaSample *pSample; - REFERENCE_TIME startTime, endTime; - HRESULT hr; - ok(nSamples == 1, "expected 1 sample, got %d\n", nSamples); - pSample = pSamples[0]; - hr = IMediaSample_GetTime(pSample, &startTime, &endTime); - if (This->isCapture) - ok(SUCCEEDED(hr), "IMediaSample_GetTime() from Capture pin failed, hr=0x%08x\n", hr); - else - ok(hr == VFW_E_SAMPLE_TIME_NOT_SET, "IMediaSample_GetTime() from Preview pin returned hr=0x%08x\n", hr); - This->receiveThreadId = GetCurrentThreadId(); - SetEvent(event); - return IMemInputPin_ReceiveMultiple(This->nullRendererMemInputPin, pSamples, - nSamples, nSamplesProcessed); -} - -static HRESULT WINAPI SinkMemInputPin_ReceiveCanBlock(IMemInputPin *iface) -{ - SinkFilter *This = impl_from_SinkFilter_IMemInputPin(iface); - return IMemInputPin_ReceiveCanBlock(This->nullRendererMemInputPin); -} - -static const IMemInputPinVtbl SinkMemInputPinVtbl = { - SinkMemInputPin_QueryInterface, - SinkMemInputPin_AddRef, - SinkMemInputPin_Release, - SinkMemInputPin_GetAllocator, - SinkMemInputPin_NotifyAllocator, - SinkMemInputPin_GetAllocatorRequirements, - SinkMemInputPin_Receive, - SinkMemInputPin_ReceiveMultiple, - SinkMemInputPin_ReceiveCanBlock -}; - -static SinkFilter* create_SinkFilter(BOOL isCapture) -{ - SinkFilter *This = NULL; - HRESULT hr; - This = CoTaskMemAlloc(sizeof(*This)); - if (This) { - memset(This, 0, sizeof(*This)); - This->IBaseFilter_iface.lpVtbl = &SinkFilterVtbl; - This->ref = 1; - This->isCapture = isCapture; - This->IPin_iface.lpVtbl = &SinkPinVtbl; - This->IMemInputPin_iface.lpVtbl = &SinkMemInputPinVtbl; - hr = CoCreateInstance(&CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, - &IID_IBaseFilter, (LPVOID*)&This->nullRenderer); - if (SUCCEEDED(hr)) { - IEnumPins *enumPins = NULL; - hr = IBaseFilter_EnumPins(This->nullRenderer, &enumPins); - if (SUCCEEDED(hr)) { - hr = IEnumPins_Next(enumPins, 1, &This->nullRendererPin, NULL); - IEnumPins_Release(enumPins); - if (SUCCEEDED(hr)) { - hr = IPin_QueryInterface(This->nullRendererPin, &IID_IMemInputPin, - (LPVOID*)&This->nullRendererMemInputPin); - if (SUCCEEDED(hr)) - return This; - IPin_Release(This->nullRendererPin); - } - } - IBaseFilter_Release(This->nullRenderer); - } - CoTaskMemFree(This); - } - return NULL; -} - -typedef struct { - IBaseFilter IBaseFilter_iface; - LONG ref; - IPin IPin_iface; - IKsPropertySet IKsPropertySet_iface; - CRITICAL_SECTION cs; - FILTER_STATE state; - IReferenceClock *referenceClock; - FILTER_INFO filterInfo; - AM_MEDIA_TYPE mediaType; - VIDEOINFOHEADER videoInfo; - WAVEFORMATEX audioInfo; - IPin *connectedTo; - IMemInputPin *memInputPin; - IMemAllocator *allocator; - DWORD mediaThreadId; -} SourceFilter; - -typedef struct { - IEnumPins IEnumPins_iface; - LONG ref; - ULONG index; - SourceFilter *filter; -} SourceEnumPins; - -typedef struct { - IEnumMediaTypes IEnumMediaTypes_iface; - LONG ref; - ULONG index; - SourceFilter *filter; -} SourceEnumMediaTypes; - -static const WCHAR sourcePinName[] = {'C','a','p','t','u','r','e',0}; - -static SourceEnumPins* create_SourceEnumPins(SourceFilter *filter); -static SourceEnumMediaTypes* create_SourceEnumMediaTypes(SourceFilter *filter); - -static inline SourceFilter* impl_from_SourceFilter_IBaseFilter(IBaseFilter *iface) -{ - return CONTAINING_RECORD(iface, SourceFilter, IBaseFilter_iface); -} - -static inline SourceFilter* impl_from_SourceFilter_IPin(IPin *iface) -{ - return CONTAINING_RECORD(iface, SourceFilter, IPin_iface); -} - -static inline SourceFilter* impl_from_SourceFilter_IKsPropertySet(IKsPropertySet *iface) -{ - return CONTAINING_RECORD(iface, SourceFilter, IKsPropertySet_iface); -} - -static inline SourceEnumPins* impl_from_SourceFilter_IEnumPins(IEnumPins *iface) -{ - return CONTAINING_RECORD(iface, SourceEnumPins, IEnumPins_iface); -} - -static inline SourceEnumMediaTypes* impl_from_SourceFilter_IEnumMediaTypes(IEnumMediaTypes *iface) -{ - return CONTAINING_RECORD(iface, SourceEnumMediaTypes, IEnumMediaTypes_iface); -} - -static HRESULT WINAPI SourceFilter_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppv) -{ - SourceFilter *This = impl_from_SourceFilter_IBaseFilter(iface); - if(IsEqualIID(riid, &IID_IUnknown)) { - *ppv = &This->IBaseFilter_iface; - } else if(IsEqualIID(riid, &IID_IPersist)) { - *ppv = &This->IBaseFilter_iface; - } else if(IsEqualIID(riid, &IID_IMediaFilter)) { - *ppv = &This->IBaseFilter_iface; - } else if(IsEqualIID(riid, &IID_IBaseFilter)) { - *ppv = &This->IBaseFilter_iface; - } else { - trace("no interface for %s\n", wine_dbgstr_guid(riid)); - *ppv = NULL; - return E_NOINTERFACE; - } - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; -} - -static ULONG WINAPI SourceFilter_AddRef(IBaseFilter *iface) -{ - SourceFilter *This = impl_from_SourceFilter_IBaseFilter(iface); - return InterlockedIncrement(&This->ref); -} - -static ULONG WINAPI SourceFilter_Release(IBaseFilter *iface) -{ - SourceFilter *This = impl_from_SourceFilter_IBaseFilter(iface); - ULONG ref = InterlockedDecrement(&This->ref); - if(!ref) { - if (This->referenceClock) - IReferenceClock_Release(This->referenceClock); - if (This->connectedTo) - IPin_Disconnect(&This->IPin_iface); - DeleteCriticalSection(&This->cs); - CoTaskMemFree(This); - } - return ref; -} - -static HRESULT WINAPI SourceFilter_GetClassID(IBaseFilter *iface, CLSID *pClassID) -{ - *pClassID = CLSID_VfwCapture; - return S_OK; -} - -static HRESULT WINAPI SourceFilter_Stop(IBaseFilter *iface) -{ - SourceFilter *This = impl_from_SourceFilter_IBaseFilter(iface); - EnterCriticalSection(&This->cs); - IMemAllocator_Decommit(This->allocator); - This->state = State_Stopped; - LeaveCriticalSection(&This->cs); - return S_OK; -} - -static HRESULT WINAPI SourceFilter_Pause(IBaseFilter *iface) -{ - SourceFilter *This = impl_from_SourceFilter_IBaseFilter(iface); - EnterCriticalSection(&This->cs); - This->state = State_Paused; - LeaveCriticalSection(&This->cs); - return S_OK; -} - -static DWORD WINAPI media_thread(LPVOID param) -{ - SourceFilter *This = (SourceFilter*) param; - HRESULT hr; - IMediaSample *sample = NULL; - REFERENCE_TIME startTime; - REFERENCE_TIME endTime; - BYTE *buffer; - - hr = IMemAllocator_GetBuffer(This->allocator, &sample, NULL, NULL, 0); - ok(SUCCEEDED(hr), "IMemAllocator_GetBuffer() failed, hr=0x%08x\n", hr); - if (SUCCEEDED(hr)) { - startTime = 10; - endTime = 20; - hr = IMediaSample_SetTime(sample, &startTime, &endTime); - ok(SUCCEEDED(hr), "IMediaSample_SetTime() failed, hr=0x%08x\n", hr); - hr = IMediaSample_SetMediaType(sample, &This->mediaType); - ok(SUCCEEDED(hr), "IMediaSample_SetMediaType() failed, hr=0x%08x\n", hr); - - hr = IMediaSample_GetPointer(sample, &buffer); - ok(SUCCEEDED(hr), "IMediaSample_GetPointer() failed, hr=0x%08x\n", hr); - if (SUCCEEDED(hr)) { - /* 10 by 10 pixel 32 RGB */ - int i; - for (i = 0; i < 100; i++) - buffer[4*i] = i; - } - - hr = IMemInputPin_Receive(This->memInputPin, sample); - ok(SUCCEEDED(hr), "delivering sample to SmartTeeFilter's Input pin failed, hr=0x%08x\n", hr); - - IMediaSample_Release(sample); - } - return 0; -} - -static HRESULT WINAPI SourceFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart) -{ - SourceFilter *This = impl_from_SourceFilter_IBaseFilter(iface); - HRESULT hr; - EnterCriticalSection(&This->cs); - hr = IMemAllocator_Commit(This->allocator); - if (SUCCEEDED(hr)) { - HANDLE thread = CreateThread(NULL, 0, media_thread, This, 0, &This->mediaThreadId); - ok(thread != NULL, "couldn't create media thread, GetLastError()=%u\n", GetLastError()); - if (thread != NULL) { - CloseHandle(thread); - This->state = State_Running; - } else { - IMemAllocator_Decommit(This->allocator); - hr = E_FAIL; - } - } - LeaveCriticalSection(&This->cs); - return hr; -} - -static HRESULT WINAPI SourceFilter_GetState(IBaseFilter *iface, DWORD dwMilliSecsTimeout, FILTER_STATE *state) -{ - SourceFilter *This = impl_from_SourceFilter_IBaseFilter(iface); - EnterCriticalSection(&This->cs); - *state = This->state; - LeaveCriticalSection(&This->cs); - return S_OK; -} - -static HRESULT WINAPI SourceFilter_SetSyncSource(IBaseFilter *iface, IReferenceClock *pClock) -{ - SourceFilter *This = impl_from_SourceFilter_IBaseFilter(iface); - EnterCriticalSection(&This->cs); - if (This->referenceClock) - IReferenceClock_Release(This->referenceClock); - This->referenceClock = pClock; - if (This->referenceClock) - IReferenceClock_AddRef(This->referenceClock); - LeaveCriticalSection(&This->cs); - return S_OK; -} - -static HRESULT WINAPI SourceFilter_GetSyncSource(IBaseFilter *iface, IReferenceClock **ppClock) -{ - SourceFilter *This = impl_from_SourceFilter_IBaseFilter(iface); - EnterCriticalSection(&This->cs); - *ppClock = This->referenceClock; - if (This->referenceClock) - IReferenceClock_AddRef(This->referenceClock); - LeaveCriticalSection(&This->cs); - return S_OK; -} - -static HRESULT WINAPI SourceFilter_EnumPins(IBaseFilter *iface, IEnumPins **ppEnum) -{ - SourceFilter *This = impl_from_SourceFilter_IBaseFilter(iface); - SourceEnumPins *sourceEnumPins = create_SourceEnumPins(This); - if (sourceEnumPins) { - *ppEnum = &sourceEnumPins->IEnumPins_iface; - return S_OK; - } - else - return E_OUTOFMEMORY; -} - -static HRESULT WINAPI SourceFilter_FindPin(IBaseFilter *iface, LPCWSTR id, IPin **ppPin) -{ - SourceFilter *This = impl_from_SourceFilter_IBaseFilter(iface); - if (ppPin == NULL) - return E_POINTER; - *ppPin = NULL; - if (lstrcmpW(id, sourcePinName) == 0) { - *ppPin = &This->IPin_iface; - IPin_AddRef(&This->IPin_iface); - return S_OK; - } - return VFW_E_NOT_FOUND; -} - -static HRESULT WINAPI SourceFilter_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *pInfo) -{ - SourceFilter *This = impl_from_SourceFilter_IBaseFilter(iface); - if (!pInfo) - return E_POINTER; - EnterCriticalSection(&This->cs); - *pInfo = This->filterInfo; - if (This->filterInfo.pGraph) - IFilterGraph_AddRef(This->filterInfo.pGraph); - LeaveCriticalSection(&This->cs); - return S_OK; -} - -static HRESULT WINAPI SourceFilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *pGraph, LPCWSTR pName) -{ - SourceFilter *This = impl_from_SourceFilter_IBaseFilter(iface); - EnterCriticalSection(&This->cs); - if (pName) - lstrcpyW(This->filterInfo.achName, pName); - else - This->filterInfo.achName[0] = 0; - This->filterInfo.pGraph = pGraph; - LeaveCriticalSection(&This->cs); - return S_OK; -} - -static HRESULT WINAPI SourceFilter_QueryVendorInfo(IBaseFilter *iface, LPWSTR *pVendorInfo) -{ - return E_NOTIMPL; -} - -static const IBaseFilterVtbl SourceFilterVtbl = { - SourceFilter_QueryInterface, - SourceFilter_AddRef, - SourceFilter_Release, - SourceFilter_GetClassID, - SourceFilter_Stop, - SourceFilter_Pause, - SourceFilter_Run, - SourceFilter_GetState, - SourceFilter_SetSyncSource, - SourceFilter_GetSyncSource, - SourceFilter_EnumPins, - SourceFilter_FindPin, - SourceFilter_QueryFilterInfo, - SourceFilter_JoinFilterGraph, - SourceFilter_QueryVendorInfo -}; - -static HRESULT WINAPI SourceEnumPins_QueryInterface(IEnumPins *iface, REFIID riid, void **ppv) -{ - SourceEnumPins *This = impl_from_SourceFilter_IEnumPins(iface); - if(IsEqualIID(riid, &IID_IUnknown)) { - *ppv = &This->IEnumPins_iface; - } else if(IsEqualIID(riid, &IID_IEnumPins)) { - *ppv = &This->IEnumPins_iface; - } else { - trace("no interface for %s\n", wine_dbgstr_guid(riid)); - *ppv = NULL; - return E_NOINTERFACE; - } - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; -} - -static ULONG WINAPI SourceEnumPins_AddRef(IEnumPins *iface) -{ - SourceEnumPins *This = impl_from_SourceFilter_IEnumPins(iface); - return InterlockedIncrement(&This->ref); -} - -static ULONG WINAPI SourceEnumPins_Release(IEnumPins *iface) -{ - SourceEnumPins *This = impl_from_SourceFilter_IEnumPins(iface); - ULONG ref; - ref = InterlockedDecrement(&This->ref); - if (ref == 0) - { - IBaseFilter_Release(&This->filter->IBaseFilter_iface); - CoTaskMemFree(This); - } - return ref; -} - -static HRESULT WINAPI SourceEnumPins_Next(IEnumPins *iface, ULONG cPins, IPin **ppPins, ULONG *pcFetched) -{ - SourceEnumPins *This = impl_from_SourceFilter_IEnumPins(iface); - if (!ppPins) - return E_POINTER; - if (cPins > 1 && !pcFetched) - return E_INVALIDARG; - if (pcFetched) - *pcFetched = 0; - if (cPins == 0) - return S_OK; - if (This->index == 0) { - ppPins[0] = &This->filter->IPin_iface; - IPin_AddRef(&This->filter->IPin_iface); - ++This->index; - if (pcFetched) - *pcFetched = 1; - return S_OK; - } - return S_FALSE; -} - -static HRESULT WINAPI SourceEnumPins_Skip(IEnumPins *iface, ULONG cPins) -{ - SourceEnumPins *This = impl_from_SourceFilter_IEnumPins(iface); - if (This->index + cPins >= 1) - return S_FALSE; - This->index += cPins; - return S_OK; -} - -static HRESULT WINAPI SourceEnumPins_Reset(IEnumPins *iface) -{ - SourceEnumPins *This = impl_from_SourceFilter_IEnumPins(iface); - This->index = 0; - return S_OK; -} - -static HRESULT WINAPI SourceEnumPins_Clone(IEnumPins *iface, IEnumPins **ppEnum) -{ - SourceEnumPins *This = impl_from_SourceFilter_IEnumPins(iface); - SourceEnumPins *clone = create_SourceEnumPins(This->filter); - if (clone == NULL) - return E_OUTOFMEMORY; - clone->index = This->index; - *ppEnum = &clone->IEnumPins_iface; - return S_OK; -} - -static const IEnumPinsVtbl SourceEnumPinsVtbl = { - SourceEnumPins_QueryInterface, - SourceEnumPins_AddRef, - SourceEnumPins_Release, - SourceEnumPins_Next, - SourceEnumPins_Skip, - SourceEnumPins_Reset, - SourceEnumPins_Clone -}; - -static SourceEnumPins* create_SourceEnumPins(SourceFilter *filter) -{ - SourceEnumPins *This; - This = CoTaskMemAlloc(sizeof(*This)); - if (This == NULL) { - return NULL; - } - This->IEnumPins_iface.lpVtbl = &SourceEnumPinsVtbl; - This->ref = 1; - This->index = 0; - This->filter = filter; - IBaseFilter_AddRef(&filter->IBaseFilter_iface); - return This; -} - -static HRESULT WINAPI SourceEnumMediaTypes_QueryInterface(IEnumMediaTypes *iface, REFIID riid, void **ppv) -{ - SourceEnumMediaTypes *This = impl_from_SourceFilter_IEnumMediaTypes(iface); - if(IsEqualIID(riid, &IID_IUnknown)) { - *ppv = &This->IEnumMediaTypes_iface; - } else if(IsEqualIID(riid, &IID_IEnumMediaTypes)) { - *ppv = &This->IEnumMediaTypes_iface; - } else { - trace("no interface for %s\n", wine_dbgstr_guid(riid)); - *ppv = NULL; - return E_NOINTERFACE; - } - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; -} - -static ULONG WINAPI SourceEnumMediaTypes_AddRef(IEnumMediaTypes *iface) -{ - SourceEnumMediaTypes *This = impl_from_SourceFilter_IEnumMediaTypes(iface); - return InterlockedIncrement(&This->ref); -} - -static ULONG WINAPI SourceEnumMediaTypes_Release(IEnumMediaTypes *iface) -{ - SourceEnumMediaTypes *This = impl_from_SourceFilter_IEnumMediaTypes(iface); - ULONG ref; - ref = InterlockedDecrement(&This->ref); - if (ref == 0) - { - IBaseFilter_Release(&This->filter->IBaseFilter_iface); - CoTaskMemFree(This); - } - return ref; -} - -static HRESULT WINAPI SourceEnumMediaTypes_Next(IEnumMediaTypes *iface, ULONG cMediaTypes, AM_MEDIA_TYPE **ppMediaTypes, ULONG *pcFetched) -{ - SourceEnumMediaTypes *This = impl_from_SourceFilter_IEnumMediaTypes(iface); - if (!ppMediaTypes) - return E_POINTER; - if (cMediaTypes > 1 && !pcFetched) - return E_INVALIDARG; - if (pcFetched) - *pcFetched = 0; - if (cMediaTypes == 0) - return S_OK; - if (This->index == 0) { - ppMediaTypes[0] = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); - if (ppMediaTypes[0]) { - *ppMediaTypes[0] = This->filter->mediaType; - ppMediaTypes[0]->pbFormat = CoTaskMemAlloc(This->filter->mediaType.cbFormat); - if (ppMediaTypes[0]->pbFormat) { - memcpy(ppMediaTypes[0]->pbFormat, This->filter->mediaType.pbFormat, This->filter->mediaType.cbFormat); - ++This->index; - if (pcFetched) - *pcFetched = 1; - return S_OK; - } - CoTaskMemFree(ppMediaTypes[0]); - } - return E_OUTOFMEMORY; - } - return S_FALSE; -} - -static HRESULT WINAPI SourceEnumMediaTypes_Skip(IEnumMediaTypes *iface, ULONG cMediaTypes) -{ - SourceEnumMediaTypes *This = impl_from_SourceFilter_IEnumMediaTypes(iface); - This->index += cMediaTypes; - if (This->index >= 1) - return S_FALSE; - return S_OK; -} - -static HRESULT WINAPI SourceEnumMediaTypes_Reset(IEnumMediaTypes *iface) -{ - SourceEnumMediaTypes *This = impl_from_SourceFilter_IEnumMediaTypes(iface); - This->index = 0; - return S_OK; -} - -static HRESULT WINAPI SourceEnumMediaTypes_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **ppEnum) -{ - SourceEnumMediaTypes *This = impl_from_SourceFilter_IEnumMediaTypes(iface); - SourceEnumMediaTypes *clone = create_SourceEnumMediaTypes(This->filter); - if (clone == NULL) - return E_OUTOFMEMORY; - clone->index = This->index; - *ppEnum = &clone->IEnumMediaTypes_iface; - return S_OK; -} - -static const IEnumMediaTypesVtbl SourceEnumMediaTypesVtbl = { - SourceEnumMediaTypes_QueryInterface, - SourceEnumMediaTypes_AddRef, - SourceEnumMediaTypes_Release, - SourceEnumMediaTypes_Next, - SourceEnumMediaTypes_Skip, - SourceEnumMediaTypes_Reset, - SourceEnumMediaTypes_Clone -}; - -static SourceEnumMediaTypes* create_SourceEnumMediaTypes(SourceFilter *filter) -{ - SourceEnumMediaTypes *This; - This = CoTaskMemAlloc(sizeof(*This)); - if (This == NULL) { - return NULL; - } - This->IEnumMediaTypes_iface.lpVtbl = &SourceEnumMediaTypesVtbl; - This->ref = 1; - This->index = 0; - This->filter = filter; - IBaseFilter_AddRef(&filter->IBaseFilter_iface); - return This; -} - -static HRESULT WINAPI SourcePin_QueryInterface(IPin *iface, REFIID riid, void **ppv) -{ - SourceFilter *This = impl_from_SourceFilter_IPin(iface); - if(IsEqualIID(riid, &IID_IUnknown)) { - *ppv = &This->IPin_iface; - } else if(IsEqualIID(riid, &IID_IPin)) { - *ppv = &This->IPin_iface; - } else if(IsEqualIID(riid, &IID_IKsPropertySet)) { - *ppv = &This->IKsPropertySet_iface; - } else { - trace("no interface for %s\n", wine_dbgstr_guid(riid)); - *ppv = NULL; - return E_NOINTERFACE; - } - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; -} - -static ULONG WINAPI SourcePin_AddRef(IPin *iface) -{ - SourceFilter *This = impl_from_SourceFilter_IPin(iface); - return IBaseFilter_AddRef(&This->IBaseFilter_iface); -} - -static ULONG WINAPI SourcePin_Release(IPin *iface) -{ - SourceFilter *This = impl_from_SourceFilter_IPin(iface); - return IBaseFilter_Release(&This->IBaseFilter_iface); -} - -static HRESULT WINAPI SourcePin_Connect(IPin *iface, IPin *pReceivePin, const AM_MEDIA_TYPE *pmt) -{ - SourceFilter *This = impl_from_SourceFilter_IPin(iface); - HRESULT hr; - - if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->majortype, &MEDIATYPE_Video)) - return VFW_E_TYPE_NOT_ACCEPTED; - if (pmt && !IsEqualGUID(&pmt->subtype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &MEDIASUBTYPE_RGB32)) - return VFW_E_TYPE_NOT_ACCEPTED; - if (pmt && !IsEqualGUID(&pmt->formattype, &GUID_NULL)) - return VFW_E_TYPE_NOT_ACCEPTED; - hr = IPin_ReceiveConnection(pReceivePin, &This->IPin_iface, &This->mediaType); - ok(SUCCEEDED(hr), "SmartTeeFilter's Input pin's IPin_ReceiveConnection() failed with 0x%08x\n", hr); - if (SUCCEEDED(hr)) { - EnterCriticalSection(&This->cs); - hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (void**)&This->memInputPin); - if (SUCCEEDED(hr)) { - hr = IMemInputPin_GetAllocator(This->memInputPin, &This->allocator); - ok(SUCCEEDED(hr), "couldn't get allocator from SmartTeeFilter, hr=0x%08x\n", hr); - if (SUCCEEDED(hr)) { - ALLOCATOR_PROPERTIES requested, actual; - ZeroMemory(&requested, sizeof(ALLOCATOR_PROPERTIES)); - IMemInputPin_GetAllocatorRequirements(This->memInputPin, &requested); - if (requested.cBuffers < 3) requested.cBuffers = 3; - if (requested.cbBuffer < 4096) requested.cbBuffer = 4096; - if (requested.cbAlign < 1) requested.cbAlign = 1; - if (requested.cbPrefix < 0) requested.cbPrefix = 0; - hr = IMemAllocator_SetProperties(This->allocator, &requested, &actual); - if (SUCCEEDED(hr)) { - hr = IMemInputPin_NotifyAllocator(This->memInputPin, This->allocator, FALSE); - if (SUCCEEDED(hr)) { - This->connectedTo = pReceivePin; - IPin_AddRef(pReceivePin); - } - } - if (FAILED(hr)) { - IMemAllocator_Release(This->allocator); - This->allocator = NULL; - } - } - if (FAILED(hr)) { - IMemInputPin_Release(This->memInputPin); - This->memInputPin = NULL; - } - } - LeaveCriticalSection(&This->cs); - - if (FAILED(hr)) - IPin_Disconnect(pReceivePin); - } - return hr; -} - -static HRESULT WINAPI SourcePin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *pmt) -{ - return E_UNEXPECTED; -} - -static HRESULT WINAPI SourcePin_Disconnect(IPin *iface) -{ - SourceFilter *This = impl_from_SourceFilter_IPin(iface); - HRESULT hr; - EnterCriticalSection(&This->cs); - if (This->connectedTo) { - if (This->state == State_Stopped) { - IMemAllocator_Release(This->allocator); - This->allocator = NULL; - IMemInputPin_Release(This->memInputPin); - This->memInputPin = NULL; - IPin_Release(This->connectedTo); - This->connectedTo = NULL; - hr = S_OK; - } - else - hr = VFW_E_NOT_STOPPED; - } else - hr = S_FALSE; - LeaveCriticalSection(&This->cs); - return hr; -} - -static HRESULT WINAPI SourcePin_ConnectedTo(IPin *iface, IPin **pPin) -{ - SourceFilter *This = impl_from_SourceFilter_IPin(iface); - HRESULT hr; - if (!pPin) - return E_POINTER; - EnterCriticalSection(&This->cs); - if (This->connectedTo) { - *pPin = This->connectedTo; - IPin_AddRef(This->connectedTo); - hr = S_OK; - } else - hr = VFW_E_NOT_CONNECTED; - LeaveCriticalSection(&This->cs); - return hr; -} - -static HRESULT WINAPI SourcePin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *pmt) -{ - SourceFilter *This = impl_from_SourceFilter_IPin(iface); - HRESULT hr; - if (!pmt) - return E_POINTER; - EnterCriticalSection(&This->cs); - if (This->connectedTo) { - *pmt = This->mediaType; - pmt->pbFormat = CoTaskMemAlloc(sizeof(This->videoInfo)); - if (pmt->pbFormat) { - memcpy(pmt->pbFormat, &This->videoInfo, sizeof(This->videoInfo)); - hr = S_OK; - } else { - memset(pmt, 0, sizeof(*pmt)); - hr = E_OUTOFMEMORY; - } - } else { - memset(pmt, 0, sizeof(*pmt)); - hr = VFW_E_NOT_CONNECTED; - } - LeaveCriticalSection(&This->cs); - return hr; -} - -static HRESULT WINAPI SourcePin_QueryPinInfo(IPin *iface, PIN_INFO *pInfo) -{ - SourceFilter *This = impl_from_SourceFilter_IPin(iface); - if (!pInfo) - return E_POINTER; - lstrcpyW(pInfo->achName, sourcePinName); - pInfo->dir = PINDIR_OUTPUT; - pInfo->pFilter = &This->IBaseFilter_iface; - IBaseFilter_AddRef(&This->IBaseFilter_iface); - return S_OK; -} - -static HRESULT WINAPI SourcePin_QueryDirection(IPin *iface, PIN_DIRECTION *pPinDir) -{ - if (!pPinDir) - return E_POINTER; - *pPinDir = PINDIR_OUTPUT; - return S_OK; -} - -static HRESULT WINAPI SourcePin_QueryId(IPin *iface, LPWSTR *id) -{ - if (!id) - return E_POINTER; - *id = CoTaskMemAlloc((lstrlenW(sourcePinName) + 1)*sizeof(WCHAR)); - if (*id) { - lstrcpyW(*id, sourcePinName); - return S_OK; - } - return E_OUTOFMEMORY; -} - -static HRESULT WINAPI SourcePin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt) -{ - return S_OK; -} - -static HRESULT WINAPI SourcePin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **ppEnum) -{ - SourceFilter *This = impl_from_SourceFilter_IPin(iface); - SourceEnumMediaTypes *sourceEnumMediaTypes = create_SourceEnumMediaTypes(This); - if (sourceEnumMediaTypes) { - *ppEnum = &sourceEnumMediaTypes->IEnumMediaTypes_iface; - return S_OK; - } - else - return E_OUTOFMEMORY; -} - -static HRESULT WINAPI SourcePin_QueryInternalConnections(IPin *iface, IPin **apPin, ULONG *nPin) -{ - return E_NOTIMPL; -} - -static HRESULT WINAPI SourcePin_EndOfStream(IPin *iface) -{ - return E_UNEXPECTED; -} - -static HRESULT WINAPI SourcePin_BeginFlush(IPin *iface) -{ - return E_UNEXPECTED; -} - -static HRESULT WINAPI SourcePin_EndFlush(IPin *iface) -{ - return E_UNEXPECTED; -} - -static HRESULT WINAPI SourcePin_NewSegment(IPin *iface, REFERENCE_TIME tStart, - REFERENCE_TIME tStop, double dRate) -{ - return S_OK; -} - -static const IPinVtbl SourcePinVtbl = { - SourcePin_QueryInterface, - SourcePin_AddRef, - SourcePin_Release, - SourcePin_Connect, - SourcePin_ReceiveConnection, - SourcePin_Disconnect, - SourcePin_ConnectedTo, - SourcePin_ConnectionMediaType, - SourcePin_QueryPinInfo, - SourcePin_QueryDirection, - SourcePin_QueryId, - SourcePin_QueryAccept, - SourcePin_EnumMediaTypes, - SourcePin_QueryInternalConnections, - SourcePin_EndOfStream, - SourcePin_BeginFlush, - SourcePin_EndFlush, - SourcePin_NewSegment -}; - -static HRESULT WINAPI SourceKSP_QueryInterface(IKsPropertySet *iface, REFIID riid, LPVOID *ppv) -{ - SourceFilter *This = impl_from_SourceFilter_IKsPropertySet(iface); - return IPin_QueryInterface(&This->IPin_iface, riid, ppv); -} - -static ULONG WINAPI SourceKSP_AddRef(IKsPropertySet *iface) -{ - SourceFilter *This = impl_from_SourceFilter_IKsPropertySet(iface); - return IBaseFilter_AddRef(&This->IBaseFilter_iface); -} - -static ULONG WINAPI SourceKSP_Release(IKsPropertySet *iface) -{ - SourceFilter *This = impl_from_SourceFilter_IKsPropertySet(iface); - return IBaseFilter_Release(&This->IBaseFilter_iface); -} - -static HRESULT WINAPI SourceKSP_Set(IKsPropertySet *iface, REFGUID guidPropSet, DWORD dwPropID, - LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData) -{ - SourceFilter *This = impl_from_SourceFilter_IKsPropertySet(iface); - trace("(%p)->(%s, %u, %p, %u, %p, %u): stub\n", This, wine_dbgstr_guid(guidPropSet), - dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData); - return E_NOTIMPL; -} - -static HRESULT WINAPI SourceKSP_Get(IKsPropertySet *iface, REFGUID guidPropSet, DWORD dwPropID, - LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, - DWORD cbPropData, DWORD *pcbReturned) -{ - SourceFilter *This = impl_from_SourceFilter_IKsPropertySet(iface); - trace("(%p)->(%s, %u, %p, %u, %p, %u, %p)\n", This, wine_dbgstr_guid(guidPropSet), - dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned); - if (IsEqualIID(guidPropSet, &ROPSETID_Pin)) { - if (pcbReturned) - *pcbReturned = sizeof(GUID); - if (pPropData) { - LPGUID guid = pPropData; - if (cbPropData >= sizeof(GUID)) - *guid = PIN_CATEGORY_CAPTURE; - } else { - if (!pcbReturned) - return E_POINTER; - } - return S_OK; - } - return E_PROP_SET_UNSUPPORTED; -} - -static HRESULT WINAPI SourceKSP_QuerySupported(IKsPropertySet *iface, REFGUID guidPropSet, - DWORD dwPropID, DWORD *pTypeSupport) -{ - SourceFilter *This = impl_from_SourceFilter_IKsPropertySet(iface); - trace("(%p)->(%s, %u, %p): stub\n", This, wine_dbgstr_guid(guidPropSet), - dwPropID, pTypeSupport); - return E_NOTIMPL; -} - -static const IKsPropertySetVtbl SourceKSPVtbl = -{ - SourceKSP_QueryInterface, - SourceKSP_AddRef, - SourceKSP_Release, - SourceKSP_Set, - SourceKSP_Get, - SourceKSP_QuerySupported -}; - -static SourceFilter* create_SourceFilter(void) -{ - SourceFilter *This = NULL; - This = CoTaskMemAlloc(sizeof(*This)); - if (This) { - memset(This, 0, sizeof(*This)); - This->IBaseFilter_iface.lpVtbl = &SourceFilterVtbl; - This->ref = 1; - This->IPin_iface.lpVtbl = &SourcePinVtbl; - This->IKsPropertySet_iface.lpVtbl = &SourceKSPVtbl; - InitializeCriticalSection(&This->cs); - return This; - } - return NULL; -} - -static SourceFilter* create_video_SourceFilter(void) -{ - SourceFilter *This = create_SourceFilter(); - if (!This) - return NULL; - This->mediaType.majortype = MEDIATYPE_Video; - This->mediaType.subtype = MEDIASUBTYPE_RGB32; - This->mediaType.bFixedSizeSamples = FALSE; - This->mediaType.bTemporalCompression = FALSE; - This->mediaType.lSampleSize = 0; - This->mediaType.formattype = FORMAT_VideoInfo; - This->mediaType.pUnk = NULL; - This->mediaType.cbFormat = sizeof(VIDEOINFOHEADER); - This->mediaType.pbFormat = (BYTE*) &This->videoInfo; - This->videoInfo.dwBitRate = 1000000; - This->videoInfo.dwBitErrorRate = 0; - This->videoInfo.AvgTimePerFrame = 400000; - This->videoInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - This->videoInfo.bmiHeader.biWidth = 10; - This->videoInfo.bmiHeader.biHeight = 10; - This->videoInfo.bmiHeader.biPlanes = 1; - This->videoInfo.bmiHeader.biBitCount = 32; - This->videoInfo.bmiHeader.biCompression = BI_RGB; - This->videoInfo.bmiHeader.biSizeImage = 0; - This->videoInfo.bmiHeader.biXPelsPerMeter = 96; - This->videoInfo.bmiHeader.biYPelsPerMeter = 96; - This->videoInfo.bmiHeader.biClrUsed = 0; - This->videoInfo.bmiHeader.biClrImportant = 0; - return This; -} - -static void test_smart_tee_filter_in_graph(IBaseFilter *smartTeeFilter, IPin *inputPin, - IPin *capturePin, IPin *previewPin) -{ - HRESULT hr; - IGraphBuilder *graphBuilder = NULL; - IMediaControl *mediaControl = NULL; - SourceFilter *sourceFilter = NULL; - SinkFilter *captureSinkFilter = NULL; - SinkFilter *previewSinkFilter = NULL; - DWORD endTime; - - hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, - (LPVOID*)&graphBuilder); - ok(SUCCEEDED(hr), "couldn't create graph builder, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - - hr = IGraphBuilder_AddFilter(graphBuilder, smartTeeFilter, NULL); - ok(SUCCEEDED(hr), "couldn't add smart tee filter to graph, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - - captureSinkFilter = create_SinkFilter(TRUE); - if (captureSinkFilter == NULL) { - skip("couldn't create capture sink filter\n"); - goto end; - } - hr = IGraphBuilder_AddFilter(graphBuilder, &captureSinkFilter->IBaseFilter_iface, NULL); - if (FAILED(hr)) { - skip("couldn't add capture sink filter to graph, hr=0x%08x\n", hr); - goto end; - } - - previewSinkFilter = create_SinkFilter(FALSE); - if (previewSinkFilter == NULL) { - skip("couldn't create preview sink filter\n"); - goto end; - } - hr = IGraphBuilder_AddFilter(graphBuilder, &previewSinkFilter->IBaseFilter_iface, NULL); - if (FAILED(hr)) { - skip("couldn't add preview sink filter to graph, hr=0x%08x\n", hr); - goto end; - } - - hr = IGraphBuilder_Connect(graphBuilder, capturePin, &captureSinkFilter->IPin_iface); - ok(hr == VFW_E_NOT_CONNECTED, "connecting Capture pin without first connecting Input pin returned 0x%08x\n", hr); - hr = IGraphBuilder_Connect(graphBuilder, previewPin, &previewSinkFilter->IPin_iface); - ok(hr == VFW_E_NOT_CONNECTED, "connecting Preview pin without first connecting Input pin returned 0x%08x\n", hr); - - sourceFilter = create_video_SourceFilter(); - if (sourceFilter == NULL) { - skip("couldn't create source filter\n"); - goto end; - } - hr = IGraphBuilder_AddFilter(graphBuilder, &sourceFilter->IBaseFilter_iface, NULL); - ok(SUCCEEDED(hr), "couldn't add source filter to graph, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - - hr = IGraphBuilder_Connect(graphBuilder, &sourceFilter->IPin_iface, inputPin); - ok(SUCCEEDED(hr), "couldn't connect source filter to Input pin, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - hr = IGraphBuilder_Connect(graphBuilder, capturePin, &captureSinkFilter->IPin_iface); - ok(SUCCEEDED(hr), "couldn't connect Capture pin to sink, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - hr = IGraphBuilder_Connect(graphBuilder, previewPin, &previewSinkFilter->IPin_iface); - ok(SUCCEEDED(hr), "couldn't connect Preview pin to sink, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - - ok(sourceFilter->allocator == captureSinkFilter->allocator, "input and capture allocators don't match\n"); - ok(sourceFilter->allocator == previewSinkFilter->allocator, "input and preview allocators don't match\n"); - - hr = IGraphBuilder_QueryInterface(graphBuilder, &IID_IMediaControl, (void**)&mediaControl); - ok(SUCCEEDED(hr), "couldn't get IMediaControl interface from IGraphBuilder, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - hr = IMediaControl_Run(mediaControl); - ok(SUCCEEDED(hr), "IMediaControl_Run() failed, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - - endTime = GetTickCount() + 5000; - while (previewSinkFilter->receiveThreadId == 0 || captureSinkFilter->receiveThreadId == 0) { - DWORD now = GetTickCount(); - if (now < endTime) - WaitForSingleObject(event, endTime - now); - else - break; - } - if (previewSinkFilter->receiveThreadId != 0 && captureSinkFilter->receiveThreadId != 0) { - todo_wine ok(sourceFilter->mediaThreadId != captureSinkFilter->receiveThreadId, - "sending thread should != capture receiving thread\n"); - todo_wine ok(sourceFilter->mediaThreadId != previewSinkFilter->receiveThreadId, - "sending thread should != preview receiving thread\n"); - todo_wine ok(captureSinkFilter->receiveThreadId != previewSinkFilter->receiveThreadId, - "capture receiving thread should != preview receiving thread\n"); - } else { - ok(0, "timeout: threads did not receive sample in time\n"); - } - - IMediaControl_Stop(mediaControl); - -end: - if (mediaControl) - IMediaControl_Release(mediaControl); - if (graphBuilder) - IGraphBuilder_Release(graphBuilder); - if (sourceFilter) - IBaseFilter_Release(&sourceFilter->IBaseFilter_iface); - if (captureSinkFilter) - IBaseFilter_Release(&captureSinkFilter->IBaseFilter_iface); - if (previewSinkFilter) - IBaseFilter_Release(&previewSinkFilter->IBaseFilter_iface); -} - -static void test_smart_tee_filter(void) -{ - HRESULT hr; - IBaseFilter *smartTeeFilter = NULL; - IEnumPins *enumPins = NULL; - IPin *pin; - IPin *inputPin = NULL; - IPin *capturePin = NULL; - IPin *previewPin = NULL; - FILTER_INFO filterInfo; - int pinNumber = 0; - IMemInputPin *memInputPin = NULL; - - hr = CoCreateInstance(&CLSID_SmartTee, NULL, CLSCTX_INPROC_SERVER, - &IID_IBaseFilter, (void**)&smartTeeFilter); - ok(SUCCEEDED(hr), "couldn't create smart tee filter, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - - hr = IBaseFilter_QueryFilterInfo(smartTeeFilter, &filterInfo); - ok(SUCCEEDED(hr), "QueryFilterInfo failed, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - - ok(!*filterInfo.achName, - "filter's name is meant to be empty but it's %s\n", wine_dbgstr_w(filterInfo.achName)); - - hr = IBaseFilter_EnumPins(smartTeeFilter, &enumPins); - ok(SUCCEEDED(hr), "cannot enum filter pins, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - - while (IEnumPins_Next(enumPins, 1, &pin, NULL) == S_OK) - { - if (pinNumber == 0) - { - inputPin = pin; - IPin_AddRef(inputPin); - } - else if (pinNumber == 1) - { - capturePin = pin; - IPin_AddRef(capturePin); - } - else if (pinNumber == 2) - { - previewPin = pin; - IPin_AddRef(previewPin); - } - else - ok(0, "pin %d isn't supposed to exist\n", pinNumber); - - IPin_Release(pin); - pinNumber++; - } - - ok(inputPin && capturePin && previewPin, "couldn't find all pins\n"); - if (!(inputPin && capturePin && previewPin)) - goto end; - - hr = IPin_QueryInterface(inputPin, &IID_IMemInputPin, (void**)&memInputPin); - ok(SUCCEEDED(hr), "couldn't get mem input pin, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - hr = IMemInputPin_ReceiveCanBlock(memInputPin); - ok(hr == S_OK, "unexpected IMemInputPin_ReceiveCanBlock() = 0x%08x\n", hr); - - test_smart_tee_filter_in_graph(smartTeeFilter, inputPin, capturePin, previewPin); - -end: - if (inputPin) - IPin_Release(inputPin); - if (capturePin) - IPin_Release(capturePin); - if (previewPin) - IPin_Release(previewPin); - if (smartTeeFilter) - IBaseFilter_Release(smartTeeFilter); - if (enumPins) - IEnumPins_Release(enumPins); - if (memInputPin) - IMemInputPin_Release(memInputPin); -} - static void test_unconnected_filter_state(void) { IBaseFilter *filter = create_smart_tee(); @@ -3066,8 +1415,6 @@ START_TEST(smartteefilter) test_connect_pin(); test_streaming();
- test_smart_tee_filter(); - CloseHandle(event); CoUninitialize(); }
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/qedit/tests/samplegrabber.c | 114 +++++++++++++++++++++++++++++-- 1 file changed, 110 insertions(+), 4 deletions(-)
diff --git a/dlls/qedit/tests/samplegrabber.c b/dlls/qedit/tests/samplegrabber.c index 3a1d1a16ce6..2eaaffb67b7 100644 --- a/dlls/qedit/tests/samplegrabber.c +++ b/dlls/qedit/tests/samplegrabber.c @@ -579,6 +579,7 @@ struct testfilter struct strmbase_sink sink; const AM_MEDIA_TYPE *sink_mt; AM_MEDIA_TYPE source_mt; + unsigned int got_sample; };
static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface) @@ -628,7 +629,7 @@ static HRESULT testsource_get_media_type(struct strmbase_pin *iface, unsigned in
static void test_sink_allocator(IPin *pin) { - ALLOCATOR_PROPERTIES req_props = {1, 5000, 1, 0}, ret_props; + ALLOCATOR_PROPERTIES req_props = {1, 256, 1, 0}, ret_props; IMemAllocator *req_allocator, *ret_allocator; IMemInputPin *input; HRESULT hr; @@ -666,9 +667,6 @@ static void test_sink_allocator(IPin *pin) hr = IMemAllocator_SetProperties(req_allocator, &req_props, &ret_props); ok(hr == S_OK, "Got hr %#x.\n", hr);
- hr = IMemAllocator_Commit(req_allocator); - ok(hr == S_OK, "Got hr %#x.\n", hr); - IMemAllocator_Release(req_allocator); IMemInputPin_Release(input); } @@ -736,6 +734,42 @@ static HRESULT testsink_get_media_type(struct strmbase_pin *iface, unsigned int
static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample *sample) { + struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter); + REFERENCE_TIME start, stop; + BYTE *data, expect[200]; + LONG size, i; + HRESULT hr; + + size = IMediaSample_GetSize(sample); + ok(size == 256, "Got size %u.\n", size); + size = IMediaSample_GetActualDataLength(sample); + ok(size == 200, "Got valid size %u.\n", size); + + hr = IMediaSample_GetPointer(sample, &data); + ok(hr == S_OK, "Got hr %#x.\n", hr); + for (i = 0; i < size; ++i) + expect[i] = i; + ok(!memcmp(data, expect, size), "Data didn't match.\n"); + + hr = IMediaSample_GetTime(sample, &start, &stop); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(start == 30000, "Got start time %s.\n", wine_dbgstr_longlong(start)); + ok(stop == 40000, "Got stop time %s.\n", wine_dbgstr_longlong(stop)); + + hr = IMediaSample_GetMediaTime(sample, &start, &stop); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(start == 10000, "Got start time %s.\n", wine_dbgstr_longlong(start)); + ok(stop == 20000, "Got stop time %s.\n", wine_dbgstr_longlong(stop)); + + hr = IMediaSample_IsDiscontinuity(sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaSample_IsPreroll(sample); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + hr = IMediaSample_IsSyncPoint(sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + ++filter->got_sample; + return S_OK; }
@@ -756,6 +790,73 @@ static void testfilter_init(struct testfilter *filter) strmbase_sink_init(&filter->sink, &filter->filter, L"sink", &testsink_ops, NULL); }
+static void test_sample_processing(IMediaControl *control, IMemInputPin *input, struct testfilter *sink) +{ + REFERENCE_TIME start, stop; + IMemAllocator *allocator; + IMediaSample *sample; + LONG size, i; + HRESULT hr; + BYTE *data; + + hr = IMemInputPin_ReceiveCanBlock(input); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMemInputPin_GetAllocator(input, &allocator); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0); + ok(hr == VFW_E_NOT_COMMITTED, "Got hr %#x.\n", hr); + + hr = IMediaControl_Pause(control); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr != S_OK) + { + IMemAllocator_Commit(allocator); + hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#x.\n", hr); + } + + hr = IMediaSample_GetPointer(sample, &data); + ok(hr == S_OK, "Got hr %#x.\n", hr); + size = IMediaSample_GetSize(sample); + ok(size == 256, "Got size %d.\n", size); + for (i = 0; i < 200; ++i) + data[i] = i; + hr = IMediaSample_SetActualDataLength(sample, 200); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + start = 10000; + stop = 20000; + hr = IMediaSample_SetMediaTime(sample, &start, &stop); + ok(hr == S_OK, "Got hr %#x.\n", hr); + start = 30000; + stop = 40000; + hr = IMediaSample_SetTime(sample, &start, &stop); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaSample_SetDiscontinuity(sample, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaSample_SetSyncPoint(sample, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(sink->got_sample == 1, "Got %u calls to Receive().\n", sink->got_sample); + sink->got_sample = 0; + + hr = IMediaControl_Stop(control); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMemInputPin_Receive(input, sample); + todo_wine ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr); + + IMediaSample_Release(sample); + IMemAllocator_Release(allocator); +} + static void test_connect_pin(void) { AM_MEDIA_TYPE req_mt = @@ -772,6 +873,7 @@ static void test_connect_pin(void) IMediaControl *control; AM_MEDIA_TYPE mt, *pmt; IFilterGraph2 *graph; + IMemInputPin *input; HRESULT hr; ULONG ref;
@@ -784,6 +886,7 @@ static void test_connect_pin(void) IFilterGraph2_AddFilter(graph, filter, L"sample grabber"); IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control); IBaseFilter_FindPin(filter, L"In", &sink); + IPin_QueryInterface(sink, &IID_IMemInputPin, (void **)&input); IBaseFilter_FindPin(filter, L"Out", &source); IBaseFilter_QueryInterface(filter, &IID_ISampleGrabber, (void **)&grabber);
@@ -916,6 +1019,8 @@ static void test_connect_pin(void) ok(compare_media_types(&testsink.sink.pin.mt, &req_mt), "Media types didn't match.\n"); ok(compare_media_types(&testsource.source.pin.mt, &testsink.sink.pin.mt), "Media types didn't match.\n");
+ test_sample_processing(control, input, &testsink); + hr = IMediaControl_Pause(control); ok(hr == S_OK, "Got hr %#x.\n", hr); hr = IFilterGraph2_Disconnect(graph, source); @@ -1053,6 +1158,7 @@ static void test_connect_pin(void) hr = IPin_ConnectionMediaType(sink, &mt); ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
+ IMemInputPin_Release(input); IPin_Release(sink); IPin_Release(source); IMediaControl_Release(control);
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/qedit/tests/samplegrabber.c | 128 ++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 1 deletion(-)
diff --git a/dlls/qedit/tests/samplegrabber.c b/dlls/qedit/tests/samplegrabber.c index 2eaaffb67b7..f82c375b76f 100644 --- a/dlls/qedit/tests/samplegrabber.c +++ b/dlls/qedit/tests/samplegrabber.c @@ -579,7 +579,7 @@ struct testfilter struct strmbase_sink sink; const AM_MEDIA_TYPE *sink_mt; AM_MEDIA_TYPE source_mt; - unsigned int got_sample; + unsigned int got_sample, got_new_segment, got_eos, got_begin_flush, got_end_flush; };
static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface) @@ -773,12 +773,48 @@ static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample return S_OK; }
+static HRESULT testsink_new_segment(struct strmbase_sink *iface, + REFERENCE_TIME start, REFERENCE_TIME stop, double rate) +{ + struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter); + ++filter->got_new_segment; + ok(start == 10000, "Got start %s.\n", wine_dbgstr_longlong(start)); + ok(stop == 20000, "Got stop %s.\n", wine_dbgstr_longlong(stop)); + ok(rate == 1.0, "Got rate %.16e.\n", rate); + return S_OK; +} + +static HRESULT testsink_eos(struct strmbase_sink *iface) +{ + struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter); + ++filter->got_eos; + return S_OK; +} + +static HRESULT testsink_begin_flush(struct strmbase_sink *iface) +{ + struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter); + ++filter->got_begin_flush; + return S_OK; +} + +static HRESULT testsink_end_flush(struct strmbase_sink *iface) +{ + struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter); + ++filter->got_end_flush; + return S_OK; +} + static const struct strmbase_sink_ops testsink_ops = { .base.pin_query_interface = testsink_query_interface, .base.pin_query_accept = testsink_query_accept, .base.pin_get_media_type = testsink_get_media_type, .pfnReceive = testsink_Receive, + .sink_new_segment = testsink_new_segment, + .sink_eos = testsink_eos, + .sink_begin_flush = testsink_begin_flush, + .sink_end_flush = testsink_end_flush, };
static void testfilter_init(struct testfilter *filter) @@ -857,6 +893,95 @@ static void test_sample_processing(IMediaControl *control, IMemInputPin *input, IMemAllocator_Release(allocator); }
+static void test_streaming_events(IMediaControl *control, IPin *sink, + IMemInputPin *input, struct testfilter *testsink) +{ + REFERENCE_TIME start, stop; + IMemAllocator *allocator; + IMediaSample *sample; + HRESULT hr; + BYTE *data; + LONG i; + + hr = IMediaControl_Pause(control); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMemInputPin_GetAllocator(input, &allocator); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaSample_GetPointer(sample, &data); + ok(hr == S_OK, "Got hr %#x.\n", hr); + for (i = 0; i < 200; ++i) + data[i] = i; + hr = IMediaSample_SetActualDataLength(sample, 200); + ok(hr == S_OK, "Got hr %#x.\n", hr); + start = 10000; + stop = 20000; + hr = IMediaSample_SetMediaTime(sample, &start, &stop); + ok(hr == S_OK, "Got hr %#x.\n", hr); + start = 30000; + stop = 40000; + hr = IMediaSample_SetTime(sample, &start, &stop); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaSample_SetDiscontinuity(sample, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaSample_SetSyncPoint(sample, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + ok(!testsink->got_new_segment, "Got %u calls to IPin::NewSegment().\n", testsink->got_new_segment); + hr = IPin_NewSegment(sink, 10000, 20000, 1.0); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(testsink->got_new_segment == 1, "Got %u calls to IPin::NewSegment().\n", testsink->got_new_segment); + + ok(!testsink->got_eos, "Got %u calls to IPin::EndOfStream().\n", testsink->got_eos); + hr = IPin_EndOfStream(sink); + ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(!testsink->got_sample, "Got %u calls to Receive().\n", testsink->got_sample); + ok(testsink->got_eos == 1, "Got %u calls to IPin::EndOfStream().\n", testsink->got_eos); + testsink->got_eos = 0; + + hr = IPin_EndOfStream(sink); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(testsink->got_eos == 1, "Got %u calls to IPin::EndOfStream().\n", testsink->got_eos); + testsink->got_eos = 0; + + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(testsink->got_sample == 1, "Got %u calls to Receive().\n", testsink->got_sample); + testsink->got_sample = 0; + + ok(!testsink->got_begin_flush, "Got %u calls to IPin::BeginFlush().\n", testsink->got_begin_flush); + hr = IPin_BeginFlush(sink); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(testsink->got_begin_flush == 1, "Got %u calls to IPin::BeginFlush().\n", testsink->got_begin_flush); + + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(testsink->got_sample == 1, "Got %u calls to Receive().\n", testsink->got_sample); + testsink->got_sample = 0; + + hr = IPin_EndOfStream(sink); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(testsink->got_eos == 1, "Got %u calls to IPin::EndOfStream().\n", testsink->got_eos); + testsink->got_eos = 0; + + ok(!testsink->got_end_flush, "Got %u calls to IPin::EndFlush().\n", testsink->got_end_flush); + hr = IPin_EndFlush(sink); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(testsink->got_end_flush == 1, "Got %u calls to IPin::EndFlush().\n", testsink->got_end_flush); + + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(testsink->got_sample == 1, "Got %u calls to Receive().\n", testsink->got_sample); + testsink->got_sample = 0; + + hr = IMediaControl_Stop(control); + ok(hr == S_OK, "Got hr %#x.\n", hr); + IMediaSample_Release(sample); + IMemAllocator_Release(allocator); +} + static void test_connect_pin(void) { AM_MEDIA_TYPE req_mt = @@ -1020,6 +1145,7 @@ static void test_connect_pin(void) ok(compare_media_types(&testsource.source.pin.mt, &testsink.sink.pin.mt), "Media types didn't match.\n");
test_sample_processing(control, input, &testsink); + test_streaming_events(control, sink, input, &testsink);
hr = IMediaControl_Pause(control); ok(hr == S_OK, "Got hr %#x.\n", hr);