quartz: Make FilterGraph_Connect and ConnectDirect behave better.

Does some security checks that it won't connect a filter to itself,
and also cleans up after a failed connection attempt.
This commit is contained in:
Maarten Lankhorst 2008-06-26 11:13:53 -07:00 committed by Alexandre Julliard
parent 46f4c4b4d8
commit 0d1eea691c
1 changed files with 156 additions and 27 deletions

View File

@ -558,6 +558,83 @@ static HRESULT WINAPI FilterGraph2_FindFilterByName(IFilterGraph2 *iface,
return VFW_E_NOT_FOUND; return VFW_E_NOT_FOUND;
} }
/* Don't allow a circular connection to form, return VFW_E_CIRCULAR_GRAPH if this would be the case.
* A circular connection will be formed if from the filter of the output pin, the input pin can be reached
*/
static HRESULT WINAPI CheckCircularConnection(IFilterGraphImpl *This, IPin *out, IPin *in)
{
#if 1
HRESULT hr;
PIN_INFO info_out, info_in;
hr = IPin_QueryPinInfo(out, &info_out);
if (FAILED(hr))
return hr;
if (info_out.dir != PINDIR_OUTPUT)
{
IBaseFilter_Release(info_out.pFilter);
return E_UNEXPECTED;
}
hr = IPin_QueryPinInfo(in, &info_in);
if (SUCCEEDED(hr))
IBaseFilter_Release(info_in.pFilter);
if (FAILED(hr))
goto out;
if (info_in.dir != PINDIR_INPUT)
{
hr = E_UNEXPECTED;
goto out;
}
if (info_out.pFilter == info_in.pFilter)
hr = VFW_E_CIRCULAR_GRAPH;
else
{
IEnumPins *enumpins;
IPin *test;
hr = IBaseFilter_EnumPins(info_out.pFilter, &enumpins);
if (FAILED(hr))
goto out;
IEnumPins_Reset(enumpins);
while ((hr = IEnumPins_Next(enumpins, 1, &test, NULL)) == S_OK)
{
PIN_DIRECTION dir = PINDIR_OUTPUT;
IPin_QueryDirection(test, &dir);
if (dir == PINDIR_INPUT)
{
IPin *victim = NULL;
IPin_ConnectedTo(test, &victim);
if (victim)
{
hr = CheckCircularConnection(This, victim, in);
IPin_Release(victim);
if (FAILED(hr))
{
IPin_Release(test);
break;
}
}
}
IPin_Release(test);
}
IEnumPins_Release(enumpins);
}
out:
IBaseFilter_Release(info_out.pFilter);
if (FAILED(hr))
ERR("Checking filtergraph returned %08x, something's not right!\n", hr);
return hr;
#else
/* Debugging filtergraphs not enabled */
return S_OK;
#endif
}
/* NOTE: despite the implication, it doesn't matter which /* NOTE: despite the implication, it doesn't matter which
* way round you put in the input and output pins */ * way round you put in the input and output pins */
static HRESULT WINAPI FilterGraph2_ConnectDirect(IFilterGraph2 *iface, static HRESULT WINAPI FilterGraph2_ConnectDirect(IFilterGraph2 *iface,
@ -596,10 +673,18 @@ static HRESULT WINAPI FilterGraph2_ConnectDirect(IFilterGraph2 *iface,
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
if (dir == PINDIR_INPUT) if (dir == PINDIR_INPUT)
{
hr = CheckCircularConnection(This, ppinOut, ppinIn);
if (SUCCEEDED(hr))
hr = IPin_Connect(ppinOut, ppinIn, pmt); hr = IPin_Connect(ppinOut, ppinIn, pmt);
}
else else
{
hr = CheckCircularConnection(This, ppinIn, ppinOut);
if (SUCCEEDED(hr))
hr = IPin_Connect(ppinIn, ppinOut, pmt); hr = IPin_Connect(ppinIn, ppinOut, pmt);
} }
}
return hr; return hr;
} }
@ -630,8 +715,8 @@ static HRESULT WINAPI FilterGraph2_Reconnect(IFilterGraph2 *iface,
return hr; return hr;
} }
static HRESULT WINAPI FilterGraph2_Disconnect(IFilterGraph2 *iface, static HRESULT WINAPI FilterGraph2_Disconnect(IFilterGraph2 *iface, IPin *ppin)
IPin *ppin) { {
ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface); ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
TRACE("(%p/%p)->(%p)\n", This, iface, ppin); TRACE("(%p/%p)->(%p)\n", This, iface, ppin);
@ -750,9 +835,8 @@ static HRESULT GetInternalConnections(IBaseFilter* pfilter, IPin* pinputpin, IPi
} }
/*** IGraphBuilder methods ***/ /*** IGraphBuilder methods ***/
static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *ppinOut, IPin *ppinIn)
IPin *ppinOut, {
IPin *ppinIn) {
ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface); ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
HRESULT hr; HRESULT hr;
AM_MEDIA_TYPE* mt; AM_MEDIA_TYPE* mt;
@ -766,6 +850,7 @@ static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface,
ULONG pin; ULONG pin;
PIN_INFO PinInfo; PIN_INFO PinInfo;
CLSID FilterCLSID; CLSID FilterCLSID;
PIN_DIRECTION dir;
TRACE("(%p/%p)->(%p, %p)\n", This, iface, ppinOut, ppinIn); TRACE("(%p/%p)->(%p, %p)\n", This, iface, ppinOut, ppinIn);
@ -786,12 +871,29 @@ static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface,
IBaseFilter_Release(PinInfo.pFilter); IBaseFilter_Release(PinInfo.pFilter);
} }
hr = IPin_QueryDirection(ppinOut, &dir);
if (FAILED(hr))
return hr;
if (dir == PINDIR_INPUT)
{
IPin *temp;
temp = ppinIn;
ppinIn = ppinOut;
ppinOut = temp;
}
hr = CheckCircularConnection(This, ppinOut, ppinIn);
if (FAILED(hr))
return hr;
/* Try direct connection first */ /* Try direct connection first */
hr = IPin_Connect(ppinOut, ppinIn, NULL); hr = IPin_Connect(ppinOut, ppinIn, NULL);
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
return S_OK; return S_OK;
} }
TRACE("Direct connection failed, trying to insert other filters\n"); TRACE("Direct connection failed, trying to render using extra filters\n");
hr = IPin_QueryPinInfo(ppinIn, &PinInfo); hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
if (FAILED(hr)) if (FAILED(hr))
@ -806,18 +908,19 @@ static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface,
* filter to the minor mediatype of input pin of the renderer */ * filter to the minor mediatype of input pin of the renderer */
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;
} }
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; return hr;
} }
if (!nbmt) { if (!nbmt)
ERR("No media type found!\n"); {
WARN("No media type found!\n");
return S_OK; return S_OK;
} }
TRACE("MajorType %s\n", debugstr_guid(&mt->majortype)); TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
@ -828,10 +931,11 @@ static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface,
tab[1] = mt->subtype; 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); 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 (FAILED(hr)) {
ERR("Unable to enum filters (%x)\n", hr); WARN("Unable to enum filters (%x)\n", hr);
return hr; return hr;
} }
hr = VFW_E_CANNOT_RENDER;
while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK) while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
{ {
VARIANT var; VARIANT var;
@ -843,7 +947,7 @@ static HRESULT WINAPI FilterGraph2_Connect(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;
} }
@ -854,13 +958,13 @@ static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface,
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;
@ -868,7 +972,7 @@ static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface,
hr = IBaseFilter_EnumPins(pfilter, &penumpins); hr = IBaseFilter_EnumPins(pfilter, &penumpins);
if (FAILED(hr)) { if (FAILED(hr)) {
ERR("Enumpins (%x)\n", hr); WARN("Enumpins (%x)\n", hr);
goto error; goto error;
} }
@ -876,11 +980,11 @@ static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface,
IEnumPins_Release(penumpins); IEnumPins_Release(penumpins);
if (FAILED(hr)) { if (FAILED(hr)) {
ERR("Next (%x)\n", hr); WARN("Obtaining next pin: (%x)\n", hr);
goto error; goto error;
} }
if (pin == 0) { if (pin == 0) {
ERR("No Pin\n"); WARN("Cannot use this filter: no pins\n");
goto error; goto error;
} }
@ -891,21 +995,38 @@ static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface,
} }
TRACE("Successfully connected to filter, follow chain...\n"); TRACE("Successfully connected to filter, follow chain...\n");
/* Render all output pins of the filter by calling IFilterGraph2_Render on each of them */ /* Render all output pins of the filter by calling IFilterGraph2_Connect on each of them */
hr = GetInternalConnections(pfilter, ppinfilter, &ppins, &nb); hr = GetInternalConnections(pfilter, ppinfilter, &ppins, &nb);
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
int i; int i;
if (nb == 0) { if (nb == 0) {
IPin_Disconnect(ppinfilter);
IPin_Disconnect(ppinOut); IPin_Disconnect(ppinOut);
goto error; goto error;
} }
TRACE("pins to consider: %d\n", nb); TRACE("pins to consider: %d\n", nb);
for(i = 0; i < nb; i++) { for(i = 0; i < nb; i++)
{
LPWSTR pinname = NULL;
TRACE("Processing pin %d\n", i); TRACE("Processing pin %d\n", i);
hr = IPin_QueryId(ppins[i], &pinname);
if (SUCCEEDED(hr))
{
if (pinname[0] == '~')
{
TRACE("Pinname=%s, skipping\n", debugstr_w(pinname));
hr = E_FAIL;
}
else
hr = IFilterGraph2_Connect(iface, ppins[i], ppinIn); hr = IFilterGraph2_Connect(iface, ppins[i], ppinIn);
CoTaskMemFree(pinname);
}
if (FAILED(hr)) { if (FAILED(hr)) {
TRACE("Cannot render pin %p (%x)\n", ppinfilter, hr); TRACE("Cannot connect pin %p (%x)\n", ppinfilter, hr);
} }
IPin_Release(ppins[i]); IPin_Release(ppins[i]);
if (SUCCEEDED(hr)) break; if (SUCCEEDED(hr)) break;
@ -914,6 +1035,13 @@ static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface,
CoTaskMemFree(ppins); CoTaskMemFree(ppins);
IPin_Release(ppinfilter); IPin_Release(ppinfilter);
IBaseFilter_Release(pfilter); IBaseFilter_Release(pfilter);
if (FAILED(hr))
{
IPin_Disconnect(ppinfilter);
IPin_Disconnect(ppinOut);
IFilterGraph2_RemoveFilter(iface, pfilter);
continue;
}
break; break;
} }
@ -928,7 +1056,8 @@ error:
IEnumMediaTypes_Release(penummt); IEnumMediaTypes_Release(penummt);
DeleteMediaType(mt); DeleteMediaType(mt);
return S_OK; TRACE("--> %08x\n", hr);
return SUCCEEDED(hr) ? S_OK : hr;
} }
static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface,