-- v7: winegstreamer: Implement ProcessInput and ProcessOutput for WMV decoder DMO. winegstreamer: Create wg_transform for WMV decoder. winegstreamer: Better handle framerate. winegstreamer: Add format field to wmv wg_format. mf/tests: Test time length returned by ProcessOutput.
From: Ziqing Hui zhui@codeweavers.com
Time length returned by ProcessOutput is equal to the one passed to ProcessInput. --- dlls/mf/tests/transform.c | 58 ++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 16 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 7d217dfe8c0..17b59c46b97 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -1617,23 +1617,23 @@ static void check_dmo_set_output_type(IMediaObject *media_object, const GUID *su } }
-#define check_dmo_output_data_buffer(a, b, c) check_dmo_output_data_buffer_(__LINE__, a, b, c) +#define check_dmo_output_data_buffer(a, b, c, d, e) check_dmo_output_data_buffer_(__LINE__, a, b, c, d, e) static DWORD check_dmo_output_data_buffer_(int line, DMO_OUTPUT_DATA_BUFFER *output_data_buffer, - const struct sample_desc *sample_desc, const WCHAR *expect_data_filename) + const struct buffer_desc *buffer_desc, const WCHAR *expect_data_filename, + REFERENCE_TIME time_stamp, REFERENCE_TIME time_length) { - const struct buffer_desc *buffer_desc = &sample_desc->buffers[0]; DWORD diff, data_length, buffer_length, expect_length; BYTE *data, *buffer; HRESULT hr;
if (output_data_buffer->dwStatus & DMO_OUTPUT_DATA_BUFFERF_TIME) - ok_(__FILE__, line)(output_data_buffer->rtTimestamp == sample_desc->sample_time, - "Unexpected time %I64d, expected %I64d.\n", - output_data_buffer->rtTimestamp, sample_desc->sample_time); + ok_(__FILE__, line)(output_data_buffer->rtTimestamp == time_stamp, + "Unexpected time stamp %I64d, expected %I64d.\n", + output_data_buffer->rtTimestamp, time_stamp); if (output_data_buffer->dwStatus & DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH) - ok_(__FILE__, line)(output_data_buffer->rtTimelength == sample_desc->sample_duration, - "Unexpected duration %I64d, expected %I64d.\n", - output_data_buffer->rtTimelength, sample_desc->sample_duration); + ok_(__FILE__, line)(output_data_buffer->rtTimelength == time_length, + "Unexpected time length %I64d, expected %I64d.\n", + output_data_buffer->rtTimelength, time_length);
load_resource(expect_data_filename, (const BYTE **)&data, &data_length);
@@ -5219,11 +5219,6 @@ static void test_wmv_decoder_media_object(void) .length = data_width * data_height * 3 / 2, .compare = compare_nv12, .dump = dump_nv12, .rect = {.right = 82, .bottom = 84}, }; - const struct sample_desc output_sample_desc_nv12 = - { - .sample_time = 0, .sample_duration = 333333, - .buffer_count = 1, .buffers = &output_buffer_desc_nv12, - }; DWORD in_count, out_count, size, expected_size, alignment, wmv_data_length, status, expected_status, diff; struct media_buffer *input_media_buffer = NULL, *output_media_buffer = NULL; DMO_OUTPUT_DATA_BUFFER output_data_buffer; @@ -5369,7 +5364,7 @@ static void test_wmv_decoder_media_object(void) hr = IMediaObject_SetOutputType(media_object, 0, type, 0); ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
- hr = IMediaObject_ProcessInput(media_object, 0, &input_media_buffer->IMediaBuffer_iface, 0, 0, 333333); + hr = IMediaObject_ProcessInput(media_object, 0, &input_media_buffer->IMediaBuffer_iface, 0, 0, 0); todo_wine ok(hr == S_OK, "ProcessInput returned %#lx.\n", hr);
@@ -5390,7 +5385,38 @@ static void test_wmv_decoder_media_object(void) ok(output_data_buffer.dwStatus == expected_status, "Got unexpected dwStatus %#lx.\n", output_data_buffer.dwStatus); if (hr == S_OK) { - diff = check_dmo_output_data_buffer(&output_data_buffer, &output_sample_desc_nv12, L"nv12frame.bmp"); + diff = check_dmo_output_data_buffer(&output_data_buffer, &output_buffer_desc_nv12, L"nv12frame.bmp", 0, 0); + ok(diff == 0, "Got %lu%% diff.\n", diff); + } + + /* Test ProcessOutput with setting framerate. */ + init_dmo_media_type_video(type, &MEDIASUBTYPE_WMV1, data_width, data_height); + ((VIDEOINFOHEADER *)type->pbFormat)->AvgTimePerFrame = 100000; + hr = IMediaObject_SetInputType(media_object, 0, type, 0); + ok(hr == S_OK, "SetInputType returned %#lx.\n", hr); + init_dmo_media_type_video(type, &MEDIASUBTYPE_NV12, data_width, data_height); + ((VIDEOINFOHEADER *)type->pbFormat)->AvgTimePerFrame = 200000; + hr = IMediaObject_SetOutputType(media_object, 0, type, 0); + ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr); + + hr = IMediaObject_ProcessInput(media_object, 0, &input_media_buffer->IMediaBuffer_iface, 0, 0, 300000); + todo_wine + ok(hr == S_OK, "ProcessInput returned %#lx.\n", hr); + + output_media_buffer->length = 0; + output_data_buffer.pBuffer = &output_media_buffer->IMediaBuffer_iface; + output_data_buffer.dwStatus = 0xdeadbeef; + output_data_buffer.rtTimestamp = 0xdeadbeef; + output_data_buffer.rtTimelength = 0xdeadbeef; + hr = IMediaObject_ProcessOutput(media_object, 0, 1, &output_data_buffer, &status); + todo_wine + ok(hr == S_OK, "ProcessOutput returned %#lx.\n", hr); + expected_status = DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT | DMO_OUTPUT_DATA_BUFFERF_TIME | DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH; + todo_wine + ok(output_data_buffer.dwStatus == expected_status, "Got unexpected dwStatus %#lx.\n", output_data_buffer.dwStatus); + if (hr == S_OK) + { + diff = check_dmo_output_data_buffer(&output_data_buffer, &output_buffer_desc_nv12, L"nv12frame.bmp", 0, 300000); ok(diff == 0, "Got %lu%% diff.\n", diff); }
From: Ziqing Hui zhui@codeweavers.com
Wrong plugins will be selected for WMV decoder if we don't set format field. --- dlls/winegstreamer/quartz_parser.c | 12 ++++++--- dlls/winegstreamer/unixlib.h | 10 +++++++- dlls/winegstreamer/wg_format.c | 39 ++++++++++++++++++++++++++++-- 3 files changed, 55 insertions(+), 6 deletions(-)
diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index c12e9ee3397..085a43b4297 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -763,11 +763,17 @@ static bool amt_to_wg_format_video_wmv(const AM_MEDIA_TYPE *mt, struct wg_format format->u.video_wmv.fps_d = video_format->AvgTimePerFrame;
if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMV1)) - format->u.video_wmv.version = 1; + format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMV1; else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMV2)) - format->u.video_wmv.version = 2; + format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMV2; + else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMV3)) + format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMV3; + else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMVA)) + format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMVA; + else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WVC1)) + format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WVC1; else - format->u.video_wmv.version = 3; + format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_UNKNOWN;
return true; } diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 19629d12fd0..539ccd3e12a 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -130,9 +130,17 @@ struct wg_format } video_h264; struct { + enum wg_wmv_video_format + { + WG_WMV_VIDEO_FORMAT_UNKNOWN, + WG_WMV_VIDEO_FORMAT_WMV1, + WG_WMV_VIDEO_FORMAT_WMV2, + WG_WMV_VIDEO_FORMAT_WMV3, + WG_WMV_VIDEO_FORMAT_WMVA, + WG_WMV_VIDEO_FORMAT_WVC1, + } format; int32_t width, height; uint32_t fps_n, fps_d; - uint32_t version; } video_wmv; struct { diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 63f1e3931b5..ac21b0af94f 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -556,19 +556,54 @@ static GstCaps *wg_format_to_caps_video_h264(const struct wg_format *format)
static GstCaps *wg_format_to_caps_video_wmv(const struct wg_format *format) { + unsigned int wmv_version; + const char *wmv_format; GstCaps *caps;
if (!(caps = gst_caps_new_empty_simple("video/x-wmv"))) return NULL;
+ switch (format->u.video_wmv.format) + { + case WG_WMV_VIDEO_FORMAT_WMV1: + wmv_format = "WMV1"; + wmv_version = 1; + break; + case WG_WMV_VIDEO_FORMAT_WMV2: + wmv_format = "WMV2"; + wmv_version = 2; + break; + case WG_WMV_VIDEO_FORMAT_WMV3: + wmv_format = "WMV3"; + wmv_version = 3; + break; + case WG_WMV_VIDEO_FORMAT_WMVA: + wmv_format = "WMVA"; + wmv_version = 3; + break; + case WG_WMV_VIDEO_FORMAT_WVC1: + wmv_format = "WVC1"; + wmv_version = 3; + break; + default: + GST_WARNING("Unknown WMV format %u.", format->u.video_wmv.format); + /* fallthrough */ + case WG_WMV_VIDEO_FORMAT_UNKNOWN: + wmv_format = NULL; + wmv_version = 0; + break; + } + + if (wmv_format) + gst_caps_set_simple(caps, "format", G_TYPE_STRING, wmv_format, NULL); + if (wmv_version) + gst_caps_set_simple(caps, "wmvversion", G_TYPE_INT, wmv_version, NULL); if (format->u.video_wmv.width) gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video_wmv.width, NULL); if (format->u.video_wmv.height) gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video_wmv.height, NULL); if (format->u.video_wmv.fps_d || format->u.video_wmv.fps_n) gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video_wmv.fps_n, format->u.video_wmv.fps_d, NULL); - if (format->u.video_wmv.version) - gst_caps_set_simple(caps, "wmvversion", G_TYPE_INT, format->u.video_wmv.version, NULL);
return caps; }
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/quartz_parser.c | 24 ++++++++++++++++++++---- dlls/winegstreamer/wg_format.c | 10 +++++----- dlls/winegstreamer/wmv_decoder.c | 6 ++++++ 3 files changed, 31 insertions(+), 9 deletions(-)
diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 085a43b4297..a2f7f066f83 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -725,8 +725,16 @@ static bool amt_to_wg_format_video(const AM_MEDIA_TYPE *mt, struct wg_format *fo format->major_type = WG_MAJOR_TYPE_VIDEO; format->u.video.width = video_format->bmiHeader.biWidth; format->u.video.height = video_format->bmiHeader.biHeight; - format->u.video.fps_n = 10000000; - format->u.video.fps_d = video_format->AvgTimePerFrame; + if (video_format->AvgTimePerFrame) + { + format->u.video_wmv.fps_n = 10000000; + format->u.video_wmv.fps_d = video_format->AvgTimePerFrame; + } + else + { + format->u.video_wmv.fps_n = 0; + format->u.video_wmv.fps_d = 0; + }
for (i = 0; i < ARRAY_SIZE(format_map); ++i) { @@ -759,8 +767,16 @@ static bool amt_to_wg_format_video_wmv(const AM_MEDIA_TYPE *mt, struct wg_format format->major_type = WG_MAJOR_TYPE_VIDEO_WMV; format->u.video_wmv.width = video_format->bmiHeader.biWidth; format->u.video_wmv.height = video_format->bmiHeader.biHeight; - format->u.video_wmv.fps_n = 10000000; - format->u.video_wmv.fps_d = video_format->AvgTimePerFrame; + if (video_format->AvgTimePerFrame) + { + format->u.video_wmv.fps_n = 10000000; + format->u.video_wmv.fps_d = video_format->AvgTimePerFrame; + } + else + { + format->u.video_wmv.fps_n = 0; + format->u.video_wmv.fps_d = 0; + }
if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMV1)) format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMV1; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index ac21b0af94f..1064b005207 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -430,7 +430,7 @@ static GstCaps *wg_format_to_caps_video(const struct wg_format *format) gst_structure_remove_fields(gst_caps_get_structure(caps, i), "width", NULL); if (!format->u.video.height) gst_structure_remove_fields(gst_caps_get_structure(caps, i), "height", NULL); - if (!format->u.video.fps_d && !format->u.video.fps_n) + if (!format->u.video.fps_d) gst_structure_remove_fields(gst_caps_get_structure(caps, i), "framerate", NULL); } } @@ -448,7 +448,7 @@ static GstCaps *wg_format_to_caps_video_cinepak(const struct wg_format *format) gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video_cinepak.width, NULL); if (format->u.video_cinepak.height) gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video_cinepak.height, NULL); - if (format->u.video_cinepak.fps_d || format->u.video_cinepak.fps_n) + if (format->u.video_cinepak.fps_d) gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video_cinepak.fps_n, format->u.video_cinepak.fps_d, NULL);
return caps; @@ -505,7 +505,7 @@ static GstCaps *wg_format_to_caps_video_h264(const struct wg_format *format) gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video_h264.width, NULL); if (format->u.video_h264.height) gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video_h264.height, NULL); - if (format->u.video_h264.fps_n || format->u.video_h264.fps_d) + if (format->u.video_h264.fps_d) gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video_h264.fps_n, format->u.video_h264.fps_d, NULL);
switch (format->u.video_h264.profile) @@ -602,7 +602,7 @@ static GstCaps *wg_format_to_caps_video_wmv(const struct wg_format *format) gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video_wmv.width, NULL); if (format->u.video_wmv.height) gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video_wmv.height, NULL); - if (format->u.video_wmv.fps_d || format->u.video_wmv.fps_n) + if (format->u.video_wmv.fps_d) gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video_wmv.fps_n, format->u.video_wmv.fps_d, NULL);
return caps; @@ -619,7 +619,7 @@ static GstCaps *wg_format_to_caps_video_indeo(const struct wg_format *format) gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video_indeo.width, NULL); if (format->u.video_indeo.height) gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video_indeo.height, NULL); - if (format->u.video_indeo.fps_d || format->u.video_indeo.fps_n) + if (format->u.video_indeo.fps_d) gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video_indeo.fps_n, format->u.video_indeo.fps_d, NULL); if (format->u.video_indeo.version) gst_caps_set_simple(caps, "indeoversion", G_TYPE_INT, format->u.video_indeo.version, NULL); diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c index 473fabab867..ed61ee0e2e3 100644 --- a/dlls/winegstreamer/wmv_decoder.c +++ b/dlls/winegstreamer/wmv_decoder.c @@ -505,6 +505,9 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index
if (!amt_to_wg_format((const AM_MEDIA_TYPE *)type, &wg_format)) return DMO_E_TYPE_NOT_ACCEPTED; + assert(wg_format.major_type == WG_MAJOR_TYPE_VIDEO_WMV); + wg_format.u.video_wmv.fps_n = 0; + wg_format.u.video_wmv.fps_d = 0;
if (!(flags & DMO_SET_TYPEF_TEST_ONLY)) decoder->input_format = wg_format; @@ -548,6 +551,9 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde
if (!amt_to_wg_format((const AM_MEDIA_TYPE *)type, &wg_format)) return DMO_E_TYPE_NOT_ACCEPTED; + assert(wg_format.major_type == WG_MAJOR_TYPE_VIDEO); + wg_format.u.video.fps_n = 0; + wg_format.u.video.fps_d = 0;
if (!(flags & DMO_SET_TYPEF_TEST_ONLY)) {
From: Ziqing Hui zhui@codeweavers.com
--- dlls/mf/tests/transform.c | 8 ++- dlls/winegstreamer/wg_transform.c | 4 +- dlls/winegstreamer/wmv_decoder.c | 94 ++++++++++++++++++++++++++----- 3 files changed, 87 insertions(+), 19 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 17b59c46b97..914789db84a 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -5243,8 +5243,12 @@ static void test_wmv_decoder_media_object(void) hr = CoInitialize(NULL); ok(hr == S_OK, "CoInitialize failed, hr %#lx.\n", hr);
- hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER, &IID_IMediaObject, (void **)&media_object); - ok(hr == S_OK, "CoCreateInstance returned %#lx.\n", hr); + if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER, &IID_IMediaObject, (void **)&media_object))) + { + CoUninitialize(); + winetest_pop_context(); + return; + }
/* Test GetStreamCount. */ in_count = out_count = 0xdeadbeef; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 65a34511284..ccdd90361fc 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -428,6 +428,7 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_INDEO: + case WG_MAJOR_TYPE_VIDEO_WMV: if (!(element = transform_find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, src_caps, raw_caps)) || !transform_append_element(transform, element, &first, &last)) { @@ -440,7 +441,6 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_VIDEO: break; case WG_MAJOR_TYPE_UNKNOWN: - case WG_MAJOR_TYPE_VIDEO_WMV: GST_FIXME("Format %u not implemented!", input_format.major_type); gst_caps_unref(raw_caps); goto out; @@ -469,6 +469,7 @@ NTSTATUS wg_transform_create(void *args) break;
case WG_MAJOR_TYPE_VIDEO: + case WG_MAJOR_TYPE_VIDEO_WMV: if (!(element = create_element("videoconvert", "base")) || !transform_append_element(transform, element, &first, &last)) goto out; @@ -482,7 +483,6 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_UNKNOWN: - case WG_MAJOR_TYPE_VIDEO_WMV: case WG_MAJOR_TYPE_VIDEO_INDEO: GST_FIXME("Format %u not implemented!", output_format.major_type); goto out; diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c index ed61ee0e2e3..9011d2cf182 100644 --- a/dlls/winegstreamer/wmv_decoder.c +++ b/dlls/winegstreamer/wmv_decoder.c @@ -28,6 +28,7 @@ #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(mfplat); +WINE_DECLARE_DEBUG_CHANNEL(winediag);
extern const GUID MEDIASUBTYPE_VC1S;
@@ -83,6 +84,9 @@ struct wmv_decoder struct wg_format input_format; struct wg_format output_format; GUID output_subtype; + + struct wg_transform *wg_transform; + struct wg_sample_queue *wg_sample_queue; };
static bool wg_format_is_set(struct wg_format *format) @@ -140,7 +144,12 @@ static ULONG WINAPI unknown_Release(IUnknown *iface) TRACE("iface %p decreasing refcount to %lu.\n", iface, refcount);
if (!refcount) + { + if (impl->wg_transform) + wg_transform_destroy(impl->wg_transform); + wg_sample_queue_destroy(impl->wg_sample_queue); free(impl); + }
return refcount; } @@ -489,6 +498,11 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index if (flags & DMO_SET_TYPEF_CLEAR) { memset(&decoder->input_format, 0, sizeof(decoder->input_format)); + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = NULL; + } return S_OK; } return DMO_E_TYPE_NOT_ACCEPTED; @@ -509,8 +523,15 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index wg_format.u.video_wmv.fps_n = 0; wg_format.u.video_wmv.fps_d = 0;
- if (!(flags & DMO_SET_TYPEF_TEST_ONLY)) - decoder->input_format = wg_format; + if (flags & DMO_SET_TYPEF_TEST_ONLY) + return S_OK; + + decoder->input_format = wg_format; + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = NULL; + }
return S_OK; } @@ -532,6 +553,11 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde if (flags & DMO_SET_TYPEF_CLEAR) { memset(&decoder->output_format, 0, sizeof(decoder->output_format)); + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = NULL; + } return S_OK; } return E_POINTER; @@ -555,11 +581,20 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde wg_format.u.video.fps_n = 0; wg_format.u.video.fps_d = 0;
- if (!(flags & DMO_SET_TYPEF_TEST_ONLY)) + if (flags & DMO_SET_TYPEF_TEST_ONLY) + return S_OK; + + decoder->output_subtype = type->subtype; + decoder->output_format = wg_format; + + /* Set up wg_transform. */ + if (decoder->wg_transform) { - decoder->output_subtype = type->subtype; - decoder->output_format = wg_format; + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = NULL; } + if (!(decoder->wg_transform = wg_transform_create(&decoder->input_format, &decoder->output_format))) + return E_FAIL;
return S_OK; } @@ -804,22 +839,51 @@ static const IPropertyStoreVtbl property_store_vtbl =
HRESULT wmv_decoder_create(IUnknown *outer, IUnknown **out) { - struct wmv_decoder *impl; + static const struct wg_format input_format = + { + .major_type = WG_MAJOR_TYPE_VIDEO_WMV, + .u.video_wmv.format = WG_WMV_VIDEO_FORMAT_WMV3, + }; + static const struct wg_format output_format = + { + .major_type = WG_MAJOR_TYPE_VIDEO, + .u.video = + { + .format = WG_VIDEO_FORMAT_NV12, + .width = 1920, + .height = 1080, + }, + }; + struct wg_transform *transform; + struct wmv_decoder *decoder; + HRESULT hr;
TRACE("outer %p, out %p.\n", outer, out);
- if (!(impl = calloc(1, sizeof(*impl)))) + if (!(transform = wg_transform_create(&input_format, &output_format))) + { + ERR_(winediag)("GStreamer doesn't support WMV decoding, please install appropriate plugins.\n"); + return E_FAIL; + } + wg_transform_destroy(transform); + + if (!(decoder = calloc(1, sizeof(*decoder)))) return E_OUTOFMEMORY; + if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue))) + { + free(decoder); + return hr; + }
- impl->IUnknown_inner.lpVtbl = &unknown_vtbl; - impl->IMFTransform_iface.lpVtbl = &transform_vtbl; - impl->IMediaObject_iface.lpVtbl = &media_object_vtbl; - impl->IPropertyBag_iface.lpVtbl = &property_bag_vtbl; - impl->IPropertyStore_iface.lpVtbl = &property_store_vtbl; - impl->refcount = 1; - impl->outer = outer ? outer : &impl->IUnknown_inner; + decoder->IUnknown_inner.lpVtbl = &unknown_vtbl; + decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; + decoder->IMediaObject_iface.lpVtbl = &media_object_vtbl; + decoder->IPropertyBag_iface.lpVtbl = &property_bag_vtbl; + decoder->IPropertyStore_iface.lpVtbl = &property_store_vtbl; + decoder->refcount = 1; + decoder->outer = outer ? outer : &decoder->IUnknown_inner;
- *out = &impl->IUnknown_inner; + *out = &decoder->IUnknown_inner; TRACE("Created %p\n", *out); return S_OK; }
From: Ziqing Hui zhui@codeweavers.com
--- dlls/mf/tests/transform.c | 14 +--- dlls/winegstreamer/gst_private.h | 4 + dlls/winegstreamer/wg_sample.c | 131 +++++++++++++++++++++++++++++++ dlls/winegstreamer/wmv_decoder.c | 29 +++++-- 4 files changed, 161 insertions(+), 17 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 914789db84a..602a03aabd0 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -1631,6 +1631,7 @@ static DWORD check_dmo_output_data_buffer_(int line, DMO_OUTPUT_DATA_BUFFER *out "Unexpected time stamp %I64d, expected %I64d.\n", output_data_buffer->rtTimestamp, time_stamp); if (output_data_buffer->dwStatus & DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH) + todo_wine ok_(__FILE__, line)(output_data_buffer->rtTimelength == time_length, "Unexpected time length %I64d, expected %I64d.\n", output_data_buffer->rtTimelength, time_length); @@ -5369,7 +5370,6 @@ static void test_wmv_decoder_media_object(void) ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
hr = IMediaObject_ProcessInput(media_object, 0, &input_media_buffer->IMediaBuffer_iface, 0, 0, 0); - todo_wine ok(hr == S_OK, "ProcessInput returned %#lx.\n", hr);
/* Test ProcessOutput. */ @@ -5382,16 +5382,11 @@ static void test_wmv_decoder_media_object(void) output_data_buffer.rtTimestamp = 0xdeadbeef; output_data_buffer.rtTimelength = 0xdeadbeef; hr = IMediaObject_ProcessOutput(media_object, 0, 1, &output_data_buffer, &status); - todo_wine ok(hr == S_OK, "ProcessOutput returned %#lx.\n", hr); expected_status = DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT | DMO_OUTPUT_DATA_BUFFERF_TIME | DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH; - todo_wine ok(output_data_buffer.dwStatus == expected_status, "Got unexpected dwStatus %#lx.\n", output_data_buffer.dwStatus); - if (hr == S_OK) - { diff = check_dmo_output_data_buffer(&output_data_buffer, &output_buffer_desc_nv12, L"nv12frame.bmp", 0, 0); ok(diff == 0, "Got %lu%% diff.\n", diff); - }
/* Test ProcessOutput with setting framerate. */ init_dmo_media_type_video(type, &MEDIASUBTYPE_WMV1, data_width, data_height); @@ -5404,7 +5399,6 @@ static void test_wmv_decoder_media_object(void) ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
hr = IMediaObject_ProcessInput(media_object, 0, &input_media_buffer->IMediaBuffer_iface, 0, 0, 300000); - todo_wine ok(hr == S_OK, "ProcessInput returned %#lx.\n", hr);
output_media_buffer->length = 0; @@ -5413,20 +5407,16 @@ static void test_wmv_decoder_media_object(void) output_data_buffer.rtTimestamp = 0xdeadbeef; output_data_buffer.rtTimelength = 0xdeadbeef; hr = IMediaObject_ProcessOutput(media_object, 0, 1, &output_data_buffer, &status); - todo_wine ok(hr == S_OK, "ProcessOutput returned %#lx.\n", hr); expected_status = DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT | DMO_OUTPUT_DATA_BUFFERF_TIME | DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH; - todo_wine ok(output_data_buffer.dwStatus == expected_status, "Got unexpected dwStatus %#lx.\n", output_data_buffer.dwStatus); - if (hr == S_OK) - { diff = check_dmo_output_data_buffer(&output_data_buffer, &output_buffer_desc_nv12, L"nv12frame.bmp", 0, 300000); ok(diff == 0, "Got %lu%% diff.\n", diff); - }
ret = IMediaBuffer_Release(&output_media_buffer->IMediaBuffer_iface); ok(ret == 0, "Release returned %lu\n", ret); ret = IMediaBuffer_Release(&input_media_buffer->IMediaBuffer_iface); + todo_wine ok(ret == 0, "Release returned %lu\n", ret);
ret = IMediaObject_Release(media_object); diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 5b4c01a3cd0..c59d3f1bb66 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -132,15 +132,19 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format);
HRESULT wg_sample_create_mf(IMFSample *sample, struct wg_sample **out); HRESULT wg_sample_create_quartz(IMediaSample *sample, struct wg_sample **out); +HRESULT wg_sample_create_dmo(IMediaBuffer *media_buffer, struct wg_sample **out); void wg_sample_release(struct wg_sample *wg_sample);
HRESULT wg_transform_push_mf(struct wg_transform *transform, IMFSample *sample, struct wg_sample_queue *queue); HRESULT wg_transform_push_quartz(struct wg_transform *transform, struct wg_sample *sample, struct wg_sample_queue *queue); +HRESULT wg_transform_push_dmo(struct wg_transform *transform, IMediaBuffer *media_buffer, + DWORD flags, REFERENCE_TIME time_stamp, REFERENCE_TIME time_length, struct wg_sample_queue *queue); HRESULT wg_transform_read_mf(struct wg_transform *transform, IMFSample *sample, DWORD sample_size, struct wg_format *format, DWORD *flags); HRESULT wg_transform_read_quartz(struct wg_transform *transform, struct wg_sample *sample); +HRESULT wg_transform_read_dmo(struct wg_transform *transform, DMO_OUTPUT_DATA_BUFFER *buffer);
HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj);
diff --git a/dlls/winegstreamer/wg_sample.c b/dlls/winegstreamer/wg_sample.c index eb4af86c381..d4bb7a8b954 100644 --- a/dlls/winegstreamer/wg_sample.c +++ b/dlls/winegstreamer/wg_sample.c @@ -57,6 +57,10 @@ struct sample { IMediaSample *sample; } quartz; + struct + { + IMediaBuffer *buffer; + } dmo; } u; };
@@ -165,6 +169,60 @@ HRESULT wg_sample_create_quartz(IMediaSample *media_sample, struct wg_sample **o return S_OK; }
+static const struct wg_sample_ops dmo_sample_ops; + +static inline struct sample *unsafe_dmo_from_wg_sample(struct wg_sample *wg_sample) +{ + struct sample *sample = CONTAINING_RECORD(wg_sample, struct sample, wg_sample); + if (sample->ops != &dmo_sample_ops) return NULL; + return sample; +} + +static void dmo_sample_destroy(struct wg_sample *wg_sample) +{ + struct sample *sample = unsafe_dmo_from_wg_sample(wg_sample); + + TRACE_(mfplat)("wg_sample %p.\n", wg_sample); + + IMediaBuffer_Release(sample->u.dmo.buffer); +} + +static const struct wg_sample_ops dmo_sample_ops = +{ + dmo_sample_destroy, +}; + +HRESULT wg_sample_create_dmo(IMediaBuffer *media_buffer, struct wg_sample **out) +{ + DWORD length, max_length; + struct sample *sample; + BYTE *buffer; + HRESULT hr; + + if (!(sample = calloc(1, sizeof(*sample)))) + return E_OUTOFMEMORY; + if (FAILED(hr = IMediaBuffer_GetBufferAndLength(media_buffer, &buffer, &length))) + goto fail; + if (FAILED(hr = IMediaBuffer_GetMaxLength(media_buffer, &max_length))) + goto fail; + + IMediaBuffer_AddRef((sample->u.dmo.buffer = media_buffer)); + sample->wg_sample.data = buffer; + sample->wg_sample.size = length; + sample->wg_sample.max_size = max_length; + sample->ops = &dmo_sample_ops; + + *out = &sample->wg_sample; + TRACE_(mfplat)("Created wg_sample %p for IMediaBuffer %p.\n", *out, media_buffer); + return S_OK; + +fail: + if (sample->u.dmo.buffer) + IMediaBuffer_Release(sample->u.dmo.buffer); + free(sample); + return hr; +} + void wg_sample_release(struct wg_sample *wg_sample) { struct sample *sample = CONTAINING_RECORD(wg_sample, struct sample, wg_sample); @@ -408,3 +466,76 @@ HRESULT wg_transform_read_quartz(struct wg_transform *transform, struct wg_sampl
return S_OK; } + +HRESULT wg_transform_push_dmo(struct wg_transform *transform, IMediaBuffer *media_buffer, + DWORD flags, REFERENCE_TIME time_stamp, REFERENCE_TIME time_length, struct wg_sample_queue *queue) +{ + struct wg_sample *wg_sample; + HRESULT hr; + + TRACE_(mfplat)("transform %p, media_buffer %p, flags %#lx, time_stamp %s, time_length %s, queue %p.\n", + transform, media_buffer, flags, wine_dbgstr_longlong(time_stamp), wine_dbgstr_longlong(time_length), queue); + + if (FAILED(hr = wg_sample_create_dmo(media_buffer, &wg_sample))) + return hr; + + if (flags & DMO_INPUT_DATA_BUFFERF_SYNCPOINT) + wg_sample->flags |= WG_SAMPLE_FLAG_SYNC_POINT; + if (flags & DMO_INPUT_DATA_BUFFERF_TIME) + { + wg_sample->flags |= WG_SAMPLE_FLAG_HAS_PTS; + wg_sample->pts = time_stamp; + } + if (flags & DMO_INPUT_DATA_BUFFERF_TIMELENGTH) + { + wg_sample->flags |= WG_SAMPLE_FLAG_HAS_DURATION; + wg_sample->pts = time_length; + } + + wg_sample_queue_begin_append(queue, wg_sample); + hr = wg_transform_push_data(transform, wg_sample); + wg_sample_queue_end_append(queue, wg_sample); + + return hr; +} + +HRESULT wg_transform_read_dmo(struct wg_transform *transform, DMO_OUTPUT_DATA_BUFFER *buffer) +{ + struct wg_sample *wg_sample; + HRESULT hr; + + TRACE_(mfplat)("transform %p, buffer %p.\n", transform, buffer); + + if (FAILED(hr = wg_sample_create_dmo(buffer->pBuffer, &wg_sample))) + return hr; + wg_sample->size = 0; + + if (FAILED(hr = wg_transform_read_data(transform, wg_sample, NULL))) + { + if (hr == MF_E_TRANSFORM_STREAM_CHANGE) + TRACE_(mfplat)("Stream format changed.\n"); + wg_sample_release(wg_sample); + return hr; + } + + buffer->dwStatus = 0; + if (wg_sample->flags & WG_SAMPLE_FLAG_INCOMPLETE) + buffer->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE; + if (wg_sample->flags & WG_SAMPLE_FLAG_HAS_PTS) + { + buffer->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_TIME; + buffer->rtTimestamp = wg_sample->pts; + } + if (wg_sample->flags & WG_SAMPLE_FLAG_HAS_DURATION) + { + buffer->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH; + buffer->rtTimelength = wg_sample->duration; + } + if (wg_sample->flags & WG_SAMPLE_FLAG_SYNC_POINT) + buffer->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT; + + IMediaBuffer_SetLength(buffer->pBuffer, wg_sample->size); + + wg_sample_release(wg_sample); + return hr; +} diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c index 9011d2cf182..46c85964ed7 100644 --- a/dlls/winegstreamer/wmv_decoder.c +++ b/dlls/winegstreamer/wmv_decoder.c @@ -687,16 +687,35 @@ static HRESULT WINAPI media_object_GetInputStatus(IMediaObject *iface, DWORD ind static HRESULT WINAPI media_object_ProcessInput(IMediaObject *iface, DWORD index, IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength) { - FIXME("iface %p, index %lu, buffer %p, flags %#lx, timestamp %s, timelength %s stub!\n", iface, - index, buffer, flags, wine_dbgstr_longlong(timestamp), wine_dbgstr_longlong(timelength)); - return E_NOTIMPL; + struct wmv_decoder *decoder = impl_from_IMediaObject(iface); + + TRACE("iface %p, index %lu, buffer %p, flags %#lx, timestamp %s, timelength %s.\n", iface, + index, buffer, flags, wine_dbgstr_longlong(timestamp), wine_dbgstr_longlong(timelength)); + + if (!decoder->wg_transform) + return DMO_E_TYPE_NOT_SET; + + return wg_transform_push_dmo(decoder->wg_transform, buffer, flags, timestamp, timelength, decoder->wg_sample_queue); }
static HRESULT WINAPI media_object_ProcessOutput(IMediaObject *iface, DWORD flags, DWORD count, DMO_OUTPUT_DATA_BUFFER *buffers, DWORD *status) { - FIXME("iface %p, flags %#lx, count %lu, buffers %p, status %p stub!\n", iface, flags, count, buffers, status); - return E_NOTIMPL; + struct wmv_decoder *decoder = impl_from_IMediaObject(iface); + HRESULT hr; + + TRACE("iface %p, flags %#lx, count %lu, buffers %p, status %p.\n", iface, flags, count, buffers, status); + + if (!decoder->wg_transform) + return DMO_E_TYPE_NOT_SET; + + if ((hr = wg_transform_read_dmo(decoder->wg_transform, buffers)) == MF_E_TRANSFORM_STREAM_CHANGE) + hr = wg_transform_read_dmo(decoder->wg_transform, buffers); + + if (SUCCEEDED(hr)) + wg_sample_queue_flush(decoder->wg_sample_queue, false); + + return hr; }
static HRESULT WINAPI media_object_Lock(IMediaObject *iface, LONG lock)
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=130406
Your paranoid android.
=== w864 (64 bit report) ===
mf: transform.c:3965: Test failed: h264dec: invalid h264 length transform.c:3965: Test failed: h264dec: invalid h264 buffer
=== w1064v1507 (64 bit report) ===
mf: transform.c:3965: Test failed: h264dec: invalid h264 length transform.c:3965: Test failed: h264dec: invalid h264 buffer
For patch 3/5 in v7 (63da6040 - winegstreamer: Better handle framerate):
I set fps_n and fps_d to 0 in SetInputType() and SetOutputType(), because according to PATCH 1, AvgTimePerFrame doesn't affect the output time length.
Also, I changed 3 files in this patch, do we keep all the 3 changes or only keep one of them?
Sorry for dropping this on the floor.
Do we still need the changes to quartz_parser.c or wg_format.c in patch 3/5?
Do we still need the changes to quartz_parser.c or wg_format.c in patch 3/5?
WMV decoder currently works without the changes to quartz_parser.c and wg_format.c in patch 3/5. But I think it would be better to have these changes. What do you think of it? Do we keep the changes or not? If not, I'll submit a new version later.
Do we still need the changes to quartz_parser.c or wg_format.c in patch 3/5?
WMV decoder currently works without the changes to quartz_parser.c and wg_format.c in patch 3/5. But I think it would be better to have these changes. What do you think of it? Do we keep the changes or not? If not, I'll submit a new version later.
I don't think the changes to amt_to_wg_format_video() should be committed without first understanding whether they're correct (e.g. what *should* quartz do when given a zero AvgTimePerFrame?)
And the changes to wg_format_to_caps() seem questionable largely because they're basically doing the same thing as the changes to amt_to_wg_format_video() but in a different place, but that change is correct, I prefer the way it's done in amt_to_wg_format_video(), on the grounds that the latter is more explicit.
On Wed Mar 22 17:40:43 2023 +0000, Zebediah Figura wrote:
Do we still need the changes to quartz_parser.c or wg_format.c in
patch 3/5?
WMV decoder currently works without the changes to quartz_parser.c and
wg_format.c in patch 3/5. But I think it would be better to have these changes. What do you think of it? Do we keep the changes or not? If not, I'll submit a new version later. I don't think the changes to amt_to_wg_format_video() should be committed without first understanding whether they're correct (e.g. what *should* quartz do when given a zero AvgTimePerFrame?) And the changes to wg_format_to_caps() seem questionable largely because they're basically doing the same thing as the changes to amt_to_wg_format_video() but in a different place, but that change is correct, I prefer the way it's done in amt_to_wg_format_video(), on the grounds that the latter is more explicit.
So we discard the changes to amt_to_wg_format_video() and wg_format_to_caps() for now?
So we discard the changes to amt_to_wg_format_video() and wg_format_to_caps() for now?
Without a particularly good reason to keep them, yes, I would say so.