From: Elizabeth Figura <zfigura(a)codeweavers.com> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59097 --- dlls/quartz/avidec.c | 146 +++++++++++++++++++++++++++++++++---- dlls/quartz/tests/avidec.c | 13 ++-- 2 files changed, 136 insertions(+), 23 deletions(-) diff --git a/dlls/quartz/avidec.c b/dlls/quartz/avidec.c index 9f1a7db1586..521e0ededf6 100644 --- a/dlls/quartz/avidec.c +++ b/dlls/quartz/avidec.c @@ -127,6 +127,106 @@ static int AVIDec_DropSample(struct avi_decompressor *This, REFERENCE_TIME tStar return 0; } +static bool is_nontrivial_rect(const BITMAPINFOHEADER *header, const RECT *rect) +{ + return rect->left || rect->top || (rect->right && rect->right != header->biWidth) + || (rect->bottom && rect->bottom != header->biHeight); +} + +static bool needs_decompressex(const AM_MEDIA_TYPE *mt) +{ + const BITMAPINFOHEADER *header; + const RECT *src, *dst; + + if (IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo2)) + { + const VIDEOINFOHEADER2 *format = (VIDEOINFOHEADER2 *)mt->pbFormat; + + header = &format->bmiHeader; + src = &format->rcSource; + dst = &format->rcTarget; + } + else + { + const VIDEOINFOHEADER *format = (VIDEOINFOHEADER *)mt->pbFormat; + + header = &format->bmiHeader; + src = &format->rcSource; + dst = &format->rcTarget; + } + + return is_nontrivial_rect(header, src) || is_nontrivial_rect(header, dst); +} + +static void fill_decompressex(struct avi_decompressor *filter, + ICDECOMPRESSEX *params, const AM_MEDIA_TYPE *mt) +{ + BITMAPINFOHEADER *header; + const RECT *src, *dst; + + if (IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo2)) + { + VIDEOINFOHEADER2 *format = (VIDEOINFOHEADER2 *)mt->pbFormat; + + header = &format->bmiHeader; + src = &format->rcSource; + dst = &format->rcTarget; + } + else + { + VIDEOINFOHEADER *format = (VIDEOINFOHEADER *)mt->pbFormat; + + header = &format->bmiHeader; + src = &format->rcSource; + dst = &format->rcTarget; + } + + memset(params, 0, sizeof(ICDECOMPRESSEX)); + params->lpbiSrc = filter->input_format; + params->lpbiDst = header; + params->xDst = dst->left; + params->yDst = dst->top; + params->dxDst = dst->right - dst->left; + params->dyDst = dst->bottom - dst->top; + params->xSrc = src->left; + params->ySrc = src->top; + params->dxSrc = src->right - src->left; + params->dySrc = src->bottom - src->top; +} + +static LRESULT begin_decompress(struct avi_decompressor *filter) +{ + LRESULT res; + + if (needs_decompressex(&filter->source.pin.mt)) + { + ICDECOMPRESSEX params; + + fill_decompressex(filter, ¶ms, &filter->source.pin.mt); + res = ICSendMessage(filter->hvid, ICM_DECOMPRESSEX_BEGIN, (DWORD_PTR)¶ms, sizeof(params)); + } + else + { + res = ICDecompressBegin(filter->hvid, filter->input_format, filter->output_format); + } + if (res) + ERR("ICDecompressEnd() failed, error %Id.\n", res); + return res; +} + +static LRESULT end_decompress(struct avi_decompressor *filter) +{ + LRESULT res; + + if (needs_decompressex(&filter->source.pin.mt)) + res = ICDecompressExEnd(filter->hvid); + else + res = ICDecompressEnd(filter->hvid); + if (res) + ERR("ICDecompressEnd() failed, error %Id.\n", res); + return res; +} + static HRESULT WINAPI avi_decompressor_sink_Receive(struct strmbase_sink *iface, IMediaSample *pSample) { struct avi_decompressor *This = impl_from_strmbase_filter(iface->pin.filter); @@ -183,10 +283,9 @@ static HRESULT WINAPI avi_decompressor_sink_Receive(struct strmbase_sink *iface, } else { - if ((res = ICDecompressEnd(This->hvid))) + if ((res = end_decompress(This))) { DeleteMediaType(mt); - ERR("ICDecompressEnd() failed, error %Id.\n", res); IMediaSample_Release(pOutSample); return E_FAIL; } @@ -201,9 +300,8 @@ static HRESULT WINAPI avi_decompressor_sink_Receive(struct strmbase_sink *iface, DeleteMediaType(mt); - if ((res = ICDecompressBegin(This->hvid, This->input_format, This->output_format))) + if ((res = begin_decompress(This))) { - ERR("ICDecompressBegin() failed, error %Id.\n", res); IMediaSample_Release(pOutSample); return E_FAIL; } @@ -238,7 +336,20 @@ 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, This->output_format, pbDstStream); + if (needs_decompressex(&This->source.pin.mt)) + { + ICDECOMPRESSEX params; + + fill_decompressex(This, ¶ms, &This->source.pin.mt); + params.lpSrc = pbSrcStream; + params.lpDst = pbDstStream; + params.dwFlags = flags; + res = ICSendMessage(This->hvid, ICM_DECOMPRESSEX, (DWORD_PTR)¶ms, sizeof(params)); + } + else + { + 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); @@ -362,8 +473,19 @@ static HRESULT avi_decompressor_source_query_accept(struct strmbase_pin *iface, sink_format = (VIDEOINFOHEADER *)filter->sink.pin.mt.pbFormat; format = (VIDEOINFOHEADER *)mt->pbFormat; - if (ICDecompressQuery(filter->hvid, &sink_format->bmiHeader, &format->bmiHeader)) - return S_FALSE; + if (needs_decompressex(mt)) + { + ICDECOMPRESSEX params; + + fill_decompressex(filter, ¶ms, mt); + if (ICSendMessage(filter->hvid, ICM_DECOMPRESSEX_QUERY, (DWORD_PTR)¶ms, sizeof(params))) + return S_FALSE; + } + else + { + if (ICDecompressQuery(filter->hvid, &sink_format->bmiHeader, &format->bmiHeader)) + return S_FALSE; + } return S_OK; } @@ -629,11 +751,8 @@ static HRESULT avi_decompressor_init_stream(struct strmbase_filter *iface) filter->late = -1; LeaveCriticalSection(&filter->late_cs); - if ((res = ICDecompressBegin(filter->hvid, filter->input_format, filter->output_format))) - { - ERR("ICDecompressBegin() failed, error %Id.\n", res); + if ((res = begin_decompress(filter))) return E_FAIL; - } if (FAILED(hr = IMemAllocator_Commit(filter->source.pAllocator))) ERR("Failed to commit allocator, hr %#lx.\n", hr); @@ -654,13 +773,10 @@ static HRESULT avi_decompressor_cleanup_stream(struct strmbase_filter *iface) if (filter->hvid) { EnterCriticalSection(&filter->filter.stream_cs); - res = ICDecompressEnd(filter->hvid); + res = end_decompress(filter); LeaveCriticalSection(&filter->filter.stream_cs); if (res) - { - ERR("ICDecompressEnd() failed, error %Id.\n", res); return E_FAIL; - } } return S_OK; diff --git a/dlls/quartz/tests/avidec.c b/dlls/quartz/tests/avidec.c index 74f02e63dd7..1472c5f21c6 100644 --- a/dlls/quartz/tests/avidec.c +++ b/dlls/quartz/tests/avidec.c @@ -2169,22 +2169,19 @@ static void test_connect_pin(void) SetRect(&format->rcTarget, 10, 20, 40, 60); hr = IPin_QueryAccept(source, &req_mt); - todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr); format->bmiHeader.biCompression = mmioFOURCC('N','V','1','2'); source_bitmap_info = format->bmiHeader; hr = IPin_QueryAccept(source, &req_mt); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr == S_OK) - { - ok(compare_media_types(&testsink.sink.pin.mt, &req_mt), "Media types didn't match.\n"); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(compare_media_types(&testsink.sink.pin.mt, &req_mt), "Media types didn't match.\n"); - test_sample_processing(control, meminput, &testsink); - } + test_sample_processing(control, meminput, &testsink); hr = IFilterGraph2_Disconnect(graph, sink); ok(hr == S_OK, "Got hr %#lx.\n", hr); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9718