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); + + bitmap_header = get_bitmap_header(&filter->renderer.sink.pin.mt); + width = bitmap_header->biWidth; + height = bitmap_header->biHeight; + depth = bitmap_header->biBitCount; + + 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]; + + if (FAILED(hr = IDirect3DSurface9_LockRect(info.lpSurf, &locked_rect, NULL, D3DLOCK_DISCARD))) + { + ERR("Failed to lock surface, hr %#x.\n", hr); return hr; } - cbSrcStream = IMediaSample_GetActualDataLength(pSample); - - 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]; - - VMR9_SendSampleData(This, &info, pbSrcStream, cbSrcStream); - - if (This->renderer.filter.state == State_Paused) + if (height > 0) { - LeaveCriticalSection(&This->renderer.csRenderLock); + 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) + { + 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;