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).
-- v9: wmvcore/tests: Add tests for compressed output. winegstreamer: Implement compressed output support in WMSyncReader. winegstreamer: Leave pts/duration unchanged if they're not set. winegstreamer: Introduce mutex for wm_reader read_thread_shutdown. 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.
On Fri Dec 1 19:43:55 2023 +0000, Zebediah Figura wrote:
Would you prefer if I just tell the tests to explicitly rewind the
stream when changing compression mode? [As mentioned in wm_reader.c](https://gitlab.winehq.org/wine/wine/-/blob/master/dlls/winegstreamer/wm_read...), no plausible program reconfigures streams dynamically anyways. That's probably best. Alternatively we could do something like if (pts < last_pts) ++callback->rewind_count; todo_wine ok(!callback->rewind_count); which I think achieves the same goal while being simpler.
Told it to rewind, felt easier and less hacky.
Oddly enough, this seems to have changed some durations from 13930000 to 13920000. I'd guess native's rounding to nearest multiple of 10000 a few times more or less, and the accumulated error from these roundings make it spill over to another millisecond.
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 e402e1aab52..56c3b20bbec 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)) + { + ERR("Too big codec_data value (%u).\n", 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 86bd380c351..aec59c314c2 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 | 9 +++++++-- dlls/winegstreamer/wg_format.c | 7 ++++++- 2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 56c3b20bbec..3a47091504d 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; @@ -664,11 +667,13 @@ static bool amt_from_wg_format_video_wmv(AM_MEDIA_TYPE *mt, const struct wg_form video_format->rcTarget = video_format->rcSource; if ((frame_time = MulDiv(10000000, format->u.video_wmv.fps_d, format->u.video_wmv.fps_n)) != -1) video_format->AvgTimePerFrame = frame_time; - video_format->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + video_format->bmiHeader.biSize = sizeof(BITMAPINFOHEADER) + format->u.video_wmv.codec_data_len; video_format->bmiHeader.biWidth = format->u.video_wmv.width; 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
--- dlls/winegstreamer/wm_reader.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 09f69bc6208..5c778ba2350 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 shutdown_cs; QWORD start_time; QWORD file_size;
@@ -601,7 +602,7 @@ static DWORD CALLBACK read_thread(void *arg)
TRACE("Starting read thread for reader %p.\n", reader);
- while (!reader->read_thread_shutdown) + while (true) { LARGE_INTEGER large_offset; uint64_t offset; @@ -609,6 +610,14 @@ static DWORD CALLBACK read_thread(void *arg) uint32_t size; HRESULT hr;
+ EnterCriticalSection(&reader->shutdown_cs); + if (reader->read_thread_shutdown) + { + LeaveCriticalSection(&reader->shutdown_cs); + break; + } + LeaveCriticalSection(&reader->shutdown_cs); + if (!wg_parser_get_next_read_offset(reader->wg_parser, &offset, &size)) continue;
@@ -1450,6 +1459,7 @@ static HRESULT init_stream(struct wm_reader *reader)
reader->wg_parser = wg_parser; reader->read_thread_shutdown = false; + if (!(reader->read_thread = CreateThread(NULL, 0, read_thread, reader, 0, NULL))) { hr = E_OUTOFMEMORY; @@ -1517,7 +1527,9 @@ out_disconnect_parser: wg_parser_disconnect(reader->wg_parser);
out_shutdown_thread: + EnterCriticalSection(&reader->shutdown_cs); reader->read_thread_shutdown = true; + LeaveCriticalSection(&reader->shutdown_cs); WaitForSingleObject(reader->read_thread, INFINITE); CloseHandle(reader->read_thread); reader->read_thread = NULL; @@ -1728,6 +1740,8 @@ static ULONG WINAPI unknown_inner_Release(IUnknown *iface)
reader->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&reader->cs); + reader->shutdown_cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&reader->shutdown_cs);
free(reader); } @@ -1781,7 +1795,9 @@ static HRESULT WINAPI reader_Close(IWMSyncReader2 *iface)
wg_parser_disconnect(reader->wg_parser);
+ EnterCriticalSection(&reader->shutdown_cs); reader->read_thread_shutdown = true; + LeaveCriticalSection(&reader->shutdown_cs); WaitForSingleObject(reader->read_thread, INFINITE); CloseHandle(reader->read_thread); reader->read_thread = NULL; @@ -2557,6 +2573,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->shutdown_cs); + object->shutdown_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": reader.shutdown_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 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 5c778ba2350..a92556e9aec 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1660,13 +1660,20 @@ static HRESULT wm_reader_read_stream_sample(struct wm_reader *reader, struct wg_
wg_parser_stream_release_buffer(stream->wg_stream);
+ *pts = buffer->pts; + *duration = buffer->duration; + if (!buffer->has_pts) + { FIXME("Missing PTS.\n"); + *pts = 0; + } if (!buffer->has_duration) + { FIXME("Missing duration.\n"); + *duration = 0; + }
- *pts = buffer->pts; - *duration = buffer->duration; *flags = 0; if (buffer->discontinuity) *flags |= WM_SF_DISCONTINUITY;
From: Alfred Agrell floating@muncher.se
--- dlls/winegstreamer/wm_reader.c | 78 ++++++++++++++++++++++++++++++---- dlls/wmvcore/tests/wmvcore.c | 61 ++++++++++++++++---------- 2 files changed, 108 insertions(+), 31 deletions(-)
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index a92556e9aec..e1bc7c8335a 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; @@ -1448,6 +1444,8 @@ static const IWMReaderTimecodeVtbl timecode_vtbl = timecode_GetTimecodeRangeBounds, };
+static void setup_stream_formats(struct wm_reader *reader); + static HRESULT init_stream(struct wm_reader *reader) { wg_parser_t wg_parser; @@ -1479,7 +1477,33 @@ static HRESULT init_stream(struct wm_reader *reader) hr = E_OUTOFMEMORY; goto out_disconnect_parser; } + for (i = 0; i < reader->stream_count; ++i) + reader->streams[i].selection = WMT_ON; + + setup_stream_formats(reader); + return S_OK; + +out_disconnect_parser: + wg_parser_disconnect(reader->wg_parser); + +out_shutdown_thread: + EnterCriticalSection(&reader->shutdown_cs); + reader->read_thread_shutdown = true; + LeaveCriticalSection(&reader->shutdown_cs); + WaitForSingleObject(reader->read_thread, INFINITE); + CloseHandle(reader->read_thread); + reader->read_thread = NULL;
+out_destroy_parser: + wg_parser_destroy(reader->wg_parser); + reader->wg_parser = 0; + + return hr; +} + +static void setup_stream_formats(struct wm_reader *reader) +{ + WORD i; for (i = 0; i < reader->stream_count; ++i) { struct wm_stream *stream = &reader->streams[i]; @@ -1487,7 +1511,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) { @@ -1513,19 +1536,57 @@ 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. * Now that they're all enabled seek back to the start again. */ wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, 0, 0, AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning); +}
- return S_OK; +static HRESULT reinit_stream(struct wm_reader *reader, bool read_compressed) +{ + wg_parser_t wg_parser; + HRESULT hr;
-out_disconnect_parser: wg_parser_disconnect(reader->wg_parser);
+ EnterCriticalSection(&reader->shutdown_cs); + reader->read_thread_shutdown = true; + LeaveCriticalSection(&reader->shutdown_cs); + WaitForSingleObject(reader->read_thread, INFINITE); + CloseHandle(reader->read_thread); + reader->read_thread = NULL; + + wg_parser_destroy(reader->wg_parser); + reader->wg_parser = 0; + + if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, read_compressed))) + return E_OUTOFMEMORY; + + reader->wg_parser = wg_parser; + reader->read_thread_shutdown = false; + + if (!(reader->read_thread = CreateThread(NULL, 0, read_thread, reader, 0, NULL))) + { + hr = E_OUTOFMEMORY; + goto out_destroy_parser; + } + + 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; + } + + assert(reader->stream_count == wg_parser_get_stream_count(reader->wg_parser)); + + setup_stream_formats(reader); + + return S_OK; + out_shutdown_thread: EnterCriticalSection(&reader->shutdown_cs); reader->read_thread_shutdown = true; @@ -2352,6 +2413,7 @@ static HRESULT WINAPI reader_SetReadStreamSamples(IWMSyncReader2 *iface, WORD st }
stream->read_compressed = compressed; + reinit_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..c1114b711f9 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -455,6 +455,7 @@ struct teststream HANDLE file; DWORD input_tid; DWORD main_tid; + DWORD input_tid_changes; };
static struct teststream *impl_from_IStream(IStream *iface) @@ -494,12 +495,10 @@ static HRESULT WINAPI stream_Read(IStream *iface, void *data, ULONG size, ULONG if (winetest_debug > 2) trace("%04lx: IStream::Read(size %lu)\n", GetCurrentThreadId(), size);
- if (!stream->input_tid) - stream->input_tid = GetCurrentThreadId(); - else + if (stream->input_tid != GetCurrentThreadId()) { - todo_wine_if(stream->input_tid == stream->main_tid) - ok(stream->input_tid == GetCurrentThreadId(), "got wrong thread\n"); + ++stream->input_tid_changes; + stream->input_tid = GetCurrentThreadId(); }
ok(size > 0, "Got zero size.\n"); @@ -523,12 +522,10 @@ static HRESULT WINAPI stream_Seek(IStream *iface, LARGE_INTEGER offset, DWORD me if (winetest_debug > 2) trace("%04lx: IStream::Seek(offset %I64u, method %#lx)\n", GetCurrentThreadId(), offset.QuadPart, method);
- if (!stream->input_tid) - stream->input_tid = GetCurrentThreadId(); - else + if (stream->input_tid != GetCurrentThreadId()) { - todo_wine_if(stream->input_tid == stream->main_tid) - ok(stream->input_tid == GetCurrentThreadId(), "got wrong thread\n"); + ++stream->input_tid_changes; + stream->input_tid = GetCurrentThreadId(); }
GetFileSizeEx(stream->file, &size); @@ -588,12 +585,10 @@ static HRESULT WINAPI stream_Stat(IStream *iface, STATSTG *stat, DWORD flags) if (winetest_debug > 1) trace("%04lx: IStream::Stat(flags %#lx)\n", GetCurrentThreadId(), flags);
- if (!stream->input_tid) - stream->input_tid = GetCurrentThreadId(); - else + if (stream->input_tid != GetCurrentThreadId()) { - todo_wine_if(stream->input_tid == stream->main_tid) - ok(stream->input_tid == GetCurrentThreadId(), "got wrong thread\n"); + ++stream->input_tid_changes; + stream->input_tid = GetCurrentThreadId(); }
ok(flags == STATFLAG_NONAME, "Got flags %#lx.\n", flags); @@ -1173,6 +1168,7 @@ static void test_sync_reader_settings(void) IWMSyncReader_Release(reader);
ok(stream.refcount == 1, "Got outstanding refcount %ld.\n", stream.refcount); + todo_wine ok(stream.input_tid_changes == 1, "Changed thread %ld times.\n", stream.input_tid_changes); CloseHandle(stream.file); ret = DeleteFileW(filename); ok(ret, "Failed to delete %s, error %lu.\n", debugstr_w(filename), GetLastError()); @@ -1404,7 +1400,6 @@ static void test_sync_reader_streaming(void)
ok(stream.refcount == 1, "Got outstanding refcount %ld.\n", stream.refcount);
- stream.input_tid = 0; /* FIXME: currently required as Wine calls IStream_Stat synchronously in OpenStream */ SetFilePointer(stream.file, 0, NULL, FILE_BEGIN); hr = IWMSyncReader_OpenStream(reader, &stream.IStream_iface); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -1415,6 +1410,7 @@ static void test_sync_reader_streaming(void) ok(!ref, "Got outstanding refcount %ld.\n", ref);
ok(stream.refcount == 1, "Got outstanding refcount %ld.\n", stream.refcount); + todo_wine ok(stream.input_tid_changes == 1, "Changed thread %ld times.\n", stream.input_tid_changes); CloseHandle(stream.file); ret = DeleteFileW(filename); ok(ret, "Failed to delete %s, error %lu.\n", debugstr_w(filename), GetLastError()); @@ -1775,6 +1771,7 @@ static void test_sync_reader_types(void) ok(!ref, "Got outstanding refcount %ld.\n", ref);
ok(stream.refcount == 1, "Got outstanding refcount %ld.\n", stream.refcount); + todo_wine ok(stream.input_tid_changes == 1, "Changed thread %ld times.\n", stream.input_tid_changes); CloseHandle(stream.file); ret = DeleteFileW(filename); ok(ret, "Failed to delete %s, error %lu.\n", debugstr_w(filename), GetLastError()); @@ -2053,7 +2050,7 @@ static HRESULT WINAPI callback_OnSample(IWMReaderCallback *iface, DWORD output, GetTickCount(), GetCurrentThreadId(), output, time, duration, flags);
/* 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 +2131,7 @@ 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); + 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 +2143,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]) @@ -2572,8 +2569,6 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st callback->last_pts[1] = 0; callback->next_pts[1] = 0; memset(callback->output_tid, 0, sizeof(callback->output_tid)); - if (callback->stream) - callback->stream->input_tid = 0;
check_async_set_output_setting(advanced, 0, L"DedicatedDeliveryThread", WMT_TYPE_BOOL, callback->dedicated_threads, S_OK); @@ -2709,6 +2704,17 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st todo_wine ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr);
+ /* FIXME: native can switch mode without rewinding, but Wine can't */ + IWMReader_Stop(reader); + wait_stopped_callback(callback); + callback->last_pts[0] = 0; + callback->next_pts[0] = 0; + callback->last_pts[1] = 0; + callback->next_pts[1] = 0; + hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + wait_started_callback(callback); + callback->expect_time = 13460000; hr = IWMReaderAdvanced2_DeliverTime(advanced, 13460000); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -2716,7 +2722,7 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st todo_wine ok(callback->last_pts[0] == 13460000, "Got pts %I64d.\n", callback->last_pts[0]); todo_wine - ok(callback->next_pts[0] == 13930000, "Got pts %I64d.\n", callback->next_pts[0]); + ok(callback->next_pts[0] == 13920000, "Got pts %I64d.\n", callback->next_pts[0]); todo_wine ok(callback->last_pts[1] == 13260000, "Got pts %I64d.\n", callback->last_pts[1]); todo_wine @@ -2729,6 +2735,16 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 2, TRUE); ok(hr == S_OK, "Got hr %#lx.\n", hr); + + IWMReader_Stop(reader); + wait_stopped_callback(callback); + callback->last_pts[0] = 0; + callback->next_pts[0] = 0; + callback->last_pts[1] = 0; + callback->next_pts[1] = 0; + hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + wait_started_callback(callback); }
callback->expect_time = test_wmv_duration * 2; @@ -3233,7 +3249,6 @@ static void test_async_reader_streaming(void) ok(callback.refcount > 1, "Got refcount %ld.\n", callback.refcount); wait_opened_callback(&callback);
- stream.input_tid = 0; /* FIXME: currently required as Wine calls IStream_Stat synchronously in OpenStream */ hr = IWMReaderAdvanced2_OpenStream(advanced, &stream.IStream_iface, &callback.IWMReaderCallback_iface, (void **)0xdeadbee0); ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr);
From: Alfred Agrell floating@muncher.se
--- dlls/wmvcore/tests/wmvcore.c | 214 +++++++++++++++++++++++++++++++++-- 1 file changed, 206 insertions(+), 8 deletions(-)
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index c1114b711f9..78868acad83 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -34,20 +34,32 @@ static const DWORD test_wmv_duration = 20460000;
HRESULT WINAPI WMCreateWriterPriv(IWMWriter **writer);
-static BOOL compare_media_types(const WM_MEDIA_TYPE *a, const WM_MEDIA_TYPE *b) +static BOOL compare_media_types(const WM_MEDIA_TYPE *a, const WM_MEDIA_TYPE *b, BOOL ignore_bitrate) { /* We can't use memcmp(), because WM_MEDIA_TYPE has a hole, which sometimes * contains junk. */ - - return IsEqualGUID(&a->majortype, &b->majortype) + BOOL equal = (IsEqualGUID(&a->majortype, &b->majortype) && IsEqualGUID(&a->subtype, &b->subtype) && a->bFixedSizeSamples == b->bFixedSizeSamples && a->bTemporalCompression == b->bTemporalCompression && a->lSampleSize == b->lSampleSize && IsEqualGUID(&a->formattype, &b->formattype) && a->pUnk == b->pUnk - && a->cbFormat == b->cbFormat - && !memcmp(a->pbFormat, b->pbFormat, a->cbFormat); + && a->cbFormat == b->cbFormat); + if (!equal) + return FALSE; + + if (ignore_bitrate) + { + size_t ignore_start = offsetof(VIDEOINFOHEADER, dwBitRate); + size_t ignore_end = ignore_start + sizeof(DWORD); + return !memcmp(a->pbFormat, b->pbFormat, ignore_start) + && !memcmp(a->pbFormat + ignore_end, b->pbFormat + ignore_end, a->cbFormat - ignore_end); + } + else + { + return !memcmp(a->pbFormat, b->pbFormat, a->cbFormat); + } }
static void init_audio_type(WM_MEDIA_TYPE *mt, const GUID *subtype, UINT bits, UINT channels, UINT rate) @@ -1720,7 +1732,7 @@ static void test_sync_reader_types(void) ret_size = sizeof(mt2_buffer); hr = IWMOutputMediaProps_GetMediaType(output_props2, mt2, &ret_size); ok(hr == S_OK, "Got hr %#lx.\n", hr); - ok(compare_media_types(mt, mt2), "Media types didn't match.\n"); + ok(compare_media_types(mt, mt2, FALSE), "Media types didn't match.\n");
ref = IWMOutputMediaProps_Release(output_props2); ok(!ref, "Got outstanding refcount %ld.\n", ref); @@ -1816,6 +1828,191 @@ 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, bool todo_bitrate) +{ + 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, todo_bitrate), "Media types didn't match.\n"); + if (todo_bitrate) + { + VIDEOINFOHEADER *vih1 = (void *)mt->pbFormat; + VIDEOINFOHEADER *vih2 = (void *)expected->pbFormat; + todo_wine ok(vih1->dwBitRate == vih2->dwBitRate, "Bitrates 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; + DWORD audio_idx = 0; + DWORD video_idx = 0; + IWMProfile *profile; + INSSBuffer *sample; + WORD stream_num; + HRESULT hr; + BYTE *data; + + 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); + + test_stream_output_type(profile, 1, &mt_wmv1, TRUE); + test_stream_output_type(profile, 2, &mt_msaudio1, FALSE); + + 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_wmv1, TRUE); + test_stream_output_type(profile, 2, &mt_msaudio1, FALSE); + + while (video_idx < 50 || audio_idx < 44) + { + DWORD next_video_time = 460000 + video_idx * 400000; + DWORD next_audio_time = audio_sample_times[audio_idx]; + + winetest_push_context("%lu/%lu", video_idx, audio_idx); + hr = IWMSyncReader_GetNextSample(reader, 0, &sample, &sample_time, &sample_duration, &flags, NULL, &stream_num); + ok(hr == S_OK, "Got hr %#lx.\n", 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, "Got hr %#lx.\n", hr); + + if (next_video_time <= next_audio_time) + { + ok(stream_num == 1, "Got %lu\n", (DWORD)stream_num); + ok(sample_time == next_video_time, "Expected %lu, got %lu\n", next_video_time, (DWORD)sample_time); + todo_wine ok(sample_duration == 10000, "Got %lu\n", (DWORD)sample_duration); + + if (video_idx == 0) + ok(flags == (WM_SF_CLEANPOINT|WM_SF_DISCONTINUITY), "Got %lu\n", flags); + else if (video_sample_sizes[video_idx] == 1117) + ok(flags == WM_SF_CLEANPOINT, "Got %lu\n", flags); + else + ok(flags == 0, "Got %lu\n", flags); + ok(bytes_count == video_sample_sizes[video_idx], + "Expected %lu, got %lu\n", video_sample_sizes[video_idx], bytes_count); + video_idx++; + } + else + { + ok(stream_num == 2, "Got %lu\n", (DWORD)stream_num); + ok(sample_time == next_audio_time, "Expected %lu, got %lu\n", next_audio_time, (DWORD)sample_time); + todo_wine ok(sample_duration == 460000, "Got %lu\n", (DWORD)sample_duration); + + if (audio_idx == 0) + todo_wine ok(flags == (WM_SF_CLEANPOINT|WM_SF_DISCONTINUITY), "Got %lu\n", flags); + else + todo_wine ok(flags == WM_SF_CLEANPOINT, "Got %lu\n", flags); + ok(bytes_count == 743, "Got %lu\n", bytes_count); + + audio_idx++; + } + + INSSBuffer_Release(sample); + winetest_pop_context(); + } + + 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; @@ -3555,7 +3752,7 @@ static void test_async_reader_types(void)
/* The sample size might differ. */ mt2->lSampleSize = mt->lSampleSize; - ok(compare_media_types(mt, mt2), "Media types didn't match.\n"); + ok(compare_media_types(mt, mt2, FALSE), "Media types didn't match.\n"); } else { @@ -3638,7 +3835,7 @@ static void test_async_reader_types(void) ret_size = sizeof(mt2_buffer); hr = IWMOutputMediaProps_GetMediaType(output_props2, mt2, &ret_size); ok(hr == S_OK, "Got hr %#lx.\n", hr); - ok(compare_media_types(mt, mt2), "Media types didn't match.\n"); + ok(compare_media_types(mt, mt2, FALSE), "Media types didn't match.\n");
ref = IWMOutputMediaProps_Release(output_props2); ok(!ref, "Got outstanding refcount %ld.\n", ref); @@ -3971,6 +4168,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();
Instead we should wrap lower level unix components, and combine optional WMV / WMA decoders (which I believe should now be more or less working) on the PE side like native does.
Possibly.
By "like native does" do you mean that native exposes its internal decoders somehow? I wasn't able to find any API to get at them, but I may have missed one.
That proposal would indeed solve a bunch of todos, but it may also have a performance impact; I don't know how much we copy things around when crossing the PE/Unix boundary.
There would unfortunately be some blitting involved. It'd be of uncompressed data, so it wouldn't be awful, but it does still add some latency.
There's also the latency of marshalling things across threads, and the extra Unix syscalls, and the fact that one GStreamer pipeline is easier to debug than two.
That said, it may still be the right thing to do. But I'm not sure that the solution in this patch series is particularly wrong either, or at least, it's not particularly ugly. (Of course, it hasn't quite reached its final form yet either.)
By "like native does" do you mean that native exposes its internal decoders somehow?
To my knowledge, it does not.
It's just the most obvious design. Microsoft isn't bound by the limitations of the GStreamer API, they have no reason to recreate the demuxer.
It'd be of uncompressed data
You mean compressed, right?
and the fact that one GStreamer pipeline is easier to debug than two
And three is even harder. Demuxer, video decoder, audio decoder. (Though any specific issue is unlikely to impact more than two.)
By "like native does" do you mean that native exposes its internal decoders somehow? I wasn't able to find any API to get at them, but I may have missed one.
A quick search tells me that it does, through the `IWMReaderAccelerator` and `IWMCodecAMVideoAccelerator` interfaces for DXVA, as documented in https://learn.microsoft.com/en-us/windows/win32/wmformat/enabling-directx-vi...
Gotta love those flaky tests...
Should I rerun until it passes, rebase daily and hope someone fixes them, or something else?
Gotta love those flaky tests...
Should I rerun until it passes, rebase daily and hope someone fixes them, or something else?
No, just make a note of which ones they are, make sure they aren't actually related, and then ignore them. We know we have flaky tests; it won't block merging.
On Sun Dec 3 22:55:07 2023 +0000, Zebediah Figura wrote:
Gotta love those flaky tests...
Should I rerun until it passes, rebase daily and hope someone fixes
them, or something else? No, just make a note of which ones they are, make sure they aren't actually related, and then ignore them. We know we have flaky tests; it won't block merging.
The failures are win32u:win32u and d3d10core:d3d10core, which have no reason to depend on anything in this MR, and also fail on several other recent MRs, so I'm confident they're unrelated.
The relevant tests are wmvcore:wmvcore, mf:transform, microkiri and Wagamama, and they're green. (There's a few GStreamer-CRITICAL in mf:transform, but they too are present in other MRs.)
On Sat Dec 2 01:04:50 2023 +0000, Alfred Agrell wrote:
changed this line in [version 9 of the diff](/wine/wine/-/merge_requests/4449/diffs?diff_id=87612&start_sha=25fe1583fbaba1798f2cd3700bbf546ba82d8263#17848a3145bd1a5c42dd4b7f68c6ad9e56f0804a_1941_1951)
I don't like messing with compare_media_types(), though. It should be possible to add the lines I mentioned *before* calling compare_media_types(). I.e. test_stream_output_type() would look like this:
``` hr = IWMMediaProps_GetMediaType(media_props, mt, &ret_size); ok(hr == S_OK, "Got hr %#lx.\n", hr); if (IsEqualGUID(&expected->subtype, &MEDIASUBTYPE_WMV1)) { const VIDEOINFOHEADER *expect_vih = (const void *)expected->pbFormat; VIDEOINFOHEADER *vih = (void *)mt->pbFormat; todo_wine ok(vih->dwBitRate == expect_vih->dwBitRate, "Expected bit rate %lu, got %lu.\n", expect_vih->dwBitRate, vih->dwBitRate); vih->dwBitRate = expect_vih->dwBitRate; } ok(compare_media_types(mt, expected), "Media types didn't match.\n"); ```
This is probably one of those things that will never affect a real application, but I can't help noticing anyway because of the way this is currently implemented: is it correct that toggling compressed output on and back off again will reset the stream format?
On Mon Dec 4 21:21:47 2023 +0000, Zebediah Figura wrote:
I don't like messing with compare_media_types(), though. It should be possible to add the lines I mentioned *before* calling compare_media_types(). I.e. test_stream_output_type() would look like this:
hr = IWMMediaProps_GetMediaType(media_props, mt, &ret_size); ok(hr == S_OK, "Got hr %#lx.\n", hr); if (IsEqualGUID(&expected->subtype, &MEDIASUBTYPE_WMV1)) { const VIDEOINFOHEADER *expect_vih = (const void *)expected->pbFormat; VIDEOINFOHEADER *vih = (void *)mt->pbFormat; todo_wine ok(vih->dwBitRate == expect_vih->dwBitRate, "Expected bit rate %lu, got %lu.\n", expect_vih->dwBitRate, vih->dwBitRate); vih->dwBitRate = expect_vih->dwBitRate; } ok(compare_media_types(mt, expected), "Media types didn't match.\n");
There's 200 ways to write any given piece of code.
I saw that one of the media types is const, and went for something that doesn't change them ...and forgot that the other media type is created in this function, and is safe to change. Yep, let's do that instead, much cleaner.
On Tue Dec 5 00:13:48 2023 +0000, Zebediah Figura wrote:
This is probably one of those things that will never affect a real application, but I can't help noticing anyway because of the way this is currently implemented: is it correct that toggling compressed output on and back off again will reset the stream format?
No, it's not.
Setting compressed output to on then off is indeed implausible, but simply setting it to off is slightly less implausible, and hits the same codepath. (Slightly. It makes more sense to configure important/early pieces, like output compression, before details, like output pixel format.)
Either way, fixed.