quartz: Combine IGraphBuilder::Render() and IGraphBuilder::Connect() into a single helper.
Signed-off-by: Zebediah Figura <z.figura12@gmail.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
2ddc3e4758
commit
c603a5bfbc
|
@ -207,7 +207,6 @@ typedef struct _IFilterGraphImpl {
|
||||||
int nItfCacheEntries;
|
int nItfCacheEntries;
|
||||||
BOOL defaultclock;
|
BOOL defaultclock;
|
||||||
GUID timeformatseek;
|
GUID timeformatseek;
|
||||||
LONG recursioncount;
|
|
||||||
IUnknown *pSite;
|
IUnknown *pSite;
|
||||||
LONG version;
|
LONG version;
|
||||||
|
|
||||||
|
@ -1059,27 +1058,6 @@ static HRESULT WINAPI FilterGraph2_SetDefaultSyncSource(IFilterGraph2 *iface)
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT GetFilterInfo(IMoniker* pMoniker, VARIANT* pvar)
|
|
||||||
{
|
|
||||||
IPropertyBag * pPropBagCat = NULL;
|
|
||||||
HRESULT hr;
|
|
||||||
|
|
||||||
VariantInit(pvar);
|
|
||||||
|
|
||||||
hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBagCat);
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
hr = IPropertyBag_Read(pPropBagCat, L"FriendlyName", pvar, NULL);
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
TRACE("Moniker = %s\n", debugstr_w(V_BSTR(pvar)));
|
|
||||||
|
|
||||||
if (pPropBagCat)
|
|
||||||
IPropertyBag_Release(pPropBagCat);
|
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct filter_create_params
|
struct filter_create_params
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
@ -1141,98 +1119,256 @@ static HRESULT create_filter(IFilterGraphImpl *graph, IMoniker *moniker, IBaseFi
|
||||||
return IMoniker_BindToObject(moniker, NULL, NULL, &IID_IBaseFilter, (void **)filter);
|
return IMoniker_BindToObject(moniker, NULL, NULL, &IID_IBaseFilter, (void **)filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Attempt to connect one of the output pins on filter to sink. Helper for
|
static HRESULT autoplug(IFilterGraphImpl *graph, IPin *source, IPin *sink, unsigned int recursion_depth);
|
||||||
* FilterGraph2_Connect(). */
|
|
||||||
static HRESULT connect_output_pin(IFilterGraphImpl *graph, IBaseFilter *filter, IPin *sink)
|
static HRESULT autoplug_through_sink(IFilterGraphImpl *graph, IPin *source,
|
||||||
|
IBaseFilter *filter, IPin *middle_sink, IPin *sink, unsigned int recursion_depth)
|
||||||
{
|
{
|
||||||
IEnumPins *enumpins;
|
BOOL any = FALSE, all = TRUE;
|
||||||
|
IPin *middle_source, *peer;
|
||||||
|
IEnumPins *source_enum;
|
||||||
|
PIN_DIRECTION dir;
|
||||||
PIN_INFO info;
|
PIN_INFO info;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
IPin *pin;
|
|
||||||
|
|
||||||
hr = IBaseFilter_EnumPins(filter, &enumpins);
|
TRACE("Trying to autoplug %p to %p through %p.\n", source, sink, middle_sink);
|
||||||
if (FAILED(hr))
|
|
||||||
return hr;
|
|
||||||
|
|
||||||
while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
|
IPin_QueryDirection(middle_sink, &dir);
|
||||||
|
if (dir != PINDIR_INPUT)
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
if (IPin_ConnectedTo(middle_sink, &peer) == S_OK)
|
||||||
{
|
{
|
||||||
IPin_QueryPinInfo(pin, &info);
|
IPin_Release(peer);
|
||||||
IBaseFilter_Release(info.pFilter);
|
return E_FAIL;
|
||||||
if (info.dir == PINDIR_OUTPUT)
|
|
||||||
{
|
|
||||||
if (info.achName[0] == '~')
|
|
||||||
{
|
|
||||||
TRACE("Skipping non-rendered pin %s.\n", debugstr_w(info.achName));
|
|
||||||
IPin_Release(pin);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(IFilterGraph2_Connect(&graph->IFilterGraph2_iface, pin, sink)))
|
|
||||||
{
|
|
||||||
IPin_Release(pin);
|
|
||||||
IEnumPins_Release(enumpins);
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IPin_Release(pin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumPins_Release(enumpins);
|
if (FAILED(hr = IFilterGraph2_ConnectDirect(&graph->IFilterGraph2_iface, source, middle_sink, NULL)))
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
if (FAILED(hr = IBaseFilter_EnumPins(filter, &source_enum)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
while (IEnumPins_Next(source_enum, 1, &middle_source, NULL) == S_OK)
|
||||||
|
{
|
||||||
|
IPin_QueryPinInfo(middle_source, &info);
|
||||||
|
IBaseFilter_Release(info.pFilter);
|
||||||
|
if (info.dir != PINDIR_OUTPUT)
|
||||||
|
{
|
||||||
|
IPin_Release(middle_source);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (info.achName[0] == '~')
|
||||||
|
{
|
||||||
|
TRACE("Skipping non-rendered pin %s.\n", debugstr_w(info.achName));
|
||||||
|
IPin_Release(middle_source);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (IPin_ConnectedTo(middle_source, &peer) == S_OK)
|
||||||
|
{
|
||||||
|
IPin_Release(peer);
|
||||||
|
IPin_Release(middle_source);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = autoplug(graph, middle_source, sink, recursion_depth + 1);
|
||||||
|
IPin_Release(middle_source);
|
||||||
|
if (SUCCEEDED(hr) && sink)
|
||||||
|
{
|
||||||
|
IEnumPins_Release(source_enum);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
any = TRUE;
|
||||||
|
if (hr != S_OK)
|
||||||
|
all = FALSE;
|
||||||
|
}
|
||||||
|
IEnumPins_Release(source_enum);
|
||||||
|
|
||||||
|
if (!sink)
|
||||||
|
{
|
||||||
|
if (all)
|
||||||
|
return S_OK;
|
||||||
|
if (any)
|
||||||
|
return VFW_S_PARTIAL_RENDER;
|
||||||
|
}
|
||||||
|
|
||||||
|
err:
|
||||||
|
IFilterGraph2_Disconnect(&graph->IFilterGraph2_iface, source);
|
||||||
|
IFilterGraph2_Disconnect(&graph->IFilterGraph2_iface, middle_sink);
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT autoplug_through_filter(IFilterGraphImpl *graph, IPin *source,
|
||||||
|
IBaseFilter *filter, IPin *sink, unsigned int recursion_depth)
|
||||||
|
{
|
||||||
|
IEnumPins *sink_enum;
|
||||||
|
IPin *filter_sink;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
TRACE("Trying to autoplug %p to %p through %p.\n", source, sink, filter);
|
||||||
|
|
||||||
|
if (FAILED(hr = IBaseFilter_EnumPins(filter, &sink_enum)))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
while (IEnumPins_Next(sink_enum, 1, &filter_sink, NULL) == S_OK)
|
||||||
|
{
|
||||||
|
hr = autoplug_through_sink(graph, source, filter, filter_sink, sink, recursion_depth);
|
||||||
|
IPin_Release(filter_sink);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
IEnumPins_Release(sink_enum);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IEnumPins_Release(sink_enum);
|
||||||
return VFW_E_CANNOT_CONNECT;
|
return VFW_E_CANNOT_CONNECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** IGraphBuilder methods ***/
|
/* Common helper for IGraphBuilder::Connect() and IGraphBuilder::Render(), which
|
||||||
static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *ppinOut, IPin *ppinIn)
|
* share most of the same code. Render() calls this with a NULL sink. */
|
||||||
|
static HRESULT autoplug(IFilterGraphImpl *graph, IPin *source, IPin *sink, unsigned int recursion_depth)
|
||||||
{
|
{
|
||||||
IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
|
IAMGraphBuilderCallback *callback = NULL;
|
||||||
|
IEnumMediaTypes *enummt;
|
||||||
|
IFilterMapper2 *mapper;
|
||||||
struct filter *filter;
|
struct filter *filter;
|
||||||
|
AM_MEDIA_TYPE *mt;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
IPin *pin;
|
|
||||||
AM_MEDIA_TYPE* mt = NULL;
|
TRACE("Trying to autoplug %p to %p, recursion depth %u.\n", source, sink, recursion_depth);
|
||||||
IEnumMediaTypes* penummt = NULL;
|
|
||||||
ULONG nbmt;
|
if (recursion_depth >= 5)
|
||||||
IEnumPins* penumpins;
|
{
|
||||||
IEnumMoniker* pEnumMoniker;
|
WARN("Recursion depth has reached 5; aborting.\n");
|
||||||
GUID tab[2];
|
return VFW_E_CANNOT_CONNECT;
|
||||||
IMoniker* pMoniker;
|
}
|
||||||
PIN_INFO PinInfo;
|
|
||||||
|
if (sink)
|
||||||
|
{
|
||||||
|
/* Try to connect directly to this sink. */
|
||||||
|
hr = IFilterGraph2_ConnectDirect(&graph->IFilterGraph2_iface, source, sink, NULL);
|
||||||
|
|
||||||
|
/* If direct connection succeeded, we should propagate that return value.
|
||||||
|
* If it returned VFW_E_NOT_CONNECTED or VFW_E_NO_AUDIO_HARDWARE, then don't
|
||||||
|
* even bother trying intermediate filters, since they won't succeed. */
|
||||||
|
if (SUCCEEDED(hr) || hr == VFW_E_NOT_CONNECTED || hr == VFW_E_NO_AUDIO_HARDWARE)
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Always prefer filters in the graph. */
|
||||||
|
LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
|
||||||
|
{
|
||||||
|
if (SUCCEEDED(hr = autoplug_through_filter(graph, source, filter->filter, sink, recursion_depth)))
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
IUnknown_QueryInterface(graph->punkFilterMapper2, &IID_IFilterMapper2, (void **)&mapper);
|
||||||
|
|
||||||
|
if (FAILED(hr = IPin_EnumMediaTypes(source, &enummt)))
|
||||||
|
{
|
||||||
|
IFilterMapper2_Release(mapper);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (graph->pSite)
|
||||||
|
IUnknown_QueryInterface(graph->pSite, &IID_IAMGraphBuilderCallback, (void **)&callback);
|
||||||
|
|
||||||
|
while (IEnumMediaTypes_Next(enummt, 1, &mt, NULL) == S_OK)
|
||||||
|
{
|
||||||
|
GUID types[2] = {mt->majortype, mt->subtype};
|
||||||
|
IEnumMoniker *enummoniker;
|
||||||
|
IBaseFilter *filter;
|
||||||
|
IMoniker *moniker;
|
||||||
|
|
||||||
|
DeleteMediaType(mt);
|
||||||
|
|
||||||
|
if (FAILED(hr = IFilterMapper2_EnumMatchingFilters(mapper, &enummoniker, 0, FALSE,
|
||||||
|
MERIT_UNLIKELY, TRUE, 1, types, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL)))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
while (IEnumMoniker_Next(enummoniker, 1, &moniker, NULL) == S_OK)
|
||||||
|
{
|
||||||
|
IPropertyBag *bag;
|
||||||
|
VARIANT var;
|
||||||
|
|
||||||
|
VariantInit(&var);
|
||||||
|
IMoniker_BindToStorage(moniker, NULL, NULL, &IID_IPropertyBag, (void **)&bag);
|
||||||
|
hr = IPropertyBag_Read(bag, L"FriendlyName", &var, NULL);
|
||||||
|
IPropertyBag_Release(bag);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
IMoniker_Release(moniker);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback && FAILED(hr = IAMGraphBuilderCallback_SelectedFilter(callback, moniker)))
|
||||||
|
{
|
||||||
|
TRACE("Filter rejected by IAMGraphBuilderCallback::SelectedFilter(), hr %#x.\n", hr);
|
||||||
|
IMoniker_Release(moniker);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = create_filter(graph, moniker, &filter);
|
||||||
|
IMoniker_Release(moniker);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
ERR("Failed to create filter for %s, hr %#x.\n", debugstr_w(V_BSTR(&var)), hr);
|
||||||
|
VariantClear(&var);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback && FAILED(hr = IAMGraphBuilderCallback_CreatedFilter(callback, filter)))
|
||||||
|
{
|
||||||
|
TRACE("Filter rejected by IAMGraphBuilderCallback::CreatedFilter(), hr %#x.\n", hr);
|
||||||
|
IBaseFilter_Release(filter);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = IFilterGraph2_AddFilter(&graph->IFilterGraph2_iface, filter, V_BSTR(&var));
|
||||||
|
VariantClear(&var);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
ERR("Failed to add filter, hr %#x.\n", hr);
|
||||||
|
IBaseFilter_Release(filter);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = autoplug_through_filter(graph, source, filter, sink, recursion_depth);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
IBaseFilter_Release(filter);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
IFilterGraph2_RemoveFilter(&graph->IFilterGraph2_iface, filter);
|
||||||
|
IBaseFilter_Release(filter);
|
||||||
|
}
|
||||||
|
IEnumMoniker_Release(enummoniker);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = VFW_E_CANNOT_CONNECT;
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (callback) IAMGraphBuilderCallback_Release(callback);
|
||||||
|
IEnumMediaTypes_Release(enummt);
|
||||||
|
IFilterMapper2_Release(mapper);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *source, IPin *sink)
|
||||||
|
{
|
||||||
|
IFilterGraphImpl *graph = impl_from_IFilterGraph2(iface);
|
||||||
PIN_DIRECTION dir;
|
PIN_DIRECTION dir;
|
||||||
IFilterMapper2 *pFilterMapper2 = NULL;
|
HRESULT hr;
|
||||||
|
|
||||||
TRACE("(%p/%p)->(%p, %p)\n", This, iface, ppinOut, ppinIn);
|
TRACE("graph %p, source %p, sink %p.\n", graph, source, sink);
|
||||||
|
|
||||||
if(!ppinOut || !ppinIn)
|
if (!source || !sink)
|
||||||
return E_POINTER;
|
return E_POINTER;
|
||||||
|
|
||||||
if (TRACE_ON(quartz))
|
if (FAILED(hr = IPin_QueryDirection(source, &dir)))
|
||||||
{
|
return hr;
|
||||||
hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
|
|
||||||
if (FAILED(hr))
|
|
||||||
return hr;
|
|
||||||
|
|
||||||
TRACE("Filter owning ppinIn(%p) => %p\n", ppinIn, PinInfo.pFilter);
|
|
||||||
IBaseFilter_Release(PinInfo.pFilter);
|
|
||||||
|
|
||||||
hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
|
|
||||||
if (FAILED(hr))
|
|
||||||
return hr;
|
|
||||||
|
|
||||||
TRACE("Filter owning ppinOut(%p) => %p\n", ppinOut, PinInfo.pFilter);
|
|
||||||
IBaseFilter_Release(PinInfo.pFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
EnterCriticalSection(&This->cs);
|
|
||||||
++This->recursioncount;
|
|
||||||
if (This->recursioncount >= 5)
|
|
||||||
{
|
|
||||||
WARN("Recursion count has reached %d\n", This->recursioncount);
|
|
||||||
hr = VFW_E_CANNOT_CONNECT;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = IPin_QueryDirection(ppinOut, &dir);
|
|
||||||
if (FAILED(hr))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (dir == PINDIR_INPUT)
|
if (dir == PINDIR_INPUT)
|
||||||
{
|
{
|
||||||
|
@ -1240,522 +1376,35 @@ static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *ppinOut,
|
||||||
|
|
||||||
TRACE("Directions seem backwards, swapping pins\n");
|
TRACE("Directions seem backwards, swapping pins\n");
|
||||||
|
|
||||||
temp = ppinIn;
|
temp = sink;
|
||||||
ppinIn = ppinOut;
|
sink = source;
|
||||||
ppinOut = temp;
|
source = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try direct connection first */
|
EnterCriticalSection(&graph->cs);
|
||||||
hr = IFilterGraph2_ConnectDirect(iface, ppinOut, ppinIn, NULL);
|
|
||||||
|
|
||||||
/* If direct connection succeeded, we should propagate that return value.
|
hr = autoplug(graph, source, sink, 0);
|
||||||
* If it returned VFW_E_NOT_CONNECTED or VFW_E_NO_AUDIO_HARDWARE, then don't
|
|
||||||
* even bother trying intermediate filters, since they won't succeed. */
|
|
||||||
if (SUCCEEDED(hr) || hr == VFW_E_NOT_CONNECTED || hr == VFW_E_NO_AUDIO_HARDWARE)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
TRACE("Direct connection failed, trying to render using extra filters\n");
|
LeaveCriticalSection(&graph->cs);
|
||||||
|
|
||||||
LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry)
|
TRACE("Returning %#x.\n", hr);
|
||||||
{
|
|
||||||
hr = IBaseFilter_EnumPins(filter->filter, &penumpins);
|
|
||||||
if (FAILED(hr))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
while (IEnumPins_Next(penumpins, 1, &pin, NULL) == S_OK)
|
|
||||||
{
|
|
||||||
IPin_QueryDirection(pin, &dir);
|
|
||||||
if (dir == PINDIR_INPUT && SUCCEEDED(IFilterGraph2_ConnectDirect(iface,
|
|
||||||
ppinOut, pin, NULL)))
|
|
||||||
{
|
|
||||||
if (SUCCEEDED(hr = connect_output_pin(This, filter->filter, ppinIn)))
|
|
||||||
{
|
|
||||||
IPin_Release(pin);
|
|
||||||
IEnumPins_Release(penumpins);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
IFilterGraph2_Disconnect(iface, pin);
|
|
||||||
IFilterGraph2_Disconnect(iface, ppinOut);
|
|
||||||
}
|
|
||||||
IPin_Release(pin);
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumPins_Release(penumpins);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the appropriate transform filter than can transform the minor media type of output pin of the upstream
|
|
||||||
* filter to the minor mediatype of input pin of the renderer */
|
|
||||||
hr = IPin_EnumMediaTypes(ppinOut, &penummt);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
WARN("EnumMediaTypes (%x)\n", hr);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
WARN("IEnumMediaTypes_Next (%x)\n", hr);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!nbmt)
|
|
||||||
{
|
|
||||||
WARN("No media type found!\n");
|
|
||||||
hr = VFW_E_INVALIDMEDIATYPE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
|
|
||||||
TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
|
|
||||||
|
|
||||||
hr = IUnknown_QueryInterface(This->punkFilterMapper2, &IID_IFilterMapper2, (void**)&pFilterMapper2);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
WARN("Unable to get IFilterMapper2 (%x)\n", hr);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Try to find a suitable filter that can connect to the pin to render */
|
|
||||||
tab[0] = mt->majortype;
|
|
||||||
tab[1] = mt->subtype;
|
|
||||||
hr = IFilterMapper2_EnumMatchingFilters(pFilterMapper2, &pEnumMoniker, 0, FALSE, MERIT_UNLIKELY, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
WARN("Unable to enum filters (%x)\n", hr);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = VFW_E_CANNOT_RENDER;
|
|
||||||
while (IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, NULL) == S_OK)
|
|
||||||
{
|
|
||||||
VARIANT var;
|
|
||||||
IBaseFilter* pfilter = NULL;
|
|
||||||
IAMGraphBuilderCallback *callback = NULL;
|
|
||||||
|
|
||||||
hr = GetFilterInfo(pMoniker, &var);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
WARN("Unable to retrieve filter info (%x)\n", hr);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = create_filter(This, pMoniker, &pfilter);
|
|
||||||
IMoniker_Release(pMoniker);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
WARN("Unable to create filter (%x), trying next one\n", hr);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (This->pSite)
|
|
||||||
{
|
|
||||||
IUnknown_QueryInterface(This->pSite, &IID_IAMGraphBuilderCallback, (LPVOID*)&callback);
|
|
||||||
if (callback)
|
|
||||||
{
|
|
||||||
HRESULT rc;
|
|
||||||
rc = IAMGraphBuilderCallback_SelectedFilter(callback, pMoniker);
|
|
||||||
if (FAILED(rc))
|
|
||||||
{
|
|
||||||
TRACE("Filter rejected by IAMGraphBuilderCallback_SelectedFilter\n");
|
|
||||||
IAMGraphBuilderCallback_Release(callback);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (callback)
|
|
||||||
{
|
|
||||||
HRESULT rc;
|
|
||||||
rc = IAMGraphBuilderCallback_CreatedFilter(callback, pfilter);
|
|
||||||
IAMGraphBuilderCallback_Release(callback);
|
|
||||||
if (FAILED(rc))
|
|
||||||
{
|
|
||||||
IBaseFilter_Release(pfilter);
|
|
||||||
pfilter = NULL;
|
|
||||||
TRACE("Filter rejected by IAMGraphBuilderCallback_CreatedFilter\n");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = IFilterGraph2_AddFilter(iface, pfilter, V_BSTR(&var));
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
WARN("Unable to add filter (%x)\n", hr);
|
|
||||||
IBaseFilter_Release(pfilter);
|
|
||||||
pfilter = NULL;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
VariantClear(&var);
|
|
||||||
|
|
||||||
hr = IBaseFilter_EnumPins(pfilter, &penumpins);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
WARN("Enumpins (%x)\n", hr);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (IEnumPins_Next(penumpins, 1, &pin, NULL) == S_OK)
|
|
||||||
{
|
|
||||||
if (SUCCEEDED(IFilterGraph2_ConnectDirect(iface, ppinOut, pin, NULL)))
|
|
||||||
{
|
|
||||||
if (SUCCEEDED(hr = connect_output_pin(This, pfilter, ppinIn)))
|
|
||||||
{
|
|
||||||
IPin_Release(pin);
|
|
||||||
IEnumPins_Release(penumpins);
|
|
||||||
IBaseFilter_Release(pfilter);
|
|
||||||
IEnumMoniker_Release(pEnumMoniker);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
IFilterGraph2_Disconnect(iface, pin);
|
|
||||||
IFilterGraph2_Disconnect(iface, ppinOut);
|
|
||||||
}
|
|
||||||
IPin_Release(pin);
|
|
||||||
}
|
|
||||||
IEnumPins_Release(penumpins);
|
|
||||||
|
|
||||||
error:
|
|
||||||
VariantClear(&var);
|
|
||||||
if (pfilter) {
|
|
||||||
IFilterGraph2_RemoveFilter(iface, pfilter);
|
|
||||||
IBaseFilter_Release(pfilter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAILED(hr))
|
|
||||||
hr = VFW_E_CANNOT_CONNECT;
|
|
||||||
|
|
||||||
IEnumMoniker_Release(pEnumMoniker);
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (pFilterMapper2)
|
|
||||||
IFilterMapper2_Release(pFilterMapper2);
|
|
||||||
if (penummt)
|
|
||||||
IEnumMediaTypes_Release(penummt);
|
|
||||||
if (mt)
|
|
||||||
DeleteMediaType(mt);
|
|
||||||
--This->recursioncount;
|
|
||||||
LeaveCriticalSection(&This->cs);
|
|
||||||
TRACE("--> %08x\n", hr);
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Render all output pins of the given filter. Helper for FilterGraph2_Render(). */
|
static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, IPin *source)
|
||||||
static HRESULT render_output_pins(IFilterGraphImpl *graph, IBaseFilter *filter)
|
|
||||||
{
|
{
|
||||||
BOOL renderany = FALSE;
|
IFilterGraphImpl *graph = impl_from_IFilterGraph2(iface);
|
||||||
BOOL renderall = TRUE;
|
|
||||||
IEnumPins *enumpins;
|
|
||||||
IPin *pin, *peer;
|
|
||||||
PIN_INFO info;
|
|
||||||
|
|
||||||
IBaseFilter_EnumPins(filter, &enumpins);
|
|
||||||
while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
|
|
||||||
{
|
|
||||||
IPin_QueryPinInfo(pin, &info);
|
|
||||||
IBaseFilter_Release(info.pFilter);
|
|
||||||
if (info.dir == PINDIR_OUTPUT)
|
|
||||||
{
|
|
||||||
if (info.achName[0] == '~')
|
|
||||||
{
|
|
||||||
TRACE("Skipping non-rendered pin %s.\n", debugstr_w(info.achName));
|
|
||||||
IPin_Release(pin);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IPin_ConnectedTo(pin, &peer) == VFW_E_NOT_CONNECTED)
|
|
||||||
{
|
|
||||||
HRESULT hr;
|
|
||||||
hr = IFilterGraph2_Render(&graph->IFilterGraph2_iface, pin);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
renderany = TRUE;
|
|
||||||
else
|
|
||||||
renderall = FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
IPin_Release(peer);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPin_Release(pin);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
|
|
||||||
IEnumMediaTypes* penummt;
|
|
||||||
struct filter *filter;
|
|
||||||
AM_MEDIA_TYPE* mt;
|
|
||||||
ULONG nbmt;
|
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
IEnumMoniker* pEnumMoniker;
|
TRACE("graph %p, source %p.\n", graph, source);
|
||||||
GUID tab[4];
|
|
||||||
ULONG nb;
|
|
||||||
IMoniker* pMoniker;
|
|
||||||
IFilterMapper2 *pFilterMapper2 = NULL;
|
|
||||||
|
|
||||||
TRACE("(%p/%p)->(%p)\n", This, iface, ppinOut);
|
EnterCriticalSection(&graph->cs);
|
||||||
|
hr = autoplug(graph, source, NULL, 0);
|
||||||
|
LeaveCriticalSection(&graph->cs);
|
||||||
|
if (hr == VFW_E_CANNOT_CONNECT)
|
||||||
|
hr = VFW_E_CANNOT_RENDER;
|
||||||
|
|
||||||
if (TRACE_ON(quartz))
|
TRACE("Returning %#x.\n", hr);
|
||||||
{
|
|
||||||
PIN_INFO PinInfo;
|
|
||||||
|
|
||||||
hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
|
|
||||||
if (FAILED(hr))
|
|
||||||
return hr;
|
|
||||||
|
|
||||||
TRACE("Filter owning pin => %p\n", PinInfo.pFilter);
|
|
||||||
IBaseFilter_Release(PinInfo.pFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Try to find out if there is a renderer for the specified subtype already, and use that
|
|
||||||
*/
|
|
||||||
EnterCriticalSection(&This->cs);
|
|
||||||
LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry)
|
|
||||||
{
|
|
||||||
IEnumPins *enumpins = NULL;
|
|
||||||
IPin *pin = NULL;
|
|
||||||
|
|
||||||
hr = IBaseFilter_EnumPins(filter->filter, &enumpins);
|
|
||||||
|
|
||||||
if (FAILED(hr) || !enumpins)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
IEnumPins_Reset(enumpins);
|
|
||||||
while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
|
|
||||||
{
|
|
||||||
IPin *to = NULL;
|
|
||||||
PIN_DIRECTION dir = PINDIR_OUTPUT;
|
|
||||||
|
|
||||||
IPin_QueryDirection(pin, &dir);
|
|
||||||
if (dir != PINDIR_INPUT)
|
|
||||||
{
|
|
||||||
IPin_Release(pin);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
IPin_ConnectedTo(pin, &to);
|
|
||||||
|
|
||||||
if (to == NULL)
|
|
||||||
{
|
|
||||||
hr = FilterGraph2_ConnectDirect(iface, ppinOut, pin, NULL);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
TRACE("Connected successfully %p/%p, %08x look if we should render more!\n", ppinOut, pin, hr);
|
|
||||||
IPin_Release(pin);
|
|
||||||
|
|
||||||
hr = render_output_pins(This, filter->filter);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
IPin_Disconnect(ppinOut);
|
|
||||||
IPin_Disconnect(pin);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
IEnumPins_Release(enumpins);
|
|
||||||
LeaveCriticalSection(&This->cs);
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
WARN("Could not connect!\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
IPin_Release(to);
|
|
||||||
|
|
||||||
IPin_Release(pin);
|
|
||||||
}
|
|
||||||
IEnumPins_Release(enumpins);
|
|
||||||
}
|
|
||||||
|
|
||||||
LeaveCriticalSection(&This->cs);
|
|
||||||
|
|
||||||
hr = IPin_EnumMediaTypes(ppinOut, &penummt);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
WARN("EnumMediaTypes (%x)\n", hr);
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumMediaTypes_Reset(penummt);
|
|
||||||
|
|
||||||
/* 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)) {
|
|
||||||
WARN("IEnumMediaTypes_Next (%x)\n", hr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!nbmt)
|
|
||||||
{
|
|
||||||
hr = VFW_E_CANNOT_RENDER;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
|
|
||||||
TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
|
|
||||||
|
|
||||||
/* 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[1], &mt->subtype))
|
|
||||||
{
|
|
||||||
DeleteMediaType(mt);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pFilterMapper2 == NULL)
|
|
||||||
{
|
|
||||||
hr = IUnknown_QueryInterface(This->punkFilterMapper2, &IID_IFilterMapper2, (void**)&pFilterMapper2);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
WARN("Unable to query IFilterMapper2 (%x)\n", hr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Try to find a suitable renderer with the same media type */
|
|
||||||
tab[0] = mt->majortype;
|
|
||||||
tab[1] = mt->subtype;
|
|
||||||
hr = IFilterMapper2_EnumMatchingFilters(pFilterMapper2, &pEnumMoniker, 0, FALSE, MERIT_UNLIKELY, TRUE, 1, tab, NULL, NULL, FALSE, 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;
|
|
||||||
IPin* ppinfilter;
|
|
||||||
IBaseFilter* pfilter = NULL;
|
|
||||||
IEnumPins* penumpins = NULL;
|
|
||||||
ULONG pin;
|
|
||||||
|
|
||||||
hr = GetFilterInfo(pMoniker, &var);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
WARN("Unable to retrieve filter info (%x)\n", hr);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = create_filter(This, pMoniker, &pfilter);
|
|
||||||
IMoniker_Release(pMoniker);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
WARN("Unable to create filter (%x), trying next one\n", hr);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = IFilterGraph2_AddFilter(iface, pfilter, V_BSTR(&var));
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
WARN("Unable to add filter (%x)\n", hr);
|
|
||||||
IBaseFilter_Release(pfilter);
|
|
||||||
pfilter = NULL;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = IBaseFilter_EnumPins(pfilter, &penumpins);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
WARN("Splitter Enumpins (%x)\n", hr);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin)) == S_OK)
|
|
||||||
{
|
|
||||||
PIN_DIRECTION dir;
|
|
||||||
|
|
||||||
if (pin == 0) {
|
|
||||||
WARN("No Pin\n");
|
|
||||||
hr = E_FAIL;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = IPin_QueryDirection(ppinfilter, &dir);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
IPin_Release(ppinfilter);
|
|
||||||
WARN("QueryDirection failed (%x)\n", hr);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if (dir != PINDIR_INPUT) {
|
|
||||||
IPin_Release(ppinfilter);
|
|
||||||
continue; /* Wrong direction */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Connect the pin to the "Renderer" */
|
|
||||||
hr = IFilterGraph2_ConnectDirect(iface, ppinOut, ppinfilter, NULL);
|
|
||||||
IPin_Release(ppinfilter);
|
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
WARN("Unable to connect %s to renderer (%x)\n", debugstr_w(V_BSTR(&var)), hr);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
TRACE("Connected, recursing %s\n", debugstr_w(V_BSTR(&var)));
|
|
||||||
|
|
||||||
VariantClear(&var);
|
|
||||||
|
|
||||||
hr = render_output_pins(This, pfilter);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
WARN("Unable to connect recursively (%x)\n", hr);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
IBaseFilter_Release(pfilter);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (SUCCEEDED(hr)) {
|
|
||||||
IEnumPins_Release(penumpins);
|
|
||||||
break; /* out of IEnumMoniker_Next loop */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* IEnumPins_Next failed, all other failure case caught by goto error */
|
|
||||||
WARN("IEnumPins_Next (%x)\n", hr);
|
|
||||||
/* goto error */
|
|
||||||
|
|
||||||
error:
|
|
||||||
VariantClear(&var);
|
|
||||||
if (penumpins)
|
|
||||||
IEnumPins_Release(penumpins);
|
|
||||||
if (pfilter) {
|
|
||||||
IFilterGraph2_RemoveFilter(iface, pfilter);
|
|
||||||
IBaseFilter_Release(pfilter);
|
|
||||||
}
|
|
||||||
if (SUCCEEDED(hr)) DebugBreak();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumMoniker_Release(pEnumMoniker);
|
|
||||||
if (nbmt)
|
|
||||||
DeleteMediaType(mt);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
break;
|
|
||||||
hr = S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pFilterMapper2)
|
|
||||||
IFilterMapper2_Release(pFilterMapper2);
|
|
||||||
|
|
||||||
IEnumMediaTypes_Release(penummt);
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5755,7 +5404,6 @@ static HRESULT filter_graph_common_create(IUnknown *outer, IUnknown **out, BOOL
|
||||||
memcpy(&fimpl->timeformatseek, &TIME_FORMAT_MEDIA_TIME, sizeof(GUID));
|
memcpy(&fimpl->timeformatseek, &TIME_FORMAT_MEDIA_TIME, sizeof(GUID));
|
||||||
fimpl->stream_start = fimpl->stream_elapsed = 0;
|
fimpl->stream_start = fimpl->stream_elapsed = 0;
|
||||||
fimpl->punkFilterMapper2 = NULL;
|
fimpl->punkFilterMapper2 = NULL;
|
||||||
fimpl->recursioncount = 0;
|
|
||||||
fimpl->version = 0;
|
fimpl->version = 0;
|
||||||
fimpl->current_pos = 0;
|
fimpl->current_pos = 0;
|
||||||
|
|
||||||
|
|
|
@ -2110,7 +2110,7 @@ static void test_graph_builder_connect(void)
|
||||||
{
|
{
|
||||||
static const GUID parser1_clsid = {0x12345678};
|
static const GUID parser1_clsid = {0x12345678};
|
||||||
static const GUID parser2_clsid = {0x87654321};
|
static const GUID parser2_clsid = {0x87654321};
|
||||||
AM_MEDIA_TYPE source_type = {{0}}, sink_type = {{0}}, parser3_type = {{0}};
|
AM_MEDIA_TYPE source_types[2] = {{{0}}}, sink_type = {{0}}, parser3_type = {{0}};
|
||||||
struct testpin source_pin, sink_pin, sink2_pin, parser1_pins[3], parser2_pins[2], parser3_pins[2];
|
struct testpin source_pin, sink_pin, sink2_pin, parser1_pins[3], parser2_pins[2], parser3_pins[2];
|
||||||
struct testfilter source, sink, sink2, parser1, parser2, parser3;
|
struct testfilter source, sink, sink2, parser1, parser2, parser3;
|
||||||
struct testfilter_cf parser1_cf = { {&testfilter_cf_vtbl}, &parser1 };
|
struct testfilter_cf parser1_cf = { {&testfilter_cf_vtbl}, &parser1 };
|
||||||
|
@ -2125,10 +2125,11 @@ static void test_graph_builder_connect(void)
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
ULONG ref;
|
ULONG ref;
|
||||||
|
|
||||||
memset(&source_type.majortype, 0xcc, sizeof(GUID));
|
memset(&source_types[0].majortype, 0xcc, sizeof(GUID));
|
||||||
|
memset(&source_types[1].majortype, 0xdd, sizeof(GUID));
|
||||||
memset(&sink_type.majortype, 0x66, sizeof(GUID));
|
memset(&sink_type.majortype, 0x66, sizeof(GUID));
|
||||||
testsource_init(&source_pin, &source_type, 1);
|
testsource_init(&source_pin, source_types, 2);
|
||||||
source_pin.request_mt = &source_type;
|
source_pin.request_mt = &source_types[1];
|
||||||
testfilter_init(&source, &source_pin, 1);
|
testfilter_init(&source, &source_pin, 1);
|
||||||
testsink_init(&sink_pin);
|
testsink_init(&sink_pin);
|
||||||
testfilter_init(&sink, &sink_pin, 1);
|
testfilter_init(&sink, &sink_pin, 1);
|
||||||
|
@ -2398,7 +2399,7 @@ todo_wine
|
||||||
regpins[1].cInstances = 1;
|
regpins[1].cInstances = 1;
|
||||||
regpins[1].nMediaTypes = 1;
|
regpins[1].nMediaTypes = 1;
|
||||||
regpins[1].lpMediaType = ®types;
|
regpins[1].lpMediaType = ®types;
|
||||||
regtypes.clsMajorType = &source_type.majortype;
|
regtypes.clsMajorType = &source_types[1].majortype;
|
||||||
regtypes.clsMinorType = &MEDIASUBTYPE_NULL;
|
regtypes.clsMinorType = &MEDIASUBTYPE_NULL;
|
||||||
hr = IFilterMapper2_RegisterFilter(mapper, &parser1_clsid, L"test", NULL, NULL, NULL, ®filter);
|
hr = IFilterMapper2_RegisterFilter(mapper, &parser1_clsid, L"test", NULL, NULL, NULL, ®filter);
|
||||||
if (hr == E_ACCESSDENIED)
|
if (hr == E_ACCESSDENIED)
|
||||||
|
|
Loading…
Reference in New Issue