Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/mf/tests/mf.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index dfbd928f60..6f225745d6 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -1246,6 +1246,7 @@ static void test_topology_loader(void) IMFPresentationDescriptor *pd; IMFSourceResolver *resolver; IMFActivate *sink_activate; + IMFStreamSink *stream_sink; unsigned int count, value; IMFMediaType *media_type; IMFStreamDescriptor *sd; @@ -1358,7 +1359,10 @@ todo_wine hr = IMFActivate_ActivateObject(sink_activate, &IID_IMFMediaSink, (void **)&sink); ok(hr == S_OK, "Failed to activate, hr %#x.\n", hr);
- hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)sink); + hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream_sink); + ok(hr == S_OK, "Failed to get stream sink, hr %#x.\n", hr); + + hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)stream_sink); ok(hr == S_OK, "Failed to set object, hr %#x.\n", hr);
hr = IMFTopology_GetCount(topology, &count); @@ -1366,7 +1370,6 @@ todo_wine ok(count == 0, "Unexpected count %u.\n", count);
hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); -todo_wine ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr); ok(full_topology != topology, "Unexpected instance.\n");
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/mf/tests/mf.c | 435 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 433 insertions(+), 2 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 6f225745d6..1a762c6874 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -1238,26 +1238,169 @@ static const IMFSampleGrabberSinkCallbackVtbl test_grabber_callback_vtbl = test_grabber_callback_OnShutdown, };
+static HRESULT WINAPI test_media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out) +{ + if (IsEqualIID(riid, &IID_IMFMediaSource) || + IsEqualIID(riid, &IID_IMFMediaEventGenerator) || + IsEqualIID(riid, &IID_IUnknown)) + { + *out = iface; + IUnknown_AddRef((IUnknown*)*out); + return S_OK; + } + + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_media_source_AddRef(IMFMediaSource *iface) +{ + return 2; +} + +static ULONG WINAPI test_media_source_Release(IMFMediaSource *iface) +{ + return 1; +} + +static HRESULT WINAPI test_media_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_media_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type, + HRESULT hr, const PROPVARIANT *value) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor) +{ + HRESULT hr; + + IMFPresentationDescriptor *pd; + IMFMediaType *mediatypes[3]; + IMFStreamDescriptor *sd[2]; + + if (FAILED(hr = MFCreateMediaType(&mediatypes[0]))) + return hr; + if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[0], &MF_MT_MAJOR_TYPE, &MFMediaType_Video))) + return hr; + if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[0], &MF_MT_SUBTYPE, &MFVideoFormat_YUY2))) + return hr; + if (FAILED(hr = MFCreateMediaType(&mediatypes[1]))) + return hr; + if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[1], &MF_MT_MAJOR_TYPE, &MFMediaType_Audio))) + return hr; + if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[1], &MF_MT_SUBTYPE, &MFAudioFormat_MP3))) + return hr; + if (FAILED(hr = IMFMediaType_SetUINT32(mediatypes[1], &MF_MT_AUDIO_SAMPLES_PER_SECOND, 32000))) + return hr; + if (FAILED(hr = IMFMediaType_SetUINT32(mediatypes[1], &MF_MT_AUDIO_NUM_CHANNELS, 2))) + return hr; + if (FAILED(hr = IMFMediaType_SetUINT32(mediatypes[1], &MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1))) + return hr; + if (FAILED(hr = MFCreateMediaType(&mediatypes[2]))) + return hr; + if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[2], &MF_MT_MAJOR_TYPE, &MFMediaType_Audio))) + return hr; + if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[2], &MF_MT_SUBTYPE, &MFAudioFormat_PCM))) + return hr; + if (FAILED(hr = MFCreateStreamDescriptor(0, 3, mediatypes, &sd[0]))) + return hr; + if (FAILED(hr = MFCreateStreamDescriptor(1, 3, mediatypes, &sd[1]))) + return hr; + if (FAILED(hr = MFCreatePresentationDescriptor(2, sd, &pd))) + return hr; + *descriptor = pd; + + IMFMediaType_Release(mediatypes[0]); + IMFMediaType_Release(mediatypes[1]); + IMFMediaType_Release(mediatypes[2]); + IMFStreamDescriptor_Release(sd[0]); + IMFStreamDescriptor_Release(sd[1]); + + return S_OK; +} + +static HRESULT WINAPI test_media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor, + const GUID *time_format, const PROPVARIANT *start_position) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_media_source_Stop(IMFMediaSource *iface) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_media_source_Pause(IMFMediaSource *iface) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_media_source_Shutdown(IMFMediaSource *iface) +{ + return S_OK; +} + +static const IMFMediaSourceVtbl test_media_source_vtbl = +{ + test_media_source_QueryInterface, + test_media_source_AddRef, + test_media_source_Release, + test_media_source_GetEvent, + test_media_source_BeginGetEvent, + test_media_source_EndGetEvent, + test_media_source_QueueEvent, + test_media_source_GetCharacteristics, + test_media_source_CreatePresentationDescriptor, + test_media_source_Start, + test_media_source_Stop, + test_media_source_Pause, + test_media_source_Shutdown, +}; + static void test_topology_loader(void) { IMFSampleGrabberSinkCallback test_grabber_callback = { &test_grabber_callback_vtbl }; + IMFMediaSource test_media_source = { &test_media_source_vtbl }; IMFTopology *topology, *topology2, *full_topology; IMFTopologyNode *src_node, *sink_node; + IMFMediaType *media_type, *current_media_type; IMFPresentationDescriptor *pd; IMFSourceResolver *resolver; IMFActivate *sink_activate; IMFStreamSink *stream_sink; unsigned int count, value; - IMFMediaType *media_type; + IMFMediaTypeHandler *mth; IMFStreamDescriptor *sd; + UINT32 enum_src, method; MF_OBJECT_TYPE obj_type; IMFMediaSource *source; IMFTopoLoader *loader; IMFByteStream *stream; IMFAttributes *attr; IMFMediaSink *sink; + WORD node_count; WCHAR *filename; BOOL selected; + DWORD flags; HRESULT hr; GUID guid;
@@ -1373,6 +1516,9 @@ todo_wine ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr); ok(full_topology != topology, "Unexpected instance.\n");
+ IMFTopology_GetNodeCount(full_topology, &node_count); + ok(node_count == 2, "Topology node count is %#x.\n", node_count); + hr = IMFTopology_GetCount(topology, &count); ok(hr == S_OK, "Failed to get attribute count, hr %#x.\n", hr); ok(count == 0, "Unexpected count %u.\n", count); @@ -1399,10 +1545,295 @@ todo_wine {
IMFTopology_Release(topology2); IMFTopology_Release(full_topology); + IMFByteStream_Release(stream); + IMFStreamDescriptor_Release(sd);
+ /* test with stream deselected */ + IMFPresentationDescriptor_GetStreamDescriptorCount(pd, &count); + ok(count == 1, "Unexpected stream descriptor count.\n"); + hr = IMFPresentationDescriptor_DeselectStream(pd, 0); + ok(hr == S_OK, "Failed to deselect stream, hr %#x.\n", hr); + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr); + IMFTopologyNode_Release(src_node); + hr = IMFTopology_GetNode(full_topology, 0, &src_node); + ok(hr == S_OK, "Failed to get full topology source node, hr %#x.\n", hr); + IMFPresentationDescriptor_Release(pd); + hr = IMFTopologyNode_GetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, &IID_IMFPresentationDescriptor, (void **)&pd); + ok(hr == S_OK, "Failed to get presentation descriptor, hr %#x.\n", hr); + IMFStreamDescriptor_Release(sd); + IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, 0, &selected, &sd); + ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr); + ok(!selected, "Stream should not be selected\n."); + + IMFPresentationDescriptor_Release(pd); + IMFTopologyNode_Release(src_node); + IMFTopology_Release(full_topology); + IMFTopology_Release(topology); IMFMediaSource_Release(source); IMFSourceResolver_Release(resolver); - IMFByteStream_Release(stream); + + /* test source stream with various media types */ + /* first, test default behavior; MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES not set */ + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "Failed to create topology, hr %#x.\n", hr); + + hr = IMFMediaSource_CreatePresentationDescriptor(&test_media_source, &pd); + ok(hr == S_OK, "Failed to create descriptor, hr %#x.\n", hr); + + hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, 0, &selected, &sd); + ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr); + + hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &mth); + ok(hr == S_OK, "Failed to get media type handler, hr %#x.\n", hr); + hr = IMFMediaTypeHandler_GetCurrentMediaType(mth, &media_type); + ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &src_node); + ok(hr == S_OK, "Failed to create topology node, hr %#x.\n", hr); + + hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_SOURCE, (IUnknown *)&test_media_source); + ok(hr == S_OK, "Failed to set node source, hr %#x.\n", hr); + hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)pd); + ok(hr == S_OK, "Failed to set node pd, hr %#x.\n", hr); + hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd); + ok(hr == S_OK, "Failed to set node sd, hr %#x.\n", hr); + + hr = IMFTopology_AddNode(topology, src_node); + ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr); + + hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + + hr = MFCreateSampleGrabberSinkActivate(media_type, &test_grabber_callback, &sink_activate); + ok(hr == S_OK, "Failed to create grabber sink, hr %#x.\n", hr); + IMFMediaType_Release(media_type); + + hr = IMFActivate_ActivateObject(sink_activate, &IID_IMFMediaSink, (void **)&sink); + ok(hr == S_OK, "Failed to activate, hr %#x.\n", hr); + + hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream_sink); + ok(hr == S_OK, "Failed to get stream sink, hr %#x.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &sink_node); + ok(hr == S_OK, "Failed to create output node, hr %#x.\n", hr); + + hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)stream_sink); + ok(hr == S_OK, "Failed to set object, hr %#x.\n", hr); + + hr = IMFTopology_AddNode(topology, sink_node); + ok(hr == S_OK, "Failed to add sink node, hr %#x.\n", hr); + + hr = IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#x.\n", hr); + + hr = IMFTopology_GetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, &enum_src); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Attribute should not be set\n."); + /* if no current media type set, loader uses first index exclusively */ + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); +todo_wine + /* when major types differ, error is MF_E_TOPO_CODEC_NOT_FOUND */ + ok(hr == MF_E_TOPO_CODEC_NOT_FOUND, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 2, &media_type); + ok(hr == S_OK, "Failed getting media type, hr %#x.\n", hr); + + /* setting current media type overrides previous behavior; tries with it, and only with it */ + hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, media_type); + ok(hr == S_OK, "Failed setting current media type, hr %#x.\n", hr); + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFTopology_GetNodeCount(full_topology, &node_count); + ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr); + ok(node_count == 2, "Unexpected node count.\n"); + + hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 1, &media_type); + ok(hr == S_OK, "Failed getting media type, hr %#x.\n", hr); + + hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, media_type); + ok(hr == S_OK, "Failed setting current media type, hr %#x.\n", hr); + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr); + + hr = IMFTopology_GetNodeCount(full_topology, &node_count); + ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr); +todo_wine + ok(node_count == 3, "Unexpected node count.\n"); + + IMFTopology_Release(full_topology); + + /* now test with MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES set on topology */ + hr = IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, 1); + ok(hr == S_OK, "Failed setting attribute\n."); + hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 2, &media_type); + ok(hr == S_OK, "Failed getting media type, hr %#x.\n", hr); + + /* first, if MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES is not set on source */ + IMFTopologyNode_GetUINT32(src_node, &MF_TOPONODE_CONNECT_METHOD, &method); + ok(hr == S_OK, "Attribute should be set\n."); + IMFTopologyNode_SetUINT32(src_node, &MF_TOPONODE_CONNECT_METHOD, method & ~MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES); + ok(hr == S_OK, "Failed setting attribute %#x\n.", hr); + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr); + + hr = IMFTopology_GetNodeCount(full_topology, &node_count); + ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr); + ok(node_count == 2, "Unexpected node count.\n"); + IMFTopologyNode_Release(src_node); + hr = IMFTopology_GetNode(full_topology, 0, &src_node); + ok(hr == S_OK, "Failed to get node, hr %#x.\n", hr); + IMFStreamDescriptor_Release(sd); + hr = IMFTopologyNode_GetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, &IID_IMFStreamDescriptor, (void **)&sd); + ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr); + IMFMediaTypeHandler_Release(mth); + hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &mth); + ok(hr == S_OK, "Failed to get media type handler, hr %#x.\n", hr); + hr = IMFMediaTypeHandler_GetCurrentMediaType(mth, ¤t_media_type); + ok(hr == S_OK, "Failed to get current media type, hr %#x.\n", hr); + hr = IMFMediaType_IsEqual(current_media_type, media_type, &flags); +todo_wine { + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(flags & MF_MEDIATYPE_EQUAL_FORMAT_DATA, "Types should be equal.\n"); +} + + IMFMediaType_Release(media_type); + IMFMediaType_Release(current_media_type); + IMFMediaTypeHandler_Release(mth); + IMFStreamSink_Release(stream_sink); + IMFMediaSink_Release(sink); + IMFActivate_Release(sink_activate); + IMFStreamDescriptor_Release(sd); + + /* add second branch with a valid first branch */ + hr = IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, 0); + ok(hr == S_OK, "Failed setting attribute\n."); + IMFTopologyNode_Release(src_node); + hr = IMFTopology_GetNode(topology, 0, &src_node); + ok(hr == S_OK, "Failed to get node, hr %#x.\n", hr); + hr = IMFTopologyNode_GetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, &IID_IMFStreamDescriptor, (void **)&sd); + ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr); + hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &mth); + ok(hr == S_OK, "Failed to get media type handler, hr %#x.\n", hr); + hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 1, &media_type); + ok(hr == S_OK, "Failed getting media type, hr %#x.\n", hr); + hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, media_type); + ok(hr == S_OK, "Failed setting current media type, hr %#x.\n", hr); + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr); + + IMFTopology_Release(full_topology); + + IMFStreamDescriptor_Release(sd); + hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, 1, &selected, &sd); + ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr); + + hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &mth); + ok(hr == S_OK, "Failed to get media type handler, hr %#x.\n", hr); + hr = IMFMediaTypeHandler_GetCurrentMediaType(mth, &media_type); + ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr); + + IMFTopologyNode_Release(src_node); + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &src_node); + ok(hr == S_OK, "Failed to create topology node, hr %#x.\n", hr); + + hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_SOURCE, (IUnknown *)&test_media_source); + ok(hr == S_OK, "Failed to set node source, hr %#x.\n", hr); + hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)pd); + ok(hr == S_OK, "Failed to set node pd, hr %#x.\n", hr); + hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd); + ok(hr == S_OK, "Failed to set node sd, hr %#x.\n", hr); + + hr = IMFTopology_AddNode(topology, src_node); + ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr); + + hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + + hr = MFCreateSampleGrabberSinkActivate(media_type, &test_grabber_callback, &sink_activate); + ok(hr == S_OK, "Failed to create grabber sink, hr %#x.\n", hr); + IMFMediaType_Release(media_type); + + hr = IMFActivate_ActivateObject(sink_activate, &IID_IMFMediaSink, (void **)&sink); + ok(hr == S_OK, "Failed to activate, hr %#x.\n", hr); + + hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream_sink); + ok(hr == S_OK, "Failed to get stream sink, hr %#x.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &sink_node); + ok(hr == S_OK, "Failed to create output node, hr %#x.\n", hr); + + hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)stream_sink); + ok(hr == S_OK, "Failed to set object, hr %#x.\n", hr); + + hr = IMFTopology_AddNode(topology, sink_node); + ok(hr == S_OK, "Failed to add sink node, hr %#x.\n", hr); + + hr = IMFTopology_GetNodeCount(topology, &node_count); + ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr); + ok(node_count == 4, "Unexpected node count.\n"); + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + /* unconnected nodes in partial topology are discarded */ + hr = IMFTopology_GetNodeCount(full_topology, &node_count); + ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr); +todo_wine + ok(node_count == 3, "Unexpected node count %d.\n", node_count); + + IMFTopology_Release(full_topology); + + /* connect nodes for second branch */ + hr = IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#x.\n", hr); + + /* all branches must have valid media types */ + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); +todo_wine + ok(hr == MF_E_TOPO_CODEC_NOT_FOUND, "Unexpected hr %#x.\n", hr); + + /* set valid media type for second branch */ + hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 1, &media_type); + ok(hr == S_OK, "Failed getting media type, hr %#x.\n", hr); + + hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, media_type); + ok(hr == S_OK, "Failed setting current media type, hr %#x.\n", hr); + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr); + + hr = IMFTopology_GetNodeCount(full_topology, &node_count); + ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr); +todo_wine + ok(node_count == 6, "Unexpected node count %d.\n", node_count); + + IMFTopology_Release(full_topology); + IMFMediaType_Release(media_type); + IMFTopologyNode_Release(src_node); + IMFTopologyNode_Release(sink_node); + IMFMediaTypeHandler_Release(mth); + IMFStreamSink_Release(stream_sink); + IMFMediaSink_Release(sink); + IMFActivate_Release(sink_activate); + IMFStreamDescriptor_Release(sd); + + IMFPresentationDescriptor_Release(pd); + IMFTopology_Release(topology); IMFTopoLoader_Release(loader);
hr = MFShutdown();
On 4/2/20 12:11 AM, Sergio Gómez Del Real wrote:
+static HRESULT WINAPI test_media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor) +{
- HRESULT hr;
- IMFPresentationDescriptor *pd;
- IMFMediaType *mediatypes[3];
- IMFStreamDescriptor *sd[2];
- if (FAILED(hr = MFCreateMediaType(&mediatypes[0])))
return hr;
- if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[0], &MF_MT_MAJOR_TYPE, &MFMediaType_Video)))
return hr;
- if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[0], &MF_MT_SUBTYPE, &MFVideoFormat_YUY2)))
return hr;
- if (FAILED(hr = MFCreateMediaType(&mediatypes[1])))
return hr;
- if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[1], &MF_MT_MAJOR_TYPE, &MFMediaType_Audio)))
return hr;
- if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[1], &MF_MT_SUBTYPE, &MFAudioFormat_MP3)))
return hr;
- if (FAILED(hr = IMFMediaType_SetUINT32(mediatypes[1], &MF_MT_AUDIO_SAMPLES_PER_SECOND, 32000)))
return hr;
- if (FAILED(hr = IMFMediaType_SetUINT32(mediatypes[1], &MF_MT_AUDIO_NUM_CHANNELS, 2)))
return hr;
- if (FAILED(hr = IMFMediaType_SetUINT32(mediatypes[1], &MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1)))
return hr;
- if (FAILED(hr = MFCreateMediaType(&mediatypes[2])))
return hr;
- if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[2], &MF_MT_MAJOR_TYPE, &MFMediaType_Audio)))
return hr;
- if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[2], &MF_MT_SUBTYPE, &MFAudioFormat_PCM)))
return hr;
- if (FAILED(hr = MFCreateStreamDescriptor(0, 3, mediatypes, &sd[0])))
return hr;
- if (FAILED(hr = MFCreateStreamDescriptor(1, 3, mediatypes, &sd[1])))
return hr;
- if (FAILED(hr = MFCreatePresentationDescriptor(2, sd, &pd)))
return hr;
- *descriptor = pd;
- IMFMediaType_Release(mediatypes[0]);
- IMFMediaType_Release(mediatypes[1]);
- IMFMediaType_Release(mediatypes[2]);
- IMFStreamDescriptor_Release(sd[0]);
- IMFStreamDescriptor_Release(sd[1]);
- return S_OK;
+}
You probably don't need this method, you can create descriptor directly in test function.
- hr = IMFTopology_GetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, &enum_src);
- ok(hr == MF_E_ATTRIBUTENOTFOUND, "Attribute should not be set\n.");
It doesn't look that this could ever be set at this point.
- IMFTopologyNode_GetUINT32(src_node, &MF_TOPONODE_CONNECT_METHOD, &method);
- ok(hr == S_OK, "Attribute should be set\n.");
- IMFTopologyNode_SetUINT32(src_node, &MF_TOPONODE_CONNECT_METHOD, method & ~MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES);
- ok(hr == S_OK, "Failed setting attribute %#x\n.", hr);
This does not test return value.
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/mf/tests/mf.c | 3 - dlls/mf/topology.c | 337 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 321 insertions(+), 19 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 1a762c6874..4ecd928970 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -1418,7 +1418,6 @@ static void test_topology_loader(void)
/* Empty topology */ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); -todo_wine ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
hr = MFCreateSourceResolver(&resolver); @@ -1463,7 +1462,6 @@ todo_wine
/* Source node only. */ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); -todo_wine ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
/* Add grabber sink. */ @@ -1489,7 +1487,6 @@ todo_wine ok(hr == S_OK, "Failed to add sink node, hr %#x.\n", hr);
hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); -todo_wine ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
hr = IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0); diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index 0b4d734442..7a4c95bea0 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -1913,47 +1913,352 @@ static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface) return refcount; }
+static void topology_loader_add_branch(struct topology *topology, IMFTopologyNode *first, IMFTopologyNode *last) +{ + IMFTopology *full_topo = &topology->IMFTopology_iface; + IMFTopologyNode *in, *out; + DWORD index; + + in = first; + IMFTopology_AddNode(full_topo, in); + while (SUCCEEDED(IMFTopologyNode_GetOutput(in, 0, &out, &index))) + { + IMFTopology_AddNode(full_topo, out); + in = out; + } +} + +static HRESULT topology_loader_resolve_branch(IMFTopologyNode *src, IMFMediaType *mediatype, IMFTopologyNode *sink, MF_CONNECT_METHOD method) +{ + IMFStreamSink *streamsink; + IMFMediaTypeHandler *mth; + HRESULT hr; + + IMFTopologyNode_GetObject(sink, (IUnknown **)&streamsink); + IMFStreamSink_GetMediaTypeHandler(streamsink, &mth); + if (method == MF_CONNECT_DIRECT) + { + if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, mediatype))) + return hr; + hr = IMFTopologyNode_ConnectOutput(src, 0, sink, 0); + return hr; + } + else + { + IMFTopologyNode *node_dec, *node_conv; + GUID major_type, subtype, mft_category; + MFT_REGISTER_TYPE_INFO mft_typeinfo; + UINT32 flags = MFT_ENUM_FLAG_ALL; + IMFActivate **activates_decs; + UINT32 num_activates_decs; + int i, j; + + IMFMediaType_GetGUID(mediatype, &MF_MT_MAJOR_TYPE, &major_type); + if (IsEqualGUID(&major_type, &MFMediaType_Audio)) + mft_category = MFT_CATEGORY_AUDIO_DECODER; + else if (IsEqualGUID(&major_type, &MFMediaType_Video)) + mft_category = MFT_CATEGORY_VIDEO_DECODER; + else + return MF_E_INVALIDMEDIATYPE; + + IMFMediaType_GetGUID(mediatype, &MF_MT_SUBTYPE, &subtype); + mft_typeinfo.guidMajorType = major_type; + mft_typeinfo.guidSubtype = subtype; + MFTEnumEx(mft_category, flags, &mft_typeinfo, NULL, &activates_decs, &num_activates_decs); + + /* for getting converters later on */ + if (IsEqualGUID(&major_type, &MFMediaType_Audio)) + mft_category = MFT_CATEGORY_AUDIO_EFFECT; + else if (IsEqualGUID(&major_type, &MFMediaType_Video)) + mft_category = MFT_CATEGORY_VIDEO_EFFECT; + + /* + * Iterate over number of decoders. + * Try to set input type on decoder with source's output media type. + * If succeeds, iterate over decoder's output media types. + * Try to set input type on sink with decoder's output media type. + * If fails, iterate over number of converters. + * Try to set input type on converter with decoder's output media type. + * If succeeds, iterate over converters output media types. + * Try to set input type on sink with converter's output media type. + */ + for (i = 0; i < num_activates_decs; i++) + { + IMFTransform *decoder; + + IMFActivate_ActivateObject(activates_decs[i], &IID_IMFTransform, (void **)&decoder); + if (SUCCEEDED(hr = IMFTransform_SetInputType(decoder, 0, mediatype, 0))) + { + UINT32 num_activates_convs; + IMFActivate **activates_convs; + IMFMediaType *decoder_mtype; + + int count = 0; + while (SUCCEEDED(IMFTransform_GetOutputAvailableType(decoder, 0, count++, &decoder_mtype))) + { + IMFTransform *converter; + + /* succeeded with source -> decoder -> sink */ + if (SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(mth, decoder_mtype))) + { + MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_dec); + IMFTopologyNode_SetObject(node_dec, (IUnknown *)decoder); + IMFTopologyNode_ConnectOutput(src, 0, node_dec, 0); + IMFTopologyNode_ConnectOutput(node_dec, 0, sink, 0); + + IMFActivate_ShutdownObject(activates_convs[i]); + return S_OK; + } + + IMFMediaType_GetGUID(decoder_mtype, &MF_MT_SUBTYPE, &subtype); + mft_typeinfo.guidSubtype = subtype; + MFTEnumEx(mft_category, flags, &mft_typeinfo, NULL, &activates_convs, &num_activates_convs); + for (j = 0; j < num_activates_convs; j++) + { + IMFMediaType *converter_mtype; + + IMFActivate_ActivateObject(activates_convs[j], &IID_IMFTransform, (void **)&converter); + if (SUCCEEDED(IMFTransform_SetInputType(converter, 0, decoder_mtype, 0))) + { + int count = 0; + while (SUCCEEDED(IMFTransform_GetOutputAvailableType(converter, 0, count++, &converter_mtype))) + { + /* succeeded with source -> decoder -> converter -> sink */ + if (SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(mth, converter_mtype))) + { + MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_dec); + IMFTopologyNode_SetObject(node_dec, (IUnknown *)decoder); + MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_conv); + IMFTopologyNode_SetObject(node_conv, (IUnknown *)converter); + IMFTopologyNode_ConnectOutput(src, 0, node_dec, 0); + IMFTopologyNode_ConnectOutput(node_dec, 0, node_conv, 0); + IMFTopologyNode_ConnectOutput(node_conv, 0, sink, 0); + + IMFActivate_ShutdownObject(activates_convs[j]); + IMFActivate_ShutdownObject(activates_decs[i]); + return S_OK; + } + } + } + IMFActivate_ShutdownObject(activates_convs[j]); + } + } + } + IMFActivate_ShutdownObject(activates_decs[i]); + } + } + return E_FAIL; +} + +static HRESULT topology_loader_resolve_partial_topology(struct topology_node *src, struct topology_node *sink, struct topology *topology, struct topology **full_topology) +{ + IMFMediaTypeHandler *mth_src, *mth_sink; + IMFTopologyNode *clone_src, *clone_sink; + UINT32 method, enum_src_types, streamid; + IMFMediaType **src_mediatypes; + IMFStreamDescriptor *desc; + IMFAttributes *attrs_src; + IMFStreamSink *strm_sink; + IMFMediaType *mtype_src; + DWORD num_media_types; + HRESULT hr; + int i; + + attrs_src = src->attributes; + if (FAILED(hr = IMFAttributes_GetUnknown(attrs_src, &MF_TOPONODE_STREAM_DESCRIPTOR, &IID_IMFStreamDescriptor, (void **)&desc))) + return hr; + strm_sink = (IMFStreamSink *)sink->object; + + if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(desc, &mth_src))) + { + IMFStreamDescriptor_Release(desc); + return hr; + } + if (FAILED(hr = IMFStreamSink_GetMediaTypeHandler(strm_sink, &mth_sink))) + { + IMFStreamDescriptor_Release(desc); + IMFMediaTypeHandler_Release(mth_src); + return hr; + } + + hr = IMFTopology_GetUINT32(&topology->IMFTopology_iface, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, &enum_src_types); + + mtype_src = NULL; + if (FAILED(hr) || !enum_src_types) + { + num_media_types = 1; + enum_src_types = 0; + if (FAILED(hr = IMFMediaTypeHandler_GetCurrentMediaType(mth_src, &mtype_src))) + if (FAILED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth_src, 0, &mtype_src))) + { + IMFMediaTypeHandler_Release(mth_src); + IMFMediaTypeHandler_Release(mth_sink); + IMFStreamDescriptor_Release(desc); + return hr; + } + } + else + IMFMediaTypeHandler_GetMediaTypeCount(mth_src, &num_media_types); + + src_mediatypes = heap_alloc(sizeof(IMFMediaType *) * num_media_types); + + if (mtype_src) + src_mediatypes[0] = mtype_src; + else + for (i = 0; i < num_media_types; i++) + IMFMediaTypeHandler_GetMediaTypeByIndex(mth_src, i, &src_mediatypes[i]); + + + MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &clone_src); + MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &clone_sink); + IMFTopologyNode_CloneFrom(clone_src, &src->IMFTopologyNode_iface); + IMFTopologyNode_CloneFrom(clone_sink, &sink->IMFTopologyNode_iface); + + if (FAILED(IMFTopologyNode_GetUINT32(clone_sink, &MF_TOPONODE_STREAMID, &streamid))) + IMFTopologyNode_SetUINT32(clone_sink, &MF_TOPONODE_STREAMID, 0); + + if (enum_src_types) + { + hr = IMFAttributes_GetUINT32(attrs_src, &MF_TOPONODE_CONNECT_METHOD, &method); + if (hr == S_OK && method != MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES) + { + for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++) + for (i = 0; i < num_media_types; i++) + if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[i], clone_sink, method))) + { + topology_loader_add_branch(*full_topology, clone_src, clone_sink); + heap_free(src_mediatypes); + return S_OK; + } + } + else + { + for (i = 0; i < num_media_types; i++) + for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++) + if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[i], clone_sink, method))) + { + topology_loader_add_branch(*full_topology, clone_src, clone_sink); + heap_free(src_mediatypes); + return S_OK; + } + } + } + else + { + if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[0], clone_sink, MF_CONNECT_DIRECT))) + { + topology_loader_add_branch(*full_topology, clone_src, clone_sink); + heap_free(src_mediatypes); + return S_OK; + } + } + + heap_free(src_mediatypes); + return MF_E_TOPO_UNSUPPORTED; +} + static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology, IMFTopology **output_topology, IMFTopology *current_topology) { struct topology *topology = unsafe_impl_from_IMFTopology(input_topology); + struct topology_node *(*node_pairs)[2]; + int num_connections; IMFStreamSink *sink; HRESULT hr; - size_t i; + int i, idx;
FIXME("%p, %p, %p, %p.\n", iface, input_topology, output_topology, current_topology);
if (current_topology) FIXME("Current topology instance is ignored.\n");
+ if (!topology || topology->nodes.count < 2) + return MF_E_TOPO_UNSUPPORTED; + + num_connections = 0; + for (i = 0; i < topology->nodes.count; i++) + { + struct topology_node *node = topology->nodes.nodes[i]; + + if (node->node_type == MF_TOPOLOGY_SOURCESTREAM_NODE) + { + if (node->outputs.count && node->outputs.streams->connection) + num_connections++; + } + } + + if (!num_connections) + return MF_E_TOPO_UNSUPPORTED; + + node_pairs = heap_alloc_zero(sizeof(struct topology_node *[2]) * num_connections); + + idx = 0; for (i = 0; i < topology->nodes.count; ++i) { struct topology_node *node = topology->nodes.nodes[i];
- switch (node->node_type) + if (node->node_type == MF_TOPOLOGY_SOURCESTREAM_NODE) { - case MF_TOPOLOGY_OUTPUT_NODE: - if (node->object) + if (node->outputs.count && node->outputs.streams->connection) + { + node_pairs[idx][0] = node; + if (node->outputs.streams->connection->node_type == MF_TOPOLOGY_TRANSFORM_NODE) { - /* Sinks must be bound beforehand. */ - if (FAILED(IUnknown_QueryInterface(node->object, &IID_IMFStreamSink, (void **)&sink))) - return MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED; - IMFStreamSink_Release(sink); + struct topology_node *sink = node->outputs.streams->connection; + + while (sink && sink->node_type != MF_TOPOLOGY_OUTPUT_NODE && sink->outputs.count) + sink = sink->outputs.streams->connection; + if (!sink || !sink->outputs.count) + { + FIXME("Check for MF_CONNECT_AS_OPTIONAL and MF_CONNECT_AS_OPTIONAL_BRANCH flags.\n"); + heap_free(node_pairs); + return MF_E_TOPO_UNSUPPORTED; + } + node_pairs[idx][1] = sink; } - break; - case MF_TOPOLOGY_SOURCESTREAM_NODE: - if (FAILED(hr = IMFAttributes_GetItem(node->attributes, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL))) - return hr; - break; - default: - ; + else if (node->outputs.streams->connection->node_type == MF_TOPOLOGY_OUTPUT_NODE) + node_pairs[idx][1] = node->outputs.streams->connection; + else { + FIXME("Tee nodes currently unhandled.\n"); + heap_free(node_pairs); + return MF_E_TOPO_UNSUPPORTED; + } + idx++; + } } }
+ /* all sinks must be activated */ + for (i = 0; i < num_connections; i++) + { + if (FAILED(IUnknown_QueryInterface(node_pairs[i][1]->object, &IID_IMFStreamSink, (void **)&sink))) + { + FIXME("Check for MF_CONNECT_AS_OPTIONAL and MF_CONNECT_AS_OPTIONAL_BRANCH flags.\n"); + heap_free(node_pairs); + return MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED; + } + IMFStreamSink_Release(sink); + } + if (FAILED(hr = MFCreateTopology(output_topology))) return hr;
- return IMFTopology_CloneFrom(*output_topology, input_topology); + /* resolve each branch */ + for (i = 0; i < num_connections; i++) + { + struct topology_node *src = node_pairs[i][0]; + struct topology_node *sink = node_pairs[i][1]; + struct topology *full_topology = unsafe_impl_from_IMFTopology(*output_topology); + + if (FAILED(hr = topology_loader_resolve_partial_topology(src, sink, topology, &full_topology))) + { + heap_free(node_pairs); + return hr; + } + } + + heap_free(node_pairs); + return S_OK; }
static const IMFTopoLoaderVtbl topologyloadervtbl =
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=68731
Your paranoid android.
=== w1064v1809_zh_CN (32 bit report) ===
mf: mf: Timeout
=== w1064v1809_zh_CN (testbot log) ===
The task timed out
On 4/1/20 4:11 PM, Sergio Gómez Del Real wrote:
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com
dlls/mf/tests/mf.c | 3 - dlls/mf/topology.c | 337 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 321 insertions(+), 19 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 1a762c6874..4ecd928970 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -1418,7 +1418,6 @@ static void test_topology_loader(void)
/* Empty topology */ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
-todo_wine ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
hr = MFCreateSourceResolver(&resolver);
@@ -1463,7 +1462,6 @@ todo_wine
/* Source node only. */ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
-todo_wine ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
/* Add grabber sink. */
@@ -1489,7 +1487,6 @@ todo_wine ok(hr == S_OK, "Failed to add sink node, hr %#x.\n", hr);
hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
-todo_wine ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
hr = IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0);
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index 0b4d734442..7a4c95bea0 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -1913,47 +1913,352 @@ static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface) return refcount; }
+static void topology_loader_add_branch(struct topology *topology, IMFTopologyNode *first, IMFTopologyNode *last) +{
- IMFTopology *full_topo = &topology->IMFTopology_iface;
- IMFTopologyNode *in, *out;
- DWORD index;
- in = first;
- IMFTopology_AddNode(full_topo, in);
- while (SUCCEEDED(IMFTopologyNode_GetOutput(in, 0, &out, &index)))
- {
IMFTopology_AddNode(full_topo, out);
in = out;
- }
+}
+static HRESULT topology_loader_resolve_branch(IMFTopologyNode *src, IMFMediaType *mediatype, IMFTopologyNode *sink, MF_CONNECT_METHOD method) +{
- IMFStreamSink *streamsink;
- IMFMediaTypeHandler *mth;
- HRESULT hr;
- IMFTopologyNode_GetObject(sink, (IUnknown **)&streamsink);
- IMFStreamSink_GetMediaTypeHandler(streamsink, &mth);
- if (method == MF_CONNECT_DIRECT)
- {
if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, mediatype)))
return hr;
hr = IMFTopologyNode_ConnectOutput(src, 0, sink, 0);
return hr;
- }
- else
- {
IMFTopologyNode *node_dec, *node_conv;
GUID major_type, subtype, mft_category;
MFT_REGISTER_TYPE_INFO mft_typeinfo;
UINT32 flags = MFT_ENUM_FLAG_ALL;
IMFActivate **activates_decs;
UINT32 num_activates_decs;
int i, j;
IMFMediaType_GetGUID(mediatype, &MF_MT_MAJOR_TYPE, &major_type);
if (IsEqualGUID(&major_type, &MFMediaType_Audio))
mft_category = MFT_CATEGORY_AUDIO_DECODER;
else if (IsEqualGUID(&major_type, &MFMediaType_Video))
mft_category = MFT_CATEGORY_VIDEO_DECODER;
else
return MF_E_INVALIDMEDIATYPE;
IMFMediaType_GetGUID(mediatype, &MF_MT_SUBTYPE, &subtype);
mft_typeinfo.guidMajorType = major_type;
mft_typeinfo.guidSubtype = subtype;
MFTEnumEx(mft_category, flags, &mft_typeinfo, NULL, &activates_decs, &num_activates_decs);
/* for getting converters later on */
if (IsEqualGUID(&major_type, &MFMediaType_Audio))
mft_category = MFT_CATEGORY_AUDIO_EFFECT;
else if (IsEqualGUID(&major_type, &MFMediaType_Video))
mft_category = MFT_CATEGORY_VIDEO_EFFECT;
/*
* Iterate over number of decoders.
* Try to set input type on decoder with source's output media type.
* If succeeds, iterate over decoder's output media types.
* Try to set input type on sink with decoder's output media type.
* If fails, iterate over number of converters.
* Try to set input type on converter with decoder's output media type.
* If succeeds, iterate over converters output media types.
* Try to set input type on sink with converter's output media type.
*/
for (i = 0; i < num_activates_decs; i++)
{
IMFTransform *decoder;
IMFActivate_ActivateObject(activates_decs[i], &IID_IMFTransform, (void **)&decoder);
if (SUCCEEDED(hr = IMFTransform_SetInputType(decoder, 0, mediatype, 0)))
{
UINT32 num_activates_convs;
IMFActivate **activates_convs;
IMFMediaType *decoder_mtype;
int count = 0;
while (SUCCEEDED(IMFTransform_GetOutputAvailableType(decoder, 0, count++, &decoder_mtype)))
{
IMFTransform *converter;
/* succeeded with source -> decoder -> sink */
if (SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(mth, decoder_mtype)))
{
MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_dec);
IMFTopologyNode_SetObject(node_dec, (IUnknown *)decoder);
IMFTopologyNode_ConnectOutput(src, 0, node_dec, 0);
IMFTopologyNode_ConnectOutput(node_dec, 0, sink, 0);
IMFActivate_ShutdownObject(activates_convs[i]);
Shouldn't this be activates_decs?
return S_OK;
}
IMFMediaType_GetGUID(decoder_mtype, &MF_MT_SUBTYPE, &subtype);
mft_typeinfo.guidSubtype = subtype;
MFTEnumEx(mft_category, flags, &mft_typeinfo, NULL, &activates_convs, &num_activates_convs);
for (j = 0; j < num_activates_convs; j++)
{
IMFMediaType *converter_mtype;
IMFActivate_ActivateObject(activates_convs[j], &IID_IMFTransform, (void **)&converter);
if (SUCCEEDED(IMFTransform_SetInputType(converter, 0, decoder_mtype, 0)))
{
int count = 0;
while (SUCCEEDED(IMFTransform_GetOutputAvailableType(converter, 0, count++, &converter_mtype)))
{
/* succeeded with source -> decoder -> converter -> sink */
if (SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(mth, converter_mtype)))
{
MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_dec);
IMFTopologyNode_SetObject(node_dec, (IUnknown *)decoder);
MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_conv);
IMFTopologyNode_SetObject(node_conv, (IUnknown *)converter);
IMFTopologyNode_ConnectOutput(src, 0, node_dec, 0);
IMFTopologyNode_ConnectOutput(node_dec, 0, node_conv, 0);
IMFTopologyNode_ConnectOutput(node_conv, 0, sink, 0);
IMFActivate_ShutdownObject(activates_convs[j]);
IMFActivate_ShutdownObject(activates_decs[i]);
return S_OK;
}
}
}
IMFActivate_ShutdownObject(activates_convs[j]);
}
}
}
IMFActivate_ShutdownObject(activates_decs[i]);
}
- }
- return E_FAIL;
+}
+static HRESULT topology_loader_resolve_partial_topology(struct topology_node *src, struct topology_node *sink, struct topology *topology, struct topology **full_topology) +{
- IMFMediaTypeHandler *mth_src, *mth_sink;
- IMFTopologyNode *clone_src, *clone_sink;
- UINT32 method, enum_src_types, streamid;
- IMFMediaType **src_mediatypes;
- IMFStreamDescriptor *desc;
- IMFAttributes *attrs_src;
- IMFStreamSink *strm_sink;
- IMFMediaType *mtype_src;
- DWORD num_media_types;
- HRESULT hr;
- int i;
- attrs_src = src->attributes;
- if (FAILED(hr = IMFAttributes_GetUnknown(attrs_src, &MF_TOPONODE_STREAM_DESCRIPTOR, &IID_IMFStreamDescriptor, (void **)&desc)))
return hr;
- strm_sink = (IMFStreamSink *)sink->object;
- if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(desc, &mth_src)))
- {
IMFStreamDescriptor_Release(desc);
return hr;
- }
- if (FAILED(hr = IMFStreamSink_GetMediaTypeHandler(strm_sink, &mth_sink)))
- {
IMFStreamDescriptor_Release(desc);
IMFMediaTypeHandler_Release(mth_src);
return hr;
- }
- hr = IMFTopology_GetUINT32(&topology->IMFTopology_iface, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, &enum_src_types);
- mtype_src = NULL;
- if (FAILED(hr) || !enum_src_types)
- {
num_media_types = 1;
enum_src_types = 0;
if (FAILED(hr = IMFMediaTypeHandler_GetCurrentMediaType(mth_src, &mtype_src)))
if (FAILED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth_src, 0, &mtype_src)))
{
IMFMediaTypeHandler_Release(mth_src);
IMFMediaTypeHandler_Release(mth_sink);
IMFStreamDescriptor_Release(desc);
return hr;
}
- }
- else
IMFMediaTypeHandler_GetMediaTypeCount(mth_src, &num_media_types);
- src_mediatypes = heap_alloc(sizeof(IMFMediaType *) * num_media_types);
- if (mtype_src)
src_mediatypes[0] = mtype_src;
- else
for (i = 0; i < num_media_types; i++)
IMFMediaTypeHandler_GetMediaTypeByIndex(mth_src, i, &src_mediatypes[i]);
- MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &clone_src);
- MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &clone_sink);
- IMFTopologyNode_CloneFrom(clone_src, &src->IMFTopologyNode_iface);
- IMFTopologyNode_CloneFrom(clone_sink, &sink->IMFTopologyNode_iface);
- if (FAILED(IMFTopologyNode_GetUINT32(clone_sink, &MF_TOPONODE_STREAMID, &streamid)))
IMFTopologyNode_SetUINT32(clone_sink, &MF_TOPONODE_STREAMID, 0);
- if (enum_src_types)
- {
hr = IMFAttributes_GetUINT32(attrs_src, &MF_TOPONODE_CONNECT_METHOD, &method);
if (hr == S_OK && method != MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES)
{
for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++)
for (i = 0; i < num_media_types; i++)
if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[i], clone_sink, method)))
{
topology_loader_add_branch(*full_topology, clone_src, clone_sink);
heap_free(src_mediatypes);
return S_OK;
}
}
else
{
for (i = 0; i < num_media_types; i++)
for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++)
if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[i], clone_sink, method)))
{
topology_loader_add_branch(*full_topology, clone_src, clone_sink);
heap_free(src_mediatypes);
return S_OK;
}
}
- }
- else
- {
if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[0], clone_sink, MF_CONNECT_DIRECT)))
Are you sure we're not supposed to try the various methods here?
{
topology_loader_add_branch(*full_topology, clone_src, clone_sink);
heap_free(src_mediatypes);
return S_OK;
}
- }
- heap_free(src_mediatypes);
- return MF_E_TOPO_UNSUPPORTED;
+}
- static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology, IMFTopology **output_topology, IMFTopology *current_topology) { struct topology *topology = unsafe_impl_from_IMFTopology(input_topology);
- struct topology_node *(*node_pairs)[2];
- int num_connections; IMFStreamSink *sink; HRESULT hr;
- size_t i;
int i, idx;
FIXME("%p, %p, %p, %p.\n", iface, input_topology, output_topology, current_topology);
if (current_topology) FIXME("Current topology instance is ignored.\n");
if (!topology || topology->nodes.count < 2)
return MF_E_TOPO_UNSUPPORTED;
num_connections = 0;
for (i = 0; i < topology->nodes.count; i++)
{
struct topology_node *node = topology->nodes.nodes[i];
if (node->node_type == MF_TOPOLOGY_SOURCESTREAM_NODE)
{
if (node->outputs.count && node->outputs.streams->connection)
num_connections++;
}
}
if (!num_connections)
return MF_E_TOPO_UNSUPPORTED;
node_pairs = heap_alloc_zero(sizeof(struct topology_node *[2]) * num_connections);
idx = 0; for (i = 0; i < topology->nodes.count; ++i) { struct topology_node *node = topology->nodes.nodes[i];
switch (node->node_type)
if (node->node_type == MF_TOPOLOGY_SOURCESTREAM_NODE) {
case MF_TOPOLOGY_OUTPUT_NODE:
if (node->object)
if (node->outputs.count && node->outputs.streams->connection)
{
node_pairs[idx][0] = node;
if (node->outputs.streams->connection->node_type == MF_TOPOLOGY_TRANSFORM_NODE) {
/* Sinks must be bound beforehand. */
if (FAILED(IUnknown_QueryInterface(node->object, &IID_IMFStreamSink, (void **)&sink)))
return MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED;
IMFStreamSink_Release(sink);
struct topology_node *sink = node->outputs.streams->connection;
while (sink && sink->node_type != MF_TOPOLOGY_OUTPUT_NODE && sink->outputs.count)
sink = sink->outputs.streams->connection;
if (!sink || !sink->outputs.count)
{
FIXME("Check for MF_CONNECT_AS_OPTIONAL and MF_CONNECT_AS_OPTIONAL_BRANCH flags.\n");
heap_free(node_pairs);
return MF_E_TOPO_UNSUPPORTED;
}
node_pairs[idx][1] = sink; }
break;
case MF_TOPOLOGY_SOURCESTREAM_NODE:
if (FAILED(hr = IMFAttributes_GetItem(node->attributes, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL)))
return hr;
break;
default:
;
else if (node->outputs.streams->connection->node_type == MF_TOPOLOGY_OUTPUT_NODE)
node_pairs[idx][1] = node->outputs.streams->connection;
else {
FIXME("Tee nodes currently unhandled.\n");
heap_free(node_pairs);
return MF_E_TOPO_UNSUPPORTED;
}
idx++;
} } }
/* all sinks must be activated */
for (i = 0; i < num_connections; i++)
{
if (FAILED(IUnknown_QueryInterface(node_pairs[i][1]->object, &IID_IMFStreamSink, (void **)&sink)))
{
FIXME("Check for MF_CONNECT_AS_OPTIONAL and MF_CONNECT_AS_OPTIONAL_BRANCH flags.\n");
heap_free(node_pairs);
return MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED;
}
IMFStreamSink_Release(sink);
}
if (FAILED(hr = MFCreateTopology(output_topology))) return hr;
- return IMFTopology_CloneFrom(*output_topology, input_topology);
/* resolve each branch */
for (i = 0; i < num_connections; i++)
{
struct topology_node *src = node_pairs[i][0];
struct topology_node *sink = node_pairs[i][1];
struct topology *full_topology = unsafe_impl_from_IMFTopology(*output_topology);
if (FAILED(hr = topology_loader_resolve_partial_topology(src, sink, topology, &full_topology)))
{
heap_free(node_pairs);
return hr;
}
}
heap_free(node_pairs);
return S_OK; }
static const IMFTopoLoaderVtbl topologyloadervtbl =
On 2/04/20 11:07 a. m., Derek Lesho wrote:
On 4/1/20 4:11 PM, Sergio Gómez Del Real wrote:
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com
dlls/mf/tests/mf.c | 3 - dlls/mf/topology.c | 337 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 321 insertions(+), 19 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 1a762c6874..4ecd928970 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -1418,7 +1418,6 @@ static void test_topology_loader(void) /* Empty topology */ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); -todo_wine ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr); hr = MFCreateSourceResolver(&resolver); @@ -1463,7 +1462,6 @@ todo_wine /* Source node only. */ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); -todo_wine ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr); /* Add grabber sink. */ @@ -1489,7 +1487,6 @@ todo_wine ok(hr == S_OK, "Failed to add sink node, hr %#x.\n", hr); hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); -todo_wine ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr); hr = IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0); diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index 0b4d734442..7a4c95bea0 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -1913,47 +1913,352 @@ static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface) return refcount; } +static void topology_loader_add_branch(struct topology *topology, IMFTopologyNode *first, IMFTopologyNode *last) +{ + IMFTopology *full_topo = &topology->IMFTopology_iface; + IMFTopologyNode *in, *out; + DWORD index;
+ in = first; + IMFTopology_AddNode(full_topo, in); + while (SUCCEEDED(IMFTopologyNode_GetOutput(in, 0, &out, &index))) + { + IMFTopology_AddNode(full_topo, out); + in = out; + } +}
+static HRESULT topology_loader_resolve_branch(IMFTopologyNode *src, IMFMediaType *mediatype, IMFTopologyNode *sink, MF_CONNECT_METHOD method) +{ + IMFStreamSink *streamsink; + IMFMediaTypeHandler *mth; + HRESULT hr;
+ IMFTopologyNode_GetObject(sink, (IUnknown **)&streamsink); + IMFStreamSink_GetMediaTypeHandler(streamsink, &mth); + if (method == MF_CONNECT_DIRECT) + { + if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, mediatype))) + return hr; + hr = IMFTopologyNode_ConnectOutput(src, 0, sink, 0); + return hr; + } + else + { + IMFTopologyNode *node_dec, *node_conv; + GUID major_type, subtype, mft_category; + MFT_REGISTER_TYPE_INFO mft_typeinfo; + UINT32 flags = MFT_ENUM_FLAG_ALL; + IMFActivate **activates_decs; + UINT32 num_activates_decs; + int i, j;
+ IMFMediaType_GetGUID(mediatype, &MF_MT_MAJOR_TYPE, &major_type); + if (IsEqualGUID(&major_type, &MFMediaType_Audio)) + mft_category = MFT_CATEGORY_AUDIO_DECODER; + else if (IsEqualGUID(&major_type, &MFMediaType_Video)) + mft_category = MFT_CATEGORY_VIDEO_DECODER; + else + return MF_E_INVALIDMEDIATYPE;
+ IMFMediaType_GetGUID(mediatype, &MF_MT_SUBTYPE, &subtype); + mft_typeinfo.guidMajorType = major_type; + mft_typeinfo.guidSubtype = subtype; + MFTEnumEx(mft_category, flags, &mft_typeinfo, NULL, &activates_decs, &num_activates_decs);
+ /* for getting converters later on */ + if (IsEqualGUID(&major_type, &MFMediaType_Audio)) + mft_category = MFT_CATEGORY_AUDIO_EFFECT; + else if (IsEqualGUID(&major_type, &MFMediaType_Video)) + mft_category = MFT_CATEGORY_VIDEO_EFFECT;
+ /* + * Iterate over number of decoders. + * Try to set input type on decoder with source's output media type. + * If succeeds, iterate over decoder's output media types. + * Try to set input type on sink with decoder's output media type. + * If fails, iterate over number of converters. + * Try to set input type on converter with decoder's output media type. + * If succeeds, iterate over converters output media types. + * Try to set input type on sink with converter's output media type. + */ + for (i = 0; i < num_activates_decs; i++) + { + IMFTransform *decoder;
+ IMFActivate_ActivateObject(activates_decs[i], &IID_IMFTransform, (void **)&decoder); + if (SUCCEEDED(hr = IMFTransform_SetInputType(decoder, 0, mediatype, 0))) + { + UINT32 num_activates_convs; + IMFActivate **activates_convs; + IMFMediaType *decoder_mtype;
+ int count = 0; + while (SUCCEEDED(IMFTransform_GetOutputAvailableType(decoder, 0, count++, &decoder_mtype))) + { + IMFTransform *converter;
+ /* succeeded with source -> decoder -> sink */ + if (SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(mth, decoder_mtype))) + {
- MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_dec);
+ IMFTopologyNode_SetObject(node_dec, (IUnknown *)decoder); + IMFTopologyNode_ConnectOutput(src, 0, node_dec, 0); + IMFTopologyNode_ConnectOutput(node_dec, 0, sink, 0);
- IMFActivate_ShutdownObject(activates_convs[i]);
Shouldn't this be activates_decs?
Yeah... thanks for catching that one.
+ return S_OK; + }
+ IMFMediaType_GetGUID(decoder_mtype, &MF_MT_SUBTYPE, &subtype); + mft_typeinfo.guidSubtype = subtype; + MFTEnumEx(mft_category, flags, &mft_typeinfo, NULL, &activates_convs, &num_activates_convs); + for (j = 0; j < num_activates_convs; j++) + { + IMFMediaType *converter_mtype;
- IMFActivate_ActivateObject(activates_convs[j], &IID_IMFTransform,
(void **)&converter); + if (SUCCEEDED(IMFTransform_SetInputType(converter, 0, decoder_mtype, 0))) + { + int count = 0; + while (SUCCEEDED(IMFTransform_GetOutputAvailableType(converter, 0, count++, &converter_mtype))) + { + /* succeeded with source -> decoder -> converter -> sink */ + if (SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(mth, converter_mtype))) + {
- MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_dec);
- IMFTopologyNode_SetObject(node_dec, (IUnknown *)decoder);
- MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_conv);
- IMFTopologyNode_SetObject(node_conv, (IUnknown *)converter);
- IMFTopologyNode_ConnectOutput(src, 0, node_dec, 0);
- IMFTopologyNode_ConnectOutput(node_dec, 0, node_conv, 0);
- IMFTopologyNode_ConnectOutput(node_conv, 0, sink, 0);
- IMFActivate_ShutdownObject(activates_convs[j]);
- IMFActivate_ShutdownObject(activates_decs[i]);
+ return S_OK; + } + } + }
- IMFActivate_ShutdownObject(activates_convs[j]);
+ } + } + } + IMFActivate_ShutdownObject(activates_decs[i]); + } + } + return E_FAIL; +}
+static HRESULT topology_loader_resolve_partial_topology(struct topology_node *src, struct topology_node *sink, struct topology *topology, struct topology **full_topology) +{ + IMFMediaTypeHandler *mth_src, *mth_sink; + IMFTopologyNode *clone_src, *clone_sink; + UINT32 method, enum_src_types, streamid; + IMFMediaType **src_mediatypes; + IMFStreamDescriptor *desc; + IMFAttributes *attrs_src; + IMFStreamSink *strm_sink; + IMFMediaType *mtype_src; + DWORD num_media_types; + HRESULT hr; + int i;
+ attrs_src = src->attributes; + if (FAILED(hr = IMFAttributes_GetUnknown(attrs_src, &MF_TOPONODE_STREAM_DESCRIPTOR, &IID_IMFStreamDescriptor, (void **)&desc))) + return hr; + strm_sink = (IMFStreamSink *)sink->object;
+ if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(desc, &mth_src))) + { + IMFStreamDescriptor_Release(desc); + return hr; + } + if (FAILED(hr = IMFStreamSink_GetMediaTypeHandler(strm_sink, &mth_sink))) + { + IMFStreamDescriptor_Release(desc); + IMFMediaTypeHandler_Release(mth_src); + return hr; + }
+ hr = IMFTopology_GetUINT32(&topology->IMFTopology_iface, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, &enum_src_types);
+ mtype_src = NULL; + if (FAILED(hr) || !enum_src_types) + { + num_media_types = 1; + enum_src_types = 0; + if (FAILED(hr = IMFMediaTypeHandler_GetCurrentMediaType(mth_src, &mtype_src))) + if (FAILED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth_src, 0, &mtype_src))) + { + IMFMediaTypeHandler_Release(mth_src); + IMFMediaTypeHandler_Release(mth_sink); + IMFStreamDescriptor_Release(desc); + return hr; + } + } + else + IMFMediaTypeHandler_GetMediaTypeCount(mth_src, &num_media_types);
+ src_mediatypes = heap_alloc(sizeof(IMFMediaType *) * num_media_types);
+ if (mtype_src) + src_mediatypes[0] = mtype_src; + else + for (i = 0; i < num_media_types; i++) + IMFMediaTypeHandler_GetMediaTypeByIndex(mth_src, i, &src_mediatypes[i]);
+ MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &clone_src); + MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &clone_sink); + IMFTopologyNode_CloneFrom(clone_src, &src->IMFTopologyNode_iface); + IMFTopologyNode_CloneFrom(clone_sink, &sink->IMFTopologyNode_iface);
+ if (FAILED(IMFTopologyNode_GetUINT32(clone_sink, &MF_TOPONODE_STREAMID, &streamid))) + IMFTopologyNode_SetUINT32(clone_sink, &MF_TOPONODE_STREAMID, 0);
+ if (enum_src_types) + { + hr = IMFAttributes_GetUINT32(attrs_src, &MF_TOPONODE_CONNECT_METHOD, &method); + if (hr == S_OK && method != MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES) + { + for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++) + for (i = 0; i < num_media_types; i++) + if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[i], clone_sink, method))) + {
- topology_loader_add_branch(*full_topology, clone_src, clone_sink);
+ heap_free(src_mediatypes); + return S_OK; + } + } + else + { + for (i = 0; i < num_media_types; i++) + for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++) + if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[i], clone_sink, method))) + {
- topology_loader_add_branch(*full_topology, clone_src, clone_sink);
+ heap_free(src_mediatypes); + return S_OK; + } + } + } + else + { + if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[0], clone_sink, MF_CONNECT_DIRECT)))
Are you sure we're not supposed to try the various methods here?
Yeah. I changed this to test something and forgot to change it back. Thanks :)
+ { + topology_loader_add_branch(*full_topology, clone_src, clone_sink); + heap_free(src_mediatypes); + return S_OK; + } + }
+ heap_free(src_mediatypes); + return MF_E_TOPO_UNSUPPORTED; +}
static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology, IMFTopology **output_topology, IMFTopology *current_topology) { struct topology *topology = unsafe_impl_from_IMFTopology(input_topology); + struct topology_node *(*node_pairs)[2]; + int num_connections; IMFStreamSink *sink; HRESULT hr; - size_t i; + int i, idx; FIXME("%p, %p, %p, %p.\n", iface, input_topology, output_topology, current_topology); if (current_topology) FIXME("Current topology instance is ignored.\n"); + if (!topology || topology->nodes.count < 2) + return MF_E_TOPO_UNSUPPORTED;
+ num_connections = 0; + for (i = 0; i < topology->nodes.count; i++) + { + struct topology_node *node = topology->nodes.nodes[i];
+ if (node->node_type == MF_TOPOLOGY_SOURCESTREAM_NODE) + { + if (node->outputs.count && node->outputs.streams->connection) + num_connections++; + } + }
+ if (!num_connections) + return MF_E_TOPO_UNSUPPORTED;
+ node_pairs = heap_alloc_zero(sizeof(struct topology_node *[2]) * num_connections);
+ idx = 0; for (i = 0; i < topology->nodes.count; ++i) { struct topology_node *node = topology->nodes.nodes[i]; - switch (node->node_type) + if (node->node_type == MF_TOPOLOGY_SOURCESTREAM_NODE) { - case MF_TOPOLOGY_OUTPUT_NODE: - if (node->object) + if (node->outputs.count && node->outputs.streams->connection) + { + node_pairs[idx][0] = node; + if (node->outputs.streams->connection->node_type == MF_TOPOLOGY_TRANSFORM_NODE) { - /* Sinks must be bound beforehand. */ - if (FAILED(IUnknown_QueryInterface(node->object, &IID_IMFStreamSink, (void **)&sink))) - return MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED; - IMFStreamSink_Release(sink); + struct topology_node *sink = node->outputs.streams->connection;
+ while (sink && sink->node_type != MF_TOPOLOGY_OUTPUT_NODE && sink->outputs.count) + sink = sink->outputs.streams->connection; + if (!sink || !sink->outputs.count) + { + FIXME("Check for MF_CONNECT_AS_OPTIONAL and MF_CONNECT_AS_OPTIONAL_BRANCH flags.\n"); + heap_free(node_pairs); + return MF_E_TOPO_UNSUPPORTED; + } + node_pairs[idx][1] = sink; } - break; - case MF_TOPOLOGY_SOURCESTREAM_NODE: - if (FAILED(hr = IMFAttributes_GetItem(node->attributes, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL))) - return hr; - break; - default: - ; + else if (node->outputs.streams->connection->node_type == MF_TOPOLOGY_OUTPUT_NODE) + node_pairs[idx][1] = node->outputs.streams->connection; + else { + FIXME("Tee nodes currently unhandled.\n"); + heap_free(node_pairs); + return MF_E_TOPO_UNSUPPORTED; + } + idx++; + } } } + /* all sinks must be activated */ + for (i = 0; i < num_connections; i++) + { + if (FAILED(IUnknown_QueryInterface(node_pairs[i][1]->object, &IID_IMFStreamSink, (void **)&sink))) + { + FIXME("Check for MF_CONNECT_AS_OPTIONAL and MF_CONNECT_AS_OPTIONAL_BRANCH flags.\n"); + heap_free(node_pairs); + return MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED; + } + IMFStreamSink_Release(sink); + }
if (FAILED(hr = MFCreateTopology(output_topology))) return hr; - return IMFTopology_CloneFrom(*output_topology, input_topology); + /* resolve each branch */ + for (i = 0; i < num_connections; i++) + { + struct topology_node *src = node_pairs[i][0]; + struct topology_node *sink = node_pairs[i][1]; + struct topology *full_topology = unsafe_impl_from_IMFTopology(*output_topology);
+ if (FAILED(hr = topology_loader_resolve_partial_topology(src, sink, topology, &full_topology))) + { + heap_free(node_pairs); + return hr; + } + }
+ heap_free(node_pairs); + return S_OK; } static const IMFTopoLoaderVtbl topologyloadervtbl =
On 4/2/20 12:11 AM, Sergio Gómez Del Real wrote:
+static void topology_loader_add_branch(struct topology *topology, IMFTopologyNode *first, IMFTopologyNode *last) +{
- IMFTopology *full_topo = &topology->IMFTopology_iface;
- IMFTopologyNode *in, *out;
- DWORD index;
- in = first;
- IMFTopology_AddNode(full_topo, in);
- while (SUCCEEDED(IMFTopologyNode_GetOutput(in, 0, &out, &index)))
- {
IMFTopology_AddNode(full_topo, out);
in = out;
- }
+}
Second node argument is not used, is that intentional? It also leaks on every iteration. I'm surprised it works, that you can connect nodes before adding them, and then have a situation when one is added and has a connection to another that isn't yet.
It also assumes that all nodes are 1-1 for i/o count, which is reasonable, but we'll need a fixme for unsupported cases. Obviously not in this helper.
+static HRESULT topology_loader_resolve_branch(IMFTopologyNode *src, IMFMediaType *mediatype, IMFTopologyNode *sink, MF_CONNECT_METHOD method) +{
- IMFStreamSink *streamsink;
- IMFMediaTypeHandler *mth;
- HRESULT hr;
- IMFTopologyNode_GetObject(sink, (IUnknown **)&streamsink);
- IMFStreamSink_GetMediaTypeHandler(streamsink, &mth);
- if (method == MF_CONNECT_DIRECT)
- {
if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, mediatype)))
return hr;
hr = IMFTopologyNode_ConnectOutput(src, 0, sink, 0);
return hr;
- }
- else
Is it checked anywhere that types are actually compatible? Also, this function only checks for DIRECT mode, what's a point of iterating over all methods when it's called?
/* for getting converters later on */
if (IsEqualGUID(&major_type, &MFMediaType_Audio))
mft_category = MFT_CATEGORY_AUDIO_EFFECT;
else if (IsEqualGUID(&major_type, &MFMediaType_Video))
mft_category = MFT_CATEGORY_VIDEO_EFFECT;
You have similar condition right above that one. I think you can ignore that for now and assume we only need decoders.
for (i = 0; i < num_activates_decs; i++)
{
IMFTransform *decoder;
IMFActivate_ActivateObject(activates_decs[i], &IID_IMFTransform, (void **)&decoder);
This definitely needs some error handling.
/* succeeded with source -> decoder -> sink */
if (SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(mth, decoder_mtype)))
{
MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_dec);
IMFTopologyNode_SetObject(node_dec, (IUnknown *)decoder);
IMFTopologyNode_ConnectOutput(src, 0, node_dec, 0);
IMFTopologyNode_ConnectOutput(node_dec, 0, sink, 0);
IMFActivate_ShutdownObject(activates_convs[i]);
return S_OK;
}
You need to set decoder output type as well, and shutting it down looks, even if it works. Is it possible loader stashes activator in some attribute? Or maybe it sets IMFActivate as object itself, and pre-activates it. Or maybe loader does not use it at all and keeps using CLSIDs. Conceptually after loader did its job it should still be possible to shut down.
topology_loader_resolve_branch() has a lot of leaks, for example you should free returned IMFActivate arrays.
- MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &clone_src);
- MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &clone_sink);
- IMFTopologyNode_CloneFrom(clone_src, &src->IMFTopologyNode_iface);
- IMFTopologyNode_CloneFrom(clone_sink, &sink->IMFTopologyNode_iface);
- if (FAILED(IMFTopologyNode_GetUINT32(clone_sink, &MF_TOPONODE_STREAMID, &streamid)))
IMFTopologyNode_SetUINT32(clone_sink, &MF_TOPONODE_STREAMID, 0);
I would prefer to clone whole topology first, and do all necessary fixups.
- if (enum_src_types)
- {
hr = IMFAttributes_GetUINT32(attrs_src, &MF_TOPONODE_CONNECT_METHOD, &method);
if (hr == S_OK && method != MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES)
{
for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++)
for (i = 0; i < num_media_types; i++)
if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[i], clone_sink, method)))
{
topology_loader_add_branch(*full_topology, clone_src, clone_sink);
heap_free(src_mediatypes);
return S_OK;
}
}
else
{
for (i = 0; i < num_media_types; i++)
for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++)
if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[i], clone_sink, method)))
{
topology_loader_add_branch(*full_topology, clone_src, clone_sink);
heap_free(src_mediatypes);
return S_OK;
}
}
- }
- else
- {
if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[0], clone_sink, MF_CONNECT_DIRECT)))
{
topology_loader_add_branch(*full_topology, clone_src, clone_sink);
heap_free(src_mediatypes);
return S_OK;
}
- }
'enum_src_types' should only control if all supported output types are considered, and not just current, so why false branch is using DIRECT? I'd expect you still might want a decoder.
I would suggest to split this patch as much as possible. It's hard to see the whole picture, but so far I have a feeling that assuming that you need to resolve from source to sink all the time is not sustainable. For example if partial topology already has decoders for some branches that won't apply. More general approach of resolving from input to output might be better, for example taking sink media type, comparing to upstream peer, regardless of node types.