From 99ce6e87a3b22c5602d7bbedd43bb40627b63321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 13 May 2022 00:17:28 +0200 Subject: [PATCH] winegstreamer: Expose output media type attributes from the stream format. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- dlls/mf/tests/mf.c | 17 ++++---- dlls/winegstreamer/gst_private.h | 3 +- dlls/winegstreamer/h264_decoder.c | 57 +++++++++++++++------------ dlls/winegstreamer/main.c | 6 ++- dlls/winegstreamer/quartz_transform.c | 2 +- dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_transform.c | 6 +++ dlls/winegstreamer/wma_decoder.c | 2 +- 8 files changed, 54 insertions(+), 40 deletions(-) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 419faa61e2b..3fe819ba23d 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -6841,7 +6841,7 @@ static void test_h264_decoder(void) 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, 60000, 1000, .todo_value = TRUE), + ATTR_RATIO(MF_MT_FRAME_RATE, 60000, 1000), ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .todo_value = TRUE), ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2, .todo_value = TRUE), ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width, .todo_value = TRUE), @@ -6855,7 +6855,7 @@ static void test_h264_decoder(void) 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, 60000, 1000, .todo_value = TRUE), + ATTR_RATIO(MF_MT_FRAME_RATE, 60000, 1000), ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .todo_value = TRUE), ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2, .todo_value = TRUE), ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width, .todo_value = TRUE), @@ -6869,7 +6869,7 @@ static void test_h264_decoder(void) 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, 60000, 1000, .todo_value = TRUE), + ATTR_RATIO(MF_MT_FRAME_RATE, 60000, 1000), ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .todo_value = TRUE), ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2, .todo_value = TRUE), ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width, .todo_value = TRUE), @@ -6883,7 +6883,7 @@ static void test_h264_decoder(void) 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, 60000, 1000, .todo_value = TRUE), + ATTR_RATIO(MF_MT_FRAME_RATE, 60000, 1000), ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .todo_value = TRUE), ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2, .todo_value = TRUE), ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width, .todo_value = TRUE), @@ -6897,7 +6897,7 @@ static void test_h264_decoder(void) 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, 60000, 1000, .todo_value = TRUE), + ATTR_RATIO(MF_MT_FRAME_RATE, 60000, 1000), ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .todo_value = TRUE), ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 2, .todo_value = TRUE), ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 2, .todo_value = TRUE), @@ -7206,7 +7206,6 @@ static void test_h264_decoder(void) hr = IMFTransform_GetOutputStreamInfo(transform, 0, &output_info); 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 == actual_width * actual_height * 2, "got cbSize %#lx\n", output_info.cbSize); ok(output_info.cbAlignment == 0, "got cbAlignment %#lx\n", output_info.cbAlignment); @@ -7248,14 +7247,12 @@ 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_nv12_tests; hr = IMFSample_GetUINT32(sample, &MFSampleExtension_CleanPoint, &value); ok(hr == MF_E_ATTRIBUTENOTFOUND, "GetUINT32 MFSampleExtension_CleanPoint returned %#lx\n", hr); @@ -7272,9 +7269,7 @@ static void test_h264_decoder(void) time = 0xdeadbeef; hr = IMFSample_GetSampleTime(output.pSample, &time); - todo_wine ok(hr == S_OK, "GetSampleTime returned %#lx\n", hr); - todo_wine ok(time == 0, "got time %I64d\n", time); /* doesn't matter what frame rate we've selected, duration is defined by the stream */ @@ -7289,7 +7284,9 @@ static void test_h264_decoder(void) ok(hr == S_OK, "ConvertToContiguousBuffer returned %#lx\n", hr); hr = IMFMediaBuffer_Lock(media_buffer, &data, NULL, &length); ok(hr == S_OK, "Lock returned %#lx\n", hr); + todo_wine ok(length == nv12_frame_len, "got length %lu\n", length); + if (length != nv12_frame_len) goto skip_nv12_tests; for (i = 0; i < actual_aperture.Area.cy; ++i) { diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 2a4b16079c1..159143d7e54 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_read_data(struct wg_transform *transform, struct wg_sample *sample, + 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 b3452269f04..f97b6cf18c2 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; }; @@ -89,8 +90,10 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) return S_OK; } -static HRESULT fill_output_media_type(IMFMediaType *media_type, IMFMediaType *default_type) +static HRESULT fill_output_media_type(struct h264_decoder *decoder, IMFMediaType *media_type) { + IMFMediaType *default_type = decoder->output_type; + struct wg_format *wg_format = &decoder->wg_format; UINT32 value, width, height; UINT64 ratio; GUID subtype; @@ -101,8 +104,7 @@ static HRESULT fill_output_media_type(IMFMediaType *media_type, IMFMediaType *de if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &ratio))) { - if (!default_type || FAILED(hr = IMFMediaType_GetUINT64(default_type, &MF_MT_FRAME_SIZE, &ratio))) - ratio = (UINT64)1920 << 32 | 1080; + ratio = (UINT64)wg_format->u.video.width << 32 | wg_format->u.video.height; if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, ratio))) return hr; } @@ -111,24 +113,21 @@ static HRESULT fill_output_media_type(IMFMediaType *media_type, IMFMediaType *de if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FRAME_RATE, NULL))) { - if (!default_type || FAILED(hr = IMFMediaType_GetUINT64(default_type, &MF_MT_FRAME_RATE, &ratio))) - ratio = (UINT64)30000 << 32 | 1001; + ratio = (UINT64)wg_format->u.video.fps_n << 32 | wg_format->u.video.fps_d; if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, ratio))) return hr; } if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_PIXEL_ASPECT_RATIO, NULL))) { - if (!default_type || FAILED(hr = IMFMediaType_GetUINT64(default_type, &MF_MT_PIXEL_ASPECT_RATIO, &ratio))) - ratio = (UINT64)1 << 32 | 1; + ratio = (UINT64)1 << 32 | 1; /* FIXME: read it from format */ if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, ratio))) return hr; } if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_SAMPLE_SIZE, NULL))) { - if ((!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_SAMPLE_SIZE, &value))) && - FAILED(hr = MFCalculateImageSize(&subtype, width, height, &value))) + if (FAILED(hr = MFCalculateImageSize(&subtype, width, height, &value))) return hr; if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, value))) return hr; @@ -136,8 +135,7 @@ static HRESULT fill_output_media_type(IMFMediaType *media_type, IMFMediaType *de if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_DEFAULT_STRIDE, NULL))) { - if ((!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_DEFAULT_STRIDE, &value))) && - FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, (LONG *)&value))) + if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, (LONG *)&value))) return hr; if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, value))) return hr; @@ -272,23 +270,15 @@ static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) { struct h264_decoder *decoder = impl_from_IMFTransform(iface); - UINT32 sample_size; - UINT64 frame_size; + UINT32 actual_width, actual_height; TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); - if (!decoder->output_type) - sample_size = 1920 * 1088 * 2; - else if (FAILED(IMFMediaType_GetUINT32(decoder->output_type, &MF_MT_SAMPLE_SIZE, &sample_size))) - { - if (FAILED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_SIZE, &frame_size))) - sample_size = 1920 * 1088 * 2; - else - sample_size = (frame_size >> 32) * (UINT32)frame_size * 2; - } + actual_width = (decoder->wg_format.u.video.width + 15) & ~15; + actual_height = (decoder->wg_format.u.video.height + 15) & ~15; info->dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; - info->cbSize = sample_size; + info->cbSize = actual_width * actual_height * 2; info->cbAlignment = 0; return S_OK; @@ -378,7 +368,7 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type))) goto done; - hr = fill_output_media_type(media_type, NULL); + hr = fill_output_media_type(decoder, media_type); done: if (SUCCEEDED(hr)) @@ -543,6 +533,8 @@ 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; + UINT64 frame_rate; HRESULT hr; TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); @@ -569,11 +561,21 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, return MF_E_BUFFERTOOSMALL; } - hr = wg_transform_read_data(decoder->wg_transform, wg_sample); + hr = wg_transform_read_data(decoder->wg_transform, wg_sample, + &wg_format); mf_destroy_wg_sample(wg_sample); if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { + decoder->wg_format = wg_format; + + /* keep the frame rate that was requested, GStreamer doesn't provide any */ + if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &frame_rate))) + { + decoder->wg_format.u.video.fps_n = frame_rate >> 32; + decoder->wg_format.u.video.fps_d = (UINT32)frame_rate; + } + samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; } @@ -641,6 +643,11 @@ HRESULT h264_decoder_create(REFIID riid, void **ret) decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; decoder->refcount = 1; + decoder->wg_format.u.video.format = WG_VIDEO_FORMAT_UNKNOWN; + decoder->wg_format.u.video.width = 1920; + decoder->wg_format.u.video.height = 1080; + decoder->wg_format.u.video.fps_n = 30000; + decoder->wg_format.u.video.fps_d = 1001; *ret = &decoder->IMFTransform_iface; TRACE("Created decoder %p\n", *ret); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index c3adbb82d61..5075b3118cd 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -329,16 +329,18 @@ 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_read_data(struct wg_transform *transform, struct wg_sample *sample, + struct wg_format *format) { struct wg_transform_read_data_params params = { .transform = transform, .sample = sample, + .format = format, }; NTSTATUS status; - TRACE("transform %p, sample %p.\n", transform, sample); + TRACE("transform %p, sample %p, format %p.\n", transform, sample, format); if ((status = __wine_unix_call(unix_handle, unix_wg_transform_read_data, ¶ms))) return HRESULT_FROM_NT(status); diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c index e093e2c201e..326b8691a42 100644 --- a/dlls/winegstreamer/quartz_transform.c +++ b/dlls/winegstreamer/quartz_transform.c @@ -350,7 +350,7 @@ static HRESULT WINAPI transform_sink_receive(struct strmbase_sink *pin, IMediaSa return hr; } - hr = wg_transform_read_data(filter->transform, &output_wg_sample); + hr = wg_transform_read_data(filter->transform, &output_wg_sample, NULL); if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { IMediaSample_Release(output_sample); diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 5911278530d..e8cdfaf7217 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -257,6 +257,7 @@ struct wg_transform_read_data_params { struct wg_transform *transform; struct wg_sample *sample; + struct wg_format *format; HRESULT result; }; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 06b26a04310..946268ee353 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -489,8 +489,10 @@ 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; + struct wg_format *format = params->format; GstBufferList *input = transform->input; GstBuffer *output_buffer; + GstCaps *output_caps; GstFlowReturn ret; NTSTATUS status; @@ -517,11 +519,15 @@ NTSTATUS wg_transform_read_data(void *args) } output_buffer = gst_sample_get_buffer(transform->output_sample); + output_caps = gst_sample_get_caps(transform->output_sample); if (gst_sample_get_info(transform->output_sample)) { gst_sample_set_info(transform->output_sample, NULL); + if (format) + wg_format_from_caps(format, output_caps); + params->result = MF_E_TRANSFORM_STREAM_CHANGE; GST_INFO("Format changed detected, returning no output"); return STATUS_SUCCESS; diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index ca53816f134..106d32adce9 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -586,7 +586,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, return MF_E_BUFFERTOOSMALL; } - if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, wg_sample))) + if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, wg_sample, NULL))) { if (wg_sample->flags & WG_SAMPLE_FLAG_INCOMPLETE) samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_INCOMPLETE;