-- v4: winegstreamer: Implement ProcessInput and ProcessOutput for WMV decoder DMO. winegstreamer: Create wg_transform for WMV decoder.
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
Framerate is fps_n / fps_d. So fps_d should not be zero. --- dlls/winegstreamer/wg_format.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index ac21b0af94f..771817c6df1 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -422,6 +422,16 @@ static GstCaps *wg_format_to_caps_video(const struct wg_format *format) return NULL;
gst_video_info_set_format(&info, video_format, format->u.video.width, abs(format->u.video.height)); + if (format->u.video.fps_d) + { + GST_VIDEO_INFO_FPS_N(&info) = format->u.video.fps_n; + GST_VIDEO_INFO_FPS_D(&info) = format->u.video.fps_d; + } + else + { + GST_VIDEO_INFO_FPS_N(&info) = 0; + GST_VIDEO_INFO_FPS_D(&info) = 1; + } if ((caps = gst_video_info_to_caps(&info))) { for (i = 0; i < gst_caps_get_size(caps); ++i) @@ -448,8 +458,10 @@ 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); + else + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, 0, 1, NULL);
return caps; } @@ -505,8 +517,10 @@ 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); + else + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, 0, 1, NULL);
switch (format->u.video_h264.profile) { @@ -602,8 +616,10 @@ 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); + else + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, 0, 1, NULL);
return caps; } @@ -619,8 +635,10 @@ 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); + else + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, 0, 1, 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/winegstreamer/wg_transform.c | 4 +- dlls/winegstreamer/wmv_decoder.c | 94 ++++++++++++++++++++++++++----- 2 files changed, 81 insertions(+), 17 deletions(-)
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 | 6 +- dlls/winegstreamer/gst_private.h | 4 + dlls/winegstreamer/wg_sample.c | 131 +++++++++++++++++++++++++++++++ dlls/winegstreamer/wmv_decoder.c | 26 ++++-- 4 files changed, 157 insertions(+), 10 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 7d217dfe8c0..bb92db57321 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -5370,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, 333333); - todo_wine ok(hr == S_OK, "ProcessInput returned %#lx.\n", hr);
/* Test ProcessOutput. */ @@ -5383,20 +5382,17 @@ 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..6ccea9aef80 100644 --- a/dlls/winegstreamer/wmv_decoder.c +++ b/dlls/winegstreamer/wmv_decoder.c @@ -681,16 +681,32 @@ 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 (SUCCEEDED(hr = wg_transform_read_dmo(decoder->wg_transform, buffers, NULL))) + wg_sample_queue_flush(decoder->wg_sample_queue, false); + + return hr; }
static HRESULT WINAPI media_object_Lock(IMediaObject *iface, LONG lock)
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/wmv_decoder.c:
.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);
You also need to support the creation failure in the test `CoCreateInstance` call.