Commit e6cc4ae4 authored by Zebediah Figura's avatar Zebediah Figura Committed by Alexandre Julliard

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.
parent ce3ccccb
......@@ -1195,16 +1195,79 @@ static HRESULT autoplug_through_filter(struct filter_graph *graph, IPin *source,
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
* share most of the same code. Render() calls this with a NULL sink. */
static HRESULT autoplug(struct filter_graph *graph, IPin *source, IPin *sink,
BOOL render_to_existing, unsigned int recursion_depth)
{
IAMGraphBuilderCallback *callback = NULL;
IEnumMediaTypes *enummt;
struct filter *graph_filter;
IEnumMoniker *enummoniker;
unsigned int type_count;
IFilterMapper2 *mapper;
struct filter *filter;
AM_MEDIA_TYPE *mt;
IBaseFilter *filter;
GUID *types = NULL;
IMoniker *moniker;
HRESULT hr;
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. */
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)))
return hr;
}
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);
return hr;
......@@ -1246,85 +1309,75 @@ static HRESULT autoplug(struct filter_graph *graph, IPin *source, IPin *sink,
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, type_count, types, NULL, NULL, FALSE,
render_to_existing, 0, NULL, NULL, NULL)))
goto out;
if (FAILED(hr = IFilterMapper2_EnumMatchingFilters(mapper, &enummoniker,
0, FALSE, MERIT_UNLIKELY, TRUE, 1, types, NULL, NULL, FALSE,
render_to_existing, 0, NULL, NULL, NULL)))
goto out;
while (IEnumMoniker_Next(enummoniker, 1, &moniker, NULL) == S_OK)
{
IPropertyBag *bag;
VARIANT var;
while (IEnumMoniker_Next(enummoniker, 1, &moniker, NULL) == S_OK)
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))
{
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);
if (FAILED(hr))
{
ERR("Failed to create filter for %s, hr %#lx.\n", debugstr_w(V_BSTR(&var)), hr);
VariantClear(&var);
continue;
}
continue;
}
if (callback && FAILED(hr = IAMGraphBuilderCallback_CreatedFilter(callback, filter)))
{
TRACE("Filter rejected by IAMGraphBuilderCallback::CreatedFilter(), hr %#lx.\n", hr);
IBaseFilter_Release(filter);
continue;
}
if (callback && FAILED(hr = IAMGraphBuilderCallback_SelectedFilter(callback, moniker)))
{
TRACE("Filter rejected by IAMGraphBuilderCallback::SelectedFilter(), hr %#lx.\n", hr);
IMoniker_Release(moniker);
continue;
}
hr = IFilterGraph2_AddFilter(&graph->IFilterGraph2_iface, filter, V_BSTR(&var));
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);
if (FAILED(hr))
{
ERR("Failed to add filter, hr %#lx.\n", hr);
IBaseFilter_Release(filter);
continue;
}
continue;
}
hr = autoplug_through_filter(graph, source, filter, sink, render_to_existing, recursion_depth);
if (SUCCEEDED(hr))
{
IBaseFilter_Release(filter);
goto out;
}
if (callback && FAILED(hr = IAMGraphBuilderCallback_CreatedFilter(callback, filter)))
{
TRACE("Filter rejected by IAMGraphBuilderCallback::CreatedFilter(), hr %#lx.\n", hr);
IBaseFilter_Release(filter);
continue;
}
IFilterGraph2_RemoveFilter(&graph->IFilterGraph2_iface, filter);
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;
}
IEnumMoniker_Release(enummoniker);
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;
out:
free(types);
if (callback) IAMGraphBuilderCallback_Release(callback);
IEnumMediaTypes_Release(enummt);
IFilterMapper2_Release(mapper);
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
* trying to render audio. */
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);
ok(!ref, "Got outstanding refcount %ld.\n", ref);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment