From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/tests/transform.c | 10 ++++++-- dlls/winegstreamer/video_decoder.c | 37 ++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 0291fe16e18..1ca6652598d 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -5886,6 +5886,7 @@ static void test_wmv_decoder(void) const struct sample_desc *output_sample_desc; const WCHAR *result_bitmap; ULONG delta; + BOOL todo; } transform_tests[] = { @@ -5908,7 +5909,7 @@ static void test_wmv_decoder(void) .expect_output_info = &expect_output_info, .output_sample_desc = &output_sample_desc_nv12_todo_time, .result_bitmap = L"nv12frame.bmp", - .delta = 0, + .delta = 0, .todo = TRUE, },
{ @@ -5941,7 +5942,7 @@ static void test_wmv_decoder(void) .expect_output_info = &expect_output_info_rgb, .output_sample_desc = &output_sample_desc_rgb, .result_bitmap = L"rgb32frame-flip.bmp", - .delta = 5, + .delta = 5, .todo = TRUE, },
}; @@ -6114,8 +6115,13 @@ static void test_wmv_decoder(void)
ret = check_mf_sample_collection(output_samples, transform_tests[j].output_sample_desc, transform_tests[j].result_bitmap); + todo_wine_if(transform_tests[j].todo) ok(ret <= transform_tests[j].delta, "got %lu%% diff\n", ret); IMFCollection_Release(output_samples); + + hr = IMFTransform_SetOutputType(transform, 0, NULL, 0); + ok(hr == S_OK, "SetOutputType returned %#lx\n", hr); + winetest_pop_context(); }
diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 6525cbff513..948fc6ab0ec 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -546,6 +546,27 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM
TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
+ if (!type) + { + if (decoder->input_type) + { + IMFMediaType_Release(decoder->input_type); + decoder->input_type = NULL; + } + if (decoder->output_type) + { + IMFMediaType_Release(decoder->output_type); + decoder->output_type = NULL; + } + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = 0; + } + + return S_OK; + } + if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) return E_INVALIDARG; @@ -597,6 +618,22 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF
TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
+ if (!type) + { + if (decoder->output_type) + { + IMFMediaType_Release(decoder->output_type); + decoder->output_type = NULL; + } + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = 0; + } + + return S_OK; + } + if (!decoder->input_type) return MF_E_TRANSFORM_TYPE_NOT_SET;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/tests/transform.c | 7 +++--- dlls/winegstreamer/video_decoder.c | 35 +++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 9 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 1ca6652598d..febb1e33365 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -5909,7 +5909,7 @@ static void test_wmv_decoder(void) .expect_output_info = &expect_output_info, .output_sample_desc = &output_sample_desc_nv12_todo_time, .result_bitmap = L"nv12frame.bmp", - .delta = 0, .todo = TRUE, + .delta = 0, },
{ @@ -5935,14 +5935,14 @@ static void test_wmv_decoder(void) },
{ - /* WMV1 -> RGB (positive stride */ + /* WMV1 -> RGB (positive stride) */ .output_type_desc = output_type_desc_rgb_positive_stride, .expect_output_type_desc = expect_output_type_desc_rgb, .expect_input_info = &expect_input_info_rgb, .expect_output_info = &expect_output_info_rgb, .output_sample_desc = &output_sample_desc_rgb, .result_bitmap = L"rgb32frame-flip.bmp", - .delta = 5, .todo = TRUE, + .delta = 5, },
}; @@ -6115,7 +6115,6 @@ static void test_wmv_decoder(void)
ret = check_mf_sample_collection(output_samples, transform_tests[j].output_sample_desc, transform_tests[j].result_bitmap); - todo_wine_if(transform_tests[j].todo) ok(ret <= transform_tests[j].delta, "got %lu%% diff\n", ret); IMFCollection_Release(output_samples);
diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 948fc6ab0ec..22b21b94bb1 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -238,7 +238,23 @@ static struct video_decoder *impl_from_IMFTransform(IMFTransform *iface) return CONTAINING_RECORD(iface, struct video_decoder, IMFTransform_iface); }
-static HRESULT try_create_wg_transform(struct video_decoder *decoder) +static HRESULT video_decoder_set_default_stride(IMFMediaType *media_type, IMFMediaType **ret) +{ + DMO_MEDIA_TYPE amt; + HRESULT hr; + + if (SUCCEEDED(hr = MFInitAMMediaTypeFromMFMediaType(media_type, FORMAT_VideoInfo, &amt))) + { + VIDEOINFOHEADER *vih = (VIDEOINFOHEADER *)amt.pbFormat; + vih->bmiHeader.biHeight = abs(vih->bmiHeader.biHeight); + hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &amt, ret); + FreeMediaType(&amt); + } + + return hr; +} + +static HRESULT try_create_wg_transform(struct video_decoder *decoder, IMFMediaType *output_type) { /* 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 @@ -256,7 +272,7 @@ static HRESULT try_create_wg_transform(struct video_decoder *decoder) if (SUCCEEDED(IMFAttributes_GetUINT32(decoder->attributes, &MF_LOW_LATENCY, &low_latency))) decoder->wg_transform_attrs.low_latency = !!low_latency;
- return wg_transform_create_mf(decoder->input_type, decoder->output_type, &decoder->wg_transform_attrs, &decoder->wg_transform); + return wg_transform_create_mf(decoder->input_type, output_type, &decoder->wg_transform_attrs, &decoder->wg_transform); }
static HRESULT create_output_media_type(struct video_decoder *decoder, const GUID *subtype, @@ -612,6 +628,7 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF { struct video_decoder *decoder = impl_from_IMFTransform(iface); UINT64 frame_size, stream_frame_size; + IMFMediaType *output_type; GUID major, subtype; HRESULT hr; ULONG i; @@ -662,25 +679,33 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF IMFMediaType_Release(decoder->output_type); IMFMediaType_AddRef((decoder->output_type = type));
+ /* WMV decoder outputs RGB formats with default stride forced to negative, likely a result of internal conversion to DMO media type */ + if (!decoder->IMediaObject_iface.lpVtbl || FAILED(video_decoder_set_default_stride(decoder->output_type, &output_type))) + { + output_type = decoder->output_type; + IMFMediaType_AddRef(output_type); + } + if (decoder->wg_transform) { struct wg_format output_format; - mf_media_type_to_wg_format(decoder->output_type, &output_format); + mf_media_type_to_wg_format(output_type, &output_format);
if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN || !wg_transform_set_output_format(decoder->wg_transform, &output_format)) { IMFMediaType_Release(decoder->output_type); decoder->output_type = NULL; - return MF_E_INVALIDMEDIATYPE; + hr = MF_E_INVALIDMEDIATYPE; } } - else if (FAILED(hr = try_create_wg_transform(decoder))) + else if (FAILED(hr = try_create_wg_transform(decoder, output_type))) { IMFMediaType_Release(decoder->output_type); decoder->output_type = NULL; }
+ IMFMediaType_Release(output_type); return hr; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/tests/transform.c | 1 - dlls/winegstreamer/video_processor.c | 39 +++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 2 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index febb1e33365..38e31af97c1 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -9377,7 +9377,6 @@ static void test_video_processor_with_dxgi_manager(void) IMFSample_Release(output.pSample);
ret = check_mf_sample_collection(output_samples, &output_sample_desc_rgb32, L"rgb32frame.bmp"); - todo_wine /* FIXME: video process vertically flips the frame... */ ok(ret <= 5, "got %lu%% diff\n", ret);
for (i = 0; i < 9; i++) diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index 6cc504727a9..a27eebf020e 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -91,9 +91,35 @@ struct video_processor IMFVideoSampleAllocatorEx *allocator; };
+static HRESULT video_processor_set_default_stride(IMFMediaType *media_type, BOOL bottom_up, IMFMediaType **ret) +{ + MFVIDEOFORMAT *format; + LONG stride; + UINT32 size; + HRESULT hr; + + if (SUCCEEDED(hr = IMFMediaType_GetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, (UINT32 *)&stride))) + { + *ret = media_type; + IMFMediaType_AddRef(media_type); + return hr; + } + + if (SUCCEEDED(hr = MFCreateMFVideoFormatFromMFMediaType(media_type, &format, &size))) + { + if (bottom_up) format->videoInfo.VideoFlags |= MFVideoFlag_BottomUpLinearRep; + hr = MFCreateVideoMediaType(format, (IMFVideoMediaType **)ret); + CoTaskMemFree(format); + } + + return hr; +} + static HRESULT try_create_wg_transform(struct video_processor *impl) { + IMFMediaType *input_type, *output_type; struct wg_transform_attrs attrs = {0}; + HRESULT hr;
if (impl->wg_transform) { @@ -101,7 +127,18 @@ static HRESULT try_create_wg_transform(struct video_processor *impl) impl->wg_transform = 0; }
- return wg_transform_create_mf(impl->input_type, impl->output_type, &attrs, &impl->wg_transform); + if (FAILED(hr = video_processor_set_default_stride(impl->input_type, !impl->device_manager, &input_type))) + return hr; + if (FAILED(hr = video_processor_set_default_stride(impl->output_type, !impl->device_manager, &output_type))) + { + IMFMediaType_Release(input_type); + return hr; + } + hr = wg_transform_create_mf(input_type, output_type, &attrs, &impl->wg_transform); + IMFMediaType_Release(output_type); + IMFMediaType_Release(input_type); + + return hr; }
static HRESULT video_processor_init_allocator(struct video_processor *processor)
From: Rémi Bernon rbernon@codeweavers.com
Stripping the caps from the unwanted fields as needed. --- dlls/quartz/tests/mpegvideo.c | 9 ++-- dlls/winegstreamer/wg_transform.c | 80 +++++++++++++++++-------------- 2 files changed, 47 insertions(+), 42 deletions(-)
diff --git a/dlls/quartz/tests/mpegvideo.c b/dlls/quartz/tests/mpegvideo.c index 08c59e169fb..835bc5bec42 100644 --- a/dlls/quartz/tests/mpegvideo.c +++ b/dlls/quartz/tests/mpegvideo.c @@ -1201,7 +1201,7 @@ static void test_quality_control(IFilterGraph2 *graph, IBaseFilter *filter, testsource->qc = NULL; }
-static void test_send_sample(IMemInputPin *input, IMediaSample *sample, const BYTE *data, LONG len, BOOL todo) +static void test_send_sample(IMemInputPin *input, IMediaSample *sample, const BYTE *data, LONG len) { BYTE *target_data; HRESULT hr; @@ -1216,8 +1216,7 @@ static void test_send_sample(IMemInputPin *input, IMediaSample *sample, const BY ok(hr == S_OK, "Got hr %#lx.\n", hr);
hr = IMemInputPin_Receive(input, sample); - todo_wine_if(todo) /* 0xc00d6d61 is MF_E_TRANSFORM_STREAM_CHANGE */ - ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(hr == S_OK, "Got hr %#lx.\n", hr); }
static void test_send_video(IMemInputPin *input, IMediaSample *sample) @@ -1248,8 +1247,8 @@ static void test_send_video(IMemInputPin *input, IMediaSample *sample) IPin *pin;
/* native won't emit anything until an unknown-sized internal buffer is filled, or EOS is announced */ - test_send_sample(input, sample, empty_mpg_frames, ARRAY_SIZE(empty_mpg_frames), TRUE); - test_send_sample(input, sample, empty_mpg_eos, ARRAY_SIZE(empty_mpg_eos), FALSE); + test_send_sample(input, sample, empty_mpg_frames, ARRAY_SIZE(empty_mpg_frames)); + test_send_sample(input, sample, empty_mpg_eos, ARRAY_SIZE(empty_mpg_eos));
hr = IMemInputPin_QueryInterface(input, &IID_IPin, (void **)&pin); ok(hr == S_OK, "Got hr %#lx.\n", hr); diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index d85da3d7633..ec08f1322c0 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -56,7 +56,6 @@ struct wg_transform bool input_is_flipped; GstElement *video_flip;
- struct wg_format output_format; GstAtomicQueue *output_queue; GstSample *output_sample; bool output_caps_changed; @@ -96,7 +95,7 @@ static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, Gst return GST_FLOW_ERROR; }
- if (transform->output_caps_changed) + if (transform->output_caps_changed && transform->attrs.allow_size_change) GST_MINI_OBJECT_FLAG_SET(sample, GST_SAMPLE_FLAG_WG_CAPS_CHANGED); transform->output_caps_changed = false;
@@ -188,28 +187,53 @@ static gboolean transform_sink_query_allocation(struct wg_transform *transform, return true; }
-static GstCaps *transform_format_to_caps(struct wg_transform *transform, const struct wg_format *format) +static void caps_remove_field(GstCaps *caps, const char *field) { - struct wg_format copy = *format; + guint i;
- if (format->major_type == WG_MAJOR_TYPE_VIDEO) + for (i = 0; i < gst_caps_get_size(caps); ++i) { - if (transform->attrs.allow_size_change) - copy.u.video.width = copy.u.video.height = 0; - copy.u.video.fps_n = copy.u.video.fps_d = 0; + GstStructure *structure = gst_caps_get_structure(caps, i); + gst_structure_remove_fields(structure, field, NULL); } +} + +static GstCaps *caps_strip_fields(GstCaps *caps, bool strip_size) +{ + if (stream_type_from_caps(caps) != GST_STREAM_TYPE_VIDEO) + return gst_caps_ref(caps); + + if ((caps = gst_caps_copy(caps))) + { + if (strip_size) + { + caps_remove_field(caps, "width"); + caps_remove_field(caps, "height"); + }
- return wg_format_to_caps(©); + /* strip fields which we do not support and could cause pipeline failure or spurious format changes */ + caps_remove_field(caps, "framerate"); + caps_remove_field(caps, "colorimetry"); + caps_remove_field(caps, "chroma-site"); + caps_remove_field(caps, "interlace-mode"); + caps_remove_field(caps, "pixel-aspect-ratio"); + } + + return caps; }
static gboolean transform_sink_query_caps(struct wg_transform *transform, GstQuery *query) { GstCaps *caps, *filter, *temp; + bool strip_size = false;
GST_LOG("transform %p, %"GST_PTR_FORMAT, transform, query);
gst_query_parse_caps(query, &filter); - if (!(caps = transform_format_to_caps(transform, &transform->output_format))) + if (filter && gst_structure_has_field(gst_caps_get_structure(filter, 0), "width")) + strip_size = transform->attrs.allow_size_change; + + if (!(caps = caps_strip_fields(transform->output_caps, strip_size))) return false;
if (filter) @@ -248,23 +272,6 @@ static gboolean transform_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery return gst_pad_query_default(pad, parent, query); }
-static gboolean transform_output_caps_is_compatible(struct wg_transform *transform, GstCaps *caps) -{ - GstCaps *copy = gst_caps_copy(caps); - gboolean ret; - gsize i; - - for (i = 0; i < gst_caps_get_size(copy); ++i) - { - GstStructure *structure = gst_caps_get_structure(copy, i); - gst_structure_remove_fields(structure, "framerate", NULL); - } - - ret = gst_caps_is_always_compatible(transform->output_caps, copy); - gst_caps_unref(copy); - return ret; -} - static void transform_sink_event_caps(struct wg_transform *transform, GstEvent *event) { GstCaps *caps; @@ -273,9 +280,7 @@ static void transform_sink_event_caps(struct wg_transform *transform, GstEvent *
gst_event_parse_caps(event, &caps);
- transform->output_caps_changed = transform->output_caps_changed - || !transform_output_caps_is_compatible(transform, caps); - + transform->output_caps_changed = true; gst_caps_unref(transform->output_caps); transform->output_caps = gst_caps_ref(caps); } @@ -411,9 +416,8 @@ NTSTATUS wg_transform_create(void *args) if (!(transform->allocator = wg_allocator_create())) goto out; transform->attrs = *params->attrs; - transform->output_format = output_format;
- if (!(src_caps = transform_format_to_caps(transform, &input_format))) + if (!(src_caps = wg_format_to_caps(&input_format))) goto out; if (!(template = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps))) goto out; @@ -427,7 +431,7 @@ NTSTATUS wg_transform_create(void *args) 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 = transform_format_to_caps(transform, &output_format))) + 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))) goto out; @@ -610,23 +614,25 @@ NTSTATUS wg_transform_set_output_format(void *args) struct wg_transform_set_output_format_params *params = args; struct wg_transform *transform = get_transform(params->transform); const struct wg_format *format = params->format; + GstCaps *caps, *stripped; GstSample *sample; - GstCaps *caps;
- if (!(caps = transform_format_to_caps(transform, format))) + if (!(caps = wg_format_to_caps(format))) { GST_ERROR("Failed to convert format %p to caps.", format); return STATUS_UNSUCCESSFUL; } - transform->output_format = *format;
GST_INFO("transform %p output caps %"GST_PTR_FORMAT, transform, caps);
- if (transform_output_caps_is_compatible(transform, caps)) + stripped = caps_strip_fields(caps, transform->attrs.allow_size_change); + if (gst_caps_is_always_compatible(transform->output_caps, stripped)) { + gst_caps_unref(stripped); gst_caps_unref(caps); return STATUS_SUCCESS; } + gst_caps_unref(stripped);
if (!gst_pad_peer_query(transform->my_src, transform->drain_query)) {
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winegstreamer/aac_decoder.c | 2 +- dlls/winegstreamer/color_convert.c | 2 +- dlls/winegstreamer/gst_private.h | 9 +++- dlls/winegstreamer/main.c | 19 ++++++-- dlls/winegstreamer/resampler.c | 2 +- dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.h | 8 +++- dlls/winegstreamer/video_decoder.c | 12 ++--- dlls/winegstreamer/video_processor.c | 3 +- dlls/winegstreamer/wg_parser.c | 19 +++++++- dlls/winegstreamer/wg_sample.c | 19 +++----- dlls/winegstreamer/wg_transform.c | 66 ++++++++++++++++++---------- dlls/winegstreamer/wma_decoder.c | 2 +- 13 files changed, 107 insertions(+), 57 deletions(-)
diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index 0d012fd710a..2cf605bc56c 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -521,7 +521,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, return hr;
if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, samples->pSample, - info.cbSize, NULL, &samples->dwStatus))) + info.cbSize, &samples->dwStatus))) wg_sample_queue_flush(decoder->wg_sample_queue, false); else samples->dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE; diff --git a/dlls/winegstreamer/color_convert.c b/dlls/winegstreamer/color_convert.c index 949b85943d0..4b60628e8ba 100644 --- a/dlls/winegstreamer/color_convert.c +++ b/dlls/winegstreamer/color_convert.c @@ -582,7 +582,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, return hr;
if (SUCCEEDED(hr = wg_transform_read_mf(impl->wg_transform, samples->pSample, - info.cbSize, NULL, &samples->dwStatus))) + info.cbSize, &samples->dwStatus))) wg_sample_queue_flush(impl->wg_sample_queue, false);
return hr; diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 85991c2efde..ba9064bc467 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -88,6 +88,7 @@ HRESULT wg_transform_create_mf(IMFMediaType *input_type, IMFMediaType *output_ty HRESULT wg_transform_create_quartz(const AM_MEDIA_TYPE *input_format, const AM_MEDIA_TYPE *output_format, const struct wg_transform_attrs *attrs, wg_transform_t *transform); void wg_transform_destroy(wg_transform_t transform); +bool wg_transform_get_output_format(wg_transform_t transform, struct wg_format *format); bool wg_transform_set_output_format(wg_transform_t transform, struct wg_format *format); bool wg_transform_get_status(wg_transform_t transform, bool *accepts_input); HRESULT wg_transform_drain(wg_transform_t transform); @@ -146,10 +147,16 @@ HRESULT wg_transform_push_quartz(wg_transform_t transform, struct wg_sample *sam HRESULT wg_transform_push_dmo(wg_transform_t transform, IMediaBuffer *media_buffer, DWORD flags, REFERENCE_TIME time_stamp, REFERENCE_TIME time_length, struct wg_sample_queue *queue); HRESULT wg_transform_read_mf(wg_transform_t transform, IMFSample *sample, - DWORD sample_size, struct wg_format *format, DWORD *flags); + DWORD sample_size, DWORD *flags); HRESULT wg_transform_read_quartz(wg_transform_t transform, struct wg_sample *sample); HRESULT wg_transform_read_dmo(wg_transform_t transform, DMO_OUTPUT_DATA_BUFFER *buffer);
+/* These unixlib entry points should not be used directly, they assume samples + * to be queued and zero-copy support, use the helpers below instead. + */ +HRESULT wg_transform_push_data(wg_transform_t transform, struct wg_sample *sample); +HRESULT wg_transform_read_data(wg_transform_t transform, struct wg_sample *sample); + HRESULT gstreamer_byte_stream_handler_create(REFIID riid, void **obj);
unsigned int wg_format_get_stride(const struct wg_format *format); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 220cc2cf52c..747479daf40 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -415,18 +415,16 @@ HRESULT wg_transform_push_data(wg_transform_t transform, struct wg_sample *sampl return params.result; }
-HRESULT wg_transform_read_data(wg_transform_t transform, struct wg_sample *sample, - struct wg_format *format) +HRESULT wg_transform_read_data(wg_transform_t transform, struct wg_sample *sample) { struct wg_transform_read_data_params params = { .transform = transform, .sample = sample, - .format = format, }; NTSTATUS status;
- TRACE("transform %#I64x, sample %p, format %p.\n", transform, sample, format); + TRACE("transform %#I64x, sample %p.\n", transform, sample);
if ((status = WINE_UNIX_CALL(unix_wg_transform_read_data, ¶ms))) return HRESULT_FROM_NT(status); @@ -450,6 +448,19 @@ bool wg_transform_get_status(wg_transform_t transform, bool *accepts_input) return true; }
+bool wg_transform_get_output_format(wg_transform_t transform, struct wg_format *format) +{ + struct wg_transform_get_output_format_params params = + { + .transform = transform, + .format = format, + }; + + TRACE("transform %#I64x, format %p.\n", transform, format); + + return !WINE_UNIX_CALL(unix_wg_transform_get_output_format, ¶ms); +} + bool wg_transform_set_output_format(wg_transform_t transform, struct wg_format *format) { struct wg_transform_set_output_format_params params = diff --git a/dlls/winegstreamer/resampler.c b/dlls/winegstreamer/resampler.c index 8df7eb32649..c1ce9897ef1 100644 --- a/dlls/winegstreamer/resampler.c +++ b/dlls/winegstreamer/resampler.c @@ -541,7 +541,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, return hr;
if (SUCCEEDED(hr = wg_transform_read_mf(impl->wg_transform, samples->pSample, - info.cbSize, NULL, &samples->dwStatus))) + info.cbSize, &samples->dwStatus))) wg_sample_queue_flush(impl->wg_sample_queue, false);
return hr; diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index bb2cb864735..6f01b3a5a69 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -56,6 +56,7 @@ extern GstCaps *wg_format_to_caps(const struct wg_format *format);
extern NTSTATUS wg_transform_create(void *args); extern NTSTATUS wg_transform_destroy(void *args); +extern NTSTATUS wg_transform_get_output_format(void *args); extern NTSTATUS wg_transform_set_output_format(void *args); extern NTSTATUS wg_transform_push_data(void *args); extern NTSTATUS wg_transform_read_data(void *args); diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 907cbb2c9b4..cf8cb0ca24c 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -325,10 +325,15 @@ struct wg_transform_read_data_params { wg_transform_t transform; struct wg_sample *sample; - struct wg_format *format; HRESULT result; };
+struct wg_transform_get_output_format_params +{ + wg_transform_t transform; + struct wg_format *format; +}; + struct wg_transform_set_output_format_params { wg_transform_t transform; @@ -410,6 +415,7 @@ enum unix_funcs
unix_wg_transform_create, unix_wg_transform_destroy, + unix_wg_transform_get_output_format, unix_wg_transform_set_output_format,
unix_wg_transform_push_data, diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 22b21b94bb1..89fbe876fc1 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -845,14 +845,17 @@ static HRESULT output_sample(struct video_decoder *decoder, IMFSample **out, IMF return S_OK; }
-static HRESULT handle_stream_type_change(struct video_decoder *decoder, const struct wg_format *format) +static HRESULT handle_stream_type_change(struct video_decoder *decoder) { UINT64 frame_size, frame_rate; + struct wg_format format; HRESULT hr;
if (decoder->stream_type) IMFMediaType_Release(decoder->stream_type); - if (!(decoder->stream_type = mf_media_type_from_wg_format(format))) + if (!(wg_transform_get_output_format(decoder->wg_transform, &format))) + return E_FAIL; + if (!(decoder->stream_type = mf_media_type_from_wg_format(&format))) return E_OUTOFMEMORY;
if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &frame_rate)) @@ -872,7 +875,6 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) { struct video_decoder *decoder = impl_from_IMFTransform(iface); - struct wg_format wg_format; UINT32 sample_size; LONGLONG duration; IMFSample *sample; @@ -922,7 +924,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, }
if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, sample, - sample_size, &wg_format, &samples->dwStatus))) + sample_size, &samples->dwStatus))) { wg_sample_queue_flush(decoder->wg_sample_queue, false);
@@ -941,7 +943,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, { samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; - hr = handle_stream_type_change(decoder, &wg_format); + hr = handle_stream_type_change(decoder); }
if (decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index a27eebf020e..0bc9d4e10cb 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -692,8 +692,7 @@ static HRESULT WINAPI video_processor_ProcessOutput(IMFTransform *iface, DWORD f IMFSample_AddRef(output_sample); }
- if (FAILED(hr = wg_transform_read_mf(impl->wg_transform, output_sample, info.cbSize, - NULL, &samples->dwStatus))) + if (FAILED(hr = wg_transform_read_mf(impl->wg_transform, output_sample, info.cbSize, &samples->dwStatus))) goto done; wg_sample_queue_flush(impl->wg_sample_queue, false);
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 431a8b74cb2..f9b76b12f8f 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1889,6 +1889,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
X(wg_transform_create), X(wg_transform_destroy), + X(wg_transform_get_output_format), X(wg_transform_set_output_format),
X(wg_transform_push_data), @@ -2074,6 +2075,21 @@ NTSTATUS wow64_wg_transform_create(void *args) return ret; }
+NTSTATUS wow64_wg_transform_get_output_format(void *args) +{ + struct + { + wg_transform_t transform; + PTR32 format; + } *params32 = args; + struct wg_transform_get_output_format_params params = + { + .transform = params32->transform, + .format = ULongToPtr(params32->format), + }; + return wg_transform_get_output_format(¶ms); +} + NTSTATUS wow64_wg_transform_set_output_format(void *args) { struct @@ -2115,14 +2131,12 @@ NTSTATUS wow64_wg_transform_read_data(void *args) { wg_transform_t transform; PTR32 sample; - PTR32 format; HRESULT result; } *params32 = args; struct wg_transform_read_data_params params = { .transform = params32->transform, .sample = ULongToPtr(params32->sample), - .format = ULongToPtr(params32->format), }; NTSTATUS ret;
@@ -2240,6 +2254,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
X64(wg_transform_create), X(wg_transform_destroy), + X64(wg_transform_get_output_format), X64(wg_transform_set_output_format),
X64(wg_transform_push_data), diff --git a/dlls/winegstreamer/wg_sample.c b/dlls/winegstreamer/wg_sample.c index 9427dad0f93..116dbb1f3ec 100644 --- a/dlls/winegstreamer/wg_sample.c +++ b/dlls/winegstreamer/wg_sample.c @@ -303,13 +303,6 @@ void wg_sample_queue_destroy(struct wg_sample_queue *queue) free(queue); }
-/* These unixlib entry points should not be used directly, they assume samples - * to be queued and zero-copy support, use the helpers below instead. - */ -HRESULT wg_transform_push_data(wg_transform_t transform, struct wg_sample *sample); -HRESULT wg_transform_read_data(wg_transform_t transform, struct wg_sample *sample, - struct wg_format *format); - HRESULT wg_transform_push_mf(wg_transform_t transform, IMFSample *sample, struct wg_sample_queue *queue) { @@ -346,23 +339,21 @@ HRESULT wg_transform_push_mf(wg_transform_t transform, IMFSample *sample, }
HRESULT wg_transform_read_mf(wg_transform_t transform, IMFSample *sample, - DWORD sample_size, struct wg_format *format, DWORD *flags) + DWORD sample_size, DWORD *flags) { struct wg_sample *wg_sample; IMFMediaBuffer *buffer; HRESULT hr;
- TRACE_(mfplat)("transform %#I64x, sample %p, format %p, flags %p.\n", transform, sample, format, flags); + TRACE_(mfplat)("transform %#I64x, sample %p, flags %p.\n", transform, sample, flags);
if (FAILED(hr = wg_sample_create_mf(sample, &wg_sample))) return hr;
wg_sample->size = 0;
- if (FAILED(hr = wg_transform_read_data(transform, wg_sample, format))) + if (FAILED(hr = wg_transform_read_data(transform, wg_sample))) { - if (hr == MF_E_TRANSFORM_STREAM_CHANGE && !format) - FIXME("Unexpected stream format change!\n"); wg_sample_release(wg_sample); return hr; } @@ -430,7 +421,7 @@ HRESULT wg_transform_read_quartz(wg_transform_t transform, struct wg_sample *wg_
TRACE_(mfplat)("transform %#I64x, wg_sample %p.\n", transform, wg_sample);
- if (FAILED(hr = wg_transform_read_data(transform, wg_sample, NULL))) + if (FAILED(hr = wg_transform_read_data(transform, wg_sample))) { if (hr == MF_E_TRANSFORM_STREAM_CHANGE) FIXME("Unexpected stream format change!\n"); @@ -505,7 +496,7 @@ HRESULT wg_transform_read_dmo(wg_transform_t transform, DMO_OUTPUT_DATA_BUFFER * return hr; wg_sample->size = 0;
- if (FAILED(hr = wg_transform_read_data(transform, wg_sample, NULL))) + if (FAILED(hr = wg_transform_read_data(transform, wg_sample))) { if (hr == MF_E_TRANSFORM_STREAM_CHANGE) TRACE_(mfplat)("Stream format changed.\n"); diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index ec08f1322c0..8352c15cd44 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -609,6 +609,48 @@ out: return status; }
+NTSTATUS wg_transform_get_output_format(void *args) +{ + struct wg_transform_get_output_format_params *params = args; + struct wg_transform *transform = get_transform(params->transform); + struct wg_format *format = params->format; + GstVideoInfo video_info; + GstCaps *output_caps; + + if (transform->output_sample) + output_caps = gst_sample_get_caps(transform->output_sample); + else + output_caps = transform->output_caps; + + GST_INFO("transform %p output caps %"GST_PTR_FORMAT, transform, output_caps); + + wg_format_from_caps(format, output_caps); + + if (stream_type_from_caps(output_caps) == GST_STREAM_TYPE_VIDEO + && gst_video_info_from_caps(&video_info, output_caps)) + { + gsize plane_align = transform->attrs.output_plane_align; + GstVideoAlignment align = {0}; + + /* set the desired output buffer alignment on the dest video info */ + align_video_info_planes(plane_align, &video_info, &align); + + GST_INFO("Returning video alignment left %u, top %u, right %u, bottom %u.", align.padding_left, + align.padding_top, align.padding_right, align.padding_bottom); + + format->u.video.padding.left = align.padding_left; + format->u.video.width += format->u.video.padding.left; + format->u.video.padding.right = align.padding_right; + format->u.video.width += format->u.video.padding.right; + format->u.video.padding.top = align.padding_top; + format->u.video.height += format->u.video.padding.top; + format->u.video.padding.bottom = align.padding_bottom; + format->u.video.height += format->u.video.padding.bottom; + } + + return STATUS_SUCCESS; +} + NTSTATUS wg_transform_set_output_format(void *args) { struct wg_transform_set_output_format_params *params = args; @@ -920,7 +962,6 @@ NTSTATUS wg_transform_read_data(void *args) struct wg_transform *transform = get_transform(params->transform); GstVideoInfo src_video_info, dst_video_info; struct wg_sample *sample = params->sample; - struct wg_format *format = params->format; GstVideoAlignment align = {0}; GstBuffer *output_buffer; GstCaps *output_caps; @@ -954,29 +995,6 @@ NTSTATUS wg_transform_read_data(void *args) if (GST_MINI_OBJECT_FLAG_IS_SET(transform->output_sample, GST_SAMPLE_FLAG_WG_CAPS_CHANGED)) { GST_MINI_OBJECT_FLAG_UNSET(transform->output_sample, GST_SAMPLE_FLAG_WG_CAPS_CHANGED); - - GST_INFO("transform %p output caps %"GST_PTR_FORMAT, transform, output_caps); - - if (format) - { - wg_format_from_caps(format, output_caps); - - if (format->major_type == WG_MAJOR_TYPE_VIDEO) - { - GST_INFO("Returning video alignment left %u, top %u, right %u, bottom %u.", align.padding_left, - align.padding_top, align.padding_right, align.padding_bottom); - - format->u.video.padding.left = align.padding_left; - format->u.video.width += format->u.video.padding.left; - format->u.video.padding.right = align.padding_right; - format->u.video.width += format->u.video.padding.right; - format->u.video.padding.top = align.padding_top; - format->u.video.height += format->u.video.padding.top; - format->u.video.padding.bottom = align.padding_bottom; - format->u.video.height += format->u.video.padding.bottom; - } - } - params->result = MF_E_TRANSFORM_STREAM_CHANGE; GST_INFO("Format changed detected, returning no output"); wg_allocator_release_sample(transform->allocator, sample, false); diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 8aa55b9b137..14a48db9ae2 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -557,7 +557,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, return hr;
if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, samples->pSample, - info.cbSize, NULL, &samples->dwStatus))) + info.cbSize, &samples->dwStatus))) wg_sample_queue_flush(decoder->wg_sample_queue, false);
return hr;
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=145861
Your paranoid android.
=== w11pro64_amd (64 bit report) ===
quartz: mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 138ca6e, expected 56ce. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 138ca6e, expected 56ce. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 138ca6e, expected 56ce. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 138ca6e, expected 56ce. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 138ca6e, expected 56ce. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 138ca6e, expected 56ce. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 138ca6e, expected 56ce. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 138ca6e, expected 56ce. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0. mpegvideo.c:945: Test failed: Got stop time 13873a0, expected 0.
Elizabeth Figura (@zfigura) commented about dlls/winegstreamer/video_decoder.c:
return CONTAINING_RECORD(iface, struct video_decoder, IMFTransform_iface);
}
-static HRESULT try_create_wg_transform(struct video_decoder *decoder) +static HRESULT video_decoder_set_default_stride(IMFMediaType *media_type, IMFMediaType **ret)
This is a misleading name for an idempotent function which doesn't set any state on any of the passed-in objects. How about something like "normalize_stride"?
Elizabeth Figura (@zfigura) commented about dlls/winegstreamer/video_decoder.c:
IMFMediaType_Release(decoder->output_type); IMFMediaType_AddRef((decoder->output_type = type));
- /* WMV decoder outputs RGB formats with default stride forced to negative, likely a result of internal conversion to DMO media type */
- if (!decoder->IMediaObject_iface.lpVtbl || FAILED(video_decoder_set_default_stride(decoder->output_type, &output_type)))
Isn't failure from video_decoder_set_default_stride() only exceptional? Falling back to the previous type seems odd here in that case.
Elizabeth Figura (@zfigura) commented about dlls/winegstreamer/video_processor.c:
impl->wg_transform = 0; }
- return wg_transform_create_mf(impl->input_type, impl->output_type, &attrs, &impl->wg_transform);
- if (FAILED(hr = video_processor_set_default_stride(impl->input_type, !impl->device_manager, &input_type)))
return hr;
- if (FAILED(hr = video_processor_set_default_stride(impl->output_type, !impl->device_manager, &output_type)))
This !impl->device_manager feels like the kind of thing that needs explanation in the form of a comment.
Elizabeth Figura (@zfigura) commented about dlls/winegstreamer/wg_transform.c:
return GST_FLOW_ERROR; }
- if (transform->output_caps_changed)
- if (transform->output_caps_changed && transform->attrs.allow_size_change)
I was under the impression that H.264 included caps changes that weren't related to size. If that's true, then "allow_size_change" should probably be renamed to "allow_format_change" or "report_format_change". If not, then "output_caps_changed" should be renamed to "output_size_changed", with the code changes that implies.
Elizabeth Figura (@zfigura) commented about dlls/winegstreamer/wg_transform.c:
- return caps;
}
static gboolean transform_sink_query_caps(struct wg_transform *transform, GstQuery *query) { GstCaps *caps, *filter, *temp;
bool strip_size = false;
GST_LOG("transform %p, %"GST_PTR_FORMAT, transform, query);
gst_query_parse_caps(query, &filter);
- if (!(caps = transform_format_to_caps(transform, &transform->output_format)))
- if (filter && gst_structure_has_field(gst_caps_get_structure(filter, 0), "width"))
strip_size = transform->attrs.allow_size_change;
- if (!(caps = caps_strip_fields(transform->output_caps, strip_size)))
But transform->output_format isn't equivalent to transform->output_caps.
GStreamer may never do a caps query at a relevant time, but if the application is required to call SetOutputType() with the new format, then pretending that the new format is already set looks very wrong.
4/5 does at least two significant changes besides removing the field. Those two changes should be split, and it wouldn't even be amiss to remove the field in a third commit after it has no users. (Assuming that we can even remove the field, though; see my inline comment.)
5/5 could use a better subject. Not only is "introduce a new function" incomplete (since the function is also *used* in the same commmit), but it doesn't tell me what code it's replacing. Nor does it explain why. Why is this separate entry point better?