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 | 70 +++++++++++++++++++++++++++++++ 8 files changed, 119 insertions(+), 8 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 5f26b1a6238..afe85ddbf3c 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -7333,7 +7333,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); @@ -7341,16 +7341,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); @@ -7373,17 +7371,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; @@ -7419,7 +7416,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);
@@ -7430,6 +7426,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..14a52df5921 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_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..1a9dcbd561c 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_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..fb2e8865089 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_format(struct wg_transform *transform, struct wg_format *format) +{ + struct wg_transform_set_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_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..3a6b162c500 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_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..ed02f025b05 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_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_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..a4aa945a708 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_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 b0048fad644..b90fde70519 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -173,6 +173,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; @@ -525,6 +550,51 @@ out: return status; }
+NTSTATUS wg_transform_set_format(void *args) +{ + struct wg_transform_set_format_params *params = args; + struct wg_transform *transform = params->transform; + GstSample *sample; + GstEvent *event; + GstCaps *caps; + gchar *str; + + if (!(caps = wg_format_to_caps(params->format))) + { + GST_ERROR("Failed to convert format to caps."); + return STATUS_UNSUCCESSFUL; + } + + if (gst_caps_is_always_compatible(transform->output_caps, caps)) + { + gst_caps_unref(caps); + return STATUS_SUCCESS; + } + + gst_caps_unref(transform->output_caps); + transform->output_caps = caps; + + if (!gst_pad_set_caps(transform->my_sink, caps) + || !(event = gst_event_new_reconfigure()) + || !gst_pad_push_event(transform->my_sink, event)) + { + GST_ERROR("Failed to reconfigure transform."); + return STATUS_UNSUCCESSFUL; + } + + str = gst_caps_to_string(caps); + GST_INFO("Configured new caps %s.", str); + g_free(str); + + 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;