From: Rémi Bernon rbernon@codeweavers.com
Using a separate peek_data entry point, which pushes the input buffer list and returns the current output sample format if requested.
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/gst_private.h | 3 +- dlls/winegstreamer/h264_decoder.c | 19 +++++++++++-- dlls/winegstreamer/main.c | 23 +++++++++++---- dlls/winegstreamer/quartz_transform.c | 12 ++++---- dlls/winegstreamer/unix_private.h | 2 +- dlls/winegstreamer/unixlib.h | 40 ++++++++++++++++++++++++++- dlls/winegstreamer/wg_format.c | 31 --------------------- dlls/winegstreamer/wg_parser.c | 1 + dlls/winegstreamer/wg_transform.c | 32 +++++++++++++++------ dlls/winegstreamer/wma_decoder.c | 11 ++++++-- 11 files changed, 116 insertions(+), 62 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 9de7308f9ff..419faa61e2b 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -7187,20 +7187,16 @@ static void test_h264_decoder(void) ok(i == 2, "got %lu iterations\n", i); todo_wine ok(h264_encoded_data_len == 1180, "got h264_encoded_data_len %lu\n", h264_encoded_data_len); - todo_wine 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); - todo_wine ok(length == 0, "got length %lu\n", length); ret = IMFSample_Release(output.pSample); ok(ret == 0, "Release returned %lu\n", ret); diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 2a4b16079c1..c92d452fbd9 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -97,7 +97,8 @@ 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); HRESULT wg_transform_push_data(struct wg_transform *transform, struct wg_sample *sample); -HRESULT wg_transform_read_data(struct wg_transform *transform, struct wg_sample *sample); +HRESULT wg_transform_peek_data(struct wg_transform *transform, struct wg_format *format); +bool wg_transform_read_data(struct wg_transform *transform, struct wg_sample *sample);
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 912a5bdf0b1..db4c74d561e 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -50,6 +50,7 @@ struct h264_decoder IMFMediaType *input_type; IMFMediaType *output_type;
+ struct wg_format wg_format; struct wg_transform *wg_transform; };
@@ -543,6 +544,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, struct h264_decoder *decoder = impl_from_IMFTransform(iface); MFT_OUTPUT_STREAM_INFO info; struct wg_sample *wg_sample; + struct wg_format wg_format; HRESULT hr;
TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); @@ -565,8 +567,21 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags,
if (wg_sample->max_size < info.cbSize) hr = MF_E_BUFFERTOOSMALL; - else - hr = wg_transform_read_data(decoder->wg_transform, wg_sample); + else if (SUCCEEDED(hr = wg_transform_peek_data(decoder->wg_transform, &wg_format))) + { + if (!wg_format_compare(&decoder->wg_format, &wg_format)) + { + decoder->wg_format = wg_format; + samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; + *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; + hr = MF_E_TRANSFORM_STREAM_CHANGE; + } + else if (!wg_transform_read_data(decoder->wg_transform, wg_sample)) + { + ERR("Failed to read transform data\n"); + hr = E_FAIL; + } + }
mf_destroy_wg_sample(wg_sample); return hr; diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index c3adbb82d61..b3fea9e760c 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -329,23 +329,36 @@ HRESULT wg_transform_push_data(struct wg_transform *transform, struct wg_sample return params.result; }
-HRESULT wg_transform_read_data(struct wg_transform *transform, struct wg_sample *sample) +HRESULT wg_transform_peek_data(struct wg_transform *transform, struct wg_format *format) { - struct wg_transform_read_data_params params = + struct wg_transform_peek_data_params params = { .transform = transform, - .sample = sample, + .format = format, }; NTSTATUS status;
- TRACE("transform %p, sample %p.\n", transform, sample); + TRACE("transform %p, format %p.\n", transform, format);
- if ((status = __wine_unix_call(unix_handle, unix_wg_transform_read_data, ¶ms))) + if ((status = __wine_unix_call(unix_handle, unix_wg_transform_peek_data, ¶ms))) return HRESULT_FROM_NT(status);
return params.result; }
+bool wg_transform_read_data(struct wg_transform *transform, struct wg_sample *sample) +{ + struct wg_transform_read_data_params params = + { + .transform = transform, + .sample = sample, + }; + + TRACE("transform %p, sample %p.\n", transform, sample); + + return !__wine_unix_call(unix_handle, unix_wg_transform_read_data, ¶ms); +} + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) { if (reason == DLL_PROCESS_ATTACH) diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c index 447f331d474..5c9ff508846 100644 --- a/dlls/winegstreamer/quartz_transform.c +++ b/dlls/winegstreamer/quartz_transform.c @@ -342,16 +342,14 @@ static HRESULT WINAPI transform_sink_receive(struct strmbase_sink *pin, IMediaSa return hr; }
- hr = wg_transform_read_data(filter->transform, &output_wg_sample); - if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) - { - IMediaSample_Release(output_sample); - break; - } + hr = wg_transform_peek_data(filter->transform, NULL); + if (SUCCEEDED(hr) && !wg_transform_read_data(filter->transform, &output_wg_sample)) + hr = E_FAIL; + if (FAILED(hr)) { IMediaSample_Release(output_sample); - return hr; + return hr == MF_E_TRANSFORM_NEED_MORE_INPUT ? S_OK : hr; }
hr = IMediaSample_SetActualDataLength(output_sample, output_wg_sample.size); diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 7bce8263aaf..10992992f2b 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -29,12 +29,12 @@ extern bool init_gstreamer(void) DECLSPEC_HIDDEN; extern GstElement *create_element(const char *name, const char *plugin_set) DECLSPEC_HIDDEN;
extern void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) DECLSPEC_HIDDEN; -extern bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) DECLSPEC_HIDDEN; extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDEN;
extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_push_data(void *args) DECLSPEC_HIDDEN; +extern NTSTATUS wg_transform_peek_data(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_read_data(void *args) DECLSPEC_HIDDEN;
#endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 5911278530d..4a72ef4bd0e 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -23,6 +23,8 @@
#include <stdbool.h> #include <stdint.h> +#include <assert.h> + #include "windef.h" #include "winternl.h" #include "wtypes.h" @@ -114,6 +116,35 @@ struct wg_format } u; };
+static inline bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) +{ + if (a->major_type != b->major_type) + return false; + + switch (a->major_type) + { + case WG_MAJOR_TYPE_MPEG1_AUDIO: + case WG_MAJOR_TYPE_WMA: + case WG_MAJOR_TYPE_H264: + case WG_MAJOR_TYPE_UNKNOWN: + return false; + + case WG_MAJOR_TYPE_AUDIO: + return a->u.audio.format == b->u.audio.format + && a->u.audio.channels == b->u.audio.channels + && a->u.audio.rate == b->u.audio.rate; + + case WG_MAJOR_TYPE_VIDEO: + /* Do not compare FPS. */ + return a->u.video.format == b->u.video.format + && a->u.video.width == b->u.video.width + && abs(a->u.video.height) == abs(b->u.video.height); + } + + assert(0); + return false; +} + enum wg_sample_flag { WG_SAMPLE_FLAG_INCOMPLETE = 1, @@ -253,11 +284,17 @@ struct wg_transform_push_data_params HRESULT result; };
+struct wg_transform_peek_data_params +{ + struct wg_transform *transform; + struct wg_format *format; + HRESULT result; +}; + struct wg_transform_read_data_params { struct wg_transform *transform; struct wg_sample *sample; - HRESULT result; };
enum unix_funcs @@ -290,6 +327,7 @@ enum unix_funcs unix_wg_transform_destroy,
unix_wg_transform_push_data, + unix_wg_transform_peek_data, unix_wg_transform_read_data, };
diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 4cebeac9182..a1ef9fb327b 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -527,34 +527,3 @@ GstCaps *wg_format_to_caps(const struct wg_format *format) assert(0); return NULL; } - -bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) -{ - if (a->major_type != b->major_type) - return false; - - switch (a->major_type) - { - case WG_MAJOR_TYPE_MPEG1_AUDIO: - case WG_MAJOR_TYPE_WMA: - case WG_MAJOR_TYPE_H264: - GST_FIXME("Format %u not implemented!", a->major_type); - /* fallthrough */ - case WG_MAJOR_TYPE_UNKNOWN: - return false; - - case WG_MAJOR_TYPE_AUDIO: - return a->u.audio.format == b->u.audio.format - && a->u.audio.channels == b->u.audio.channels - && a->u.audio.rate == b->u.audio.rate; - - case WG_MAJOR_TYPE_VIDEO: - /* Do not compare FPS. */ - return a->u.video.format == b->u.video.format - && a->u.video.width == b->u.video.width - && abs(a->u.video.height) == abs(b->u.video.height); - } - - assert(0); - return false; -} diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 7d55897aa0a..954fdd3dc3d 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1627,5 +1627,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_transform_destroy),
X(wg_transform_push_data), + X(wg_transform_peek_data), X(wg_transform_read_data), }; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index f8211001be9..a4125a7d822 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -471,15 +471,13 @@ static NTSTATUS read_transform_output_data(GstBuffer *buffer, struct wg_sample * return STATUS_SUCCESS; }
-NTSTATUS wg_transform_read_data(void *args) +NTSTATUS wg_transform_peek_data(void *args) { - struct wg_transform_read_data_params *params = args; + struct wg_transform_peek_data_params *params = args; struct wg_transform *transform = params->transform; - struct wg_sample *sample = params->sample; + struct wg_format *format = params->format; GstBufferList *input = transform->input; - GstBuffer *output_buffer; GstFlowReturn ret; - NTSTATUS status;
if (!gst_buffer_list_length(transform->input)) GST_DEBUG("Not input buffer queued"); @@ -497,12 +495,31 @@ NTSTATUS wg_transform_read_data(void *args)
if (!transform->output_sample && !(transform->output_sample = gst_atomic_queue_pop(transform->output_queue))) { - sample->size = 0; params->result = MF_E_TRANSFORM_NEED_MORE_INPUT; - GST_INFO("Cannot read %u bytes, no output available", sample->max_size); + GST_INFO("No output sample available"); return STATUS_SUCCESS; }
+ if (format) + wg_format_from_caps(format, gst_sample_get_caps(transform->output_sample)); + + params->result = S_OK; + return STATUS_SUCCESS; +} + +NTSTATUS wg_transform_read_data(void *args) +{ + struct wg_transform_read_data_params *params = args; + struct wg_transform *transform = params->transform; + struct wg_sample *sample = params->sample; + GstBuffer *output_buffer; + NTSTATUS status; + + if (!transform->output_sample) + { + GST_ERROR("No output sample available"); + return STATUS_UNSUCCESSFUL; + } output_buffer = gst_sample_get_buffer(transform->output_sample);
if ((status = read_transform_output_data(output_buffer, sample))) @@ -514,6 +531,5 @@ NTSTATUS wg_transform_read_data(void *args) transform->output_sample = NULL; }
- params->result = S_OK; return STATUS_SUCCESS; } diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 71369add244..c7466b74471 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -580,10 +580,17 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, wg_sample->size = 0; if (wg_sample->max_size < info.cbSize) hr = MF_E_BUFFERTOOSMALL; - else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, wg_sample))) + else if (SUCCEEDED(hr = wg_transform_peek_data(decoder->wg_transform, NULL))) { - if (wg_sample->flags & WG_SAMPLE_FLAG_INCOMPLETE) + if (!wg_transform_read_data(decoder->wg_transform, wg_sample)) + { + ERR("Failed to read transform data\n"); + hr = E_FAIL; + } + else if (wg_sample->flags & WG_SAMPLE_FLAG_INCOMPLETE) + { samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_INCOMPLETE; + } }
mf_destroy_wg_sample(wg_sample);