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.
This commit is contained in:
Maarten Lankhorst 2008-06-26 11:26:53 -07:00 committed by Alexandre Julliard
parent 0d1eea691c
commit d54c53a4b6
1 changed files with 223 additions and 211 deletions

View File

@ -1060,8 +1060,80 @@ error:
return SUCCEEDED(hr) ? S_OK : hr; return SUCCEEDED(hr) ? S_OK : hr;
} }
static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, static HRESULT WINAPI FilterGraph2_RenderRecurse(IFilterGraphImpl *This, IPin *ppinOut)
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); ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
IEnumMediaTypes* penummt; IEnumMediaTypes* penummt;
AM_MEDIA_TYPE* mt; AM_MEDIA_TYPE* mt;
@ -1069,11 +1141,13 @@ static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface,
HRESULT hr; HRESULT hr;
IEnumMoniker* pEnumMoniker; IEnumMoniker* pEnumMoniker;
GUID tab[2]; GUID tab[4];
ULONG nb; ULONG nb;
IMoniker* pMoniker; IMoniker* pMoniker;
INT x; INT x;
BOOL final = FALSE;
TRACE("(%p/%p)->(%p)\n", This, iface, ppinOut); TRACE("(%p/%p)->(%p)\n", This, iface, ppinOut);
if (TRACE_ON(quartz)) if (TRACE_ON(quartz))
@ -1093,7 +1167,6 @@ static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface,
EnterCriticalSection(&This->cs); EnterCriticalSection(&This->cs);
for (x = 0; x < This->nFilters; ++x) for (x = 0; x < This->nFilters; ++x)
{ {
BOOL renderer = TRUE;
IEnumPins *enumpins = NULL; IEnumPins *enumpins = NULL;
IPin *pin = NULL; IPin *pin = NULL;
@ -1105,46 +1178,43 @@ static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface,
IEnumPins_Reset(enumpins); IEnumPins_Reset(enumpins);
while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK) while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
{ {
IPin *to = NULL;
PIN_DIRECTION dir = PINDIR_OUTPUT; PIN_DIRECTION dir = PINDIR_OUTPUT;
IPin_QueryDirection(pin, &dir); IPin_QueryDirection(pin, &dir);
IPin_Release(pin);
pin = NULL;
if (dir != PINDIR_INPUT) if (dir != PINDIR_INPUT)
{ {
renderer = FALSE; IPin_Release(pin);
break; continue;
} }
}
IEnumPins_Reset(enumpins);
if (renderer == TRUE)
{
while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
{
IPin *to = NULL;
IPin_ConnectedTo(pin, &to); IPin_ConnectedTo(pin, &to);
if (to == NULL) if (to == NULL)
{ {
hr = IFilterGraph2_Connect(iface, ppinOut, pin); hr = IPin_Connect(ppinOut, pin, NULL);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
TRACE("Connected succesfully %p/%p, %08x look if we should render more!\n", ppinOut, pin, hr);
IPin_Release(pin); IPin_Release(pin);
hr = FilterGraph2_RenderRecurse(This, pin);
if (FAILED(hr))
{
IPin_Disconnect(ppinOut);
IPin_Disconnect(pin);
continue;
}
IEnumPins_Release(enumpins); IEnumPins_Release(enumpins);
LeaveCriticalSection(&This->cs); LeaveCriticalSection(&This->cs);
ERR("Connected succesfully\n");
return hr; return hr;
} }
WARN("Could not connect!\n");
} }
else else
IPin_Release(to); IPin_Release(to);
IPin_Release(pin); IPin_Release(pin);
} }
}
IEnumPins_Release(enumpins); IEnumPins_Release(enumpins);
} }
@ -1152,34 +1222,60 @@ static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface,
hr = IPin_EnumMediaTypes(ppinOut, &penummt); hr = IPin_EnumMediaTypes(ppinOut, &penummt);
if (FAILED(hr)) { if (FAILED(hr)) {
ERR("EnumMediaTypes (%x)\n", hr); WARN("EnumMediaTypes (%x)\n", hr);
return hr; return hr;
} }
IEnumMediaTypes_Reset(penummt); 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); hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
if (FAILED(hr)) { if (FAILED(hr)) {
ERR("IEnumMediaTypes_Next (%x)\n", hr); WARN("IEnumMediaTypes_Next (%x)\n", hr);
return hr;
}
if (!nbmt)
break; break;
}
if (!nbmt && !final)
{
final = TRUE;
tab[0] = tab[1] = GUID_NULL;
IEnumMediaTypes_Reset(penummt);
continue;
}
else if (!nbmt)
{
hr = VFW_E_CANNOT_RENDER;
break;
}
else
{
TRACE("MajorType %s\n", debugstr_guid(&mt->majortype)); TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
TRACE("SubType %s\n", debugstr_guid(&mt->subtype)); TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
/* Try to find a suitable renderer with the same media type */ /* Only enumerate once, this doesn't account for all previous ones, but this should be enough nonetheless */
tab[0] = mt->majortype; if (IsEqualIID(&tab[0], &mt->majortype) && IsEqualIID(&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); DeleteMediaType(mt);
if (FAILED(hr)) { continue;
ERR("Unable to enum filters (%x)\n", hr);
return hr;
} }
while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK) /* 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)
{ {
VARIANT var; VARIANT var;
GUID clsid; GUID clsid;
@ -1191,19 +1287,20 @@ static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface,
hr = GetFilterInfo(pMoniker, &clsid, &var); hr = GetFilterInfo(pMoniker, &clsid, &var);
IMoniker_Release(pMoniker); IMoniker_Release(pMoniker);
if (FAILED(hr)) { if (FAILED(hr)) {
ERR("Unable to retrieve filter info (%x)\n", hr); WARN("Unable to retrieve filter info (%x)\n", hr);
goto error; goto error;
} }
hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pfilter); hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pfilter);
if (FAILED(hr)) { if (FAILED(hr))
ERR("Unable to create filter (%x), trying next one\n", hr); {
WARN("Unable to create filter (%x), trying next one\n", hr);
goto error; goto error;
} }
hr = IFilterGraph2_AddFilter(iface, pfilter, V_UNION(&var, bstrVal)); hr = IFilterGraph2_AddFilter(iface, pfilter, V_UNION(&var, bstrVal));
if (FAILED(hr)) { if (FAILED(hr)) {
ERR("Unable to add filter (%x)\n", hr); WARN("Unable to add filter (%x)\n", hr);
IBaseFilter_Release(pfilter); IBaseFilter_Release(pfilter);
pfilter = NULL; pfilter = NULL;
goto error; goto error;
@ -1211,30 +1308,36 @@ static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface,
hr = IBaseFilter_EnumPins(pfilter, &penumpins); hr = IBaseFilter_EnumPins(pfilter, &penumpins);
if (FAILED(hr)) { if (FAILED(hr)) {
ERR("Splitter Enumpins (%x)\n", hr); WARN("Splitter Enumpins (%x)\n", hr);
goto error; goto error;
} }
hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin); hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin);
IEnumPins_Release(penumpins); IEnumPins_Release(penumpins);
if (FAILED(hr)) { if (FAILED(hr)) {
ERR("Next (%x)\n", hr); WARN("Next (%x)\n", hr);
goto error; goto error;
} }
if (pin == 0) { if (pin == 0) {
ERR("No Pin\n"); WARN("No Pin\n");
hr = E_FAIL;
goto error; goto error;
} }
/* Connect the pin to render to the renderer */ /* Connect the pin to the "Renderer" */
hr = IFilterGraph2_Connect(iface, ppinOut, ppinfilter); hr = IPin_Connect(ppinOut, ppinfilter, NULL);
if (FAILED(hr)) {
TRACE("Unable to connect to renderer (%x)\n", hr);
IPin_Release(ppinfilter); IPin_Release(ppinfilter);
if (FAILED(hr)) {
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; goto error;
} }
IPin_Release(ppinfilter);
IBaseFilter_Release(pfilter); IBaseFilter_Release(pfilter);
pfilter = NULL;
break; break;
error: error:
@ -1242,37 +1345,32 @@ error:
IFilterGraph2_RemoveFilter(iface, pfilter); IFilterGraph2_RemoveFilter(iface, pfilter);
IBaseFilter_Release(pfilter); IBaseFilter_Release(pfilter);
} }
if (!FAILED(hr)) DebugBreak();
} }
if (nbmt)
DeleteMediaType(mt); DeleteMediaType(mt);
if (SUCCEEDED(hr))
break; break;
hr = S_OK;
} }
IEnumMediaTypes_Release(penummt); IEnumMediaTypes_Release(penummt);
return hr;
return S_OK;
} }
static HRESULT WINAPI FilterGraph2_RenderFile(IFilterGraph2 *iface, static HRESULT WINAPI FilterGraph2_RenderFile(IFilterGraph2 *iface,
LPCWSTR lpcwstrFile, LPCWSTR lpcwstrFile,
LPCWSTR lpcwstrPlayList) { LPCWSTR lpcwstrPlayList)
{
ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface); ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
static const WCHAR string[] = {'R','e','a','d','e','r',0}; static const WCHAR string[] = {'R','e','a','d','e','r',0};
IBaseFilter* preader = NULL; IBaseFilter* preader = NULL;
IBaseFilter* psplitter = NULL;
IPin* ppinreader = NULL; IPin* ppinreader = NULL;
IPin* ppinsplitter = NULL; IEnumPins* penumpins = NULL;
IEnumPins* penumpins;
ULONG pin;
HRESULT hr; HRESULT hr;
IEnumMoniker* pEnumMoniker = NULL; BOOL partial = FALSE;
GUID tab[2]; HRESULT any = FALSE;
IPin** ppins = NULL;
ULONG nb;
IMoniker* pMoniker;
IFileSourceFilter* pfile = NULL;
AM_MEDIA_TYPE mt;
WCHAR* filename;
TRACE("(%p/%p)->(%s, %s)\n", This, iface, debugstr_w(lpcwstrFile), debugstr_w(lpcwstrPlayList)); 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; return E_INVALIDARG;
hr = IFilterGraph2_AddSourceFilter(iface, lpcwstrFile, string, &preader); hr = IFilterGraph2_AddSourceFilter(iface, lpcwstrFile, string, &preader);
if (FAILED(hr))
/* Retrieve file media type */ return hr;
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)) if (SUCCEEDED(hr))
hr = IBaseFilter_EnumPins(preader, &penumpins); hr = IBaseFilter_EnumPins(preader, &penumpins);
if (SUCCEEDED(hr)) { 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) while (IEnumPins_Next(penumpins, 1, &ppinreader, NULL) == S_OK)
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)
{ {
VARIANT var; PIN_DIRECTION dir;
GUID clsid;
hr = GetFilterInfo(pMoniker, &clsid, &var); IPin_QueryDirection(ppinreader, &dir);
IMoniker_Release(pMoniker); if (dir == PINDIR_OUTPUT)
if (FAILED(hr)) { {
ERR("Unable to retrieve filter info (%x)\n", hr); INT i;
continue;
}
hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&psplitter); hr = IFilterGraph2_Render(iface, ppinreader);
if (FAILED(hr)) { ERR("Render %08x\n", hr);
ERR("Unable to create filter (%x), trying next one\n", hr);
continue;
}
hr = IFilterGraph2_AddFilter(iface, psplitter, V_UNION(&var, bstrVal)); for (i = 0; i < This->nFilters; ++i)
if (FAILED(hr)) { FIXME("Filters in chain: %s\n", debugstr_w(This->pFilterNames[i]));
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)) if (SUCCEEDED(hr))
hr = IPin_Connect(ppinreader, ppinsplitter, NULL); any = TRUE;
if (hr != S_OK)
/* Make sure there's some output pins in the filter */ partial = TRUE;
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;
if (SUCCEEDED(hr)) {
TRACE("Successfully connected to filter\n");
break;
}
TRACE("Cannot connect to filter (%x), trying next one\n", hr);
if (ppins) {
CoTaskMemFree(ppins);
ppins = NULL;
}
IFilterGraph2_RemoveFilter(iface, psplitter);
IBaseFilter_Release(psplitter);
psplitter = NULL;
}
/* 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;
}
IPin_Release(ppins[i]);
}
CoTaskMemFree(ppins);
hr = (partial ? VFW_S_PARTIAL_RENDER : S_OK);
}
IPin_Release(ppinreader); IPin_Release(ppinreader);
IBaseFilter_Release(preader); }
if (psplitter) IEnumPins_Release(penumpins);
IBaseFilter_Release(psplitter);
if (!any)
hr = VFW_E_CANNOT_RENDER;
else if (partial)
hr = VFW_S_PARTIAL_RENDER;
else
hr = S_OK;
}
IBaseFilter_Release(preader);
TRACE("--> %08x\n", hr);
return 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); ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
int i; int i;
IBaseFilter* pfilter; IBaseFilter* pfilter;