[PATCH 3/4] quartz: Combine IGraphBuilder::Render() and IGraphBuilder::Connect() into a single helper.
Zebediah Figura
z.figura12 at gmail.com
Mon Jun 15 22:51:25 CDT 2020
From: Zebediah Figura <zfigura at codeweavers.com>
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
dlls/quartz/filtergraph.c | 750 +++++++++-----------------------
dlls/quartz/tests/filtergraph.c | 11 +-
2 files changed, 205 insertions(+), 556 deletions(-)
diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c
index cb212e4961b..e3faf64fb82 100644
--- a/dlls/quartz/filtergraph.c
+++ b/dlls/quartz/filtergraph.c
@@ -207,7 +207,6 @@ typedef struct _IFilterGraphImpl {
int nItfCacheEntries;
BOOL defaultclock;
GUID timeformatseek;
- LONG recursioncount;
IUnknown *pSite;
LONG version;
@@ -1059,27 +1058,6 @@ static HRESULT WINAPI FilterGraph2_SetDefaultSyncSource(IFilterGraph2 *iface)
return hr;
}
-static HRESULT GetFilterInfo(IMoniker* pMoniker, VARIANT* pvar)
-{
- IPropertyBag * pPropBagCat = NULL;
- HRESULT hr;
-
- VariantInit(pvar);
-
- hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBagCat);
-
- if (SUCCEEDED(hr))
- hr = IPropertyBag_Read(pPropBagCat, L"FriendlyName", pvar, NULL);
-
- if (SUCCEEDED(hr))
- TRACE("Moniker = %s\n", debugstr_w(V_BSTR(pvar)));
-
- if (pPropBagCat)
- IPropertyBag_Release(pPropBagCat);
-
- return hr;
-}
-
struct filter_create_params
{
HRESULT hr;
@@ -1141,621 +1119,292 @@ static HRESULT create_filter(IFilterGraphImpl *graph, IMoniker *moniker, IBaseFi
return IMoniker_BindToObject(moniker, NULL, NULL, &IID_IBaseFilter, (void **)filter);
}
-/* Attempt to connect one of the output pins on filter to sink. Helper for
- * FilterGraph2_Connect(). */
-static HRESULT connect_output_pin(IFilterGraphImpl *graph, IBaseFilter *filter, IPin *sink)
-{
- IEnumPins *enumpins;
- PIN_INFO info;
- HRESULT hr;
- IPin *pin;
-
- hr = IBaseFilter_EnumPins(filter, &enumpins);
- if (FAILED(hr))
- return hr;
-
- while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
- {
- IPin_QueryPinInfo(pin, &info);
- IBaseFilter_Release(info.pFilter);
- if (info.dir == PINDIR_OUTPUT)
- {
- if (info.achName[0] == '~')
- {
- TRACE("Skipping non-rendered pin %s.\n", debugstr_w(info.achName));
- IPin_Release(pin);
- continue;
- }
-
- if (SUCCEEDED(IFilterGraph2_Connect(&graph->IFilterGraph2_iface, pin, sink)))
- {
- IPin_Release(pin);
- IEnumPins_Release(enumpins);
- return S_OK;
- }
- }
- IPin_Release(pin);
- }
-
- IEnumPins_Release(enumpins);
- return VFW_E_CANNOT_CONNECT;
-}
+static HRESULT autoplug(IFilterGraphImpl *graph, IPin *source, IPin *sink, unsigned int recursion_depth);
-/*** IGraphBuilder methods ***/
-static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *ppinOut, IPin *ppinIn)
+static HRESULT autoplug_through_sink(IFilterGraphImpl *graph, IPin *source,
+ IBaseFilter *filter, IPin *middle_sink, IPin *sink, unsigned int recursion_depth)
{
- IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
- struct filter *filter;
- HRESULT hr;
- IPin *pin;
- AM_MEDIA_TYPE* mt = NULL;
- IEnumMediaTypes* penummt = NULL;
- ULONG nbmt;
- IEnumPins* penumpins;
- IEnumMoniker* pEnumMoniker;
- GUID tab[2];
- IMoniker* pMoniker;
- PIN_INFO PinInfo;
+ BOOL any = FALSE, all = TRUE;
+ IPin *middle_source, *peer;
+ IEnumPins *source_enum;
PIN_DIRECTION dir;
- IFilterMapper2 *pFilterMapper2 = NULL;
-
- TRACE("(%p/%p)->(%p, %p)\n", This, iface, ppinOut, ppinIn);
-
- if(!ppinOut || !ppinIn)
- return E_POINTER;
-
- if (TRACE_ON(quartz))
- {
- hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
- if (FAILED(hr))
- return hr;
-
- TRACE("Filter owning ppinIn(%p) => %p\n", ppinIn, PinInfo.pFilter);
- IBaseFilter_Release(PinInfo.pFilter);
-
- hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
- if (FAILED(hr))
- return hr;
+ PIN_INFO info;
+ HRESULT hr;
- TRACE("Filter owning ppinOut(%p) => %p\n", ppinOut, PinInfo.pFilter);
- IBaseFilter_Release(PinInfo.pFilter);
- }
+ TRACE("Trying to autoplug %p to %p through %p.\n", source, sink, middle_sink);
- EnterCriticalSection(&This->cs);
- ++This->recursioncount;
- if (This->recursioncount >= 5)
- {
- WARN("Recursion count has reached %d\n", This->recursioncount);
- hr = VFW_E_CANNOT_CONNECT;
- goto out;
- }
-
- hr = IPin_QueryDirection(ppinOut, &dir);
- if (FAILED(hr))
- goto out;
+ IPin_QueryDirection(middle_sink, &dir);
+ if (dir != PINDIR_INPUT)
+ return E_FAIL;
- if (dir == PINDIR_INPUT)
+ if (IPin_ConnectedTo(middle_sink, &peer) == S_OK)
{
- IPin *temp;
-
- TRACE("Directions seem backwards, swapping pins\n");
-
- temp = ppinIn;
- ppinIn = ppinOut;
- ppinOut = temp;
+ IPin_Release(peer);
+ return E_FAIL;
}
- /* Try direct connection first */
- hr = IFilterGraph2_ConnectDirect(iface, ppinOut, ppinIn, NULL);
-
- /* If direct connection succeeded, we should propagate that return value.
- * If it returned VFW_E_NOT_CONNECTED or VFW_E_NO_AUDIO_HARDWARE, then don't
- * even bother trying intermediate filters, since they won't succeed. */
- if (SUCCEEDED(hr) || hr == VFW_E_NOT_CONNECTED || hr == VFW_E_NO_AUDIO_HARDWARE)
- goto out;
+ if (FAILED(hr = IFilterGraph2_ConnectDirect(&graph->IFilterGraph2_iface, source, middle_sink, NULL)))
+ return E_FAIL;
- TRACE("Direct connection failed, trying to render using extra filters\n");
+ if (FAILED(hr = IBaseFilter_EnumPins(filter, &source_enum)))
+ goto err;
- LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry)
+ while (IEnumPins_Next(source_enum, 1, &middle_source, NULL) == S_OK)
{
- hr = IBaseFilter_EnumPins(filter->filter, &penumpins);
- if (FAILED(hr))
- goto out;
-
- while (IEnumPins_Next(penumpins, 1, &pin, NULL) == S_OK)
+ IPin_QueryPinInfo(middle_source, &info);
+ IBaseFilter_Release(info.pFilter);
+ if (info.dir != PINDIR_OUTPUT)
{
- IPin_QueryDirection(pin, &dir);
- if (dir == PINDIR_INPUT && SUCCEEDED(IFilterGraph2_ConnectDirect(iface,
- ppinOut, pin, NULL)))
- {
- if (SUCCEEDED(hr = connect_output_pin(This, filter->filter, ppinIn)))
- {
- IPin_Release(pin);
- IEnumPins_Release(penumpins);
- goto out;
- }
-
- IFilterGraph2_Disconnect(iface, pin);
- IFilterGraph2_Disconnect(iface, ppinOut);
- }
- IPin_Release(pin);
- }
-
- IEnumPins_Release(penumpins);
- }
-
- /* Find the appropriate transform filter than can transform the minor media type of output pin of the upstream
- * filter to the minor mediatype of input pin of the renderer */
- hr = IPin_EnumMediaTypes(ppinOut, &penummt);
- if (FAILED(hr))
- {
- WARN("EnumMediaTypes (%x)\n", hr);
- goto out;
- }
-
- hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
- if (FAILED(hr)) {
- WARN("IEnumMediaTypes_Next (%x)\n", hr);
- goto out;
- }
-
- if (!nbmt)
- {
- WARN("No media type found!\n");
- hr = VFW_E_INVALIDMEDIATYPE;
- goto out;
- }
- TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
- TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
-
- hr = IUnknown_QueryInterface(This->punkFilterMapper2, &IID_IFilterMapper2, (void**)&pFilterMapper2);
- if (FAILED(hr)) {
- WARN("Unable to get IFilterMapper2 (%x)\n", hr);
- goto out;
- }
-
- /* Try to find a suitable filter that can connect to the pin to render */
- tab[0] = mt->majortype;
- tab[1] = mt->subtype;
- hr = IFilterMapper2_EnumMatchingFilters(pFilterMapper2, &pEnumMoniker, 0, FALSE, MERIT_UNLIKELY, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
- if (FAILED(hr)) {
- WARN("Unable to enum filters (%x)\n", hr);
- goto out;
- }
-
- hr = VFW_E_CANNOT_RENDER;
- while (IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, NULL) == S_OK)
- {
- VARIANT var;
- IBaseFilter* pfilter = NULL;
- IAMGraphBuilderCallback *callback = NULL;
-
- hr = GetFilterInfo(pMoniker, &var);
- if (FAILED(hr)) {
- WARN("Unable to retrieve filter info (%x)\n", hr);
- goto error;
- }
-
- hr = create_filter(This, pMoniker, &pfilter);
- IMoniker_Release(pMoniker);
- if (FAILED(hr)) {
- WARN("Unable to create filter (%x), trying next one\n", hr);
- goto error;
+ IPin_Release(middle_source);
+ continue;
}
-
- if (This->pSite)
+ if (info.achName[0] == '~')
{
- IUnknown_QueryInterface(This->pSite, &IID_IAMGraphBuilderCallback, (LPVOID*)&callback);
- if (callback)
- {
- HRESULT rc;
- rc = IAMGraphBuilderCallback_SelectedFilter(callback, pMoniker);
- if (FAILED(rc))
- {
- TRACE("Filter rejected by IAMGraphBuilderCallback_SelectedFilter\n");
- IAMGraphBuilderCallback_Release(callback);
- goto error;
- }
- }
+ TRACE("Skipping non-rendered pin %s.\n", debugstr_w(info.achName));
+ IPin_Release(middle_source);
+ continue;
}
-
- if (callback)
+ if (IPin_ConnectedTo(middle_source, &peer) == S_OK)
{
- HRESULT rc;
- rc = IAMGraphBuilderCallback_CreatedFilter(callback, pfilter);
- IAMGraphBuilderCallback_Release(callback);
- if (FAILED(rc))
- {
- IBaseFilter_Release(pfilter);
- pfilter = NULL;
- TRACE("Filter rejected by IAMGraphBuilderCallback_CreatedFilter\n");
- goto error;
- }
- }
-
- hr = IFilterGraph2_AddFilter(iface, pfilter, V_BSTR(&var));
- if (FAILED(hr)) {
- WARN("Unable to add filter (%x)\n", hr);
- IBaseFilter_Release(pfilter);
- pfilter = NULL;
- goto error;
- }
-
- VariantClear(&var);
-
- hr = IBaseFilter_EnumPins(pfilter, &penumpins);
- if (FAILED(hr)) {
- WARN("Enumpins (%x)\n", hr);
- goto error;
+ IPin_Release(peer);
+ IPin_Release(middle_source);
+ continue;
}
- while (IEnumPins_Next(penumpins, 1, &pin, NULL) == S_OK)
+ hr = autoplug(graph, middle_source, sink, recursion_depth + 1);
+ IPin_Release(middle_source);
+ if (SUCCEEDED(hr) && sink)
{
- if (SUCCEEDED(IFilterGraph2_ConnectDirect(iface, ppinOut, pin, NULL)))
- {
- if (SUCCEEDED(hr = connect_output_pin(This, pfilter, ppinIn)))
- {
- IPin_Release(pin);
- IEnumPins_Release(penumpins);
- IBaseFilter_Release(pfilter);
- IEnumMoniker_Release(pEnumMoniker);
- goto out;
- }
- IFilterGraph2_Disconnect(iface, pin);
- IFilterGraph2_Disconnect(iface, ppinOut);
- }
- IPin_Release(pin);
- }
- IEnumPins_Release(penumpins);
-
-error:
- VariantClear(&var);
- if (pfilter) {
- IFilterGraph2_RemoveFilter(iface, pfilter);
- IBaseFilter_Release(pfilter);
+ IEnumPins_Release(source_enum);
+ return hr;
}
+ if (SUCCEEDED(hr))
+ any = TRUE;
+ if (hr != S_OK)
+ all = FALSE;
}
+ IEnumPins_Release(source_enum);
- if (FAILED(hr))
- hr = VFW_E_CANNOT_CONNECT;
-
- IEnumMoniker_Release(pEnumMoniker);
+ if (!sink)
+ {
+ if (all)
+ return S_OK;
+ if (any)
+ return VFW_S_PARTIAL_RENDER;
+ }
-out:
- if (pFilterMapper2)
- IFilterMapper2_Release(pFilterMapper2);
- if (penummt)
- IEnumMediaTypes_Release(penummt);
- if (mt)
- DeleteMediaType(mt);
- --This->recursioncount;
- LeaveCriticalSection(&This->cs);
- TRACE("--> %08x\n", hr);
- return hr;
+err:
+ IFilterGraph2_Disconnect(&graph->IFilterGraph2_iface, source);
+ IFilterGraph2_Disconnect(&graph->IFilterGraph2_iface, middle_sink);
+ return E_FAIL;
}
-/* Render all output pins of the given filter. Helper for FilterGraph2_Render(). */
-static HRESULT render_output_pins(IFilterGraphImpl *graph, IBaseFilter *filter)
+static HRESULT autoplug_through_filter(IFilterGraphImpl *graph, IPin *source,
+ IBaseFilter *filter, IPin *sink, unsigned int recursion_depth)
{
- BOOL renderany = FALSE;
- BOOL renderall = TRUE;
- IEnumPins *enumpins;
- IPin *pin, *peer;
- PIN_INFO info;
+ IEnumPins *sink_enum;
+ IPin *filter_sink;
+ HRESULT hr;
- IBaseFilter_EnumPins(filter, &enumpins);
- while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
+ TRACE("Trying to autoplug %p to %p through %p.\n", source, sink, filter);
+
+ if (FAILED(hr = IBaseFilter_EnumPins(filter, &sink_enum)))
+ return hr;
+
+ while (IEnumPins_Next(sink_enum, 1, &filter_sink, NULL) == S_OK)
{
- IPin_QueryPinInfo(pin, &info);
- IBaseFilter_Release(info.pFilter);
- if (info.dir == PINDIR_OUTPUT)
+ hr = autoplug_through_sink(graph, source, filter, filter_sink, sink, recursion_depth);
+ IPin_Release(filter_sink);
+ if (SUCCEEDED(hr))
{
- if (info.achName[0] == '~')
- {
- TRACE("Skipping non-rendered pin %s.\n", debugstr_w(info.achName));
- IPin_Release(pin);
- continue;
- }
-
- if (IPin_ConnectedTo(pin, &peer) == VFW_E_NOT_CONNECTED)
- {
- HRESULT hr;
- hr = IFilterGraph2_Render(&graph->IFilterGraph2_iface, pin);
- if (SUCCEEDED(hr))
- renderany = TRUE;
- else
- renderall = FALSE;
- }
- else
- IPin_Release(peer);
+ IEnumPins_Release(sink_enum);
+ return hr;
}
-
- IPin_Release(pin);
}
-
- IEnumPins_Release(enumpins);
-
- if (renderall)
- return S_OK;
-
- if (renderany)
- return VFW_S_PARTIAL_RENDER;
-
- return VFW_E_CANNOT_RENDER;
+ IEnumPins_Release(sink_enum);
+ return VFW_E_CANNOT_CONNECT;
}
-/* Ogg hates me if I create a direct rendering method
- *
- * It can only connect to a pin properly once, so use a recursive method that does
- *
- * +----+ --- (PIN 1) (Render is called on this pin)
- * | |
- * +----+ --- (PIN 2)
- *
- * Enumerate possible renderers that EXACTLY match the requested type
- *
- * If none is available, try to add intermediate filters that can connect to the input pin
- * then call Render on that intermediate pin's output pins
- * if it succeeds: Render returns success, if it doesn't, the intermediate filter is removed,
- * and another filter that can connect to the input pin is tried
- * if we run out of filters that can, give up and return VFW_E_CANNOT_RENDER
- * It's recursive, but fun!
- */
-
-static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, IPin *ppinOut)
+/* 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)
{
- IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
- IEnumMediaTypes* penummt;
+ IAMGraphBuilderCallback *callback = NULL;
+ IEnumMediaTypes *enummt;
+ IFilterMapper2 *mapper;
struct filter *filter;
- AM_MEDIA_TYPE* mt;
- ULONG nbmt;
+ AM_MEDIA_TYPE *mt;
HRESULT hr;
- IEnumMoniker* pEnumMoniker;
- GUID tab[4];
- ULONG nb;
- IMoniker* pMoniker;
- IFilterMapper2 *pFilterMapper2 = NULL;
+ TRACE("Trying to autoplug %p to %p, recursion depth %u.\n", source, sink, recursion_depth);
- TRACE("(%p/%p)->(%p)\n", This, iface, ppinOut);
+ if (recursion_depth >= 5)
+ {
+ WARN("Recursion depth has reached 5; aborting.\n");
+ return VFW_E_CANNOT_CONNECT;
+ }
- if (TRACE_ON(quartz))
+ if (sink)
{
- PIN_INFO PinInfo;
+ /* Try to connect directly to this sink. */
+ hr = IFilterGraph2_ConnectDirect(&graph->IFilterGraph2_iface, source, sink, NULL);
- hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
- if (FAILED(hr))
+ /* If direct connection succeeded, we should propagate that return value.
+ * If it returned VFW_E_NOT_CONNECTED or VFW_E_NO_AUDIO_HARDWARE, then don't
+ * even bother trying intermediate filters, since they won't succeed. */
+ if (SUCCEEDED(hr) || hr == VFW_E_NOT_CONNECTED || hr == VFW_E_NO_AUDIO_HARDWARE)
return hr;
-
- TRACE("Filter owning pin => %p\n", PinInfo.pFilter);
- IBaseFilter_Release(PinInfo.pFilter);
}
- /* Try to find out if there is a renderer for the specified subtype already, and use that
- */
- EnterCriticalSection(&This->cs);
- LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry)
+ /* Always prefer filters in the graph. */
+ LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
{
- IEnumPins *enumpins = NULL;
- IPin *pin = NULL;
-
- hr = IBaseFilter_EnumPins(filter->filter, &enumpins);
-
- if (FAILED(hr) || !enumpins)
- continue;
-
- IEnumPins_Reset(enumpins);
- while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
- {
- IPin *to = NULL;
- PIN_DIRECTION dir = PINDIR_OUTPUT;
-
- IPin_QueryDirection(pin, &dir);
- if (dir != PINDIR_INPUT)
- {
- IPin_Release(pin);
- continue;
- }
- IPin_ConnectedTo(pin, &to);
-
- if (to == NULL)
- {
- hr = FilterGraph2_ConnectDirect(iface, ppinOut, pin, NULL);
- if (SUCCEEDED(hr))
- {
- TRACE("Connected successfully %p/%p, %08x look if we should render more!\n", ppinOut, pin, hr);
- IPin_Release(pin);
-
- hr = render_output_pins(This, filter->filter);
- if (FAILED(hr))
- {
- IPin_Disconnect(ppinOut);
- IPin_Disconnect(pin);
- continue;
- }
- IEnumPins_Release(enumpins);
- LeaveCriticalSection(&This->cs);
- return hr;
- }
- WARN("Could not connect!\n");
- }
- else
- IPin_Release(to);
-
- IPin_Release(pin);
- }
- IEnumPins_Release(enumpins);
+ if (SUCCEEDED(hr = autoplug_through_filter(graph, source, filter->filter, sink, recursion_depth)))
+ return hr;
}
- LeaveCriticalSection(&This->cs);
+ IUnknown_QueryInterface(graph->punkFilterMapper2, &IID_IFilterMapper2, (void **)&mapper);
- hr = IPin_EnumMediaTypes(ppinOut, &penummt);
- if (FAILED(hr)) {
- WARN("EnumMediaTypes (%x)\n", hr);
+ if (FAILED(hr = IPin_EnumMediaTypes(source, &enummt)))
+ {
+ IFilterMapper2_Release(mapper);
return hr;
}
- IEnumMediaTypes_Reset(penummt);
+ if (graph->pSite)
+ IUnknown_QueryInterface(graph->pSite, &IID_IAMGraphBuilderCallback, (void **)&callback);
- /* Looks like no existing renderer of the kind exists
- * Try adding new ones
- */
- tab[0] = tab[1] = GUID_NULL;
- while (SUCCEEDED(hr))
+ while (IEnumMediaTypes_Next(enummt, 1, &mt, NULL) == S_OK)
{
- hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
- if (FAILED(hr)) {
- WARN("IEnumMediaTypes_Next (%x)\n", hr);
- break;
- }
- if (!nbmt)
- {
- hr = VFW_E_CANNOT_RENDER;
- break;
- }
- else
+ GUID types[2] = {mt->majortype, mt->subtype};
+ IEnumMoniker *enummoniker;
+ IBaseFilter *filter;
+ IMoniker *moniker;
+
+ DeleteMediaType(mt);
+
+ if (FAILED(hr = IFilterMapper2_EnumMatchingFilters(mapper, &enummoniker, 0, FALSE,
+ MERIT_UNLIKELY, TRUE, 1, types, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL)))
+ goto out;
+
+ while (IEnumMoniker_Next(enummoniker, 1, &moniker, NULL) == S_OK)
{
- TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
- TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
+ IPropertyBag *bag;
+ VARIANT var;
- /* Only enumerate once, this doesn't account for all previous ones, but this should be enough nonetheless */
- if (IsEqualIID(&tab[0], &mt->majortype) && IsEqualIID(&tab[1], &mt->subtype))
+ VariantInit(&var);
+ IMoniker_BindToStorage(moniker, NULL, NULL, &IID_IPropertyBag, (void **)&bag);
+ hr = IPropertyBag_Read(bag, L"FriendlyName", &var, NULL);
+ IPropertyBag_Release(bag);
+ if (FAILED(hr))
{
- DeleteMediaType(mt);
+ IMoniker_Release(moniker);
continue;
}
- if (pFilterMapper2 == NULL)
+ if (callback && FAILED(hr = IAMGraphBuilderCallback_SelectedFilter(callback, moniker)))
{
- hr = IUnknown_QueryInterface(This->punkFilterMapper2, &IID_IFilterMapper2, (void**)&pFilterMapper2);
- if (FAILED(hr))
- {
- WARN("Unable to query IFilterMapper2 (%x)\n", hr);
- break;
- }
+ TRACE("Filter rejected by IAMGraphBuilderCallback::SelectedFilter(), hr %#x.\n", hr);
+ IMoniker_Release(moniker);
+ continue;
}
- /* Try to find a suitable renderer with the same media type */
- tab[0] = mt->majortype;
- tab[1] = mt->subtype;
- hr = IFilterMapper2_EnumMatchingFilters(pFilterMapper2, &pEnumMoniker, 0, FALSE, MERIT_UNLIKELY, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
+ hr = create_filter(graph, moniker, &filter);
+ IMoniker_Release(moniker);
if (FAILED(hr))
{
- WARN("Unable to enum filters (%x)\n", hr);
- break;
+ ERR("Failed to create filter for %s, hr %#x.\n", debugstr_w(V_BSTR(&var)), hr);
+ VariantClear(&var);
+ continue;
}
- }
- hr = E_FAIL;
- while (IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
- {
- VARIANT var;
- IPin* ppinfilter;
- IBaseFilter* pfilter = NULL;
- IEnumPins* penumpins = NULL;
- ULONG pin;
-
- hr = GetFilterInfo(pMoniker, &var);
- if (FAILED(hr)) {
- WARN("Unable to retrieve filter info (%x)\n", hr);
- goto error;
+ if (callback && FAILED(hr = IAMGraphBuilderCallback_CreatedFilter(callback, filter)))
+ {
+ TRACE("Filter rejected by IAMGraphBuilderCallback::CreatedFilter(), hr %#x.\n", hr);
+ IBaseFilter_Release(filter);
+ continue;
}
- hr = create_filter(This, pMoniker, &pfilter);
- IMoniker_Release(pMoniker);
+ hr = IFilterGraph2_AddFilter(&graph->IFilterGraph2_iface, filter, V_BSTR(&var));
+ VariantClear(&var);
if (FAILED(hr))
{
- WARN("Unable to create filter (%x), trying next one\n", hr);
- goto error;
- }
-
- hr = IFilterGraph2_AddFilter(iface, pfilter, V_BSTR(&var));
- if (FAILED(hr)) {
- WARN("Unable to add filter (%x)\n", hr);
- IBaseFilter_Release(pfilter);
- pfilter = NULL;
- goto error;
+ ERR("Failed to add filter, hr %#x.\n", hr);
+ IBaseFilter_Release(filter);
+ continue;
}
- hr = IBaseFilter_EnumPins(pfilter, &penumpins);
- if (FAILED(hr)) {
- WARN("Splitter Enumpins (%x)\n", hr);
- goto error;
+ hr = autoplug_through_filter(graph, source, filter, sink, recursion_depth);
+ if (SUCCEEDED(hr))
+ {
+ IBaseFilter_Release(filter);
+ goto out;
}
- while ((hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin)) == S_OK)
- {
- PIN_DIRECTION dir;
+ IFilterGraph2_RemoveFilter(&graph->IFilterGraph2_iface, filter);
+ IBaseFilter_Release(filter);
+ }
+ IEnumMoniker_Release(enummoniker);
+ }
- if (pin == 0) {
- WARN("No Pin\n");
- hr = E_FAIL;
- goto error;
- }
+ hr = VFW_E_CANNOT_CONNECT;
- hr = IPin_QueryDirection(ppinfilter, &dir);
- if (FAILED(hr)) {
- IPin_Release(ppinfilter);
- WARN("QueryDirection failed (%x)\n", hr);
- goto error;
- }
- if (dir != PINDIR_INPUT) {
- IPin_Release(ppinfilter);
- continue; /* Wrong direction */
- }
+out:
+ if (callback) IAMGraphBuilderCallback_Release(callback);
+ IEnumMediaTypes_Release(enummt);
+ IFilterMapper2_Release(mapper);
+ return hr;
+}
- /* Connect the pin to the "Renderer" */
- hr = IFilterGraph2_ConnectDirect(iface, ppinOut, ppinfilter, NULL);
- IPin_Release(ppinfilter);
+static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *source, IPin *sink)
+{
+ IFilterGraphImpl *graph = impl_from_IFilterGraph2(iface);
+ PIN_DIRECTION dir;
+ HRESULT hr;
- if (FAILED(hr)) {
- WARN("Unable to connect %s to renderer (%x)\n", debugstr_w(V_BSTR(&var)), hr);
- goto error;
- }
- TRACE("Connected, recursing %s\n", debugstr_w(V_BSTR(&var)));
+ TRACE("graph %p, source %p, sink %p.\n", graph, source, sink);
- VariantClear(&var);
+ if (!source || !sink)
+ return E_POINTER;
- hr = render_output_pins(This, pfilter);
- if (FAILED(hr)) {
- WARN("Unable to connect recursively (%x)\n", hr);
- goto error;
- }
- IBaseFilter_Release(pfilter);
- break;
- }
- if (SUCCEEDED(hr)) {
- IEnumPins_Release(penumpins);
- break; /* out of IEnumMoniker_Next loop */
- }
+ if (FAILED(hr = IPin_QueryDirection(source, &dir)))
+ return hr;
- /* IEnumPins_Next failed, all other failure case caught by goto error */
- WARN("IEnumPins_Next (%x)\n", hr);
- /* goto error */
+ if (dir == PINDIR_INPUT)
+ {
+ IPin *temp;
-error:
- VariantClear(&var);
- if (penumpins)
- IEnumPins_Release(penumpins);
- if (pfilter) {
- IFilterGraph2_RemoveFilter(iface, pfilter);
- IBaseFilter_Release(pfilter);
- }
- if (SUCCEEDED(hr)) DebugBreak();
- }
+ TRACE("Directions seem backwards, swapping pins\n");
- IEnumMoniker_Release(pEnumMoniker);
- if (nbmt)
- DeleteMediaType(mt);
- if (SUCCEEDED(hr))
- break;
- hr = S_OK;
+ temp = sink;
+ sink = source;
+ source = temp;
}
- if (pFilterMapper2)
- IFilterMapper2_Release(pFilterMapper2);
+ EnterCriticalSection(&graph->cs);
+
+ hr = autoplug(graph, source, sink, 0);
+
+ LeaveCriticalSection(&graph->cs);
+
+ TRACE("Returning %#x.\n", hr);
+ return hr;
+}
+
+static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, IPin *source)
+{
+ IFilterGraphImpl *graph = impl_from_IFilterGraph2(iface);
+ HRESULT hr;
+
+ TRACE("graph %p, source %p.\n", graph, source);
+
+ EnterCriticalSection(&graph->cs);
+ hr = autoplug(graph, source, NULL, 0);
+ LeaveCriticalSection(&graph->cs);
+ if (hr == VFW_E_CANNOT_CONNECT)
+ hr = VFW_E_CANNOT_RENDER;
- IEnumMediaTypes_Release(penummt);
+ TRACE("Returning %#x.\n", hr);
return hr;
}
@@ -5755,7 +5404,6 @@ static HRESULT filter_graph_common_create(IUnknown *outer, IUnknown **out, BOOL
memcpy(&fimpl->timeformatseek, &TIME_FORMAT_MEDIA_TIME, sizeof(GUID));
fimpl->stream_start = fimpl->stream_elapsed = 0;
fimpl->punkFilterMapper2 = NULL;
- fimpl->recursioncount = 0;
fimpl->version = 0;
fimpl->current_pos = 0;
diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c
index 22ed37cd307..5a61b754648 100644
--- a/dlls/quartz/tests/filtergraph.c
+++ b/dlls/quartz/tests/filtergraph.c
@@ -2110,7 +2110,7 @@ static void test_graph_builder_connect(void)
{
static const GUID parser1_clsid = {0x12345678};
static const GUID parser2_clsid = {0x87654321};
- AM_MEDIA_TYPE source_type = {{0}}, sink_type = {{0}}, parser3_type = {{0}};
+ AM_MEDIA_TYPE source_types[2] = {{{0}}}, sink_type = {{0}}, parser3_type = {{0}};
struct testpin source_pin, sink_pin, sink2_pin, parser1_pins[3], parser2_pins[2], parser3_pins[2];
struct testfilter source, sink, sink2, parser1, parser2, parser3;
struct testfilter_cf parser1_cf = { {&testfilter_cf_vtbl}, &parser1 };
@@ -2125,10 +2125,11 @@ static void test_graph_builder_connect(void)
HRESULT hr;
ULONG ref;
- memset(&source_type.majortype, 0xcc, sizeof(GUID));
+ memset(&source_types[0].majortype, 0xcc, sizeof(GUID));
+ memset(&source_types[1].majortype, 0xdd, sizeof(GUID));
memset(&sink_type.majortype, 0x66, sizeof(GUID));
- testsource_init(&source_pin, &source_type, 1);
- source_pin.request_mt = &source_type;
+ testsource_init(&source_pin, source_types, 2);
+ source_pin.request_mt = &source_types[1];
testfilter_init(&source, &source_pin, 1);
testsink_init(&sink_pin);
testfilter_init(&sink, &sink_pin, 1);
@@ -2398,7 +2399,7 @@ todo_wine
regpins[1].cInstances = 1;
regpins[1].nMediaTypes = 1;
regpins[1].lpMediaType = ®types;
- regtypes.clsMajorType = &source_type.majortype;
+ regtypes.clsMajorType = &source_types[1].majortype;
regtypes.clsMinorType = &MEDIASUBTYPE_NULL;
hr = IFilterMapper2_RegisterFilter(mapper, &parser1_clsid, L"test", NULL, NULL, NULL, ®filter);
if (hr == E_ACCESSDENIED)
--
2.27.0
More information about the wine-devel
mailing list