-- v3: mfreadwrite/reader: Implement IMFSourceReaderEx_GetTransformForStream. mfreadwrite/reader: Create and append a converter transform. mfreadwrite/reader: Keep the stream transforms in a list. mfreadwrite/reader: Call SetOutputType directly on the decoder transform. mf/topology_loader: Only propagate some media type attributes. mfreadwrite/reader: Split source_reader_create_decoder_for_stream helper.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mfreadwrite/reader.c | 61 +++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 32 deletions(-)
diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 6e895667ef6..0ee6a173832 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -1825,56 +1825,53 @@ static HRESULT source_reader_configure_decoder(struct source_reader *reader, DWO return MF_E_TOPO_CODEC_NOT_FOUND; }
-static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type) +static HRESULT source_reader_create_transform(struct source_reader *reader, DWORD index, + IMFMediaType *input_type, IMFMediaType *output_type) { MFT_REGISTER_TYPE_INFO in_type, out_type; - CLSID *clsids, mft_clsid, category; - unsigned int i = 0, count; - IMFMediaType *input_type; + GUID *classes, category; HRESULT hr; + UINT count;
- /* TODO: should we check if the source type is compressed? */ - - if (FAILED(hr = IMFMediaType_GetMajorType(output_type, &out_type.guidMajorType))) + if (FAILED(hr = IMFMediaType_GetMajorType(input_type, &in_type.guidMajorType)) + || FAILED(hr = IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &in_type.guidSubtype))) + return hr; + if (FAILED(hr = IMFMediaType_GetMajorType(output_type, &out_type.guidMajorType)) + || FAILED(hr = IMFMediaType_GetGUID(output_type, &MF_MT_SUBTYPE, &out_type.guidSubtype))) return hr;
if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Video)) - { category = MFT_CATEGORY_VIDEO_DECODER; - } else if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio)) - { category = MFT_CATEGORY_AUDIO_DECODER; - } else - { - WARN("Unhandled major type %s.\n", debugstr_guid(&out_type.guidMajorType)); return MF_E_TOPO_CODEC_NOT_FOUND; + + count = 0; + if (SUCCEEDED(hr = MFTEnum(category, 0, &in_type, &out_type, NULL, &classes, &count))) + { + if (!count) + return MF_E_TOPO_CODEC_NOT_FOUND; + /* TODO: Should we iterate over all of them? */ + hr = source_reader_configure_decoder(reader, index, &classes[0], input_type, output_type); + CoTaskMemFree(classes); }
- if (FAILED(hr = IMFMediaType_GetGUID(output_type, &MF_MT_SUBTYPE, &out_type.guidSubtype))) - return hr; + return hr; +}
- in_type.guidMajorType = out_type.guidMajorType; +static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type) +{ + IMFMediaType *input_type; + unsigned int i = 0; + HRESULT hr;
- while (source_reader_get_native_media_type(reader, index, i++, &input_type) == S_OK) + while (SUCCEEDED(hr = source_reader_get_native_media_type(reader, index, i++, &input_type))) { - if (SUCCEEDED(IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &in_type.guidSubtype))) + if (SUCCEEDED(hr = source_reader_create_transform(reader, index, input_type, output_type))) { - count = 0; - if (SUCCEEDED(hr = MFTEnum(category, 0, &in_type, &out_type, NULL, &clsids, &count)) && count) - { - mft_clsid = clsids[0]; - CoTaskMemFree(clsids); - - /* TODO: Should we iterate over all of them? */ - if (SUCCEEDED(source_reader_configure_decoder(reader, index, &mft_clsid, input_type, output_type))) - { - IMFMediaType_Release(input_type); - return S_OK; - } - - } + IMFMediaType_Release(input_type); + return S_OK; }
IMFMediaType_Release(input_type);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/topology_loader.c | 59 +++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 18 deletions(-)
diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 50d9d3bd74f..4e6cf6ca33e 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -215,26 +215,49 @@ static HRESULT topology_node_list_branches(IMFTopologyNode *node, struct list *b return hr; }
-static HRESULT topology_branch_fill_media_type(IMFMediaType *up_type, IMFMediaType *down_type) +static void media_type_try_copy_attr(IMFMediaType *dst, IMFMediaType *src, const GUID *attr, HRESULT *hr) { - HRESULT hr = S_OK; PROPVARIANT value; - UINT32 count; - GUID key;
- if (FAILED(hr = IMFMediaType_GetCount(up_type, &count))) - return hr; + PropVariantInit(&value); + if (SUCCEEDED(*hr) && FAILED(IMFMediaType_GetItem(dst, attr, NULL)) + && SUCCEEDED(IMFMediaType_GetItem(src, attr, &value))) + *hr = IMFMediaType_SetItem(dst, attr, &value); + PropVariantClear(&value); +}
- while (count--) - { - PropVariantInit(&value); - hr = IMFMediaType_GetItemByIndex(up_type, count, &key, &value); - if (SUCCEEDED(hr) && FAILED(IMFMediaType_GetItem(down_type, &key, NULL))) - hr = IMFMediaType_SetItem(down_type, &key, &value); - PropVariantClear(&value); - if (FAILED(hr)) - return hr; - } +/* update a media type with additional attributes reported by upstream element */ +/* also present in mfreadwrite/reader.c pipeline */ +static HRESULT update_media_type_from_upstream(IMFMediaType *media_type, IMFMediaType *upstream_type) +{ + HRESULT hr = S_OK; + + /* propagate common video attributes */ + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FRAME_SIZE, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FRAME_RATE, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_ROTATION, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FIXED_SIZE_SAMPLES, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_PIXEL_ASPECT_RATIO, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, &hr); + + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_CHROMA_SITING, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_INTERLACE_MODE, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_TRANSFER_FUNCTION, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_PRIMARIES, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_YUV_MATRIX, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_LIGHTING, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_NOMINAL_RANGE, &hr); + + /* propagate common audio attributes */ + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_NUM_CHANNELS, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_CHANNEL_MASK, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_SAMPLES_PER_BLOCK, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, &hr);
return hr; } @@ -310,7 +333,7 @@ static HRESULT topology_branch_connect_indirect(IMFTopology *topology, MF_CONNEC hr = topology_branch_connect_down(topology, MF_CONNECT_DIRECT, &up_branch, up_type); if (down_type) { - if (SUCCEEDED(topology_branch_fill_media_type(up_type, down_type)) + if (SUCCEEDED(update_media_type_from_upstream(down_type, up_type)) && SUCCEEDED(IMFTransform_SetOutputType(transform, 0, down_type, 0))) method = MF_CONNECT_DIRECT; } @@ -319,7 +342,7 @@ static HRESULT topology_branch_connect_indirect(IMFTopology *topology, MF_CONNEC if (SUCCEEDED(hr) && method != MF_CONNECT_DIRECT && SUCCEEDED(IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type))) { - if (SUCCEEDED(topology_branch_fill_media_type(up_type, media_type))) + if (SUCCEEDED(update_media_type_from_upstream(media_type, up_type))) IMFTransform_SetOutputType(transform, 0, media_type, 0); IMFMediaType_Release(media_type); }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mfreadwrite/reader.c | 169 ++++++++++++++++++++++---------------- 1 file changed, 97 insertions(+), 72 deletions(-)
diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 0ee6a173832..94b472b6b89 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -678,6 +678,53 @@ static HRESULT source_reader_allocate_stream_sample(MFT_OUTPUT_STREAM_INFO *info return hr; }
+static void media_type_try_copy_attr(IMFMediaType *dst, IMFMediaType *src, const GUID *attr, HRESULT *hr) +{ + PROPVARIANT value; + + PropVariantInit(&value); + if (SUCCEEDED(*hr) && FAILED(IMFMediaType_GetItem(dst, attr, NULL)) + && SUCCEEDED(IMFMediaType_GetItem(src, attr, &value))) + *hr = IMFMediaType_SetItem(dst, attr, &value); + PropVariantClear(&value); +} + +/* update a media type with additional attributes reported by upstream element */ +/* also present in mf/topology_loader.c pipeline */ +static HRESULT update_media_type_from_upstream(IMFMediaType *media_type, IMFMediaType *upstream_type) +{ + HRESULT hr = S_OK; + + /* propagate common video attributes */ + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FRAME_SIZE, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FRAME_RATE, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_ROTATION, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FIXED_SIZE_SAMPLES, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_PIXEL_ASPECT_RATIO, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, &hr); + + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_CHROMA_SITING, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_INTERLACE_MODE, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_TRANSFER_FUNCTION, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_PRIMARIES, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_YUV_MATRIX, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_LIGHTING, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_NOMINAL_RANGE, &hr); + + /* propagate common audio attributes */ + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_NUM_CHANNELS, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_CHANNEL_MASK, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_SAMPLES_PER_BLOCK, &hr); + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, &hr); + + return hr; +} + static HRESULT source_reader_pull_transform_samples(struct source_reader *reader, struct media_stream *stream, struct transform_entry *entry); static HRESULT source_reader_push_transform_samples(struct source_reader *reader, struct media_stream *stream, @@ -1756,82 +1803,16 @@ static HRESULT source_reader_setup_sample_allocator(struct source_reader *reader return hr; }
-static HRESULT source_reader_configure_decoder(struct source_reader *reader, DWORD index, const CLSID *clsid, - IMFMediaType *input_type, IMFMediaType *output_type) -{ - IMFMediaTypeHandler *type_handler; - unsigned int block_alignment = 0; - IMFTransform *transform = NULL; - IMFMediaType *type = NULL; - GUID major = { 0 }; - DWORD flags; - HRESULT hr; - int i = 0; - - if (FAILED(hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform))) - { - WARN("Failed to create transform object, hr %#lx.\n", hr); - return hr; - } - - if (FAILED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0))) - { - WARN("Failed to set decoder input type, hr %#lx.\n", hr); - IMFTransform_Release(transform); - return hr; - } - - /* Find the relevant output type. */ - while (IMFTransform_GetOutputAvailableType(transform, 0, i++, &type) == S_OK) - { - flags = 0; - - if (SUCCEEDED(IMFMediaType_IsEqual(type, output_type, &flags))) - { - if (flags & MF_MEDIATYPE_EQUAL_FORMAT_TYPES) - { - if (SUCCEEDED(IMFTransform_SetOutputType(transform, 0, type, 0))) - { - if (SUCCEEDED(source_reader_get_source_type_handler(reader, index, &type_handler))) - { - IMFMediaTypeHandler_SetCurrentMediaType(type_handler, input_type); - IMFMediaTypeHandler_Release(type_handler); - } - - if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)reader->streams[index].current))) - WARN("Failed to copy attributes, hr %#lx.\n", hr); - if (SUCCEEDED(IMFMediaType_GetMajorType(type, &major)) && IsEqualGUID(&major, &MFMediaType_Audio)) - IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment); - IMFMediaType_Release(type); - - if (reader->streams[index].decoder.transform) - IMFTransform_Release(reader->streams[index].decoder.transform); - - reader->streams[index].decoder.transform = transform; - reader->streams[index].decoder.min_buffer_size = block_alignment; - - return S_OK; - } - } - } - - IMFMediaType_Release(type); - } - - WARN("Failed to find suitable decoder output type.\n"); - - IMFTransform_Release(transform); - - return MF_E_TOPO_CODEC_NOT_FOUND; -} - static HRESULT source_reader_create_transform(struct source_reader *reader, DWORD index, IMFMediaType *input_type, IMFMediaType *output_type) { + struct media_stream *stream = &reader->streams[index]; + struct transform_entry *entry = &stream->decoder; MFT_REGISTER_TYPE_INFO in_type, out_type; GUID *classes, category; + IMFTransform *transform; + UINT i, count; HRESULT hr; - UINT count;
if (FAILED(hr = IMFMediaType_GetMajorType(input_type, &in_type.guidMajorType)) || FAILED(hr = IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &in_type.guidSubtype))) @@ -1847,13 +1828,39 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, DWOR else return MF_E_TOPO_CODEC_NOT_FOUND;
+ if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio)) + IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, + &entry->min_buffer_size); + count = 0; if (SUCCEEDED(hr = MFTEnum(category, 0, &in_type, &out_type, NULL, &classes, &count))) { if (!count) return MF_E_TOPO_CODEC_NOT_FOUND; - /* TODO: Should we iterate over all of them? */ - hr = source_reader_configure_decoder(reader, index, &classes[0], input_type, output_type); + + for (i = 0; i < count; i++) + { + IMFMediaType *media_type; + + if (FAILED(hr = CoCreateInstance(&classes[i], NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform))) + break; + if (SUCCEEDED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0)) + && SUCCEEDED(hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type))) + { + if (SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type))) + hr = IMFTransform_SetOutputType(transform, 0, output_type, 0); + IMFMediaType_Release(media_type); + + if (SUCCEEDED(hr)) + { + entry->transform = transform; + return S_OK; + } + } + + IMFTransform_Release(transform); + } + CoTaskMemFree(classes); }
@@ -1862,6 +1869,7 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, DWOR
static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type) { + struct media_stream *stream = &reader->streams[index]; IMFMediaType *input_type; unsigned int i = 0; HRESULT hr; @@ -1870,6 +1878,23 @@ static HRESULT source_reader_create_decoder_for_stream(struct source_reader *rea { if (SUCCEEDED(hr = source_reader_create_transform(reader, index, input_type, output_type))) { + IMFMediaTypeHandler *type_handler; + + if (SUCCEEDED(source_reader_get_source_type_handler(reader, index, &type_handler))) + { + if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, input_type))) + WARN("Failed to set current input media type, hr %#lx\n", hr); + IMFMediaTypeHandler_Release(type_handler); + } + + if (FAILED(hr = IMFTransform_GetOutputCurrentType(stream->decoder.transform, 0, &output_type))) + WARN("Failed to get decoder output media type, hr %#lx\n", hr); + else + { + IMFMediaType_CopyAllItems(output_type, (IMFAttributes *)stream->current); + IMFMediaType_Release(output_type); + } + IMFMediaType_Release(input_type); return S_OK; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mfreadwrite/reader.c | 133 +++++++++++++++++++++++++++++--------- 1 file changed, 103 insertions(+), 30 deletions(-)
diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 94b472b6b89..039935b253a 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -73,6 +73,7 @@ enum media_stream_flags
struct transform_entry { + struct list entry; IMFTransform *transform; unsigned int min_buffer_size; }; @@ -81,7 +82,7 @@ struct media_stream { IMFMediaStream *stream; IMFMediaType *current; - struct transform_entry decoder; + struct list transforms; IMFVideoSampleAllocatorEx *allocator; DWORD id; unsigned int index; @@ -202,6 +203,30 @@ static ULONG source_reader_addref(struct source_reader *reader) return InterlockedIncrement(&reader->refcount); }
+static void transform_entry_destroy(struct transform_entry *entry) +{ + IMFTransform_Release(entry->transform); + free(entry); +} + +static void media_stream_destroy(struct media_stream *stream) +{ + struct transform_entry *entry, *next; + + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &stream->transforms, struct transform_entry, entry) + { + list_remove(&entry->entry); + transform_entry_destroy(entry); + } + + if (stream->stream) + IMFMediaStream_Release(stream->stream); + if (stream->current) + IMFMediaType_Release(stream->current); + if (stream->allocator) + IMFVideoSampleAllocatorEx_Release(stream->allocator); +} + static ULONG source_reader_release(struct source_reader *reader) { ULONG refcount = InterlockedDecrement(&reader->refcount); @@ -222,15 +247,7 @@ static ULONG source_reader_release(struct source_reader *reader) for (i = 0; i < reader->stream_count; ++i) { struct media_stream *stream = &reader->streams[i]; - - if (stream->stream) - IMFMediaStream_Release(stream->stream); - if (stream->current) - IMFMediaType_Release(stream->current); - if (stream->decoder.transform) - IMFTransform_Release(stream->decoder.transform); - if (stream->allocator) - IMFVideoSampleAllocatorEx_Release(stream->allocator); + media_stream_destroy(stream); } source_reader_release_responses(reader, NULL); free(reader->streams); @@ -748,10 +765,15 @@ static HRESULT source_reader_push_transform_samples(struct source_reader *reader static HRESULT source_reader_pull_transform_samples(struct source_reader *reader, struct media_stream *stream, struct transform_entry *entry) { - MFT_OUTPUT_STREAM_INFO stream_info = { 0 }; + MFT_OUTPUT_STREAM_INFO stream_info = {0}; + struct transform_entry *next = NULL; + struct list *ptr; DWORD status; HRESULT hr;
+ if ((ptr = list_next(&stream->transforms, &entry->entry))) + next = LIST_ENTRY(ptr, struct transform_entry, entry); + if (FAILED(hr = IMFTransform_GetOutputStreamInfo(entry->transform, 0, &stream_info))) return hr; stream_info.cbSize = max(stream_info.cbSize, entry->min_buffer_size); @@ -764,8 +786,13 @@ static HRESULT source_reader_pull_transform_samples(struct source_reader *reader && FAILED(hr = source_reader_allocate_stream_sample(&stream_info, &out_buffer.pSample))) break;
- if (SUCCEEDED(hr = IMFTransform_ProcessOutput(stream->decoder.transform, 0, 1, &out_buffer, &status))) - hr = source_reader_queue_sample(reader, stream, out_buffer.pSample); + if (SUCCEEDED(hr = IMFTransform_ProcessOutput(entry->transform, 0, 1, &out_buffer, &status))) + { + if (next) + hr = source_reader_push_transform_samples(reader, stream, next, out_buffer.pSample); + else + hr = source_reader_queue_sample(reader, stream, out_buffer.pSample); + }
if (out_buffer.pSample) IMFSample_Release(out_buffer.pSample); @@ -779,38 +806,51 @@ static HRESULT source_reader_pull_transform_samples(struct source_reader *reader static HRESULT source_reader_drain_transform_samples(struct source_reader *reader, struct media_stream *stream, struct transform_entry *entry) { + struct transform_entry *next = NULL; + struct list *ptr; HRESULT hr;
+ if ((ptr = list_next(&stream->transforms, &entry->entry))) + next = LIST_ENTRY(ptr, struct transform_entry, entry); + if (FAILED(hr = IMFTransform_ProcessMessage(entry->transform, MFT_MESSAGE_COMMAND_DRAIN, 0))) WARN("Failed to drain transform %p, hr %#lx\n", entry->transform, hr); if (FAILED(hr = source_reader_pull_transform_samples(reader, stream, entry)) && hr != MF_E_TRANSFORM_NEED_MORE_INPUT) WARN("Failed to pull pending samples, hr %#lx.\n", hr);
- return S_OK; + return next ? source_reader_drain_transform_samples(reader, stream, next) : S_OK; }
static HRESULT source_reader_flush_transform_samples(struct source_reader *reader, struct media_stream *stream, struct transform_entry *entry) { + struct transform_entry *next = NULL; + struct list *ptr; HRESULT hr;
+ if ((ptr = list_next(&stream->transforms, &entry->entry))) + next = LIST_ENTRY(ptr, struct transform_entry, entry); + if (FAILED(hr = IMFTransform_ProcessMessage(entry->transform, MFT_MESSAGE_COMMAND_FLUSH, 0))) WARN("Failed to flush transform %p, hr %#lx\n", entry->transform, hr);
- return S_OK; + return next ? source_reader_flush_transform_samples(reader, stream, next) : S_OK; }
static HRESULT source_reader_process_sample(struct source_reader *reader, struct media_stream *stream, IMFSample *sample) { + struct transform_entry *entry; + struct list *ptr; HRESULT hr;
- if (!stream->decoder.transform) + if (!(ptr = list_head(&stream->transforms))) return source_reader_queue_sample(reader, stream, sample); + entry = LIST_ENTRY(ptr, struct transform_entry, entry);
/* It's assumed that decoder has 1 input and 1 output, both id's are 0. */ - if (SUCCEEDED(hr = source_reader_push_transform_samples(reader, stream, &stream->decoder, sample)) + if (SUCCEEDED(hr = source_reader_push_transform_samples(reader, stream, entry, sample)) || hr == MF_E_TRANSFORM_NEED_MORE_INPUT) hr = stream->requests ? source_reader_request_sample(reader, stream) : S_OK; else @@ -894,12 +934,16 @@ static HRESULT source_reader_media_stream_state_handler(struct source_reader *re switch (event_type) { case MEEndOfStream: + { + struct list *ptr; + stream->state = STREAM_STATE_EOS; stream->flags &= ~STREAM_FLAG_SAMPLE_REQUESTED;
- if (stream->decoder.transform) + if ((ptr = list_head(&stream->transforms))) { - if (FAILED(hr = source_reader_drain_transform_samples(reader, stream, &stream->decoder))) + struct transform_entry *entry = LIST_ENTRY(ptr, struct transform_entry, entry); + if (FAILED(hr = source_reader_drain_transform_samples(reader, stream, entry))) WARN("Failed to drain pending samples, hr %#lx.\n", hr); }
@@ -907,6 +951,7 @@ static HRESULT source_reader_media_stream_state_handler(struct source_reader *re source_reader_queue_response(reader, stream, S_OK, MF_SOURCE_READERF_ENDOFSTREAM, 0, NULL);
break; + } case MEStreamSeeked: case MEStreamStarted: stream->state = STREAM_STATE_READY; @@ -1259,13 +1304,15 @@ static void source_reader_release_responses(struct source_reader *reader, struct static void source_reader_flush_stream(struct source_reader *reader, DWORD stream_index) { struct media_stream *stream = &reader->streams[stream_index]; + struct list *ptr; HRESULT hr;
source_reader_release_responses(reader, stream);
- if (stream->decoder.transform) + if ((ptr = list_head(&stream->transforms))) { - if (FAILED(hr = source_reader_flush_transform_samples(reader, stream, &stream->decoder))) + struct transform_entry *entry = LIST_ENTRY(ptr, struct transform_entry, entry); + if (FAILED(hr = source_reader_flush_transform_samples(reader, stream, entry))) WARN("Failed to drain pending samples, hr %#lx.\n", hr); }
@@ -1700,6 +1747,8 @@ static HRESULT source_reader_get_source_type_handler(struct source_reader *reade
static HRESULT source_reader_set_compatible_media_type(struct source_reader *reader, DWORD index, IMFMediaType *type) { + struct media_stream *stream = &reader->streams[index]; + struct transform_entry *entry, *next; IMFMediaTypeHandler *type_handler; IMFMediaType *native_type; BOOL type_set = FALSE; @@ -1707,7 +1756,7 @@ static HRESULT source_reader_set_compatible_media_type(struct source_reader *rea DWORD flags; HRESULT hr;
- if (FAILED(hr = IMFMediaType_IsEqual(type, reader->streams[index].current, &flags))) + if (FAILED(hr = IMFMediaType_IsEqual(type, stream->current, &flags))) return hr;
if (!(flags & MF_MEDIATYPE_EQUAL_MAJOR_TYPES)) @@ -1717,6 +1766,12 @@ static HRESULT source_reader_set_compatible_media_type(struct source_reader *rea if (flags & MF_MEDIATYPE_EQUAL_FORMAT_DATA) return S_OK;
+ LIST_FOR_EACH_ENTRY_SAFE(entry, next, &stream->transforms, struct transform_entry, entry) + { + list_remove(&entry->entry); + transform_entry_destroy(entry); + } + if (FAILED(hr = source_reader_get_source_type_handler(reader, index, &type_handler))) return hr;
@@ -1727,7 +1782,7 @@ static HRESULT source_reader_set_compatible_media_type(struct source_reader *rea if (SUCCEEDED(IMFMediaType_IsEqual(native_type, type, &flags)) && (flags & compare_flags) == compare_flags) { if ((type_set = SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(type_handler, native_type)))) - IMFMediaType_CopyAllItems(native_type, (IMFAttributes *)reader->streams[index].current); + IMFMediaType_CopyAllItems(native_type, (IMFAttributes *)stream->current); }
IMFMediaType_Release(native_type); @@ -1803,12 +1858,11 @@ static HRESULT source_reader_setup_sample_allocator(struct source_reader *reader return hr; }
-static HRESULT source_reader_create_transform(struct source_reader *reader, DWORD index, - IMFMediaType *input_type, IMFMediaType *output_type) +static HRESULT source_reader_create_transform(struct source_reader *reader, + IMFMediaType *input_type, IMFMediaType *output_type, struct transform_entry **out) { - struct media_stream *stream = &reader->streams[index]; - struct transform_entry *entry = &stream->decoder; MFT_REGISTER_TYPE_INFO in_type, out_type; + struct transform_entry *entry; GUID *classes, category; IMFTransform *transform; UINT i, count; @@ -1828,6 +1882,9 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, DWOR else return MF_E_TOPO_CODEC_NOT_FOUND;
+ if (!(entry = calloc(1, sizeof(*entry)))) + return E_OUTOFMEMORY; + if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio)) IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &entry->min_buffer_size); @@ -1854,6 +1911,7 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, DWOR if (SUCCEEDED(hr)) { entry->transform = transform; + *out = entry; return S_OK; } } @@ -1864,6 +1922,7 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, DWOR CoTaskMemFree(classes); }
+ free(entry); return hr; }
@@ -1876,10 +1935,14 @@ static HRESULT source_reader_create_decoder_for_stream(struct source_reader *rea
while (SUCCEEDED(hr = source_reader_get_native_media_type(reader, index, i++, &input_type))) { - if (SUCCEEDED(hr = source_reader_create_transform(reader, index, input_type, output_type))) + struct transform_entry *entry; + + if (SUCCEEDED(hr = source_reader_create_transform(reader, input_type, output_type, &entry))) { IMFMediaTypeHandler *type_handler;
+ list_add_tail(&stream->transforms, &entry->entry); + if (SUCCEEDED(source_reader_get_source_type_handler(reader, index, &type_handler))) { if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, input_type))) @@ -1887,7 +1950,7 @@ static HRESULT source_reader_create_decoder_for_stream(struct source_reader *rea IMFMediaTypeHandler_Release(type_handler); }
- if (FAILED(hr = IMFTransform_GetOutputCurrentType(stream->decoder.transform, 0, &output_type))) + if (FAILED(hr = IMFTransform_GetOutputCurrentType(entry->transform, 0, &output_type))) WARN("Failed to get decoder output media type, hr %#lx\n", hr); else { @@ -2180,6 +2243,7 @@ static HRESULT WINAPI src_reader_GetServiceForStream(IMFSourceReaderEx *iface, D REFIID riid, void **object) { struct source_reader *reader = impl_from_IMFSourceReaderEx(iface); + struct media_stream *stream = &reader->streams[index]; IUnknown *obj = NULL; HRESULT hr = S_OK;
@@ -2202,7 +2266,14 @@ static HRESULT WINAPI src_reader_GetServiceForStream(IMFSourceReaderEx *iface, D hr = MF_E_INVALIDSTREAMNUMBER; else { - obj = (IUnknown *)reader->streams[index].decoder.transform; + struct list *ptr; + + if ((ptr = list_tail(&stream->transforms))) + { + struct transform_entry *entry = LIST_ENTRY(ptr, struct transform_entry, entry); + obj = (IUnknown *)entry->transform; + } + if (!obj) hr = E_NOINTERFACE; } break; @@ -2425,6 +2496,8 @@ static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttri IMFMediaType *src_type; BOOL selected;
+ list_init(&object->streams[i].transforms); + if (FAILED(hr = MFCreateMediaType(&object->streams[i].current))) break;
From: Rémi Bernon rbernon@codeweavers.com
This enables advanced color conversion in all cases, and thus allows NV12 -> RGB32 conversion even when MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING is not set. This should be harmless and makes the code simpler as we can simply append a VideoProcessor transform in all cases.
The tests todos is tweaked to reflect cases where a single processor is used, which outputs slightly different attributes to when it is connected to an upstream decoder. Ultimately we could try to match native here, but it shouldn't matter too much in the meantime. --- dlls/mfreadwrite/reader.c | 95 +++++++++++++++++++++++++-------- dlls/mfreadwrite/tests/mfplat.c | 65 +++++++++++++--------- 2 files changed, 114 insertions(+), 46 deletions(-)
diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 039935b253a..9ff34f77151 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -76,6 +76,7 @@ struct transform_entry struct list entry; IMFTransform *transform; unsigned int min_buffer_size; + GUID category; };
struct media_stream @@ -84,6 +85,7 @@ struct media_stream IMFMediaType *current; struct list transforms; IMFVideoSampleAllocatorEx *allocator; + IMFTransform *transform_service; DWORD id; unsigned int index; enum media_stream_state state; @@ -1766,6 +1768,11 @@ static HRESULT source_reader_set_compatible_media_type(struct source_reader *rea if (flags & MF_MEDIATYPE_EQUAL_FORMAT_DATA) return S_OK;
+ if (stream->transform_service) + { + IMFTransform_Release(stream->transform_service); + stream->transform_service = NULL; + } LIST_FOR_EACH_ENTRY_SAFE(entry, next, &stream->transforms, struct transform_entry, entry) { list_remove(&entry->entry); @@ -1858,7 +1865,23 @@ static HRESULT source_reader_setup_sample_allocator(struct source_reader *reader return hr; }
-static HRESULT source_reader_create_transform(struct source_reader *reader, +static BOOL source_reader_allow_video_processor(struct source_reader *reader, BOOL *advanced) +{ + UINT32 value; + + *advanced = FALSE; + if (!reader->attributes) + return FALSE; + + if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, &value))) + *advanced = value; + if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, &value))) + return value || *advanced; + + return *advanced; +} + +static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL decoder, BOOL allow_processor, IMFMediaType *input_type, IMFMediaType *output_type, struct transform_entry **out) { MFT_REGISTER_TYPE_INFO in_type, out_type; @@ -1876,21 +1899,23 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, return hr;
if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Video)) - category = MFT_CATEGORY_VIDEO_DECODER; + category = decoder ? MFT_CATEGORY_VIDEO_DECODER : MFT_CATEGORY_VIDEO_PROCESSOR; else if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio)) - category = MFT_CATEGORY_AUDIO_DECODER; + category = decoder ? MFT_CATEGORY_AUDIO_DECODER : MFT_CATEGORY_AUDIO_EFFECT; else return MF_E_TOPO_CODEC_NOT_FOUND;
if (!(entry = calloc(1, sizeof(*entry)))) return E_OUTOFMEMORY; + list_init(&entry->entry); + entry->category = category;
if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio)) IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &entry->min_buffer_size);
count = 0; - if (SUCCEEDED(hr = MFTEnum(category, 0, &in_type, &out_type, NULL, &classes, &count))) + if (SUCCEEDED(hr = MFTEnum(category, 0, &in_type, allow_processor ? NULL : &out_type, NULL, &classes, &count))) { if (!count) return MF_E_TOPO_CODEC_NOT_FOUND; @@ -1904,9 +1929,19 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, if (SUCCEEDED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0)) && SUCCEEDED(hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type))) { - if (SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type))) - hr = IMFTransform_SetOutputType(transform, 0, output_type, 0); - IMFMediaType_Release(media_type); + if (SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type)) + && FAILED(hr = IMFTransform_SetOutputType(transform, 0, output_type, 0)) && allow_processor + && SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type))) + { + struct transform_entry *converter; + + if (SUCCEEDED(hr = IMFTransform_SetOutputType(transform, 0, media_type, 0)) + && SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type)) + && SUCCEEDED(hr = source_reader_create_transform(reader, FALSE, FALSE, media_type, output_type, &converter))) + list_add_tail(&entry->entry, &converter->entry); + + IMFMediaType_Release(media_type); + }
if (SUCCEEDED(hr)) { @@ -1928,20 +1963,46 @@ static HRESULT source_reader_create_transform(struct source_reader *reader,
static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type) { + BOOL enable_advanced, allow_processor; struct media_stream *stream = &reader->streams[index]; IMFMediaType *input_type; unsigned int i = 0; HRESULT hr;
+ allow_processor = source_reader_allow_video_processor(reader, &enable_advanced); + while (SUCCEEDED(hr = source_reader_get_native_media_type(reader, index, i++, &input_type))) { struct transform_entry *entry;
- if (SUCCEEDED(hr = source_reader_create_transform(reader, input_type, output_type, &entry))) + /* first, try to append a single processor, then try again with a decoder and a processor */ + if ((allow_processor && SUCCEEDED(hr = source_reader_create_transform(reader, FALSE, FALSE, input_type, output_type, &entry))) + || SUCCEEDED(hr = source_reader_create_transform(reader, TRUE, allow_processor, input_type, output_type, &entry))) { + struct list *ptr = list_head(&entry->entry); + struct transform_entry *service = ptr ? LIST_ENTRY(ptr, struct transform_entry, entry) : entry; IMFMediaTypeHandler *type_handler;
- list_add_tail(&stream->transforms, &entry->entry); + if (enable_advanced) + { + /* when advanced video processing is enabled, converters are exposed as stream transform service */ + stream->transform_service = service->transform; + IMFTransform_AddRef(stream->transform_service); + } + else + { + /* when advanced video processing is disabled, only decoders are exposed as stream transform service */ + if (IsEqualGUID(&entry->category, &MFT_CATEGORY_AUDIO_DECODER) + || IsEqualGUID(&entry->category, &MFT_CATEGORY_VIDEO_DECODER)) + { + stream->transform_service = entry->transform; + IMFTransform_AddRef(stream->transform_service); + } + } + + /* move any additional transforms that have been created */ + list_move_head(&stream->transforms, &entry->entry); + list_add_head(&stream->transforms, &entry->entry);
if (SUCCEEDED(source_reader_get_source_type_handler(reader, index, &type_handler))) { @@ -1950,7 +2011,7 @@ static HRESULT source_reader_create_decoder_for_stream(struct source_reader *rea IMFMediaTypeHandler_Release(type_handler); }
- if (FAILED(hr = IMFTransform_GetOutputCurrentType(entry->transform, 0, &output_type))) + if (FAILED(hr = IMFTransform_GetOutputCurrentType(service->transform, 0, &output_type))) WARN("Failed to get decoder output media type, hr %#lx\n", hr); else { @@ -2264,18 +2325,8 @@ static HRESULT WINAPI src_reader_GetServiceForStream(IMFSourceReaderEx *iface, D
if (index >= reader->stream_count) hr = MF_E_INVALIDSTREAMNUMBER; - else - { - struct list *ptr; - - if ((ptr = list_tail(&stream->transforms))) - { - struct transform_entry *entry = LIST_ENTRY(ptr, struct transform_entry, entry); - obj = (IUnknown *)entry->transform; - } - - if (!obj) hr = E_NOINTERFACE; - } + else if (!(obj = (IUnknown *)stream->transform_service)) + hr = E_NOINTERFACE; break; }
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 08e19589ad1..91f9641ccfc 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -909,7 +909,7 @@ static void test_source_reader(const char *filename, bool video) hr = IMFMediaType_SetGUID(mediatype, &MF_MT_SUBTYPE, &MFVideoFormat_RGB32); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFSourceReader_SetCurrentMediaType(reader, MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, mediatype); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); IMFMediaType_Release(mediatype);
if (hr == S_OK) @@ -922,7 +922,7 @@ static void test_source_reader(const char *filename, bool video) ok(IsEqualGUID(&subtype, &MFVideoFormat_RGB32), "Got subtype %s.\n", debugstr_guid(&subtype));
hr = IMFMediaType_GetUINT32(mediatype, &MF_MT_DEFAULT_STRIDE, &stride); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); todo_wine ok(stride == 160 * 4, "Got stride %u.\n", stride);
IMFMediaType_Release(mediatype); @@ -1687,7 +1687,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad static const struct attribute_desc nv12_expect_advanced_desc[] = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12, .todo_value = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12), ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE), ATTR_UINT32(MF_MT_COMPRESSED, 0, .todo = TRUE), @@ -1721,7 +1721,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad static const struct attribute_desc yuy2_expect_advanced_desc[] = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YUY2, .todo_value = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YUY2), ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE), ATTR_UINT32(MF_MT_COMPRESSED, 0, .todo = TRUE), @@ -1738,7 +1738,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad static const struct attribute_desc rgb32_expect_desc[] = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .todo_value = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE), ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 384, .todo = TRUE), @@ -1746,15 +1746,24 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad ATTR_UINT32(MF_MT_SAMPLE_SIZE, 36864, .todo = TRUE), {0}, }; - static const struct attribute_desc rgb32_expect_advanced_desc[] = + static const struct attribute_desc rgb32_expect_advanced_desc_todo1[] = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .todo_value = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE), ATTR_UINT32(MF_MT_COMPRESSED, 0, .todo = TRUE), ATTR_UINT32(MF_MT_INTERLACE_MODE, 2, .todo = TRUE), }; + static const struct attribute_desc rgb32_expect_advanced_desc_todo2[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_UINT32(MF_MT_COMPRESSED, 0, .todo = TRUE), + ATTR_UINT32(MF_MT_INTERLACE_MODE, 2, .todo_value = TRUE), + }; IMFStreamDescriptor *video_stream; IMFSourceReaderEx *reader_ex; IMFAttributes *attributes; @@ -1840,16 +1849,21 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad init_media_type(media_type, nv12_stream_type_desc, 2); /* doesn't need the frame size */ hr = IMFSourceReader_SetCurrentMediaType(reader, 0, NULL, media_type); if (enable_advanced) - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); else + { + todo_wine_if(enable_processing) /* Wine enables advanced video processing in all cases */ ok(hr == MF_E_TOPO_CODEC_NOT_FOUND, "Unexpected hr %#lx.\n", hr); + } IMFMediaType_Release(media_type);
hr = IMFSourceReader_GetCurrentMediaType(reader, 0, &media_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (enable_advanced) check_media_type(media_type, nv12_expect_advanced_desc, -1); - else + else if (!enable_processing) + check_media_type(media_type, rgb32_stream_type_desc, -1); + else if (!winetest_platform_is_wine) /* Wine enables advanced video processing in all cases */ check_media_type(media_type, rgb32_stream_type_desc, -1); IMFMediaType_Release(media_type);
@@ -1858,7 +1872,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad if (!enable_advanced) ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr); else - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (hr == S_OK) { hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); @@ -1912,7 +1926,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad init_media_type(media_type, rgb32_stream_type_desc, 2); /* doesn't need the frame size */ hr = IMFSourceReader_SetCurrentMediaType(reader, 0, NULL, media_type); if (enable_processing || enable_advanced) - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); else ok(hr == MF_E_TOPO_CODEC_NOT_FOUND, "Unexpected hr %#lx.\n", hr); IMFMediaType_Release(media_type); @@ -1920,7 +1934,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad hr = IMFSourceReader_GetCurrentMediaType(reader, 0, &media_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (enable_advanced) - check_media_type(media_type, rgb32_expect_advanced_desc, -1); + check_media_type(media_type, rgb32_expect_advanced_desc_todo1, -1); else if (enable_processing) check_media_type(media_type, rgb32_expect_desc, -1); else @@ -1932,7 +1946,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad if (!enable_advanced) ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr); else - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (hr == S_OK) { hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); @@ -1954,19 +1968,22 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad init_media_type(media_type, yuy2_stream_type_desc, 2); /* doesn't need the frame size */ hr = IMFSourceReader_SetCurrentMediaType(reader, 0, NULL, media_type); if (enable_advanced) - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); else + { + todo_wine_if(enable_processing) /* Wine enables advanced video processing in all cases */ ok(hr == MF_E_TOPO_CODEC_NOT_FOUND, "Unexpected hr %#lx.\n", hr); + } IMFMediaType_Release(media_type);
hr = IMFSourceReader_GetCurrentMediaType(reader, 0, &media_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (enable_advanced) check_media_type(media_type, yuy2_expect_advanced_desc, -1); - else if (enable_processing) - check_media_type(media_type, rgb32_expect_desc, -1); - else + else if (!enable_processing) check_media_type(media_type, nv12_stream_type_desc, -1); + else if (!winetest_platform_is_wine) /* Wine enables advanced video processing in all cases */ + check_media_type(media_type, rgb32_expect_desc, -1); IMFMediaType_Release(media_type);
/* convert transform is only exposed with MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING */ @@ -1974,7 +1991,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad if (!enable_advanced) ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr); else - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (hr == S_OK) { hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); @@ -2058,7 +2075,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad init_media_type(media_type, rgb32_stream_type_desc, 2); /* doesn't need the frame size */ hr = IMFSourceReader_SetCurrentMediaType(reader, 0, NULL, media_type); if (enable_processing || enable_advanced) - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); else todo_wine ok(hr == MF_E_INVALIDMEDIATYPE, "Unexpected hr %#lx.\n", hr); IMFMediaType_Release(media_type); @@ -2066,11 +2083,11 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad hr = IMFSourceReader_GetCurrentMediaType(reader, 0, &media_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (enable_advanced) - check_media_type(media_type, rgb32_expect_advanced_desc, -1); - else if (enable_processing) - check_media_type(media_type, rgb32_expect_desc, -1); - else + check_media_type(media_type, rgb32_expect_advanced_desc_todo2, -1); + else if (!enable_processing) check_media_type(media_type, h264_stream_type_desc, -1); + else if (!winetest_platform_is_wine) /* Wine enables advanced video processing in all cases */ + check_media_type(media_type, rgb32_expect_desc, -1); IMFMediaType_Release(media_type);
/* the exposed transform is the H264 decoder or the converter with MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING */ @@ -2078,7 +2095,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad if (!enable_processing && !enable_advanced) ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr); else - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (hr == S_OK) { hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mfreadwrite/reader.c | 50 +++++++++++++++++++++++++++++++-- dlls/mfreadwrite/tests/mfplat.c | 20 ++++++------- 2 files changed, 58 insertions(+), 12 deletions(-)
diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 9ff34f77151..82fb650601e 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -77,6 +77,7 @@ struct transform_entry IMFTransform *transform; unsigned int min_buffer_size; GUID category; + BOOL hidden; };
struct media_stream @@ -1997,6 +1998,15 @@ static HRESULT source_reader_create_decoder_for_stream(struct source_reader *rea { stream->transform_service = entry->transform; IMFTransform_AddRef(stream->transform_service); + + /* converters are hidden from the stream transforms */ + if (service != entry) + service->hidden = TRUE; + } + else + { + /* converters are hidden from the stream transforms */ + entry->hidden = TRUE; } }
@@ -2431,12 +2441,48 @@ static HRESULT WINAPI src_reader_RemoveAllTransformsForStream(IMFSourceReaderEx return E_NOTIMPL; }
+static struct transform_entry *get_transform_at_index(struct media_stream *stream, UINT index) +{ + struct transform_entry *entry; + + LIST_FOR_EACH_ENTRY(entry, &stream->transforms, struct transform_entry, entry) + if (!entry->hidden && !index--) + return entry; + + return NULL; +} + static HRESULT WINAPI src_reader_GetTransformForStream(IMFSourceReaderEx *iface, DWORD stream_index, DWORD transform_index, GUID *category, IMFTransform **transform) { - FIXME("%p, %#lx, %#lx, %p, %p.\n", iface, stream_index, transform_index, category, transform); + struct source_reader *reader = impl_from_IMFSourceReaderEx(iface); + struct transform_entry *entry; + HRESULT hr;
- return E_NOTIMPL; + TRACE("%p, %#lx, %#lx, %p, %p.\n", iface, stream_index, transform_index, category, transform); + + EnterCriticalSection(&reader->cs); + + if (stream_index == MF_SOURCE_READER_FIRST_VIDEO_STREAM) + stream_index = reader->first_video_stream_index; + else if (stream_index == MF_SOURCE_READER_FIRST_AUDIO_STREAM) + stream_index = reader->first_audio_stream_index; + + if (stream_index >= reader->stream_count) + hr = MF_E_INVALIDSTREAMNUMBER; + else if (!(entry = get_transform_at_index(&reader->streams[stream_index], transform_index))) + hr = MF_E_INVALIDINDEX; + else + { + *category = entry->category; + *transform = entry->transform; + IMFTransform_AddRef(*transform); + hr = S_OK; + } + + LeaveCriticalSection(&reader->cs); + + return hr; }
static const IMFSourceReaderExVtbl srcreader_vtbl = diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 91f9641ccfc..aacd3c101b8 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -2011,9 +2011,9 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 0, &category, &transform); if (!enable_advanced) - todo_wine ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); + ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); else - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (hr == S_OK) { hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); @@ -2030,7 +2030,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad }
hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 1, &category, &transform); - todo_wine ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); + ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); IMFSourceReaderEx_Release(reader_ex);
IMFSourceReader_Release(reader); @@ -2123,9 +2123,9 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 0, &category, &transform); if (!enable_processing && !enable_advanced) - todo_wine ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); + ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); else - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (hr == S_OK) { hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); @@ -2144,9 +2144,9 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad /* the video processor can be accessed at index 1 with MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING */ hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 1, &category, &transform); if (!enable_advanced) - todo_wine ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); + ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); else - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (hr == S_OK) { hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); @@ -2163,7 +2163,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad }
hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 2, &category, &transform); - todo_wine ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); + ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); IMFSourceReaderEx_Release(reader_ex);
/* H264 -> NV12 conversion */ @@ -2212,7 +2212,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad hr = IMFSourceReader_QueryInterface(reader, &IID_IMFSourceReaderEx, (void **)&reader_ex); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 0, &category, &transform); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (hr == S_OK) { hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); @@ -2242,7 +2242,7 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad }
hr = IMFSourceReaderEx_GetTransformForStream(reader_ex, 0, 1, &category, &transform); - todo_wine ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); + ok(hr == MF_E_INVALIDINDEX, "Unexpected hr %#lx.\n", hr); IMFSourceReaderEx_Release(reader_ex);
skip_tests:
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=143606
Your paranoid android.
=== debian11 (32 bit report) ===
mfreadwrite: mfplat.c:925: Test failed: test.mp4: Unexpected hr 0xc00d36e6. Unhandled exception: assertion failed in 32-bit code (0xf7fb9559). mfplat: Timeout
Report validation errors: mfreadwrite:mfplat prints too much data (51976 bytes)
=== debian11 (32 bit ar:MA report) ===
mfreadwrite: mfplat.c:925: Test failed: test.mp4: Unexpected hr 0xc00d36e6.
=== debian11 (32 bit de report) ===
mfreadwrite: mfplat.c:925: Test failed: test.mp4: Unexpected hr 0xc00d36e6.
=== debian11 (32 bit fr report) ===
mfreadwrite: mfplat.c:925: Test failed: test.mp4: Unexpected hr 0xc00d36e6.
=== debian11 (32 bit he:IL report) ===
mfreadwrite: mfplat.c:925: Test failed: test.mp4: Unexpected hr 0xc00d36e6.
=== debian11 (32 bit hi:IN report) ===
mfreadwrite: mfplat.c:925: Test failed: test.mp4: Unexpected hr 0xc00d36e6.
=== debian11 (32 bit ja:JP report) ===
mfreadwrite: mfplat.c:925: Test failed: test.mp4: Unexpected hr 0xc00d36e6.
=== debian11 (32 bit zh:CN report) ===
mfreadwrite: mfplat.c:925: Test failed: test.mp4: Unexpected hr 0xc00d36e6.
=== debian11b (32 bit WoW report) ===
mfreadwrite: mfplat.c:925: Test failed: test.mp4: Unexpected hr 0xc00d36e6.
=== debian11b (64 bit WoW report) ===
mfmediaengine: mfmediaengine.c:1358: Test failed: Unexpected 52% diff
mfreadwrite: mfplat.c:925: Test failed: test.mp4: Unexpected hr 0xc00d36e6.
On Tue Feb 27 17:33:43 2024 +0000, Rémi Bernon wrote:
The output type might still contain different attributes, such as different subtype. It's not completely clear how native handles this and there's plenty of possibilities. The main reason I'm doing this is because the frame size isn't required, and might be provided by the decoder instead. I could do that completion for hand-picked attributes if that sounds better. This is probably not completely correct, as it propagates every attribute downstream when I believe some get swallowed, but it was also easier. Note that there's the same kind of thing being done in the topology loader now, for mostly the same reasons.
I updated the code to only propagate hand-picked attributes instead of everything, also made a similar change on the mf/topology_loader side. It actually fixed a couple of things where some pipelines failed to resolve (when decoder transforms are used, which is not yet the case in upstream Wine), as MF_MT_COMPRESSED_TYPE was incorrectly propagated.
Current version fails for me in one test:
mfplat.c:925: Test failed: test.mp4: Unexpected hr 0xc00d36e6.
On Fri Mar 1 14:58:45 2024 +0000, Nikolay Sivov wrote:
Current version fails for me in one test: mfplat.c:925: Test failed: test.mp4: Unexpected hr 0xc00d36e6.
Ah indeed, sorry. There's also another failure in mfmediaengine, both because we need to propagate MF_MT_DEFAULT_STRIDE.