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();
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 =