-- v2: winegstreamer: Check H264 ProcessOutput sample against actual image size. winegstreamer: Use H264 input media type frame size when specified. winegstreamer: Implement H264 SetOutputType by reconfiguring the pipeline.
From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/mf/tests/mf.c | 11 ++-- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/h264_decoder.c | 23 ++++++++- dlls/winegstreamer/main.c | 13 +++++ dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.h | 7 +++ dlls/winegstreamer/wg_parser.c | 1 + dlls/winegstreamer/wg_transform.c | 84 +++++++++++++++++++++++++++++++ 8 files changed, 133 insertions(+), 8 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 00be50c8494..80a4cf155bc 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -7818,7 +7818,7 @@ static void test_h264_decoder(void) todo_wine ok(hr == MF_E_TRANSFORM_STREAM_CHANGE, "ProcessOutput returned %#lx\n", hr);
- if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) + while (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { hr = IMFTransform_ProcessInput(transform, 0, sample, 0); ok(hr == S_OK, "ProcessInput returned %#lx\n", hr); @@ -7826,16 +7826,14 @@ static void test_h264_decoder(void) ok(ret <= 1, "Release returned %lu\n", ret); sample = next_h264_sample(&h264_encoded_data, &h264_encoded_data_len); hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); - todo_wine + todo_wine_if(hr == MF_E_TRANSFORM_NEED_MORE_INPUT) ok(hr == MF_E_TRANSFORM_STREAM_CHANGE, "ProcessOutput returned %#lx\n", hr); }
ok(output.dwStreamID == 0, "got dwStreamID %lu\n", output.dwStreamID); ok(!!output.pSample, "got pSample %p\n", output.pSample); - todo_wine ok(output.dwStatus == MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE, "got dwStatus %#lx\n", output.dwStatus); ok(!output.pEvents, "got pEvents %p\n", output.pEvents); - todo_wine ok(status == MFT_PROCESS_OUTPUT_STATUS_NEW_STREAMS, "got status %#lx\n", status); hr = IMFSample_GetTotalLength(output.pSample, &length); ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr); @@ -7858,17 +7856,16 @@ static void test_h264_decoder(void) memset(&output, 0, sizeof(output)); output.pSample = create_sample(NULL, actual_width * actual_height * 2); hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); - todo_wine ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr); ok(output.dwStreamID == 0, "got dwStreamID %lu\n", output.dwStreamID); ok(!!output.pSample, "got pSample %p\n", output.pSample); ok(output.dwStatus == 0, "got dwStatus %#lx\n", output.dwStatus); ok(!output.pEvents, "got pEvents %p\n", output.pEvents); ok(status == 0, "got status %#lx\n", status); - if (hr != S_OK) goto skip_i420_tests;
hr = IMFSample_GetSampleTime(output.pSample, &time); ok(hr == S_OK, "GetSampleTime returned %#lx\n", hr); + todo_wine_if(time == 1334666) /* when VA-API plugin is used */ ok(time - 333666 <= 2, "got time %I64d\n", time);
duration = 0xdeadbeef; @@ -7904,7 +7901,6 @@ static void test_h264_decoder(void)
check_sample(output.pSample, i420_frame_data, output_file);
-skip_i420_tests: ret = IMFSample_Release(output.pSample); ok(ret == 0, "Release returned %lu\n", ret);
@@ -7915,6 +7911,7 @@ skip_i420_tests: memset(&output, 0, sizeof(output)); output.pSample = create_sample(NULL, actual_width * actual_height * 2); hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); + todo_wine_if(hr == S_OK) /* when VA-API plugin is used */ ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr); ok(output.dwStreamID == 0, "got dwStreamID %lu\n", output.dwStreamID); ok(!!output.pSample, "got pSample %p\n", output.pSample); diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 8348d2e8360..7b8f05dc09c 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -102,6 +102,7 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, struct wg_transform *wg_transform_create(const struct wg_format *input_format, const struct wg_format *output_format); void wg_transform_destroy(struct wg_transform *transform); +bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_format *format);
unsigned int wg_format_get_max_size(const struct wg_format *format);
diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 012a7060f29..afae14fb8e7 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -467,7 +467,28 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF IMFMediaType_Release(decoder->output_type); IMFMediaType_AddRef((decoder->output_type = type));
- if (FAILED(hr = try_create_wg_transform(decoder))) + if (decoder->wg_transform) + { + struct wg_format output_format; + mf_media_type_to_wg_format(decoder->output_type, &output_format); + + /* Don't force any specific size, H264 streams already have the metadata for it + * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later. + */ + output_format.u.video.width = 0; + output_format.u.video.height = 0; + output_format.u.video.fps_d = 0; + output_format.u.video.fps_n = 0; + + if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN + || !wg_transform_set_output_format(decoder->wg_transform, &output_format)) + { + IMFMediaType_Release(decoder->output_type); + decoder->output_type = NULL; + return MF_E_INVALIDMEDIATYPE; + } + } + else if (FAILED(hr = try_create_wg_transform(decoder))) { IMFMediaType_Release(decoder->output_type); decoder->output_type = NULL; diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index fc7b9d73285..20dcdccc606 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -348,6 +348,19 @@ HRESULT wg_transform_read_data(struct wg_transform *transform, struct wg_sample return params.result; }
+bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_format *format) +{ + struct wg_transform_set_output_format_params params = + { + .transform = transform, + .format = format, + }; + + TRACE("transform %p, format %p.\n", transform, format); + + return !__wine_unix_call(unix_handle, unix_wg_transform_set_output_format, ¶ms); +} + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) { if (reason == DLL_PROCESS_ATTACH) diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index e9f472986ae..617204e97c7 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -34,6 +34,7 @@ extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDE
extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; +extern NTSTATUS wg_transform_set_output_format(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_push_data(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_read_data(void *args) DECLSPEC_HIDDEN;
diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 860a8ab2a52..e2eef2a4932 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -263,6 +263,12 @@ struct wg_transform_read_data_params HRESULT result; };
+struct wg_transform_set_output_format_params +{ + struct wg_transform *transform; + const struct wg_format *format; +}; + enum unix_funcs { unix_wg_parser_create, @@ -291,6 +297,7 @@ enum unix_funcs
unix_wg_transform_create, unix_wg_transform_destroy, + unix_wg_transform_set_output_format,
unix_wg_transform_push_data, unix_wg_transform_read_data, diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 7d55897aa0a..f0487fd1ffa 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1625,6 +1625,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
X(wg_transform_create), X(wg_transform_destroy), + X(wg_transform_set_output_format),
X(wg_transform_push_data), X(wg_transform_read_data), diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 070263698fb..e703e93b07e 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -51,6 +51,7 @@ struct wg_transform GstPad *my_src, *my_sink; GstPad *their_sink, *their_src; GstSegment segment; + GstQuery *drain_query;
guint input_max_length; GstAtomicQueue *input_queue; @@ -175,6 +176,31 @@ static gboolean transform_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery g_object_unref(pool); return true; } + + case GST_QUERY_CAPS: + { + GstCaps *caps, *filter, *temp; + gchar *str; + + gst_query_parse_caps(query, &filter); + caps = gst_caps_ref(transform->output_caps); + + if (filter) + { + temp = gst_caps_intersect(caps, filter); + gst_caps_unref(caps); + caps = temp; + } + + str = gst_caps_to_string(caps); + GST_INFO("Returning caps %s", str); + g_free(str); + + gst_query_set_caps_result(query, caps); + gst_caps_unref(caps); + return true; + } + default: GST_WARNING("Ignoring "%s" query.", gst_query_type_get_name(query->type)); break; @@ -236,6 +262,7 @@ NTSTATUS wg_transform_destroy(void *args) g_object_unref(transform->container); g_object_unref(transform->my_sink); g_object_unref(transform->my_src); + gst_query_unref(transform->drain_query); gst_caps_unref(transform->output_caps); gst_atomic_queue_unref(transform->output_queue); free(transform); @@ -344,6 +371,8 @@ NTSTATUS wg_transform_create(void *args) goto out; if (!(transform->output_queue = gst_atomic_queue_new(8))) goto out; + if (!(transform->drain_query = gst_query_new_drain())) + goto out; if (!(transform->allocator = wg_allocator_create(transform_request_sample, transform))) goto out; transform->input_max_length = 1; @@ -505,6 +534,8 @@ out: gst_caps_unref(src_caps); if (transform->allocator) wg_allocator_destroy(transform->allocator); + if (transform->drain_query) + gst_query_unref(transform->drain_query); if (transform->output_queue) gst_atomic_queue_unref(transform->output_queue); if (transform->input_queue) @@ -519,6 +550,59 @@ out: return status; }
+NTSTATUS wg_transform_set_output_format(void *args) +{ + struct wg_transform_set_output_format_params *params = args; + struct wg_transform *transform = params->transform; + const struct wg_format *format = params->format; + GstSample *sample; + GstCaps *caps; + gchar *str; + + if (!(caps = wg_format_to_caps(format))) + { + GST_ERROR("Failed to convert format %p to caps.", format); + return STATUS_UNSUCCESSFUL; + } + + if (gst_caps_is_always_compatible(transform->output_caps, caps)) + { + gst_caps_unref(caps); + return STATUS_SUCCESS; + } + + if (!gst_pad_peer_query(transform->my_src, transform->drain_query)) + { + GST_ERROR("Failed to drain transform %p.", transform); + return STATUS_UNSUCCESSFUL; + } + + gst_caps_unref(transform->output_caps); + transform->output_caps = caps; + + if (!gst_pad_push_event(transform->my_sink, gst_event_new_reconfigure())) + { + GST_ERROR("Failed to reconfigure transform %p.", transform); + return STATUS_UNSUCCESSFUL; + } + + str = gst_caps_to_string(caps); + GST_INFO("Configured new caps %s.", str); + g_free(str); + + /* Ideally and to be fully compatible with native transform, the queued + * output buffers will need to be converted to the new output format and + * kept queued. + */ + if (transform->output_sample) + gst_sample_unref(transform->output_sample); + while ((sample = gst_atomic_queue_pop(transform->output_queue))) + gst_sample_unref(sample); + transform->output_sample = NULL; + + return STATUS_SUCCESS; +} + static void wg_sample_free_notify(void *arg) { struct wg_sample *sample = arg;
From: Rémi Bernon rbernon@codeweavers.com
Updating the internal stream format frame size accordingly.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/mf/tests/mf.c | 141 +++++++++--------------------- dlls/winegstreamer/h264_decoder.c | 7 ++ 2 files changed, 48 insertions(+), 100 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 80a4cf155bc..1d4f29e9361 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -7157,144 +7157,98 @@ static void test_h264_decoder(void) ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_H264_ES), }, }; - static const media_type_desc default_outputs[] = + static const DWORD input_width = 120, input_height = 248; + const media_type_desc default_outputs[] = { { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12), ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001), - ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 1920), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, input_width), ATTR_UINT32(MF_MT_INTERLACE_MODE, 7), ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_RATIO(MF_MT_FRAME_SIZE, input_width, input_height), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, input_width * input_height * 3 / 2), + /* ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), missing on Win7 */ }, { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YV12), ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001), - ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 1920), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, input_width), ATTR_UINT32(MF_MT_INTERLACE_MODE, 7), ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_RATIO(MF_MT_FRAME_SIZE, input_width, input_height), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, input_width * input_height * 3 / 2), + /* ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), missing on Win7 */ }, { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_IYUV), ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001), - ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 1920), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, input_width), ATTR_UINT32(MF_MT_INTERLACE_MODE, 7), ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_RATIO(MF_MT_FRAME_SIZE, input_width, input_height), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, input_width * input_height * 3 / 2), + /* ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), missing on Win7 */ }, { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_I420), ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001), - ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 1920), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, input_width), ATTR_UINT32(MF_MT_INTERLACE_MODE, 7), ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_RATIO(MF_MT_FRAME_SIZE, input_width, input_height), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, input_width * input_height * 3 / 2), + /* ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), missing on Win7 */ }, { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YUY2), ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001), - ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 3840), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, input_width * 2), ATTR_UINT32(MF_MT_INTERLACE_MODE, 7), ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_RATIO(MF_MT_FRAME_SIZE, input_width, input_height), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, input_width * input_height * 2), + /* ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), missing on Win7 */ }, }; - static const media_type_desc default_outputs_extra[] = - { - { - ATTR_RATIO(MF_MT_FRAME_SIZE, 1920, 1080), - ATTR_UINT32(MF_MT_SAMPLE_SIZE, 3110400), - ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), - }, - { - ATTR_RATIO(MF_MT_FRAME_SIZE, 1920, 1080), - ATTR_UINT32(MF_MT_SAMPLE_SIZE, 3110400), - ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), - }, - { - ATTR_RATIO(MF_MT_FRAME_SIZE, 1920, 1080), - ATTR_UINT32(MF_MT_SAMPLE_SIZE, 3110400), - ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), - }, - { - ATTR_RATIO(MF_MT_FRAME_SIZE, 1920, 1080), - ATTR_UINT32(MF_MT_SAMPLE_SIZE, 3110400), - ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), - }, - { - ATTR_RATIO(MF_MT_FRAME_SIZE, 1920, 1080), - ATTR_UINT32(MF_MT_SAMPLE_SIZE, 4147200), - ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), - }, - }; - static const media_type_desc default_outputs_win7[] = - { - { - ATTR_RATIO(MF_MT_FRAME_SIZE, 1920, 1088), - ATTR_UINT32(MF_MT_SAMPLE_SIZE, 3133440), - }, - { - ATTR_RATIO(MF_MT_FRAME_SIZE, 1920, 1088), - ATTR_UINT32(MF_MT_SAMPLE_SIZE, 3133440), - }, - { - ATTR_RATIO(MF_MT_FRAME_SIZE, 1920, 1088), - ATTR_UINT32(MF_MT_SAMPLE_SIZE, 3133440), - }, - { - ATTR_RATIO(MF_MT_FRAME_SIZE, 1920, 1088), - ATTR_UINT32(MF_MT_SAMPLE_SIZE, 3133440), - }, - { - ATTR_RATIO(MF_MT_FRAME_SIZE, 1920, 1088), - ATTR_UINT32(MF_MT_SAMPLE_SIZE, 4177920), - }, - }; - static const struct attribute_desc input_type_desc[] = + const struct attribute_desc input_type_desc[] = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_H264), + ATTR_RATIO(MF_MT_FRAME_SIZE, input_width, input_height), {0}, }; - static const struct attribute_desc minimal_output_type_desc[] = + const struct attribute_desc minimal_output_type_desc[] = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12), - ATTR_RATIO(MF_MT_FRAME_SIZE, 1920, 1080), + ATTR_RATIO(MF_MT_FRAME_SIZE, input_width, input_height), {0}, }; - static const struct attribute_desc output_type_desc[] = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12), - ATTR_RATIO(MF_MT_FRAME_SIZE, 1920, 1080), - ATTR_RATIO(MF_MT_FRAME_RATE, 60000, 1000), - ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 2, 1), - ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 3840), - ATTR_UINT32(MF_MT_SAMPLE_SIZE, 3840 * 1080 * 3 / 2), - ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), - {0}, - }; - static const struct attribute_desc output_type_desc_win7[] = + const struct attribute_desc output_type_desc[] = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12), - ATTR_RATIO(MF_MT_FRAME_SIZE, 1920, 1088), + ATTR_RATIO(MF_MT_FRAME_SIZE, input_width, input_height), ATTR_RATIO(MF_MT_FRAME_RATE, 60000, 1000), ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 2, 1), ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 3840), - ATTR_UINT32(MF_MT_SAMPLE_SIZE, 3840 * 1088 * 3 / 2), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, 3840 * input_height * 3 / 2), ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), {0}, }; @@ -7307,15 +7261,6 @@ static void test_h264_decoder(void) ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 2), {0}, }; - static const struct attribute_desc new_output_type_desc_win7[] = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_I420), - ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), - ATTR_RATIO(MF_MT_FRAME_RATE, 1, 1), - ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 2), - {0}, - }; static const MFVideoArea actual_aperture = {.Area={82,84}}; static const DWORD actual_width = 96, actual_height = 96; const media_type_desc actual_outputs[] = @@ -7407,7 +7352,6 @@ static void test_h264_decoder(void) IMFMediaType *media_type; LONGLONG time, duration; IMFTransform *transform; - BOOL is_win7 = FALSE; ULONG i, ret, flags; HANDLE output_file; IMFSample *sample; @@ -7502,6 +7446,9 @@ static void test_h264_decoder(void) init_media_type(media_type, input_type_desc, 2); hr = IMFTransform_SetInputType(transform, 0, media_type, 0); ok(hr == S_OK, "SetInputType returned %#lx.\n", hr); + init_media_type(media_type, input_type_desc, -1); + hr = IMFTransform_SetInputType(transform, 0, media_type, 0); + ok(hr == S_OK, "SetInputType returned %#lx.\n", hr); ret = IMFMediaType_Release(media_type); ok(ret == 1, "Release returned %lu\n", ret);
@@ -7511,8 +7458,7 @@ static void test_h264_decoder(void) ok(hr == S_OK, "GetOutputStreamInfo returned %#lx\n", hr); ok(output_info.dwFlags == flags, "got dwFlags %#lx\n", output_info.dwFlags); todo_wine - ok(output_info.cbSize == 1920 * 1080 * 2 || broken(output_info.cbSize == 1920 * 1088 * 2) /* Win7 */, - "got cbSize %#lx\n", output_info.cbSize); + ok(output_info.cbSize == input_width * input_height * 2, "got cbSize %#lx\n", output_info.cbSize); ok(output_info.cbAlignment == 0, "got cbAlignment %#lx\n", output_info.cbAlignment);
/* output types can now be enumerated (though they are actually the same for all input types) */ @@ -7523,9 +7469,6 @@ static void test_h264_decoder(void) winetest_push_context("out %lu", i); ok(hr == S_OK, "GetOutputAvailableType returned %#lx\n", hr); check_media_type(media_type, default_outputs[i], -1); - hr = IMFMediaType_GetItem(media_type, &MF_MT_VIDEO_ROTATION, NULL); - is_win7 = broken(FAILED(hr)); - check_media_type(media_type, is_win7 ? default_outputs_win7[i] : default_outputs_extra[i], -1); ret = IMFMediaType_Release(media_type); ok(ret == 0, "Release returned %lu\n", ret); winetest_pop_context(); @@ -7553,8 +7496,8 @@ static void test_h264_decoder(void) init_media_type(media_type, minimal_output_type_desc, i + 1); } hr = IMFTransform_SetOutputType(transform, 0, media_type, 0); - ok(hr == (is_win7 ? MF_E_INVALIDMEDIATYPE : S_OK), "SetOutputType returned %#lx.\n", hr); - init_media_type(media_type, is_win7 ? output_type_desc_win7 : output_type_desc, -1); + ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr); + init_media_type(media_type, output_type_desc, -1); hr = IMFTransform_SetOutputType(transform, 0, media_type, 0); ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr); ret = IMFMediaType_Release(media_type); @@ -7562,7 +7505,7 @@ static void test_h264_decoder(void)
hr = IMFTransform_GetOutputCurrentType(transform, 0, &media_type); ok(hr == S_OK, "GetOutputCurrentType returned %#lx\n", hr); - check_media_type(media_type, is_win7 ? output_type_desc_win7 : output_type_desc, -1); + check_media_type(media_type, output_type_desc, -1); ret = IMFMediaType_Release(media_type); ok(ret == 0, "Release returned %lu\n", ret);
@@ -7574,7 +7517,6 @@ static void test_h264_decoder(void) winetest_push_context("out %lu", i); ok(hr == S_OK, "GetOutputAvailableType returned %#lx\n", hr); check_media_type(media_type, default_outputs[i], -1); - check_media_type(media_type, is_win7 ? default_outputs_win7[i] : default_outputs_extra[i], -1); ret = IMFMediaType_Release(media_type); ok(ret == 0, "Release returned %lu\n", ret); winetest_pop_context(); @@ -7598,8 +7540,7 @@ static void test_h264_decoder(void) ok(hr == S_OK, "GetOutputStreamInfo returned %#lx\n", hr); ok(output_info.dwFlags == flags, "got dwFlags %#lx\n", output_info.dwFlags); todo_wine - ok(output_info.cbSize == 1920 * 1080 * 2 || broken(output_info.cbSize == 1920 * 1088 * 2) /* Win7 */, - "got cbSize %#lx\n", output_info.cbSize); + ok(output_info.cbSize == input_width * input_height * 2, "got cbSize %#lx\n", output_info.cbSize); ok(output_info.cbAlignment == 0, "got cbAlignment %#lx\n", output_info.cbAlignment);
input_count = output_count = 0xdeadbeef; @@ -7710,7 +7651,7 @@ static void test_h264_decoder(void) /* current output type is still the one we selected */ hr = IMFTransform_GetOutputCurrentType(transform, 0, &media_type); ok(hr == S_OK, "GetOutputCurrentType returned %#lx\n", hr); - check_media_type(media_type, is_win7 ? output_type_desc_win7 : output_type_desc, -1); + check_media_type(media_type, output_type_desc, -1); hr = IMFMediaType_GetItemType(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, NULL); ok(hr == MF_E_ATTRIBUTENOTFOUND, "GetItemType returned %#lx\n", hr); ret = IMFMediaType_Release(media_type); @@ -7794,10 +7735,10 @@ static void test_h264_decoder(void) /* we can change it, but only with the correct frame size */ hr = MFCreateMediaType(&media_type); ok(hr == S_OK, "MFCreateMediaType returned %#lx\n", hr); - init_media_type(media_type, is_win7 ? output_type_desc_win7 : output_type_desc, -1); + init_media_type(media_type, output_type_desc, -1); hr = IMFTransform_SetOutputType(transform, 0, media_type, 0); ok(hr == MF_E_INVALIDMEDIATYPE, "SetOutputType returned %#lx.\n", hr); - init_media_type(media_type, is_win7 ? new_output_type_desc_win7 : new_output_type_desc, -1); + init_media_type(media_type, new_output_type_desc, -1); hr = IMFTransform_SetOutputType(transform, 0, media_type, 0); ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr); ret = IMFMediaType_Release(media_type); @@ -7805,7 +7746,7 @@ static void test_h264_decoder(void)
hr = IMFTransform_GetOutputCurrentType(transform, 0, &media_type); ok(hr == S_OK, "GetOutputCurrentType returned %#lx\n", hr); - check_media_type(media_type, is_win7 ? new_output_type_desc_win7 : new_output_type_desc, -1); + check_media_type(media_type, new_output_type_desc, -1); hr = IMFMediaType_GetItemType(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, NULL); ok(hr == MF_E_ATTRIBUTENOTFOUND, "GetItemType returned %#lx\n", hr); ret = IMFMediaType_Release(media_type); diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index afae14fb8e7..471ad49d8e6 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -401,6 +401,7 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM { struct h264_decoder *decoder = impl_from_IMFTransform(iface); GUID major, subtype; + UINT64 frame_size; HRESULT hr; ULONG i;
@@ -429,6 +430,12 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM IMFMediaType_Release(decoder->input_type); IMFMediaType_AddRef((decoder->input_type = type));
+ if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) + { + decoder->wg_format.u.video.width = frame_size >> 32; + decoder->wg_format.u.video.height = (UINT32)frame_size; + } + return S_OK; }
From: Rémi Bernon rbernon@codeweavers.com
Instead of maximum output sample size returned from GetOutputStreamInfo.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/mf/tests/mf.c | 4 ++-- dlls/winegstreamer/h264_decoder.c | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 1d4f29e9361..9c87460b115 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -7671,7 +7671,7 @@ static void test_h264_decoder(void)
status = 0; memset(&output, 0, sizeof(output)); - output.pSample = create_sample(NULL, actual_width * actual_height * 2); + output.pSample = create_sample(NULL, nv12_frame_len); hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr); ok(output.dwStreamID == 0, "got dwStreamID %lu\n", output.dwStreamID); @@ -7715,7 +7715,7 @@ static void test_h264_decoder(void) for (i = 0; i < actual_aperture.Area.cy; ++i) { memset(data + actual_width * i + actual_aperture.Area.cx, 0xcd, actual_width - actual_aperture.Area.cx); - memset(data + actual_width * (actual_height + i) + actual_aperture.Area.cx, 0xcd, actual_width - actual_aperture.Area.cx); + memset(data + actual_width * (actual_height + i / 2) + actual_aperture.Area.cx, 0xcd, actual_width - actual_aperture.Area.cx); } memset(data + actual_width * actual_aperture.Area.cy, 0xcd, (actual_height - actual_aperture.Area.cy) * actual_width); memset(data + actual_width * (actual_height + actual_aperture.Area.cy / 2), 0xcd, (actual_height - actual_aperture.Area.cy) / 2 * actual_width); diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 471ad49d8e6..43b8f83a20c 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -581,10 +581,11 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) { struct h264_decoder *decoder = impl_from_IMFTransform(iface); - MFT_OUTPUT_STREAM_INFO info; struct wg_sample *wg_sample; struct wg_format wg_format; + UINT32 sample_size; UINT64 frame_rate; + GUID subtype; HRESULT hr;
TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); @@ -592,9 +593,6 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, if (count != 1) return E_INVALIDARG;
- if (FAILED(hr = IMFTransform_GetOutputStreamInfo(iface, 0, &info))) - return hr; - if (!decoder->wg_transform) return MF_E_TRANSFORM_TYPE_NOT_SET;
@@ -602,10 +600,16 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, samples[0].dwStatus = 0; if (!samples[0].pSample) return E_INVALIDARG;
+ if (FAILED(hr = IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &subtype))) + return hr; + if (FAILED(hr = MFCalculateImageSize(&subtype, decoder->wg_format.u.video.width, + decoder->wg_format.u.video.height, &sample_size))) + return hr; + if (FAILED(hr = wg_sample_create_mf(samples[0].pSample, &wg_sample))) return hr;
- if (wg_sample->max_size < info.cbSize) + if (wg_sample->max_size < sample_size) { wg_sample_release(wg_sample); return MF_E_BUFFERTOOSMALL;
v2: Fix buffer overflow in the NV12 frame fixup.
This merge request was approved by Zebediah Figura.