[PATCH 5/6] quartz/tests/filtergraph: Add some tests for EC_COMPLETE.

Zebediah Figura z.figura12 at gmail.com
Tue Sep 25 23:30:22 CDT 2018


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/quartz/tests/filtergraph.c | 430 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 430 insertions(+)

diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c
index 6838c02..1345e41 100644
--- a/dlls/quartz/tests/filtergraph.c
+++ b/dlls/quartz/tests/filtergraph.c
@@ -1139,6 +1139,11 @@ struct testfilter
     IEnumPins IEnumPins_iface;
     struct testpin *pins;
     unsigned int pin_count, enum_idx;
+
+    IAMFilterMiscFlags IAMFilterMiscFlags_iface;
+    ULONG misc_flags;
+
+    IMediaSeeking IMediaSeeking_iface;
 };
 
 static inline struct testfilter *impl_from_IEnumPins(IEnumPins *iface)
@@ -1234,6 +1239,18 @@ static HRESULT WINAPI testfilter_QueryInterface(IBaseFilter *iface, REFIID iid,
         IBaseFilter_AddRef(*out);
         return S_OK;
     }
+    else if (IsEqualGUID(iid, &IID_IAMFilterMiscFlags) && filter->IAMFilterMiscFlags_iface.lpVtbl)
+    {
+        *out = &filter->IAMFilterMiscFlags_iface;
+        IAMFilterMiscFlags_AddRef(*out);
+        return S_OK;
+    }
+    else if (IsEqualGUID(iid, &IID_IMediaSeeking) && filter->IMediaSeeking_iface.lpVtbl)
+    {
+        *out = &filter->IMediaSeeking_iface;
+        IMediaSeeking_AddRef(*out);
+        return S_OK;
+    }
 
     *out = NULL;
     return E_NOINTERFACE;
@@ -1418,6 +1435,195 @@ static const IBaseFilterVtbl testfilter_vtbl =
     testfilter_QueryVendorInfo
 };
 
+static struct testfilter *impl_from_IAMFilterMiscFlags(IAMFilterMiscFlags *iface)
+{
+    return CONTAINING_RECORD(iface, struct testfilter, IAMFilterMiscFlags_iface);
+}
+
+static HRESULT WINAPI testmiscflags_QueryInterface(IAMFilterMiscFlags *iface, REFIID iid, void **out)
+{
+    struct testfilter *filter = impl_from_IAMFilterMiscFlags(iface);
+    return IBaseFilter_QueryInterface(&filter->IBaseFilter_iface, iid, out);
+}
+
+static ULONG WINAPI testmiscflags_AddRef(IAMFilterMiscFlags *iface)
+{
+    struct testfilter *filter = impl_from_IAMFilterMiscFlags(iface);
+    return InterlockedIncrement(&filter->ref);
+}
+
+static ULONG WINAPI testmiscflags_Release(IAMFilterMiscFlags *iface)
+{
+    struct testfilter *filter = impl_from_IAMFilterMiscFlags(iface);
+    return InterlockedDecrement(&filter->ref);
+}
+
+static ULONG WINAPI testmiscflags_GetMiscFlags(IAMFilterMiscFlags *iface)
+{
+    struct testfilter *filter = impl_from_IAMFilterMiscFlags(iface);
+    if (winetest_debug > 1) trace("%p->GetMiscFlags()\n", filter);
+    return filter->misc_flags;
+}
+
+static const IAMFilterMiscFlagsVtbl testmiscflags_vtbl =
+{
+    testmiscflags_QueryInterface,
+    testmiscflags_AddRef,
+    testmiscflags_Release,
+    testmiscflags_GetMiscFlags,
+};
+
+static struct testfilter *impl_from_IMediaSeeking(IMediaSeeking *iface)
+{
+    return CONTAINING_RECORD(iface, struct testfilter, IMediaSeeking_iface);
+}
+
+static HRESULT WINAPI testseek_QueryInterface(IMediaSeeking *iface, REFIID iid, void **out)
+{
+    struct testfilter *filter = impl_from_IMediaSeeking(iface);
+    return IBaseFilter_QueryInterface(&filter->IBaseFilter_iface, iid, out);
+}
+
+static ULONG WINAPI testseek_AddRef(IMediaSeeking *iface)
+{
+    struct testfilter *filter = impl_from_IMediaSeeking(iface);
+    return InterlockedIncrement(&filter->ref);
+}
+
+static ULONG WINAPI testseek_Release(IMediaSeeking *iface)
+{
+    struct testfilter *filter = impl_from_IMediaSeeking(iface);
+    return InterlockedDecrement(&filter->ref);
+}
+
+static HRESULT WINAPI testseek_GetCapabilities(IMediaSeeking *iface, DWORD *caps)
+{
+    if (winetest_debug > 1) trace("%p->GetCapabilities()\n", iface);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI testseek_CheckCapabilities(IMediaSeeking *iface, DWORD *caps)
+{
+    ok(0, "Unexpected call.\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI testseek_IsFormatSupported(IMediaSeeking *iface, const GUID *format)
+{
+    if (winetest_debug > 1) trace("%p->IsFormatSupported(%s)\n", iface, wine_dbgstr_guid(format));
+    return S_OK;
+}
+
+static HRESULT WINAPI testseek_QueryPreferredFormat(IMediaSeeking *iface, GUID *format)
+{
+    ok(0, "Unexpected call.\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI testseek_GetTimeFormat(IMediaSeeking *iface, GUID *format)
+{
+    ok(0, "Unexpected call.\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI testseek_IsUsingTimeFormat(IMediaSeeking *iface, const GUID *format)
+{
+    if (winetest_debug > 1) trace("%p->IsUsingTimeFormat(%s)\n", iface, wine_dbgstr_guid(format));
+    return S_FALSE;
+}
+
+static HRESULT WINAPI testseek_SetTimeFormat(IMediaSeeking *iface, const GUID *format)
+{
+    ok(0, "Unexpected call.\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI testseek_GetDuration(IMediaSeeking *iface, LONGLONG *duration)
+{
+    ok(0, "Unexpected call.\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI testseek_GetStopPosition(IMediaSeeking *iface, LONGLONG *stop)
+{
+    ok(0, "Unexpected call.\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI testseek_GetCurrentPosition(IMediaSeeking *iface, LONGLONG *current)
+{
+    ok(0, "Unexpected call.\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI testseek_ConvertTimeFormat(IMediaSeeking *iface, LONGLONG *target,
+    const GUID *target_format, LONGLONG source, const GUID *source_format)
+{
+    ok(0, "Unexpected call.\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI testseek_SetPositions(IMediaSeeking *iface, LONGLONG *current,
+    DWORD current_flags, LONGLONG *stop, DWORD stop_flags )
+{
+    ok(0, "Unexpected call.\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI testseek_GetPositions(IMediaSeeking *iface, LONGLONG *current, LONGLONG *stop)
+{
+    ok(0, "Unexpected call.\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI testseek_GetAvailable(IMediaSeeking *iface, LONGLONG *earliest, LONGLONG *latest)
+{
+    ok(0, "Unexpected call.\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI testseek_SetRate(IMediaSeeking *iface, double rate)
+{
+    ok(0, "Unexpected call.\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI testseek_GetRate(IMediaSeeking *iface, double *rate)
+{
+    ok(0, "Unexpected call.\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI testseek_GetPreroll(IMediaSeeking *iface, LONGLONG *preroll)
+{
+    ok(0, "Unexpected call.\n");
+    return E_NOTIMPL;
+}
+
+static const IMediaSeekingVtbl testseek_vtbl =
+{
+    testseek_QueryInterface,
+    testseek_AddRef,
+    testseek_Release,
+    testseek_GetCapabilities,
+    testseek_CheckCapabilities,
+    testseek_IsFormatSupported,
+    testseek_QueryPreferredFormat,
+    testseek_GetTimeFormat,
+    testseek_IsUsingTimeFormat,
+    testseek_SetTimeFormat,
+    testseek_GetDuration,
+    testseek_GetStopPosition,
+    testseek_GetCurrentPosition,
+    testseek_ConvertTimeFormat,
+    testseek_SetPositions,
+    testseek_GetPositions,
+    testseek_GetAvailable,
+    testseek_SetRate,
+    testseek_GetRate,
+    testseek_GetPreroll,
+};
+
 struct testfilter_cf
 {
     IClassFactory IClassFactory_iface;
@@ -2769,6 +2975,229 @@ todo_wine
     ok(sink.state == State_Stopped, "Got state %u.\n", sink.state);
 }
 
+/* Helper function to check whether a filter is considered a renderer, i.e.
+ * whether its EC_COMPLETE notification will be passed on to the application. */
+static HRESULT check_ec_complete(IFilterGraph2 *graph, IBaseFilter *filter)
+{
+    IMediaEventSink *eventsink;
+    LONG_PTR param1, param2;
+    IMediaControl *control;
+    IMediaEvent *eventsrc;
+    HRESULT hr, ret_hr;
+    LONG code;
+
+    IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
+    IFilterGraph2_QueryInterface(graph, &IID_IMediaEvent, (void **)&eventsrc);
+    IFilterGraph2_QueryInterface(graph, &IID_IMediaEventSink, (void **)&eventsink);
+
+    IMediaControl_Run(control);
+
+    hr = IMediaEvent_GetEvent(eventsrc, &code, &param1, &param2, 0);
+    ok(hr == E_ABORT, "Got hr %#x.\n", hr);
+
+    hr = IMediaEventSink_Notify(eventsink, EC_COMPLETE, S_OK, (LONG_PTR)filter);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    ret_hr = IMediaEvent_GetEvent(eventsrc, &code, &param1, &param2, 0);
+    if (ret_hr == S_OK)
+    {
+        ok(code == EC_COMPLETE, "Got code %#x.\n", code);
+        ok(param1 == S_OK, "Got param1 %#lx.\n", param1);
+        ok(!param2, "Got param2 %#lx.\n", param2);
+        hr = IMediaEvent_FreeEventParams(eventsrc, code, param1, param2);
+        ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+        hr = IMediaEvent_GetEvent(eventsrc, &code, &param1, &param2, 0);
+        ok(hr == E_ABORT, "Got hr %#x.\n", hr);
+    }
+
+    IMediaControl_Stop(control);
+
+    IMediaControl_Release(control);
+    IMediaEvent_Release(eventsrc);
+    IMediaEventSink_Release(eventsink);
+    return ret_hr;
+}
+
+static void test_ec_complete(void)
+{
+    struct testpin filter1_pin, filter2_pin, filter3_pin, source_pins[3];
+    struct testfilter filter1, filter2, filter3, source;
+
+    IFilterGraph2 *graph = create_graph();
+    IMediaEventSink *eventsink;
+    LONG_PTR param1, param2;
+    IMediaControl *control;
+    IMediaEvent *eventsrc;
+    HRESULT hr;
+    LONG code;
+
+    testsink_init(&filter1_pin);
+    testsink_init(&filter2_pin);
+    testsink_init(&filter3_pin);
+    testfilter_init(&filter1, &filter1_pin, 1);
+    testfilter_init(&filter2, &filter2_pin, 1);
+    testfilter_init(&filter3, &filter3_pin, 1);
+    testsource_init(&source_pins[0], NULL, 0);
+    testsource_init(&source_pins[1], NULL, 0);
+    testsource_init(&source_pins[2], NULL, 0);
+    testfilter_init(&source, source_pins, 3);
+
+    filter1.IAMFilterMiscFlags_iface.lpVtbl = &testmiscflags_vtbl;
+    filter2.IAMFilterMiscFlags_iface.lpVtbl = &testmiscflags_vtbl;
+    filter1.misc_flags = filter2.misc_flags = AM_FILTER_MISC_FLAGS_IS_RENDERER;
+
+    IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
+    IFilterGraph2_QueryInterface(graph, &IID_IMediaEvent, (void **)&eventsrc);
+    IFilterGraph2_QueryInterface(graph, &IID_IMediaEventSink, (void **)&eventsink);
+
+    IFilterGraph2_AddFilter(graph, &filter1.IBaseFilter_iface, NULL);
+    IFilterGraph2_AddFilter(graph, &filter2.IBaseFilter_iface, NULL);
+    IFilterGraph2_AddFilter(graph, &filter3.IBaseFilter_iface, NULL);
+    IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL);
+    IFilterGraph2_ConnectDirect(graph, &source_pins[0].IPin_iface, &filter1_pin.IPin_iface, NULL);
+    IFilterGraph2_ConnectDirect(graph, &source_pins[1].IPin_iface, &filter2_pin.IPin_iface, NULL);
+    IFilterGraph2_ConnectDirect(graph, &source_pins[2].IPin_iface, &filter3_pin.IPin_iface, NULL);
+
+    /* EC_COMPLETE is only delivered to the user after all renderers deliver it. */
+
+    IMediaControl_Run(control);
+
+    while ((hr = IMediaEvent_GetEvent(eventsrc, &code, &param1, &param2, 0)) == S_OK)
+    {
+        ok(code != EC_COMPLETE, "Got unexpected EC_COMPLETE.\n");
+        IMediaEvent_FreeEventParams(eventsrc, code, param1, param2);
+    }
+    ok(hr == E_ABORT, "Got hr %#x.\n", hr);
+
+    hr = IMediaEventSink_Notify(eventsink, EC_COMPLETE, S_OK, (LONG_PTR)&filter1.IBaseFilter_iface);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    hr = IMediaEvent_GetEvent(eventsrc, &code, &param1, &param2, 50);
+    ok(hr == E_ABORT, "Got hr %#x.\n", hr);
+
+    hr = IMediaEventSink_Notify(eventsink, EC_COMPLETE, S_OK, (LONG_PTR)&filter2.IBaseFilter_iface);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    hr = IMediaEvent_GetEvent(eventsrc, &code, &param1, &param2, 0);
+todo_wine {
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(code == EC_COMPLETE, "Got code %#x.\n", code);
+}
+    ok(param1 == S_OK, "Got param1 %#lx.\n", param1);
+    ok(!param2, "Got param2 %#lx.\n", param2);
+    hr = IMediaEvent_FreeEventParams(eventsrc, code, param1, param2);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    hr = IMediaEvent_GetEvent(eventsrc, &code, &param1, &param2, 50);
+    ok(hr == E_ABORT, "Got hr %#x.\n", hr);
+
+    hr = IMediaEventSink_Notify(eventsink, EC_COMPLETE, S_OK, (LONG_PTR)&filter3.IBaseFilter_iface);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    hr = IMediaEvent_GetEvent(eventsrc, &code, &param1, &param2, 50);
+todo_wine
+    ok(hr == E_ABORT, "Got hr %#x.\n", hr);
+
+    IMediaControl_Stop(control);
+
+    /* Test CancelDefaultHandling(). */
+
+    IMediaControl_Run(control);
+
+    hr = IMediaEvent_CancelDefaultHandling(eventsrc, EC_COMPLETE);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    hr = IMediaEvent_GetEvent(eventsrc, &code, &param1, &param2, 50);
+    ok(hr == E_ABORT, "Got hr %#x.\n", hr);
+
+    hr = IMediaEventSink_Notify(eventsink, EC_COMPLETE, S_OK, (LONG_PTR)&filter1.IBaseFilter_iface);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    hr = IMediaEvent_GetEvent(eventsrc, &code, &param1, &param2, 0);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(code == EC_COMPLETE, "Got code %#x.\n", code);
+    ok(param1 == S_OK, "Got param1 %#lx.\n", param1);
+    ok(param2 == (LONG_PTR)&filter1.IBaseFilter_iface, "Got param2 %#lx.\n", param2);
+    hr = IMediaEvent_FreeEventParams(eventsrc, code, param1, param2);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    hr = IMediaEvent_GetEvent(eventsrc, &code, &param1, &param2, 50);
+    ok(hr == E_ABORT, "Got hr %#x.\n", hr);
+
+    hr = IMediaEventSink_Notify(eventsink, EC_COMPLETE, S_OK, (LONG_PTR)&filter3.IBaseFilter_iface);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    hr = IMediaEvent_GetEvent(eventsrc, &code, &param1, &param2, 0);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(code == EC_COMPLETE, "Got code %#x.\n", code);
+    ok(param1 == S_OK, "Got param1 %#lx.\n", param1);
+    ok(param2 == (LONG_PTR)&filter3.IBaseFilter_iface, "Got param2 %#lx.\n", param2);
+    hr = IMediaEvent_FreeEventParams(eventsrc, code, param1, param2);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    hr = IMediaEvent_GetEvent(eventsrc, &code, &param1, &param2, 50);
+    ok(hr == E_ABORT, "Got hr %#x.\n", hr);
+
+    IMediaControl_Stop(control);
+    hr = IMediaEvent_RestoreDefaultHandling(eventsrc, EC_COMPLETE);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    /* A filter counts as a renderer if it (1) exposes IAMFilterMiscFlags and
+     * reports itself as a renderer, or (2) exposes IMediaSeeking and has no
+     * output pins. Despite MSDN, QueryInternalConnections() does not seem to
+     * be used. */
+
+    IFilterGraph2_RemoveFilter(graph, &filter1.IBaseFilter_iface);
+    IFilterGraph2_RemoveFilter(graph, &filter2.IBaseFilter_iface);
+    IFilterGraph2_RemoveFilter(graph, &filter3.IBaseFilter_iface);
+    filter1.misc_flags = 0;
+    IFilterGraph2_AddFilter(graph, &filter1.IBaseFilter_iface, NULL);
+    IFilterGraph2_ConnectDirect(graph, &source_pins[0].IPin_iface, &filter1_pin.IPin_iface, NULL);
+
+    hr = check_ec_complete(graph, &filter1.IBaseFilter_iface);
+todo_wine
+    ok(hr == E_ABORT, "Got hr %#x.\n", hr);
+
+    IFilterGraph2_RemoveFilter(graph, &filter1.IBaseFilter_iface);
+    filter1_pin.dir = PINDIR_INPUT;
+    filter1.IAMFilterMiscFlags_iface.lpVtbl = NULL;
+    filter1.IMediaSeeking_iface.lpVtbl = &testseek_vtbl;
+    IFilterGraph2_AddFilter(graph, &filter1.IBaseFilter_iface, NULL);
+    IFilterGraph2_ConnectDirect(graph, &source_pins[0].IPin_iface, &filter1_pin.IPin_iface, NULL);
+
+    hr = check_ec_complete(graph, &filter1.IBaseFilter_iface);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    IFilterGraph2_RemoveFilter(graph, &filter1.IBaseFilter_iface);
+    filter1_pin.dir = PINDIR_OUTPUT;
+    IFilterGraph2_AddFilter(graph, &filter1.IBaseFilter_iface, NULL);
+
+    hr = check_ec_complete(graph, &filter1.IBaseFilter_iface);
+    ok(hr == E_ABORT, "Got hr %#x.\n", hr);
+
+    IFilterGraph2_RemoveFilter(graph, &filter1.IBaseFilter_iface);
+    filter1.IMediaSeeking_iface.lpVtbl = NULL;
+    filter1_pin.dir = PINDIR_INPUT;
+    filter1.pin_count = 1;
+    filter1_pin.QueryInternalConnections_hr = S_OK;
+    IFilterGraph2_AddFilter(graph, &filter1.IBaseFilter_iface, NULL);
+    IFilterGraph2_ConnectDirect(graph, &source_pins[0].IPin_iface, &filter1_pin.IPin_iface, NULL);
+
+    hr = check_ec_complete(graph, &filter1.IBaseFilter_iface);
+todo_wine
+    ok(hr == E_ABORT, "Got hr %#x.\n", hr);
+
+    IMediaControl_Release(control);
+    IMediaEvent_Release(eventsrc);
+    IMediaEventSink_Release(eventsink);
+    hr = IFilterGraph2_Release(graph);
+    ok(!hr, "Got outstanding refcount %d.\n", hr);
+    ok(filter1.ref == 1, "Got outstanding refcount %d.\n", filter1.ref);
+    ok(filter2.ref == 1, "Got outstanding refcount %d.\n", filter2.ref);
+    ok(filter3.ref == 1, "Got outstanding refcount %d.\n", filter3.ref);
+}
+
 START_TEST(filtergraph)
 {
     CoInitializeEx(NULL, COINIT_MULTITHREADED);
@@ -2785,6 +3214,7 @@ START_TEST(filtergraph)
     test_connect_direct();
     test_sync_source();
     test_filter_state();
+    test_ec_complete();
 
     CoUninitialize();
     test_render_with_multithread();
-- 
2.7.4




More information about the wine-devel mailing list