From: Conor McCarthy <cmccarthy@codeweavers.com> Windows does not call MFTEnumEx to get a resampler. --- dlls/mf/tests/topology.c | 2 +- dlls/mf/topology_loader.c | 144 +++++++++++++++++++++++++++++++++++++- 2 files changed, 143 insertions(+), 3 deletions(-) diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index 63a8192aca3..46bc9d52d7a 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -2550,7 +2550,7 @@ static void test_topology_loader(void) /* PCM -> PCM, different enumerated bps, no current type, sink allow converter, no output types */ .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_ALLOW_CONVERTER, .source_method = MF_CONNECT_DIRECT, .expected_result = MF_E_INVALIDMEDIATYPE, .converter_class = CLSID_CResamplerMediaObject, - .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_TODO, + .flags = LOADER_NO_CURRENT_OUTPUT, }, { /* PCM -> PCM, different enumerated bps, no current type, sink allow converter, no current output type */ diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index f68e17134ee..4a73c8441d7 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -32,6 +32,8 @@ #include "wine/list.h" #include "mf_private.h" +#include "initguid.h" +#include "wmcodecdsp.h" WINE_DEFAULT_DEBUG_CHANNEL(mfplat); @@ -442,6 +444,145 @@ HRESULT topology_node_init_media_type(IMFTopologyNode *node, DWORD stream, BOOL return hr; } +static HRESULT create_transform_node(const GUID *class_id, IMFTopologyNode **node_out, + IMFTransform **transform_out, BOOL set_id) +{ + IMFTopologyNode *node = NULL; + IMFTransform *transform; + HRESULT hr; + + if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform))) + return hr; + + if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node)) + || (set_id && FAILED(hr = IMFTopologyNode_SetGUID(node, &MF_TOPONODE_TRANSFORM_OBJECTID, class_id))) + || FAILED(hr = IMFTopologyNode_SetObject(node, (IUnknown *)transform))) + goto failed; + + *node_out = node; + *transform_out = transform; + + return S_OK; + +failed: + if (node) + IMFTopologyNode_Release(node); + IMFTransform_Release(transform); + + return hr; +} + +static HRESULT topology_branch_connect_converter_with_types(IMFTopology *topology, struct topology_branch *branch, + IMFMediaType *up_type, IMFMediaType *down_type) +{ + IMFMediaTypeHandler *up_handler = NULL, *down_handler = NULL; + HRESULT hr, ret_hr = MF_E_TOPO_CODEC_NOT_FOUND; + IMFMediaType *output_type, *media_type; + IMFTransform *transform; + IMFTopologyNode *node; + GUID major; + UINT i; + + TRACE("branch %s, up_type %s, down_type %s.\n", debugstr_topology_branch(branch), debugstr_media_type(up_type), + debugstr_media_type(down_type)); + + if (FAILED(hr = IMFMediaType_GetMajorType(up_type, &major))) + return hr; + + if (IsEqualGUID(&major, &MFMediaType_Audio)) + { + /* Changing the resampler GUID in Windows regedit does not prevent a CResamplerMediaObject + * being used, implying that MFTEnumEx() is not called for resamplers. */ + if (FAILED(hr = create_transform_node(&CLSID_CResamplerMediaObject, &node, &transform, TRUE))) + return hr; + } + else if (IsEqualGUID(&major, &MFMediaType_Video)) + { + return topology_branch_connect_indirect(topology, MF_CONNECT_ALLOW_CONVERTER, branch, up_type, down_type); + } + else + { + return MF_E_INVALIDMEDIATYPE; + } + + if (FAILED(hr = topology_node_get_type_handler(branch->up.node, branch->up.stream, TRUE, &up_handler))) + goto done; + if (FAILED(hr = topology_node_get_type_handler(branch->down.node, branch->down.stream, FALSE, &down_handler))) + goto done; + + if (FAILED(hr = IMFTransform_SetInputType(transform, 0, up_type, 0)) + || FAILED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(up_handler, up_type, NULL))) + { + goto done; + } + + for (i = 0; SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, i, &output_type)); ++i) + { + DWORD flags; + + /* IsMediaTypeSupported() is not called until the type passes a sanity check of some kind. + * The below condition at least matches the test results. */ + if (down_type && (FAILED(IMFMediaType_IsEqual(output_type, down_type, &flags)) + || !(flags & MF_MEDIATYPE_EQUAL_MAJOR_TYPES) || !(flags & MF_MEDIATYPE_EQUAL_FORMAT_TYPES))) + { + IMFMediaType_Release(output_type); + continue; + } + + if (down_type) + { + /* It is not clear exactly how the type should be compiled, but probably attributes from the down + * type should have priority, and then we should add any from upstream which have not been set. */ + if (FAILED(clone_media_type_and_update_from_upstream(down_type, output_type, &media_type))) + continue; + update_media_type_from_upstream(media_type, up_type); + } + else + { + if (FAILED(clone_media_type_and_update_from_upstream(output_type, up_type, &media_type))) + continue; + } + + IMFMediaType_Release(output_type); + + /* Error code from this call seems to be the required return if we never get past here. */ + if (SUCCEEDED(ret_hr = IMFMediaTypeHandler_IsMediaTypeSupported(down_handler, media_type, NULL))) + { + hr = IMFMediaTypeHandler_SetCurrentMediaType(up_handler, up_type); + + ret_hr = MF_E_TOPO_CODEC_NOT_FOUND; + + if (SUCCEEDED(hr) && SUCCEEDED(hr = IMFTransform_SetOutputType(transform, 0, media_type, 0)) + && SUCCEEDED(ret_hr = IMFTopologyNode_ConnectOutput(branch->up.node, branch->up.stream, node, 0)) + && SUCCEEDED(ret_hr = IMFTopologyNode_ConnectOutput(node, 0, branch->down.node, branch->down.stream)) + && SUCCEEDED(ret_hr = IMFTopology_AddNode(topology, node))) + { + TRACE("Connected converter %p, input %s, output %s.\n", transform, debugstr_media_type(up_type), + debugstr_media_type(media_type)); + } + } + IMFMediaType_Release(media_type); + + if (SUCCEEDED(ret_hr)) + break; + } + + /* Return unexpected errors such as allocation failure. */ + if (FAILED(hr) && hr != MF_E_INVALIDMEDIATYPE && hr != MF_E_NO_MORE_TYPES) + ret_hr = hr; + +done: + if (down_handler) + IMFMediaTypeHandler_Release(down_handler); + if (up_handler) + IMFMediaTypeHandler_Release(up_handler); + if (node) + IMFTopologyNode_Release(node); + IMFTransform_Release(transform); + + return ret_hr; +} + static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_METHOD method, struct topology_branch *branch, IMFMediaType *up_type) { @@ -478,8 +619,7 @@ static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_ME } if (FAILED(hr) && (method & MF_CONNECT_ALLOW_CONVERTER) == MF_CONNECT_ALLOW_CONVERTER) - hr = topology_branch_connect_indirect(topology, MF_CONNECT_ALLOW_CONVERTER, - branch, up_type, down_type); + hr = topology_branch_connect_converter_with_types(topology, branch, up_type, down_type); if (FAILED(hr) && (method & MF_CONNECT_ALLOW_DECODER) == MF_CONNECT_ALLOW_DECODER) hr = topology_branch_connect_indirect(topology, MF_CONNECT_ALLOW_DECODER, -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10009