[PATCH v5 0/6] MR4449: winegstreamer: WMReader compressed output
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). -- v5: 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. winegstreamer: Move file size to struct wm_reader. winegstreamer: Fill in a few more pieces of WMV format handling. winegstreamer: Add codec_data to WMVs. https://gitlab.winehq.org/wine/wine/-/merge_requests/4449
From: Alfred Agrell <floating(a)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; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4449
From: Alfred Agrell <floating(a)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); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4449
From: Alfred Agrell <floating(a)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; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4449
From: Alfred Agrell <floating(a)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; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4449
From: Alfred Agrell <floating(a)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); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4449
From: Alfred Agrell <floating(a)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(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4449
Hi, It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated. The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=140259 Your paranoid android. === build (build log) === error: patch failed: dlls/winegstreamer/quartz_parser.c:454 Task: Patch failed to apply === debian11 (build log) === error: patch failed: dlls/winegstreamer/quartz_parser.c:454 Task: Patch failed to apply === debian11b (build log) === error: patch failed: dlls/winegstreamer/quartz_parser.c:454 Task: Patch failed to apply
participants (3)
-
Alfred Agrell -
Alfred Agrell (@Alcaro) -
Marvin