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 d252bab9b3..c4ab17f5e9 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 | 50 +++++++++++++++++++++++++++------------------- 2 files changed, 30 insertions(+), 22 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index c4ab17f5e9..0bcf6a268f 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..3090ba9bce 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,39 @@ 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)) + || FAILED(MFCreateTopology(output_topology)) + || count < 2) + { + hr = MF_E_TOPO_UNSUPPORTED; + 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))) + IMFTopology_Release(*output_topology); + 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); }
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/mf/topology.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index 3090ba9bce..70b9f4962c 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,13 +1961,16 @@ 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(output_topology)) + || FAILED(MFCreateTopology(&context.output_topology)) || count < 2) { hr = MF_E_TOPO_UNSUPPORTED; return hr; }
+ context.input_topology = input_topology; + memset(&context.key, 0xff, sizeof(context.key)); + i = 0; while (SUCCEEDED(IMFTopology_GetNode(input_topology, i++, &node))) { @@ -1971,7 +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(*output_topology); + IMFTopology_Release(context.output_topology); IMFTopologyNode_Release(node); IUnknown_Release(object); hr = MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED; @@ -1985,7 +1997,12 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in IMFTopologyNode_Release(node); }
- return IMFTopology_CloneFrom(*output_topology, input_topology); + if (FAILED(hr = IMFTopology_CloneFrom(context.output_topology, input_topology))) + IMFTopology_Release(context.output_topology); + else + *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 70b9f4962c..83e3b0a7c5 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 83e3b0a7c5..20f351bfb3 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) {
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/mf/tests/mf.c | 5 --- dlls/mf/topology.c | 98 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 90 insertions(+), 13 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 0bcf6a268f..28efe310f6 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 20f351bfb3..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,11 +2138,19 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in IMFTopologyNode_Release(node); }
- if (FAILED(hr = IMFTopology_CloneFrom(context.output_topology, input_topology))) - IMFTopology_Release(context.output_topology); - else - *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 | 75 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-)
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index c51a739aa8..802c26eab8 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -2016,6 +2016,79 @@ 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); + + for (i = 0; i < num_media_types; i++) + { + if (SUCCEEDED(hr = IMFMediaTypeHandler_SetCurrentMediaType(mth_src, src_mediatypes[i]))) + break; + } + + 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 +2115,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;
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 802c26eab8..1284bde12a 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -2089,6 +2089,34 @@ static HRESULT topology_loader_connect_source(struct topoloader_context *context 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; @@ -2118,7 +2146,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 | 134 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 129 insertions(+), 5 deletions(-)
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index 1284bde12a..3ee8ddc40b 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) { @@ -2074,13 +2175,36 @@ static HRESULT topology_loader_connect_source(struct topoloader_context *context src_mediatypes[0] = mtype_src;
hr = IMFAttributes_GetUINT32(attrs_src, &MF_TOPONODE_CONNECT_METHOD, &method); - - for (i = 0; i < num_media_types; i++) + if (!enum_src_types || (hr == S_OK && !(method & MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES))) { - if (SUCCEEDED(hr = IMFMediaTypeHandler_SetCurrentMediaType(mth_src, src_mediatypes[i]))) - break; + 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]); + if (SUCCEEDED(hr = topology_loader_connect_nodes(context, source_node, 0, downstream_node, input_index, src_mediatypes[i], method))) + goto out; + } + if (method == MF_CONNECT_ALLOW_CONVERTER) + method++; + } + } + 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]); + if (SUCCEEDED(hr = topology_loader_connect_nodes(context, source_node, 0, downstream_node, input_index, src_mediatypes[i], method))) + goto out; + if (method == MF_CONNECT_ALLOW_CONVERTER) + method++; + } + } }
+out: while (num_media_types--) IMFMediaType_Release(src_mediatypes[num_media_types]); IMFMediaTypeHandler_Release(mth_src); @@ -2105,7 +2229,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 28efe310f6..0d7ab15d8a 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 3ee8ddc40b..d278f84899 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; } }