diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c index e3faf64fb82..a23e35d6a1c 100644 --- a/dlls/quartz/filtergraph.c +++ b/dlls/quartz/filtergraph.c @@ -1119,10 +1119,12 @@ static HRESULT create_filter(IFilterGraphImpl *graph, IMoniker *moniker, IBaseFi return IMoniker_BindToObject(moniker, NULL, NULL, &IID_IBaseFilter, (void **)filter); } -static HRESULT autoplug(IFilterGraphImpl *graph, IPin *source, IPin *sink, unsigned int recursion_depth); +static HRESULT autoplug(IFilterGraphImpl *graph, IPin *source, IPin *sink, + BOOL render_to_existing, unsigned int recursion_depth); static HRESULT autoplug_through_sink(IFilterGraphImpl *graph, IPin *source, - IBaseFilter *filter, IPin *middle_sink, IPin *sink, unsigned int recursion_depth) + IBaseFilter *filter, IPin *middle_sink, IPin *sink, + BOOL render_to_existing, BOOL allow_renderers, unsigned int recursion_depth) { BOOL any = FALSE, all = TRUE; IPin *middle_source, *peer; @@ -1171,7 +1173,7 @@ static HRESULT autoplug_through_sink(IFilterGraphImpl *graph, IPin *source, continue; } - hr = autoplug(graph, middle_source, sink, recursion_depth + 1); + hr = autoplug(graph, middle_source, sink, render_to_existing, recursion_depth + 1); IPin_Release(middle_source); if (SUCCEEDED(hr) && sink) { @@ -1187,7 +1189,7 @@ static HRESULT autoplug_through_sink(IFilterGraphImpl *graph, IPin *source, if (!sink) { - if (all) + if (all && (any || allow_renderers)) return S_OK; if (any) return VFW_S_PARTIAL_RENDER; @@ -1200,7 +1202,8 @@ err: } static HRESULT autoplug_through_filter(IFilterGraphImpl *graph, IPin *source, - IBaseFilter *filter, IPin *sink, unsigned int recursion_depth) + IBaseFilter *filter, IPin *sink, BOOL render_to_existing, + BOOL allow_renderers, unsigned int recursion_depth) { IEnumPins *sink_enum; IPin *filter_sink; @@ -1213,7 +1216,8 @@ static HRESULT autoplug_through_filter(IFilterGraphImpl *graph, IPin *source, while (IEnumPins_Next(sink_enum, 1, &filter_sink, NULL) == S_OK) { - hr = autoplug_through_sink(graph, source, filter, filter_sink, sink, recursion_depth); + hr = autoplug_through_sink(graph, source, filter, filter_sink, sink, + render_to_existing, allow_renderers, recursion_depth); IPin_Release(filter_sink); if (SUCCEEDED(hr)) { @@ -1227,7 +1231,8 @@ static HRESULT autoplug_through_filter(IFilterGraphImpl *graph, IPin *source, /* Common helper for IGraphBuilder::Connect() and IGraphBuilder::Render(), which * share most of the same code. Render() calls this with a NULL sink. */ -static HRESULT autoplug(IFilterGraphImpl *graph, IPin *source, IPin *sink, unsigned int recursion_depth) +static HRESULT autoplug(IFilterGraphImpl *graph, IPin *source, IPin *sink, + BOOL render_to_existing, unsigned int recursion_depth) { IAMGraphBuilderCallback *callback = NULL; IEnumMediaTypes *enummt; @@ -1259,7 +1264,8 @@ static HRESULT autoplug(IFilterGraphImpl *graph, IPin *source, IPin *sink, unsig /* Always prefer filters in the graph. */ LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry) { - if (SUCCEEDED(hr = autoplug_through_filter(graph, source, filter->filter, sink, recursion_depth))) + if (SUCCEEDED(hr = autoplug_through_filter(graph, source, filter->filter, + sink, render_to_existing, TRUE, recursion_depth))) return hr; } @@ -1334,7 +1340,8 @@ static HRESULT autoplug(IFilterGraphImpl *graph, IPin *source, IPin *sink, unsig continue; } - hr = autoplug_through_filter(graph, source, filter, sink, recursion_depth); + hr = autoplug_through_filter(graph, source, filter, sink, + render_to_existing, !render_to_existing, recursion_depth); if (SUCCEEDED(hr)) { IBaseFilter_Release(filter); @@ -1383,7 +1390,7 @@ static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *source, I EnterCriticalSection(&graph->cs); - hr = autoplug(graph, source, sink, 0); + hr = autoplug(graph, source, sink, FALSE, 0); LeaveCriticalSection(&graph->cs); @@ -1399,7 +1406,7 @@ static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, IPin *source) TRACE("graph %p, source %p.\n", graph, source); EnterCriticalSection(&graph->cs); - hr = autoplug(graph, source, NULL, 0); + hr = autoplug(graph, source, NULL, FALSE, 0); LeaveCriticalSection(&graph->cs); if (hr == VFW_E_CANNOT_CONNECT) hr = VFW_E_CANNOT_RENDER; @@ -1598,14 +1605,24 @@ static HRESULT WINAPI FilterGraph2_ReconnectEx(IFilterGraph2 *iface, IPin *pin, return hr; } -static HRESULT WINAPI FilterGraph2_RenderEx(IFilterGraph2 *iface, IPin *pPinOut, DWORD dwFlags, - DWORD *pvContext) +static HRESULT WINAPI FilterGraph2_RenderEx(IFilterGraph2 *iface, IPin *source, DWORD flags, DWORD *context) { - IFilterGraphImpl *This = impl_from_IFilterGraph2(iface); + IFilterGraphImpl *graph = impl_from_IFilterGraph2(iface); + HRESULT hr; - TRACE("(%p/%p)->(%p %08x %p): stub !!!\n", This, iface, pPinOut, dwFlags, pvContext); + TRACE("graph %p, source %p, flags %#x, context %p.\n", graph, source, flags, context); - return S_OK; + if (flags & ~AM_RENDEREX_RENDERTOEXISTINGRENDERERS) + FIXME("Unknown flags %#x.\n", flags); + + EnterCriticalSection(&graph->cs); + hr = autoplug(graph, source, NULL, !!(flags & AM_RENDEREX_RENDERTOEXISTINGRENDERERS), 0); + LeaveCriticalSection(&graph->cs); + if (hr == VFW_E_CANNOT_CONNECT) + hr = VFW_E_CANNOT_RENDER; + + TRACE("Returning %#x.\n", hr); + return hr; } diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c index 5a61b754648..de8e32034f8 100644 --- a/dlls/quartz/tests/filtergraph.c +++ b/dlls/quartz/tests/filtergraph.c @@ -1978,9 +1978,6 @@ static void test_graph_builder_render(void) /* Test enumeration of filters from the registry. */ - graph = create_graph(); - IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL); - CoRegisterClassObject(&sink1_clsid, (IUnknown *)&sink1_cf.IClassFactory_iface, CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie1); CoRegisterClassObject(&sink2_clsid, (IUnknown *)&sink2_cf.IClassFactory_iface, @@ -2007,6 +2004,9 @@ static void test_graph_builder_render(void) } ok(hr == S_OK, "Got hr %#x.\n", hr); + graph = create_graph(); + IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL); + regpins.dwFlags = REG_PINFLAG_B_RENDERER; IFilterMapper2_RegisterFilter(mapper, &sink2_clsid, L"test", NULL, NULL, NULL, ®filter); @@ -2086,6 +2086,26 @@ static void test_graph_builder_render(void) ok(hr == S_OK, "Got hr %#x.\n", hr); ok(source_pin.peer == &sink1_pin.IPin_iface, "Got peer %p.\n", source_pin.peer); + ref = IFilterGraph2_Release(graph); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + /* Test AM_RENDEREX_RENDERTOEXISTINGRENDERERS. */ + + graph = create_graph(); + IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL); + + hr = IFilterGraph2_RenderEx(graph, &source_pin.IPin_iface, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL); + ok(hr == VFW_E_CANNOT_RENDER, "Got hr %#x.\n", hr); + + IFilterGraph2_AddFilter(graph, &sink1.IBaseFilter_iface, NULL); + + hr = IFilterGraph2_RenderEx(graph, &source_pin.IPin_iface, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source_pin.peer == &sink1_pin.IPin_iface, "Got peer %p.\n", source_pin.peer); + + ref = IFilterGraph2_Release(graph); + ok(!ref, "Got outstanding refcount %d.\n", ref); + IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &sink1_clsid); IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &sink2_clsid); @@ -2093,8 +2113,6 @@ out: CoRevokeClassObject(cookie1); CoRevokeClassObject(cookie2); IFilterMapper2_Release(mapper); - ref = IFilterGraph2_Release(graph); - ok(!ref, "Got outstanding refcount %d.\n", ref); ok(source.ref == 1, "Got outstanding refcount %d.\n", source.ref); ok(source_pin.ref == 1, "Got outstanding refcount %d.\n", source_pin.ref); ok(sink1.ref == 1, "Got outstanding refcount %d.\n", sink1.ref);