diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index d2da59a0d9b..41becb2b159 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; @@ -1767,6 +1769,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); @@ -1859,7 +1866,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; @@ -1877,21 +1900,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; @@ -1905,9 +1930,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)) { @@ -1929,20 +1964,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))) { @@ -1951,7 +2012,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 { @@ -2265,18 +2326,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);