mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-15 04:54:46 +00:00
quartz: Call EnumMatchingFilters() once in autoplug().
Instead of iterating through types one by one and calling EnumMatchingFilters() on each one, build a list of all media types exposed by the pin and call the function once. This avoids trying to pointless autoplug the same filter multiple times, which speeds up autoplugging greatly for cases when a given filter connects less than instantaneously. The most prominent example of such a filter is the AVI decompressor, which has to call ICLocate() on connection. ICLocate() is not a fast API on Wine, and it is even slower on Windows; this reduces the number of times we try to call it greatly.
This commit is contained in:
parent
ce3ccccb2c
commit
e6cc4ae4b4
|
@ -1195,16 +1195,79 @@ static HRESULT autoplug_through_filter(struct filter_graph *graph, IPin *source,
|
||||||
return VFW_E_CANNOT_CONNECT;
|
return VFW_E_CANNOT_CONNECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HRESULT get_autoplug_types(IPin *source, unsigned int *ret_count, GUID **ret_types)
|
||||||
|
{
|
||||||
|
unsigned int i, mt_count = 0, mt_capacity = 16;
|
||||||
|
AM_MEDIA_TYPE **mts = NULL;
|
||||||
|
IEnumMediaTypes *enummt;
|
||||||
|
GUID *types = NULL;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
if (FAILED(hr = IPin_EnumMediaTypes(source, &enummt)))
|
||||||
|
{
|
||||||
|
ERR("Failed to enumerate media types, hr %#lx.\n", hr);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
ULONG count;
|
||||||
|
|
||||||
|
if (!(mts = realloc(mts, mt_capacity * sizeof(*mts))))
|
||||||
|
{
|
||||||
|
hr = E_OUTOFMEMORY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(hr = IEnumMediaTypes_Next(enummt, mt_capacity - mt_count, mts + mt_count, &count)))
|
||||||
|
{
|
||||||
|
ERR("Failed to get media types, hr %#lx.\n", hr);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
mt_count += count;
|
||||||
|
if (hr == S_FALSE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
mt_capacity *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(types = malloc(mt_count * 2 * sizeof(*types))))
|
||||||
|
{
|
||||||
|
hr = E_OUTOFMEMORY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < mt_count; ++i)
|
||||||
|
{
|
||||||
|
types[i * 2] = mts[i]->majortype;
|
||||||
|
types[i * 2 + 1] = mts[i]->subtype;
|
||||||
|
DeleteMediaType(mts[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
*ret_count = mt_count;
|
||||||
|
*ret_types = types;
|
||||||
|
|
||||||
|
hr = S_OK;
|
||||||
|
out:
|
||||||
|
free(mts);
|
||||||
|
IEnumMediaTypes_Release(enummt);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
/* Common helper for IGraphBuilder::Connect() and IGraphBuilder::Render(), which
|
/* Common helper for IGraphBuilder::Connect() and IGraphBuilder::Render(), which
|
||||||
* share most of the same code. Render() calls this with a NULL sink. */
|
* share most of the same code. Render() calls this with a NULL sink. */
|
||||||
static HRESULT autoplug(struct filter_graph *graph, IPin *source, IPin *sink,
|
static HRESULT autoplug(struct filter_graph *graph, IPin *source, IPin *sink,
|
||||||
BOOL render_to_existing, unsigned int recursion_depth)
|
BOOL render_to_existing, unsigned int recursion_depth)
|
||||||
{
|
{
|
||||||
IAMGraphBuilderCallback *callback = NULL;
|
IAMGraphBuilderCallback *callback = NULL;
|
||||||
IEnumMediaTypes *enummt;
|
struct filter *graph_filter;
|
||||||
|
IEnumMoniker *enummoniker;
|
||||||
|
unsigned int type_count;
|
||||||
IFilterMapper2 *mapper;
|
IFilterMapper2 *mapper;
|
||||||
struct filter *filter;
|
IBaseFilter *filter;
|
||||||
AM_MEDIA_TYPE *mt;
|
GUID *types = NULL;
|
||||||
|
IMoniker *moniker;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
TRACE("Trying to autoplug %p to %p, recursion depth %u.\n", source, sink, recursion_depth);
|
TRACE("Trying to autoplug %p to %p, recursion depth %u.\n", source, sink, recursion_depth);
|
||||||
|
@ -1228,16 +1291,16 @@ static HRESULT autoplug(struct filter_graph *graph, IPin *source, IPin *sink,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Always prefer filters in the graph. */
|
/* Always prefer filters in the graph. */
|
||||||
LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
|
LIST_FOR_EACH_ENTRY(graph_filter, &graph->filters, struct filter, entry)
|
||||||
{
|
{
|
||||||
if (SUCCEEDED(hr = autoplug_through_filter(graph, source, filter->filter,
|
if (SUCCEEDED(hr = autoplug_through_filter(graph, source, graph_filter->filter,
|
||||||
sink, render_to_existing, recursion_depth)))
|
sink, render_to_existing, recursion_depth)))
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
IUnknown_QueryInterface(graph->punkFilterMapper2, &IID_IFilterMapper2, (void **)&mapper);
|
IUnknown_QueryInterface(graph->punkFilterMapper2, &IID_IFilterMapper2, (void **)&mapper);
|
||||||
|
|
||||||
if (FAILED(hr = IPin_EnumMediaTypes(source, &enummt)))
|
if (FAILED(hr = get_autoplug_types(source, &type_count, &types)))
|
||||||
{
|
{
|
||||||
IFilterMapper2_Release(mapper);
|
IFilterMapper2_Release(mapper);
|
||||||
return hr;
|
return hr;
|
||||||
|
@ -1246,85 +1309,75 @@ static HRESULT autoplug(struct filter_graph *graph, IPin *source, IPin *sink,
|
||||||
if (graph->pSite)
|
if (graph->pSite)
|
||||||
IUnknown_QueryInterface(graph->pSite, &IID_IAMGraphBuilderCallback, (void **)&callback);
|
IUnknown_QueryInterface(graph->pSite, &IID_IAMGraphBuilderCallback, (void **)&callback);
|
||||||
|
|
||||||
while (IEnumMediaTypes_Next(enummt, 1, &mt, NULL) == S_OK)
|
if (FAILED(hr = IFilterMapper2_EnumMatchingFilters(mapper, &enummoniker,
|
||||||
|
0, FALSE, MERIT_UNLIKELY, TRUE, type_count, types, NULL, NULL, FALSE,
|
||||||
|
render_to_existing, 0, NULL, NULL, NULL)))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
while (IEnumMoniker_Next(enummoniker, 1, &moniker, NULL) == S_OK)
|
||||||
{
|
{
|
||||||
GUID types[2] = {mt->majortype, mt->subtype};
|
IPropertyBag *bag;
|
||||||
IEnumMoniker *enummoniker;
|
VARIANT var;
|
||||||
IBaseFilter *filter;
|
|
||||||
IMoniker *moniker;
|
|
||||||
|
|
||||||
DeleteMediaType(mt);
|
VariantInit(&var);
|
||||||
|
IMoniker_BindToStorage(moniker, NULL, NULL, &IID_IPropertyBag, (void **)&bag);
|
||||||
if (FAILED(hr = IFilterMapper2_EnumMatchingFilters(mapper, &enummoniker,
|
hr = IPropertyBag_Read(bag, L"FriendlyName", &var, NULL);
|
||||||
0, FALSE, MERIT_UNLIKELY, TRUE, 1, types, NULL, NULL, FALSE,
|
IPropertyBag_Release(bag);
|
||||||
render_to_existing, 0, NULL, NULL, NULL)))
|
if (FAILED(hr))
|
||||||
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 %#lx.\n", hr);
|
|
||||||
IMoniker_Release(moniker);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = create_filter(graph, moniker, &filter);
|
|
||||||
IMoniker_Release(moniker);
|
IMoniker_Release(moniker);
|
||||||
if (FAILED(hr))
|
continue;
|
||||||
{
|
|
||||||
ERR("Failed to create filter for %s, hr %#lx.\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 %#lx.\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 %#lx.\n", hr);
|
|
||||||
IBaseFilter_Release(filter);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = autoplug_through_filter(graph, source, filter, sink, render_to_existing, recursion_depth);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
IBaseFilter_Release(filter);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
IFilterGraph2_RemoveFilter(&graph->IFilterGraph2_iface, filter);
|
|
||||||
IBaseFilter_Release(filter);
|
|
||||||
}
|
}
|
||||||
IEnumMoniker_Release(enummoniker);
|
|
||||||
|
if (callback && FAILED(hr = IAMGraphBuilderCallback_SelectedFilter(callback, moniker)))
|
||||||
|
{
|
||||||
|
TRACE("Filter rejected by IAMGraphBuilderCallback::SelectedFilter(), hr %#lx.\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 %#lx.\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 %#lx.\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 %#lx.\n", hr);
|
||||||
|
IBaseFilter_Release(filter);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = autoplug_through_filter(graph, source, filter, sink, render_to_existing, 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;
|
hr = VFW_E_CANNOT_CONNECT;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
free(types);
|
||||||
if (callback) IAMGraphBuilderCallback_Release(callback);
|
if (callback) IAMGraphBuilderCallback_Release(callback);
|
||||||
IEnumMediaTypes_Release(enummt);
|
|
||||||
IFilterMapper2_Release(mapper);
|
IFilterMapper2_Release(mapper);
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5344,7 +5344,7 @@ static void test_autoplug_uyvy(void)
|
||||||
* failure to decode up to missing audio hardware, even though we're not
|
* failure to decode up to missing audio hardware, even though we're not
|
||||||
* trying to render audio. */
|
* trying to render audio. */
|
||||||
hr = IFilterGraph2_Render(graph, &source_pin.IPin_iface);
|
hr = IFilterGraph2_Render(graph, &source_pin.IPin_iface);
|
||||||
todo_wine ok(hr == S_OK || hr == VFW_E_NO_AUDIO_HARDWARE, "Got hr %#lx.\n", hr);
|
ok(hr == S_OK || hr == VFW_E_NO_AUDIO_HARDWARE, "Got hr %#lx.\n", hr);
|
||||||
|
|
||||||
ref = IFilterGraph2_Release(graph);
|
ref = IFilterGraph2_Release(graph);
|
||||||
ok(!ref, "Got outstanding refcount %ld.\n", ref);
|
ok(!ref, "Got outstanding refcount %ld.\n", ref);
|
||||||
|
|
Loading…
Reference in a new issue