wine-wine/dlls/quartz/vmr9.c

481 lines
14 KiB
C
Raw Normal View History

2012-04-03 19:37:55 +00:00
/*
* 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;
2012-04-03 19:37:58 +00:00
BaseControlWindow baseControlWindow;
2012-04-03 19:37:55 +00:00
IUnknown IUnknown_inner;
BITMAPINFOHEADER bmiheader;
IUnknown * outer_unk;
BOOL bUnkOuterValid;
BOOL bAggregatable;
} VMR9Impl;
static inline VMR9Impl *impl_from_inner_IUnknown(IUnknown *iface)
{
return CONTAINING_RECORD(iface, VMR9Impl, IUnknown_inner);
}
2012-04-03 19:37:58 +00:00
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);
}
2012-04-03 19:37:55 +00:00
static HRESULT WINAPI VMR9_DoRenderSample(BaseRenderer *iface, IMediaSample * pSample)
{
VMR9Impl *This = (VMR9Impl *)iface;
LPBYTE pbSrcStream = NULL;
REFERENCE_TIME tStart, tStop;
VMR9PresentationInfo info;
HRESULT hr;
TRACE("%p %p\n", iface, pSample);
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;
hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
if (FAILED(hr))
{
ERR("Cannot get pointer to sample data (%x)\n", hr);
return hr;
}
info.rtStart = tStart;
info.rtEnd = tStop;
info.szAspectRatio.cx = This->bmiheader.biWidth;
info.szAspectRatio.cy = This->bmiheader.biHeight;
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);
}
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);
}
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;
}
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 const BaseRendererFuncTable BaseFuncTable = {
VMR9_CheckMediaType,
VMR9_DoRenderSample,
/**/
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
VMR9_ShouldDrawSampleNow,
NULL,
/**/
NULL,
NULL,
NULL,
NULL,
NULL,
};
2012-04-03 19:37:58 +00:00
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 const BaseWindowFuncTable renderer_BaseWindowFuncTable = {
VMR9_GetClassWindowStyles,
BaseWindowImpl_GetDefaultRect,
NULL,
BaseControlWindowImpl_PossiblyEatMessage,
NULL,
};
2012-04-03 19:37:55 +00:00
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;
2012-04-03 19:37:58 +00:00
else if (IsEqualIID(riid, &IID_IVideoWindow))
*ppv = &This->baseControlWindow.IVideoWindow_iface;
2012-04-03 19:37:55 +00:00
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_IBasicVideo))
FIXME("No interface for IID_IBasicVideo\n");
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_IAMFilterMiscFlags))
FIXME("No interface for IID_IAMFilterMiscFlags\n");
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");
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
};
2012-04-03 19:37:58 +00:00
/*** 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
};
2012-04-03 19:37:55 +00:00
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->outer_unk = outer_unk;
pVMR9->bUnkOuterValid = FALSE;
pVMR9->bAggregatable = FALSE;
pVMR9->IUnknown_inner.lpVtbl = &IInner_VTable;
hr = BaseRenderer_Init(&pVMR9->renderer, &VMR9_Vtbl, outer_unk, &CLSID_VideoMixingRenderer9, (DWORD_PTR)(__FILE__ ": VMR9Impl.csFilter"), &BaseFuncTable);
2012-04-03 19:37:58 +00:00
if (FAILED(hr))
goto fail;
2012-04-03 19:37:55 +00:00
2012-04-03 19:37:58 +00:00
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;
*ppv = (LPVOID)pVMR9;
TRACE("Created at %p\n", pVMR9);
return hr;
2012-04-03 19:37:55 +00:00
2012-04-03 19:37:58 +00:00
fail:
BaseRendererImpl_Release(&pVMR9->renderer.filter.IBaseFilter_iface);
CoTaskMemFree(pVMR9);
2012-04-03 19:37:55 +00:00
return hr;
}