From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/quartz/tests/avidec.c | 144 ++++++++++++++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 1 deletion(-)
diff --git a/dlls/quartz/tests/avidec.c b/dlls/quartz/tests/avidec.c index 00e1f44fbd3..5dc94f9e775 100644 --- a/dlls/quartz/tests/avidec.c +++ b/dlls/quartz/tests/avidec.c @@ -1,7 +1,8 @@ /* * AVI decompressor filter unit tests * - * Copyright 2018 Zebediah Figura + * Copyright 2018-2021 Elizabeth Figura + * Copyright 2025 Elizabeth Figura for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -1047,6 +1048,145 @@ static void test_sink_allocator(IMemInputPin *input) IMemAllocator_Release(ret_allocator); }
+static void test_source_allocator(IFilterGraph2 *graph, IMediaControl *control, + IPin *sink, IPin *source, struct testfilter *testsource, struct testfilter *testsink) +{ + ALLOCATOR_PROPERTIES props, req_props = {2, 30000, 32, 0}; + IMemAllocator *allocator; + IMediaSample *sample; + HRESULT hr; + + VIDEOINFOHEADER sink_format = + { + .bmiHeader.biSize = sizeof(BITMAPINFOHEADER), + .bmiHeader.biCompression = test_handler, + .bmiHeader.biWidth = 29, + .bmiHeader.biHeight = -24, + .bmiHeader.biBitCount = 16, + }; + AM_MEDIA_TYPE sink_mt = + { + .majortype = MEDIATYPE_Video, + .subtype = test_subtype, + .formattype = FORMAT_VideoInfo, + .lSampleSize = 888, + .cbFormat = sizeof(sink_format), + .pbFormat = (BYTE *)&sink_format, + }; + + VIDEOINFOHEADER source_format = + { + .bmiHeader.biSize = sizeof(BITMAPINFOHEADER), + .bmiHeader.biCompression = mmioFOURCC('I','4','2','0'), + .bmiHeader.biWidth = 29, + .bmiHeader.biHeight = -24, + .bmiHeader.biBitCount = 12, + .bmiHeader.biPlanes = 1, + .bmiHeader.biSizeImage = 123, + }; + AM_MEDIA_TYPE source_mt = + { + .majortype = MEDIATYPE_Video, + .subtype = MEDIASUBTYPE_I420, + .formattype = FORMAT_VideoInfo, + .bFixedSizeSamples = TRUE, + .lSampleSize = 999, + .cbFormat = sizeof(source_format), + .pbFormat = (BYTE *)&source_format, + }; + + hr = IFilterGraph2_ConnectDirect(graph, &testsource->source.pin.IPin_iface, sink, &sink_mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &source_mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + ok(!!testsink->sink.pAllocator, "Expected an allocator.\n"); + hr = IMemAllocator_GetProperties(testsink->sink.pAllocator, &props); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(props.cBuffers == 1, "Got %ld buffers.\n", props.cBuffers); + todo_wine ok(props.cbBuffer == 999, "Got size %ld.\n", props.cbBuffer); + ok(props.cbAlign == 1, "Got alignment %ld.\n", props.cbAlign); + ok(!props.cbPrefix, "Got prefix %ld.\n", props.cbPrefix); + + hr = IMemAllocator_GetBuffer(testsink->sink.pAllocator, &sample, NULL, NULL, 0); + ok(hr == VFW_E_NOT_COMMITTED, "Got hr %#lx.\n", hr); + + sink_bitmap_info = sink_format.bmiHeader; + source_bitmap_info = source_format.bmiHeader; + + hr = IMediaControl_Pause(control); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IMemAllocator_GetBuffer(testsink->sink.pAllocator, &sample, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + if (hr == S_OK) + IMediaSample_Release(sample); + + hr = IMediaControl_Stop(control); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IMemAllocator_GetBuffer(testsink->sink.pAllocator, &sample, NULL, NULL, 0); + ok(hr == VFW_E_NOT_COMMITTED, "Got hr %#lx.\n", hr); + + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface); + + /* Evidently setting bFixedSizeSamples to FALSE means the AVI decompressor + * won't set a sample size at all. The AVI decompressor will never propose + * a media type with bFixedSizeSamples set to FALSE, and conceptually isn't + * supposed to handle that case, but it won't reject it either. Presumably + * it then expects the downstream filter to be the one setting up the + * allocator. Not that this is documented or normal behaviour, of course. */ + source_mt.bFixedSizeSamples = FALSE; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &source_mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + ok(!!testsink->sink.pAllocator, "Expected an allocator.\n"); + hr = IMemAllocator_GetProperties(testsink->sink.pAllocator, &props); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(props.cBuffers == 1, "Got %ld buffers.\n", props.cBuffers); + todo_wine ok(!props.cbBuffer, "Got size %ld.\n", props.cbBuffer); + ok(props.cbAlign == 1, "Got alignment %ld.\n", props.cbAlign); + ok(!props.cbPrefix, "Got prefix %ld.\n", props.cbPrefix); + + hr = IMediaControl_Pause(control); + todo_wine ok(hr == VFW_E_SIZENOTSET, "Got hr %#lx.\n", hr); + if (hr == S_OK) + { + hr = IMediaControl_Stop(control); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + } + + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface); + source_mt.bFixedSizeSamples = TRUE; + + CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, + &IID_IMemAllocator, (void **)&allocator); + testsink->sink.pAllocator = allocator; + + hr = IMemAllocator_SetProperties(allocator, &req_props, &props); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &source_mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + ok(testsink->sink.pAllocator == allocator, "Expected an allocator.\n"); + hr = IMemAllocator_GetProperties(testsink->sink.pAllocator, &props); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(props.cBuffers == 1, "Got %ld buffers.\n", props.cBuffers); + todo_wine ok(props.cbBuffer == 999, "Got size %ld.\n", props.cbBuffer); + ok(props.cbAlign == 1, "Got alignment %ld.\n", props.cbAlign); + ok(!props.cbPrefix, "Got prefix %ld.\n", props.cbPrefix); + + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface); + + IFilterGraph2_Disconnect(graph, sink); + IFilterGraph2_Disconnect(graph, &testsource->source.pin.IPin_iface); +} + static void test_sample_processing(IMediaControl *control, IMemInputPin *input, struct testfilter *sink) { REFERENCE_TIME start, stop; @@ -1288,6 +1428,8 @@ static void test_connect_pin(void) IPin_QueryInterface(sink, &IID_IMemInputPin, (void **)&meminput); IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
+ test_source_allocator(graph, control, sink, source, &testsource, &testsink); + /* Test sink connection. */
peer = (IPin *)0xdeadbeef;
From: Elizabeth Figura zfigura@codeweavers.com
There's no reason to do this, and it breaks on amstream's custom allocator, which fails when setting the data length to anything other than the sample size. --- dlls/quartz/avidec.c | 3 --- 1 file changed, 3 deletions(-)
diff --git a/dlls/quartz/avidec.c b/dlls/quartz/avidec.c index 6377b7b597a..1f89687506c 100644 --- a/dlls/quartz/avidec.c +++ b/dlls/quartz/avidec.c @@ -149,9 +149,6 @@ static HRESULT WINAPI avi_decompressor_sink_Receive(struct strmbase_sink *iface, return hr; }
- hr = IMediaSample_SetActualDataLength(pOutSample, 0); - assert(hr == S_OK); - hr = IMediaSample_GetPointer(pOutSample, &pbDstStream); if (FAILED(hr)) { ERR("Failed to get output buffer pointer, hr %#lx.\n", hr);
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/quartz/tests/avidec.c | 377 +++++++++++++++++++++++++++++++++++-- 1 file changed, 366 insertions(+), 11 deletions(-)
diff --git a/dlls/quartz/tests/avidec.c b/dlls/quartz/tests/avidec.c index 5dc94f9e775..902b1566638 100644 --- a/dlls/quartz/tests/avidec.c +++ b/dlls/quartz/tests/avidec.c @@ -153,14 +153,15 @@ static LRESULT CALLBACK vfw_driver_proc(DWORD_PTR id, HDRVR driver, UINT msg, expect_sink_format.biSizeImage = 200; ok(!memcmp(params->lpbiInput, &expect_sink_format, sizeof(BITMAPINFOHEADER)), "Input types didn't match.\n"); - ok(!memcmp(params->lpbiOutput, &source_bitmap_info, sizeof(BITMAPINFOHEADER)), - "Output types didn't match.\n"); + todo_wine_if (testmode == 8) + ok(!memcmp(params->lpbiOutput, &source_bitmap_info, sizeof(BITMAPINFOHEADER)), + "Output types didn't match.\n"); ok(!params->ckid, "Got chunk id %#lx.\n", params->ckid);
for (i = 0; i < 200; ++i) expect[i] = i; ok(!memcmp(params->lpInput, expect, 200), "Data didn't match.\n"); - for (i = 0; i < 24 * (((29 * 12 + 31) / 8) & ~3); ++i) + for (i = 0; i < source_bitmap_info.biSizeImage; ++i) output[i] = 111 - i;
return ICERR_OK; @@ -799,6 +800,11 @@ struct testfilter struct strmbase_sink sink; const AM_MEDIA_TYPE *mt; unsigned int got_sample, got_new_segment, got_eos, got_begin_flush, got_end_flush; + IMemAllocator IMemAllocator_iface; + IMemAllocator *wrapped_allocator; + + IMediaSample IMediaSample_iface; + IMediaSample *wrapped_sample; };
static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface) @@ -891,26 +897,33 @@ static DWORD WINAPI call_qc_notify(void *ptr) static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample *sample) { struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter); - BYTE *data, expect[24 * (((29 * 12 + 31) / 8) & ~3)]; REFERENCE_TIME start, stop; + BYTE *data, *expect; + AM_MEDIA_TYPE *mt; LONG size, i; HRESULT hr;
++filter->got_sample;
size = IMediaSample_GetSize(sample); - ok(size == 24 * (((29 * 12 + 31) / 8) & ~3), "Got size %lu.\n", size); + if (testmode == 8) + ok(size == 321, "Got size %lu.\n", size); + else + ok(size == source_bitmap_info.biSizeImage, "Got size %lu.\n", size); size = IMediaSample_GetActualDataLength(sample); - ok(size == 24 * (((29 * 12 + 31) / 8) & ~3), "Got valid size %lu.\n", size); + todo_wine_if (testmode == 8) + ok(size == source_bitmap_info.biSizeImage, "Got valid size %lu.\n", size);
hr = IMediaSample_GetPointer(sample, &data); ok(hr == S_OK, "Got hr %#lx.\n", hr); + expect = malloc(size); for (i = 0; i < size; ++i) expect[i] = 111 - i; ok(!memcmp(data, expect, size), "Data didn't match.\n"); + free(expect);
hr = IMediaSample_GetTime(sample, &start, &stop); - if (testmode == 0) + if (testmode == 0 || testmode == 8) { ok(hr == VFW_E_SAMPLE_TIME_NOT_SET, "Got hr %#lx.\n", hr); } @@ -935,6 +948,12 @@ static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample hr = IMediaSample_IsSyncPoint(sample); todo_wine_if (testmode == 5 || testmode == 6) ok(hr == S_OK, "Got hr %#lx.\n", hr);
+ hr = IMediaSample_GetMediaType(sample, &mt); + if (testmode == 8) + ok(hr == S_OK, "Got hr %#lx.\n", hr); + else + ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + if (testmode == 7) { HANDLE h = CreateThread(NULL, 0, call_qc_notify, filter, 0, NULL); @@ -989,6 +1008,276 @@ static const struct strmbase_sink_ops testsink_ops = .sink_end_flush = testsink_end_flush, };
+static struct testfilter *impl_from_IMediaSample(IMediaSample *iface) +{ + return CONTAINING_RECORD(iface, struct testfilter, IMediaSample_iface); +} + +static HRESULT WINAPI sample_QueryInterface(IMediaSample *iface, REFIID iid, void **out) +{ + ok(IsEqualGUID(iid, &IID_IMediaSample2), "Got unexpected IID %s.\n", debugstr_guid(iid)); + return E_NOTIMPL; +} + +static ULONG WINAPI sample_AddRef(IMediaSample *iface) +{ + return 2; +} + +static ULONG WINAPI sample_Release(IMediaSample *iface) +{ + return 1; +} + +static HRESULT WINAPI sample_GetPointer(IMediaSample *iface, BYTE **data) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_GetPointer(filter->wrapped_sample, data); +} + +static LONG WINAPI sample_GetSize(IMediaSample *iface) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_GetSize(filter->wrapped_sample); +} + +static HRESULT WINAPI sample_GetTime(IMediaSample *iface, REFERENCE_TIME *start, REFERENCE_TIME *end) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_GetTime(filter->wrapped_sample, start, end); +} + +static HRESULT WINAPI sample_SetTime(IMediaSample *iface, REFERENCE_TIME *start, REFERENCE_TIME *end) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_SetTime(filter->wrapped_sample, start, end); +} + +static HRESULT WINAPI sample_IsSyncPoint(IMediaSample *iface) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_IsSyncPoint(filter->wrapped_sample); +} + +static HRESULT WINAPI sample_SetSyncPoint(IMediaSample *iface, BOOL sync_point) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_SetSyncPoint(filter->wrapped_sample, sync_point); +} + +static HRESULT WINAPI sample_IsPreroll(IMediaSample *iface) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_IsPreroll(filter->wrapped_sample); +} + +static HRESULT WINAPI sample_SetPreroll(IMediaSample *iface, BOOL preroll) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_SetPreroll(filter->wrapped_sample, preroll); +} + +static LONG WINAPI sample_GetActualDataLength(IMediaSample *iface) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_GetActualDataLength(filter->wrapped_sample); +} + +static HRESULT WINAPI sample_SetActualDataLength(IMediaSample *iface, LONG size) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + if (winetest_debug > 1) trace("SetActualDataLength(%ld)\n", size); + + todo_wine ok(size == 222, "Got size %ld.\n", size); + + IMediaSample_SetActualDataLength(filter->wrapped_sample, size); + return E_FAIL; +} + +static HRESULT WINAPI sample_GetMediaType(IMediaSample *iface, AM_MEDIA_TYPE **mt) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_GetMediaType(filter->wrapped_sample, mt); +} + +static HRESULT WINAPI sample_SetMediaType(IMediaSample *iface, AM_MEDIA_TYPE *mt) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_IsDiscontinuity(IMediaSample *iface) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_IsDiscontinuity(filter->wrapped_sample); +} + +static HRESULT WINAPI sample_SetDiscontinuity(IMediaSample *iface, BOOL discontinuity) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_SetDiscontinuity(filter->wrapped_sample, discontinuity); +} + +static HRESULT WINAPI sample_GetMediaTime(IMediaSample *iface, LONGLONG *start, LONGLONG *end) +{ + struct testfilter *filter = impl_from_IMediaSample(iface); + + return IMediaSample_GetMediaTime(filter->wrapped_sample, start, end); +} + +static HRESULT WINAPI sample_SetMediaTime(IMediaSample *iface, LONGLONG *start, LONGLONG *end) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static const IMediaSampleVtbl sample_vtbl = +{ + sample_QueryInterface, + sample_AddRef, + sample_Release, + sample_GetPointer, + sample_GetSize, + sample_GetTime, + sample_SetTime, + sample_IsSyncPoint, + sample_SetSyncPoint, + sample_IsPreroll, + sample_SetPreroll, + sample_GetActualDataLength, + sample_SetActualDataLength, + sample_GetMediaType, + sample_SetMediaType, + sample_IsDiscontinuity, + sample_SetDiscontinuity, + sample_GetMediaTime, + sample_SetMediaTime, +}; + +static struct testfilter *impl_from_IMemAllocator(IMemAllocator *iface) +{ + return CONTAINING_RECORD(iface, struct testfilter, IMemAllocator_iface); +} + +static HRESULT WINAPI allocator_QueryInterface(IMemAllocator *iface, REFIID iid, void **out) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static ULONG WINAPI allocator_AddRef(IMemAllocator *iface) +{ + return 2; +} + +static ULONG WINAPI allocator_Release(IMemAllocator *iface) +{ + return 1; +} + +static HRESULT WINAPI allocator_SetProperties(IMemAllocator *iface, + ALLOCATOR_PROPERTIES *req_props, ALLOCATOR_PROPERTIES *ret_props) +{ + struct testfilter *filter = impl_from_IMemAllocator(iface); + + return IMemAllocator_SetProperties(filter->wrapped_allocator, req_props, ret_props); +} + +static HRESULT WINAPI allocator_GetProperties(IMemAllocator *iface, ALLOCATOR_PROPERTIES *props) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI allocator_Commit(IMemAllocator *iface) +{ + struct testfilter *filter = impl_from_IMemAllocator(iface); + + return IMemAllocator_Commit(filter->wrapped_allocator); +} + +static HRESULT WINAPI allocator_Decommit(IMemAllocator *iface) +{ + struct testfilter *filter = impl_from_IMemAllocator(iface); + + return IMemAllocator_Decommit(filter->wrapped_allocator); +} + +static HRESULT WINAPI allocator_GetBuffer(IMemAllocator *iface, IMediaSample **sample, + REFERENCE_TIME *start_time, REFERENCE_TIME *end_time, DWORD flags) +{ + struct testfilter *filter = impl_from_IMemAllocator(iface); + HRESULT hr; + + VIDEOINFOHEADER format = + { + .bmiHeader.biSize = sizeof(BITMAPINFOHEADER), + .bmiHeader.biCompression = mmioFOURCC('I','4','2','0'), + .bmiHeader.biWidth = 10, + .bmiHeader.biHeight = 20, + .bmiHeader.biBitCount = 32, + .bmiHeader.biPlanes = 1, + .bmiHeader.biSizeImage = 222, + }; + AM_MEDIA_TYPE mt = + { + .majortype = MEDIATYPE_Video, + .subtype = MEDIASUBTYPE_I420, + .formattype = FORMAT_VideoInfo, + .cbFormat = sizeof(format), + .pbFormat = (BYTE *)&format, + }; + + if (winetest_debug > 1) trace("GetBuffer()\n"); + + source_bitmap_info = format.bmiHeader; + + ok(!start_time, "Got start time.\n"); + ok(!end_time, "Got end time.\n"); + ok(!flags, "Got flags %#lx.\n", flags); + + ok(!filter->wrapped_sample, "Should not have called GetBuffer() twice here.\n"); + + hr = IMemAllocator_GetBuffer(filter->wrapped_allocator, &filter->wrapped_sample, start_time, end_time, flags); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IMediaSample_SetMediaType(filter->wrapped_sample, &mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + *sample = &filter->IMediaSample_iface; + return S_OK; +} + +static HRESULT WINAPI allocator_ReleaseBuffer(IMemAllocator *iface, IMediaSample *sample) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static const IMemAllocatorVtbl allocator_vtbl = +{ + allocator_QueryInterface, + allocator_AddRef, + allocator_Release, + allocator_SetProperties, + allocator_GetProperties, + allocator_Commit, + allocator_Decommit, + allocator_GetBuffer, + allocator_ReleaseBuffer, +}; + static void testfilter_init(struct testfilter *filter) { static const GUID clsid = {0xabacab}; @@ -996,6 +1285,8 @@ static void testfilter_init(struct testfilter *filter) strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops); strmbase_source_init(&filter->source, &filter->filter, L"source", &testsource_ops); strmbase_sink_init(&filter->sink, &filter->filter, L"sink", &testsink_ops, NULL); + filter->IMemAllocator_iface.lpVtbl = &allocator_vtbl; + filter->IMediaSample_iface.lpVtbl = &sample_vtbl; }
static void test_sink_allocator(IMemInputPin *input) @@ -1052,9 +1343,12 @@ static void test_source_allocator(IFilterGraph2 *graph, IMediaControl *control, IPin *sink, IPin *source, struct testfilter *testsource, struct testfilter *testsink) { ALLOCATOR_PROPERTIES props, req_props = {2, 30000, 32, 0}; - IMemAllocator *allocator; + IMemAllocator *allocator, *sink_allocator; IMediaSample *sample; + IMemInputPin *input; HRESULT hr; + BYTE *data; + LONG size;
VIDEOINFOHEADER sink_format = { @@ -1164,7 +1458,8 @@ static void test_source_allocator(IFilterGraph2 *graph, IMediaControl *control,
CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (void **)&allocator); - testsink->sink.pAllocator = allocator; + testsink->wrapped_allocator = allocator; + testsink->sink.pAllocator = &testsink->IMemAllocator_iface;
hr = IMemAllocator_SetProperties(allocator, &req_props, &props); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -1172,14 +1467,74 @@ static void test_source_allocator(IFilterGraph2 *graph, IMediaControl *control, hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &source_mt); ok(hr == S_OK, "Got hr %#lx.\n", hr);
- ok(testsink->sink.pAllocator == allocator, "Expected an allocator.\n"); - hr = IMemAllocator_GetProperties(testsink->sink.pAllocator, &props); + ok(testsink->sink.pAllocator == &testsink->IMemAllocator_iface, "Expected our allocator to be used.\n"); + hr = IMemAllocator_GetProperties(allocator, &props); ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(props.cBuffers == 1, "Got %ld buffers.\n", props.cBuffers); todo_wine ok(props.cbBuffer == 999, "Got size %ld.\n", props.cbBuffer); ok(props.cbAlign == 1, "Got alignment %ld.\n", props.cbAlign); ok(!props.cbPrefix, "Got prefix %ld.\n", props.cbPrefix);
+ /* Test dynamic format change. */ + + IPin_QueryInterface(sink, &IID_IMemInputPin, (void **)&input); + + CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, + &IID_IMemAllocator, (void **)&sink_allocator); + + req_props.cBuffers = 1; + req_props.cbBuffer = 256; + req_props.cbAlign = 1; + req_props.cbPrefix = 0; + hr = IMemAllocator_SetProperties(sink_allocator, &req_props, &props); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IMemInputPin_NotifyAllocator(input, sink_allocator, TRUE); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IMemAllocator_Commit(sink_allocator); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + req_props.cbBuffer = 321; + hr = IMemAllocator_SetProperties(allocator, &req_props, &props); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IMediaControl_Pause(control); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IMemAllocator_GetProperties(allocator, &props); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(props.cBuffers == 1, "Got %ld buffers.\n", props.cBuffers); + ok(props.cbBuffer == 321, "Got size %ld.\n", props.cbBuffer); + ok(props.cbAlign == 1, "Got alignment %ld.\n", props.cbAlign); + ok(!props.cbPrefix, "Got prefix %ld.\n", props.cbPrefix); + + hr = IMemAllocator_GetBuffer(sink_allocator, &sample, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IMediaSample_GetPointer(sample, &data); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + size = IMediaSample_GetSize(sample); + ok(size == 256, "Got size %ld.\n", size); + for (unsigned int i = 0; i < 200; ++i) + data[i] = i; + hr = IMediaSample_SetActualDataLength(sample, 200); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IMediaSample_SetSyncPoint(sample, TRUE); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + testmode = 8; + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(testsink->got_sample == 1, "Got %u calls to Receive().\n", testsink->got_sample); + testsink->got_sample = 0; + + hr = IMediaControl_Stop(control); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + IMemInputPin_Release(input); + IMemAllocator_Release(sink_allocator); + IFilterGraph2_Disconnect(graph, source); IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface);
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/quartz/avidec.c | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-)
diff --git a/dlls/quartz/avidec.c b/dlls/quartz/avidec.c index 1f89687506c..bcd9dd217bd 100644 --- a/dlls/quartz/avidec.c +++ b/dlls/quartz/avidec.c @@ -47,12 +47,29 @@ struct avi_decompressor struct strmbase_sink sink;
HIC hvid; - BITMAPINFOHEADER* pBihIn; + BITMAPINFOHEADER *input_format;
CRITICAL_SECTION late_cs; REFERENCE_TIME late; };
+static BITMAPINFOHEADER *copy_bitmap_header(const AM_MEDIA_TYPE *mt) +{ + const BITMAPINFOHEADER *src; + BITMAPINFOHEADER *header; + size_t size; + + if (IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo)) + src = &((const VIDEOINFOHEADER *)mt->pbFormat)->bmiHeader; + else + src = &((const VIDEOINFOHEADER2 *)mt->pbFormat)->bmiHeader; + size = src->biSize + src->biClrUsed * sizeof(RGBQUAD); + + if ((header = malloc(size))) + memcpy(header, src, size); + return header; +} + static struct avi_decompressor *impl_from_strmbase_filter(struct strmbase_filter *iface) { return CONTAINING_RECORD(iface, struct avi_decompressor, filter); @@ -141,7 +158,7 @@ static HRESULT WINAPI avi_decompressor_sink_Receive(struct strmbase_sink *iface, cbSrcStream = IMediaSample_GetActualDataLength(pSample);
/* Update input size to match sample size */ - This->pBihIn->biSizeImage = cbSrcStream; + This->input_format->biSizeImage = cbSrcStream;
if (FAILED(hr = IMemAllocator_GetBuffer(This->source.pAllocator, &pOutSample, NULL, NULL, 0))) { @@ -173,7 +190,7 @@ static HRESULT WINAPI avi_decompressor_sink_Receive(struct strmbase_sink *iface, flags |= ICDECOMPRESS_HURRYUP; LeaveCriticalSection(&This->late_cs);
- res = ICDecompress(This->hvid, flags, This->pBihIn, pbSrcStream, &source_format->bmiHeader, pbDstStream); + res = ICDecompress(This->hvid, flags, This->input_format, pbSrcStream, &source_format->bmiHeader, pbDstStream); if (res != ICERR_OK) ERR("Failed to decompress, error %Id.\n", res);
@@ -227,20 +244,12 @@ static HRESULT avi_decompressor_sink_connect(struct strmbase_sink *iface, IPin * This->hvid = ICLocate(pmt->majortype.Data1, pmt->subtype.Data1, bmi, NULL, ICMODE_DECOMPRESS); if (This->hvid) { - DWORD bih_size; LRESULT result;
- /* Copy bitmap header from media type to 1 for input and 1 for output */ - bih_size = bmi->biSize + bmi->biClrUsed * 4; - This->pBihIn = CoTaskMemAlloc(bih_size); - if (!This->pBihIn) - { - hr = E_OUTOFMEMORY; - goto failed; - } - memcpy(This->pBihIn, bmi, bih_size); + if (!(This->input_format = copy_bitmap_header(pmt))) + return E_OUTOFMEMORY;
- if ((result = ICDecompressQuery(This->hvid, This->pBihIn, NULL))) + if ((result = ICDecompressQuery(This->hvid, This->input_format, NULL))) { WARN("No decompressor found, error %Id.\n", result); return VFW_E_TYPE_NOT_ACCEPTED; @@ -264,9 +273,9 @@ static void avi_decompressor_sink_disconnect(struct strmbase_sink *iface)
if (filter->hvid) ICClose(filter->hvid); - CoTaskMemFree(filter->pBihIn); + free(filter->input_format); filter->hvid = NULL; - filter->pBihIn = NULL; + filter->input_format = NULL; }
static const struct strmbase_sink_ops sink_ops = @@ -562,7 +571,7 @@ static HRESULT avi_decompressor_init_stream(struct strmbase_filter *iface) LeaveCriticalSection(&filter->late_cs);
source_format = (VIDEOINFOHEADER *)filter->source.pin.mt.pbFormat; - if ((res = ICDecompressBegin(filter->hvid, filter->pBihIn, &source_format->bmiHeader))) + if ((res = ICDecompressBegin(filter->hvid, filter->input_format, &source_format->bmiHeader))) { ERR("ICDecompressBegin() failed, error %Id.\n", res); return E_FAIL;
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/quartz/avidec.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-)
diff --git a/dlls/quartz/avidec.c b/dlls/quartz/avidec.c index bcd9dd217bd..e4ff86599ab 100644 --- a/dlls/quartz/avidec.c +++ b/dlls/quartz/avidec.c @@ -53,17 +53,27 @@ struct avi_decompressor REFERENCE_TIME late; };
-static BITMAPINFOHEADER *copy_bitmap_header(const AM_MEDIA_TYPE *mt) +static const BITMAPINFOHEADER *get_bitmap_header(const AM_MEDIA_TYPE *mt) { - const BITMAPINFOHEADER *src; - BITMAPINFOHEADER *header; - size_t size; - if (IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo)) - src = &((const VIDEOINFOHEADER *)mt->pbFormat)->bmiHeader; + return &((VIDEOINFOHEADER *)mt->pbFormat)->bmiHeader; + else + return &((VIDEOINFOHEADER2 *)mt->pbFormat)->bmiHeader; +} + +static size_t get_bitmap_info_size(const BITMAPINFOHEADER *header) +{ + if (header->biCompression == BI_BITFIELDS) + return header->biSize + 3 * sizeof(DWORD); else - src = &((const VIDEOINFOHEADER2 *)mt->pbFormat)->bmiHeader; - size = src->biSize + src->biClrUsed * sizeof(RGBQUAD); + return header->biSize + header->biClrUsed * sizeof(RGBQUAD); +} + +static BITMAPINFOHEADER *copy_bitmap_header(const AM_MEDIA_TYPE *mt) +{ + const BITMAPINFOHEADER *src = get_bitmap_header(mt); + size_t size = get_bitmap_info_size(src); + BITMAPINFOHEADER *header;
if ((header = malloc(size))) memcpy(header, src, size);
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/quartz/avidec.c | 76 +++++++++++++++++++++++++++++++------- dlls/quartz/tests/avidec.c | 10 ++--- 2 files changed, 66 insertions(+), 20 deletions(-)
diff --git a/dlls/quartz/avidec.c b/dlls/quartz/avidec.c index e4ff86599ab..0bb526b6d65 100644 --- a/dlls/quartz/avidec.c +++ b/dlls/quartz/avidec.c @@ -47,7 +47,7 @@ struct avi_decompressor struct strmbase_sink sink;
HIC hvid; - BITMAPINFOHEADER *input_format; + BITMAPINFOHEADER *input_format, *output_format;
CRITICAL_SECTION late_cs; REFERENCE_TIME late; @@ -130,13 +130,13 @@ static int AVIDec_DropSample(struct avi_decompressor *This, REFERENCE_TIME tStar static HRESULT WINAPI avi_decompressor_sink_Receive(struct strmbase_sink *iface, IMediaSample *pSample) { struct avi_decompressor *This = impl_from_strmbase_filter(iface->pin.filter); - VIDEOINFOHEADER *source_format; HRESULT hr; IMediaSample* pOutSample = NULL; LONG cbDstStream, cbSrcStream; LPBYTE pbDstStream; LPBYTE pbSrcStream; LONGLONG tStart, tStop; + AM_MEDIA_TYPE *mt; DWORD flags = 0; LRESULT res;
@@ -150,8 +150,6 @@ static HRESULT WINAPI avi_decompressor_sink_Receive(struct strmbase_sink *iface, return VFW_E_NOT_CONNECTED; }
- source_format = (VIDEOINFOHEADER *)This->source.pin.mt.pbFormat; - if (This->filter.state == State_Stopped) return VFW_E_WRONG_STATE;
@@ -176,6 +174,46 @@ static HRESULT WINAPI avi_decompressor_sink_Receive(struct strmbase_sink *iface, return hr; }
+ /* Handle dynamic format change. */ + if ((hr = IMediaSample_GetMediaType(pOutSample, &mt)) == S_OK) + { + if (!memcmp(This->output_format, get_bitmap_header(mt), get_bitmap_info_size(This->output_format))) + { + DeleteMediaType(mt); + } + else + { + if ((res = ICDecompressEnd(This->hvid))) + { + DeleteMediaType(mt); + ERR("ICDecompressEnd() failed, error %Id.\n", res); + IMediaSample_Release(pOutSample); + return E_FAIL; + } + + free(This->output_format); + if (!(This->output_format = copy_bitmap_header(mt))) + { + DeleteMediaType(mt); + IMediaSample_Release(pOutSample); + return E_OUTOFMEMORY; + } + + DeleteMediaType(mt); + + if ((res = ICDecompressBegin(This->hvid, This->input_format, This->output_format))) + { + ERR("ICDecompressBegin() failed, error %Id.\n", res); + IMediaSample_Release(pOutSample); + return E_FAIL; + } + } + } + else if (hr != S_FALSE) + { + ERR("Failed to get media type, hr %#lx.\n", hr); + } + hr = IMediaSample_GetPointer(pOutSample, &pbDstStream); if (FAILED(hr)) { ERR("Failed to get output buffer pointer, hr %#lx.\n", hr); @@ -183,9 +221,9 @@ static HRESULT WINAPI avi_decompressor_sink_Receive(struct strmbase_sink *iface, return hr; } cbDstStream = IMediaSample_GetSize(pOutSample); - if (cbDstStream < source_format->bmiHeader.biSizeImage) + if (cbDstStream < This->output_format->biSizeImage) { - ERR("Sample size is too small (%ld < %lu).\n", cbDstStream, source_format->bmiHeader.biSizeImage); + ERR("Sample size is too small (%ld < %lu).\n", cbDstStream, This->output_format->biSizeImage); IMediaSample_Release(pOutSample); return E_FAIL; } @@ -200,7 +238,7 @@ static HRESULT WINAPI avi_decompressor_sink_Receive(struct strmbase_sink *iface, flags |= ICDECOMPRESS_HURRYUP; LeaveCriticalSection(&This->late_cs);
- res = ICDecompress(This->hvid, flags, This->input_format, pbSrcStream, &source_format->bmiHeader, pbDstStream); + res = ICDecompress(This->hvid, flags, This->input_format, pbSrcStream, This->output_format, pbDstStream); if (res != ICERR_OK) ERR("Failed to decompress, error %Id.\n", res);
@@ -210,7 +248,7 @@ static HRESULT WINAPI avi_decompressor_sink_Receive(struct strmbase_sink *iface, return S_OK; }
- IMediaSample_SetActualDataLength(pOutSample, source_format->bmiHeader.biSizeImage); + IMediaSample_SetActualDataLength(pOutSample, This->output_format->biSizeImage);
IMediaSample_SetPreroll(pOutSample, (IMediaSample_IsPreroll(pSample) == S_OK)); IMediaSample_SetDiscontinuity(pOutSample, (IMediaSample_IsDiscontinuity(pSample) == S_OK)); @@ -447,14 +485,17 @@ static HRESULT avi_decompressor_source_get_media_type(struct strmbase_pin *iface static HRESULT WINAPI avi_decompressor_source_DecideBufferSize(struct strmbase_source *iface, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest) { - const VIDEOINFOHEADER *source_format = (VIDEOINFOHEADER *)iface->pin.mt.pbFormat; + struct avi_decompressor *filter = impl_from_strmbase_filter(iface->pin.filter); ALLOCATOR_PROPERTIES actual;
+ if (!(filter->output_format = copy_bitmap_header(&iface->pin.mt))) + return E_OUTOFMEMORY; + if (!ppropInputRequest->cbAlign) ppropInputRequest->cbAlign = 1;
- if (ppropInputRequest->cbBuffer < source_format->bmiHeader.biSizeImage) - ppropInputRequest->cbBuffer = source_format->bmiHeader.biSizeImage; + if (ppropInputRequest->cbBuffer < filter->output_format->biSizeImage) + ppropInputRequest->cbBuffer = filter->output_format->biSizeImage;
if (!ppropInputRequest->cBuffers) ppropInputRequest->cBuffers = 1; @@ -462,6 +503,14 @@ static HRESULT WINAPI avi_decompressor_source_DecideBufferSize(struct strmbase_s return IMemAllocator_SetProperties(pAlloc, ppropInputRequest, &actual); }
+static void avi_decompressor_source_disconnect(struct strmbase_source *iface) +{ + struct avi_decompressor *filter = impl_from_strmbase_filter(iface->pin.filter); + + free(filter->output_format); + filter->output_format = NULL; +} + static const struct strmbase_source_ops source_ops = { .base.pin_query_interface = avi_decompressor_source_query_interface, @@ -470,6 +519,7 @@ static const struct strmbase_source_ops source_ops = .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection, .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator, .pfnDecideBufferSize = avi_decompressor_source_DecideBufferSize, + .source_disconnect = avi_decompressor_source_disconnect, };
static struct avi_decompressor *impl_from_source_IQualityControl(IQualityControl *iface) @@ -569,7 +619,6 @@ static void avi_decompressor_destroy(struct strmbase_filter *iface) static HRESULT avi_decompressor_init_stream(struct strmbase_filter *iface) { struct avi_decompressor *filter = impl_from_strmbase_filter(iface); - VIDEOINFOHEADER *source_format; LRESULT res; HRESULT hr;
@@ -580,8 +629,7 @@ static HRESULT avi_decompressor_init_stream(struct strmbase_filter *iface) filter->late = -1; LeaveCriticalSection(&filter->late_cs);
- source_format = (VIDEOINFOHEADER *)filter->source.pin.mt.pbFormat; - if ((res = ICDecompressBegin(filter->hvid, filter->input_format, &source_format->bmiHeader))) + if ((res = ICDecompressBegin(filter->hvid, filter->input_format, filter->output_format))) { ERR("ICDecompressBegin() failed, error %Id.\n", res); return E_FAIL; diff --git a/dlls/quartz/tests/avidec.c b/dlls/quartz/tests/avidec.c index 902b1566638..4a0f731fc66 100644 --- a/dlls/quartz/tests/avidec.c +++ b/dlls/quartz/tests/avidec.c @@ -153,9 +153,8 @@ static LRESULT CALLBACK vfw_driver_proc(DWORD_PTR id, HDRVR driver, UINT msg, expect_sink_format.biSizeImage = 200; ok(!memcmp(params->lpbiInput, &expect_sink_format, sizeof(BITMAPINFOHEADER)), "Input types didn't match.\n"); - todo_wine_if (testmode == 8) - ok(!memcmp(params->lpbiOutput, &source_bitmap_info, sizeof(BITMAPINFOHEADER)), - "Output types didn't match.\n"); + ok(!memcmp(params->lpbiOutput, &source_bitmap_info, sizeof(BITMAPINFOHEADER)), + "Output types didn't match.\n"); ok(!params->ckid, "Got chunk id %#lx.\n", params->ckid);
for (i = 0; i < 200; ++i) @@ -911,8 +910,7 @@ static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample else ok(size == source_bitmap_info.biSizeImage, "Got size %lu.\n", size); size = IMediaSample_GetActualDataLength(sample); - todo_wine_if (testmode == 8) - ok(size == source_bitmap_info.biSizeImage, "Got valid size %lu.\n", size); + ok(size == source_bitmap_info.biSizeImage, "Got valid size %lu.\n", size);
hr = IMediaSample_GetPointer(sample, &data); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -1098,7 +1096,7 @@ static HRESULT WINAPI sample_SetActualDataLength(IMediaSample *iface, LONG size)
if (winetest_debug > 1) trace("SetActualDataLength(%ld)\n", size);
- todo_wine ok(size == 222, "Got size %ld.\n", size); + ok(size == 222, "Got size %ld.\n", size);
IMediaSample_SetActualDataLength(filter->wrapped_sample, size); return E_FAIL;