diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c index b82cbcd5800..19dbb8cbfc5 100644 --- a/dlls/quartz/filtergraph.c +++ b/dlls/quartz/filtergraph.c @@ -176,6 +176,7 @@ typedef struct _IFilterGraphImpl { /* IVideoFrameStep */ LONG ref; + IUnknown *punkFilterMapper2; IFilterMapper2 * pFilterMapper2; IBaseFilter ** ppFiltersInGraph; LPWSTR * pFilterNames; @@ -260,6 +261,12 @@ static HRESULT WINAPI FilterGraphInner_QueryInterface(IUnknown * iface, } else if (IsEqualGUID(&IID_IMediaPosition, riid)) { *ppvObj = &(This->IMediaPosition_vtbl); TRACE(" returning IMediaPosition interface (%p)\n", *ppvObj); + } else if (IsEqualGUID(&IID_IFilterMapper, riid)) { + TRACE(" requesting IFilterMapper interface from aggregated filtermapper (%p)\n", *ppvObj); + return IUnknown_QueryInterface(This->punkFilterMapper2, riid, ppvObj); + } else if (IsEqualGUID(&IID_IFilterMapper2, riid)) { + *ppvObj = This->pFilterMapper2; + TRACE(" returning IFilterMapper2 interface from aggregated filtermapper (%p)\n", *ppvObj); } else { *ppvObj = NULL; FIXME("unknown interface %s\n", debugstr_guid(riid)); @@ -289,6 +296,8 @@ static ULONG WINAPI FilterGraphInner_Release(IUnknown * iface) if (ref == 0) { int i; + This->ref = 1; /* guard against reentrancy (aggregation). */ + IMediaControl_Stop((IMediaControl*)&(This->IMediaControl_vtbl)); while (This->nFilters) @@ -302,7 +311,19 @@ static ULONG WINAPI FilterGraphInner_Release(IUnknown * iface) if (This->ItfCacheEntries[i].iface) IUnknown_Release(This->ItfCacheEntries[i].iface); } - IFilterMapper2_Release(This->pFilterMapper2); + + /* AddRef on controlling IUnknown, to compensate for Release of cached IFilterMapper2 interface below. + + * NOTE: Filtergraph_AddRef isn't suitable, because bUnkOuterValid may be FALSE but punkOuter non-NULL + * and already passed as punkOuter to filtermapper in FilterGraph_create - this will happen in case of + * CoCreateInstance of filtergraph with non-null pUnkOuter and REFIID other than IID_Unknown that is + * cleaning up after error. */ + if (This->pUnkOuter) IUnknown_AddRef(This->pUnkOuter); + else IUnknown_AddRef((IUnknown*)&This->IInner_vtbl); + + IFilterMapper2_Release(This->pFilterMapper2); + IUnknown_Release(This->punkFilterMapper2); + CloseHandle(This->hEventCompletion); EventsQueue_Destroy(&This->evqueue); This->cs.DebugInfo->Spare[0] = 0; @@ -5394,11 +5415,31 @@ HRESULT FilterGraph_create(IUnknown *pUnkOuter, LPVOID *ppObj) memcpy(&fimpl->timeformatseek, &TIME_FORMAT_MEDIA_TIME, sizeof(GUID)); fimpl->start_time = fimpl->position = 0; fimpl->stop_position = -1; + fimpl->punkFilterMapper2 = NULL; + + /* create Filtermapper aggregated. */ + hr = CoCreateInstance(&CLSID_FilterMapper2, pUnkOuter ? pUnkOuter : (IUnknown*)&fimpl->IInner_vtbl, CLSCTX_INPROC_SERVER, + &IID_IUnknown, (LPVOID*)&fimpl->punkFilterMapper2); + + if (SUCCEEDED(hr)) { + hr = IUnknown_QueryInterface(fimpl->punkFilterMapper2, &IID_IFilterMapper2, (LPVOID*)&fimpl->pFilterMapper2); + } + + if (SUCCEEDED(hr)) { + /* Release controlling IUnknown - compensate refcount increase from caching IFilterMapper2 interface. */ + if (pUnkOuter) IUnknown_Release(pUnkOuter); + else IUnknown_Release((IUnknown*)&fimpl->IInner_vtbl); + } - hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&fimpl->pFilterMapper2); if (FAILED(hr)) { ERR("Unable to create filter mapper (%x)\n", hr); - return hr; + if (fimpl->punkFilterMapper2) IUnknown_Release(fimpl->punkFilterMapper2); + CloseHandle(fimpl->hEventCompletion); + EventsQueue_Destroy(&fimpl->evqueue); + fimpl->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&fimpl->cs); + CoTaskMemFree(fimpl); + return hr; } IFilterGraph2_SetDefaultSyncSource((IFilterGraph2*)fimpl);