Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/mf/tests/mf.c | 570 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 501 insertions(+), 69 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index c79ae69f91..a92f183096 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -32,6 +32,7 @@ DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); DEFINE_GUID(MFVideoFormat_P208, 0x38303250, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); DEFINE_GUID(MFVideoFormat_ABGR32, 0x00000020, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +DEFINE_GUID(MFAudioFormat_ZZZ, 0x20202020, 0x2020, 0x2020, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20);
#undef INITGUID #include <guiddef.h> @@ -54,34 +55,6 @@ static void _expect_ref(IUnknown* obj, ULONG expected_refcount, int line) expected_refcount); }
-static WCHAR *load_resource(const WCHAR *name) -{ - static WCHAR pathW[MAX_PATH]; - DWORD written; - HANDLE file; - HRSRC res; - void *ptr; - - GetTempPathW(ARRAY_SIZE(pathW), pathW); - lstrcatW(pathW, name); - - file = CreateFileW(pathW, GENERIC_READ|GENERIC_WRITE, 0, - NULL, CREATE_ALWAYS, 0, 0); - ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %d\n", - wine_dbgstr_w(pathW), GetLastError()); - - res = FindResourceW(NULL, name, (LPCWSTR)RT_RCDATA); - ok(res != 0, "couldn't find resource\n"); - ptr = LockResource(LoadResource(GetModuleHandleA(NULL), res)); - WriteFile(file, ptr, SizeofResource(GetModuleHandleA(NULL), res), - &written, NULL); - ok(written == SizeofResource(GetModuleHandleA(NULL), res), - "couldn't write resource\n" ); - CloseHandle(file); - - return pathW; -} - static HRESULT WINAPI test_unk_QueryInterface(IUnknown *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IUnknown)) @@ -1391,27 +1364,367 @@ 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) +{ + return E_NOTIMPL; +} + +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 HRESULT WINAPI test_mft_generic_QueryInterface(IMFTransform *iface, REFIID riid, void **out) +{ + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMFTransform)) + { + *out = iface; + IUnknown_AddRef((IUnknown*)*out); + return S_OK; + } + + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_mft_generic_AddRef(IMFTransform *iface) +{ + return 2; +} + +static ULONG WINAPI test_mft_generic_Release(IMFTransform *iface) +{ + return 1; +} + +static HRESULT WINAPI test_mft_generic_GetStreamLimits(IMFTransform *iface, DWORD *inputmin, DWORD *inputmax, DWORD *outputmin, DWORD *outputmax) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_mft_generic_GetStreamCount(IMFTransform *iface, DWORD *input_streams, DWORD *output_streams) +{ + *input_streams = 1; + *output_streams = 1; + return S_OK; +} + +static HRESULT WINAPI test_mft_generic_GetStreamIDs(IMFTransform *iface, DWORD inputidsize, DWORD *inputids, DWORD outputidsize, DWORD *outputids) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_mft_generic_GetInputStreamInfo(IMFTransform *iface, DWORD inputstream, MFT_INPUT_STREAM_INFO *streaminfo) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_mft_generic_GetOutputStreamInfo(IMFTransform *iface, DWORD outputstream, MFT_OUTPUT_STREAM_INFO *streaminfo) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_mft_generic_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_mft_generic_GetInputStreamAttributes(IMFTransform *iface, DWORD inputstream, IMFAttributes **attributes) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_mft_generic_GetOutputStreamAttributes(IMFTransform *iface, DWORD outputstream, IMFAttributes **attributes) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_mft_generic_DeleteInputStream(IMFTransform *iface, DWORD streamid) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_mft_generic_AddInputStreams(IMFTransform *iface, DWORD num_streams, DWORD *streamids) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_mft_generic_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_mft_conv_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) +{ + static IMFMediaType *conv_out_type; + + if (id != 0 || index != 0) + return MF_E_NO_MORE_TYPES; + + MFCreateMediaType(&conv_out_type); + IMFMediaType_SetGUID(conv_out_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); + IMFMediaType_SetGUID(conv_out_type, &MF_MT_SUBTYPE, &MFAudioFormat_ZZZ); + IMFMediaType_SetUINT32(conv_out_type, &MF_MT_AUDIO_NUM_CHANNELS, 1); + IMFMediaType_SetUINT32(conv_out_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, 32000); + + *type = conv_out_type; + return S_OK; +} + +static HRESULT WINAPI test_mft_conv_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + UINT32 num_channels, sample; + + IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &num_channels); + IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &sample); + + if (num_channels == 2 && sample == 44100) + return S_OK; + + return MF_E_INVALIDMEDIATYPE; +} + +static HRESULT WINAPI test_mft_conv_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + UINT32 num_channels, sample; + + IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &num_channels); + IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &sample); + + if (num_channels == 1 && sample == 32000) + return S_OK; + + return MF_E_INVALIDMEDIATYPE; +} + +static HRESULT WINAPI test_mft_conv_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_mft_conv_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_mft_generic_GetInputStatus(IMFTransform *iface, DWORD inputstream, DWORD *flags) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_mft_generic_GetOutputStatus(IMFTransform *iface, DWORD *flags) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_mft_generic_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_mft_generic_ProcessEvent(IMFTransform *iface, DWORD inputstream, IMFMediaEvent *event) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_mft_generic_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE type, ULONG_PTR param) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_mft_generic_ProcessInput(IMFTransform *iface, DWORD inputstream, IMFSample *sample, DWORD flags) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_mft_generic_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD outbufcount, MFT_OUTPUT_DATA_BUFFER *outsamples, DWORD *status) +{ + return E_NOTIMPL; +} + +static const IMFTransformVtbl test_mft_conv_vtbl = +{ + test_mft_generic_QueryInterface, + test_mft_generic_AddRef, + test_mft_generic_Release, + test_mft_generic_GetStreamLimits, + test_mft_generic_GetStreamCount, + test_mft_generic_GetStreamIDs, + test_mft_generic_GetInputStreamInfo, + test_mft_generic_GetOutputStreamInfo, + test_mft_generic_GetAttributes, + test_mft_generic_GetInputStreamAttributes, + test_mft_generic_GetOutputStreamAttributes, + test_mft_generic_DeleteInputStream, + test_mft_generic_AddInputStreams, + test_mft_generic_GetInputAvailableType, + test_mft_conv_GetOutputAvailableType, + test_mft_conv_SetInputType, + test_mft_conv_SetOutputType, + test_mft_conv_GetInputCurrentType, + test_mft_conv_GetOutputCurrentType, + test_mft_generic_GetInputStatus, + test_mft_generic_GetOutputStatus, + test_mft_generic_SetOutputBounds, + test_mft_generic_ProcessEvent, + test_mft_generic_ProcessMessage, + test_mft_generic_ProcessInput, + test_mft_generic_ProcessOutput, +}; + +static IMFTransform test_mft_conv = { &test_mft_conv_vtbl }; + +static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv) +{ + if (IsEqualGUID(riid, &IID_IUnknown) || (IsEqualGUID(riid, &IID_IClassFactory))) { + *ppv = iface; + return S_OK; + } + + *ppv = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface) +{ + return 2; +} + +static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) +{ + return 1; +} + +static HRESULT WINAPI ClassFactoryConv_CreateInstance(IClassFactory *iface, + IUnknown *pUnkOuter, REFIID riid, void **ppv) +{ + *ppv = &test_mft_conv; + return S_OK; +} + +static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL fLock) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static const IClassFactoryVtbl ClassFactoryConvVtbl = { + ClassFactory_QueryInterface, + ClassFactory_AddRef, + ClassFactory_Release, + ClassFactoryConv_CreateInstance, + ClassFactory_LockServer +}; + +static IClassFactory ClassFactoryConv = { &ClassFactoryConvVtbl }; + +static const CLSID test_conv_clsid = { 0x12345678, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } }; static void test_topology_loader(void) { IMFSampleGrabberSinkCallback test_grabber_callback = { &test_grabber_callback_vtbl }; - IMFTopology *topology, *topology2, *full_topology; + IMFMediaSource test_media_source = { &test_media_source_vtbl }; + IMFTopology *topology, *full_topology = NULL; + static WCHAR str[] = { 'c','o','n','v', 0 }; + IMFMediaType *media_type, *mediatypes_pd[3]; IMFTopologyNode *src_node, *sink_node; + MFT_REGISTER_TYPE_INFO typeinfo; IMFPresentationDescriptor *pd; - IMFSourceResolver *resolver; IMFActivate *sink_activate; + IMFStreamSink *stream_sink; unsigned int count, value; - IMFMediaType *media_type; + IMFMediaTypeHandler *mth; IMFStreamDescriptor *sd; - MF_OBJECT_TYPE obj_type; - IMFMediaSource *source; IMFTopoLoader *loader; - IMFByteStream *stream; - IMFAttributes *attr; IMFMediaSink *sink; - WCHAR *filename; + WORD node_count; BOOL selected; HRESULT hr; GUID guid; + DWORD reg;
hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); ok(hr == S_OK, "Startup failure, hr %#x.\n", hr); @@ -1430,35 +1743,38 @@ static void test_topology_loader(void) todo_wine ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
- hr = MFCreateSourceResolver(&resolver); - ok(hr == S_OK, "Failed to create source resolver, hr %#x.\n", hr); - - filename = load_resource(L"test.wav"); - - hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, filename, &stream); - ok(hr == S_OK, "Failed to create file stream, hr %#x.\n", hr); - - IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attr); - IMFAttributes_SetString(attr, &MF_BYTESTREAM_CONTENT_TYPE, L"audio/wav"); - IMFAttributes_Release(attr); - - hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL, - &obj_type, (IUnknown **)&source); - ok(hr == S_OK || broken(FAILED(hr)) /* Vista */, "Failed to create source, hr %#x.\n", hr); - if (FAILED(hr)) - return; - - hr = IMFMediaSource_CreatePresentationDescriptor(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 = MFCreateMediaType(&mediatypes_pd[0]); + ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr); + hr = IMFMediaType_SetGUID(mediatypes_pd[0], &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); + ok(hr == S_OK, "Failed to set GUID, hr %#x.\n", hr); + hr = IMFMediaType_SetGUID(mediatypes_pd[0], &MF_MT_SUBTYPE, &MFAudioFormat_ZZZ); + ok(hr == S_OK, "Failed to set GUID, hr %#x.\n", hr); + hr = IMFMediaType_SetUINT32(mediatypes_pd[0], &MF_MT_AUDIO_NUM_CHANNELS, 2); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + hr = IMFMediaType_SetUINT32(mediatypes_pd[0], &MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + hr = MFCreateMediaType(&mediatypes_pd[1]); + ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr); + hr = IMFMediaType_SetGUID(mediatypes_pd[1], &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); + ok(hr == S_OK, "Failed to set GUID, hr %#x.\n", hr); + hr = IMFMediaType_SetGUID(mediatypes_pd[1], &MF_MT_SUBTYPE, &MFAudioFormat_ZZZ); + ok(hr == S_OK, "Failed to set GUID, hr %#x.\n", hr); + hr = IMFMediaType_SetUINT32(mediatypes_pd[1], &MF_MT_AUDIO_NUM_CHANNELS, 1); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + hr = IMFMediaType_SetUINT32(mediatypes_pd[1], &MF_MT_AUDIO_SAMPLES_PER_SECOND, 32000); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + hr = MFCreateStreamDescriptor(0, 2, mediatypes_pd, &sd); + ok(hr == S_OK, "Failed to create stream descriptor, hr %#x.\n", hr); + hr = MFCreatePresentationDescriptor(1, &sd, &pd); + ok(hr == S_OK, "Failed to create presentation descriptor, hr %#x.\n", hr); + hr = IMFPresentationDescriptor_SelectStream(pd, 0); + ok(hr == S_OK, "Failed selecting stream.\n");
/* Add source 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 *)source); + 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); @@ -1481,7 +1797,11 @@ todo_wine
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); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_ZZZ); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, 1); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, 32000); ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
hr = MFCreateSampleGrabberSinkActivate(media_type, &test_grabber_callback, &sink_activate); @@ -1511,22 +1831,49 @@ 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); ok(hr == S_OK, "Failed to get attribute count, hr %#x.\n", hr); ok(count == 0, "Unexpected count %u.\n", count);
+ /* if no current media type set, loader uses first index exclusively */ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); todo_wine + ok(hr == MF_E_TOPO_CODEC_NOT_FOUND, "Unexpected 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, 0, &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); +todo_wine + ok(hr == MF_E_TOPO_CODEC_NOT_FOUND, "Unexpected 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); - ok(full_topology != topology, "Unexpected instance.\n");
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);
+ hr = E_FAIL; hr = IMFTopology_GetCount(full_topology, &count); ok(hr == S_OK, "Failed to get attribute count, hr %#x.\n", hr); todo_wine @@ -1543,16 +1890,101 @@ todo_wine { ok(hr == S_OK, "Failed to get attribute, hr %#x.\n", hr); ok(value == MF_TOPOLOGY_RESOLUTION_SUCCEEDED, "Unexpected value %#x.\n", value); } - hr = IMFTopoLoader_Load(loader, full_topology, &topology2, NULL); + + IMFTopology_Release(full_topology); + + /* test with stream deselected */ + hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, 0, &selected, &sd); + ok(hr == S_OK, "Failed getting stream descriptor, hr %#x.\n", hr); + + hr = IMFPresentationDescriptor_DeselectStream(pd, 0); + ok(hr == S_OK, "Failed deselecting 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); - ok(full_topology != topology2, "Unexpected instance.\n"); + + IMFPresentationDescriptor_Release(pd); + IMFStreamDescriptor_Release(sd); + IMFTopologyNode_Release(src_node); + + hr = IMFTopology_GetNode(full_topology, 0, &src_node); + ok(hr == S_OK, "Failed to get source node, hr %#x.\n", hr); + 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); + hr = 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"); + + IMFStreamDescriptor_Release(sd); + IMFTopologyNode_Release(src_node); + IMFPresentationDescriptor_Release(pd); + IMFTopology_Release(full_topology);
- IMFTopology_Release(topology2); + /* register a converter to test source -> mft -> sink */ + hr = CoRegisterClassObject(&test_conv_clsid, (IUnknown*)&ClassFactoryConv, CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®); + ok(hr == S_OK, "Failed to register class object, hr %#x.\n"); + + typeinfo.guidMajorType = MFMediaType_Audio; + typeinfo.guidSubtype = MFAudioFormat_ZZZ; + hr = MFTRegisterLocalByCLSID(&test_conv_clsid, &MFT_CATEGORY_AUDIO_DECODER, str, MFT_ENUM_FLAG_ASYNCMFT, 1, &typeinfo, 1, &typeinfo); + ok(hr == S_OK, "Failed to register mft, hr %#x.\n"); + + hr = IMFTopology_GetNode(topology, 0, &src_node); + ok(hr == S_OK, "Failed to get source node, hr %#x.\n", hr); + + hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 0, &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 %d.\n", node_count); IMFTopology_Release(full_topology);
- IMFMediaSource_Release(source); - IMFSourceResolver_Release(resolver); - IMFByteStream_Release(stream); + /* test when MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES attribute is set on topology */ + hr = IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, 1); + ok(hr == S_OK, "Failed to set attribute.\n"); + + /* test with MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES set on source */ + hr = IMFTopologyNode_SetUINT32(src_node, &MF_TOPONODE_CONNECT_METHOD, MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES); + ok(hr == S_OK, "Failed to set attribute.\n"); + + 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 %d.\n", node_count); + + /* now test without MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES on source */ + hr = IMFTopologyNode_SetUINT32(src_node, &MF_TOPONODE_CONNECT_METHOD, ~MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES); + ok(hr == S_OK, "Failed to set attribute.\n"); + + IMFTopology_Release(full_topology); + 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 %d.\n", node_count); + IMFTopology_Release(full_topology); + + IMFMediaType_Release(mediatypes_pd[0]); + IMFMediaType_Release(mediatypes_pd[1]); + IMFStreamDescriptor_Release(sd); + IMFPresentationDescriptor_Release(pd); + IMFTopology_RemoveNode(topology, src_node); + + hr = MFTUnregister(test_conv_clsid); + ok(hr == S_OK, "Failed to unregister mft, hr %#x.\n"); + hr = CoRevokeClassObject(reg); + ok(hr == S_OK, "Failed to unregister class object, hr %#x.\n"); + IMFTopoLoader_Release(loader);
hr = MFShutdown();
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/mf/tests/mf.c | 2 -- dlls/mf/topology.c | 51 ++++++++++++++++++++++++++++------------------ 2 files changed, 31 insertions(+), 22 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index a92f183096..cfee1ca0ae 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -1740,7 +1740,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 = MFCreateMediaType(&mediatypes_pd[0]); @@ -1788,7 +1787,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. */ diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index 432979206b..a6342c0c4e 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -1938,8 +1938,11 @@ static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface) 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); + MF_TOPOLOGY_TYPE node_type; + IMFTopologyNode *node; IMFStreamSink *sink; + IUnknown *object; + WORD count; HRESULT hr; size_t i;
@@ -1948,32 +1951,40 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in if (current_topology) FIXME("Current topology instance is ignored.\n");
- for (i = 0; i < topology->nodes.count; ++i) + if (FAILED(IMFTopology_GetNodeCount(input_topology, &count)) + || count < 2) + { + hr = MF_E_TOPO_UNSUPPORTED; + return hr; + } + + if (FAILED(hr = MFCreateTopology(output_topology))) + return hr; + + i = 0; + while (SUCCEEDED(IMFTopology_GetNode(input_topology, i++, &node))) { - struct topology_node *node = topology->nodes.nodes[i]; + IMFTopologyNode_GetNodeType(node, &node_type);
- switch (node->node_type) + if (node_type == MF_TOPOLOGY_OUTPUT_NODE) { - case MF_TOPOLOGY_OUTPUT_NODE: - if (node->object) + if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object))) + { + /* Sinks must be bound beforehand. */ + if (FAILED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&sink))) { - /* 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); - } - break; - case MF_TOPOLOGY_SOURCESTREAM_NODE: - if (FAILED(hr = IMFAttributes_GetItem(node->attributes, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL))) + IMFTopologyNode_Release(node); + IUnknown_Release(object); + hr = MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED; return hr; - break; - default: - ; + } + IMFStreamSink_Release(sink); + IUnknown_Release(object); + } } - }
- if (FAILED(hr = MFCreateTopology(output_topology))) - return hr; + IMFTopologyNode_Release(node); + }
return IMFTopology_CloneFrom(*output_topology, input_topology); }
On 6/15/20 4:41 AM, Sergio Gómez Del Real wrote:
- if (FAILED(IMFTopology_GetNodeCount(input_topology, &count))
|| count < 2)
- {
hr = MF_E_TOPO_UNSUPPORTED;
return hr;
- }
This should come up later as more generic case of zero branches, or badly incomplete output topology.
- if (FAILED(hr = MFCreateTopology(output_topology)))
return hr;
- i = 0;
- while (SUCCEEDED(IMFTopology_GetNode(input_topology, i++, &node))) {
Won't moving creation call before the loop leak output topology on error case? I seems unlikely that on error condition it still returns empty output topology.
On 22/06/20 6:37 a. m., Nikolay Sivov wrote:
On 6/15/20 4:41 AM, Sergio Gómez Del Real wrote:
- if (FAILED(IMFTopology_GetNodeCount(input_topology, &count))
|| count < 2)
- {
hr = MF_E_TOPO_UNSUPPORTED;
return hr;
- }
This should come up later as more generic case of zero branches, or badly incomplete output topology.
The reason I insist with this is that this case specifically returns MF_E_TOPO_UNSUPPORTED. Continuing with processing could return a different, mistaken, error.
- if (FAILED(hr = MFCreateTopology(output_topology)))
return hr;
- i = 0;
- while (SUCCEEDED(IMFTopology_GetNode(input_topology, i++, &node))) {
Won't moving creation call before the loop leak output topology on error case? I seems unlikely that on error condition it still returns empty output topology.
Right. There could be an error later on, if output node doesn't have IMFStreamSink interface, which would leak output_topology. I'll also add error checking for _CloneFrom().
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/mf/topology.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index a6342c0c4e..4d437e6961 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -1935,9 +1935,18 @@ static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface) return refcount; }
+struct topoloader_context +{ + IMFTopology *input_topology; + IMFTopology *output_topology; + GUID key; + unsigned int marker; +}; + static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology, IMFTopology **output_topology, IMFTopology *current_topology) { + struct topoloader_context context = { 0 }; MF_TOPOLOGY_TYPE node_type; IMFTopologyNode *node; IMFStreamSink *sink; @@ -1952,14 +1961,15 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in FIXME("Current topology instance is ignored.\n");
if (FAILED(IMFTopology_GetNodeCount(input_topology, &count)) + || FAILED(MFCreateTopology(&context.output_topology)) || count < 2) { hr = MF_E_TOPO_UNSUPPORTED; return hr; }
- if (FAILED(hr = MFCreateTopology(output_topology))) - return hr; + context.input_topology = input_topology; + memset(&context.key, 0xff, sizeof(context.key));
i = 0; while (SUCCEEDED(IMFTopology_GetNode(input_topology, i++, &node))) @@ -1973,6 +1983,7 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in /* Sinks must be bound beforehand. */ if (FAILED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&sink))) { + IMFTopology_Release(context.output_topology); IMFTopologyNode_Release(node); IUnknown_Release(object); hr = MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED; @@ -1986,7 +1997,10 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in IMFTopologyNode_Release(node); }
- return IMFTopology_CloneFrom(*output_topology, input_topology); + if (SUCCEEDED(hr = IMFTopology_CloneFrom(context.output_topology, input_topology))) + *output_topology = context.output_topology; + + return hr; }
static const IMFTopoLoaderVtbl topologyloadervtbl =
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/mf/topology.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-)
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index 4d437e6961..1f7e33f76b 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -1943,6 +1943,37 @@ struct topoloader_context unsigned int marker; };
+static HRESULT topology_loader_clone_node(struct topoloader_context *context, IMFTopologyNode *node, IMFTopologyNode **ret, + unsigned int marker) +{ + IMFTopologyNode *cloned_node; + MF_TOPOLOGY_TYPE node_type; + HRESULT hr; + + if (ret) *ret = NULL; + + IMFTopologyNode_GetNodeType(node, &node_type); + + if (FAILED(hr = MFCreateTopologyNode(node_type, &cloned_node))) + return hr; + + if (SUCCEEDED(hr = IMFTopologyNode_CloneFrom(cloned_node, node))) + hr = IMFTopologyNode_SetUINT32(cloned_node, &context->key, marker); + + if (SUCCEEDED(hr)) + hr = IMFTopology_AddNode(context->output_topology, cloned_node); + + if (SUCCEEDED(hr) && ret) + { + *ret = cloned_node; + IMFTopologyNode_AddRef(*ret); + } + + IMFTopologyNode_Release(cloned_node); + + return hr; +} + static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology, IMFTopology **output_topology, IMFTopology *current_topology) { @@ -1976,7 +2007,16 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in { IMFTopologyNode_GetNodeType(node, &node_type);
- if (node_type == MF_TOPOLOGY_OUTPUT_NODE) + /* Clone and mark source nodes. */ + if (node_type == MF_TOPOLOGY_SOURCESTREAM_NODE) + { + if (FAILED(hr = topology_loader_clone_node(&context, node, NULL, 0))) + { + WARN("Failed to clone source node, hr %#x.\n", hr); + continue; + } + } + else if (node_type == MF_TOPOLOGY_OUTPUT_NODE) { if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object))) {
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/mf/topology.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index 1f7e33f76b..03aa967d9e 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -1943,6 +1943,28 @@ struct topoloader_context unsigned int marker; };
+static int topology_loader_get_branch_depth(IMFTopologyNode *node, int level) +{ + IMFTopologyNode *current_node; + MF_TOPOLOGY_TYPE node_type; + static int max_level = 0; + + if (level > max_level) + max_level = level; + + IMFTopologyNode_GetNodeType(node, &node_type); + if (node_type == MF_TOPOLOGY_SOURCESTREAM_NODE || node_type == MF_TOPOLOGY_TRANSFORM_NODE) + { + int stream = 0; + DWORD input_stream; + + while (SUCCEEDED(IMFTopologyNode_GetOutput(node, stream++, ¤t_node, &input_stream))) + topology_loader_get_branch_depth(current_node, level + 1); + } + + return max_level; +} + static HRESULT topology_loader_clone_node(struct topoloader_context *context, IMFTopologyNode *node, IMFTopologyNode **ret, unsigned int marker) { @@ -1978,13 +2000,13 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in IMFTopology **output_topology, IMFTopology *current_topology) { struct topoloader_context context = { 0 }; + unsigned short i, max_branch_depth = 0; MF_TOPOLOGY_TYPE node_type; IMFTopologyNode *node; IMFStreamSink *sink; IUnknown *object; WORD count; HRESULT hr; - size_t i;
FIXME("%p, %p, %p, %p.\n", iface, input_topology, output_topology, current_topology);
@@ -2010,11 +2032,16 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in /* Clone and mark source nodes. */ if (node_type == MF_TOPOLOGY_SOURCESTREAM_NODE) { + unsigned int branch_depth; + if (FAILED(hr = topology_loader_clone_node(&context, node, NULL, 0))) { WARN("Failed to clone source node, hr %#x.\n", hr); continue; } + branch_depth = topology_loader_get_branch_depth(node, 0); + if (branch_depth > max_branch_depth) + max_branch_depth = branch_depth; } else if (node_type == MF_TOPOLOGY_OUTPUT_NODE) {
On 6/15/20 4:41 AM, Sergio Gómez Del Real wrote:
+static int topology_loader_get_branch_depth(IMFTopologyNode *node, int level) +{
- IMFTopologyNode *current_node;
- MF_TOPOLOGY_TYPE node_type;
- static int max_level = 0;
- if (level > max_level)
max_level = level;
- IMFTopologyNode_GetNodeType(node, &node_type);
- if (node_type == MF_TOPOLOGY_SOURCESTREAM_NODE || node_type == MF_TOPOLOGY_TRANSFORM_NODE)
- {
int stream = 0;
DWORD input_stream;
while (SUCCEEDED(IMFTopologyNode_GetOutput(node, stream++, ¤t_node, &input_stream)))
topology_loader_get_branch_depth(current_node, level + 1);
- }
- return max_level;
+}
I don't understand the purpose of this. Could you elaborate? I see it's used in 6/10, but why can't we iterate until output node is reached?
P.S. regardless of the above, static variable should not be used for this.
On 22/06/20 6:44 a. m., Nikolay Sivov wrote:
On 6/15/20 4:41 AM, Sergio Gómez Del Real wrote:
+static int topology_loader_get_branch_depth(IMFTopologyNode *node, int level) +{
- IMFTopologyNode *current_node;
- MF_TOPOLOGY_TYPE node_type;
- static int max_level = 0;
- if (level > max_level)
max_level = level;
- IMFTopologyNode_GetNodeType(node, &node_type);
- if (node_type == MF_TOPOLOGY_SOURCESTREAM_NODE || node_type == MF_TOPOLOGY_TRANSFORM_NODE)
- {
int stream = 0;
DWORD input_stream;
while (SUCCEEDED(IMFTopologyNode_GetOutput(node, stream++, ¤t_node, &input_stream)))
topology_loader_get_branch_depth(current_node, level + 1);
- }
- return max_level;
+}
I don't understand the purpose of this. Could you elaborate? I see it's used in 6/10, but why can't we iterate until output node is reached?
At any point in the branch, a node could have multiple output streams, issuing multiple sub-branches, leading to other nodes with potential for further sub-branching. This gives some generality without complicating matters too much. The idea is to get the deepest level present in the branch(es) starting at a source, hence the use of max_level.
P.S. regardless of the above, static variable should not be used for this.
Why?
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/mf/tests/mf.c | 5 --- dlls/mf/topology.c | 96 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 90 insertions(+), 11 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index cfee1ca0ae..6d0a3176ac 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -1874,20 +1874,15 @@ todo_wine hr = E_FAIL; hr = IMFTopology_GetCount(full_topology, &count); ok(hr == S_OK, "Failed to get attribute count, hr %#x.\n", hr); -todo_wine ok(count == 1, "Unexpected count %u.\n", count);
hr = IMFTopology_GetItemByIndex(full_topology, 0, &guid, NULL); -todo_wine { ok(hr == S_OK, "Failed to get attribute key, hr %#x.\n", hr); ok(IsEqualGUID(&guid, &MF_TOPOLOGY_RESOLUTION_STATUS), "Unexpected key %s.\n", wine_dbgstr_guid(&guid)); -} value = 0xdeadbeef; hr = IMFTopology_GetUINT32(full_topology, &MF_TOPOLOGY_RESOLUTION_STATUS, &value); -todo_wine { ok(hr == S_OK, "Failed to get attribute, hr %#x.\n", hr); ok(value == MF_TOPOLOGY_RESOLUTION_SUCCEEDED, "Unexpected value %#x.\n", value); -}
IMFTopology_Release(full_topology);
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index 03aa967d9e..c51a739aa8 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -1965,6 +1965,26 @@ static int topology_loader_get_branch_depth(IMFTopologyNode *node, int level) return max_level; }
+static IMFTopologyNode *topology_loader_get_node_for_marker(struct topoloader_context *context, TOPOID *id) +{ + IMFTopologyNode *node; + unsigned short i = 0; + unsigned int value; + + while (SUCCEEDED(IMFTopology_GetNode(context->output_topology, i++, &node))) + { + if (SUCCEEDED(IMFTopologyNode_GetUINT32(node, &context->key, &value)) && value == context->marker) + { + IMFTopologyNode_GetTopoNodeID(node, id); + return node; + } + IMFTopologyNode_Release(node); + } + + *id = 0; + return NULL; +} + static HRESULT topology_loader_clone_node(struct topoloader_context *context, IMFTopologyNode *node, IMFTopologyNode **ret, unsigned int marker) { @@ -1996,8 +2016,62 @@ static HRESULT topology_loader_clone_node(struct topoloader_context *context, IM return hr; }
+static HRESULT topology_loader_resolve_nodes(struct topoloader_context *context) +{ + IMFTopologyNode *node, *downstream_node, *orig_node, *orig_downstream_node; + MF_TOPOLOGY_TYPE node_type; + unsigned int input_index; + HRESULT hr = E_FAIL; + TOPOID id; + int i; + + while ((node = topology_loader_get_node_for_marker(context, &id))) + { + IMFTopology_GetNodeByID(context->input_topology, id, &orig_node); + + IMFTopologyNode_GetNodeType(node, &node_type); + + i = 0; + /* traverse output streams of node and connect them to their downstreams */ + while (SUCCEEDED(IMFTopologyNode_GetOutput(orig_node, i, &orig_downstream_node, &input_index))) + { + IMFTopologyNode_GetTopoNodeID(orig_downstream_node, &id); + if (FAILED(IMFTopology_GetNodeByID(context->output_topology, id, &downstream_node))) + topology_loader_clone_node(context, orig_downstream_node, &downstream_node, context->marker + 1); + + switch (node_type) + { + case MF_TOPOLOGY_SOURCESTREAM_NODE: + hr = S_OK; + break; + case MF_TOPOLOGY_TRANSFORM_NODE: + hr = S_OK; + break; + case MF_TOPOLOGY_TEE_NODE: + FIXME("Tee node unsupported.\n"); + break; + default: + WARN("Unexpected node type %d.\n", node_type); + } + + IMFTopologyNode_Release(orig_downstream_node); + IMFTopologyNode_Release(downstream_node); + + if (FAILED(hr)) + goto out; + i++; + } + + IMFTopologyNode_DeleteItem(node, &context->key); + IMFTopologyNode_Release(node); + } + +out: + return hr; +} + static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology, - IMFTopology **output_topology, IMFTopology *current_topology) + IMFTopology **ret_topology, IMFTopology *current_topology) { struct topoloader_context context = { 0 }; unsigned short i, max_branch_depth = 0; @@ -2008,7 +2082,7 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in WORD count; HRESULT hr;
- FIXME("%p, %p, %p, %p.\n", iface, input_topology, output_topology, current_topology); + TRACE("%p, %p, %p, %p.\n", iface, input_topology, ret_topology, current_topology);
if (current_topology) FIXME("Current topology instance is ignored.\n"); @@ -2018,7 +2092,7 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in || count < 2) { hr = MF_E_TOPO_UNSUPPORTED; - return hr; + goto out; }
context.input_topology = input_topology; @@ -2054,7 +2128,7 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in IMFTopologyNode_Release(node); IUnknown_Release(object); hr = MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED; - return hr; + goto out; } IMFStreamSink_Release(sink); IUnknown_Release(object); @@ -2064,9 +2138,19 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in IMFTopologyNode_Release(node); }
- if (SUCCEEDED(hr = IMFTopology_CloneFrom(context.output_topology, input_topology))) - *output_topology = context.output_topology; + for (context.marker = 0; context.marker < max_branch_depth; ++context.marker) + { + if (FAILED(hr = topology_loader_resolve_nodes(&context))) + break; + } + + if (SUCCEEDED(hr)) + { + IMFTopology_SetUINT32(context.output_topology, &MF_TOPOLOGY_RESOLUTION_STATUS, MF_TOPOLOGY_RESOLUTION_SUCCEEDED); + *ret_topology = context.output_topology; + }
+out: return hr; }
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/mf/topology.c | 94 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-)
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index c51a739aa8..e38035ddd2 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -2016,6 +2016,98 @@ static HRESULT topology_loader_clone_node(struct topoloader_context *context, IM return hr; }
+static HRESULT topology_loader_connect_source(struct topoloader_context *context, IMFTopologyNode *source_node, + IMFTopologyNode *downstream_node, unsigned int input_index) +{ + IMFStreamDescriptor *strm_desc; + IMFMediaType **src_mediatypes; + UINT32 method, enum_src_types; + IMFMediaTypeHandler *mth_src; + struct topology_node *src; + IMFAttributes *attrs_src; + IMFMediaType *mtype_src; + DWORD num_media_types; + HRESULT hr; + int i; + + src = impl_from_IMFTopologyNode(source_node); + attrs_src = src->attributes; + if (FAILED(hr = IMFAttributes_GetUnknown(attrs_src, &MF_TOPONODE_STREAM_DESCRIPTOR, &IID_IMFStreamDescriptor, (void **)&strm_desc))) + return hr; + + if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(strm_desc, &mth_src))) + { + IMFStreamDescriptor_Release(strm_desc); + return hr; + } + IMFStreamDescriptor_Release(strm_desc); + + if (FAILED(IMFTopology_GetUINT32(context->input_topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, &enum_src_types))) + enum_src_types = 0; + + if (!enum_src_types) + { + num_media_types = 1; + if (FAILED(hr = IMFMediaTypeHandler_GetCurrentMediaType(mth_src, &mtype_src))) + if (FAILED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth_src, 0, &mtype_src))) + { + IMFMediaTypeHandler_Release(mth_src); + return hr; + } + } + else + IMFMediaTypeHandler_GetMediaTypeCount(mth_src, &num_media_types); + + src_mediatypes = heap_alloc(sizeof(IMFMediaType *) * num_media_types); + if (!src_mediatypes) + { + if (!enum_src_types) + IMFMediaType_Release(mtype_src); + IMFMediaTypeHandler_Release(mth_src); + return E_OUTOFMEMORY; + } + + if (enum_src_types) + for (i = 0; i < num_media_types; i++) + IMFMediaTypeHandler_GetMediaTypeByIndex(mth_src, i, &src_mediatypes[i]); + else + src_mediatypes[0] = mtype_src; + + hr = IMFAttributes_GetUINT32(attrs_src, &MF_TOPONODE_CONNECT_METHOD, &method); + if (!enum_src_types || (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++) + { + IMFMediaTypeHandler_SetCurrentMediaType(mth_src, src_mediatypes[i]); + hr = S_OK; + goto out; + } + } + } + else + { + for (i = 0; i < num_media_types; i++) + { + for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++) + { + IMFMediaTypeHandler_SetCurrentMediaType(mth_src, src_mediatypes[i]); + hr = S_OK; + goto out; + } + } + } + +out: + while (num_media_types--) + IMFMediaType_Release(src_mediatypes[num_media_types]); + IMFMediaTypeHandler_Release(mth_src); + heap_free(src_mediatypes); + + return hr; +} + static HRESULT topology_loader_resolve_nodes(struct topoloader_context *context) { IMFTopologyNode *node, *downstream_node, *orig_node, *orig_downstream_node; @@ -2042,7 +2134,7 @@ static HRESULT topology_loader_resolve_nodes(struct topoloader_context *context) switch (node_type) { case MF_TOPOLOGY_SOURCESTREAM_NODE: - hr = S_OK; + hr = topology_loader_connect_source(context, node, downstream_node, input_index); break; case MF_TOPOLOGY_TRANSFORM_NODE: hr = S_OK;
On 6/15/20 4:41 AM, Sergio Gómez Del Real wrote:
- hr = IMFAttributes_GetUINT32(attrs_src, &MF_TOPONODE_CONNECT_METHOD, &method);
- if (!enum_src_types || (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++)
{
IMFMediaTypeHandler_SetCurrentMediaType(mth_src, src_mediatypes[i]);
hr = S_OK;
goto out;
}
}
- }
- else
- {
for (i = 0; i < num_media_types; i++)
{
for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++)
{
IMFMediaTypeHandler_SetCurrentMediaType(mth_src, src_mediatypes[i]);
hr = S_OK;
goto out;
}
}
- }
I think this was carried from previous iteration of the patches? I think same concern still apply, why specified method is essentially ignored? Loops are reduced to 1 iteration until following patches, it's better to avoid that.
On 22/06/20 6:53 a. m., Nikolay Sivov wrote:
On 6/15/20 4:41 AM, Sergio Gómez Del Real wrote:
- hr = IMFAttributes_GetUINT32(attrs_src, &MF_TOPONODE_CONNECT_METHOD, &method);
- if (!enum_src_types || (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++)
{
IMFMediaTypeHandler_SetCurrentMediaType(mth_src, src_mediatypes[i]);
hr = S_OK;
goto out;
}
}
- }
- else
- {
for (i = 0; i < num_media_types; i++)
{
for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++)
{
IMFMediaTypeHandler_SetCurrentMediaType(mth_src, src_mediatypes[i]);
hr = S_OK;
goto out;
}
}
- }
I think this was carried from previous iteration of the patches? I think same concern still apply, why specified method is essentially ignored? Loops are reduced to 1 iteration until following patches, it's better to avoid that.
Yes, this is indeed incorrect. Forgot to apply the modifications I had. Will send them in next iteration.
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/mf/topology.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-)
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index e38035ddd2..bb8b9de267 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -2108,6 +2108,34 @@ out: return hr; }
+static HRESULT topology_loader_connect_transform(struct topoloader_context *context, IMFTopologyNode *transform_node, unsigned int output_index, + IMFTopologyNode *downstream_node, unsigned int input_index) +{ + UINT32 method = MF_CONNECT_ALLOW_DECODER; + IMFTransform *transform; + IMFMediaType *mediatype; + HRESULT hr; + int i; + + IMFTopologyNode_GetObject(transform_node, (IUnknown **)&transform); + + IMFTopologyNode_GetUINT32(downstream_node, &MF_TOPONODE_CONNECT_METHOD, &method); + + i = 0; + while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, output_index, i++, &mediatype))) + { + hr = S_OK; + + IMFMediaType_Release(mediatype); + + if (SUCCEEDED(hr)) + break; + } + + IMFTransform_Release(transform); + return hr; +} + static HRESULT topology_loader_resolve_nodes(struct topoloader_context *context) { IMFTopologyNode *node, *downstream_node, *orig_node, *orig_downstream_node; @@ -2137,7 +2165,7 @@ static HRESULT topology_loader_resolve_nodes(struct topoloader_context *context) hr = topology_loader_connect_source(context, node, downstream_node, input_index); break; case MF_TOPOLOGY_TRANSFORM_NODE: - hr = S_OK; + hr = topology_loader_connect_transform(context, node, i, downstream_node, input_index); break; case MF_TOPOLOGY_TEE_NODE: FIXME("Tee node unsupported.\n");
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/mf/topology.c | 111 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 106 insertions(+), 5 deletions(-)
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index bb8b9de267..7aaffaf807 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -2016,6 +2016,107 @@ static HRESULT topology_loader_clone_node(struct topoloader_context *context, IM return hr; }
+static HRESULT topology_loader_is_mediatype_compatible_with_sink(IMFMediaTypeHandler *sink_mediatype_handler, IMFMediaType *mediatype) +{ + IMFMediaType *sink_mediatype; + HRESULT hr; + + if (FAILED(hr = IMFMediaTypeHandler_GetCurrentMediaType(sink_mediatype_handler, &sink_mediatype))) + hr = IMFMediaTypeHandler_GetMediaTypeByIndex(sink_mediatype_handler, 0, &sink_mediatype); + + if (SUCCEEDED(hr)) + { + DWORD flags; + + if (SUCCEEDED(hr = IMFMediaType_IsEqual(mediatype, sink_mediatype, &flags))) + if (!(flags & MF_MEDIATYPE_EQUAL_FORMAT_DATA)) + hr = MF_E_INVALIDMEDIATYPE; + + IMFMediaType_Release(sink_mediatype); + } + + return hr; +} + +static HRESULT topology_loader_connect_direct(IMFTopologyNode *upstream_node, unsigned int output_index, + IMFTopologyNode *downstream_node, unsigned int input_index, IMFMediaType *output_type) +{ + MF_TOPOLOGY_TYPE node_type; + HRESULT hr; + + IMFTopologyNode_GetNodeType(downstream_node, &node_type); + + if (node_type == MF_TOPOLOGY_TRANSFORM_NODE) + { + IMFTransform *mft; + + if (SUCCEEDED(hr = IMFTopologyNode_GetObject(downstream_node, (IUnknown **)&mft))) + { + hr = IMFTransform_SetInputType(mft, input_index, output_type, 0); + IMFTransform_Release(mft); + } + } + else if (node_type == MF_TOPOLOGY_OUTPUT_NODE) + { + IMFMediaTypeHandler *mediatype_handler; + IMFStreamSink *sink; + + if (SUCCEEDED(hr = IMFTopologyNode_GetObject(downstream_node, (IUnknown **)&sink))) + { + if (SUCCEEDED(hr = IMFStreamSink_GetMediaTypeHandler(sink, &mediatype_handler))) + { + if (SUCCEEDED(hr = topology_loader_is_mediatype_compatible_with_sink(mediatype_handler, output_type))) + IMFMediaTypeHandler_SetCurrentMediaType(mediatype_handler, output_type); + IMFMediaTypeHandler_Release(mediatype_handler); + } + IMFStreamSink_Release(sink); + } + } + else if (node_type == MF_TOPOLOGY_TEE_NODE) + { + FIXME("Tee nodes are not supported.\n"); + hr = MF_E_INVALIDTYPE; + } + else + { + WARN("Unexpected node type %d.\n", node_type); + hr = MF_E_INVALIDTYPE; + } + + if (SUCCEEDED(hr)) + hr = IMFTopologyNode_ConnectOutput(upstream_node, output_index, downstream_node, input_index); + + return hr; +} + +static HRESULT topology_loader_connect_nodes(struct topoloader_context *context, IMFTopologyNode *upstream_node, unsigned int output_index, + IMFTopologyNode *downstream_node, unsigned int input_index, IMFMediaType *output_type, UINT32 connect_method) +{ + HRESULT hr; + GUID major; + + if (FAILED(hr = IMFMediaType_GetMajorType(output_type, &major))) + goto out; + + /* always try first a direct connection */ + if (FAILED(hr = topology_loader_connect_direct(upstream_node, output_index, downstream_node, input_index, output_type)) + && connect_method != MF_CONNECT_DIRECT) + { + switch (connect_method) + { + case MF_CONNECT_ALLOW_CONVERTER: + hr = S_OK; + break; + case MF_CONNECT_ALLOW_DECODER: + hr = S_OK; + break; + } + } + +out: + return hr; +} + static HRESULT topology_loader_connect_source(struct topoloader_context *context, IMFTopologyNode *source_node, IMFTopologyNode *downstream_node, unsigned int input_index) { @@ -2081,8 +2182,8 @@ static HRESULT topology_loader_connect_source(struct topoloader_context *context for (i = 0; i < num_media_types; i++) { IMFMediaTypeHandler_SetCurrentMediaType(mth_src, src_mediatypes[i]); - hr = S_OK; - goto out; + if (SUCCEEDED(hr = topology_loader_connect_nodes(context, source_node, 0, downstream_node, input_index, src_mediatypes[i], method))) + goto out; } } } @@ -2093,8 +2194,8 @@ static HRESULT topology_loader_connect_source(struct topoloader_context *context for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++) { IMFMediaTypeHandler_SetCurrentMediaType(mth_src, src_mediatypes[i]); - hr = S_OK; - goto out; + if (SUCCEEDED(hr = topology_loader_connect_nodes(context, source_node, 0, downstream_node, input_index, src_mediatypes[i], method))) + goto out; } } } @@ -2124,7 +2225,7 @@ static HRESULT topology_loader_connect_transform(struct topoloader_context *cont i = 0; while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, output_index, i++, &mediatype))) { - hr = S_OK; + hr = topology_loader_connect_nodes(context, transform_node, output_index, downstream_node, input_index, mediatype, method);
IMFMediaType_Release(mediatype);
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/mf/Makefile.in | 2 +- dlls/mf/tests/mf.c | 4 -- dlls/mf/topology.c | 124 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 123 insertions(+), 7 deletions(-)
diff --git a/dlls/mf/Makefile.in b/dlls/mf/Makefile.in index fe156e43ab..34118fed67 100644 --- a/dlls/mf/Makefile.in +++ b/dlls/mf/Makefile.in @@ -1,6 +1,6 @@ MODULE = mf.dll IMPORTLIB = mf -IMPORTS = advapi32 mfplat ole32 uuid mfuuid +IMPORTS = advapi32 mfplat ole32 uuid mfuuid wmcodecdspuuid
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 6d0a3176ac..cec6d66f77 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -1841,7 +1841,6 @@ todo_wine
/* if no current media type set, loader uses first index exclusively */ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); -todo_wine ok(hr == MF_E_TOPO_CODEC_NOT_FOUND, "Unexpected hr %#x.\n", hr);
hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &mth); @@ -1855,7 +1854,6 @@ todo_wine ok(hr == S_OK, "Failed setting current media type, hr %#x.\n", hr);
hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); -todo_wine ok(hr == MF_E_TOPO_CODEC_NOT_FOUND, "Unexpected hr %#x.\n", hr);
hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 1, &media_type); @@ -1935,7 +1933,6 @@ todo_wine 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 %d.\n", node_count); IMFTopology_Release(full_topology);
@@ -1952,7 +1949,6 @@ todo_wine
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);
/* now test without MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES on source */ diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index 7aaffaf807..c29e3e36b0 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -29,6 +29,7 @@ #include "mfapi.h" #include "mferror.h" #include "mfidl.h" +#include "wmcodecdsp.h"
#include "wine/debug.h"
@@ -2089,15 +2090,134 @@ static HRESULT topology_loader_connect_direct(IMFTopologyNode *upstream_node, un return hr; }
+static HRESULT topology_loader_connect_converter_node(struct topoloader_context *context, IMFTopologyNode *upstream_node, unsigned int output_index, + IMFTopologyNode *downstream_node, unsigned int input_index, IMFMediaType *output_type, const CLSID *clsid) +{ + IMFTransform *transform = NULL; + IMFMediaType *mediatype = NULL; + HRESULT hr; + + if (FAILED(hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform))) + { + WARN("Failed to create converter transform for %s, hr %#x.\n", debugstr_guid(clsid), hr); + return hr; + } + + if (SUCCEEDED(hr = IMFTransform_SetInputType(transform, 0, output_type, 0))) + { + IMFTopologyNode *converter_node; + + MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &converter_node); + IMFTopologyNode_SetObject(converter_node, (IUnknown *)transform); + + if (SUCCEEDED(hr = topology_loader_connect_direct(upstream_node, output_index, converter_node, 0, mediatype))) + { + unsigned int i = 0; + while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, i++, &mediatype))) + { + hr = topology_loader_connect_direct(converter_node, 0, downstream_node, input_index, mediatype); + + IMFMediaType_Release(mediatype); + + if (SUCCEEDED(hr)) + { + IMFTopology_AddNode(context->output_topology, converter_node); + break; + } + } + } + + IMFTransform_Release(transform); + IMFTopologyNode_Release(converter_node); + } + + return hr; +} + +static HRESULT topology_loader_connect_decoder_node(struct topoloader_context *context, IMFTopologyNode *upstream_node, unsigned int output_index, + IMFTopologyNode *downstream_node, unsigned int input_index, IMFMediaType *input_type, const CLSID *clsid) +{ + HRESULT hr = MF_E_TOPO_CODEC_NOT_FOUND; + unsigned int i = 0, j = 0, count = 0; + MFT_REGISTER_TYPE_INFO input_info; + IMFMediaType *current_mediatype; + IMFActivate **activators = NULL; + IMFTransform *transform = NULL; + IMFTopologyNode *decoder_node; + const GUID *category; + + IMFMediaType_GetMajorType(input_type, &input_info.guidMajorType); + IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &input_info.guidSubtype); + + if (IsEqualGUID(&MFMediaType_Audio, &input_info.guidMajorType)) + category = &MFT_CATEGORY_AUDIO_DECODER; + else + category = &MFT_CATEGORY_VIDEO_DECODER; + + if (SUCCEEDED(MFTEnumEx(*category, MFT_ENUM_FLAG_ALL, &input_info, NULL, &activators, &count))) + { + for (i = 0; i < count; ++i) + { + if (FAILED(IMFActivate_ActivateObject(activators[i], &IID_IMFTransform, (void **)&transform))) + { + WARN("Failed to activate transform, hr %#x.\n", hr); + continue; + } + + if (SUCCEEDED(MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &decoder_node)) + && SUCCEEDED(IMFTransform_SetInputType(transform, 0, input_type, 0)) + && SUCCEEDED(IMFTopologyNode_SetObject(decoder_node, (IUnknown *)transform))) + { + j = 0; + while (SUCCEEDED(IMFTransform_GetOutputAvailableType(transform, 0, j++, ¤t_mediatype))) + { + if (SUCCEEDED(hr = topology_loader_connect_direct(decoder_node, 0, downstream_node, input_index, current_mediatype)) + || SUCCEEDED(hr = topology_loader_connect_converter_node(context, decoder_node, 0, downstream_node, input_index, current_mediatype, clsid))) + { + IMFTopology_AddNode(context->output_topology, decoder_node); + IMFTransform_SetOutputType(transform, 0, current_mediatype, 0); + IMFMediaType_Release(current_mediatype); + break; + } + IMFMediaType_Release(current_mediatype); + } + IMFTopologyNode_Release(decoder_node); + } + + IMFTransform_Release(transform); + + if (SUCCEEDED(hr)) + break; + } + for (i = 0; i < count; ++i) + IMFActivate_Release(activators[i]); + CoTaskMemFree(activators); + } + + return hr; +} + static HRESULT topology_loader_connect_nodes(struct topoloader_context *context, IMFTopologyNode *upstream_node, unsigned int output_index, IMFTopologyNode *downstream_node, unsigned int input_index, IMFMediaType *output_type, UINT32 connect_method) { + const GUID *clsid; HRESULT hr; GUID major;
if (FAILED(hr = IMFMediaType_GetMajorType(output_type, &major))) goto out;
+ if (IsEqualGUID(&major, &MFMediaType_Video)) + clsid = &CLSID_VideoProcessorMFT; + else if (IsEqualGUID(&major, &MFMediaType_Audio)) + clsid = &CLSID_CResamplerMediaObject; + else + { + WARN("Unexpected major type %s.\n", debugstr_guid(&major)); + hr = E_UNEXPECTED; + goto out; + } + /* always try first a direct connection */ if (FAILED(hr = topology_loader_connect_direct(upstream_node, output_index, downstream_node, input_index, output_type)) && connect_method != MF_CONNECT_DIRECT) @@ -2105,10 +2225,10 @@ static HRESULT topology_loader_connect_nodes(struct topoloader_context *context, switch (connect_method) { case MF_CONNECT_ALLOW_CONVERTER: - hr = S_OK; + hr = topology_loader_connect_converter_node(context, upstream_node, output_index, downstream_node, input_index, output_type, clsid); break; case MF_CONNECT_ALLOW_DECODER: - hr = S_OK; + hr = topology_loader_connect_decoder_node(context, upstream_node, output_index, downstream_node, input_index, output_type, clsid); break; } }
On 6/15/20 4:41 AM, Sergio Gómez Del Real wrote:
- /* register a converter to test source -> mft -> sink */
- hr = CoRegisterClassObject(&test_conv_clsid, (IUnknown*)&ClassFactoryConv, CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®);
- ok(hr == S_OK, "Failed to register class object, hr %#x.\n");
- typeinfo.guidMajorType = MFMediaType_Audio;
- typeinfo.guidSubtype = MFAudioFormat_ZZZ;
- hr = MFTRegisterLocalByCLSID(&test_conv_clsid, &MFT_CATEGORY_AUDIO_DECODER, str, MFT_ENUM_FLAG_ASYNCMFT, 1, &typeinfo, 1, &typeinfo);
- ok(hr == S_OK, "Failed to register mft, hr %#x.\n");
With MFTRegisterLocal() you won't need to register class object. I don't think ASYNCMFT is essential here, right? We don't currently support async transforms anywhere, so it's better to use default flags.
- hr = MFTUnregister(test_conv_clsid);
- ok(hr == S_OK, "Failed to unregister mft, hr %#x.\n");
- hr = CoRevokeClassObject(reg);
- ok(hr == S_OK, "Failed to unregister class object, hr %#x.\n");
MFTUnregister() is used for globally registered transforms.