-- v6: winegstreamer: Implement ProcessInput and ProcessOutput for WMV decoder DMO. winegstreamer: Create wg_transform for WMV decoder. winegstreamer: Make sure fps_d is not zero. winegstreamer: Add format field to wmv wg_format.
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/wg_format.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
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);
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 7d217dfe8c0..7f68f49859b 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -5248,8 +5248,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 473fabab867..4fd3c65f629 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; @@ -506,8 +520,15 @@ 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;
- 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; } @@ -529,6 +550,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; @@ -549,11 +575,20 @@ 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;
- 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; } @@ -798,22 +833,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 | 8 +- dlls/winegstreamer/gst_private.h | 4 + dlls/winegstreamer/wg_sample.c | 131 +++++++++++++++++++++++++++++++ dlls/winegstreamer/wmv_decoder.c | 33 ++++++-- 4 files changed, 165 insertions(+), 11 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 7f68f49859b..f042bcdbf21 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 %I64d, expected %I64d.\n", output_data_buffer->rtTimestamp, sample_desc->sample_time); if (output_data_buffer->dwStatus & DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH) + todo_wine 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); @@ -5374,7 +5375,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, 333333); - todo_wine ok(hr == S_OK, "ProcessInput returned %#lx.\n", hr);
/* Test ProcessOutput. */ @@ -5387,20 +5387,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_sample_desc_nv12, L"nv12frame.bmp"); 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..53036dc1c00 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, struct wg_format *format);
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..56933a32d55 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_format *format) +{ + struct wg_sample *wg_sample; + HRESULT hr; + + TRACE_(mfplat)("transform %p, buffer %p, format %p.\n", transform, buffer, format); + + 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, format))) + { + if (hr == MF_E_TRANSFORM_STREAM_CHANGE && !format) + FIXME("Unexpected stream format change!\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 4fd3c65f629..09013a3081a 100644 --- a/dlls/winegstreamer/wmv_decoder.c +++ b/dlls/winegstreamer/wmv_decoder.c @@ -681,16 +681,39 @@ 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); + struct wg_format format; + 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, &format)) == MF_E_TRANSFORM_STREAM_CHANGE) + { + decoder->output_format = format; + hr = wg_transform_read_dmo(decoder->wg_transform, buffers, NULL); + } + + 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=130359
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
Right, but will we ever pass a non-NULL format for DMO objects?
I pass a non-NULL format in the lastest version in ProcessOutput(). It record the changed format returned by gstreamer.
Right, but will we ever pass a non-NULL format for DMO objects?
I pass a non-NULL format in the lastest version in ProcessOutput(). It record the changed format returned by gstreamer.
Looking at that, I don't see what it achieves? We only pass the output format when recreating the wg_transform and in GetOutputSizeInfo(), but we don't recreate the wg_transform here, and in practice the width and height shouldn't change.
Patch 2/4 in v6 has a confusing title, since it doesn't change anything about the value of fps_d, but rather, how fps_n and fps_d are translated to framerate.
Moreover, though, I don't hate it, but it might be clearer to explicitly translate an AvgTimePerFrame of zero to fps_n = fps_d = 0.
Can we have tests for framerates other than zero?
Looking at that, I don't see what it achieves? We only pass the output format when recreating the wg_transform and in GetOutputSizeInfo(), but we don't recreate the wg_transform here, and in practice the width and height shouldn't change.
OK, so we remove the format argument in `wg_transform_read_dmo()`?
OK, so we remove the format argument in `wg_transform_read_dmo()`?
If there's no use for it, yeah. Cf. the DirectShow helper.
Can we have tests for framerates other than zero?
OK, I've added some tests.