diff --git a/dlls/quartz/Makefile.in b/dlls/quartz/Makefile.in index 56a7cf920ac..1ec502a15b1 100644 --- a/dlls/quartz/Makefile.in +++ b/dlls/quartz/Makefile.in @@ -1,6 +1,6 @@ MODULE = quartz.dll IMPORTLIB = quartz -IMPORTS = strmiids strmbase uuid dsound msacm32 msvfw32 ole32 oleaut32 shlwapi rpcrt4 user32 gdi32 advapi32 +IMPORTS = strmiids dxguid strmbase uuid dsound msacm32 msvfw32 ole32 oleaut32 shlwapi rpcrt4 user32 gdi32 advapi32 EXTRADEFS = -DENTRY_PREFIX=QUARTZ_ -DPROXY_DELEGATION -DWINE_REGISTER_DLL C_SRCS = \ @@ -24,6 +24,7 @@ C_SRCS = \ regsvr.c \ systemclock.c \ videorenderer.c \ + vmr9.c \ waveparser.c RC_SRCS = version.rc diff --git a/dlls/quartz/main.c b/dlls/quartz/main.c index cdc44fcca25..6488b7eb8ad 100644 --- a/dlls/quartz/main.c +++ b/dlls/quartz/main.c @@ -71,6 +71,7 @@ static const struct object_creation_info object_creation[] = { &CLSID_MPEG1Splitter, MPEGSplitter_create }, { &CLSID_VideoRenderer, VideoRenderer_create }, { &CLSID_NullRenderer, NullRenderer_create }, + { &CLSID_VideoMixingRenderer9, VMR9Impl_create }, { &CLSID_VideoRendererDefault, VideoRendererDefault_create }, { &CLSID_DSoundRender, DSoundRender_create }, { &CLSID_AudioRender, DSoundRender_create }, diff --git a/dlls/quartz/quartz_private.h b/dlls/quartz/quartz_private.h index a19c87542cc..35cd52b706b 100644 --- a/dlls/quartz/quartz_private.h +++ b/dlls/quartz/quartz_private.h @@ -56,6 +56,7 @@ HRESULT VideoRendererDefault_create(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC HRESULT QUARTZ_CreateSystemClock(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN; HRESULT ACMWrapper_create(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN; HRESULT WAVEParser_create(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN; +HRESULT VMR9Impl_create(IUnknown *pUnkOuter, LPVOID *ppv) DECLSPEC_HIDDEN; HRESULT EnumMonikerImpl_Create(IMoniker ** ppMoniker, ULONG nMonikerCount, IEnumMoniker ** ppEnum) DECLSPEC_HIDDEN; diff --git a/dlls/quartz/quartz_strmif.idl b/dlls/quartz/quartz_strmif.idl index ef19709a268..ed7abe6b21a 100644 --- a/dlls/quartz/quartz_strmif.idl +++ b/dlls/quartz/quartz_strmif.idl @@ -150,3 +150,10 @@ coclass ACMWrapper { interface IBaseFilter; } uuid(d51bd5a1-7548-11cf-a520-0080c77ef58a) ] coclass WAVEParser { interface IBaseFilter; } + +[ + helpstring("Video Mixing Renderer 9"), + threading(both), + uuid(51b4abf3-748f-4e3b-a276-c828330e926a) +] +coclass VideoMixingRenderer9 { interface IBaseFilter; } diff --git a/dlls/quartz/regsvr.c b/dlls/quartz/regsvr.c index 7adf7d4fe08..22455f7c271 100644 --- a/dlls/quartz/regsvr.c +++ b/dlls/quartz/regsvr.c @@ -958,6 +958,18 @@ static struct regsvr_filter const filter_list[] = { { 0xFFFFFFFF }, } }, + { &CLSID_VideoMixingRenderer9, + &CLSID_LegacyAmFilterCategory, + {'V','i','d','e','o',' ','M','i','x','i','n','g',' ','R','e','n','d','e','r','e','r',' ','9',0}, + 0x200000, + { { REG_PINFLAG_B_RENDERER, + { { &MEDIATYPE_Video, &GUID_NULL }, + { NULL } + }, + }, + { 0xFFFFFFFF }, + } + }, { &CLSID_DSoundRender, &CLSID_LegacyAmFilterCategory, {'A','u','d','i','o',' ','R','e','n','d','e','r','e','r',0}, diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c new file mode 100644 index 00000000000..b1d75a3d5b4 --- /dev/null +++ b/dlls/quartz/vmr9.c @@ -0,0 +1,369 @@ +/* + * 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; + 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); +} + +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, +}; + +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 + { + 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_IVideoWindow)) + FIXME("No interface for IID_IVideoWindow\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 +}; + +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); + + if (SUCCEEDED(hr)) + { + *ppv = (LPVOID)pVMR9; + TRACE("Created at %p\n", pVMR9); + } + else + { + BaseRendererImpl_Release(&pVMR9->renderer.filter.IBaseFilter_iface); + CoTaskMemFree(pVMR9); + } + + return hr; +}