From d54c53a4b64223cb5744571b9f56064543e385c0 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 26 Jun 2008 11:26:53 -0700 Subject: [PATCH] quartz: Fix Render and RenderFile. RenderFile should add a source filter and call Render on each output pin, while Render() should try to connect, first directly to any existing renderers, and then using intermediates. It uses recursion since this is the only possible way to implement Render sanely. --- dlls/quartz/filtergraph.c | 400 ++++++++++++++++++++------------------ 1 file changed, 206 insertions(+), 194 deletions(-) diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c index 3ca9c6ff77..9f6f79a756 100644 --- a/dlls/quartz/filtergraph.c +++ b/dlls/quartz/filtergraph.c @@ -1060,8 +1060,80 @@ error: return SUCCEEDED(hr) ? S_OK : hr; } -static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, - IPin *ppinOut) { +static HRESULT WINAPI FilterGraph2_RenderRecurse(IFilterGraphImpl *This, IPin *ppinOut) +{ + /* This pin has been connected now, try to call render on all pins that aren't connected */ + IPin *to = NULL; + PIN_INFO info; + IEnumPins *enumpins = NULL; + BOOL renderany = FALSE; + BOOL renderall = TRUE; + + IPin_QueryPinInfo(ppinOut, &info); + + IBaseFilter_EnumPins(info.pFilter, &enumpins); + /* Don't need to hold a reference, IEnumPins does */ + IBaseFilter_Release(info.pFilter); + + IEnumPins_Reset(enumpins); + while (IEnumPins_Next(enumpins, 1, &to, NULL) == S_OK) + { + PIN_DIRECTION dir = PINDIR_INPUT; + + IPin_QueryDirection(to, &dir); + + if (dir == PINDIR_OUTPUT) + { + IPin *out = NULL; + + IPin_ConnectedTo(to, &out); + if (!out) + { + HRESULT hr; + hr = IFilterGraph2_Render((IFilterGraph2 *)&This->IFilterGraph2_vtbl, to); + if (SUCCEEDED(hr)) + renderany = TRUE; + else + renderall = FALSE; + } + else + IPin_Release(out); + } + + IPin_Release(to); + } + + IEnumPins_Release(enumpins); + + if (renderall) + return S_OK; + + if (renderany) + return VFW_S_PARTIAL_RENDER; + + return VFW_E_CANNOT_RENDER; +} + +/* 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) +{ ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface); IEnumMediaTypes* penummt; AM_MEDIA_TYPE* mt; @@ -1069,11 +1141,13 @@ static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, HRESULT hr; IEnumMoniker* pEnumMoniker; - GUID tab[2]; + GUID tab[4]; ULONG nb; IMoniker* pMoniker; INT x; + BOOL final = FALSE; + TRACE("(%p/%p)->(%p)\n", This, iface, ppinOut); if (TRACE_ON(quartz)) @@ -1093,7 +1167,6 @@ static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, EnterCriticalSection(&This->cs); for (x = 0; x < This->nFilters; ++x) { - BOOL renderer = TRUE; IEnumPins *enumpins = NULL; IPin *pin = NULL; @@ -1105,46 +1178,43 @@ static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, IEnumPins_Reset(enumpins); while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK) { + IPin *to = NULL; PIN_DIRECTION dir = PINDIR_OUTPUT; IPin_QueryDirection(pin, &dir); - IPin_Release(pin); - pin = NULL; if (dir != PINDIR_INPUT) { - renderer = FALSE; - break; + IPin_Release(pin); + continue; } - } + IPin_ConnectedTo(pin, &to); - IEnumPins_Reset(enumpins); - if (renderer == TRUE) - { - while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK) + if (to == NULL) { - IPin *to = NULL; - - IPin_ConnectedTo(pin, &to); - - if (to == NULL) + hr = IPin_Connect(ppinOut, pin, NULL); + if (SUCCEEDED(hr)) { - hr = IFilterGraph2_Connect(iface, ppinOut, pin); - if (SUCCEEDED(hr)) + TRACE("Connected succesfully %p/%p, %08x look if we should render more!\n", ppinOut, pin, hr); + IPin_Release(pin); + + hr = FilterGraph2_RenderRecurse(This, pin); + if (FAILED(hr)) { - IPin_Release(pin); - IEnumPins_Release(enumpins); - LeaveCriticalSection(&This->cs); - ERR("Connected succesfully\n"); - return hr; + IPin_Disconnect(ppinOut); + IPin_Disconnect(pin); + continue; } + IEnumPins_Release(enumpins); + LeaveCriticalSection(&This->cs); + return hr; } - else - IPin_Release(to); - - IPin_Release(pin); + WARN("Could not connect!\n"); } - } + else + IPin_Release(to); + IPin_Release(pin); + } IEnumPins_Release(enumpins); } @@ -1152,34 +1222,60 @@ static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, hr = IPin_EnumMediaTypes(ppinOut, &penummt); if (FAILED(hr)) { - ERR("EnumMediaTypes (%x)\n", hr); + WARN("EnumMediaTypes (%x)\n", hr); return hr; } IEnumMediaTypes_Reset(penummt); - while(1) + /* Looks like no existing renderer of the kind exists + * Try adding new ones + */ + tab[0] = tab[1] = GUID_NULL; + while (SUCCEEDED(hr)) { hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt); if (FAILED(hr)) { - ERR("IEnumMediaTypes_Next (%x)\n", hr); - return hr; + WARN("IEnumMediaTypes_Next (%x)\n", hr); + break; } - if (!nbmt) + if (!nbmt && !final) + { + final = TRUE; + tab[0] = tab[1] = GUID_NULL; + IEnumMediaTypes_Reset(penummt); + continue; + } + else if (!nbmt) + { + hr = VFW_E_CANNOT_RENDER; break; - TRACE("MajorType %s\n", debugstr_guid(&mt->majortype)); - TRACE("SubType %s\n", debugstr_guid(&mt->subtype)); + } + else + { + TRACE("MajorType %s\n", debugstr_guid(&mt->majortype)); + TRACE("SubType %s\n", debugstr_guid(&mt->subtype)); - /* Try to find a suitable renderer with the same media type */ - tab[0] = mt->majortype; - tab[1] = GUID_NULL; - hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, MERIT_UNLIKELY, TRUE, 1, tab, NULL, NULL, TRUE, FALSE, 0, NULL, NULL, NULL); - if (FAILED(hr)) { - ERR("Unable to enum filters (%x)\n", hr); - return hr; + /* 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[0], &mt->majortype)) + { + DeleteMediaType(mt); + continue; + } + + /* Try to find a suitable renderer with the same media type */ + tab[0] = mt->majortype; + tab[1] = mt->subtype; + hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, MERIT_UNLIKELY, TRUE, 1, tab, NULL, NULL, !final, FALSE, 0, NULL, NULL, NULL); + if (FAILED(hr)) + { + WARN("Unable to enum filters (%x)\n", hr); + break; + } } + hr = E_FAIL; - while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK) + while (IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK) { VARIANT var; GUID clsid; @@ -1191,19 +1287,20 @@ static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, hr = GetFilterInfo(pMoniker, &clsid, &var); IMoniker_Release(pMoniker); if (FAILED(hr)) { - ERR("Unable to retrieve filter info (%x)\n", hr); + WARN("Unable to retrieve filter info (%x)\n", hr); goto error; } hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pfilter); - if (FAILED(hr)) { - ERR("Unable to create filter (%x), trying next one\n", hr); - goto error; + if (FAILED(hr)) + { + WARN("Unable to create filter (%x), trying next one\n", hr); + goto error; } hr = IFilterGraph2_AddFilter(iface, pfilter, V_UNION(&var, bstrVal)); if (FAILED(hr)) { - ERR("Unable to add filter (%x)\n", hr); + WARN("Unable to add filter (%x)\n", hr); IBaseFilter_Release(pfilter); pfilter = NULL; goto error; @@ -1211,30 +1308,36 @@ static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, hr = IBaseFilter_EnumPins(pfilter, &penumpins); if (FAILED(hr)) { - ERR("Splitter Enumpins (%x)\n", hr); + WARN("Splitter Enumpins (%x)\n", hr); goto error; } hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin); IEnumPins_Release(penumpins); if (FAILED(hr)) { - ERR("Next (%x)\n", hr); - goto error; + WARN("Next (%x)\n", hr); + goto error; } if (pin == 0) { - ERR("No Pin\n"); - goto error; + WARN("No Pin\n"); + hr = E_FAIL; + goto error; } - /* Connect the pin to render to the renderer */ - hr = IFilterGraph2_Connect(iface, ppinOut, ppinfilter); + /* Connect the pin to the "Renderer" */ + hr = IPin_Connect(ppinOut, ppinfilter, NULL); + IPin_Release(ppinfilter); + if (FAILED(hr)) { - TRACE("Unable to connect to renderer (%x)\n", hr); - IPin_Release(ppinfilter); + WARN("Unable to connect %s to renderer (%x)\n", debugstr_w(V_UNION(&var, bstrVal)), hr); + goto error; + } + TRACE("Connected, recursing %s\n", debugstr_w(V_UNION(&var, bstrVal))); + hr = FilterGraph2_RenderRecurse(This, ppinfilter); + if (FAILED(hr)) { + WARN("Unable to connect recursively (%x)\n", hr); goto error; } - IPin_Release(ppinfilter); IBaseFilter_Release(pfilter); - pfilter = NULL; break; error: @@ -1242,37 +1345,32 @@ error: IFilterGraph2_RemoveFilter(iface, pfilter); IBaseFilter_Release(pfilter); } + if (!FAILED(hr)) DebugBreak(); } - DeleteMediaType(mt); - break; + if (nbmt) + DeleteMediaType(mt); + if (SUCCEEDED(hr)) + break; + hr = S_OK; } IEnumMediaTypes_Release(penummt); - - return S_OK; + return hr; } static HRESULT WINAPI FilterGraph2_RenderFile(IFilterGraph2 *iface, - LPCWSTR lpcwstrFile, - LPCWSTR lpcwstrPlayList) { + LPCWSTR lpcwstrFile, + LPCWSTR lpcwstrPlayList) +{ ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface); static const WCHAR string[] = {'R','e','a','d','e','r',0}; IBaseFilter* preader = NULL; - IBaseFilter* psplitter = NULL; IPin* ppinreader = NULL; - IPin* ppinsplitter = NULL; - IEnumPins* penumpins; - ULONG pin; + IEnumPins* penumpins = NULL; HRESULT hr; - IEnumMoniker* pEnumMoniker = NULL; - GUID tab[2]; - IPin** ppins = NULL; - ULONG nb; - IMoniker* pMoniker; - IFileSourceFilter* pfile = NULL; - AM_MEDIA_TYPE mt; - WCHAR* filename; + BOOL partial = FALSE; + HRESULT any = FALSE; TRACE("(%p/%p)->(%s, %s)\n", This, iface, debugstr_w(lpcwstrFile), debugstr_w(lpcwstrPlayList)); @@ -1280,134 +1378,47 @@ static HRESULT WINAPI FilterGraph2_RenderFile(IFilterGraph2 *iface, return E_INVALIDARG; hr = IFilterGraph2_AddSourceFilter(iface, lpcwstrFile, string, &preader); - - /* Retrieve file media type */ - if (SUCCEEDED(hr)) - hr = IBaseFilter_QueryInterface(preader, &IID_IFileSourceFilter, (LPVOID*)&pfile); - if (SUCCEEDED(hr)) { - hr = IFileSourceFilter_GetCurFile(pfile, &filename, &mt); - IFileSourceFilter_Release(pfile); - } - - if (SUCCEEDED(hr)) - hr = IBaseFilter_EnumPins(preader, &penumpins); - if (SUCCEEDED(hr)) { - hr = IEnumPins_Next(penumpins, 1, &ppinreader, &pin); - IEnumPins_Release(penumpins); - } - - if (SUCCEEDED(hr)) { - tab[0] = mt.majortype; - tab[1] = mt.subtype; - hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, MERIT_UNLIKELY, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL); - } - if (FAILED(hr)) - { - if (ppinreader) - IPin_Release(ppinreader); - if (pEnumMoniker) - IEnumMoniker_Release(pEnumMoniker); - if (preader) { - IFilterGraph2_RemoveFilter(iface, preader); - IBaseFilter_Release(preader); - } return hr; - } - hr = VFW_E_CANNOT_RENDER; - while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK) + if (SUCCEEDED(hr)) + hr = IBaseFilter_EnumPins(preader, &penumpins); + if (SUCCEEDED(hr)) { - VARIANT var; - GUID clsid; - - hr = GetFilterInfo(pMoniker, &clsid, &var); - IMoniker_Release(pMoniker); - if (FAILED(hr)) { - ERR("Unable to retrieve filter info (%x)\n", hr); - continue; - } - - hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&psplitter); - if (FAILED(hr)) { - ERR("Unable to create filter (%x), trying next one\n", hr); - continue; - } - - hr = IFilterGraph2_AddFilter(iface, psplitter, V_UNION(&var, bstrVal)); - if (FAILED(hr)) { - ERR("Unable add filter (%x)\n", hr); - IBaseFilter_Release(psplitter); - continue; - } - - /* Connect file source and splitter filters together */ - /* Make the splitter analyze incoming data */ - - hr = IBaseFilter_EnumPins(psplitter, &penumpins); - if (SUCCEEDED(hr)) { - hr = IEnumPins_Next(penumpins, 1, &ppinsplitter, &pin); - IEnumPins_Release(penumpins); - } - - if (SUCCEEDED(hr)) - hr = IPin_Connect(ppinreader, ppinsplitter, NULL); - - /* Make sure there's some output pins in the filter */ - if (SUCCEEDED(hr)) - hr = GetInternalConnections(psplitter, ppinsplitter, &ppins, &nb); - if (SUCCEEDED(hr)) { - if(nb == 0) { - IPin_Disconnect(ppinreader); - TRACE("No output pins found in filter\n"); - hr = VFW_E_CANNOT_RENDER; - } - } - - if (ppinsplitter) - IPin_Release(ppinsplitter); - ppinsplitter = NULL; + while (IEnumPins_Next(penumpins, 1, &ppinreader, NULL) == S_OK) + { + PIN_DIRECTION dir; - if (SUCCEEDED(hr)) { - TRACE("Successfully connected to filter\n"); - break; - } + IPin_QueryDirection(ppinreader, &dir); + if (dir == PINDIR_OUTPUT) + { + INT i; - TRACE("Cannot connect to filter (%x), trying next one\n", hr); + hr = IFilterGraph2_Render(iface, ppinreader); + ERR("Render %08x\n", hr); - if (ppins) { - CoTaskMemFree(ppins); - ppins = NULL; - } - IFilterGraph2_RemoveFilter(iface, psplitter); - IBaseFilter_Release(psplitter); - psplitter = NULL; - } + for (i = 0; i < This->nFilters; ++i) + FIXME("Filters in chain: %s\n", debugstr_w(This->pFilterNames[i])); - /* Render all output pin of the splitter by calling IFilterGraph2_Render on each of them */ - if (SUCCEEDED(hr)) { - int partial = 0; - int i; - TRACE("pins to consider: %d\n", nb); - for(i = 0; i < nb; i++) { - TRACE("Processing pin %d\n", i); - hr = IFilterGraph2_Render(iface, ppins[i]); - if (FAILED(hr)) { - ERR("Cannot render pin %p (%x)\n", ppins[i], hr); - partial = 1; + if (SUCCEEDED(hr)) + any = TRUE; + if (hr != S_OK) + partial = TRUE; } - IPin_Release(ppins[i]); + IPin_Release(ppinreader); } - CoTaskMemFree(ppins); + IEnumPins_Release(penumpins); - hr = (partial ? VFW_S_PARTIAL_RENDER : S_OK); + if (!any) + hr = VFW_E_CANNOT_RENDER; + else if (partial) + hr = VFW_S_PARTIAL_RENDER; + else + hr = S_OK; } - - IPin_Release(ppinreader); IBaseFilter_Release(preader); - if (psplitter) - IBaseFilter_Release(psplitter); + TRACE("--> %08x\n", hr); return hr; } @@ -1805,7 +1816,8 @@ static HRESULT WINAPI SendGetState(IBaseFilter *pFilter, DWORD_PTR data) } -static HRESULT SendFilterMessage(IMediaControl *iface, fnFoundFilter FoundFilter, DWORD_PTR data) { +static HRESULT SendFilterMessage(IMediaControl *iface, fnFoundFilter FoundFilter, DWORD_PTR data) +{ ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface); int i; IBaseFilter* pfilter; -- 2.32.0.93.g670b81a890