-- v3: winegstreamer: Implement MF_LOW_LATENCY attribute and latency query. winegstreamer: Pass desired input queue length to wg_transform_create. winegstreamer: Pass desired output plane alignment to wg_transform_create. winegstreamer: Implement MFT_MESSAGE_COMMAND_FLUSH for the H264 decoder. winegstreamer: Implement MFT_MESSAGE_COMMAND_DRAIN for the H264 decoder.
From: Paul Gofman pgofman@codeweavers.com
--- dlls/mf/tests/transform.c | 5 +++-- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/h264_decoder.c | 13 ++++++++---- dlls/winegstreamer/main.c | 15 +++++++++++++ dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_parser.c | 1 + dlls/winegstreamer/wg_transform.c | 35 +++++++++++++++++++++++++++++++ 8 files changed, 66 insertions(+), 6 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 8d01a7480a2..27dd4ad17c2 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -3879,10 +3879,10 @@ static void test_h264_decoder(void)
hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0); ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr); + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0); + ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr); } - todo_wine ok(i == 2, "got %lu iterations\n", i); - todo_wine ok(h264_encoded_data_len == 2425, "got h264_encoded_data_len %lu\n", h264_encoded_data_len); ok(hr == MF_E_TRANSFORM_STREAM_CHANGE, "ProcessOutput returned %#lx\n", hr); ok(output_status == MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE, "got output[0].dwStatus %#lx\n", output_status); @@ -3981,6 +3981,7 @@ static void test_h264_decoder(void) ok(ref == 1, "Release returned %ld\n", ref);
ret = check_mf_sample_collection(output_samples, &expect_output_sample_i420, L"i420frame.bmp"); + todo_wine /* wg_transform_set_output_format() should convert already processed samples instead of dropping */ ok(ret == 0, "got %lu%% diff\n", ret); IMFCollection_Release(output_samples);
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 54f59aa708a..9a559f58507 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -106,6 +106,7 @@ struct wg_transform *wg_transform_create(const struct wg_format *input_format, void wg_transform_destroy(struct wg_transform *transform); bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_format *format); bool wg_transform_get_status(struct wg_transform *transform, bool *accepts_input); +HRESULT wg_transform_drain(struct wg_transform *transform);
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 97289f69a4d..96888e49178 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -614,8 +614,9 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_
TRACE("iface %p, message %#x, param %Ix.\n", iface, message, param);
- if (message == MFT_MESSAGE_SET_D3D_MANAGER) + switch (message) { + case MFT_MESSAGE_SET_D3D_MANAGER: if (FAILED(hr = IMFVideoSampleAllocatorEx_SetDirectXManager(decoder->allocator, (IUnknown *)param))) return hr;
@@ -625,10 +626,14 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ else decoder->output_info.dwFlags &= ~MFT_OUTPUT_STREAM_PROVIDES_SAMPLES; return S_OK; - }
- FIXME("Ignoring message %#x.\n", message); - return S_OK; + case MFT_MESSAGE_COMMAND_DRAIN: + return wg_transform_drain(decoder->wg_transform); + + default: + FIXME("Ignoring message %#x.\n", message); + return S_OK; + } }
static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 2e7763872d0..955644b6a60 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -426,6 +426,21 @@ bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_fo return !WINE_UNIX_CALL(unix_wg_transform_set_output_format, ¶ms); }
+HRESULT wg_transform_drain(struct wg_transform *transform) +{ + NTSTATUS status; + + TRACE("transform %p.\n", transform); + + if ((status = WINE_UNIX_CALL(unix_wg_transform_drain, transform))) + { + WARN("wg_transform_drain returned status %#lx\n", status); + return HRESULT_FROM_NT(status); + } + + return S_OK; +} + #define ALIGN(n, alignment) (((n) + (alignment) - 1) & ~((alignment) - 1))
unsigned int wg_format_get_stride(const struct wg_format *format) diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 962668045c1..dcc89298748 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -53,6 +53,7 @@ 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; extern NTSTATUS wg_transform_get_status(void *args) DECLSPEC_HIDDEN; +extern NTSTATUS wg_transform_drain(void *args) DECLSPEC_HIDDEN;
/* wg_allocator.c */
diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index e20fdd7256b..c712be0ed13 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -376,6 +376,7 @@ enum unix_funcs unix_wg_transform_push_data, unix_wg_transform_read_data, unix_wg_transform_get_status, + unix_wg_transform_drain, };
#endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index ef274b1dc27..c55685931ae 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1939,4 +1939,5 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_transform_push_data), X(wg_transform_read_data), X(wg_transform_get_status), + X(wg_transform_drain), }; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 19ce2a1013f..1f3d94d297b 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -869,3 +869,38 @@ NTSTATUS wg_transform_get_status(void *args) params->accepts_input = gst_atomic_queue_length(transform->input_queue) < transform->input_max_length; return STATUS_SUCCESS; } + +NTSTATUS wg_transform_drain(void *args) +{ + struct wg_transform *transform = args; + GstBuffer *input_buffer; + GstFlowReturn ret; + GstEvent *event; + + GST_LOG("transform %p", transform); + + while ((input_buffer = gst_atomic_queue_pop(transform->input_queue))) + { + if ((ret = gst_pad_push(transform->my_src, input_buffer))) + GST_WARNING("Failed to push transform input, error %d", ret); + } + + if (!(event = gst_event_new_segment_done(GST_FORMAT_TIME, -1)) + || !gst_pad_push_event(transform->my_src, event)) + goto error; + if (!(event = gst_event_new_eos()) + || !gst_pad_push_event(transform->my_src, event)) + goto error; + if (!(event = gst_event_new_stream_start("stream")) + || !gst_pad_push_event(transform->my_src, event)) + goto error; + if (!(event = gst_event_new_segment(&transform->segment)) + || !gst_pad_push_event(transform->my_src, event)) + goto error; + + return STATUS_SUCCESS; + +error: + GST_ERROR("Failed to drain transform %p.", transform); + return STATUS_UNSUCCESSFUL; +}
From: Paul Gofman pgofman@codeweavers.com
--- dlls/mf/tests/transform.c | 9 --------- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/h264_decoder.c | 3 +++ dlls/winegstreamer/main.c | 15 +++++++++++++++ dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_parser.c | 1 + dlls/winegstreamer/wg_transform.c | 24 ++++++++++++++++++++++++ 8 files changed, 46 insertions(+), 9 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 27dd4ad17c2..55001d97025 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -4026,7 +4026,6 @@ static void test_h264_decoder_concat_streams(void) { {.length = 0x3600}, {.length = 0x4980}, - {.length = 0, .todo_length = TRUE}, }; const struct attribute_desc output_sample_attributes[] = { @@ -4057,13 +4056,6 @@ static void test_h264_decoder_concat_streams(void) .buffer_count = 1, .buffers = output_buffer_desc + 1, .repeat_count = 6, .todo_time = TRUE, }, - { - /* Wine outputs spurious buffers */ - .attributes = output_sample_attributes + 0, - .sample_time = 0, .sample_duration = 400000, - .buffer_count = 1, .buffers = output_buffer_desc + 2, .repeat_count = 22, - .todo_time = TRUE, .todo_length = TRUE, - }, {0}, }; const WCHAR *filenames[] = @@ -4212,7 +4204,6 @@ static void test_h264_decoder_concat_streams(void)
hr = IMFCollection_GetElementCount(output_samples, &output_count); ok(hr == S_OK, "GetElementCount returned %#lx\n", hr); - todo_wine ok(output_count == 96, "GetElementCount returned %#lx\n", output_count);
ret = check_mf_sample_collection(output_samples, output_sample_desc, NULL); diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 9a559f58507..af4590af8bb 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -107,6 +107,7 @@ void wg_transform_destroy(struct wg_transform *transform); bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_format *format); bool wg_transform_get_status(struct wg_transform *transform, bool *accepts_input); HRESULT wg_transform_drain(struct wg_transform *transform); +HRESULT wg_transform_flush(struct wg_transform *transform);
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 96888e49178..f8d4ea10d5e 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -630,6 +630,9 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ case MFT_MESSAGE_COMMAND_DRAIN: return wg_transform_drain(decoder->wg_transform);
+ case MFT_MESSAGE_COMMAND_FLUSH: + return wg_transform_flush(decoder->wg_transform); + default: FIXME("Ignoring message %#x.\n", message); return S_OK; diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 955644b6a60..bd4f7108387 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -441,6 +441,21 @@ HRESULT wg_transform_drain(struct wg_transform *transform) return S_OK; }
+HRESULT wg_transform_flush(struct wg_transform *transform) +{ + NTSTATUS status; + + TRACE("transform %p.\n", transform); + + if ((status = WINE_UNIX_CALL(unix_wg_transform_flush, transform))) + { + WARN("wg_transform_flush returned status %#lx\n", status); + return HRESULT_FROM_NT(status); + } + + return S_OK; +} + #define ALIGN(n, alignment) (((n) + (alignment) - 1) & ~((alignment) - 1))
unsigned int wg_format_get_stride(const struct wg_format *format) diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index dcc89298748..808b59dba57 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -54,6 +54,7 @@ extern NTSTATUS wg_transform_push_data(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_read_data(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_get_status(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_drain(void *args) DECLSPEC_HIDDEN; +extern NTSTATUS wg_transform_flush(void *args) DECLSPEC_HIDDEN;
/* wg_allocator.c */
diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index c712be0ed13..e03085cd4f7 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -377,6 +377,7 @@ enum unix_funcs unix_wg_transform_read_data, unix_wg_transform_get_status, unix_wg_transform_drain, + unix_wg_transform_flush, };
#endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index c55685931ae..f043c4e18b4 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1940,4 +1940,5 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_transform_read_data), X(wg_transform_get_status), X(wg_transform_drain), + X(wg_transform_flush), }; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 1f3d94d297b..054e574770c 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -904,3 +904,27 @@ error: GST_ERROR("Failed to drain transform %p.", transform); return STATUS_UNSUCCESSFUL; } + +NTSTATUS wg_transform_flush(void *args) +{ + struct wg_transform *transform = args; + GstBuffer *input_buffer; + GstSample *sample; + NTSTATUS status; + + GST_LOG("transform %p", transform); + + while ((input_buffer = gst_atomic_queue_pop(transform->input_queue))) + gst_buffer_unref(input_buffer); + + if ((status = wg_transform_drain(transform))) + return status; + + while ((sample = gst_atomic_queue_pop(transform->output_queue))) + gst_sample_unref(sample); + if ((sample = transform->output_sample)) + gst_sample_unref(sample); + transform->output_sample = NULL; + + return STATUS_SUCCESS; +}
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winegstreamer/aac_decoder.c | 6 ++++-- dlls/winegstreamer/color_convert.c | 6 ++++-- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/h264_decoder.c | 9 +++++++-- dlls/winegstreamer/main.c | 3 ++- dlls/winegstreamer/quartz_transform.c | 9 ++++++--- dlls/winegstreamer/resampler.c | 6 ++++-- dlls/winegstreamer/unixlib.h | 6 ++++++ dlls/winegstreamer/video_decoder.c | 3 ++- dlls/winegstreamer/video_processor.c | 6 ++++-- dlls/winegstreamer/wg_transform.c | 12 ++++++------ dlls/winegstreamer/wma_decoder.c | 6 ++++-- dlls/winegstreamer/wmv_decoder.c | 6 ++++-- 13 files changed, 54 insertions(+), 26 deletions(-)
diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index d79ede69c9d..1fc545fc283 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -67,6 +67,7 @@ static struct aac_decoder *impl_from_IMFTransform(IMFTransform *iface) static HRESULT try_create_wg_transform(struct aac_decoder *decoder) { struct wg_format input_format, output_format; + struct wg_transform_attrs attrs = {0};
if (decoder->wg_transform) wg_transform_destroy(decoder->wg_transform); @@ -80,7 +81,7 @@ static HRESULT try_create_wg_transform(struct aac_decoder *decoder) if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE;
- if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format))) + if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) return E_FAIL;
return S_OK; @@ -625,13 +626,14 @@ HRESULT aac_decoder_create(REFIID riid, void **ret) }, }; static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_AUDIO_MPEG4}; + struct wg_transform_attrs attrs = {0}; struct wg_transform *transform; struct aac_decoder *decoder; HRESULT hr;
TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret);
- if (!(transform = wg_transform_create(&input_format, &output_format))) + if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) { ERR_(winediag)("GStreamer doesn't support WMA decoding, please install appropriate plugins\n"); return E_FAIL; diff --git a/dlls/winegstreamer/color_convert.c b/dlls/winegstreamer/color_convert.c index ed591c8e669..624191daf33 100644 --- a/dlls/winegstreamer/color_convert.c +++ b/dlls/winegstreamer/color_convert.c @@ -98,6 +98,7 @@ static inline struct color_convert *impl_from_IUnknown(IUnknown *iface) static HRESULT try_create_wg_transform(struct color_convert *impl) { struct wg_format input_format, output_format; + struct wg_transform_attrs attrs = {0};
if (impl->wg_transform) wg_transform_destroy(impl->wg_transform); @@ -111,7 +112,7 @@ static HRESULT try_create_wg_transform(struct color_convert *impl) if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE;
- if (!(impl->wg_transform = wg_transform_create(&input_format, &output_format))) + if (!(impl->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) return E_FAIL;
return S_OK; @@ -936,13 +937,14 @@ HRESULT color_convert_create(IUnknown *outer, IUnknown **out) .height = 1080, }, }; + struct wg_transform_attrs attrs = {0}; struct wg_transform *transform; struct color_convert *impl; HRESULT hr;
TRACE("outer %p, out %p.\n", outer, out);
- if (!(transform = wg_transform_create(&input_format, &output_format))) + if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) { ERR_(winediag)("GStreamer doesn't support video conversion, please install appropriate plugins.\n"); return E_FAIL; diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index af4590af8bb..d397ab21ca0 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -102,7 +102,7 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags);
struct wg_transform *wg_transform_create(const struct wg_format *input_format, - const struct wg_format *output_format); + const struct wg_format *output_format, const struct wg_transform_attrs *attrs); void wg_transform_destroy(struct wg_transform *transform); bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_format *format); bool wg_transform_get_status(struct wg_transform *transform, bool *accepts_input); diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index f8d4ea10d5e..81b06445df9 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -76,6 +76,10 @@ static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface)
static HRESULT try_create_wg_transform(struct h264_decoder *decoder) { + struct wg_transform_attrs attrs = + { + .output_plane_align = 15, + }; struct wg_format input_format; struct wg_format output_format;
@@ -99,7 +103,7 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) output_format.u.video.fps_d = 0; output_format.u.video.fps_n = 0;
- if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format))) + if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) return E_FAIL;
return S_OK; @@ -832,13 +836,14 @@ HRESULT h264_decoder_create(REFIID riid, void **ret) }, }; static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_VIDEO_H264}; + struct wg_transform_attrs attrs = {0}; struct wg_transform *transform; struct h264_decoder *decoder; HRESULT hr;
TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret);
- if (!(transform = wg_transform_create(&input_format, &output_format))) + if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) { ERR_(winediag)("GStreamer doesn't support H.264 decoding, please install appropriate plugins\n"); return E_FAIL; diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index bd4f7108387..88179feeb56 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -337,12 +337,13 @@ 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) + const struct wg_format *output_format, const struct wg_transform_attrs *attrs) { struct wg_transform_create_params params = { .input_format = input_format, .output_format = output_format, + .attrs = attrs, };
TRACE("input_format %p, output_format %p.\n", input_format, output_format); diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c index 09ad4862410..84f6bbd6361 100644 --- a/dlls/winegstreamer/quartz_transform.c +++ b/dlls/winegstreamer/quartz_transform.c @@ -98,6 +98,7 @@ static HRESULT transform_init_stream(struct strmbase_filter *iface) { struct transform *filter = impl_from_strmbase_filter(iface); struct wg_format input_format, output_format; + struct wg_transform_attrs attrs = {0}; HRESULT hr;
if (filter->source.pin.peer) @@ -111,7 +112,7 @@ static HRESULT transform_init_stream(struct strmbase_filter *iface) if (FAILED(hr = wg_sample_queue_create(&filter->sample_queue))) return hr;
- filter->transform = wg_transform_create(&input_format, &output_format); + filter->transform = wg_transform_create(&input_format, &output_format, &attrs); if (!filter->transform) { wg_sample_queue_destroy(filter->sample_queue); @@ -710,11 +711,12 @@ HRESULT mpeg_audio_codec_create(IUnknown *outer, IUnknown **out) .rate = 44100, }, }; + struct wg_transform_attrs attrs = {0}; struct wg_transform *transform; struct transform *object; HRESULT hr;
- transform = wg_transform_create(&input_format, &output_format); + transform = wg_transform_create(&input_format, &output_format, &attrs); if (!transform) { ERR_(winediag)("GStreamer doesn't support MPEG-1 audio decoding, please install appropriate plugins.\n"); @@ -844,11 +846,12 @@ HRESULT mpeg_layer3_decoder_create(IUnknown *outer, IUnknown **out) .rate = 44100, }, }; + struct wg_transform_attrs attrs = {0}; struct wg_transform *transform; struct transform *object; HRESULT hr;
- transform = wg_transform_create(&input_format, &output_format); + transform = wg_transform_create(&input_format, &output_format, &attrs); if (!transform) { ERR_(winediag)("GStreamer doesn't support MPEG-1 audio decoding, please install appropriate plugins.\n"); diff --git a/dlls/winegstreamer/resampler.c b/dlls/winegstreamer/resampler.c index 88e9727ff21..7ed8cf48fbf 100644 --- a/dlls/winegstreamer/resampler.c +++ b/dlls/winegstreamer/resampler.c @@ -56,6 +56,7 @@ struct resampler static HRESULT try_create_wg_transform(struct resampler *impl) { struct wg_format input_format, output_format; + struct wg_transform_attrs attrs = {0};
if (impl->wg_transform) wg_transform_destroy(impl->wg_transform); @@ -69,7 +70,7 @@ static HRESULT try_create_wg_transform(struct resampler *impl) if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE;
- if (!(impl->wg_transform = wg_transform_create(&input_format, &output_format))) + if (!(impl->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) return E_FAIL;
return S_OK; @@ -895,13 +896,14 @@ HRESULT resampler_create(IUnknown *outer, IUnknown **out) .rate = 44100, }, }; + struct wg_transform_attrs attrs = {0}; struct wg_transform *transform; struct resampler *impl; HRESULT hr;
TRACE("outer %p, out %p.\n", outer, out);
- if (!(transform = wg_transform_create(&input_format, &output_format))) + if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) { ERR_(winediag)("GStreamer doesn't support audio resampling, please install appropriate plugins.\n"); return E_FAIL; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index e03085cd4f7..15b5dcff352 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -305,11 +305,17 @@ struct wg_parser_stream_seek_params DWORD start_flags, stop_flags; };
+struct wg_transform_attrs +{ + UINT32 output_plane_align; +}; + struct wg_transform_create_params { struct wg_transform *transform; const struct wg_format *input_format; const struct wg_format *output_format; + const struct wg_transform_attrs *attrs; };
struct wg_transform_push_data_params diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 04d175c7910..abcadf90a32 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -68,6 +68,7 @@ static struct video_decoder *impl_from_IMFTransform(IMFTransform *iface)
static HRESULT try_create_wg_transform(struct video_decoder *decoder) { + struct wg_transform_attrs attrs = {0}; struct wg_format input_format; struct wg_format output_format;
@@ -86,7 +87,7 @@ static HRESULT try_create_wg_transform(struct video_decoder *decoder) output_format.u.video.fps_d = 0; output_format.u.video.fps_n = 0;
- if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format))) + if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) { ERR("Failed to create transform with input major_type %u.\n", input_format.major_type); return E_FAIL; diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index 21bc46b0bb3..3cb0ccc090b 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -88,6 +88,7 @@ struct video_processor static HRESULT try_create_wg_transform(struct video_processor *impl) { struct wg_format input_format, output_format; + struct wg_transform_attrs attrs = {0};
if (impl->wg_transform) wg_transform_destroy(impl->wg_transform); @@ -101,7 +102,7 @@ static HRESULT try_create_wg_transform(struct video_processor *impl) if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE;
- if (!(impl->wg_transform = wg_transform_create(&input_format, &output_format))) + if (!(impl->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) return E_FAIL;
return S_OK; @@ -602,13 +603,14 @@ HRESULT video_processor_create(REFIID riid, void **ret) .height = 1080, }, }; + struct wg_transform_attrs attrs = {0}; struct wg_transform *transform; struct video_processor *impl; HRESULT hr;
TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret);
- if (!(transform = wg_transform_create(&input_format, &output_format))) + if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) { ERR_(winediag)("GStreamer doesn't support video conversion, please install appropriate plugins.\n"); return E_FAIL; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 054e574770c..a0be84d5178 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -43,6 +43,8 @@
struct wg_transform { + struct wg_transform_attrs attrs; + GstElement *container; GstAllocator *allocator; GstPad *my_src, *my_sink; @@ -55,7 +57,6 @@ struct wg_transform bool input_is_flipped; GstElement *video_flip;
- guint output_plane_align; struct wg_format output_format; struct wg_sample *output_wg_sample; GstAtomicQueue *output_queue; @@ -111,7 +112,7 @@ static gboolean transform_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery { case GST_QUERY_ALLOCATION: { - gsize plane_align = transform->output_plane_align; + gsize plane_align = transform->attrs.output_plane_align; GstStructure *config, *params; GstVideoAlignment align; gboolean needs_pool; @@ -300,8 +301,8 @@ NTSTATUS wg_transform_create(void *args) goto out; if (!(transform->allocator = wg_allocator_create(transform_request_sample, transform))) goto out; + transform->attrs = *params->attrs; transform->input_max_length = 1; - transform->output_plane_align = 0; transform->output_format = output_format;
if (!(src_caps = wg_format_to_caps(&input_format))) @@ -344,7 +345,6 @@ NTSTATUS wg_transform_create(void *args) * to match its expectations. */ transform->input_max_length = 16; - transform->output_plane_align = 15; /* fallthrough */ case WG_MAJOR_TYPE_AUDIO_MPEG1: case WG_MAJOR_TYPE_AUDIO_MPEG4: @@ -795,7 +795,7 @@ NTSTATUS wg_transform_read_data(void *args)
if (format) { - gsize plane_align = transform->output_plane_align; + gsize plane_align = transform->attrs.output_plane_align; GstVideoAlignment align; GstVideoInfo info;
@@ -827,7 +827,7 @@ NTSTATUS wg_transform_read_data(void *args) }
if ((status = read_transform_output_data(output_buffer, output_caps, - transform->output_plane_align, sample))) + transform->attrs.output_plane_align, sample))) { wg_allocator_release_sample(transform->allocator, sample, false); return status; diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 4a0d5f2592e..dd06faf494d 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -70,6 +70,7 @@ static inline struct wma_decoder *impl_from_IUnknown(IUnknown *iface) static HRESULT try_create_wg_transform(struct wma_decoder *decoder) { struct wg_format input_format, output_format; + struct wg_transform_attrs attrs = {0};
if (decoder->wg_transform) wg_transform_destroy(decoder->wg_transform); @@ -83,7 +84,7 @@ static HRESULT try_create_wg_transform(struct wma_decoder *decoder) if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE;
- if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format))) + if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) return E_FAIL;
return S_OK; @@ -851,13 +852,14 @@ HRESULT wma_decoder_create(IUnknown *outer, IUnknown **out) }, }; static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_AUDIO_WMA}; + struct wg_transform_attrs attrs = {0}; struct wg_transform *transform; struct wma_decoder *decoder; HRESULT hr;
TRACE("outer %p, out %p.\n", outer, out);
- if (!(transform = wg_transform_create(&input_format, &output_format))) + if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) { ERR_(winediag)("GStreamer doesn't support WMA decoding, please install appropriate plugins\n"); return E_FAIL; diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c index a22de7ccb7f..32dbbbbe686 100644 --- a/dlls/winegstreamer/wmv_decoder.c +++ b/dlls/winegstreamer/wmv_decoder.c @@ -540,6 +540,7 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde const DMO_MEDIA_TYPE *type, DWORD flags) { struct wmv_decoder *decoder = impl_from_IMediaObject(iface); + struct wg_transform_attrs attrs = {0}; struct wg_format wg_format; unsigned int i;
@@ -593,7 +594,7 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde wg_transform_destroy(decoder->wg_transform); decoder->wg_transform = NULL; } - if (!(decoder->wg_transform = wg_transform_create(&decoder->input_format, &decoder->output_format))) + if (!(decoder->wg_transform = wg_transform_create(&decoder->input_format, &decoder->output_format, &attrs))) return E_FAIL;
return S_OK; @@ -885,13 +886,14 @@ HRESULT wmv_decoder_create(IUnknown *outer, IUnknown **out) .height = 1080, }, }; + struct wg_transform_attrs attrs = {0}; struct wg_transform *transform; struct wmv_decoder *decoder; HRESULT hr;
TRACE("outer %p, out %p.\n", outer, out);
- if (!(transform = wg_transform_create(&input_format, &output_format))) + if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) { ERR_(winediag)("GStreamer doesn't support WMV decoding, please install appropriate plugins.\n"); return E_FAIL;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winegstreamer/h264_decoder.c | 6 ++++++ dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_transform.c | 13 ++----------- 3 files changed, 9 insertions(+), 11 deletions(-)
diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 81b06445df9..8795d12169f 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -76,9 +76,15 @@ static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface)
static HRESULT try_create_wg_transform(struct h264_decoder *decoder) { + /* Call of Duty: Black Ops 3 doesn't care about the ProcessInput/ProcessOutput + * return values, it calls them in a specific order and expects the decoder + * transform to be able to queue its input buffers. We need to use a buffer list + * to match its expectations. + */ struct wg_transform_attrs attrs = { .output_plane_align = 15, + .input_queue_length = 15, }; struct wg_format input_format; struct wg_format output_format; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 15b5dcff352..938319faea7 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -308,6 +308,7 @@ struct wg_parser_stream_seek_params struct wg_transform_attrs { UINT32 output_plane_align; + UINT32 input_queue_length; };
struct wg_transform_create_params diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index a0be84d5178..f21914b4086 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -51,7 +51,6 @@ struct wg_transform GstSegment segment; GstQuery *drain_query;
- guint input_max_length; GstAtomicQueue *input_queue;
bool input_is_flipped; @@ -302,7 +301,6 @@ NTSTATUS wg_transform_create(void *args) if (!(transform->allocator = wg_allocator_create(transform_request_sample, transform))) goto out; transform->attrs = *params->attrs; - transform->input_max_length = 1; transform->output_format = output_format;
if (!(src_caps = wg_format_to_caps(&input_format))) @@ -339,13 +337,6 @@ NTSTATUS wg_transform_create(void *args) switch (input_format.major_type) { case WG_MAJOR_TYPE_VIDEO_H264: - /* Call of Duty: Black Ops 3 doesn't care about the ProcessInput/ProcessOutput - * return values, it calls them in a specific order and expects the decoder - * transform to be able to queue its input buffers. We need to use a buffer list - * to match its expectations. - */ - transform->input_max_length = 16; - /* fallthrough */ case WG_MAJOR_TYPE_AUDIO_MPEG1: case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: @@ -561,7 +552,7 @@ NTSTATUS wg_transform_push_data(void *args) guint length;
length = gst_atomic_queue_length(transform->input_queue); - if (length >= transform->input_max_length) + if (length >= transform->attrs.input_queue_length + 1) { GST_INFO("Refusing %u bytes, %u buffers already queued", sample->size, length); params->result = MF_E_NOTACCEPTING; @@ -866,7 +857,7 @@ NTSTATUS wg_transform_get_status(void *args) struct wg_transform_get_status_params *params = args; struct wg_transform *transform = params->transform;
- params->accepts_input = gst_atomic_queue_length(transform->input_queue) < transform->input_max_length; + params->accepts_input = gst_atomic_queue_length(transform->input_queue) < transform->attrs.input_queue_length + 1; return STATUS_SUCCESS; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winegstreamer/h264_decoder.c | 4 ++++ dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_transform.c | 23 +++++++++++++++++++++++ 3 files changed, 28 insertions(+)
diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 8795d12169f..c6e817df6b0 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -88,6 +88,7 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) }; struct wg_format input_format; struct wg_format output_format; + UINT32 low_latency;
if (decoder->wg_transform) wg_transform_destroy(decoder->wg_transform); @@ -109,6 +110,9 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) output_format.u.video.fps_d = 0; output_format.u.video.fps_n = 0;
+ if (SUCCEEDED(IMFAttributes_GetUINT32(decoder->attributes, &MF_LOW_LATENCY, &low_latency))) + attrs.low_latency = !!low_latency; + if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) return E_FAIL;
diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 938319faea7..a9892bf9d4f 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -309,6 +309,7 @@ struct wg_transform_attrs { UINT32 output_plane_align; UINT32 input_queue_length; + BOOL low_latency; };
struct wg_transform_create_params diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index f21914b4086..d6218af04b9 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -101,6 +101,26 @@ static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, Gst return GST_FLOW_OK; }
+static gboolean transform_src_query_latency(struct wg_transform *transform, GstQuery *query) +{ + GST_LOG("transform %p, query %p", transform, query); + gst_query_set_latency(query, transform->attrs.low_latency, 0, 0); + return true; +} + +static gboolean transform_src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) +{ + struct wg_transform *transform = gst_pad_get_element_private(pad); + + switch (query->type) + { + case GST_QUERY_LATENCY: + return transform_src_query_latency(transform, query); + default: + return gst_pad_query_default(pad, parent, query); + } +} + static gboolean transform_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) { struct wg_transform *transform = gst_pad_get_element_private(pad); @@ -312,6 +332,9 @@ NTSTATUS wg_transform_create(void *args) if (!transform->my_src) goto out;
+ gst_pad_set_element_private(transform->my_src, transform); + gst_pad_set_query_function(transform->my_src, transform_src_query_cb); + if (!(transform->output_caps = wg_format_to_caps(&output_format))) goto out; if (!(template = gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS, transform->output_caps)))
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=133313
Your paranoid android.
=== w7u_el (32 bit report) ===
mf: transform.c:4207: Test failed: GetElementCount returned 0x78 transform.c:4209: Test failed: sample 97: got 1 buffers transform.c:4209: Test failed: sample 97: got sample time 14800000 transform.c:4209: Test failed: sample 97: got sample duration 400000 transform.c:1028: Test failed: sample 97: buffer 0: got unexpected buffer 0a5c:transform: unhandled exception c0000005 at 00426542
On Thu Jun 1 07:13:55 2023 +0000, **** wrote:
Marvin replied on the mailing list:
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=133313 Your paranoid android. === w7u_el (32 bit report) === mf: transform.c:4207: Test failed: GetElementCount returned 0x78 transform.c:4209: Test failed: sample 97: got 1 buffers transform.c:4209: Test failed: sample 97: got sample time 14800000 transform.c:4209: Test failed: sample 97: got sample duration 400000 transform.c:1028: Test failed: sample 97: buffer 0: got unexpected buffer 0a5c:transform: unhandled exception c0000005 at 00426542
This is a rare preexisting failure, where flush is sometimes skipped. I'll fix them separately.
On Wed May 24 18:44:37 2023 +0000, Rémi Bernon wrote:
We don't have to send the segment end timestamp, and it works just the same if we use -1 like for when it was started. What matters it to restore the timestamp for stream start so that buffer times are kept consistent. I don't see how it is different to keep the timestamp in a field vs keep the segment. I prefer keeping the segment as it saves useless local variable (and segment initialization every time we want to create one).
Well, currently, "segment" doesn't need to be a local variable. I don't see how "saving a useless local variable" is preferable to saving a useless struct field. If I see a struct field, I expect there's some reason it needs to be a struct field.
Along the same lines, if I see a struct field, I expect there to be some reason it has the type it does. I don't see how that applies to "segment" as of patch 5/10. We're not using it as a segment; we're only using the start time. Well, patch 6/10 uses it as a segment proper, but the point is we never actually use the end time. That seems potentially unclear or confusing to a reader, who would expect that if we're saving a whole segment in the struct that we're going to update all its members, and wastes a bit of mental time trying to tell if the stop time is ever updated.
I don't hate the current organization, so I'm not going to block the patch series simply based on that, but I do think it would be better to only track the members we are using.
This merge request was approved by Zebediah Figura.