wine/dlls/quartz/vmr9.c
2012-08-15 12:17:54 +02:00

2309 lines
72 KiB
C

/*
* Video Mixing Renderer for dx9
*
* Copyright 2004 Christian Costa
* Copyright 2008 Maarten Lankhorst
* Copyright 2012 Aric Stewart
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#define NONAMELESSSTRUCT
#define NONAMELESSUNION
#include "quartz_private.h"
#include "uuids.h"
#include "vfwmsgs.h"
#include "amvideo.h"
#include "windef.h"
#include "winbase.h"
#include "dshow.h"
#include "evcode.h"
#include "strmif.h"
#include "ddraw.h"
#include "dvdmedia.h"
#include "d3d9.h"
#include "vmr9.h"
#include "pin.h"
#include "wine/unicode.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(quartz);
typedef struct
{
BaseRenderer renderer;
BaseControlWindow baseControlWindow;
BaseControlVideo baseControlVideo;
IUnknown IUnknown_inner;
IAMFilterMiscFlags IAMFilterMiscFlags_iface;
IVMRFilterConfig9 IVMRFilterConfig9_iface;
IVMRWindowlessControl9 IVMRWindowlessControl9_iface;
IVMRSurfaceAllocatorNotify9 IVMRSurfaceAllocatorNotify9_iface;
IVMRSurfaceAllocatorEx9 *allocator;
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 */
HWND hWndClippingWindow;
RECT source_rect;
RECT target_rect;
LONG VideoWidth;
LONG VideoHeight;
} VMR9Impl;
static inline VMR9Impl *impl_from_inner_IUnknown(IUnknown *iface)
{
return CONTAINING_RECORD(iface, VMR9Impl, IUnknown_inner);
}
static inline VMR9Impl *impl_from_BaseWindow( BaseWindow *wnd )
{
return CONTAINING_RECORD(wnd, VMR9Impl, baseControlWindow.baseWindow);
}
static inline VMR9Impl *impl_from_IVideoWindow( IVideoWindow *iface)
{
return CONTAINING_RECORD(iface, VMR9Impl, baseControlWindow.IVideoWindow_iface);
}
static inline VMR9Impl *impl_from_BaseControlVideo( BaseControlVideo *cvid )
{
return CONTAINING_RECORD(cvid, VMR9Impl, baseControlVideo);
}
static inline VMR9Impl *impl_from_IBasicVideo( IBasicVideo *iface)
{
return CONTAINING_RECORD(iface, VMR9Impl, baseControlVideo.IBasicVideo_iface);
}
static inline VMR9Impl *impl_from_IAMFilterMiscFlags( IAMFilterMiscFlags *iface)
{
return CONTAINING_RECORD(iface, VMR9Impl, IAMFilterMiscFlags_iface);
}
static inline VMR9Impl *impl_from_IVMRFilterConfig9( IVMRFilterConfig9 *iface)
{
return CONTAINING_RECORD(iface, VMR9Impl, IVMRFilterConfig9_iface);
}
static inline VMR9Impl *impl_from_IVMRWindowlessControl9( IVMRWindowlessControl9 *iface)
{
return CONTAINING_RECORD(iface, VMR9Impl, IVMRWindowlessControl9_iface);
}
static inline VMR9Impl *impl_from_IVMRSurfaceAllocatorNotify9( IVMRSurfaceAllocatorNotify9 *iface)
{
return CONTAINING_RECORD(iface, VMR9Impl, IVMRSurfaceAllocatorNotify9_iface);
}
typedef struct
{
IVMRImagePresenter9 IVMRImagePresenter9_iface;
IVMRSurfaceAllocatorEx9 IVMRSurfaceAllocatorEx9_iface;
LONG refCount;
HANDLE ack;
DWORD tid;
HANDLE hWndThread;
IDirect3DDevice9 *d3d9_dev;
IDirect3D9 *d3d9_ptr;
IDirect3DSurface9 **d3d9_surfaces;
IDirect3DVertexBuffer9 *d3d9_vertex;
HMONITOR hMon;
DWORD num_surfaces;
BOOL reset;
VMR9AllocationInfo info;
VMR9Impl* pVMR9;
IVMRSurfaceAllocatorNotify9 *SurfaceAllocatorNotify;
} VMR9DefaultAllocatorPresenterImpl;
static inline VMR9DefaultAllocatorPresenterImpl *impl_from_IVMRImagePresenter9( IVMRImagePresenter9 *iface)
{
return CONTAINING_RECORD(iface, VMR9DefaultAllocatorPresenterImpl, IVMRImagePresenter9_iface);
}
static inline VMR9DefaultAllocatorPresenterImpl *impl_from_IVMRSurfaceAllocatorEx9( IVMRSurfaceAllocatorEx9 *iface)
{
return CONTAINING_RECORD(iface, VMR9DefaultAllocatorPresenterImpl, IVMRSurfaceAllocatorEx9_iface);
}
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;
else
info.dwFlags = VMR9Sample_SrcDstRectsValid | VMR9Sample_TimeValid;
if (IMediaSample_IsDiscontinuity(pSample) == S_OK)
info.dwFlags |= VMR9Sample_Discontinuity;
if (IMediaSample_IsPreroll(pSample) == S_OK)
info.dwFlags |= VMR9Sample_Preroll;
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))
{
ERR("Cannot get pointer to sample data (%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;
hr = IVMRSurfaceAllocatorEx9_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;
}
static HRESULT WINAPI VMR9_CheckMediaType(BaseRenderer *iface, const AM_MEDIA_TYPE * pmt)
{
VMR9Impl *This = (VMR9Impl*)iface;
if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) || !pmt->pbFormat)
return S_FALSE;
/* Ignore subtype, test for bicompression instead */
if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo))
{
VIDEOINFOHEADER *format = (VIDEOINFOHEADER *)pmt->pbFormat;
This->bmiheader = format->bmiHeader;
TRACE("Resolution: %dx%d\n", format->bmiHeader.biWidth, format->bmiHeader.biHeight);
This->source_rect.right = This->VideoWidth = format->bmiHeader.biWidth;
This->source_rect.bottom = This->VideoHeight = format->bmiHeader.biHeight;
This->source_rect.top = This->source_rect.left = 0;
}
else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2))
{
VIDEOINFOHEADER2 *format = (VIDEOINFOHEADER2 *)pmt->pbFormat;
This->bmiheader = format->bmiHeader;
TRACE("Resolution: %dx%d\n", format->bmiHeader.biWidth, format->bmiHeader.biHeight);
This->source_rect.right = This->VideoWidth = format->bmiHeader.biWidth;
This->source_rect.bottom = This->VideoHeight = format->bmiHeader.biHeight;
This->source_rect.top = This->source_rect.left = 0;
}
else
{
ERR("Format type %s not supported\n", debugstr_guid(&pmt->formattype));
return S_FALSE;
}
if (This->bmiheader.biCompression)
return S_FALSE;
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 */
if (IMediaSample_IsPreroll(pSample) == S_OK)
return E_FAIL;
return S_FALSE;
}
static 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;
}
static 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,
/**/
NULL,
NULL,
NULL,
VMR9_OnStartStreaming,
VMR9_OnStopStreaming,
NULL,
NULL,
NULL,
VMR9_ShouldDrawSampleNow,
NULL,
/**/
VMR9_CompleteConnect,
VMR9_BreakConnect,
NULL,
NULL,
NULL,
};
static LPWSTR WINAPI VMR9_GetClassWindowStyles(BaseWindow *This, DWORD *pClassStyles, DWORD *pWindowStyles, DWORD *pWindowStylesEx)
{
static WCHAR classnameW[] = { 'I','V','M','R','9',' ','C','l','a','s','s', 0 };
*pClassStyles = 0;
*pWindowStyles = WS_SIZEBOX;
*pWindowStylesEx = 0;
return classnameW;
}
static RECT WINAPI VMR9_GetDefaultRect(BaseWindow *This)
{
VMR9Impl* pVMR9 = impl_from_BaseWindow(This);
static RECT defRect;
defRect.left = defRect.top = 0;
defRect.right = pVMR9->VideoWidth;
defRect.bottom = pVMR9->VideoHeight;
return defRect;
}
static BOOL WINAPI VMR9_OnSize(BaseWindow *This, LONG Width, LONG Height)
{
VMR9Impl* pVMR9 = impl_from_BaseWindow(This);
TRACE("WM_SIZE %d %d\n", Width, Height);
GetClientRect(This->hWnd, &pVMR9->target_rect);
TRACE("WM_SIZING: DestRect=(%d,%d),(%d,%d)\n",
pVMR9->target_rect.left,
pVMR9->target_rect.top,
pVMR9->target_rect.right - pVMR9->target_rect.left,
pVMR9->target_rect.bottom - pVMR9->target_rect.top);
return BaseWindowImpl_OnSize(This, Width, Height);
}
static const BaseWindowFuncTable renderer_BaseWindowFuncTable = {
VMR9_GetClassWindowStyles,
VMR9_GetDefaultRect,
NULL,
BaseControlWindowImpl_PossiblyEatMessage,
VMR9_OnSize,
};
static HRESULT WINAPI VMR9_GetSourceRect(BaseControlVideo* This, RECT *pSourceRect)
{
VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
CopyRect(pSourceRect,&pVMR9->source_rect);
return S_OK;
}
static HRESULT WINAPI VMR9_GetStaticImage(BaseControlVideo* This, LONG *pBufferSize, LONG *pDIBImage)
{
VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
BITMAPINFOHEADER *bmiHeader;
LONG needed_size;
AM_MEDIA_TYPE *amt = &pVMR9->renderer.pInputPin->pin.mtCurrent;
char *ptr;
FIXME("(%p/%p)->(%p, %p): partial stub\n", pVMR9, This, pBufferSize, pDIBImage);
EnterCriticalSection(&pVMR9->renderer.filter.csFilter);
if (!pVMR9->renderer.pMediaSample)
{
LeaveCriticalSection(&pVMR9->renderer.filter.csFilter);
return (pVMR9->renderer.filter.state == State_Paused ? E_UNEXPECTED : VFW_E_NOT_PAUSED);
}
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));
LeaveCriticalSection(&pVMR9->renderer.filter.csFilter);
return VFW_E_RUNTIME_ERROR;
}
needed_size = bmiHeader->biSize;
needed_size += IMediaSample_GetActualDataLength(pVMR9->renderer.pMediaSample);
if (!pDIBImage)
{
*pBufferSize = needed_size;
LeaveCriticalSection(&pVMR9->renderer.filter.csFilter);
return S_OK;
}
if (needed_size < *pBufferSize)
{
ERR("Buffer too small %u/%u\n", needed_size, *pBufferSize);
LeaveCriticalSection(&pVMR9->renderer.filter.csFilter);
return E_FAIL;
}
*pBufferSize = needed_size;
memcpy(pDIBImage, bmiHeader, bmiHeader->biSize);
IMediaSample_GetPointer(pVMR9->renderer.pMediaSample, (BYTE **)&ptr);
memcpy((char *)pDIBImage + bmiHeader->biSize, ptr, IMediaSample_GetActualDataLength(pVMR9->renderer.pMediaSample));
LeaveCriticalSection(&pVMR9->renderer.filter.csFilter);
return S_OK;
}
static HRESULT WINAPI VMR9_GetTargetRect(BaseControlVideo* This, RECT *pTargetRect)
{
VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
CopyRect(pTargetRect,&pVMR9->target_rect);
return S_OK;
}
static VIDEOINFOHEADER* WINAPI VMR9_GetVideoFormat(BaseControlVideo* This)
{
VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
AM_MEDIA_TYPE *pmt;
TRACE("(%p/%p)\n", pVMR9, This);
pmt = &pVMR9->renderer.pInputPin->pin.mtCurrent;
if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) {
return (VIDEOINFOHEADER*)pmt->pbFormat;
} else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2)) {
static VIDEOINFOHEADER vih;
VIDEOINFOHEADER2 *vih2 = (VIDEOINFOHEADER2*)pmt->pbFormat;
memcpy(&vih,vih2,sizeof(VIDEOINFOHEADER));
memcpy(&vih.bmiHeader, &vih2->bmiHeader, sizeof(BITMAPINFOHEADER));
return &vih;
} else {
ERR("Unknown format type %s\n", qzdebugstr_guid(&pmt->formattype));
return NULL;
}
}
static HRESULT WINAPI VMR9_IsDefaultSourceRect(BaseControlVideo* This)
{
VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
FIXME("(%p/%p)->(): stub !!!\n", pVMR9, This);
return S_OK;
}
static HRESULT WINAPI VMR9_IsDefaultTargetRect(BaseControlVideo* This)
{
VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
FIXME("(%p/%p)->(): stub !!!\n", pVMR9, This);
return S_OK;
}
static HRESULT WINAPI VMR9_SetDefaultSourceRect(BaseControlVideo* This)
{
VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
pVMR9->source_rect.left = 0;
pVMR9->source_rect.top = 0;
pVMR9->source_rect.right = pVMR9->VideoWidth;
pVMR9->source_rect.bottom = pVMR9->VideoHeight;
return S_OK;
}
static HRESULT WINAPI VMR9_SetDefaultTargetRect(BaseControlVideo* This)
{
RECT rect;
VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
if (!GetClientRect(pVMR9->baseControlWindow.baseWindow.hWnd, &rect))
return E_FAIL;
pVMR9->target_rect.left = 0;
pVMR9->target_rect.top = 0;
pVMR9->target_rect.right = rect.right;
pVMR9->target_rect.bottom = rect.bottom;
return S_OK;
}
static HRESULT WINAPI VMR9_SetSourceRect(BaseControlVideo* This, RECT *pSourceRect)
{
VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
CopyRect(&pVMR9->source_rect,pSourceRect);
return S_OK;
}
static HRESULT WINAPI VMR9_SetTargetRect(BaseControlVideo* This, RECT *pTargetRect)
{
VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
CopyRect(&pVMR9->target_rect,pTargetRect);
return S_OK;
}
static const BaseControlVideoFuncTable renderer_BaseControlVideoFuncTable = {
VMR9_GetSourceRect,
VMR9_GetStaticImage,
VMR9_GetTargetRect,
VMR9_GetVideoFormat,
VMR9_IsDefaultSourceRect,
VMR9_IsDefaultTargetRect,
VMR9_SetDefaultSourceRect,
VMR9_SetDefaultTargetRect,
VMR9_SetSourceRect,
VMR9_SetTargetRect
};
static HRESULT WINAPI VMR9Inner_QueryInterface(IUnknown * iface, REFIID riid, LPVOID * ppv)
{
VMR9Impl *This = impl_from_inner_IUnknown(iface);
TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
if (This->bAggregatable)
This->bUnkOuterValid = TRUE;
*ppv = NULL;
if (IsEqualIID(riid, &IID_IUnknown))
*ppv = &This->IUnknown_inner;
else if (IsEqualIID(riid, &IID_IVideoWindow))
*ppv = &This->baseControlWindow.IVideoWindow_iface;
else if (IsEqualIID(riid, &IID_IBasicVideo))
*ppv = &This->baseControlVideo.IBasicVideo_iface;
else if (IsEqualIID(riid, &IID_IAMFilterMiscFlags))
*ppv = &This->IAMFilterMiscFlags_iface;
else if (IsEqualIID(riid, &IID_IVMRFilterConfig9))
*ppv = &This->IVMRFilterConfig9_iface;
else if (IsEqualIID(riid, &IID_IVMRWindowlessControl9) && This->mode == VMR9Mode_Windowless)
*ppv = &This->IVMRWindowlessControl9_iface;
else if (IsEqualIID(riid, &IID_IVMRSurfaceAllocatorNotify9) && This->mode == VMR9Mode_Renderless)
*ppv = &This->IVMRSurfaceAllocatorNotify9_iface;
else
{
HRESULT hr;
hr = BaseRendererImpl_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
if (SUCCEEDED(hr))
return hr;
}
if (*ppv)
{
IUnknown_AddRef((IUnknown *)(*ppv));
return S_OK;
}
else if (IsEqualIID(riid, &IID_IBasicVideo2))
FIXME("No interface for IID_IBasicVideo2\n");
else if (IsEqualIID(riid, &IID_IVMRWindowlessControl9))
;
else if (IsEqualIID(riid, &IID_IVMRSurfaceAllocatorNotify9))
;
else if (IsEqualIID(riid, &IID_IMediaPosition))
FIXME("No interface for IID_IMediaPosition\n");
else if (IsEqualIID(riid, &IID_IQualProp))
FIXME("No interface for IID_IQualProp\n");
else if (IsEqualIID(riid, &IID_IVMRAspectRatioControl9))
FIXME("No interface for IID_IVMRAspectRatioControl9\n");
else if (IsEqualIID(riid, &IID_IVMRDeinterlaceControl9))
FIXME("No interface for IID_IVMRDeinterlaceControl9\n");
else if (IsEqualIID(riid, &IID_IVMRMixerBitmap9))
FIXME("No interface for IID_IVMRMixerBitmap9\n");
else if (IsEqualIID(riid, &IID_IVMRMonitorConfig9))
FIXME("No interface for IID_IVMRMonitorConfig9\n");
else if (IsEqualIID(riid, &IID_IVMRMixerControl9))
FIXME("No interface for IID_IVMRMixerControl9\n");
else
FIXME("No interface for %s\n", debugstr_guid(riid));
return E_NOINTERFACE;
}
static ULONG WINAPI VMR9Inner_AddRef(IUnknown * iface)
{
VMR9Impl *This = impl_from_inner_IUnknown(iface);
ULONG refCount = BaseFilterImpl_AddRef(&This->renderer.filter.IBaseFilter_iface);
TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
return refCount;
}
static ULONG WINAPI VMR9Inner_Release(IUnknown * iface)
{
VMR9Impl *This = impl_from_inner_IUnknown(iface);
ULONG refCount = BaseRendererImpl_Release(&This->renderer.filter.IBaseFilter_iface);
TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
if (!refCount)
{
TRACE("Destroying\n");
BaseControlWindow_Destroy(&This->baseControlWindow);
CloseHandle(This->hD3d9);
if (This->allocator)
IVMRSurfaceAllocatorEx9_Release(This->allocator);
if (This->presenter)
IVMRImagePresenter9_Release(This->presenter);
This->num_surfaces = 0;
if (This->allocator_d3d9_dev)
{
IDirect3DDevice9_Release(This->allocator_d3d9_dev);
This->allocator_d3d9_dev = NULL;
}
CoTaskMemFree(This);
}
return refCount;
}
static const IUnknownVtbl IInner_VTable =
{
VMR9Inner_QueryInterface,
VMR9Inner_AddRef,
VMR9Inner_Release
};
static HRESULT WINAPI VMR9_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
{
VMR9Impl *This = (VMR9Impl *)iface;
if (This->bAggregatable)
This->bUnkOuterValid = TRUE;
if (This->outer_unk)
{
if (This->bAggregatable)
return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
if (IsEqualIID(riid, &IID_IUnknown))
{
HRESULT hr;
IUnknown_AddRef(&This->IUnknown_inner);
hr = IUnknown_QueryInterface(&This->IUnknown_inner, riid, ppv);
IUnknown_Release(&This->IUnknown_inner);
This->bAggregatable = TRUE;
return hr;
}
*ppv = NULL;
return E_NOINTERFACE;
}
return IUnknown_QueryInterface(&This->IUnknown_inner, riid, ppv);
}
static ULONG WINAPI VMR9_AddRef(IBaseFilter * iface)
{
VMR9Impl *This = (VMR9Impl *)iface;
LONG ret;
if (This->outer_unk && This->bUnkOuterValid)
ret = IUnknown_AddRef(This->outer_unk);
else
ret = IUnknown_AddRef(&This->IUnknown_inner);
TRACE("(%p)->AddRef from %d\n", iface, ret - 1);
return ret;
}
static ULONG WINAPI VMR9_Release(IBaseFilter * iface)
{
VMR9Impl *This = (VMR9Impl *)iface;
LONG ret;
if (This->outer_unk && This->bUnkOuterValid)
ret = IUnknown_Release(This->outer_unk);
else
ret = IUnknown_Release(&This->IUnknown_inner);
TRACE("(%p)->Release from %d\n", iface, ret + 1);
if (ret)
return ret;
return 0;
}
static const IBaseFilterVtbl VMR9_Vtbl =
{
VMR9_QueryInterface,
VMR9_AddRef,
VMR9_Release,
BaseFilterImpl_GetClassID,
BaseRendererImpl_Stop,
BaseRendererImpl_Pause,
BaseRendererImpl_Run,
BaseRendererImpl_GetState,
BaseRendererImpl_SetSyncSource,
BaseFilterImpl_GetSyncSource,
BaseFilterImpl_EnumPins,
BaseRendererImpl_FindPin,
BaseFilterImpl_QueryFilterInfo,
BaseFilterImpl_JoinFilterGraph,
BaseFilterImpl_QueryVendorInfo
};
/*** IUnknown methods ***/
static HRESULT WINAPI Videowindow_QueryInterface(IVideoWindow *iface, REFIID riid, LPVOID*ppvObj)
{
VMR9Impl *This = impl_from_IVideoWindow(iface);
TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppvObj);
}
static ULONG WINAPI Videowindow_AddRef(IVideoWindow *iface)
{
VMR9Impl *This = impl_from_IVideoWindow(iface);
TRACE("(%p/%p)->()\n", This, iface);
return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
}
static ULONG WINAPI Videowindow_Release(IVideoWindow *iface)
{
VMR9Impl *This = impl_from_IVideoWindow(iface);
TRACE("(%p/%p)->()\n", This, iface);
return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
}
static const IVideoWindowVtbl IVideoWindow_VTable =
{
Videowindow_QueryInterface,
Videowindow_AddRef,
Videowindow_Release,
BaseControlWindowImpl_GetTypeInfoCount,
BaseControlWindowImpl_GetTypeInfo,
BaseControlWindowImpl_GetIDsOfNames,
BaseControlWindowImpl_Invoke,
BaseControlWindowImpl_put_Caption,
BaseControlWindowImpl_get_Caption,
BaseControlWindowImpl_put_WindowStyle,
BaseControlWindowImpl_get_WindowStyle,
BaseControlWindowImpl_put_WindowStyleEx,
BaseControlWindowImpl_get_WindowStyleEx,
BaseControlWindowImpl_put_AutoShow,
BaseControlWindowImpl_get_AutoShow,
BaseControlWindowImpl_put_WindowState,
BaseControlWindowImpl_get_WindowState,
BaseControlWindowImpl_put_BackgroundPalette,
BaseControlWindowImpl_get_BackgroundPalette,
BaseControlWindowImpl_put_Visible,
BaseControlWindowImpl_get_Visible,
BaseControlWindowImpl_put_Left,
BaseControlWindowImpl_get_Left,
BaseControlWindowImpl_put_Width,
BaseControlWindowImpl_get_Width,
BaseControlWindowImpl_put_Top,
BaseControlWindowImpl_get_Top,
BaseControlWindowImpl_put_Height,
BaseControlWindowImpl_get_Height,
BaseControlWindowImpl_put_Owner,
BaseControlWindowImpl_get_Owner,
BaseControlWindowImpl_put_MessageDrain,
BaseControlWindowImpl_get_MessageDrain,
BaseControlWindowImpl_get_BorderColor,
BaseControlWindowImpl_put_BorderColor,
BaseControlWindowImpl_get_FullScreenMode,
BaseControlWindowImpl_put_FullScreenMode,
BaseControlWindowImpl_SetWindowForeground,
BaseControlWindowImpl_NotifyOwnerMessage,
BaseControlWindowImpl_SetWindowPosition,
BaseControlWindowImpl_GetWindowPosition,
BaseControlWindowImpl_GetMinIdealImageSize,
BaseControlWindowImpl_GetMaxIdealImageSize,
BaseControlWindowImpl_GetRestorePosition,
BaseControlWindowImpl_HideCursor,
BaseControlWindowImpl_IsCursorHidden
};
/*** IUnknown methods ***/
static HRESULT WINAPI Basicvideo_QueryInterface(IBasicVideo *iface, REFIID riid, LPVOID * ppvObj)
{
VMR9Impl *This = impl_from_IBasicVideo(iface);
TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppvObj);
}
static ULONG WINAPI Basicvideo_AddRef(IBasicVideo *iface)
{
VMR9Impl *This = impl_from_IBasicVideo(iface);
TRACE("(%p/%p)->()\n", This, iface);
return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
}
static ULONG WINAPI Basicvideo_Release(IBasicVideo *iface)
{
VMR9Impl *This = impl_from_IBasicVideo(iface);
TRACE("(%p/%p)->()\n", This, iface);
return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
}
static const IBasicVideoVtbl IBasicVideo_VTable =
{
Basicvideo_QueryInterface,
Basicvideo_AddRef,
Basicvideo_Release,
BaseControlVideoImpl_GetTypeInfoCount,
BaseControlVideoImpl_GetTypeInfo,
BaseControlVideoImpl_GetIDsOfNames,
BaseControlVideoImpl_Invoke,
BaseControlVideoImpl_get_AvgTimePerFrame,
BaseControlVideoImpl_get_BitRate,
BaseControlVideoImpl_get_BitErrorRate,
BaseControlVideoImpl_get_VideoWidth,
BaseControlVideoImpl_get_VideoHeight,
BaseControlVideoImpl_put_SourceLeft,
BaseControlVideoImpl_get_SourceLeft,
BaseControlVideoImpl_put_SourceWidth,
BaseControlVideoImpl_get_SourceWidth,
BaseControlVideoImpl_put_SourceTop,
BaseControlVideoImpl_get_SourceTop,
BaseControlVideoImpl_put_SourceHeight,
BaseControlVideoImpl_get_SourceHeight,
BaseControlVideoImpl_put_DestinationLeft,
BaseControlVideoImpl_get_DestinationLeft,
BaseControlVideoImpl_put_DestinationWidth,
BaseControlVideoImpl_get_DestinationWidth,
BaseControlVideoImpl_put_DestinationTop,
BaseControlVideoImpl_get_DestinationTop,
BaseControlVideoImpl_put_DestinationHeight,
BaseControlVideoImpl_get_DestinationHeight,
BaseControlVideoImpl_SetSourcePosition,
BaseControlVideoImpl_GetSourcePosition,
BaseControlVideoImpl_SetDefaultSourcePosition,
BaseControlVideoImpl_SetDestinationPosition,
BaseControlVideoImpl_GetDestinationPosition,
BaseControlVideoImpl_SetDefaultDestinationPosition,
BaseControlVideoImpl_GetVideoSize,
BaseControlVideoImpl_GetVideoPaletteEntries,
BaseControlVideoImpl_GetCurrentImage,
BaseControlVideoImpl_IsUsingDefaultSource,
BaseControlVideoImpl_IsUsingDefaultDestination
};
static HRESULT WINAPI AMFilterMiscFlags_QueryInterface(IAMFilterMiscFlags *iface, REFIID riid, void **ppv) {
VMR9Impl *This = impl_from_IAMFilterMiscFlags(iface);
return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
}
static ULONG WINAPI AMFilterMiscFlags_AddRef(IAMFilterMiscFlags *iface) {
VMR9Impl *This = impl_from_IAMFilterMiscFlags(iface);
return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
}
static ULONG WINAPI AMFilterMiscFlags_Release(IAMFilterMiscFlags *iface) {
VMR9Impl *This = impl_from_IAMFilterMiscFlags(iface);
return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
}
static ULONG WINAPI AMFilterMiscFlags_GetMiscFlags(IAMFilterMiscFlags *iface) {
return AM_FILTER_MISC_FLAGS_IS_RENDERER;
}
static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl = {
AMFilterMiscFlags_QueryInterface,
AMFilterMiscFlags_AddRef,
AMFilterMiscFlags_Release,
AMFilterMiscFlags_GetMiscFlags
};
static HRESULT WINAPI VMR9FilterConfig_QueryInterface(IVMRFilterConfig9 *iface, REFIID riid, LPVOID * ppv)
{
VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
}
static ULONG WINAPI VMR9FilterConfig_AddRef(IVMRFilterConfig9 *iface)
{
VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
}
static ULONG WINAPI VMR9FilterConfig_Release(IVMRFilterConfig9 *iface)
{
VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
}
static HRESULT WINAPI VMR9FilterConfig_SetImageCompositor(IVMRFilterConfig9 *iface, IVMRImageCompositor9 *compositor)
{
VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
FIXME("(%p/%p)->(%p) stub\n", iface, This, compositor);
return E_NOTIMPL;
}
static HRESULT WINAPI VMR9FilterConfig_SetNumberOfStreams(IVMRFilterConfig9 *iface, DWORD max)
{
VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
FIXME("(%p/%p)->(%u) stub\n", iface, This, max);
return E_NOTIMPL;
}
static HRESULT WINAPI VMR9FilterConfig_GetNumberOfStreams(IVMRFilterConfig9 *iface, DWORD *max)
{
VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
FIXME("(%p/%p)->(%p) stub\n", iface, This, max);
return E_NOTIMPL;
}
static HRESULT WINAPI VMR9FilterConfig_SetRenderingPrefs(IVMRFilterConfig9 *iface, DWORD renderflags)
{
VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
FIXME("(%p/%p)->(%u) stub\n", iface, This, renderflags);
return E_NOTIMPL;
}
static HRESULT WINAPI VMR9FilterConfig_GetRenderingPrefs(IVMRFilterConfig9 *iface, DWORD *renderflags)
{
VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
FIXME("(%p/%p)->(%p) stub\n", iface, This, renderflags);
return E_NOTIMPL;
}
static HRESULT WINAPI VMR9FilterConfig_SetRenderingMode(IVMRFilterConfig9 *iface, DWORD mode)
{
HRESULT hr = S_OK;
VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
TRACE("(%p/%p)->(%u)\n", iface, This, mode);
EnterCriticalSection(&This->renderer.filter.csFilter);
if (This->mode)
{
LeaveCriticalSection(&This->renderer.filter.csFilter);
return VFW_E_WRONG_STATE;
}
if (This->allocator)
IVMRSurfaceAllocatorEx9_Release(This->allocator);
if (This->presenter)
IVMRImagePresenter9_Release(This->presenter);
This->allocator = NULL;
This->presenter = NULL;
switch (mode)
{
case VMR9Mode_Windowed:
case VMR9Mode_Windowless:
This->allocator_is_ex = 0;
This->cookie = ~0;
hr = VMR9DefaultAllocatorPresenterImpl_create(This, (LPVOID*)&This->presenter);
if (SUCCEEDED(hr))
hr = IVMRImagePresenter9_QueryInterface(This->presenter, &IID_IVMRSurfaceAllocatorEx9, (LPVOID*)&This->allocator);
if (FAILED(hr))
{
ERR("Unable to find Presenter interface\n");
IVMRImagePresenter9_Release(This->presenter);
This->allocator = NULL;
This->presenter = NULL;
}
else
hr = IVMRSurfaceAllocatorEx9_AdviseNotify(This->allocator, &This->IVMRSurfaceAllocatorNotify9_iface);
break;
case VMR9Mode_Renderless:
break;
default:
LeaveCriticalSection(&This->renderer.filter.csFilter);
return E_INVALIDARG;
}
This->mode = mode;
LeaveCriticalSection(&This->renderer.filter.csFilter);
return hr;
}
static HRESULT WINAPI VMR9FilterConfig_GetRenderingMode(IVMRFilterConfig9 *iface, DWORD *mode)
{
VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
TRACE("(%p/%p)->(%p) stub\n", iface, This, mode);
if (!mode)
return E_POINTER;
if (This->mode)
*mode = This->mode;
else
*mode = VMR9Mode_Windowed;
return S_OK;
}
static const IVMRFilterConfig9Vtbl VMR9_FilterConfig_Vtbl =
{
VMR9FilterConfig_QueryInterface,
VMR9FilterConfig_AddRef,
VMR9FilterConfig_Release,
VMR9FilterConfig_SetImageCompositor,
VMR9FilterConfig_SetNumberOfStreams,
VMR9FilterConfig_GetNumberOfStreams,
VMR9FilterConfig_SetRenderingPrefs,
VMR9FilterConfig_GetRenderingPrefs,
VMR9FilterConfig_SetRenderingMode,
VMR9FilterConfig_GetRenderingMode
};
static HRESULT WINAPI VMR9WindowlessControl_QueryInterface(IVMRWindowlessControl9 *iface, REFIID riid, LPVOID * ppv)
{
VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
}
static ULONG WINAPI VMR9WindowlessControl_AddRef(IVMRWindowlessControl9 *iface)
{
VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
}
static ULONG WINAPI VMR9WindowlessControl_Release(IVMRWindowlessControl9 *iface)
{
VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
}
static HRESULT WINAPI VMR9WindowlessControl_GetNativeVideoSize(IVMRWindowlessControl9 *iface, LONG *width, LONG *height, LONG *arwidth, LONG *arheight)
{
VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
TRACE("(%p/%p)->(%p, %p, %p, %p)\n", iface, This, width, height, arwidth, arheight);
if (!width || !height || !arwidth || !arheight)
{
ERR("Got no pointer\n");
return E_POINTER;
}
*width = This->bmiheader.biWidth;
*height = This->bmiheader.biHeight;
*arwidth = This->bmiheader.biWidth;
*arheight = This->bmiheader.biHeight;
return S_OK;
}
static HRESULT WINAPI VMR9WindowlessControl_GetMinIdealVideoSize(IVMRWindowlessControl9 *iface, LONG *width, LONG *height)
{
VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
FIXME("(%p/%p)->(...) stub\n", iface, This);
return E_NOTIMPL;
}
static HRESULT WINAPI VMR9WindowlessControl_GetMaxIdealVideoSize(IVMRWindowlessControl9 *iface, LONG *width, LONG *height)
{
VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
FIXME("(%p/%p)->(...) stub\n", iface, This);
return E_NOTIMPL;
}
static HRESULT WINAPI VMR9WindowlessControl_SetVideoPosition(IVMRWindowlessControl9 *iface, const RECT *source, const RECT *dest)
{
VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
TRACE("(%p/%p)->(%p, %p)\n", iface, This, source, dest);
EnterCriticalSection(&This->renderer.filter.csFilter);
if (source)
This->source_rect = *source;
if (dest)
{
This->target_rect = *dest;
if (This->baseControlWindow.baseWindow.hWnd)
{
FIXME("Output rectangle: starting at %dx%d, up to point %dx%d\n", dest->left, dest->top, dest->right, dest->bottom);
SetWindowPos(This->baseControlWindow.baseWindow.hWnd, NULL, dest->left, dest->top, dest->right - dest->left,
dest->bottom-dest->top, SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOOWNERZORDER|SWP_NOREDRAW);
}
}
LeaveCriticalSection(&This->renderer.filter.csFilter);
return S_OK;
}
static HRESULT WINAPI VMR9WindowlessControl_GetVideoPosition(IVMRWindowlessControl9 *iface, RECT *source, RECT *dest)
{
VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
if (source)
*source = This->source_rect;
if (dest)
*dest = This->target_rect;
FIXME("(%p/%p)->(%p/%p) stub\n", iface, This, source, dest);
return S_OK;
}
static HRESULT WINAPI VMR9WindowlessControl_GetAspectRatioMode(IVMRWindowlessControl9 *iface, DWORD *mode)
{
VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
FIXME("(%p/%p)->(...) stub\n", iface, This);
return E_NOTIMPL;
}
static HRESULT WINAPI VMR9WindowlessControl_SetAspectRatioMode(IVMRWindowlessControl9 *iface, DWORD mode)
{
VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
FIXME("(%p/%p)->(...) stub\n", iface, This);
return E_NOTIMPL;
}
static HRESULT WINAPI VMR9WindowlessControl_SetVideoClippingWindow(IVMRWindowlessControl9 *iface, HWND hwnd)
{
VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
TRACE("(%p/%p)->(%p)\n", iface, This, hwnd);
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);
return S_OK;
}
static HRESULT WINAPI VMR9WindowlessControl_RepaintVideo(IVMRWindowlessControl9 *iface, HWND hwnd, HDC hdc)
{
VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
HRESULT hr;
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)
{
VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
FIXME("(%p/%p)->(...) stub\n", iface, This);
return E_NOTIMPL;
}
static HRESULT WINAPI VMR9WindowlessControl_GetCurrentImage(IVMRWindowlessControl9 *iface, BYTE **dib)
{
VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
FIXME("(%p/%p)->(...) stub\n", iface, This);
return E_NOTIMPL;
}
static HRESULT WINAPI VMR9WindowlessControl_SetBorderColor(IVMRWindowlessControl9 *iface, COLORREF color)
{
VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
FIXME("(%p/%p)->(...) stub\n", iface, This);
return E_NOTIMPL;
}
static HRESULT WINAPI VMR9WindowlessControl_GetBorderColor(IVMRWindowlessControl9 *iface, COLORREF *color)
{
VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
FIXME("(%p/%p)->(...) stub\n", iface, This);
return E_NOTIMPL;
}
static const IVMRWindowlessControl9Vtbl VMR9_WindowlessControl_Vtbl =
{
VMR9WindowlessControl_QueryInterface,
VMR9WindowlessControl_AddRef,
VMR9WindowlessControl_Release,
VMR9WindowlessControl_GetNativeVideoSize,
VMR9WindowlessControl_GetMinIdealVideoSize,
VMR9WindowlessControl_GetMaxIdealVideoSize,
VMR9WindowlessControl_SetVideoPosition,
VMR9WindowlessControl_GetVideoPosition,
VMR9WindowlessControl_GetAspectRatioMode,
VMR9WindowlessControl_SetAspectRatioMode,
VMR9WindowlessControl_SetVideoClippingWindow,
VMR9WindowlessControl_RepaintVideo,
VMR9WindowlessControl_DisplayModeChanged,
VMR9WindowlessControl_GetCurrentImage,
VMR9WindowlessControl_SetBorderColor,
VMR9WindowlessControl_GetBorderColor
};
static HRESULT WINAPI VMR9SurfaceAllocatorNotify_QueryInterface(IVMRSurfaceAllocatorNotify9 *iface, REFIID riid, LPVOID * ppv)
{
VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
}
static ULONG WINAPI VMR9SurfaceAllocatorNotify_AddRef(IVMRSurfaceAllocatorNotify9 *iface)
{
VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
}
static ULONG WINAPI VMR9SurfaceAllocatorNotify_Release(IVMRSurfaceAllocatorNotify9 *iface)
{
VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
}
static HRESULT WINAPI VMR9SurfaceAllocatorNotify_AdviseSurfaceAllocator(IVMRSurfaceAllocatorNotify9 *iface, DWORD_PTR id, IVMRSurfaceAllocator9 *alloc)
{
VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
/* FIXME: This code is not tested!!! */
FIXME("(%p/%p)->(...) stub\n", iface, This);
This->cookie = id;
if (This->presenter)
return VFW_E_WRONG_STATE;
if (FAILED(IVMRSurfaceAllocator9_QueryInterface(alloc, &IID_IVMRImagePresenter9, (void **)&This->presenter)))
return E_NOINTERFACE;
if (SUCCEEDED(IVMRSurfaceAllocator9_QueryInterface(alloc, &IID_IVMRSurfaceAllocatorEx9, (void **)&This->allocator)))
This->allocator_is_ex = 1;
else
{
This->allocator = (IVMRSurfaceAllocatorEx9 *)alloc;
IVMRSurfaceAllocator9_AddRef(alloc);
This->allocator_is_ex = 0;
}
return S_OK;
}
static HRESULT WINAPI VMR9SurfaceAllocatorNotify_SetD3DDevice(IVMRSurfaceAllocatorNotify9 *iface, IDirect3DDevice9 *device, HMONITOR monitor)
{
VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
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)->(...) 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);
if (!allocinfo || !numbuffers || !surface)
return E_POINTER;
if (!*numbuffers || *numbuffers < allocinfo->MinBuffers)
{
ERR("Invalid number of buffers?\n");
return E_INVALIDARG;
}
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)
{
VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
FIXME("(%p/%p)->(...) stub\n", iface, This);
return E_NOTIMPL;
}
static const IVMRSurfaceAllocatorNotify9Vtbl IVMRSurfaceAllocatorNotify9_Vtbl =
{
VMR9SurfaceAllocatorNotify_QueryInterface,
VMR9SurfaceAllocatorNotify_AddRef,
VMR9SurfaceAllocatorNotify_Release,
VMR9SurfaceAllocatorNotify_AdviseSurfaceAllocator,
VMR9SurfaceAllocatorNotify_SetD3DDevice,
VMR9SurfaceAllocatorNotify_ChangeD3DDevice,
VMR9SurfaceAllocatorNotify_AllocateSurfaceHelper,
VMR9SurfaceAllocatorNotify_NotifyEvent
};
HRESULT VMR9Impl_create(IUnknown * outer_unk, LPVOID * ppv)
{
HRESULT hr;
VMR9Impl * pVMR9;
TRACE("(%p, %p)\n", outer_unk, ppv);
*ppv = NULL;
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;
pVMR9->IUnknown_inner.lpVtbl = &IInner_VTable;
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;
pVMR9->IVMRFilterConfig9_iface.lpVtbl = &VMR9_FilterConfig_Vtbl;
pVMR9->IVMRWindowlessControl9_iface.lpVtbl = &VMR9_WindowlessControl_Vtbl;
pVMR9->IVMRSurfaceAllocatorNotify9_iface.lpVtbl = &IVMRSurfaceAllocatorNotify9_Vtbl;
hr = BaseRenderer_Init(&pVMR9->renderer, &VMR9_Vtbl, outer_unk, &CLSID_VideoMixingRenderer9, (DWORD_PTR)(__FILE__ ": VMR9Impl.csFilter"), &BaseFuncTable);
if (FAILED(hr))
goto fail;
hr = BaseControlWindow_Init(&pVMR9->baseControlWindow, &IVideoWindow_VTable, &pVMR9->renderer.filter, &pVMR9->renderer.filter.csFilter, &pVMR9->renderer.pInputPin->pin, &renderer_BaseWindowFuncTable);
if (FAILED(hr))
goto fail;
hr = BaseControlVideo_Init(&pVMR9->baseControlVideo, &IBasicVideo_VTable, &pVMR9->renderer.filter, &pVMR9->renderer.filter.csFilter, &pVMR9->renderer.pInputPin->pin, &renderer_BaseControlVideoFuncTable);
if (FAILED(hr))
goto fail;
*ppv = (LPVOID)pVMR9;
ZeroMemory(&pVMR9->source_rect, sizeof(RECT));
ZeroMemory(&pVMR9->target_rect, sizeof(RECT));
TRACE("Created at %p\n", pVMR9);
return hr;
fail:
BaseRendererImpl_Release(&pVMR9->renderer.filter.IBaseFilter_iface);
CloseHandle(pVMR9->hD3d9);
CoTaskMemFree(pVMR9);
return hr;
}
static HRESULT WINAPI VMR9_ImagePresenter_QueryInterface(IVMRImagePresenter9 *iface, REFIID riid, LPVOID * ppv)
{
VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
*ppv = NULL;
if (IsEqualIID(riid, &IID_IUnknown))
*ppv = (LPVOID)&(This->IVMRImagePresenter9_iface);
else if (IsEqualIID(riid, &IID_IVMRImagePresenter9))
*ppv = &This->IVMRImagePresenter9_iface;
else if (IsEqualIID(riid, &IID_IVMRSurfaceAllocatorEx9))
*ppv = &This->IVMRSurfaceAllocatorEx9_iface;
if (*ppv)
{
IUnknown_AddRef((IUnknown *)(*ppv));
return S_OK;
}
FIXME("No interface for %s\n", debugstr_guid(riid));
return E_NOINTERFACE;
}
static ULONG WINAPI VMR9_ImagePresenter_AddRef(IVMRImagePresenter9 *iface)
{
VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
ULONG refCount = InterlockedIncrement(&This->refCount);
TRACE("(%p)->() AddRef from %d\n", iface, refCount - 1);
return refCount;
}
static ULONG WINAPI VMR9_ImagePresenter_Release(IVMRImagePresenter9 *iface)
{
VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
ULONG refCount = InterlockedDecrement(&This->refCount);
TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
if (!refCount)
{
int i;
TRACE("Destroying\n");
CloseHandle(This->ack);
IDirect3D9_Release(This->d3d9_ptr);
TRACE("Number of surfaces: %u\n", This->num_surfaces);
for (i = 0; i < This->num_surfaces; ++i)
{
IDirect3DSurface9 *surface = This->d3d9_surfaces[i];
TRACE("Releasing surface %p\n", surface);
if (surface)
IDirect3DSurface9_Release(surface);
}
CoTaskMemFree(This->d3d9_surfaces);
This->d3d9_surfaces = NULL;
This->num_surfaces = 0;
if (This->d3d9_vertex)
{
IDirect3DVertexBuffer9_Release(This->d3d9_vertex);
This->d3d9_vertex = NULL;
}
CoTaskMemFree(This);
return 0;
}
return refCount;
}
static HRESULT WINAPI VMR9_ImagePresenter_StartPresenting(IVMRImagePresenter9 *iface, DWORD_PTR id)
{
VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
TRACE("(%p/%p/%p)->(...) stub\n", iface, This,This->pVMR9);
return S_OK;
}
static HRESULT WINAPI VMR9_ImagePresenter_StopPresenting(IVMRImagePresenter9 *iface, DWORD_PTR id)
{
VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
TRACE("(%p/%p/%p)->(...) stub\n", iface, This,This->pVMR9);
return S_OK;
}
#define USED_FVF (D3DFVF_XYZRHW | D3DFVF_TEX1)
struct VERTEX { float x, y, z, rhw, u, v; };
static HRESULT VMR9_ImagePresenter_PresentTexture(VMR9DefaultAllocatorPresenterImpl *This, IDirect3DSurface9 *surface)
{
IDirect3DTexture9 *texture = NULL;
HRESULT hr;
hr = IDirect3DDevice9_SetFVF(This->d3d9_dev, USED_FVF);
if (FAILED(hr))
{
FIXME("SetFVF: %08x\n", hr);
return hr;
}
hr = IDirect3DDevice9_SetStreamSource(This->d3d9_dev, 0, This->d3d9_vertex, 0, sizeof(struct VERTEX));
if (FAILED(hr))
{
FIXME("SetStreamSource: %08x\n", hr);
return hr;
}
hr = IDirect3DSurface9_GetContainer(surface, &IID_IDirect3DTexture9, (void **) &texture);
if (FAILED(hr))
{
FIXME("IDirect3DSurface9_GetContainer failed\n");
return hr;
}
hr = IDirect3DDevice9_SetTexture(This->d3d9_dev, 0, (IDirect3DBaseTexture9 *)texture);
IDirect3DTexture9_Release(texture);
if (FAILED(hr))
{
FIXME("SetTexture: %08x\n", hr);
return hr;
}
hr = IDirect3DDevice9_DrawPrimitive(This->d3d9_dev, D3DPT_TRIANGLESTRIP, 0, 2);
if (FAILED(hr))
{
FIXME("DrawPrimitive: %08x\n", hr);
return hr;
}
return S_OK;
}
static HRESULT VMR9_ImagePresenter_PresentOffscreenSurface(VMR9DefaultAllocatorPresenterImpl *This, IDirect3DSurface9 *surface)
{
HRESULT hr;
IDirect3DSurface9 *target = NULL;
RECT target_rect;
hr = IDirect3DDevice9_GetBackBuffer(This->d3d9_dev, 0, 0, D3DBACKBUFFER_TYPE_MONO, &target);
if (FAILED(hr))
{
ERR("IDirect3DDevice9_GetBackBuffer -- %08x\n", hr);
return hr;
}
target_rect = This->pVMR9->target_rect;
target_rect.right -= target_rect.left;
target_rect.bottom -= target_rect.top;
target_rect.left = target_rect.top = 0;
/* Flip */
target_rect.top = target_rect.bottom;
target_rect.bottom = 0;
hr = IDirect3DDevice9_StretchRect(This->d3d9_dev, surface, &This->pVMR9->source_rect, target, &target_rect, D3DTEXF_LINEAR);
if (FAILED(hr))
ERR("IDirect3DDevice9_StretchRect -- %08x\n", hr);
IDirect3DSurface9_Release(target);
return hr;
}
static HRESULT WINAPI VMR9_ImagePresenter_PresentImage(IVMRImagePresenter9 *iface, DWORD_PTR id, VMR9PresentationInfo *info)
{
VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
HRESULT hr;
RECT output;
BOOL render = FALSE;
TRACE("(%p/%p/%p)->(...) stub\n", iface, This, This->pVMR9);
GetWindowRect(This->pVMR9->baseControlWindow.baseWindow.hWnd, &output);
TRACE("Output rectangle: starting at %dx%d, up to point %dx%d\n", output.left, output.top, output.right, output.bottom);
/* This might happen if we don't have active focus (eg on a different virtual desktop) */
if (!This->d3d9_dev)
return S_OK;
/* Display image here */
hr = IDirect3DDevice9_Clear(This->d3d9_dev, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
if (FAILED(hr))
FIXME("hr: %08x\n", hr);
hr = IDirect3DDevice9_BeginScene(This->d3d9_dev);
if (SUCCEEDED(hr))
{
if (This->d3d9_vertex)
hr = VMR9_ImagePresenter_PresentTexture(This, info->lpSurf);
else
hr = VMR9_ImagePresenter_PresentOffscreenSurface(This, info->lpSurf);
render = SUCCEEDED(hr);
}
else
FIXME("BeginScene: %08x\n", hr);
hr = IDirect3DDevice9_EndScene(This->d3d9_dev);
if (render && SUCCEEDED(hr))
{
hr = IDirect3DDevice9_Present(This->d3d9_dev, NULL, NULL, This->pVMR9->baseControlWindow.baseWindow.hWnd, NULL);
if (FAILED(hr))
FIXME("Presenting image: %08x\n", hr);
}
return S_OK;
}
static const IVMRImagePresenter9Vtbl VMR9_ImagePresenter =
{
VMR9_ImagePresenter_QueryInterface,
VMR9_ImagePresenter_AddRef,
VMR9_ImagePresenter_Release,
VMR9_ImagePresenter_StartPresenting,
VMR9_ImagePresenter_StopPresenting,
VMR9_ImagePresenter_PresentImage
};
static HRESULT WINAPI VMR9_SurfaceAllocator_QueryInterface(IVMRSurfaceAllocatorEx9 *iface, REFIID riid, LPVOID * ppv)
{
VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
return VMR9_ImagePresenter_QueryInterface(&This->IVMRImagePresenter9_iface, riid, ppv);
}
static ULONG WINAPI VMR9_SurfaceAllocator_AddRef(IVMRSurfaceAllocatorEx9 *iface)
{
VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
return VMR9_ImagePresenter_AddRef(&This->IVMRImagePresenter9_iface);
}
static ULONG WINAPI VMR9_SurfaceAllocator_Release(IVMRSurfaceAllocatorEx9 *iface)
{
VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
return VMR9_ImagePresenter_Release(&This->IVMRImagePresenter9_iface);
}
static HRESULT VMR9_SurfaceAllocator_SetAllocationSettings(VMR9DefaultAllocatorPresenterImpl *This, VMR9AllocationInfo *allocinfo)
{
D3DCAPS9 caps;
UINT width, height;
HRESULT hr;
if (!(allocinfo->dwFlags & VMR9AllocFlag_TextureSurface))
/* Only needed for texture surfaces */
return S_OK;
hr = IDirect3DDevice9_GetDeviceCaps(This->d3d9_dev, &caps);
if (FAILED(hr))
return hr;
if (!(caps.TextureCaps & D3DPTEXTURECAPS_POW2) || (caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY))
{
width = allocinfo->dwWidth;
height = allocinfo->dwHeight;
}
else
{
width = height = 1;
while (width < allocinfo->dwWidth)
width *= 2;
while (height < allocinfo->dwHeight)
height *= 2;
FIXME("NPOW2 support missing, not using proper surfaces!\n");
}
if (caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY)
{
if (height > width)
width = height;
else
height = width;
FIXME("Square texture support required..\n");
}
hr = IDirect3DDevice9_CreateVertexBuffer(This->d3d9_dev, 4 * sizeof(struct VERTEX), D3DUSAGE_WRITEONLY, USED_FVF, allocinfo->Pool, &This->d3d9_vertex, NULL);
if (FAILED(hr))
{
ERR("Couldn't create vertex buffer: %08x\n", hr);
return hr;
}
This->reset = TRUE;
allocinfo->dwHeight = height;
allocinfo->dwWidth = width;
return hr;
}
static DWORD WINAPI MessageLoop(LPVOID lpParameter)
{
MSG msg;
BOOL fGotMessage;
VMR9DefaultAllocatorPresenterImpl *This = lpParameter;
TRACE("Starting message loop\n");
if (FAILED(BaseWindowImpl_PrepareWindow(&This->pVMR9->baseControlWindow.baseWindow)))
{
FIXME("Failed to prepare window\n");
return FALSE;
}
SetEvent(This->ack);
while ((fGotMessage = GetMessageW(&msg, NULL, 0, 0)) != 0 && fGotMessage != -1)
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
TRACE("End of message loop\n");
return 0;
}
static UINT d3d9_adapter_from_hwnd(IDirect3D9 *d3d9, HWND hwnd, HMONITOR *mon_out)
{
UINT d3d9_adapter;
HMONITOR mon;
mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL);
if (!mon)
d3d9_adapter = 0;
else
{
for (d3d9_adapter = 0; d3d9_adapter < IDirect3D9_GetAdapterCount(d3d9); ++d3d9_adapter)
{
if (mon == IDirect3D9_GetAdapterMonitor(d3d9, d3d9_adapter))
break;
}
if (d3d9_adapter >= IDirect3D9_GetAdapterCount(d3d9))
d3d9_adapter = 0;
}
if (mon_out)
*mon_out = mon;
return d3d9_adapter;
}
static BOOL CreateRenderingWindow(VMR9DefaultAllocatorPresenterImpl *This, VMR9AllocationInfo *info, DWORD *numbuffers)
{
D3DPRESENT_PARAMETERS d3dpp;
DWORD d3d9_adapter;
HRESULT hr;
TRACE("(%p)->()\n", This);
This->hWndThread = CreateThread(NULL, 0, MessageLoop, This, 0, &This->tid);
if (!This->hWndThread)
return FALSE;
WaitForSingleObject(This->ack, INFINITE);
if (!This->pVMR9->baseControlWindow.baseWindow.hWnd) return FALSE;
/* Obtain a monitor and d3d9 device */
d3d9_adapter = d3d9_adapter_from_hwnd(This->d3d9_ptr, This->pVMR9->baseControlWindow.baseWindow.hWnd, &This->hMon);
/* Now try to create the d3d9 device */
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.hDeviceWindow = This->pVMR9->baseControlWindow.baseWindow.hWnd;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferHeight = This->pVMR9->target_rect.bottom - This->pVMR9->target_rect.top;
d3dpp.BackBufferWidth = This->pVMR9->target_rect.right - This->pVMR9->target_rect.left;
hr = IDirect3D9_CreateDevice(This->d3d9_ptr, d3d9_adapter, D3DDEVTYPE_HAL, NULL, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &This->d3d9_dev);
if (FAILED(hr))
{
ERR("Could not create device: %08x\n", hr);
BaseWindowImpl_DoneWithWindow(&This->pVMR9->baseControlWindow.baseWindow);
return FALSE;
}
IVMRSurfaceAllocatorNotify9_SetD3DDevice(This->SurfaceAllocatorNotify, This->d3d9_dev, This->hMon);
This->d3d9_surfaces = CoTaskMemAlloc(*numbuffers * sizeof(IDirect3DSurface9 *));
ZeroMemory(This->d3d9_surfaces, *numbuffers * sizeof(IDirect3DSurface9 *));
hr = VMR9_SurfaceAllocator_SetAllocationSettings(This, info);
if (FAILED(hr))
ERR("Setting allocation settings failed: %08x\n", hr);
if (SUCCEEDED(hr))
{
hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(This->SurfaceAllocatorNotify, info, numbuffers, This->d3d9_surfaces);
if (FAILED(hr))
ERR("Allocating surfaces failed: %08x\n", hr);
}
if (FAILED(hr))
{
IVMRSurfaceAllocatorEx9_TerminateDevice(This->pVMR9->allocator, This->pVMR9->cookie);
BaseWindowImpl_DoneWithWindow(&This->pVMR9->baseControlWindow.baseWindow);
return FALSE;
}
This->num_surfaces = *numbuffers;
return TRUE;
}
static HRESULT WINAPI VMR9_SurfaceAllocator_InitializeDevice(IVMRSurfaceAllocatorEx9 *iface, DWORD_PTR id, VMR9AllocationInfo *allocinfo, DWORD *numbuffers)
{
VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
if (This->pVMR9->mode != VMR9Mode_Windowed && !This->pVMR9->hWndClippingWindow)
{
ERR("No window set\n");
return VFW_E_WRONG_STATE;
}
This->info = *allocinfo;
if (!CreateRenderingWindow(This, allocinfo, numbuffers))
{
ERR("Failed to create rendering window, expect no output!\n");
return VFW_E_WRONG_STATE;
}
return S_OK;
}
static HRESULT WINAPI VMR9_SurfaceAllocator_TerminateDevice(IVMRSurfaceAllocatorEx9 *iface, DWORD_PTR id)
{
VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
if (!This->pVMR9->baseControlWindow.baseWindow.hWnd)
{
return S_OK;
}
SendMessageW(This->pVMR9->baseControlWindow.baseWindow.hWnd, WM_CLOSE, 0, 0);
PostThreadMessageW(This->tid, WM_QUIT, 0, 0);
WaitForSingleObject(This->hWndThread, INFINITE);
This->hWndThread = NULL;
BaseWindowImpl_DoneWithWindow(&This->pVMR9->baseControlWindow.baseWindow);
return S_OK;
}
/* Recreate all surfaces (If allocated as D3DPOOL_DEFAULT) and survive! */
static HRESULT VMR9_SurfaceAllocator_UpdateDeviceReset(VMR9DefaultAllocatorPresenterImpl *This)
{
struct VERTEX t_vert[4];
UINT width, height;
INT i;
void *bits = NULL;
D3DPRESENT_PARAMETERS d3dpp;
HRESULT hr;
if (!This->pVMR9->baseControlWindow.baseWindow.hWnd)
{
ERR("No window\n");
return E_FAIL;
}
if (!This->d3d9_surfaces || !This->reset)
return S_OK;
This->reset = FALSE;
TRACE("RESETTING\n");
if (This->d3d9_vertex)
{
IDirect3DVertexBuffer9_Release(This->d3d9_vertex);
This->d3d9_vertex = NULL;
}
for (i = 0; i < This->num_surfaces; ++i)
{
IDirect3DSurface9 *surface = This->d3d9_surfaces[i];
TRACE("Releasing surface %p\n", surface);
if (surface)
IDirect3DSurface9_Release(surface);
}
ZeroMemory(This->d3d9_surfaces, sizeof(IDirect3DSurface9 *) * This->num_surfaces);
/* Now try to create the d3d9 device */
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.hDeviceWindow = This->pVMR9->baseControlWindow.baseWindow.hWnd;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
if (This->d3d9_dev)
IDirect3DDevice9_Release(This->d3d9_dev);
This->d3d9_dev = NULL;
hr = IDirect3D9_CreateDevice(This->d3d9_ptr, d3d9_adapter_from_hwnd(This->d3d9_ptr, This->pVMR9->baseControlWindow.baseWindow.hWnd, &This->hMon), D3DDEVTYPE_HAL, NULL, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &This->d3d9_dev);
if (FAILED(hr))
{
hr = IDirect3D9_CreateDevice(This->d3d9_ptr, d3d9_adapter_from_hwnd(This->d3d9_ptr, This->pVMR9->baseControlWindow.baseWindow.hWnd, &This->hMon), D3DDEVTYPE_HAL, NULL, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &This->d3d9_dev);
if (FAILED(hr))
{
ERR("--> Creating device: %08x\n", hr);
return S_OK;
}
}
IVMRSurfaceAllocatorNotify9_ChangeD3DDevice(This->SurfaceAllocatorNotify, This->d3d9_dev, This->hMon);
IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(This->SurfaceAllocatorNotify, &This->info, &This->num_surfaces, This->d3d9_surfaces);
This->reset = FALSE;
if (!(This->info.dwFlags & VMR9AllocFlag_TextureSurface))
return S_OK;
hr = IDirect3DDevice9_CreateVertexBuffer(This->d3d9_dev, 4 * sizeof(struct VERTEX), D3DUSAGE_WRITEONLY, USED_FVF,
This->info.Pool, &This->d3d9_vertex, NULL);
width = This->info.dwWidth;
height = This->info.dwHeight;
for (i = 0; i < sizeof(t_vert) / sizeof(t_vert[0]); ++i)
{
if (i % 2)
{
t_vert[i].x = (float)This->pVMR9->target_rect.right - (float)This->pVMR9->target_rect.left - 0.5f;
t_vert[i].u = (float)This->pVMR9->source_rect.right / (float)width;
}
else
{
t_vert[i].x = -0.5f;
t_vert[i].u = (float)This->pVMR9->source_rect.left / (float)width;
}
if (i % 4 < 2)
{
t_vert[i].y = -0.5f;
t_vert[i].v = (float)This->pVMR9->source_rect.bottom / (float)height;
}
else
{
t_vert[i].y = (float)This->pVMR9->target_rect.bottom - (float)This->pVMR9->target_rect.top - 0.5f;
t_vert[i].v = (float)This->pVMR9->source_rect.top / (float)height;
}
t_vert[i].z = 0.0f;
t_vert[i].rhw = 1.0f;
}
FIXME("Vertex rectangle:\n");
FIXME("X, Y: %f, %f\n", t_vert[0].x, t_vert[0].y);
FIXME("X, Y: %f, %f\n", t_vert[3].x, t_vert[3].y);
FIXME("TOP, LEFT: %f, %f\n", t_vert[0].u, t_vert[0].v);
FIXME("DOWN, BOTTOM: %f, %f\n", t_vert[3].u, t_vert[3].v);
IDirect3DVertexBuffer9_Lock(This->d3d9_vertex, 0, sizeof(t_vert), &bits, 0);
memcpy(bits, t_vert, sizeof(t_vert));
IDirect3DVertexBuffer9_Unlock(This->d3d9_vertex);
return S_OK;
}
static HRESULT WINAPI VMR9_SurfaceAllocator_GetSurface(IVMRSurfaceAllocatorEx9 *iface, DWORD_PTR id, DWORD surfaceindex, DWORD flags, IDirect3DSurface9 **surface)
{
VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
/* Update everything first, this is needed because the surface might be destroyed in the reset */
if (!This->d3d9_dev)
{
TRACE("Device has left me!\n");
return E_FAIL;
}
VMR9_SurfaceAllocator_UpdateDeviceReset(This);
if (surfaceindex >= This->num_surfaces)
{
ERR("surfaceindex is greater than num_surfaces\n");
return E_FAIL;
}
*surface = This->d3d9_surfaces[surfaceindex];
IDirect3DSurface9_AddRef(*surface);
return S_OK;
}
static HRESULT WINAPI VMR9_SurfaceAllocator_AdviseNotify(IVMRSurfaceAllocatorEx9 *iface, IVMRSurfaceAllocatorNotify9 *allocnotify)
{
VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
TRACE("(%p/%p)->(...)\n", iface, This);
/* No AddRef taken here or the base VMR9 filter would never be destroied */
This->SurfaceAllocatorNotify = allocnotify;
return S_OK;
}
static const IVMRSurfaceAllocatorEx9Vtbl VMR9_SurfaceAllocator =
{
VMR9_SurfaceAllocator_QueryInterface,
VMR9_SurfaceAllocator_AddRef,
VMR9_SurfaceAllocator_Release,
VMR9_SurfaceAllocator_InitializeDevice,
VMR9_SurfaceAllocator_TerminateDevice,
VMR9_SurfaceAllocator_GetSurface,
VMR9_SurfaceAllocator_AdviseNotify,
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;
int i;
VMR9DefaultAllocatorPresenterImpl* This;
This = CoTaskMemAlloc(sizeof(VMR9DefaultAllocatorPresenterImpl));
if (!This)
return E_OUTOFMEMORY;
This->d3d9_ptr = init_d3d9(parent->hD3d9);
if (!This->d3d9_ptr)
{
WARN("Could not initialize d3d9.dll\n");
CoTaskMemFree(This);
return VFW_E_DDRAW_CAPS_NOT_SUITABLE;
}
i = 0;
do
{
D3DDISPLAYMODE mode;
hr = IDirect3D9_EnumAdapterModes(This->d3d9_ptr, i++, D3DFMT_X8R8G8B8, 0, &mode);
} while (FAILED(hr));
if (FAILED(hr))
ERR("HR: %08x\n", hr);
if (hr == D3DERR_NOTAVAILABLE)
{
ERR("Format not supported\n");
IDirect3D9_Release(This->d3d9_ptr);
CoTaskMemFree(This);
return VFW_E_DDRAW_CAPS_NOT_SUITABLE;
}
This->IVMRImagePresenter9_iface.lpVtbl = &VMR9_ImagePresenter;
This->IVMRSurfaceAllocatorEx9_iface.lpVtbl = &VMR9_SurfaceAllocator;
This->refCount = 1;
This->pVMR9 = parent;
This->d3d9_surfaces = NULL;
This->d3d9_dev = NULL;
This->hMon = 0;
This->d3d9_vertex = NULL;
This->num_surfaces = 0;
This->hWndThread = NULL;
This->ack = CreateEventW(NULL, 0, 0, NULL);
This->SurfaceAllocatorNotify = NULL;
This->reset = FALSE;
*ppv = This;
return S_OK;
}