[PATCH v3 6/7] winegstreamer: Support wg_transform output format change events.
Rémi Bernon
wine at gitlab.winehq.org
Mon May 23 11:38:25 CDT 2022
From: Rémi Bernon <rbernon at 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 at 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);
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/61
More information about the wine-devel
mailing list