Supersedes !8183.
JR East Train Simulator's IMFByteStream implementation relies on the following two properties: - Reads are always aligned on a 256KiB boundary. - Reads are never larger than 256KiB.
When chunking was initially benchmarked[1], a chunk size of 512KiB only performed marginally better than 256KiB, so this change has a negligible performance impact while being more correct.
I'm testing using a WAV handler here because it's easy to create the data for it in memory (avoids including a large video file in git), but the same behavior can be observed with other handlers, such as MP4.
[1] https://gitlab.winehq.org/wine/wine/-/merge_requests/2390#note_27314
From: Charlotte Pabst cpabst@codeweavers.com
Some games rely on this constant. --- dlls/mfsrcsnk/tests/mfsrcsnk.c | 281 +++++++++++++++++++++++++++++++++ 1 file changed, 281 insertions(+)
diff --git a/dlls/mfsrcsnk/tests/mfsrcsnk.c b/dlls/mfsrcsnk/tests/mfsrcsnk.c index 03d206a5f55..41fc652c77d 100644 --- a/dlls/mfsrcsnk/tests/mfsrcsnk.c +++ b/dlls/mfsrcsnk/tests/mfsrcsnk.c @@ -824,6 +824,286 @@ static void test_thinning(void) IMFMediaSource_Release(source); }
+struct bufsize_test_byte_stream +{ + IMFByteStream iface; + ULONG refcount; + + IMFByteStream *inner; +}; + +static struct bufsize_test_byte_stream *bufsize_test_byte_stream_from_iface(IMFByteStream *iface) +{ + return (struct bufsize_test_byte_stream *) iface; +} + +static HRESULT WINAPI bufsize_test_byte_stream_QueryInterface(IMFByteStream *iface, REFIID riid, void **obj) +{ + struct bufsize_test_byte_stream *stream = bufsize_test_byte_stream_from_iface(iface); + + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMFByteStream)) + { + *obj = &stream->iface; + IMFByteStream_AddRef(iface); + return S_OK; + } + + return IMFByteStream_QueryInterface(stream->inner, riid, obj); +} + +static ULONG WINAPI bufsize_test_byte_stream_AddRef(IMFByteStream *iface) +{ + return ++bufsize_test_byte_stream_from_iface(iface)->refcount; +} + +static ULONG WINAPI bufsize_test_byte_stream_Release(IMFByteStream *iface) +{ + struct bufsize_test_byte_stream *stream = bufsize_test_byte_stream_from_iface(iface); + ULONG rc = --stream->refcount; + if (rc == 0) { + IMFByteStream_Release(stream->inner); + free(stream); + } + return rc; +} + +static HRESULT WINAPI bufsize_test_byte_stream_GetCapabilities(IMFByteStream *iface, DWORD *pdwCapabilities) +{ + return IMFByteStream_GetCapabilities(bufsize_test_byte_stream_from_iface(iface)->inner, pdwCapabilities); +} + +static HRESULT WINAPI bufsize_test_byte_stream_GetLength(IMFByteStream *iface, QWORD *pqwLength) +{ + return IMFByteStream_GetLength(bufsize_test_byte_stream_from_iface(iface)->inner, pqwLength); +} + +static HRESULT WINAPI bufsize_test_byte_stream_SetLength(IMFByteStream *iface, QWORD qwLength) +{ + return IMFByteStream_SetLength(bufsize_test_byte_stream_from_iface(iface)->inner, qwLength); +} + +static HRESULT WINAPI bufsize_test_byte_stream_GetCurrentPosition(IMFByteStream *iface, QWORD *pqwPosition) +{ + return IMFByteStream_GetCurrentPosition(bufsize_test_byte_stream_from_iface(iface)->inner, pqwPosition); +} + +static HRESULT WINAPI bufsize_test_byte_stream_SetCurrentPosition(IMFByteStream *iface, QWORD qwPosition) +{ + todo_wine_if(!(qwPosition % 0x40000 == 0)) + ok(qwPosition % 0x40000 == 0, "IMFByteStream::SetCurrentPosition pos=%lld should be aligned on 0x40000 boundary.\n", qwPosition); + return IMFByteStream_SetCurrentPosition(bufsize_test_byte_stream_from_iface(iface)->inner, qwPosition); +} + +static HRESULT WINAPI bufsize_test_byte_stream_IsEndOfStream(IMFByteStream *iface, BOOL *pfEndOfStream) +{ + return IMFByteStream_IsEndOfStream(bufsize_test_byte_stream_from_iface(iface)->inner, pfEndOfStream); +} + +static HRESULT WINAPI bufsize_test_byte_stream_Read(IMFByteStream *iface, BYTE* pb, ULONG cb, ULONG *pcbRead) +{ + QWORD current = 0; + IMFByteStream_GetCurrentPosition(bufsize_test_byte_stream_from_iface(iface)->inner, ¤t); + todo_wine_if(!(current % 0x40000 == 0)) + ok(current % 0x40000 == 0, "IMFByteStream::Read pos=%lld should be aligned on 0x40000 boundary.\n", current); + todo_wine_if(!(cb <= 0x40000)) + ok(cb <= 0x40000, "IMFByteStream::BeginRead size=%lu should not be larger than 0x40000.\n", cb); + return IMFByteStream_Read(bufsize_test_byte_stream_from_iface(iface)->inner, pb, cb, pcbRead); +} + +static HRESULT WINAPI bufsize_test_byte_stream_BeginRead(IMFByteStream *iface, BYTE *pb, ULONG cb, IMFAsyncCallback *pCallback, IUnknown *punkState) +{ + QWORD current = 0; + IMFByteStream_GetCurrentPosition(bufsize_test_byte_stream_from_iface(iface)->inner, ¤t); + todo_wine_if(!(current % 0x40000 == 0)) + ok(current % 0x40000 == 0, "IMFByteStream::BeginRead pos=%lld should be aligned on 0x40000 boundary.\n", current); + todo_wine_if(!(cb <= 0x40000)) + ok(cb <= 0x40000, "IMFByteStream::BeginRead size=%lu should not be larger than 0x40000.\n", cb); + return IMFByteStream_BeginRead(bufsize_test_byte_stream_from_iface(iface)->inner, pb, cb, pCallback, punkState); +} + +static HRESULT WINAPI bufsize_test_byte_stream_EndRead(IMFByteStream *iface, IMFAsyncResult *pResult, ULONG *pcbRead) +{ + return IMFByteStream_EndRead(bufsize_test_byte_stream_from_iface(iface)->inner, pResult, pcbRead); +} + +static HRESULT WINAPI bufsize_test_byte_stream_Write(IMFByteStream *iface, const BYTE *pb, ULONG cb, ULONG *pcbWritten) +{ + return IMFByteStream_Write(bufsize_test_byte_stream_from_iface(iface)->inner, pb, cb, pcbWritten); +} + +static HRESULT WINAPI bufsize_test_byte_stream_BeginWrite(IMFByteStream *iface, const BYTE *pb, ULONG cb, IMFAsyncCallback *pCallback, IUnknown *punkState) +{ + return IMFByteStream_BeginWrite(bufsize_test_byte_stream_from_iface(iface)->inner, pb, cb, pCallback, punkState); +} + +static HRESULT WINAPI bufsize_test_byte_stream_EndWrite(IMFByteStream *iface, IMFAsyncResult *pResult, ULONG *pcbWritten) +{ + return IMFByteStream_EndWrite(bufsize_test_byte_stream_from_iface(iface)->inner, pResult, pcbWritten); +} + +static HRESULT WINAPI bufsize_test_byte_stream_Seek(IMFByteStream *iface, MFBYTESTREAM_SEEK_ORIGIN SeekOrigin, LONGLONG llSeekOffset, DWORD dwSeekFlags, QWORD *pqwCurrentPosition) +{ + HRESULT hr = IMFByteStream_Seek(bufsize_test_byte_stream_from_iface(iface)->inner, SeekOrigin, llSeekOffset, dwSeekFlags, pqwCurrentPosition); + + QWORD current = 0; + IMFByteStream_GetCurrentPosition(bufsize_test_byte_stream_from_iface(iface)->inner, ¤t); + todo_wine_if(!(current % 0x40000 == 0)) + ok(current % 0x40000 == 0, "IMFByteStream::Seek pos=%lld should be aligned on 0x40000 boundary.\n", current); + return hr; +} + +static HRESULT WINAPI bufsize_test_byte_stream_Flush(IMFByteStream *iface) +{ + return IMFByteStream_Flush(bufsize_test_byte_stream_from_iface(iface)->inner); +} + +static HRESULT WINAPI bufsize_test_byte_stream_Close(IMFByteStream *iface) +{ + return IMFByteStream_Close(bufsize_test_byte_stream_from_iface(iface)->inner); +} + +static const IMFByteStreamVtbl bufsize_test_byte_stream_vtbl = { + bufsize_test_byte_stream_QueryInterface, + bufsize_test_byte_stream_AddRef, + bufsize_test_byte_stream_Release, + bufsize_test_byte_stream_GetCapabilities, + bufsize_test_byte_stream_GetLength, + bufsize_test_byte_stream_SetLength, + bufsize_test_byte_stream_GetCurrentPosition, + bufsize_test_byte_stream_SetCurrentPosition, + bufsize_test_byte_stream_IsEndOfStream, + bufsize_test_byte_stream_Read, + bufsize_test_byte_stream_BeginRead, + bufsize_test_byte_stream_EndRead, + bufsize_test_byte_stream_Write, + bufsize_test_byte_stream_BeginWrite, + bufsize_test_byte_stream_EndWrite, + bufsize_test_byte_stream_Seek, + bufsize_test_byte_stream_Flush, + bufsize_test_byte_stream_Close, +}; + +static IMFByteStream *create_bufsize_test_byte_stream(IMFByteStream *inner) +{ + struct bufsize_test_byte_stream *stream = calloc(1, sizeof *stream); + stream->iface.lpVtbl = &bufsize_test_byte_stream_vtbl; + stream->refcount = 1; + stream->inner = inner; + + return &stream->iface; +} + +static void test_source_buffer_size(void) +{ + /* using WAV source as example - but this should hold for any of our builtin sources */ + static const GUID CLSID_WAVByteStreamHandler = {0x42c9b9f5,0x16fc,0x47ef,{0xaf,0x22,0xda,0x05,0xf7,0xc8,0x42,0xe3}}; + static const ULONG sizes[3] = + { + 0x5000, /* smaller */ + 0x50000, /* larger */ + 0x500000, /* much larger */ + }; + IMFByteStream *byte_stream; + IMFMediaSource *source; + IMFMediaStream *stream; + IMFPresentationDescriptor *pres_desc; + IMFAsyncCallback *callback; + PROPVARIANT propvar; + HRESULT hr; + + for (UINT i = 0; i < 3; i++) + { + ULONG read_size = 0, wav_size = sizes[i]; + BYTE *wav_data = calloc(wav_size, 1); + + const BYTE header[] = { +#define EMBED_U32(X) (X) & 0xff, ((X) >> 8) & 0xff, ((X) >> 16) & 0xff, ((X) >> 24) & 0xff +#define EMBED_U16(X) (X) & 0xff, ((X) >> 8) & 0xff + 'R', 'I', 'F', 'F', + EMBED_U32(wav_size - 8), + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + EMBED_U32(16), + EMBED_U16(1), /* PCM */ + EMBED_U16(1), /* channels */ + EMBED_U32(48000), /* rate */ + EMBED_U32((48000*8*1)/8), /* bytes per second */ + EMBED_U16((8*1)/8), /* block alignment */ + EMBED_U16(8), /* bits per sample */ + 'd', 'a', 't', 'a', + EMBED_U32(wav_size - 44), +#undef EMBED_U16 +#undef EMBED_U32 + }; + _Static_assert(sizeof header == 44); + + memcpy(wav_data, header, sizeof header); + + byte_stream = create_byte_stream(wav_data, wav_size); + byte_stream = create_bufsize_test_byte_stream(byte_stream); + + free(wav_data); + + hr = create_source(&CLSID_WAVByteStreamHandler, byte_stream, &source); + if (FAILED(hr)) + { + win_skip("Failed to create WAV source: %#lx.\n", hr); + return; + } + + hr = IMFMediaSource_CreatePresentationDescriptor(source, &pres_desc); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + propvar.vt = VT_EMPTY; + hr = IMFMediaSource_Start(source, pres_desc, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFPresentationDescriptor_Release(pres_desc); + + callback = create_test_callback(TRUE); + + hr = wait_media_event(source, callback, MENewStream, 100, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); + stream = (IMFMediaStream *)propvar.punkVal; + IMFMediaStream_AddRef(stream); + PropVariantClear(&propvar); + + hr = wait_media_event(source, callback, MESourceStarted, 100, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = wait_media_event(stream, callback, MEStreamStarted, 100, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + while (read_size < wav_size - sizeof header) + { + IMFSample *sample; + DWORD size; + if ((hr = IMFMediaStream_RequestSample(stream, NULL)) != S_OK) break; + if ((hr = wait_media_event(stream, callback, MEMediaSample, 100, &propvar)) != S_OK) break; + if ((hr = IUnknown_QueryInterface(propvar.punkVal, &IID_IMFSample, (void **) &sample)) != S_OK) break; + if ((hr = IMFSample_GetTotalLength(sample, &size)) != S_OK) break; + read_size += size; + IMFSample_Release(sample); + PropVariantClear(&propvar); + } + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(read_size == wav_size - sizeof header, "Incomplete bytes read: %lu.\n", read_size); + + hr = IMFMediaSource_Stop(source); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(source, callback, MESourceStopped, 100, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + hr = wait_media_event(stream, callback, MEStreamStopped, 100, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + + IMFMediaSource_Release(source); + IMFMediaStream_Release(stream); + IMFAsyncCallback_Release(callback); + IMFByteStream_Release(byte_stream); + } +} + START_TEST(mfsrcsnk) { HRESULT hr; @@ -833,6 +1113,7 @@ START_TEST(mfsrcsnk)
test_wave_sink(); test_thinning(); + test_source_buffer_size();
hr = MFShutdown(); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
From: Charlotte Pabst cpabst@codeweavers.com
--- dlls/mfsrcsnk/tests/mfsrcsnk.c | 6 ------ dlls/winegstreamer/wg_parser.c | 5 +---- 2 files changed, 1 insertion(+), 10 deletions(-)
diff --git a/dlls/mfsrcsnk/tests/mfsrcsnk.c b/dlls/mfsrcsnk/tests/mfsrcsnk.c index 41fc652c77d..7f27214d586 100644 --- a/dlls/mfsrcsnk/tests/mfsrcsnk.c +++ b/dlls/mfsrcsnk/tests/mfsrcsnk.c @@ -889,7 +889,6 @@ static HRESULT WINAPI bufsize_test_byte_stream_GetCurrentPosition(IMFByteStream
static HRESULT WINAPI bufsize_test_byte_stream_SetCurrentPosition(IMFByteStream *iface, QWORD qwPosition) { - todo_wine_if(!(qwPosition % 0x40000 == 0)) ok(qwPosition % 0x40000 == 0, "IMFByteStream::SetCurrentPosition pos=%lld should be aligned on 0x40000 boundary.\n", qwPosition); return IMFByteStream_SetCurrentPosition(bufsize_test_byte_stream_from_iface(iface)->inner, qwPosition); } @@ -903,9 +902,7 @@ static HRESULT WINAPI bufsize_test_byte_stream_Read(IMFByteStream *iface, BYTE* { QWORD current = 0; IMFByteStream_GetCurrentPosition(bufsize_test_byte_stream_from_iface(iface)->inner, ¤t); - todo_wine_if(!(current % 0x40000 == 0)) ok(current % 0x40000 == 0, "IMFByteStream::Read pos=%lld should be aligned on 0x40000 boundary.\n", current); - todo_wine_if(!(cb <= 0x40000)) ok(cb <= 0x40000, "IMFByteStream::BeginRead size=%lu should not be larger than 0x40000.\n", cb); return IMFByteStream_Read(bufsize_test_byte_stream_from_iface(iface)->inner, pb, cb, pcbRead); } @@ -914,9 +911,7 @@ static HRESULT WINAPI bufsize_test_byte_stream_BeginRead(IMFByteStream *iface, B { QWORD current = 0; IMFByteStream_GetCurrentPosition(bufsize_test_byte_stream_from_iface(iface)->inner, ¤t); - todo_wine_if(!(current % 0x40000 == 0)) ok(current % 0x40000 == 0, "IMFByteStream::BeginRead pos=%lld should be aligned on 0x40000 boundary.\n", current); - todo_wine_if(!(cb <= 0x40000)) ok(cb <= 0x40000, "IMFByteStream::BeginRead size=%lu should not be larger than 0x40000.\n", cb); return IMFByteStream_BeginRead(bufsize_test_byte_stream_from_iface(iface)->inner, pb, cb, pCallback, punkState); } @@ -947,7 +942,6 @@ static HRESULT WINAPI bufsize_test_byte_stream_Seek(IMFByteStream *iface, MFBYTE
QWORD current = 0; IMFByteStream_GetCurrentPosition(bufsize_test_byte_stream_from_iface(iface)->inner, ¤t); - todo_wine_if(!(current % 0x40000 == 0)) ok(current % 0x40000 == 0, "IMFByteStream::Seek pos=%lld should be aligned on 0x40000 boundary.\n", current); return hr; } diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 1a29015356e..6880cfd410e 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -97,7 +97,7 @@ struct wg_parser
struct input_cache_chunk input_cache_chunks[4]; }; -static const unsigned int input_cache_chunk_size = 512 << 10; +static const unsigned int input_cache_chunk_size = 256 << 10;
struct wg_parser_stream { @@ -1245,9 +1245,6 @@ static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, return GST_FLOW_OK; }
- if (size >= input_cache_chunk_size || sizeof(void*) == 4) - return issue_read_request(parser, offset, size, buffer); - if (offset >= parser->file_size) return GST_FLOW_EOS;