From: Ziqing Hui zhui@codeweavers.com
--- dlls/mfreadwrite/writer.c | 138 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 134 insertions(+), 4 deletions(-)
diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index 48ff27f14d1..b901a9b026c 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -172,10 +172,142 @@ static HRESULT create_marker_context(unsigned int marker_type, void *user_contex return S_OK; }
+static HRESULT enum_transforms(IMFMediaType *input_type, IMFMediaType *output_type, BOOL use_encoder, + IMFActivate ***activates, UINT32 *count) +{ + MFT_REGISTER_TYPE_INFO input_type_info, output_type_info; + GUID category; + HRESULT hr; + + /* Get type infos. */ + if (input_type) + { + if (FAILED(hr = IMFMediaType_GetMajorType(input_type, &input_type_info.guidMajorType)) + || FAILED(hr = IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &input_type_info.guidSubtype))) + return hr; + } + if (FAILED(hr = IMFMediaType_GetMajorType(output_type, &output_type_info.guidMajorType)) + || FAILED(hr = IMFMediaType_GetGUID(output_type, &MF_MT_SUBTYPE, &output_type_info.guidSubtype))) + return hr; + + /* Set category according to major type. */ + if (IsEqualGUID(&output_type_info.guidMajorType, &MFMediaType_Video)) + category = use_encoder ? MFT_CATEGORY_VIDEO_ENCODER : MFT_CATEGORY_VIDEO_PROCESSOR; + else if (IsEqualGUID(&output_type_info.guidMajorType, &MFMediaType_Audio)) + category = use_encoder ? MFT_CATEGORY_AUDIO_ENCODER : MFT_CATEGORY_AUDIO_EFFECT; + else + return MF_E_TOPO_CODEC_NOT_FOUND; + + /* Enumerate available transforms. */ + *count = 0; + if (FAILED(hr = MFTEnumEx(category, 0, (input_type ? NULL : &input_type_info), &output_type_info, + activates, count))) + return hr; + if (!*count) + return MF_E_TOPO_CODEC_NOT_FOUND; + + return hr; +} + +static void transform_entry_release(struct transform_entry *entry) +{ + if (entry->transform) + IMFTransform_Release(entry->transform); + free(entry); +} + +static HRESULT create_transform_entry_from_activate(IMFActivate *activate, + IMFMediaType *input_type, IMFMediaType *output_type, struct transform_entry **out) +{ + IMFMediaType *output_current_type = NULL; + struct transform_entry *entry = NULL; + IMFTransform *transform = NULL; + HRESULT hr; + + /* Create object. */ + if (!(entry = calloc(1, sizeof(*entry)))) + return E_OUTOFMEMORY; + + /* Create transform. */ + if (FAILED(hr = IMFActivate_ActivateObject(activate, &IID_IMFTransform, (void **)&transform))) + goto done; + + /* Set output type on transform. */ + if (FAILED(hr = IMFTransform_SetOutputType(transform, 0, output_type, 0)) + || FAILED(hr = IMFTransform_GetOutputCurrentType(transform, 0, &output_current_type))) + goto done; + + /* Set input type on transform. */ + if (input_type) + { + if (FAILED(hr = update_media_type(input_type, output_current_type))) + goto done; + if (FAILED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0))) + goto done; + } + + list_init(&entry->entry); + IMFTransform_AddRef((entry->transform = transform)); + *out = entry; + + TRACE("Created transform entry %p, transform %p.\n", entry, entry->transform); + +done: + if (output_current_type) + IMFMediaType_Release(output_current_type); + if (transform) + IMFTransform_Release(transform); + if (FAILED(hr)) + free(entry); + return hr; +} + static HRESULT create_transform_entry(IMFMediaType *input_type, IMFMediaType *output_type, BOOL use_encoder, struct transform_entry **out) { - return E_NOTIMPL; + struct transform_entry *entry = NULL, *converter = NULL; + IMFMediaType *encoder_input_type; + IMFActivate **activates; + UINT32 count = 0, i; + HRESULT hr; + + if (FAILED(hr = enum_transforms(input_type, output_type, use_encoder, &activates, &count))) + return hr; + + for (i = 0; i < count; i++) + { + if (SUCCEEDED(hr = create_transform_entry_from_activate(activates[i], input_type, output_type, &entry))) + { + TRACE("Create transform entry %p, transform %p.", entry, entry->transform); + *out = entry; + break; + } + + /* Failed to use a single encoder, try using an encoder and a converter. */ + if (use_encoder && SUCCEEDED(hr = create_transform_entry_from_activate(activates[i], NULL, output_type, &entry))) + { + if (SUCCEEDED(hr = IMFTransform_GetInputAvailableType(entry->transform, 0, 0, &encoder_input_type))) + { + hr = create_transform_entry(input_type, encoder_input_type, FALSE, &converter); + IMFMediaType_Release(encoder_input_type); + if (SUCCEEDED(hr)) + { + list_add_head(&entry->entry, &converter->entry); + TRACE("Create converter entry %p, transform %p; encoder entry %p, transform %p.", + converter, converter->transform, entry, entry->transform); + *out = converter; + break; + } + } + transform_entry_release(entry); + } + } + + for (i = 0; i < count; ++i) + IMFActivate_Release(activates[i]); + CoTaskMemFree(activates); + + return hr; }
static void stream_release_transforms(struct stream *stream) @@ -185,9 +317,7 @@ static void stream_release_transforms(struct stream *stream) LIST_FOR_EACH_ENTRY_SAFE(entry, next, &stream->transforms, struct transform_entry, entry) { list_remove(&entry->entry); - if (entry->transform) - IMFTransform_Release(entry->transform); - free(entry); + transform_entry_release(entry); } }