-- v8: winegstreamer: Implement ProcessInput and ProcessOutput for WMV decoder DMO. winegstreamer: Create wg_transform for WMV decoder. winegstreamer: Ignore framerate of media type for WMV decoder DMO. 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/wmv_decoder.c | 6 ++++++ 1 file changed, 6 insertions(+)
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)
This merge request was approved by Zebediah Figura.