Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/quartz_parser.c | 29 +++++++++++++++++------------ dlls/winegstreamer/wm_reader.c | 4 ++-- dlls/wmvcore/tests/wmvcore.c | 4 ++-- 4 files changed, 22 insertions(+), 17 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 109ce6ab28f..f11543d7fb2 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -101,7 +101,7 @@ HRESULT decodebin_parser_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN HRESULT mpeg_splitter_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN; HRESULT wave_parser_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
-bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format); +bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool wm); bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format);
BOOL init_gstreamer(void) DECLSPEC_HIDDEN; diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 4e7e22a64ea..77a186bbb26 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -275,7 +275,7 @@ static unsigned int get_image_size(const struct wg_format *format) return 0; }
-static bool amt_from_wg_format_video(AM_MEDIA_TYPE *mt, const struct wg_format *format) +static bool amt_from_wg_format_video(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool wm) { static const struct { @@ -322,6 +322,11 @@ static bool amt_from_wg_format_video(AM_MEDIA_TYPE *mt, const struct wg_format *
memset(video_format, 0, sizeof(*video_format));
+ if (wm) + { + SetRect(&video_format->rcSource, 0, 0, format->u.video.width, format->u.video.height); + video_format->rcTarget = video_format->rcSource; + } if ((frame_time = MulDiv(10000000, format->u.video.fps_d, format->u.video.fps_n)) != -1) video_format->AvgTimePerFrame = frame_time; video_format->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); @@ -343,7 +348,7 @@ static bool amt_from_wg_format_video(AM_MEDIA_TYPE *mt, const struct wg_format * return true; }
-bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format) +bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool wm) { memset(mt, 0, sizeof(*mt));
@@ -356,7 +361,7 @@ bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format) return amt_from_wg_format_audio(mt, format);
case WG_MAJOR_TYPE_VIDEO: - return amt_from_wg_format_video(mt, format); + return amt_from_wg_format_video(mt, format, wm); }
assert(0); @@ -1076,7 +1081,7 @@ static HRESULT decodebin_parser_source_get_media_type(struct parser_source *pin,
memset(mt, 0, sizeof(AM_MEDIA_TYPE));
- if (amt_from_wg_format(mt, &format)) + if (amt_from_wg_format(mt, &format, false)) { if (!index--) return S_OK; @@ -1086,14 +1091,14 @@ static HRESULT decodebin_parser_source_get_media_type(struct parser_source *pin, if (format.major_type == WG_MAJOR_TYPE_VIDEO && index < ARRAY_SIZE(video_formats)) { format.u.video.format = video_formats[index]; - if (!amt_from_wg_format(mt, &format)) + if (!amt_from_wg_format(mt, &format, false)) return E_OUTOFMEMORY; return S_OK; } else if (format.major_type == WG_MAJOR_TYPE_AUDIO && !index) { format.u.audio.format = WG_AUDIO_FORMAT_S16LE; - if (!amt_from_wg_format(mt, &format)) + if (!amt_from_wg_format(mt, &format, false)) return E_OUTOFMEMORY; return S_OK; } @@ -1613,7 +1618,7 @@ static HRESULT wave_parser_source_query_accept(struct parser_source *pin, const HRESULT hr;
wg_parser_stream_get_preferred_format(pin->wg_stream, &format); - if (!amt_from_wg_format(&pad_mt, &format)) + if (!amt_from_wg_format(&pad_mt, &format, false)) return E_OUTOFMEMORY; hr = compare_media_types(mt, &pad_mt) ? S_OK : S_FALSE; FreeMediaType(&pad_mt); @@ -1628,7 +1633,7 @@ static HRESULT wave_parser_source_get_media_type(struct parser_source *pin, if (index > 0) return VFW_S_NO_MORE_ITEMS; wg_parser_stream_get_preferred_format(pin->wg_stream, &format); - if (!amt_from_wg_format(mt, &format)) + if (!amt_from_wg_format(mt, &format, false)) return E_OUTOFMEMORY; return S_OK; } @@ -1699,7 +1704,7 @@ static HRESULT avi_splitter_source_query_accept(struct parser_source *pin, const HRESULT hr;
wg_parser_stream_get_preferred_format(pin->wg_stream, &format); - if (!amt_from_wg_format(&pad_mt, &format)) + if (!amt_from_wg_format(&pad_mt, &format, false)) return E_OUTOFMEMORY; hr = compare_media_types(mt, &pad_mt) ? S_OK : S_FALSE; FreeMediaType(&pad_mt); @@ -1714,7 +1719,7 @@ static HRESULT avi_splitter_source_get_media_type(struct parser_source *pin, if (index > 0) return VFW_S_NO_MORE_ITEMS; wg_parser_stream_get_preferred_format(pin->wg_stream, &format); - if (!amt_from_wg_format(mt, &format)) + if (!amt_from_wg_format(mt, &format, false)) return E_OUTOFMEMORY; return S_OK; } @@ -1783,7 +1788,7 @@ static HRESULT mpeg_splitter_source_query_accept(struct parser_source *pin, cons HRESULT hr;
wg_parser_stream_get_preferred_format(pin->wg_stream, &format); - if (!amt_from_wg_format(&pad_mt, &format)) + if (!amt_from_wg_format(&pad_mt, &format, false)) return E_OUTOFMEMORY; hr = compare_media_types(mt, &pad_mt) ? S_OK : S_FALSE; FreeMediaType(&pad_mt); @@ -1798,7 +1803,7 @@ static HRESULT mpeg_splitter_source_get_media_type(struct parser_source *pin, if (index > 0) return VFW_S_NO_MORE_ITEMS; wg_parser_stream_get_preferred_format(pin->wg_stream, &format); - if (!amt_from_wg_format(mt, &format)) + if (!amt_from_wg_format(mt, &format, false)) return E_OUTOFMEMORY; return S_OK; } diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 82f74318062..1d46db3fb0d 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -157,7 +157,7 @@ static IWMOutputMediaProps *output_props_create(const struct wg_format *format) object->IWMOutputMediaProps_iface.lpVtbl = &output_props_vtbl; object->refcount = 1;
- if (!amt_from_wg_format(&object->mt, format)) + if (!amt_from_wg_format(&object->mt, format, true)) { free(object); return NULL; @@ -338,7 +338,7 @@ static HRESULT WINAPI stream_config_GetStreamType(IWMStreamConfig *iface, GUID *
EnterCriticalSection(&reader->cs);
- if (!amt_from_wg_format(&mt, &config->stream->format)) + if (!amt_from_wg_format(&mt, &config->stream->format, true)) { LeaveCriticalSection(&reader->cs); return E_OUTOFMEMORY; diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 6e196234208..469666161a4 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -629,8 +629,8 @@ static void check_video_type(const WM_MEDIA_TYPE *mt) todo_wine ok(!mt->bTemporalCompression, "Got temporal compression %d.\n", mt->bTemporalCompression); ok(!mt->pUnk, "Got pUnk %p.\n", mt->pUnk);
- todo_wine ok(EqualRect(&video_info->rcSource, &rect), "Got source rect %s.\n", wine_dbgstr_rect(&rect)); - todo_wine ok(EqualRect(&video_info->rcTarget, &rect), "Got target rect %s.\n", wine_dbgstr_rect(&rect)); + ok(EqualRect(&video_info->rcSource, &rect), "Got source rect %s.\n", wine_dbgstr_rect(&rect)); + ok(EqualRect(&video_info->rcTarget, &rect), "Got target rect %s.\n", wine_dbgstr_rect(&rect)); ok(!video_info->dwBitRate, "Got bit rate %u.\n", video_info->dwBitRate); ok(!video_info->dwBitErrorRate, "Got bit error rate %u.\n", video_info->dwBitErrorRate); ok(video_info->bmiHeader.biSize == sizeof(video_info->bmiHeader),
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/quartz_parser.c | 2 ++ dlls/wmvcore/tests/wmvcore.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 77a186bbb26..4cc4795a5ff 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -314,6 +314,8 @@ static bool amt_from_wg_format_video(AM_MEDIA_TYPE *mt, const struct wg_format *
mt->majortype = MEDIATYPE_Video; mt->subtype = *format_table[format->u.video.format].subtype; + if (wm) + mt->bFixedSizeSamples = TRUE; mt->bTemporalCompression = TRUE; mt->lSampleSize = 1; mt->formattype = FORMAT_VideoInfo; diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 469666161a4..fa730c978e3 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -625,7 +625,7 @@ static void check_video_type(const WM_MEDIA_TYPE *mt) static const RECT rect = {.right = 64, .bottom = 48};
ok(IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo), "Got format %s.\n", debugstr_guid(&mt->formattype)); - todo_wine ok(mt->bFixedSizeSamples == TRUE, "Got fixed size %d.\n", mt->bFixedSizeSamples); + ok(mt->bFixedSizeSamples == TRUE, "Got fixed size %d.\n", mt->bFixedSizeSamples); todo_wine ok(!mt->bTemporalCompression, "Got temporal compression %d.\n", mt->bTemporalCompression); ok(!mt->pUnk, "Got pUnk %p.\n", mt->pUnk);
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/quartz_parser.c | 3 ++- dlls/wmvcore/tests/wmvcore.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 4cc4795a5ff..e0f82878cea 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -316,7 +316,8 @@ static bool amt_from_wg_format_video(AM_MEDIA_TYPE *mt, const struct wg_format * mt->subtype = *format_table[format->u.video.format].subtype; if (wm) mt->bFixedSizeSamples = TRUE; - mt->bTemporalCompression = TRUE; + else + mt->bTemporalCompression = TRUE; mt->lSampleSize = 1; mt->formattype = FORMAT_VideoInfo; mt->cbFormat = sizeof(VIDEOINFOHEADER); diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index fa730c978e3..bc7d044b39b 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -626,7 +626,7 @@ static void check_video_type(const WM_MEDIA_TYPE *mt)
ok(IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo), "Got format %s.\n", debugstr_guid(&mt->formattype)); ok(mt->bFixedSizeSamples == TRUE, "Got fixed size %d.\n", mt->bFixedSizeSamples); - todo_wine ok(!mt->bTemporalCompression, "Got temporal compression %d.\n", mt->bTemporalCompression); + ok(!mt->bTemporalCompression, "Got temporal compression %d.\n", mt->bTemporalCompression); ok(!mt->pUnk, "Got pUnk %p.\n", mt->pUnk);
ok(EqualRect(&video_info->rcSource, &rect), "Got source rect %s.\n", wine_dbgstr_rect(&rect));
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/wm_syncreader.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/dlls/winegstreamer/wm_syncreader.c b/dlls/winegstreamer/wm_syncreader.c index 1f5827cf244..2c65f652cdb 100644 --- a/dlls/winegstreamer/wm_syncreader.c +++ b/dlls/winegstreamer/wm_syncreader.c @@ -249,12 +249,24 @@ static HRESULT WINAPI WMSyncReader_SetOutputProps(IWMSyncReader2 *iface, DWORD o return wm_reader_set_output_props(&reader->reader, output, props); }
-static HRESULT WINAPI WMSyncReader_SetOutputSetting(IWMSyncReader2 *iface, DWORD output_num, const WCHAR *name, - WMT_ATTR_DATATYPE type, const BYTE *value, WORD length) +static HRESULT WINAPI WMSyncReader_SetOutputSetting(IWMSyncReader2 *iface, DWORD output, + const WCHAR *name, WMT_ATTR_DATATYPE type, const BYTE *value, WORD size) { - struct sync_reader *This = impl_from_IWMSyncReader2(iface); - FIXME("(%p)->(%d %s %d %p %d): stub!\n", This, output_num, debugstr_w(name), type, value, length); - return E_NOTIMPL; + struct sync_reader *reader = impl_from_IWMSyncReader2(iface); + + TRACE("reader %p, output %u, name %s, type %#x, value %p, size %u.\n", + reader, output, debugstr_w(name), type, value, size); + + if (!wcscmp(name, L"VideoSampleDurations")) + { + FIXME("Ignoring VideoSampleDurations setting.\n"); + return S_OK; + } + else + { + FIXME("Unknown setting %s; returning E_NOTIMPL.\n", debugstr_w(name)); + return E_NOTIMPL; + } }
static HRESULT WINAPI WMSyncReader_SetRange(IWMSyncReader2 *iface, QWORD start, LONGLONG duration)
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/wm_reader.c | 44 ++++++++++- dlls/wmvcore/tests/wmvcore.c | 131 +++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+), 3 deletions(-)
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 1d46db3fb0d..80393d4e7a1 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -874,9 +874,47 @@ static HRESULT WINAPI header_info_GetAttributeByIndex(IWMHeaderInfo3 *iface, WOR static HRESULT WINAPI header_info_GetAttributeByName(IWMHeaderInfo3 *iface, WORD *stream_number, const WCHAR *name, WMT_ATTR_DATATYPE *type, BYTE *value, WORD *size) { - FIXME("iface %p, stream_number %p, name %s, type %p, value %p, size %p, stub!\n", - iface, stream_number, debugstr_w(name), type, value, size); - return E_NOTIMPL; + struct wm_reader *reader = impl_from_IWMHeaderInfo3(iface); + const WORD req_size = *size; + + TRACE("reader %p, stream_number %p, name %s, type %p, value %p, size %u.\n", + reader, stream_number, debugstr_w(name), type, value, *size); + + if (!stream_number) + return E_INVALIDARG; + + if (!wcscmp(name, L"Duration")) + { + QWORD duration; + + if (*stream_number) + { + WARN("Requesting duration for stream %u, returning ASF_E_NOTFOUND.\n", *stream_number); + return ASF_E_NOTFOUND; + } + + *size = sizeof(QWORD); + if (!value) + { + *type = WMT_TYPE_QWORD; + return S_OK; + } + if (req_size < *size) + return ASF_E_BUFFERTOOSMALL; + + *type = WMT_TYPE_QWORD; + EnterCriticalSection(&reader->cs); + duration = wg_parser_stream_get_duration(wg_parser_get_stream(reader->wg_parser, 0)); + LeaveCriticalSection(&reader->cs); + TRACE("Returning duration %s.\n", debugstr_time(duration)); + memcpy(value, &duration, sizeof(QWORD)); + return S_OK; + } + else + { + FIXME("Unknown attribute %s.\n", debugstr_w(name)); + return ASF_E_NOTFOUND; + } }
static HRESULT WINAPI header_info_SetAttribute(IWMHeaderInfo3 *iface, WORD stream_number, diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index bc7d044b39b..6d510553fef 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -420,6 +420,135 @@ static const IStreamVtbl stream_vtbl = stream_Clone, };
+static void test_reader_attributes(IWMProfile *profile) +{ + WORD size, stream_number, ret_stream_number; + IWMHeaderInfo *header_info; + IWMStreamConfig *config; + WMT_ATTR_DATATYPE type; + ULONG count, i; + QWORD duration; + DWORD dword; + HRESULT hr; + + IWMProfile_QueryInterface(profile, &IID_IWMHeaderInfo, (void **)&header_info); + + hr = IWMProfile_GetStreamCount(profile, &count); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(count == 2, "Got count %u.\n", count); + + for (i = 0; i < count; ++i) + { + hr = IWMProfile_GetStream(profile, i, &config); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IWMStreamConfig_GetStreamNumber(config, &stream_number); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ret_stream_number = stream_number; + + size = sizeof(DWORD); + type = 0xdeadbeef; + dword = 0xdeadbeef; + hr = IWMHeaderInfo_GetAttributeByName(header_info, &ret_stream_number, + L"WM/VideoFrameRate", &type, (BYTE *)&dword, &size); + ok(hr == ASF_E_NOTFOUND, "Got hr %#x.\n", hr); + ok(type == 0xdeadbeef, "Got type %#x.\n", type); + ok(size == sizeof(DWORD), "Got size %u.\n", size); + ok(dword == 0xdeadbeef, "Got frame rate %u.\n", dword); + ok(ret_stream_number == stream_number, "Expected stream number %u, got %u.\n", + stream_number, ret_stream_number); + + size = sizeof(QWORD); + type = 0xdeadbeef; + duration = 0xdeadbeef; + hr = IWMHeaderInfo_GetAttributeByName(header_info, &ret_stream_number, + L"Duration", &type, (BYTE *)&duration, &size); + ok(hr == ASF_E_NOTFOUND, "Got hr %#x.\n", hr); + ok(type == 0xdeadbeef, "Got type %#x.\n", type); + ok(size == sizeof(QWORD), "Got size %u.\n", size); + ok(ret_stream_number == stream_number, "Expected stream number %u, got %u.\n", + stream_number, ret_stream_number); + + IWMStreamConfig_Release(config); + } + + /* WM/VideoFrameRate with a NULL stream number. */ + + size = sizeof(DWORD); + type = 0xdeadbeef; + dword = 0xdeadbeef; + hr = IWMHeaderInfo_GetAttributeByName(header_info, NULL, + L"WM/VideoFrameRate", &type, (BYTE *)&dword, &size); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(type == 0xdeadbeef, "Got type %#x.\n", type); + ok(size == sizeof(DWORD), "Got size %u.\n", size); + ok(dword == 0xdeadbeef, "Got frame rate %u.\n", dword); + + /* And with a zero stream number. */ + + stream_number = 0; + size = sizeof(DWORD); + type = 0xdeadbeef; + dword = 0xdeadbeef; + hr = IWMHeaderInfo_GetAttributeByName(header_info, &stream_number, + L"WM/VideoFrameRate", &type, (BYTE *)&dword, &size); + ok(hr == ASF_E_NOTFOUND, "Got hr %#x.\n", hr); + ok(type == 0xdeadbeef, "Got type %#x.\n", type); + ok(size == sizeof(DWORD), "Got size %u.\n", size); + ok(dword == 0xdeadbeef, "Got frame rate %u.\n", dword); + ok(stream_number == 0, "Got stream number %u.\n", stream_number); + + /* Duration with a NULL stream number. */ + + size = sizeof(QWORD); + type = 0xdeadbeef; + duration = 0xdeadbeef; + hr = IWMHeaderInfo_GetAttributeByName(header_info, NULL, + L"Duration", &type, (BYTE *)&duration, &size); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(type == 0xdeadbeef, "Got type %#x.\n", type); + ok(size == sizeof(QWORD), "Got size %u.\n", size); + ok(duration == 0xdeadbeef, "Got duration %I64u.\n", duration); + + /* And with a zero stream number. */ + + size = sizeof(QWORD); + type = 0xdeadbeef; + duration = 0xdeadbeef; + hr = IWMHeaderInfo_GetAttributeByName(header_info, &stream_number, + L"Duration", &type, (BYTE *)&duration, &size); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(type == WMT_TYPE_QWORD, "Got type %#x.\n", type); + ok(size == sizeof(QWORD), "Got size %u.\n", size); + ok(duration == 20460000, "Got duration %I64u.\n", duration); + ok(stream_number == 0, "Got stream number %u.\n", stream_number); + + /* Pass a too-small size. */ + + size = sizeof(QWORD) - 1; + type = 0xdeadbeef; + duration = 0xdeadbeef; + hr = IWMHeaderInfo_GetAttributeByName(header_info, &stream_number, + L"Duration", &type, (BYTE *)&duration, &size); + ok(hr == ASF_E_BUFFERTOOSMALL, "Got hr %#x.\n", hr); + ok(type == 0xdeadbeef, "Got type %#x.\n", type); + ok(size == sizeof(QWORD), "Got size %u.\n", size); + ok(duration == 0xdeadbeef, "Got duration %I64u.\n", duration); + ok(stream_number == 0, "Got stream number %u.\n", stream_number); + + /* Pass a NULL buffer. */ + + size = 0xdead; + type = 0xdeadbeef; + hr = IWMHeaderInfo_GetAttributeByName(header_info, &stream_number, + L"Duration", &type, NULL, &size); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(type == WMT_TYPE_QWORD, "Got type %#x.\n", type); + ok(size == sizeof(QWORD), "Got size %u.\n", size); + ok(stream_number == 0, "Got stream number %u.\n", stream_number); + + IWMHeaderInfo_Release(header_info); +} + static void test_sync_reader_streaming(void) { DWORD size, flags, output_number, expect_output_number; @@ -596,6 +725,8 @@ static void test_sync_reader_streaming(void) &pts, &duration, &flags, NULL, NULL); ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
+ test_reader_attributes(profile); + hr = IWMSyncReader_Close(reader); ok(hr == S_OK, "Got hr %#x.\n", hr);
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/wm_reader.c | 21 +++++++++++++++++++++ dlls/wmvcore/tests/wmvcore.c | 22 ++++++++++++++++++++++ 2 files changed, 43 insertions(+)
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 80393d4e7a1..bd7fcd06bd3 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -910,6 +910,27 @@ static HRESULT WINAPI header_info_GetAttributeByName(IWMHeaderInfo3 *iface, WORD memcpy(value, &duration, sizeof(QWORD)); return S_OK; } + else if (!wcscmp(name, L"Seekable")) + { + if (*stream_number) + { + WARN("Requesting duration for stream %u, returning ASF_E_NOTFOUND.\n", *stream_number); + return ASF_E_NOTFOUND; + } + + *size = sizeof(BOOL); + if (!value) + { + *type = WMT_TYPE_BOOL; + return S_OK; + } + if (req_size < *size) + return ASF_E_BUFFERTOOSMALL; + + *type = WMT_TYPE_BOOL; + *(BOOL *)value = TRUE; + return S_OK; + } else { FIXME("Unknown attribute %s.\n", debugstr_w(name)); diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 6d510553fef..92208c0b8a3 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -468,6 +468,17 @@ static void test_reader_attributes(IWMProfile *profile) ok(ret_stream_number == stream_number, "Expected stream number %u, got %u.\n", stream_number, ret_stream_number);
+ size = sizeof(DWORD); + type = 0xdeadbeef; + dword = 0xdeadbeef; + hr = IWMHeaderInfo_GetAttributeByName(header_info, &ret_stream_number, + L"Seekable", &type, (BYTE *)&dword, &size); + ok(hr == ASF_E_NOTFOUND, "Got hr %#x.\n", hr); + ok(type == 0xdeadbeef, "Got type %#x.\n", type); + ok(size == sizeof(DWORD), "Got size %u.\n", size); + ok(ret_stream_number == stream_number, "Expected stream number %u, got %u.\n", + stream_number, ret_stream_number); + IWMStreamConfig_Release(config); }
@@ -546,6 +557,17 @@ static void test_reader_attributes(IWMProfile *profile) ok(size == sizeof(QWORD), "Got size %u.\n", size); ok(stream_number == 0, "Got stream number %u.\n", stream_number);
+ size = sizeof(DWORD); + type = 0xdeadbeef; + dword = 0xdeadbeef; + hr = IWMHeaderInfo_GetAttributeByName(header_info, &stream_number, + L"Seekable", &type, (BYTE *)&dword, &size); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(type == WMT_TYPE_BOOL, "Got type %#x.\n", type); + ok(size == sizeof(DWORD), "Got size %u.\n", size); + ok(dword == TRUE, "Got duration %I64u.\n", duration); + ok(stream_number == 0, "Got stream number %u.\n", stream_number); + IWMHeaderInfo_Release(header_info); }
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/gst_private.h | 2 + dlls/winegstreamer/wm_reader.c | 132 +++++++++++++++++++++++------ dlls/winegstreamer/wm_syncreader.c | 8 +- dlls/wmvcore/tests/wmvcore.c | 40 +++++++++ 4 files changed, 151 insertions(+), 31 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index f11543d7fb2..9674ee35052 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -139,6 +139,7 @@ struct wm_reader QWORD start_time;
IStream *source_stream; + HANDLE file; HANDLE read_thread; bool read_thread_shutdown; struct wg_parser *wg_parser; @@ -167,6 +168,7 @@ struct wm_stream *wm_reader_get_stream_by_stream_number(struct wm_reader *reader HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, INSSBuffer **sample, QWORD *pts, QWORD *duration, DWORD *flags); void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops); +HRESULT wm_reader_open_file(struct wm_reader *reader, const WCHAR *filename); HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream); void wm_reader_seek(struct wm_reader *reader, QWORD start, LONGLONG duration); HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output, diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index bd7fcd06bd3..2f5659608a9 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -438,22 +438,34 @@ static DWORD CALLBACK read_thread(void *arg) { struct wm_reader *reader = arg; IStream *stream = reader->source_stream; + HANDLE file = reader->file; size_t buffer_size = 4096; uint64_t file_size; - STATSTG stat; void *data;
if (!(data = malloc(buffer_size))) return 0;
- IStream_Stat(stream, &stat, STATFLAG_NONAME); - file_size = stat.cbSize.QuadPart; + if (file) + { + LARGE_INTEGER size; + + GetFileSizeEx(file, &size); + file_size = size.QuadPart; + } + else + { + STATSTG stat; + + IStream_Stat(stream, &stat, STATFLAG_NONAME); + file_size = stat.cbSize.QuadPart; + }
TRACE("Starting read thread for reader %p.\n", reader);
while (!reader->read_thread_shutdown) { - LARGE_INTEGER stream_offset; + LARGE_INTEGER large_offset; uint64_t offset; ULONG ret_size; uint32_t size; @@ -481,14 +493,32 @@ static DWORD CALLBACK read_thread(void *arg)
ret_size = 0;
- stream_offset.QuadPart = offset; - if (SUCCEEDED(hr = IStream_Seek(stream, stream_offset, STREAM_SEEK_SET, NULL))) - hr = IStream_Read(stream, data, size, &ret_size); - if (FAILED(hr)) - ERR("Failed to read %u bytes at offset %I64u, hr %#x.\n", size, offset, hr); - else if (ret_size != size) + large_offset.QuadPart = offset; + if (file) + { + if (!SetFilePointerEx(file, large_offset, NULL, FILE_BEGIN) + || !ReadFile(file, data, size, &ret_size, NULL)) + { + ERR("Failed to read %u bytes at offset %I64u, error %u.\n", size, offset, GetLastError()); + wg_parser_push_data(reader->wg_parser, NULL, 0); + continue; + } + } + else + { + if (SUCCEEDED(hr = IStream_Seek(stream, large_offset, STREAM_SEEK_SET, NULL))) + hr = IStream_Read(stream, data, size, &ret_size); + if (FAILED(hr)) + { + ERR("Failed to read %u bytes at offset %I64u, hr %#x.\n", size, offset, hr); + wg_parser_push_data(reader->wg_parser, NULL, 0); + continue; + } + } + + if (ret_size != size) ERR("Unexpected short read: requested %u bytes, got %u.\n", size, ret_size); - wg_parser_push_data(reader->wg_parser, SUCCEEDED(hr) ? data : NULL, ret_size); + wg_parser_push_data(reader->wg_parser, data, ret_size); }
free(data); @@ -1326,26 +1356,16 @@ static const IWMReaderTimecodeVtbl timecode_vtbl = timecode_GetTimecodeRangeBounds, };
-HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream) +static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) { struct wg_parser *wg_parser; - STATSTG stat; HRESULT hr; WORD i;
- if (FAILED(hr = IStream_Stat(stream, &stat, STATFLAG_NONAME))) - { - ERR("Failed to stat stream, hr %#x.\n", hr); - return hr; - } - if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, false))) return E_OUTOFMEMORY;
- EnterCriticalSection(&reader->cs); - reader->wg_parser = wg_parser; - IStream_AddRef(reader->source_stream = stream); reader->read_thread_shutdown = false; if (!(reader->read_thread = CreateThread(NULL, 0, read_thread, reader, 0, NULL))) { @@ -1353,7 +1373,7 @@ HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream) goto out_destroy_parser; }
- if (FAILED(hr = wg_parser_connect(reader->wg_parser, stat.cbSize.QuadPart))) + if (FAILED(hr = wg_parser_connect(reader->wg_parser, file_size))) { ERR("Failed to connect parser, hr %#x.\n", hr); goto out_shutdown_thread; @@ -1402,7 +1422,6 @@ HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream) wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, 0, 0, AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
- LeaveCriticalSection(&reader->cs); return S_OK;
out_disconnect_parser: @@ -1417,8 +1436,60 @@ out_shutdown_thread: out_destroy_parser: wg_parser_destroy(reader->wg_parser); reader->wg_parser = NULL; - IStream_Release(reader->source_stream); - reader->source_stream = NULL; + + return hr; +} + +HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream) +{ + STATSTG stat; + HRESULT hr; + + if (FAILED(hr = IStream_Stat(stream, &stat, STATFLAG_NONAME))) + { + ERR("Failed to stat stream, hr %#x.\n", hr); + return hr; + } + + EnterCriticalSection(&reader->cs); + + IStream_AddRef(reader->source_stream = stream); + if (FAILED(hr = init_stream(reader, stat.cbSize.QuadPart))) + { + IStream_Release(stream); + reader->source_stream = NULL; + } + + LeaveCriticalSection(&reader->cs); + return hr; +} + +HRESULT wm_reader_open_file(struct wm_reader *reader, const WCHAR *filename) +{ + LARGE_INTEGER size; + HANDLE file; + HRESULT hr; + + if ((file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) + { + ERR("Failed to open %s, error %u.\n", debugstr_w(filename), GetLastError()); + return HRESULT_FROM_WIN32(GetLastError()); + } + + if (!GetFileSizeEx(file, &size)) + { + ERR("Failed to get the size of %s, error %u.\n", debugstr_w(filename), GetLastError()); + CloseHandle(file); + return HRESULT_FROM_WIN32(GetLastError()); + } + + EnterCriticalSection(&reader->cs); + + reader->file = file; + + if (FAILED(hr = init_stream(reader, size.QuadPart))) + reader->file = NULL;
LeaveCriticalSection(&reader->cs); return hr; @@ -1428,7 +1499,7 @@ HRESULT wm_reader_close(struct wm_reader *reader) { EnterCriticalSection(&reader->cs);
- if (!reader->source_stream) + if (!reader->wg_parser) { LeaveCriticalSection(&reader->cs); return NS_E_INVALID_REQUEST; @@ -1443,8 +1514,13 @@ HRESULT wm_reader_close(struct wm_reader *reader)
wg_parser_destroy(reader->wg_parser); reader->wg_parser = NULL; - IStream_Release(reader->source_stream); + + if (reader->source_stream) + IStream_Release(reader->source_stream); reader->source_stream = NULL; + if (reader->file) + CloseHandle(reader->file); + reader->file = NULL;
LeaveCriticalSection(&reader->cs); return S_OK; diff --git a/dlls/winegstreamer/wm_syncreader.c b/dlls/winegstreamer/wm_syncreader.c index 2c65f652cdb..fff048df06e 100644 --- a/dlls/winegstreamer/wm_syncreader.c +++ b/dlls/winegstreamer/wm_syncreader.c @@ -226,9 +226,11 @@ static HRESULT WINAPI WMSyncReader_GetStreamSelected(IWMSyncReader2 *iface, WORD
static HRESULT WINAPI WMSyncReader_Open(IWMSyncReader2 *iface, const WCHAR *filename) { - struct sync_reader *This = impl_from_IWMSyncReader2(iface); - FIXME("(%p)->(%s): stub!\n", This, debugstr_w(filename)); - return E_NOTIMPL; + struct sync_reader *reader = impl_from_IWMSyncReader2(iface); + + TRACE("reader %p, filename %s.\n", reader, debugstr_w(filename)); + + return wm_reader_open_file(&reader->reader, filename); }
static HRESULT WINAPI WMSyncReader_OpenStream(IWMSyncReader2 *iface, IStream *stream) diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 92208c0b8a3..eae320c4d2e 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -1012,6 +1012,45 @@ static void test_sync_reader_types(void) ok(ret, "Failed to delete %s, error %u.\n", debugstr_w(filename), GetLastError()); }
+static void test_sync_reader_file(void) +{ + const WCHAR *filename = load_resource(L"test.wmv"); + IWMSyncReader *reader; + IWMProfile *profile; + DWORD count; + HRESULT hr; + ULONG ref; + BOOL ret; + + hr = WMCreateSyncReader(NULL, 0, &reader); + ok(hr == S_OK, "Got hr %#x.\n", hr); + IWMSyncReader_QueryInterface(reader, &IID_IWMProfile, (void **)&profile); + + hr = IWMSyncReader_Open(reader, filename); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + count = 0xdeadbeef; + hr = IWMSyncReader_GetOutputCount(reader, &count); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(count == 2, "Got count %u.\n", count); + + hr = IWMSyncReader_Close(reader); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IWMSyncReader_Close(reader); + ok(hr == NS_E_INVALID_REQUEST, "Got hr %#x.\n", hr); + + hr = IWMSyncReader_Open(reader, filename); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + IWMProfile_Release(profile); + ref = IWMSyncReader_Release(reader); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + ret = DeleteFileW(filename); + ok(ret, "Failed to delete %s, error %u.\n", debugstr_w(filename), GetLastError()); +} + START_TEST(wmvcore) { HRESULT hr; @@ -1030,6 +1069,7 @@ START_TEST(wmvcore) test_iscontentprotected(); test_sync_reader_streaming(); test_sync_reader_types(); + test_sync_reader_file();
CoUninitialize(); }