Along with !4450, this fixes WMV videos in microkiri (https://bugs.winehq.org/show_bug.cgi?id=9127#c102) and Wagamama High Spec Trial Edition (https://wagahigh.com/download_trial.php#normal ; ダウンロード means download).
-- v4: wmvcore/tests: Add tests for compressed output. winegstreamer: Implement compressed output support in WMSyncReader. winegstreamer: Introduce mutex for wm_reader read_thread_shutdown and wg_parser.
From: Alfred Agrell floating@muncher.se
Same as the commit in !4450. Will disappear on next rebase after that one's merged. --- dlls/winegstreamer/wg_format.c | 68 ++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+)
diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 7d4bc7a5f8c..274a6dec261 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -201,6 +201,70 @@ static void wg_format_from_caps_audio_mpeg1(struct wg_format *format, const GstC format->u.audio_mpeg1.rate = rate; }
+static void wg_format_from_caps_audio_wma(struct wg_format *format, const GstCaps *caps) +{ + const GstStructure *structure = gst_caps_get_structure(caps, 0); + gint version, bitrate, rate, depth, channels, block_align; + const GValue *codec_data_value; + GstBuffer *codec_data; + GstMapInfo map; + + if (!gst_structure_get_int(structure, "wmaversion", &version)) + { + GST_WARNING("Missing "wmaversion" value in %" GST_PTR_FORMAT ".", caps); + return; + } + if (!gst_structure_get_int(structure, "bitrate", &bitrate)) + { + GST_WARNING("Missing "bitrate" value in %" GST_PTR_FORMAT ".", caps); + return; + } + if (!gst_structure_get_int(structure, "rate", &rate)) + { + GST_WARNING("Missing "rate" value in %" GST_PTR_FORMAT ".", caps); + return; + } + if (!gst_structure_get_int(structure, "depth", &depth)) + { + GST_WARNING("Missing "depth" value in %" GST_PTR_FORMAT ".", caps); + return; + } + if (!gst_structure_get_int(structure, "channels", &channels)) + { + GST_WARNING("Missing "channels" value in %" GST_PTR_FORMAT ".", caps); + return; + } + if (!gst_structure_get_int(structure, "block_align", &block_align)) + { + GST_WARNING("Missing "block_align" value in %" GST_PTR_FORMAT ".", caps); + return; + } + if (!(codec_data_value = gst_structure_get_value(structure, "codec_data")) + || !(codec_data = gst_value_get_buffer(codec_data_value))) + { + GST_WARNING("Missing "codec_data" value in %" GST_PTR_FORMAT ".", caps); + return; + } + + format->major_type = WG_MAJOR_TYPE_AUDIO_WMA; + format->u.audio_wma.version = version; + format->u.audio_wma.bitrate = bitrate; + format->u.audio_wma.rate = rate; + format->u.audio_wma.depth = depth; + format->u.audio_wma.channels = channels; + format->u.audio_wma.block_align = block_align; + + gst_buffer_map(codec_data, &map, GST_MAP_READ); + if (map.size <= sizeof(format->u.audio_wma.codec_data)) + { + format->u.audio_wma.codec_data_len = map.size; + memcpy(format->u.audio_wma.codec_data, map.data, map.size); + } + else + GST_WARNING("Too big codec_data value (%u) in %" GST_PTR_FORMAT ".", (UINT)map.size, caps); + gst_buffer_unmap(codec_data, &map); +} + static void wg_format_from_caps_video_cinepak(struct wg_format *format, const GstCaps *caps) { const GstStructure *structure = gst_caps_get_structure(caps, 0); @@ -336,6 +400,10 @@ void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) { wg_format_from_caps_audio_mpeg1(format, caps); } + else if (!strcmp(name, "audio/x-wma")) + { + wg_format_from_caps_audio_wma(format, caps); + } else if (!strcmp(name, "video/x-cinepak")) { wg_format_from_caps_video_cinepak(format, caps);
From: Alfred Agrell floating@muncher.se
Same as the commit in !4450. Will disappear on next rebase after that one's merged. --- dlls/winegstreamer/quartz_parser.c | 127 ++++++++++++++++++++++++++++- dlls/wmvcore/tests/wmvcore.c | 11 ++- 2 files changed, 130 insertions(+), 8 deletions(-)
diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 0670fbd5181..596f7a5011a 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -278,6 +278,68 @@ static bool amt_from_wg_format_audio_mpeg1(AM_MEDIA_TYPE *mt, const struct wg_fo return false; }
+static bool amt_from_wg_format_audio_wma(AM_MEDIA_TYPE *mt, const struct wg_format *format) +{ + DWORD codec_data_len, size; + WAVEFORMATEX *wave_format; + const GUID *subtype; + WORD fmt_tag; + + mt->majortype = MEDIATYPE_Audio; + mt->formattype = FORMAT_WaveFormatEx; + + switch (format->u.audio_wma.version) + { + case 1: + subtype = &MEDIASUBTYPE_MSAUDIO1; + codec_data_len = MSAUDIO1_WFX_EXTRA_BYTES; + fmt_tag = WAVE_FORMAT_MSAUDIO1; + break; + case 2: + subtype = &MEDIASUBTYPE_WMAUDIO2; + codec_data_len = WMAUDIO2_WFX_EXTRA_BYTES; + fmt_tag = WAVE_FORMAT_WMAUDIO2; + break; + case 3: + subtype = &MEDIASUBTYPE_WMAUDIO3; + codec_data_len = WMAUDIO3_WFX_EXTRA_BYTES; + fmt_tag = WAVE_FORMAT_WMAUDIO3; + break; + case 4: + subtype = &MEDIASUBTYPE_WMAUDIO_LOSSLESS; + codec_data_len = 18; + fmt_tag = WAVE_FORMAT_WMAUDIO_LOSSLESS; + break; + default: + assert(false); + return false; + } + + size = sizeof(WAVEFORMATEX) + codec_data_len; + if (!(wave_format = CoTaskMemAlloc(size))) + return false; + memset(wave_format, 0, size); + + mt->subtype = *subtype; + mt->bFixedSizeSamples = TRUE; + mt->lSampleSize = format->u.audio_wma.block_align; + mt->cbFormat = size; + mt->pbFormat = (BYTE *)wave_format; + wave_format->wFormatTag = fmt_tag; + wave_format->nChannels = format->u.audio_wma.channels; + wave_format->nSamplesPerSec = format->u.audio_wma.rate; + wave_format->nAvgBytesPerSec = format->u.audio_wma.bitrate / 8; + wave_format->nBlockAlign = format->u.audio_wma.block_align; + wave_format->wBitsPerSample = format->u.audio_wma.depth; + wave_format->cbSize = codec_data_len; + + if (format->u.audio_wma.codec_data_len == codec_data_len) + memcpy(wave_format+1, format->u.audio_wma.codec_data, format->u.audio_wma.codec_data_len); + else + FIXME("Unexpected codec_data length; got %u, expected %lu\n", format->u.audio_wma.codec_data_len, codec_data_len); + return true; +} + #define ALIGN(n, alignment) (((n) + (alignment) - 1) & ~((alignment) - 1))
static unsigned int wg_format_get_max_size_video_raw(enum wg_video_format format, unsigned int width, unsigned int height) @@ -384,8 +446,13 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) } break;
- case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: + /* Estimated max size of a compressed audio frame. + * There's no way to no way to know the real upper bound, + * so let's just use one second of decompressed size and hope it works. */ + return format->u.audio_wma.rate * format->u.audio_wma.channels * format->u.audio_wma.depth / 8; + + case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: case WG_MAJOR_TYPE_VIDEO_INDEO: @@ -643,7 +710,6 @@ bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool switch (format->major_type) { case WG_MAJOR_TYPE_AUDIO_MPEG4: - case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_INDEO: FIXME("Format %u not implemented!\n", format->major_type); @@ -657,6 +723,9 @@ bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool case WG_MAJOR_TYPE_AUDIO_MPEG1: return amt_from_wg_format_audio_mpeg1(mt, format);
+ case WG_MAJOR_TYPE_AUDIO_WMA: + return amt_from_wg_format_audio_wma(mt, format); + case WG_MAJOR_TYPE_VIDEO: return amt_from_wg_format_video(mt, format, wm);
@@ -787,6 +856,55 @@ static bool amt_to_wg_format_audio_mpeg1_layer3(const AM_MEDIA_TYPE *mt, struct return true; }
+static bool amt_to_wg_format_audio_wma(const AM_MEDIA_TYPE *mt, struct wg_format *format) +{ + const WAVEFORMATEX *audio_format = (const WAVEFORMATEX *)mt->pbFormat; + + if (!IsEqualGUID(&mt->formattype, &FORMAT_WaveFormatEx)) + { + FIXME("Unknown format type %s.\n", debugstr_guid(&mt->formattype)); + return false; + } + if (mt->cbFormat < sizeof(*audio_format) || !mt->pbFormat) + { + ERR("Unexpected format size %lu.\n", mt->cbFormat); + return false; + } + + if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MSAUDIO1)) + format->u.audio_wma.version = 1; + else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO2)) + format->u.audio_wma.version = 2; + else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO3)) + format->u.audio_wma.version = 3; + else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO_LOSSLESS)) + format->u.audio_wma.version = 4; + else + assert(false); + format->major_type = WG_MAJOR_TYPE_AUDIO_WMA; + format->u.audio_wma.bitrate = audio_format->nAvgBytesPerSec * 8; + format->u.audio_wma.rate = audio_format->nSamplesPerSec; + format->u.audio_wma.depth = audio_format->wBitsPerSample; + format->u.audio_wma.channels = audio_format->nChannels; + format->u.audio_wma.block_align = audio_format->nBlockAlign; + + format->u.audio_wma.codec_data_len = 0; + if (format->u.audio_wma.version == 1) + format->u.audio_wma.codec_data_len = 4; + if (format->u.audio_wma.version == 2) + format->u.audio_wma.codec_data_len = 10; + if (format->u.audio_wma.version == 3) + format->u.audio_wma.codec_data_len = 18; + if (format->u.audio_wma.version == 4) + format->u.audio_wma.codec_data_len = 18; + if (mt->cbFormat >= sizeof(WAVEFORMATEX) + format->u.audio_wma.codec_data_len) + memcpy(format->u.audio_wma.codec_data, audio_format+1, format->u.audio_wma.codec_data_len); + else + FIXME("Too small format block, can't copy codec data\n"); + + return true; +} + static bool amt_to_wg_format_video(const AM_MEDIA_TYPE *mt, struct wg_format *format) { static const struct @@ -932,6 +1050,11 @@ bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format) return amt_to_wg_format_audio_mpeg1(mt, format); if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MP3)) return amt_to_wg_format_audio_mpeg1_layer3(mt, format); + if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MSAUDIO1) + || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO2) + || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO3) + || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO_LOSSLESS)) + return amt_to_wg_format_audio_wma(mt, format); return amt_to_wg_format_audio(mt, format); }
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index f40ae37c0ce..1741299e654 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -1455,7 +1455,7 @@ static void check_audio_type(const WM_MEDIA_TYPE *mt) }
static void test_stream_media_props(IWMStreamConfig *config, - const GUID *majortype, const GUID *subtype, const GUID *formattype, BOOL todo_subtype) + const GUID *majortype, const GUID *subtype, const GUID *formattype) { char mt_buffer[2000]; WM_MEDIA_TYPE *mt = (WM_MEDIA_TYPE *)mt_buffer; @@ -1484,7 +1484,6 @@ static void test_stream_media_props(IWMStreamConfig *config, ok(size == sizeof(WM_MEDIA_TYPE) + mt->cbFormat, "got %lu.\n", size); ok(IsEqualGUID(&mt->majortype, majortype), "Expected major type %s, got %s.\n", debugstr_guid(majortype), debugstr_guid(&mt->majortype)); - todo_wine_if(todo_subtype) ok(IsEqualGUID(&mt->subtype, subtype), "Expected sub type %s, got %s.\n", debugstr_guid(subtype), debugstr_guid(&mt->subtype)); ok(IsEqualGUID(&mt->formattype, formattype), "Expected format type %s, got %s.\n", @@ -1546,9 +1545,9 @@ static void test_sync_reader_types(void) ok(IsEqualGUID(&majortype, &MEDIATYPE_Audio), "Got major type %s.\n", debugstr_guid(&majortype));
if (IsEqualGUID(&majortype, &MEDIATYPE_Audio)) - test_stream_media_props(config, &MEDIATYPE_Audio, &MEDIASUBTYPE_MSAUDIO1, &FORMAT_WaveFormatEx, TRUE); + test_stream_media_props(config, &MEDIATYPE_Audio, &MEDIASUBTYPE_MSAUDIO1, &FORMAT_WaveFormatEx); else - test_stream_media_props(config, &MEDIATYPE_Video, &MEDIASUBTYPE_WMV1, &FORMAT_VideoInfo, FALSE); + test_stream_media_props(config, &MEDIATYPE_Video, &MEDIASUBTYPE_WMV1, &FORMAT_VideoInfo);
ref = IWMStreamConfig_Release(config); ok(!ref, "Got outstanding refcount %ld.\n", ref); @@ -3425,9 +3424,9 @@ static void test_async_reader_types(void) ok(IsEqualGUID(&majortype, &MEDIATYPE_Audio), "Got major type %s.\n", debugstr_guid(&majortype));
if (IsEqualGUID(&majortype, &MEDIATYPE_Audio)) - test_stream_media_props(config, &MEDIATYPE_Audio, &MEDIASUBTYPE_MSAUDIO1, &FORMAT_WaveFormatEx, TRUE); + test_stream_media_props(config, &MEDIATYPE_Audio, &MEDIASUBTYPE_MSAUDIO1, &FORMAT_WaveFormatEx); else - test_stream_media_props(config, &MEDIATYPE_Video, &MEDIASUBTYPE_WMV1, &FORMAT_VideoInfo, FALSE); + test_stream_media_props(config, &MEDIATYPE_Video, &MEDIASUBTYPE_WMV1, &FORMAT_VideoInfo);
ref = IWMStreamConfig_Release(config); ok(!ref, "Got outstanding refcount %ld.\n", ref);
From: Alfred Agrell floating@muncher.se
--- dlls/winegstreamer/quartz_parser.c | 14 +++++++++++--- dlls/winegstreamer/unixlib.h | 2 ++ dlls/winegstreamer/wg_format.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-)
diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 596f7a5011a..2244d202ab6 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -621,11 +621,11 @@ static bool amt_from_wg_format_video_cinepak(AM_MEDIA_TYPE *mt, const struct wg_
static bool amt_from_wg_format_video_wmv(AM_MEDIA_TYPE *mt, const struct wg_format *format) { - VIDEOINFO *video_format; + VIDEOINFOHEADER *video_format; uint32_t frame_time; const GUID *subtype;
- if (!(video_format = CoTaskMemAlloc(sizeof(*video_format)))) + if (!(video_format = CoTaskMemAlloc(sizeof(*video_format) + format->u.video_wmv.codec_data_len))) return false;
switch (format->u.video_wmv.format) @@ -656,7 +656,7 @@ static bool amt_from_wg_format_video_wmv(AM_MEDIA_TYPE *mt, const struct wg_form mt->bTemporalCompression = TRUE; mt->lSampleSize = 0; mt->formattype = FORMAT_VideoInfo; - mt->cbFormat = sizeof(VIDEOINFOHEADER); + mt->cbFormat = sizeof(*video_format) + format->u.video_wmv.codec_data_len; mt->pbFormat = (BYTE *)video_format;
memset(video_format, 0, sizeof(*video_format)); @@ -669,6 +669,7 @@ static bool amt_from_wg_format_video_wmv(AM_MEDIA_TYPE *mt, const struct wg_form video_format->bmiHeader.biHeight = format->u.video_wmv.height; video_format->bmiHeader.biPlanes = 1; video_format->bmiHeader.biCompression = mt->subtype.Data1; + memcpy(video_format+1, format->u.video_wmv.codec_data, format->u.video_wmv.codec_data_len);
return true; } @@ -997,6 +998,13 @@ static bool amt_to_wg_format_video_wmv(const AM_MEDIA_TYPE *mt, struct wg_format else format->u.video_wmv.format = WG_WMV_VIDEO_FORMAT_UNKNOWN;
+ format->u.video_wmv.codec_data_len = mt->cbFormat - sizeof(VIDEOINFOHEADER); + if (format->u.video_wmv.codec_data_len > sizeof(format->u.video_wmv.codec_data)) + { + WARN("Too big codec_data value (%u).\n", (UINT)format->u.video_wmv.codec_data_len); + format->u.video_wmv.codec_data_len = 0; + } + memcpy(format->u.video_wmv.codec_data, video_format+1, format->u.video_wmv.codec_data_len); return true; }
diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 7a2a4a8da2f..9af8f7dc1a2 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -157,6 +157,8 @@ struct wg_format wg_wmv_video_format format; int32_t width, height; uint32_t fps_n, fps_d; + uint32_t codec_data_len; + unsigned char codec_data[64]; } video_wmv; struct { diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 274a6dec261..a66718fe928 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -300,6 +300,9 @@ static void wg_format_from_caps_video_wmv(struct wg_format *format, const GstCap gchar format_buffer[5] = {'W','M','V','0',0}; enum wg_wmv_video_format wmv_format; const gchar *wmv_format_str = NULL; + const GValue *codec_data_value; + GstBuffer *codec_data; + GstMapInfo map;
if (!gst_structure_get_int(structure, "width", &width)) { @@ -344,6 +347,19 @@ static void wg_format_from_caps_video_wmv(struct wg_format *format, const GstCap format->u.video_wmv.format = wmv_format; format->u.video_wmv.fps_n = fps_n; format->u.video_wmv.fps_d = fps_d; + + if ((codec_data_value = gst_structure_get_value(structure, "codec_data")) && (codec_data = gst_value_get_buffer(codec_data_value))) + { + gst_buffer_map(codec_data, &map, GST_MAP_READ); + if (map.size <= sizeof(format->u.video_wmv.codec_data)) + { + format->u.video_wmv.codec_data_len = map.size; + memcpy(format->u.video_wmv.codec_data, map.data, map.size); + } + else + GST_WARNING("Too big codec_data value (%u) in %" GST_PTR_FORMAT ".", (UINT)map.size, caps); + gst_buffer_unmap(codec_data, &map); + } }
static void wg_format_from_caps_video_mpeg1(struct wg_format *format, const GstCaps *caps) @@ -733,6 +749,7 @@ static GstCaps *wg_format_to_caps_video_wmv(const struct wg_format *format) { unsigned int wmv_version; const char *wmv_format; + GstBuffer *buffer; GstCaps *caps;
if (!(caps = gst_caps_new_empty_simple("video/x-wmv"))) @@ -780,6 +797,19 @@ static GstCaps *wg_format_to_caps_video_wmv(const struct wg_format *format) 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.codec_data_len) + { + if (!(buffer = gst_buffer_new_and_alloc(format->u.video_wmv.codec_data_len))) + { + gst_caps_unref(caps); + return NULL; + } + + gst_buffer_fill(buffer, 0, format->u.video_wmv.codec_data, format->u.video_wmv.codec_data_len); + gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); + gst_buffer_unref(buffer); + } + return caps; }
From: Alfred Agrell floating@muncher.se
--- dlls/winegstreamer/quartz_parser.c | 7 ++++++- dlls/winegstreamer/wg_format.c | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 2244d202ab6..5e8f859cc7c 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -400,6 +400,10 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) return wg_format_get_max_size_video_raw(WG_VIDEO_FORMAT_YV12, format->u.video_mpeg1.width, format->u.video_mpeg1.height);
+ case WG_MAJOR_TYPE_VIDEO_WMV: + return wg_format_get_max_size_video_raw(WG_VIDEO_FORMAT_YV12, + format->u.video_wmv.width, format->u.video_wmv.height); + case WG_MAJOR_TYPE_AUDIO: { unsigned int rate = format->u.audio.rate, channels = format->u.audio.channels; @@ -454,7 +458,6 @@ unsigned int wg_format_get_max_size(const struct wg_format *format)
case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_VIDEO_H264: - case WG_MAJOR_TYPE_VIDEO_WMV: case WG_MAJOR_TYPE_VIDEO_INDEO: FIXME("Format %u not implemented!\n", format->major_type); return 0; @@ -669,6 +672,8 @@ static bool amt_from_wg_format_video_wmv(AM_MEDIA_TYPE *mt, const struct wg_form video_format->bmiHeader.biHeight = format->u.video_wmv.height; video_format->bmiHeader.biPlanes = 1; video_format->bmiHeader.biCompression = mt->subtype.Data1; + video_format->bmiHeader.biBitCount = 24; + video_format->dwBitRate = 0; memcpy(video_format+1, format->u.video_wmv.codec_data, format->u.video_wmv.codec_data_len);
return true; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index a66718fe928..9404a0290eb 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -893,7 +893,6 @@ bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_H264: - case WG_MAJOR_TYPE_VIDEO_WMV: case WG_MAJOR_TYPE_VIDEO_INDEO: case WG_MAJOR_TYPE_VIDEO_MPEG1: GST_FIXME("Format %u not implemented!", a->major_type); @@ -917,6 +916,12 @@ bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) /* Do not compare FPS. */ return a->u.video_cinepak.width == b->u.video_cinepak.width && a->u.video_cinepak.height == b->u.video_cinepak.height; + + case WG_MAJOR_TYPE_VIDEO_WMV: + /* Do not compare FPS. */ + return a->u.video_wmv.format == b->u.video_wmv.format + && a->u.video_wmv.width == b->u.video_wmv.width + && a->u.video_wmv.height == b->u.video_wmv.height; }
assert(0);
From: Alfred Agrell floating@muncher.se
--- dlls/winegstreamer/wm_reader.c | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-)
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 882b6df1bbb..09f69bc6208 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -55,6 +55,7 @@ struct wm_reader
CRITICAL_SECTION cs; QWORD start_time; + QWORD file_size;
IStream *source_stream; HANDLE file; @@ -592,27 +593,12 @@ static DWORD CALLBACK read_thread(void *arg) IStream *stream = reader->source_stream; HANDLE file = reader->file; size_t buffer_size = 4096; - uint64_t file_size; + uint64_t file_size = reader->file_size; void *data;
if (!(data = malloc(buffer_size))) return 0;
- 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) @@ -1453,7 +1439,7 @@ static const IWMReaderTimecodeVtbl timecode_vtbl = timecode_GetTimecodeRangeBounds, };
-static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) +static HRESULT init_stream(struct wm_reader *reader) { wg_parser_t wg_parser; HRESULT hr; @@ -1470,7 +1456,7 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) goto out_destroy_parser; }
- if (FAILED(hr = wg_parser_connect(reader->wg_parser, file_size))) + if (FAILED(hr = wg_parser_connect(reader->wg_parser, reader->file_size))) { ERR("Failed to connect parser, hr %#lx.\n", hr); goto out_shutdown_thread; @@ -2134,8 +2120,9 @@ static HRESULT WINAPI reader_Open(IWMSyncReader2 *iface, const WCHAR *filename) }
reader->file = file; + reader->file_size = size.QuadPart;
- if (FAILED(hr = init_stream(reader, size.QuadPart))) + if (FAILED(hr = init_stream(reader))) reader->file = NULL;
LeaveCriticalSection(&reader->cs); @@ -2166,7 +2153,9 @@ static HRESULT WINAPI reader_OpenStream(IWMSyncReader2 *iface, IStream *stream) }
IStream_AddRef(reader->source_stream = stream); - if (FAILED(hr = init_stream(reader, stat.cbSize.QuadPart))) + reader->file_size = stat.cbSize.QuadPart; + + if (FAILED(hr = init_stream(reader))) { IStream_Release(stream); reader->source_stream = NULL;
From: Alfred Agrell floating@muncher.se
Latter is meaningless in this commit, but necessary in the next. --- dlls/winegstreamer/wm_reader.c | 36 ++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-)
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 09f69bc6208..5de8d70aff5 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -54,6 +54,7 @@ struct wm_reader LONG refcount;
CRITICAL_SECTION cs; + CRITICAL_SECTION init_cs; /* Protects wg_parser and read_thread_shutdown */ QWORD start_time; QWORD file_size;
@@ -601,15 +602,25 @@ static DWORD CALLBACK read_thread(void *arg)
TRACE("Starting read thread for reader %p.\n", reader);
- while (!reader->read_thread_shutdown) + while (true) { + wg_parser_t parser; LARGE_INTEGER large_offset; uint64_t offset; ULONG ret_size; uint32_t size; HRESULT hr;
- if (!wg_parser_get_next_read_offset(reader->wg_parser, &offset, &size)) + EnterCriticalSection(&reader->init_cs); + if (reader->read_thread_shutdown) + { + LeaveCriticalSection(&reader->init_cs); + break; + } + parser = reader->wg_parser; + LeaveCriticalSection(&reader->init_cs); + + if (!wg_parser_get_next_read_offset(parser, &offset, &size)) continue;
if (offset >= file_size) @@ -619,7 +630,7 @@ static DWORD CALLBACK read_thread(void *arg)
if (!size) { - wg_parser_push_data(reader->wg_parser, data, 0); + wg_parser_push_data(parser, data, 0); continue; }
@@ -638,7 +649,7 @@ static DWORD CALLBACK read_thread(void *arg) || !ReadFile(file, data, size, &ret_size, NULL)) { ERR("Failed to read %u bytes at offset %I64u, error %lu.\n", size, offset, GetLastError()); - wg_parser_push_data(reader->wg_parser, NULL, 0); + wg_parser_push_data(parser, NULL, 0); continue; } } @@ -649,14 +660,14 @@ static DWORD CALLBACK read_thread(void *arg) if (FAILED(hr)) { ERR("Failed to read %u bytes at offset %I64u, hr %#lx.\n", size, offset, hr); - wg_parser_push_data(reader->wg_parser, NULL, 0); + wg_parser_push_data(parser, NULL, 0); continue; } }
if (ret_size != size) ERR("Unexpected short read: requested %u bytes, got %lu.\n", size, ret_size); - wg_parser_push_data(reader->wg_parser, data, ret_size); + wg_parser_push_data(parser, data, ret_size); }
free(data); @@ -1448,8 +1459,11 @@ static HRESULT init_stream(struct wm_reader *reader) if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, FALSE))) return E_OUTOFMEMORY;
+ EnterCriticalSection(&reader->init_cs); reader->wg_parser = wg_parser; reader->read_thread_shutdown = false; + LeaveCriticalSection(&reader->init_cs); + if (!(reader->read_thread = CreateThread(NULL, 0, read_thread, reader, 0, NULL))) { hr = E_OUTOFMEMORY; @@ -1517,14 +1531,18 @@ out_disconnect_parser: wg_parser_disconnect(reader->wg_parser);
out_shutdown_thread: + EnterCriticalSection(&reader->init_cs); reader->read_thread_shutdown = true; + LeaveCriticalSection(&reader->init_cs); WaitForSingleObject(reader->read_thread, INFINITE); CloseHandle(reader->read_thread); reader->read_thread = NULL;
out_destroy_parser: + EnterCriticalSection(&reader->init_cs); wg_parser_destroy(reader->wg_parser); reader->wg_parser = 0; + LeaveCriticalSection(&reader->init_cs);
return hr; } @@ -1728,6 +1746,8 @@ static ULONG WINAPI unknown_inner_Release(IUnknown *iface)
reader->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&reader->cs); + reader->init_cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&reader->init_cs);
free(reader); } @@ -1781,7 +1801,9 @@ static HRESULT WINAPI reader_Close(IWMSyncReader2 *iface)
wg_parser_disconnect(reader->wg_parser);
+ EnterCriticalSection(&reader->init_cs); reader->read_thread_shutdown = true; + LeaveCriticalSection(&reader->init_cs); WaitForSingleObject(reader->read_thread, INFINITE); CloseHandle(reader->read_thread); reader->read_thread = NULL; @@ -2557,6 +2579,8 @@ HRESULT WINAPI winegstreamer_create_wm_sync_reader(IUnknown *outer, void **out)
InitializeCriticalSection(&object->cs); object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": reader.cs"); + InitializeCriticalSection(&object->init_cs); + object->init_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": reader.init_cs");
TRACE("Created reader %p.\n", object); *out = outer ? (void *)&object->IUnknown_inner : (void *)&object->IWMSyncReader2_iface;
From: Alfred Agrell floating@muncher.se
--- dlls/winegstreamer/wm_reader.c | 60 ++++++++++++++++++++++------------ dlls/wmvcore/tests/wmvcore.c | 29 ++++++++++++++-- 2 files changed, 66 insertions(+), 23 deletions(-)
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 5de8d70aff5..c214dc100f0 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -30,10 +30,6 @@ struct wm_stream WMT_STREAM_SELECTION selection; WORD index; bool eos; - /* Note that we only pretend to read compressed samples, and instead output - * uncompressed samples regardless of whether we are configured to read - * compressed samples. Rather, the behaviour of the reader objects differs - * in nontrivial ways depending on this field. */ bool read_compressed;
IWMReaderAllocatorEx *output_allocator; @@ -620,6 +616,12 @@ static DWORD CALLBACK read_thread(void *arg) parser = reader->wg_parser; LeaveCriticalSection(&reader->init_cs);
+ if (!parser) + { + Sleep(10); + continue; + } + if (!wg_parser_get_next_read_offset(parser, &offset, &size)) continue;
@@ -1450,13 +1452,22 @@ static const IWMReaderTimecodeVtbl timecode_vtbl = timecode_GetTimecodeRangeBounds, };
-static HRESULT init_stream(struct wm_reader *reader) +static HRESULT init_stream(struct wm_reader *reader, bool read_compressed) { wg_parser_t wg_parser; HRESULT hr; WORD i;
- if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, FALSE))) + if (reader->wg_parser) + { + wg_parser_disconnect(reader->wg_parser); + EnterCriticalSection(&reader->init_cs); + wg_parser_destroy(reader->wg_parser); + reader->wg_parser = 0; + LeaveCriticalSection(&reader->init_cs); + } + + if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, read_compressed))) return E_OUTOFMEMORY;
EnterCriticalSection(&reader->init_cs); @@ -1464,7 +1475,7 @@ static HRESULT init_stream(struct wm_reader *reader) reader->read_thread_shutdown = false; LeaveCriticalSection(&reader->init_cs);
- if (!(reader->read_thread = CreateThread(NULL, 0, read_thread, reader, 0, NULL))) + if (!reader->read_thread && !(reader->read_thread = CreateThread(NULL, 0, read_thread, reader, 0, NULL))) { hr = E_OUTOFMEMORY; goto out_destroy_parser; @@ -1476,14 +1487,20 @@ static HRESULT init_stream(struct wm_reader *reader) goto out_shutdown_thread; }
- reader->stream_count = wg_parser_get_stream_count(reader->wg_parser); - - if (!(reader->streams = calloc(reader->stream_count, sizeof(*reader->streams)))) + if (!reader->streams) { - hr = E_OUTOFMEMORY; - goto out_disconnect_parser; + reader->stream_count = wg_parser_get_stream_count(reader->wg_parser); + if (!(reader->streams = calloc(reader->stream_count, sizeof(*reader->streams)))) + { + hr = E_OUTOFMEMORY; + goto out_disconnect_parser; + } + for (i = 0; i < reader->stream_count; ++i) + reader->streams[i].selection = WMT_ON; }
+ assert(reader->stream_count == wg_parser_get_stream_count(reader->wg_parser)); + for (i = 0; i < reader->stream_count; ++i) { struct wm_stream *stream = &reader->streams[i]; @@ -1491,7 +1508,6 @@ static HRESULT init_stream(struct wm_reader *reader) stream->wg_stream = wg_parser_get_stream(reader->wg_parser, i); stream->reader = reader; stream->index = i; - stream->selection = WMT_ON; wg_parser_stream_get_preferred_format(stream->wg_stream, &stream->format); if (stream->format.major_type == WG_MAJOR_TYPE_AUDIO) { @@ -1517,7 +1533,8 @@ static HRESULT init_stream(struct wm_reader *reader) if (stream->format.u.video.height > 0) stream->format.u.video.height = -stream->format.u.video.height; } - wg_parser_stream_enable(stream->wg_stream, &stream->format); + if (stream->selection == WMT_ON) + wg_parser_stream_enable(stream->wg_stream, &stream->format); }
/* We probably discarded events because streams weren't enabled yet. @@ -1666,13 +1683,15 @@ static HRESULT wm_reader_read_stream_sample(struct wm_reader *reader, struct wg_
wg_parser_stream_release_buffer(stream->wg_stream);
- if (!buffer->has_pts) + if (buffer->has_pts) + *pts = buffer->pts; + else FIXME("Missing PTS.\n"); - if (!buffer->has_duration) + if (buffer->has_duration) + *duration = buffer->duration; + else FIXME("Missing duration.\n");
- *pts = buffer->pts; - *duration = buffer->duration; *flags = 0; if (buffer->discontinuity) *flags |= WM_SF_DISCONTINUITY; @@ -2144,7 +2163,7 @@ static HRESULT WINAPI reader_Open(IWMSyncReader2 *iface, const WCHAR *filename) reader->file = file; reader->file_size = size.QuadPart;
- if (FAILED(hr = init_stream(reader))) + if (FAILED(hr = init_stream(reader, false))) reader->file = NULL;
LeaveCriticalSection(&reader->cs); @@ -2177,7 +2196,7 @@ static HRESULT WINAPI reader_OpenStream(IWMSyncReader2 *iface, IStream *stream) IStream_AddRef(reader->source_stream = stream); reader->file_size = stat.cbSize.QuadPart;
- if (FAILED(hr = init_stream(reader))) + if (FAILED(hr = init_stream(reader, false))) { IStream_Release(stream); reader->source_stream = NULL; @@ -2351,6 +2370,7 @@ static HRESULT WINAPI reader_SetReadStreamSamples(IWMSyncReader2 *iface, WORD st }
stream->read_compressed = compressed; + init_stream(reader, compressed);
LeaveCriticalSection(&reader->cs); return S_OK; diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 1741299e654..35688bd04e4 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -1848,6 +1848,7 @@ struct callback QWORD next_pts[2]; QWORD expect_time; HANDLE expect_ontime, got_ontime; + bool todo_rewind; };
static struct callback *impl_from_IWMReaderCallback(IWMReaderCallback *iface) @@ -2052,8 +2053,16 @@ static HRESULT WINAPI callback_OnSample(IWMReaderCallback *iface, DWORD output, trace("%lu: %04lx: IWMReaderCallback::OnSample(output %lu, time %I64u, duration %I64u, flags %#lx)\n", GetTickCount(), GetCurrentThreadId(), output, time, duration, flags);
+ if (callback->last_pts[output] > time && callback->todo_rewind) + { + callback->todo_rewind = false; + todo_wine ok(0, "changing compression state in Wine rewinds the stream\n"); + callback->last_pts[0] = 0; + callback->last_pts[1] = 0; + } + /* uncompressed samples are slightly out of order because of decoding delay */ - ok(callback->last_pts[output] <= time, "got time %I64d\n", time); + ok(callback->last_pts[output] <= time, "expected %I64d <= %I64d\n", callback->last_pts[output], time); callback->last_pts[output] = time; callback->next_pts[output] = time + duration;
@@ -2134,7 +2143,15 @@ static HRESULT WINAPI callback_advanced_OnStreamSample(IWMReaderCallbackAdvanced trace("%lu: %04lx: IWMReaderCallbackAdvanced::OnStreamSample(stream %u, pts %I64u, duration %I64u, flags %#lx)\n", GetTickCount(), GetCurrentThreadId(), stream_number, pts, duration, flags);
- ok(callback->last_pts[output] <= pts, "got pts %I64d\n", pts); + if (callback->last_pts[output] > pts && callback->todo_rewind) + { + callback->todo_rewind = false; + todo_wine ok(0, "changing compression state in Wine rewinds the stream\n"); + callback->last_pts[0] = 0; + callback->last_pts[1] = 0; + } + + ok(callback->last_pts[output] <= pts, "expected %I64d <= %I64d\n", callback->last_pts[output], pts); callback->last_pts[output] = pts; callback->next_pts[output] = pts + duration;
@@ -2146,7 +2163,7 @@ static HRESULT WINAPI callback_advanced_OnStreamSample(IWMReaderCallbackAdvanced else { ok(callback->callback_tid == GetCurrentThreadId(), "got wrong thread\n"); - ok(callback->last_pts[1 - output] <= pts, "got pts %I64d\n", pts); + ok(callback->last_pts[1 - output] <= pts, "expected %I64d <= %I64d\n", callback->last_pts[1 - output], pts); }
if (!callback->output_tid[output]) @@ -2709,6 +2726,8 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st todo_wine ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr);
+ if (winetest_platform_is_wine) + callback->todo_rewind = true; callback->expect_time = 13460000; hr = IWMReaderAdvanced2_DeliverTime(advanced, 13460000); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -2723,6 +2742,7 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st ok(callback->next_pts[1] == 13270000, "Got pts %I64d.\n", callback->next_pts[1]); ok(callback->sample_count > 0, "Got no samples.\n"); callback->sample_count = 0; + ok(!callback->todo_rewind, "Didn't rewind as expected\n");
callback->read_compressed = true; hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 1, TRUE); @@ -2731,6 +2751,8 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st ok(hr == S_OK, "Got hr %#lx.\n", hr); }
+ if (winetest_platform_is_wine && callback->read_compressed) + callback->todo_rewind = true; callback->expect_time = test_wmv_duration * 2; hr = IWMReaderAdvanced2_DeliverTime(advanced, test_wmv_duration * 2); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -2754,6 +2776,7 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st callback->next_pts[0] = 0; callback->last_pts[1] = 0; callback->next_pts[1] = 0; + ok(!callback->todo_rewind, "Didn't rewind as expected\n");
hr = IWMReader_Stop(reader); ok(hr == S_OK, "Got hr %#lx.\n", hr);
From: Alfred Agrell floating@muncher.se
--- dlls/wmvcore/tests/wmvcore.c | 185 +++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+)
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 35688bd04e4..97c343704ac 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -1819,6 +1819,190 @@ static void test_sync_reader_file(void) ok(ret, "Failed to delete %s, error %lu.\n", debugstr_w(filename), GetLastError()); }
+static void test_stream_output_type(IWMProfile *profile, WORD stream_num, const WM_MEDIA_TYPE *expected) +{ + IWMStreamConfig *stream_config; + IWMMediaProps *media_props; + char mt_buffer[2000]; + WM_MEDIA_TYPE *mt; + DWORD ret_size; + HRESULT hr; + + hr = IWMProfile_GetStreamByNumber(profile, stream_num, &stream_config); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IWMStreamConfig_QueryInterface(stream_config, &IID_IWMMediaProps, (void**)&media_props); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + mt = (WM_MEDIA_TYPE *)mt_buffer; + memset(mt_buffer, 0xcc, sizeof(mt_buffer)); + ret_size = sizeof(mt_buffer); + hr = IWMMediaProps_GetMediaType(media_props, mt, &ret_size); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(compare_media_types(mt, expected), "Media types didn't match.\n"); + + IWMStreamConfig_Release(stream_config); + IWMMediaProps_Release(media_props); +} + +static const VIDEOINFOHEADER vih_wmv1 = { + .rcSource = { 0, 0, 64, 48 }, + .rcTarget = { 0, 0, 64, 48 }, + .dwBitRate = 0x0002e418, + .dwBitErrorRate = 0, + .AvgTimePerFrame = 0, + .bmiHeader.biSize = sizeof(BITMAPINFOHEADER), + .bmiHeader.biWidth = 64, + .bmiHeader.biHeight = 48, + .bmiHeader.biPlanes = 1, + .bmiHeader.biBitCount = 0x18, + .bmiHeader.biCompression = MAKEFOURCC('W','M','V','1'), + .bmiHeader.biSizeImage = 0, + .bmiHeader.biXPelsPerMeter = 0, + .bmiHeader.biYPelsPerMeter = 0, +}; +static const WM_MEDIA_TYPE mt_wmv1 = { + /* MEDIATYPE_Video, MEDIASUBTYPE_WMV1, FORMAT_VideoInfo */ + .majortype = {0x73646976, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}, + .subtype = {0x31564d57, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}, + .bTemporalCompression = TRUE, + .formattype = {0x05589f80, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}}, + .cbFormat = sizeof(VIDEOINFOHEADER), + .pbFormat = (BYTE *)&vih_wmv1, +}; + +static const MSAUDIO1WAVEFORMAT wfx_msaudio1 = { + .wfx.wFormatTag = WAVE_FORMAT_MSAUDIO1, + .wfx.nChannels = 1, + .wfx.nSamplesPerSec = 44100, + .wfx.nAvgBytesPerSec = 16000, + .wfx.nBlockAlign = 0x02e7, + .wfx.wBitsPerSample = 0x0010, + .wfx.cbSize = MSAUDIO1_WFX_EXTRA_BYTES, + .wSamplesPerBlock = 0, + .wEncodeOptions = 1, +}; +static const WM_MEDIA_TYPE mt_msaudio1 = { + /* MEDIATYPE_Audio, MEDIASUBTYPE_MSAUDIO1, FORMAT_WaveFormatEx */ + .majortype = {0x73647561, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}, + .subtype = {0x00000160, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}, + .bFixedSizeSamples = TRUE, + .lSampleSize = 0x02e7, + .formattype = {0x05589f81, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}}, + .cbFormat = sizeof(MSAUDIO1WAVEFORMAT), + .pbFormat = (BYTE *)&wfx_msaudio1, +}; + +static void test_sync_reader_compressed_output(void) +{ + static const DWORD audio_sample_times[] = { + 0, 460000, 920000, 1390000, 1850000, 2320000, 2780000, 3250000, 3710000, 4180000, 4640000, 5100000, + 5570000, 6030000, 6500000, 6960000, 7430000, 7890000, 8350000, 8820000, 9280000, 9750000, 10210000, + 10680000, 11140000, 11610000, 12070000, 12530000, 13000000, 13460000, 13930000, 14390000, 14860000, + 15320000, 15790000, 16250000, 16710000, 17180000, 17640000, 18110000, 18570000, 19040000, 19500000, 19960000, + 99999999 + }; + static const DWORD video_sample_sizes[] = { + 1117, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 1117, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 1117, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 1117, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 1117, 8 + }; + + const WCHAR *filename = load_resource(L"test.wmv"); + DWORD flags, bytes_count; + QWORD sample_time, sample_duration; + IWMSyncReader *reader; + IWMProfile *profile; + INSSBuffer *sample; + WORD stream_num; + HRESULT hr; + BYTE *data; + + DWORD audio_idx = 0; + DWORD video_idx = 0; + + VIDEOINFOHEADER vih = vih_wmv1; + WM_MEDIA_TYPE mt = mt_wmv1; + mt.pbFormat = (BYTE *)&vih; + + hr = WMCreateSyncReader(NULL, 0, &reader); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + IWMSyncReader_QueryInterface(reader, &IID_IWMProfile, (void **)&profile); + + hr = IWMSyncReader_Open(reader, filename); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + if (winetest_platform_is_wine) + { + todo_wine ok(0, "dwBitRate is not implemented\n"); + vih.dwBitRate = 0; + } + test_stream_output_type(profile, 1, &mt); + test_stream_output_type(profile, 2, &mt_msaudio1); + + hr = IWMSyncReader_SetReadStreamSamples(reader, 1, TRUE); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IWMSyncReader_SetReadStreamSamples(reader, 2, TRUE); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + test_stream_output_type(profile, 1, &mt); + test_stream_output_type(profile, 2, &mt_msaudio1); + + while (video_idx < 50 || audio_idx < 44) + { + DWORD next_video_time = 460000 + video_idx * 400000; + DWORD next_audio_time = audio_sample_times[audio_idx]; + + sample_duration = 1234; + hr = IWMSyncReader_GetNextSample(reader, 0, &sample, &sample_time, &sample_duration, &flags, NULL, &stream_num); + ok(hr == S_OK, "%lu/%lu: Got hr %#lx.\n", video_idx, audio_idx, hr); + /* we don't care about the buffer, but GetLength is unimplemented in Wine */ + hr = INSSBuffer_GetBufferAndLength(sample, &data, &bytes_count); + ok(hr == S_OK, "%lu/%lu: Got hr %#lx.\n", video_idx, audio_idx, hr); + + if (next_video_time <= next_audio_time) + { + ok(stream_num == 1, "%lu: Got %lu\n", video_idx, (DWORD)stream_num); + ok(sample_time == next_video_time, "%lu: Expected %lu, got %lu\n", video_idx, next_video_time, (DWORD)sample_time); + todo_wine ok(sample_duration == 10000, "%lu: Got %lu\n", video_idx, (DWORD)sample_duration); + + if (video_idx == 0) + ok(flags == (WM_SF_CLEANPOINT|WM_SF_DISCONTINUITY), "%lu: Got %lu\n", audio_idx, flags); + else if (video_sample_sizes[video_idx] == 1117) + ok(flags == WM_SF_CLEANPOINT, "%lu: Got %lu\n", audio_idx, flags); + else + ok(flags == 0, "%lu: Got %lu\n", audio_idx, flags); + ok(bytes_count == video_sample_sizes[video_idx], + "%lu: Expected %lu, got %lu\n", video_idx, video_sample_sizes[video_idx], bytes_count); + video_idx++; + } + else + { + ok(stream_num == 2, "%lu: Got %lu\n", audio_idx, (DWORD)stream_num); + ok(sample_time == next_audio_time, "%lu: Expected %lu, got %lu\n", audio_idx, next_audio_time, (DWORD)sample_time); + todo_wine ok(sample_duration == 460000, "%lu: Got %lu\n", audio_idx, (DWORD)sample_duration); + + if (audio_idx == 0) + todo_wine ok(flags == (WM_SF_CLEANPOINT|WM_SF_DISCONTINUITY), "%lu: Got %lu\n", audio_idx, flags); + else + todo_wine ok(flags == WM_SF_CLEANPOINT, "%lu: Got %lu\n", audio_idx, flags); + ok(bytes_count == 743, "%lu: Got %lu\n", audio_idx, bytes_count); + + audio_idx++; + } + + INSSBuffer_Release(sample); + } + + hr = IWMSyncReader_GetNextSample(reader, 0, &sample, &sample_time, &sample_duration, &flags, NULL, &stream_num); + ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#lx.\n", hr); + + IWMSyncReader_Release(reader); + IWMProfile_Release(profile); +} + struct callback { IWMReaderCallback IWMReaderCallback_iface; @@ -3979,6 +4163,7 @@ START_TEST(wmvcore) test_sync_reader_streaming(); test_sync_reader_types(); test_sync_reader_file(); + test_sync_reader_compressed_output(); test_async_reader_settings(); test_async_reader_streaming(); test_async_reader_types();