diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c index 8c8f89ce2ac..e0e126d8ef0 100644 --- a/dlls/quartz/filtergraph.c +++ b/dlls/quartz/filtergraph.c @@ -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) + 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}; - IEnumMoniker *enummoniker; - IBaseFilter *filter; - IMoniker *moniker; + IPropertyBag *bag; + VARIANT var; - DeleteMediaType(mt); - - 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) + 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; - } - - 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); + continue; } - 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; out: + free(types); if (callback) IAMGraphBuilderCallback_Release(callback); - IEnumMediaTypes_Release(enummt); IFilterMapper2_Release(mapper); return hr; } diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c index 391f9777175..00232ea7a52 100644 --- a/dlls/quartz/tests/filtergraph.c +++ b/dlls/quartz/tests/filtergraph.c @@ -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);