Signed-off-by: Zebediah Figura z.figura12@gmail.com --- videoconvert seems to be faster at converting YUV -> YUV than YUV -> RGB, which makes sense.
This patch set, as well as following patch sets, aim to improve the speed of video post-processing in the quartz pipeline. Particularly large video samples can take long enough to process that not only will the video play back slowly, but (depending on demuxer) the audio will get "stuck behind" it and stutter.
dlls/quartz/vmr9.c | 155 ++++++++++++++++++++++----------------------- 1 file changed, 76 insertions(+), 79 deletions(-)
diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index 6b653e56092..f81d8067059 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -207,89 +207,41 @@ static inline struct quartz_vmr *impl_from_IBaseFilter(IBaseFilter *iface) return CONTAINING_RECORD(iface, struct quartz_vmr, renderer.filter.IBaseFilter_iface); }
-static DWORD VMR9_SendSampleData(struct quartz_vmr *This, VMR9PresentationInfo *info, LPBYTE data, - DWORD size) +static HRESULT WINAPI VMR9_DoRenderSample(struct strmbase_renderer *iface, IMediaSample *sample) { - const BITMAPINFOHEADER *bmiHeader = get_bitmap_header(&This->renderer.sink.pin.mt); - HRESULT hr = S_OK; - int width; - int height; - D3DLOCKED_RECT lock; - - TRACE("%p %p %d\n", This, data, size); - - width = bmiHeader->biWidth; - height = bmiHeader->biHeight; - - hr = IDirect3DSurface9_LockRect(info->lpSurf, &lock, NULL, D3DLOCK_DISCARD); - if (FAILED(hr)) - { - ERR("IDirect3DSurface9_LockRect failed (%x)\n",hr); - return hr; - } - - if (height > 0) { - /* Bottom up image needs inverting */ - lock.pBits = (char *)lock.pBits + (height * lock.Pitch); - while (height--) - { - lock.pBits = (char *)lock.pBits - lock.Pitch; - memcpy(lock.pBits, data, width * bmiHeader->biBitCount / 8); - data = data + width * bmiHeader->biBitCount / 8; - } - } - else if (lock.Pitch != width * bmiHeader->biBitCount / 8) - { - WARN("Slow path! %u/%u\n", lock.Pitch, width * bmiHeader->biBitCount/8); - - while (height--) - { - memcpy(lock.pBits, data, width * bmiHeader->biBitCount / 8); - data = data + width * bmiHeader->biBitCount / 8; - lock.pBits = (char *)lock.pBits + lock.Pitch; - } - } - else memcpy(lock.pBits, data, size); - - IDirect3DSurface9_UnlockRect(info->lpSurf); - - hr = IVMRImagePresenter9_PresentImage(This->presenter, This->cookie, info); - return hr; -} - -static HRESULT WINAPI VMR9_DoRenderSample(struct strmbase_renderer *iface, IMediaSample *pSample) -{ - struct quartz_vmr *This = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface); - const HANDLE events[2] = {This->run_event, This->renderer.flush_event}; + struct quartz_vmr *filter = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface); + const HANDLE events[2] = {filter->run_event, filter->renderer.flush_event}; + const BITMAPINFOHEADER *bitmap_header; + unsigned int data_size, width, depth; + REFERENCE_TIME start_time, end_time; VMR9PresentationInfo info = {}; - LPBYTE pbSrcStream = NULL; - long cbSrcStream = 0; - REFERENCE_TIME tStart, tStop; + D3DLOCKED_RECT locked_rect; + BYTE *data = NULL; HRESULT hr; + int height;
- TRACE("%p %p\n", iface, pSample); + TRACE("filter %p, sample %p.\n", filter, sample);
/* It is possible that there is no device at this point */
- if (!This->allocator || !This->presenter) + if (!filter->allocator || !filter->presenter) { ERR("NO PRESENTER!!\n"); return S_FALSE; }
- hr = IMediaSample_GetTime(pSample, &tStart, &tStop); - if (FAILED(hr)) - info.dwFlags = VMR9Sample_SrcDstRectsValid; - else - info.dwFlags = VMR9Sample_SrcDstRectsValid | VMR9Sample_TimeValid; + info.dwFlags = VMR9Sample_SrcDstRectsValid;
- if (IMediaSample_IsDiscontinuity(pSample) == S_OK) + if (SUCCEEDED(hr = IMediaSample_GetTime(sample, &start_time, &end_time))) + info.dwFlags |= VMR9Sample_TimeValid; + + if (IMediaSample_IsDiscontinuity(sample) == S_OK) info.dwFlags |= VMR9Sample_Discontinuity;
- if (IMediaSample_IsPreroll(pSample) == S_OK) + if (IMediaSample_IsPreroll(sample) == S_OK) info.dwFlags |= VMR9Sample_Preroll;
- if (IMediaSample_IsSyncPoint(pSample) == S_OK) + if (IMediaSample_IsSyncPoint(sample) == S_OK) info.dwFlags |= VMR9Sample_SyncPoint;
/* If we render ourselves, and this is a preroll sample, discard it */ @@ -298,28 +250,73 @@ static HRESULT WINAPI VMR9_DoRenderSample(struct strmbase_renderer *iface, IMedi return S_OK; }
- hr = IMediaSample_GetPointer(pSample, &pbSrcStream); - if (FAILED(hr)) + if (FAILED(hr = IMediaSample_GetPointer(sample, &data))) { - ERR("Cannot get pointer to sample data (%x)\n", hr); + ERR("Failed to get pointer to sample data, hr %#x.\n", hr); return hr; } + data_size = IMediaSample_GetActualDataLength(sample);
- cbSrcStream = IMediaSample_GetActualDataLength(pSample); + bitmap_header = get_bitmap_header(&filter->renderer.sink.pin.mt); + width = bitmap_header->biWidth; + height = bitmap_header->biHeight; + depth = bitmap_header->biBitCount;
- info.rtStart = tStart; - info.rtEnd = tStop; - info.szAspectRatio.cx = This->bmiheader.biWidth; - info.szAspectRatio.cy = This->bmiheader.biHeight; - info.lpSurf = This->surfaces[(++This->cur_surface) % This->num_surfaces]; + info.rtStart = start_time; + info.rtEnd = end_time; + info.szAspectRatio.cx = width; + info.szAspectRatio.cy = height; + info.lpSurf = filter->surfaces[(++filter->cur_surface) % filter->num_surfaces];
- VMR9_SendSampleData(This, &info, pbSrcStream, cbSrcStream); + if (FAILED(hr = IDirect3DSurface9_LockRect(info.lpSurf, &locked_rect, NULL, D3DLOCK_DISCARD))) + { + ERR("Failed to lock surface, hr %#x.\n", hr); + return hr; + }
- if (This->renderer.filter.state == State_Paused) + if (height > 0) + { + BYTE *dst = (BYTE *)locked_rect.pBits + (height * locked_rect.Pitch); + const BYTE *src = data; + + TRACE("Inverting image.\n"); + + while (height--) + { + dst -= locked_rect.Pitch; + memcpy(dst, src, width * depth / 8); + src += width * depth / 8; + } + } + else if (locked_rect.Pitch != width * depth / 8) { - LeaveCriticalSection(&This->renderer.csRenderLock); + BYTE *dst = locked_rect.pBits; + const BYTE *src = data; + + TRACE("Source pitch %u does not match dest pitch %u; copying manually.\n", + width * depth / 8, locked_rect.Pitch); + + while (height--) + { + memcpy(dst, src, width * depth / 8); + src += width * depth / 8; + dst += locked_rect.Pitch; + } + } + else + { + memcpy(locked_rect.pBits, data, data_size); + } + + IDirect3DSurface9_UnlockRect(info.lpSurf); + + hr = IVMRImagePresenter9_PresentImage(filter->presenter, filter->cookie, &info); + + if (filter->renderer.filter.state == State_Paused) + { + LeaveCriticalSection(&filter->renderer.csRenderLock); WaitForMultipleObjects(2, events, FALSE, INFINITE); - EnterCriticalSection(&This->renderer.csRenderLock); + EnterCriticalSection(&filter->renderer.csRenderLock); }
return hr;
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/vmr9.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index f81d8067059..5c2cf33820d 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -211,8 +211,8 @@ static HRESULT WINAPI VMR9_DoRenderSample(struct strmbase_renderer *iface, IMedi { struct quartz_vmr *filter = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface); const HANDLE events[2] = {filter->run_event, filter->renderer.flush_event}; + unsigned int data_size, width, depth, src_pitch; const BITMAPINFOHEADER *bitmap_header; - unsigned int data_size, width, depth; REFERENCE_TIME start_time, end_time; VMR9PresentationInfo info = {}; D3DLOCKED_RECT locked_rect; @@ -261,6 +261,7 @@ static HRESULT WINAPI VMR9_DoRenderSample(struct strmbase_renderer *iface, IMedi width = bitmap_header->biWidth; height = bitmap_header->biHeight; depth = bitmap_header->biBitCount; + src_pitch = ((width * depth / 8) + 3) & ~3;
info.rtStart = start_time; info.rtEnd = end_time; @@ -285,21 +286,21 @@ static HRESULT WINAPI VMR9_DoRenderSample(struct strmbase_renderer *iface, IMedi { dst -= locked_rect.Pitch; memcpy(dst, src, width * depth / 8); - src += width * depth / 8; + src += src_pitch; } } - else if (locked_rect.Pitch != width * depth / 8) + else if (locked_rect.Pitch != src_pitch) { BYTE *dst = locked_rect.pBits; const BYTE *src = data;
TRACE("Source pitch %u does not match dest pitch %u; copying manually.\n", - width * depth / 8, locked_rect.Pitch); + src_pitch, locked_rect.Pitch);
while (height--) { memcpy(dst, src, width * depth / 8); - src += width * depth / 8; + src += src_pitch; dst += locked_rect.Pitch; } }
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/vmr9.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index 5c2cf33820d..bee5a107185 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -261,7 +261,11 @@ static HRESULT WINAPI VMR9_DoRenderSample(struct strmbase_renderer *iface, IMedi width = bitmap_header->biWidth; height = bitmap_header->biHeight; depth = bitmap_header->biBitCount; - src_pitch = ((width * depth / 8) + 3) & ~3; + if (bitmap_header->biCompression == mmioFOURCC('N','V','1','2') + || bitmap_header->biCompression == mmioFOURCC('Y','V','1','2')) + src_pitch = width; + else /* packed YUV (UYVY or YUY2) or RGB */ + src_pitch = ((width * depth / 8) + 3) & ~3;
info.rtStart = start_time; info.rtEnd = end_time;
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/vmr9.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index bee5a107185..d4331d321df 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -279,7 +279,7 @@ static HRESULT WINAPI VMR9_DoRenderSample(struct strmbase_renderer *iface, IMedi return hr; }
- if (height > 0) + if (height > 0 && bitmap_header->biCompression == BI_RGB) { BYTE *dst = (BYTE *)locked_rect.pBits + (height * locked_rect.Pitch); const BYTE *src = data; @@ -298,6 +298,8 @@ static HRESULT WINAPI VMR9_DoRenderSample(struct strmbase_renderer *iface, IMedi BYTE *dst = locked_rect.pBits; const BYTE *src = data;
+ height = abs(height); + TRACE("Source pitch %u does not match dest pitch %u; copying manually.\n", src_pitch, locked_rect.Pitch);
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/vmr9.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index d4331d321df..3636d47702c 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -428,11 +428,14 @@ static HRESULT allocate_surfaces(struct quartz_vmr *filter, const AM_MEDIA_TYPE case 32: info.Format = D3DFMT_X8R8G8B8; break; default: FIXME("Unhandled bit depth %u.\n", filter->bmiheader.biBitCount); + free(filter->surfaces); return E_INVALIDARG; }
info.dwFlags = VMR9AllocFlag_TextureSurface; - return initialize_device(filter, &info, count); + if (FAILED(hr = initialize_device(filter, &info, count))) + free(filter->surfaces); + return hr; }
for (i = 0; i < ARRAY_SIZE(formats); ++i) @@ -457,6 +460,7 @@ static HRESULT allocate_surfaces(struct quartz_vmr *filter, const AM_MEDIA_TYPE } }
+ free(filter->surfaces); return hr; }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=73813
Your paranoid android.
=== debiant (64 bit WoW report) ===
quartz: videorenderer.c:1054: Test failed: Got time f005c00000000.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/tests/vmr9.c | 2 +- dlls/quartz/vmr9.c | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/dlls/quartz/tests/vmr9.c b/dlls/quartz/tests/vmr9.c index 2641b7a04bb..fae824b827d 100644 --- a/dlls/quartz/tests/vmr9.c +++ b/dlls/quartz/tests/vmr9.c @@ -696,7 +696,7 @@ static void test_media_types(void) VIDEOINFOHEADER vih = { {0}, {0}, 0, 0, 0, - {sizeof(BITMAPINFOHEADER), 32, 24, 1, 0, BI_RGB} + {sizeof(BITMAPINFOHEADER), 32, 24, 1, 0, 0xdeadbeef} }; IEnumMediaTypes *enummt; unsigned int i; diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index 3636d47702c..b49b2b67dbb 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -338,8 +338,6 @@ static HRESULT WINAPI VMR9_CheckMediaType(struct strmbase_renderer *iface, const && !IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo2)) return S_FALSE;
- if (get_bitmap_header(mt)->biCompression != BI_RGB) - return S_FALSE; return S_OK; }