quartz: Hookup the VMR-9 to directX and the Allocator-Presenter.

This commit is contained in:
Aric Stewart 2012-06-06 13:47:26 -05:00 committed by Alexandre Julliard
parent 583d915520
commit ac421e3341
1 changed files with 356 additions and 12 deletions

View File

@ -61,12 +61,24 @@ typedef struct
IVMRImagePresenter9 *presenter;
BOOL allocator_is_ex;
/*
* The Video Mixing Renderer supports 3 modes, renderless, windowless and windowed
* What I do is implement windowless as a special case of renderless, and then
* windowed also as a special case of windowless. This is probably the easiest way.
*/
VMR9Mode mode;
BITMAPINFOHEADER bmiheader;
IUnknown * outer_unk;
BOOL bUnkOuterValid;
BOOL bAggregatable;
HMODULE hD3d9;
/* Presentation related members */
IDirect3DDevice9 *allocator_d3d9_dev;
HMONITOR allocator_mon;
DWORD num_surfaces;
DWORD cur_surface;
DWORD_PTR cookie;
/* for Windowless Mode */
@ -160,16 +172,92 @@ static inline VMR9DefaultAllocatorPresenterImpl *impl_from_IVMRSurfaceAllocatorE
static HRESULT VMR9DefaultAllocatorPresenterImpl_create(VMR9Impl *parent, LPVOID * ppv);
static DWORD VMR9_SendSampleData(VMR9Impl *This, VMR9PresentationInfo *info, LPBYTE data, DWORD size)
{
AM_MEDIA_TYPE *amt;
HRESULT hr = S_OK;
int width;
int height;
BITMAPINFOHEADER *bmiHeader;
D3DLOCKED_RECT lock;
TRACE("%p %p %d\n", This, data, size);
amt = &This->renderer.pInputPin->pin.mtCurrent;
if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo))
{
bmiHeader = &((VIDEOINFOHEADER *)amt->pbFormat)->bmiHeader;
}
else if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo2))
{
bmiHeader = &((VIDEOINFOHEADER2 *)amt->pbFormat)->bmiHeader;
}
else
{
FIXME("Unknown type %s\n", debugstr_guid(&amt->subtype));
return VFW_E_RUNTIME_ERROR;
}
TRACE("biSize = %d\n", bmiHeader->biSize);
TRACE("biWidth = %d\n", bmiHeader->biWidth);
TRACE("biHeight = %d\n", bmiHeader->biHeight);
TRACE("biPlanes = %d\n", bmiHeader->biPlanes);
TRACE("biBitCount = %d\n", bmiHeader->biBitCount);
TRACE("biCompression = %s\n", debugstr_an((LPSTR)&(bmiHeader->biCompression), 4));
TRACE("biSizeImage = %d\n", bmiHeader->biSizeImage);
width = bmiHeader->biWidth;
height = bmiHeader->biHeight;
TRACE("Src Rect: %d %d %d %d\n", This->source_rect.left, This->source_rect.top, This->source_rect.right, This->source_rect.bottom);
TRACE("Dst Rect: %d %d %d %d\n", This->target_rect.left, This->target_rect.top, This->target_rect.right, This->target_rect.bottom);
hr = IDirect3DSurface9_LockRect(info->lpSurf, &lock, NULL, D3DLOCK_DISCARD);
if (FAILED(hr))
{
ERR("IDirect3DSurface9_LockRect failed (%x)\n",hr);
return hr;
}
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(BaseRenderer *iface, IMediaSample * pSample)
{
VMR9Impl *This = (VMR9Impl *)iface;
LPBYTE pbSrcStream = NULL;
long cbSrcStream = 0;
REFERENCE_TIME tStart, tStop;
VMR9PresentationInfo info;
HRESULT hr;
TRACE("%p %p\n", iface, pSample);
/* It is possible that there is no device at this point */
if (!This->allocator || !This->presenter)
{
ERR("NO PRESENTER!!\n");
return S_FALSE;
}
hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
if (FAILED(hr))
info.dwFlags = VMR9Sample_SrcDstRectsValid;
@ -185,6 +273,12 @@ static HRESULT WINAPI VMR9_DoRenderSample(BaseRenderer *iface, IMediaSample * pS
if (IMediaSample_IsSyncPoint(pSample) == S_OK)
info.dwFlags |= VMR9Sample_SyncPoint;
/* If we render ourselves, and this is a preroll sample, discard it */
if (This->baseControlWindow.baseWindow.hWnd && (info.dwFlags & VMR9Sample_Preroll))
{
return S_OK;
}
hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
if (FAILED(hr))
{
@ -192,11 +286,21 @@ static HRESULT WINAPI VMR9_DoRenderSample(BaseRenderer *iface, IMediaSample * pS
return hr;
}
cbSrcStream = IMediaSample_GetActualDataLength(pSample);
info.rtStart = tStart;
info.rtEnd = tStop;
info.szAspectRatio.cx = This->bmiheader.biWidth;
info.szAspectRatio.cy = This->bmiheader.biHeight;
hr = IVMRSurfaceAllocator9_GetSurface(This->allocator, This->cookie, (++This->cur_surface)%This->num_surfaces, 0, &info.lpSurf);
if (FAILED(hr))
return hr;
VMR9_SendSampleData(This, &info, pbSrcStream, cbSrcStream);
IDirect3DSurface9_Release(info.lpSurf);
return hr;
}
@ -239,6 +343,91 @@ static HRESULT WINAPI VMR9_CheckMediaType(BaseRenderer *iface, const AM_MEDIA_TY
return S_OK;
}
static HRESULT VMR9_maybe_init(VMR9Impl *This, BOOL force)
{
VMR9AllocationInfo info;
DWORD buffers;
HRESULT hr;
TRACE("my mode: %u, my window: %p, my last window: %p\n", This->mode, This->baseControlWindow.baseWindow.hWnd, This->hWndClippingWindow);
if (This->baseControlWindow.baseWindow.hWnd || !This->renderer.pInputPin->pin.pConnectedTo)
return S_OK;
if (This->mode == VMR9Mode_Windowless && !This->hWndClippingWindow)
return (force ? VFW_E_RUNTIME_ERROR : S_OK);
TRACE("Initializing\n");
info.dwFlags = VMR9AllocFlag_TextureSurface;
info.dwHeight = This->source_rect.bottom;
info.dwWidth = This->source_rect.right;
info.Pool = D3DPOOL_DEFAULT;
info.MinBuffers = 2;
FIXME("Reduce ratio to least common denominator\n");
info.szAspectRatio.cx = info.dwWidth;
info.szAspectRatio.cy = info.dwHeight;
info.szNativeSize.cx = This->bmiheader.biWidth;
info.szNativeSize.cy = This->bmiheader.biHeight;
buffers = 2;
switch (This->bmiheader.biBitCount)
{
case 8: info.Format = D3DFMT_R3G3B2; break;
case 15: info.Format = D3DFMT_X1R5G5B5; break;
case 16: info.Format = D3DFMT_R5G6B5; break;
case 24: info.Format = D3DFMT_R8G8B8; break;
case 32: info.Format = D3DFMT_X8R8G8B8; break;
default:
FIXME("Unknown bpp %u\n", This->bmiheader.biBitCount);
hr = E_INVALIDARG;
}
This->cur_surface = 0;
if (This->num_surfaces)
{
ERR("num_surfaces or d3d9_surfaces not 0\n");
return E_FAIL;
}
hr = IVMRSurfaceAllocatorEx9_InitializeDevice(This->allocator, This->cookie, &info, &buffers);
if (SUCCEEDED(hr))
{
This->source_rect.left = This->source_rect.top = 0;
This->source_rect.right = This->bmiheader.biWidth;
This->source_rect.bottom = This->bmiheader.biHeight;
This->num_surfaces = buffers;
}
return hr;
}
static VOID WINAPI VMR9_OnStartStreaming(BaseRenderer* iface)
{
VMR9Impl *This = (VMR9Impl*)iface;
TRACE("(%p)\n", This);
VMR9_maybe_init(This, TRUE);
IVMRImagePresenter9_StartPresenting(This->presenter, This->cookie);
SetWindowPos(This->baseControlWindow.baseWindow.hWnd, NULL,
This->source_rect.left,
This->source_rect.top,
This->source_rect.right - This->source_rect.left,
This->source_rect.bottom - This->source_rect.top,
SWP_NOZORDER|SWP_NOMOVE|SWP_DEFERERASE);
ShowWindow(This->baseControlWindow.baseWindow.hWnd, SW_SHOW);
GetClientRect(This->baseControlWindow.baseWindow.hWnd, &This->target_rect);
}
static VOID WINAPI VMR9_OnStopStreaming(BaseRenderer* iface)
{
VMR9Impl *This = (VMR9Impl*)iface;
TRACE("(%p)\n", This);
if (This->renderer.filter.state == State_Running)
IVMRImagePresenter9_StopPresenting(This->presenter, This->cookie);
}
static HRESULT WINAPI VMR9_ShouldDrawSampleNow(BaseRenderer *This, IMediaSample *pSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime)
{
/* Preroll means the sample isn't shown, this is used for key frames and things like that */
@ -247,6 +436,43 @@ static HRESULT WINAPI VMR9_ShouldDrawSampleNow(BaseRenderer *This, IMediaSample
return S_FALSE;
}
HRESULT WINAPI VMR9_CompleteConnect(BaseRenderer *This, IPin *pReceivePin)
{
VMR9Impl *pVMR9 = (VMR9Impl*)This;
HRESULT hr = S_OK;
TRACE("(%p)\n", This);
if (!pVMR9->mode && SUCCEEDED(hr))
hr = IVMRFilterConfig9_SetRenderingMode(&pVMR9->IVMRFilterConfig9_iface, VMR9Mode_Windowed);
if (SUCCEEDED(hr))
hr = VMR9_maybe_init(pVMR9, FALSE);
return hr;
}
HRESULT WINAPI VMR9_BreakConnect(BaseRenderer *This)
{
VMR9Impl *pVMR9 = (VMR9Impl*)This;
HRESULT hr = S_OK;
if (!pVMR9->mode)
return S_FALSE;
if (This->pInputPin->pin.pConnectedTo && pVMR9->allocator && pVMR9->presenter)
{
if (pVMR9->renderer.filter.state != State_Stopped)
{
ERR("Disconnecting while not stopped! UNTESTED!!\n");
}
if (pVMR9->renderer.filter.state == State_Running)
hr = IVMRImagePresenter9_StopPresenting(pVMR9->presenter, pVMR9->cookie);
IVMRSurfaceAllocatorEx9_TerminateDevice(pVMR9->allocator, pVMR9->cookie);
pVMR9->num_surfaces = 0;
}
return hr;
}
static const BaseRendererFuncTable BaseFuncTable = {
VMR9_CheckMediaType,
VMR9_DoRenderSample,
@ -254,16 +480,16 @@ static const BaseRendererFuncTable BaseFuncTable = {
NULL,
NULL,
NULL,
NULL,
NULL,
VMR9_OnStartStreaming,
VMR9_OnStopStreaming,
NULL,
NULL,
NULL,
VMR9_ShouldDrawSampleNow,
NULL,
/**/
NULL,
NULL,
VMR9_CompleteConnect,
VMR9_BreakConnect,
NULL,
NULL,
NULL,
@ -565,12 +791,20 @@ static ULONG WINAPI VMR9Inner_Release(IUnknown * iface)
{
TRACE("Destroying\n");
BaseControlWindow_Destroy(&This->baseControlWindow);
CloseHandle(This->hD3d9);
if (This->allocator)
IVMRSurfaceAllocator9_Release(This->allocator);
if (This->presenter)
IVMRImagePresenter9_Release(This->presenter);
This->num_surfaces = 0;
if (This->allocator_d3d9_dev)
{
IUnknown_Release(This->allocator_d3d9_dev);
This->allocator_d3d9_dev = NULL;
}
CoTaskMemFree(This);
}
return refCount;
@ -1098,6 +1332,7 @@ static HRESULT WINAPI VMR9WindowlessControl_SetVideoClippingWindow(IVMRWindowles
EnterCriticalSection(&This->renderer.filter.csFilter);
This->hWndClippingWindow = hwnd;
VMR9_maybe_init(This, FALSE);
if (!hwnd)
IVMRSurfaceAllocatorEx9_TerminateDevice(This->allocator, This->cookie);
LeaveCriticalSection(&This->renderer.filter.csFilter);
@ -1107,9 +1342,30 @@ static HRESULT WINAPI VMR9WindowlessControl_SetVideoClippingWindow(IVMRWindowles
static HRESULT WINAPI VMR9WindowlessControl_RepaintVideo(IVMRWindowlessControl9 *iface, HWND hwnd, HDC hdc)
{
VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
HRESULT hr;
FIXME("(%p/%p)->(...) stub\n", iface, This);
return E_NOTIMPL;
FIXME("(%p/%p)->(...) semi-stub\n", iface, This);
EnterCriticalSection(&This->renderer.filter.csFilter);
if (hwnd != This->hWndClippingWindow && hwnd != This->baseControlWindow.baseWindow.hWnd)
{
ERR("Not handling changing windows yet!!!\n");
LeaveCriticalSection(&This->renderer.filter.csFilter);
return S_OK;
}
if (!This->allocator_d3d9_dev)
{
ERR("No d3d9 device!\n");
LeaveCriticalSection(&This->renderer.filter.csFilter);
return VFW_E_WRONG_STATE;
}
/* Windowless extension */
hr = IDirect3DDevice9_Present(This->allocator_d3d9_dev, NULL, NULL, This->baseControlWindow.baseWindow.hWnd, NULL);
LeaveCriticalSection(&This->renderer.filter.csFilter);
return hr;
}
static HRESULT WINAPI VMR9WindowlessControl_DisplayModeChanged(IVMRWindowlessControl9 *iface)
@ -1212,21 +1468,35 @@ static HRESULT WINAPI VMR9SurfaceAllocatorNotify_SetD3DDevice(IVMRSurfaceAllocat
{
VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
FIXME("(%p/%p)->(...) stub\n", iface, This);
return E_NOTIMPL;
FIXME("(%p/%p)->(...) semi-stub\n", iface, This);
if (This->allocator_d3d9_dev)
IDirect3DDevice9_Release(This->allocator_d3d9_dev);
This->allocator_d3d9_dev = device;
IDirect3DDevice9_AddRef(This->allocator_d3d9_dev);
This->allocator_mon = monitor;
return S_OK;
}
static HRESULT WINAPI VMR9SurfaceAllocatorNotify_ChangeD3DDevice(IVMRSurfaceAllocatorNotify9 *iface, IDirect3DDevice9 *device, HMONITOR monitor)
{
VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
FIXME("(%p/%p)->(...) stub\n", iface, This);
return E_NOTIMPL;
FIXME("(%p/%p)->(...) semi-stub\n", iface, This);
if (This->allocator_d3d9_dev)
IDirect3DDevice9_Release(This->allocator_d3d9_dev);
This->allocator_d3d9_dev = device;
IDirect3DDevice9_AddRef(This->allocator_d3d9_dev);
This->allocator_mon = monitor;
return S_OK;
}
static HRESULT WINAPI VMR9SurfaceAllocatorNotify_AllocateSurfaceHelper(IVMRSurfaceAllocatorNotify9 *iface, VMR9AllocationInfo *allocinfo, DWORD *numbuffers, IDirect3DSurface9 **surface)
{
VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
INT i;
HRESULT hr = S_OK;
FIXME("(%p/%p)->(%p, %p => %u, %p) semi-stub\n", iface, This, allocinfo, numbuffers, (numbuffers ? *numbuffers : 0), surface);
@ -1239,7 +1509,59 @@ static HRESULT WINAPI VMR9SurfaceAllocatorNotify_AllocateSurfaceHelper(IVMRSurfa
return E_INVALIDARG;
}
return E_NOTIMPL;
if (!This->allocator_d3d9_dev)
{
ERR("No direct3d device when requested to allocate a surface!\n");
return VFW_E_WRONG_STATE;
}
if (allocinfo->dwFlags & VMR9AllocFlag_OffscreenSurface)
{
ERR("Creating offscreen surface\n");
for (i = 0; i < *numbuffers; ++i)
{
hr = IDirect3DDevice9_CreateOffscreenPlainSurface(This->allocator_d3d9_dev, allocinfo->dwWidth, allocinfo->dwHeight,
allocinfo->Format, allocinfo->Pool, &surface[i], NULL);
if (FAILED(hr))
break;
}
}
else if (allocinfo->dwFlags & VMR9AllocFlag_TextureSurface)
{
TRACE("Creating texture surface\n");
for (i = 0; i < *numbuffers; ++i)
{
IDirect3DTexture9 *texture;
hr = IDirect3DDevice9_CreateTexture(This->allocator_d3d9_dev, allocinfo->dwWidth, allocinfo->dwHeight, 1, 0,
allocinfo->Format, allocinfo->Pool, &texture, NULL);
if (FAILED(hr))
break;
IDirect3DTexture9_GetSurfaceLevel(texture, 0, &surface[i]);
IDirect3DTexture9_Release(texture);
}
}
else
{
FIXME("Could not allocate for type %08x\n", allocinfo->dwFlags);
return E_NOTIMPL;
}
if (i >= allocinfo->MinBuffers)
{
hr = S_OK;
*numbuffers = i;
}
else
{
ERR("Allocation failed\n");
for (--i; i >= 0; --i)
{
IDirect3DSurface9_Release(surface[i]);
}
*numbuffers = 0;
}
return hr;
}
static HRESULT WINAPI VMR9SurfaceAllocatorNotify_NotifyEvent(IVMRSurfaceAllocatorNotify9 *iface, LONG code, LONG_PTR param1, LONG_PTR param2)
@ -1273,6 +1595,14 @@ HRESULT VMR9Impl_create(IUnknown * outer_unk, LPVOID * ppv)
pVMR9 = CoTaskMemAlloc(sizeof(VMR9Impl));
pVMR9->hD3d9 = LoadLibraryA("d3d9.dll");
if (!pVMR9->hD3d9 )
{
WARN("Could not load d3d9.dll\n");
CoTaskMemFree(pVMR9);
return VFW_E_DDRAW_CAPS_NOT_SUITABLE;
}
pVMR9->outer_unk = outer_unk;
pVMR9->bUnkOuterValid = FALSE;
pVMR9->bAggregatable = FALSE;
@ -1280,6 +1610,9 @@ HRESULT VMR9Impl_create(IUnknown * outer_unk, LPVOID * ppv)
pVMR9->IAMFilterMiscFlags_iface.lpVtbl = &IAMFilterMiscFlags_Vtbl;
pVMR9->mode = 0;
pVMR9->allocator_d3d9_dev = NULL;
pVMR9->allocator_mon= NULL;
pVMR9->num_surfaces = pVMR9->cur_surface = 0;
pVMR9->allocator = NULL;
pVMR9->presenter = NULL;
pVMR9->hWndClippingWindow = NULL;
@ -1307,6 +1640,7 @@ HRESULT VMR9Impl_create(IUnknown * outer_unk, LPVOID * ppv)
fail:
BaseRendererImpl_Release(&pVMR9->renderer.filter.IBaseFilter_iface);
CloseHandle(pVMR9->hD3d9);
CoTaskMemFree(pVMR9);
return hr;
}
@ -1909,6 +2243,16 @@ static const IVMRSurfaceAllocatorEx9Vtbl VMR9_SurfaceAllocator =
NULL /* This isn't the SurfaceAllocatorEx type yet, working on it */
};
static IDirect3D9 *init_d3d9(HMODULE d3d9_handle)
{
IDirect3D9 * (__stdcall * d3d9_create)(UINT SDKVersion);
d3d9_create = (void *)GetProcAddress(d3d9_handle, "Direct3DCreate9");
if (!d3d9_create) return NULL;
return d3d9_create(D3D_SDK_VERSION);
}
static HRESULT VMR9DefaultAllocatorPresenterImpl_create(VMR9Impl *parent, LPVOID * ppv)
{
HRESULT hr = S_OK;
@ -1919,7 +2263,7 @@ static HRESULT VMR9DefaultAllocatorPresenterImpl_create(VMR9Impl *parent, LPVOID
if (!This)
return E_OUTOFMEMORY;
This->d3d9_ptr = NULL;
This->d3d9_ptr = init_d3d9(parent->hD3d9);
if (!This->d3d9_ptr)
{
WARN("Could not initialize d3d9.dll\n");