[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, &regfilter);
     if (hr == E_ACCESSDENIED)
-- 
2.27.0




More information about the wine-devel mailing list