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:
parent
46f4c4b4d8
commit
0d1eea691c
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue