windows-nt/Source/XPSP1/NT/multimedia/dshow/vidctl/vidvidimpl.h
2020-09-26 16:20:57 +08:00

1200 lines
46 KiB
C++

//==========================================================================;
// MSVidVideoRenderer.h : Declaration of the CMSVidVideoRenderer
// copyright (c) Microsoft Corp. 1998-1999.
//==========================================================================;
#ifndef __MSVidVIDEORENDERERIMPL_H_
#define __MSVidVIDEORENDERERIMPL_H_
#pragma once
#include <algorithm>
#include <evcode.h>
#include <uuids.h>
#include <amvideo.h>
#include <strmif.h>
#include "vidrect.h"
#include "vrsegimpl.h"
#include "outputimpl.h"
#include "seg.h"
#include "videorenderercp.h"
#include "strmif.h"
#include "resource.h" // main symbols
//typedef CComQIPtr<IVMRSurfaceAllocator> PQVMRSAlloc;
//typedef CComQIPtr<IVMRAlphaBitmap> PQVMRAlphaBitm;
/////////////////////////////////////////////////////////////////////////////
// CMSVidVideoRenderer
template<class T, LPCGUID LibID, LPCGUID Category, class MostDerivedClass = IMSVidVideoRenderer>
class DECLSPEC_NOVTABLE IMSVidVideoRendererImpl :
public IMSVidOutputDeviceImpl<T, LibID, Category, MostDerivedClass>,
public IMSVidVRGraphSegmentImpl<T> {
public:
IMSVidVideoRendererImpl()
{
m_opacity = -1;
m_rectPosition.top = -1;
m_rectPosition.left = -1;
m_rectPosition.bottom = -1;
m_rectPosition.right = -1;
m_SourceSize = sslFullSize;
m_lOverScan = 1;
}
virtual ~IMSVidVideoRendererImpl() {
m_PQIPicture.Release();
}
protected:
typedef IMSVidVRGraphSegmentImpl<T> VRSegbasetype;
PQIPic m_PQIPicture;
FLOAT m_opacity;
NORMALIZEDRECT m_rectPosition;
SourceSizeList m_SourceSize;
LONG m_lOverScan;
CScalingRect m_ClipRect;
public:
virtual HRESULT SetVRConfig() {
HRESULT hr = S_OK;
if (m_pVMR) {
hr = VRSegbasetype::SetVRConfig();
if (FAILED(hr)) {
return hr;
}
if(m_pVMRWC){
hr = m_pVMRWC->SetColorKey(m_ColorKey);
}
else{
return ImplReportError(__uuidof(T), IDS_E_NOTWNDLESS, __uuidof(IVMRFilterConfig), E_FAIL);
}
if (FAILED(hr) && hr != E_NOTIMPL) {
return hr;
}
}
return NOERROR;
}
STDMETHOD(Refresh)() {
ReComputeSourceRect();
return VRSegbasetype::Refresh();
}
// IMSVidVideoRenderer
STDMETHOD(get_OverScan)(LONG * plPercent)
{
if (!m_fInit) {
return ImplReportError(__uuidof(T), IDS_OBJ_NO_INIT, __uuidof(IMSVidVideoRenderer), CO_E_NOTINITIALIZED);
}
if (plPercent == NULL) {
return E_POINTER;
}
try {
*plPercent = m_lOverScan;
return NOERROR;
} catch(...) {
return E_UNEXPECTED;
}
}
STDMETHOD(put_OverScan)(LONG lPercent)
{
if (!m_fInit) {
return ImplReportError(__uuidof(T), IDS_OBJ_NO_INIT, __uuidof(IMSVidVideoRenderer), CO_E_NOTINITIALIZED);
}
try {
if(lPercent > 4900 || lPercent < 0){
return ImplReportError(__uuidof(T), IDS_INVALID_OVERSCAN, __uuidof(IMSVidVideoRenderer), CO_E_ERRORINAPP);
}
m_lOverScan = lPercent;
return ReComputeSourceRect();
} catch(...) {
return E_UNEXPECTED;
}
}
STDMETHOD(get_SourceSize)(/*[out, retval]*/ SourceSizeList *pCurrentSize) {
if (!m_fInit) {
return ImplReportError(__uuidof(T), IDS_OBJ_NO_INIT, __uuidof(IMSVidVideoRenderer), CO_E_NOTINITIALIZED);
}
if (!pCurrentSize) {
return E_POINTER;
}
try {
*pCurrentSize = m_SourceSize;
return NOERROR;
} catch(...) {
return E_UNEXPECTED;
}
}
// TODO: add checks for input value being null
STDMETHOD(get_MaxVidRect)(/*[out, retval]*/ IMSVidRect **ppVidRect){
HRESULT hr = S_OK;
CComQIPtr<IMSVidRect>PQIMSVRect;
try{
PQIMSVRect = static_cast<IMSVidRect *>(new CVidRect(0,0,0,0));
if(!PQIMSVRect){
throw(E_UNEXPECTED);
}
if(!m_pVMR){
throw(ImplReportError(__uuidof(T), IDS_OBJ_NO_INIT, __uuidof(IMSVidVideoRenderer), CO_E_NOTINITIALIZED));
}
long dwWidth, dwHeight;
if(m_pVMRWC){
hr = m_pVMRWC->GetMaxIdealVideoSize(&dwWidth, &dwHeight);
if(FAILED(hr)){
throw(hr);
}
}
else{
throw(ImplReportError(__uuidof(T), IDS_E_NOTWNDLESS, __uuidof(IVMRFilterConfig), E_FAIL));
}
PQIMSVRect->put_Height(dwHeight);
PQIMSVRect->put_Width(dwWidth);
}
catch(HRESULT hres){
PQIMSVRect = static_cast<IMSVidRect *>(new CVidRect(-1,-1,-1,-1));
*ppVidRect = PQIMSVRect.Detach();
return hres;
}
*ppVidRect = PQIMSVRect.Detach();
return hr;
}
STDMETHOD(get_MinVidRect)(/*[out, retval]*/ IMSVidRect **ppVidRect){
HRESULT hr = S_OK;
CComQIPtr<IMSVidRect>PQIMSVRect;
try{
PQIMSVRect = static_cast<IMSVidRect *>(new CVidRect(0,0,0,0));
if(!PQIMSVRect){
throw(E_UNEXPECTED);
}
if(!m_pVMR){
throw(ImplReportError(__uuidof(T), IDS_OBJ_NO_INIT, __uuidof(IMSVidVideoRenderer), CO_E_NOTINITIALIZED));
}
long dwWidth, dwHeight;
if(m_pVMRWC){
hr = m_pVMRWC->GetMinIdealVideoSize(&dwWidth, &dwHeight);
if(FAILED(hr)){
throw(hr);
}
}
else{
throw(ImplReportError(__uuidof(T), IDS_E_NOTWNDLESS, __uuidof(IMSVidVideoRenderer), E_FAIL));
}
PQIMSVRect->put_Height(dwHeight);
PQIMSVRect->put_Width(dwWidth);
}
catch(HRESULT hres){
PQIMSVRect = static_cast<IMSVidRect *>(new CVidRect(-1,-1,-1,-1));
*ppVidRect = PQIMSVRect.Detach();
return hres;
}
*ppVidRect = PQIMSVRect.Detach();
return hr;
}
STDMETHOD(put_SourceSize)(/*[in]*/ SourceSizeList NewSize) {
if (!m_fInit) {
return ImplReportError(__uuidof(T), IDS_OBJ_NO_INIT, __uuidof(IMSVidVideoRenderer), CO_E_NOTINITIALIZED);
}
try {
SourceSizeList prev = m_SourceSize;
m_SourceSize = NewSize;
if (m_SourceSize != prev) {
return ReComputeSourceRect();
}
return NOERROR;
} catch(...) {
return E_UNEXPECTED;
}
}
STDMETHOD(get_CustomCompositorClass)(/*[out, retval]*/ BSTR *CompositorCLSID) {
try{
if(!CompositorCLSID){
return E_POINTER;
}
GUID2 gRetVal;
HRESULT hr = get__CustomCompositorClass(&gRetVal);
if(SUCCEEDED(hr)){
*CompositorCLSID = gRetVal.GetBSTR();
return S_OK;
}
}
catch(...){
return E_UNEXPECTED;
}
return S_OK;
}
STDMETHOD(get__CustomCompositorClass)(/*[out, retval]*/ GUID* CompositorCLSID) {
HRESULT hr = S_OK;
try{
if(!CompositorCLSID){
return E_POINTER;
}
if(m_compositorGuid != GUID_NULL){
*CompositorCLSID = m_compositorGuid;
return S_OK;
}
PQVMRImageComp pRetVal;
hr = get__CustomCompositor(&pRetVal);
if(FAILED(hr)){
return hr;
}
CComQIPtr<IPersist> ipRet(pRetVal);
hr = ipRet->GetClassID((CLSID*)CompositorCLSID);
if(SUCCEEDED(hr)){
return S_OK;
}
else{
return E_UNEXPECTED;
}
}
catch(...){
return E_UNEXPECTED;
}
return S_OK;
}
STDMETHOD(put_CustomCompositorClass)(/*[in]*/ BSTR CompositorCLSID) {
try{
GUID2 inGuid(CompositorCLSID);
HRESULT hr = put__CustomCompositorClass(inGuid);
if(SUCCEEDED(hr)){
return S_OK;
}
else{
return hr;
}
}
catch(...){
return E_UNEXPECTED;
}
return S_OK;
}
STDMETHOD(put__CustomCompositorClass)(/*[in]*/ REFCLSID CompositorCLSID) {
try{
CComQIPtr<IVMRImageCompositor>IVMRICPtr;
IVMRICPtr.Release();
HRESULT hr = CoCreateInstance( CompositorCLSID, NULL, CLSCTX_INPROC_SERVER, IID_IVMRImageCompositor, (LPVOID*) &IVMRICPtr);
if(FAILED(hr)){
return E_UNEXPECTED;
}
hr = put__CustomCompositor(IVMRICPtr);
if(FAILED(hr)){
return hr;
}
else{
return S_OK;
}
}
catch(...){
return E_UNEXPECTED;
}
return S_OK;
}
STDMETHOD(get__CustomCompositor)(/*[out, retval]*/ IVMRImageCompositor** Compositor) {
try{
if(!Compositor){
return E_POINTER;
}
if(!ImCompositor){
return ImplReportError(__uuidof(T), IDS_OBJ_NO_INIT, __uuidof(IMSVidVideoRenderer), CO_E_NOTINITIALIZED);;
}
else{
*Compositor = ImCompositor;
return S_OK;
}
}
catch(...){
return E_UNEXPECTED;
}
return S_OK;
}
STDMETHOD(put__CustomCompositor)(/*[in]*/ IVMRImageCompositor* Compositor) {
try{
if(!Compositor){
return E_POINTER;
}
ImCompositor = Compositor;
HRESULT hr = CleanupVMR();
if(FAILED(hr)){
return hr;
}
}
catch(...){
return E_UNEXPECTED;
}
return S_OK;
}
STDMETHOD(get_AvailableSourceRect)(IMSVidRect **ppVidRect) {
CComQIPtr<IMSVidRect>PQIMSVRect = static_cast<IMSVidRect *>(new CVidRect(0,0,0,0));
try{
if(!ppVidRect){
return E_POINTER;
}
SIZE Size, Ar;
HRESULT hr = get_NativeSize(&Size, &Ar);
hr = PQIMSVRect->put_Height(Size.cy);
if(FAILED(hr)){
throw(hr);
}
hr = PQIMSVRect->put_Width(Size.cx);
if(FAILED(hr)){
throw(hr);
}
}
catch(...){
return E_UNEXPECTED;
}
*ppVidRect = PQIMSVRect.Detach();
return S_OK;
}
STDMETHOD(put_ClippedSourceRect)(IMSVidRect *pVidRect) {
if (!m_fInit) {
return ImplReportError(__uuidof(T), IDS_OBJ_NO_INIT, __uuidof(IMSVidVideoRenderer), CO_E_NOTINITIALIZED);
}
if (!pVidRect) {
return E_POINTER;
}
try {
m_ClipRect = *(static_cast<CScalingRect*>(static_cast<CVidRect*>(pVidRect)));
return ReComputeSourceRect();
} catch(...) {
return E_UNEXPECTED;
}
}
STDMETHOD(get_ClippedSourceRect)(IMSVidRect **ppVidRect) {
if (!m_fInit) {
return ImplReportError(__uuidof(T), IDS_OBJ_NO_INIT, __uuidof(IMSVidVideoRenderer), CO_E_NOTINITIALIZED);
}
if (!ppVidRect) {
return E_POINTER;
}
try {
CComQIPtr<IMSVidRect>PQIMSVRect = static_cast<IMSVidRect *>(new CVidRect(-1,-1,-1,-1));
PQIMSVRect->put_Left(m_ClipRect.left);
PQIMSVRect->put_Height(m_ClipRect.bottom - m_ClipRect.top);
PQIMSVRect->put_Top(m_ClipRect.top);
PQIMSVRect->put_Width(m_ClipRect.right - m_ClipRect.left);
*ppVidRect = PQIMSVRect.Detach();
return S_OK;
} catch(...) {
return E_UNEXPECTED;
}
}
/*************************************************************************/
/* Function: Capture */
/* Description: Returns the current image on screen */
/*************************************************************************/
STDMETHOD(Capture)(IPictureDisp **currentImage){
HBITMAP hBitmap = 0;
HPALETTE hPalette = 0;
//VMRALPHABITMAP vmrAlphaBitmapStruct;
CComQIPtr<IPicture> retPicture;
PICTDESC PictDescStruct;
HRESULT hr = S_OK;
BYTE *lpDIB = NULL;
try{
if(!currentImage){
throw(E_POINTER);
}
if(!m_pVMR){
throw(E_FAIL);
}
if(m_pVMRWC){
hr = m_pVMRWC->GetCurrentImage(&lpDIB);
}
else{
throw(ImplReportError(__uuidof(T), IDS_E_NOTWNDLESS, __uuidof(IMSVidVideoRenderer), E_FAIL));
}
if(FAILED(hr)){
throw(hr);
}
HDC curDC = GetDC(NULL);
UINT wUsage = DIB_RGB_COLORS;
DWORD dwFlags = CBM_INIT;
hBitmap = CreateDIBitmap(curDC,
reinterpret_cast<BITMAPINFOHEADER*>(lpDIB), dwFlags,
reinterpret_cast<void *>((LPBYTE)(lpDIB) + (int)(reinterpret_cast<BITMAPINFOHEADER*>(lpDIB)->biSize)),
reinterpret_cast<BITMAPINFO*>(lpDIB),
wUsage);
ReleaseDC(NULL,curDC);
ZeroMemory(&PictDescStruct, sizeof(PictDescStruct));
PictDescStruct.bmp.hbitmap = hBitmap;
PictDescStruct.bmp.hpal = NULL;
PictDescStruct.picType = PICTYPE_BITMAP;
PictDescStruct.cbSizeofstruct = sizeof(PictDescStruct);
hr = OleCreatePictureIndirect(&PictDescStruct, IID_IPicture, TRUE, (void **)&retPicture);
if(SUCCEEDED(hr)){
hr = retPicture.QueryInterface(reinterpret_cast<IPictureDisp**>(currentImage));
return hr;
}
else{
throw(hr);
}
}
catch(HRESULT hres){
hr = hres;
}
catch(...){
hr = E_UNEXPECTED;
}
if(lpDIB){
CoTaskMemFree(lpDIB);
}
return hr;
}
/*************************************************************************/
/* Function: get_MixerBitmap */
/* Description: Returns the current alpha bitmap to script wrapped in a */
/* IPictureDisp. */
/*************************************************************************/
STDMETHOD(get_MixerBitmap)(/*[out,retval]*/ IPictureDisp** ppIPDisp){
#if 0
HDC *pHDC = NULL;
HBITMAP hBitmap = 0;
HPALETTE hPalette = 0;
VMRALPHABITMAP vmrAlphaBitmapStruct;
PQIPicDisp retPicture;
CComQIPtr<IVMRMixerBitmap> PQIVMRMixerBitmap;
PICTDESC PictDescStruct;
try{
HRESULT hr = get__MixerBitmap(&PQIVMRMixerBitmap);
if(FAILED(hr)){
return hr;
}
hr = PQIVMRMixerBitmap->GetAlphaBitmapParameters(&vmrAlphaBitmapStruct);
if(FAILED(hr)){
return hr;
}
hr = vmrAlphaBitmapStruct.pDDS->GetDC(pHDC);
if(FAILED(hr)){
return hr;
}
hBitmap = static_cast<HBITMAP>(GetCurrentObject(*pHDC, OBJ_BITMAP));
if(!hBitmap){
return hr;
}
hPalette = static_cast<HPALETTE>(GetCurrentObject(*pHDC, OBJ_PAL));
if(!hPalette){
return hr ;
}
PictDescStruct.bmp.hbitmap = hBitmap;
PictDescStruct.bmp.hpal = hPalette;
PictDescStruct.picType = PICTYPE_BITMAP;
PictDescStruct.cbSizeofstruct = sizeof(PictDescStruct.bmp);
hr = OleCreatePictureIndirect(&PictDescStruct, IID_IPictureDisp, true, reinterpret_cast<void**> (&retPicture));
if(FAILED(hr)){
return hr;
}
}
catch(HRESULT hr){
return hr;
}
catch(...){
return E_FAIL;
}
ppIPDisp = &retPicture.Detach();
return S_OK;
#endif
// If m_PQIPicture is set, return it
try{
if(m_PQIPicture){
CComQIPtr<IPictureDisp> PQIPDisp(m_PQIPicture);
*ppIPDisp = PQIPDisp.Detach();
throw S_OK;
}
else{
throw ImplReportError(__uuidof(T), IDS_OBJ_NO_INIT, __uuidof(IMSVidVideoRenderer), CO_E_NOTINITIALIZED);
}
}
catch(HRESULT hres){
return hres;
}
catch(...){
return E_UNEXPECTED;
}
}
/*************************************************************************/
/* Function: get__MixerBitmap */
/* Description: Returns the IVMRMixerBitmap from the VMR */
/*************************************************************************/
STDMETHOD(get__MixerBitmap)(/*[out, retval]*/ IVMRMixerBitmap ** ppIVMRMBitmap){
try{
if(!ppIVMRMBitmap){
return E_POINTER;
}
// Make sure there is a VMR filter init'ed
if(!m_pVMR){
return ImplReportError(__uuidof(T), IDS_OBJ_NO_INIT, __uuidof(IMSVidVideoRenderer), CO_E_NOTINITIALIZED);
}
CComQIPtr<IVMRMixerBitmap> PQIVMRMBitmap(m_pVMR);
*ppIVMRMBitmap = PQIVMRMBitmap.Detach();
}
catch(HRESULT hr){
return hr;
}
catch(...){
return E_UNEXPECTED;
}
return S_OK;
}
/*************************************************************************/
/* Function: put_MixerBitmap */
/* Description: Updates the current VMR Alpha Bitmap */
/* uses SutupMixerBitmap helper function */
/*************************************************************************/
STDMETHOD(put_MixerBitmap)(/*[in*/ IPictureDisp* pIPDisp){
try{
return SetupMixerBitmap(pIPDisp);
}
catch(HRESULT hr){
return hr;
}
catch(...){
return E_UNEXPECTED;
}
}
/*************************************************************************/
/* Function: put__MixerBitmap */
/* Description: Updates the current VMR Alpha Bitmap */
/* directly using the VMR fucntions */
/*************************************************************************/
STDMETHOD(put__MixerBitmap)(/*[in]*/ VMRALPHABITMAP * pVMRAlphaBitmapStruct){ //pMixerPicture
try{
HRESULT hr = S_OK;
if(!pVMRAlphaBitmapStruct){
return E_POINTER;
}
// Make sure there is a vmr to add the bitmap to
if(!m_pVMR){
return ImplReportError(__uuidof(T), IDS_OBJ_NO_INIT, __uuidof(IMSVidVideoRenderer), CO_E_NOTINITIALIZED);
}
// Querry the vmr for the MixerBitmap Interface
CComQIPtr<IVMRMixerBitmap> pVMRMBitmap(m_pVMR);
if (!pVMRMBitmap) {
return E_UNEXPECTED;
}
// Set the mixer bitmap to pVMRAlphaBitmapStruct
hr = pVMRMBitmap->SetAlphaBitmap(pVMRAlphaBitmapStruct);
return hr;
}
catch(HRESULT hr){
return hr;
}
catch(...){
return E_UNEXPECTED;
}
}
/**************************************************************************/
/* Function: get_MixerBitmapPositionRect */
/* Description: Lets script folk access the position of the overlay bitmap*/
/* the units are normalized vs the display rect so the values*/
/* should be between 0 and 1 though will be converted if they*/
/* are not */
/**************************************************************************/
STDMETHOD(get_MixerBitmapPositionRect)(/*[out,retval]*/IMSVidRect **ppIMSVRect){
HRESULT hr = S_OK;
CComQIPtr<IMSVidRect>PQIMSVRect;
try{
CComQIPtr<IVMRMixerBitmap> PQIVMRMBitmap;
PQIMSVRect = static_cast<IMSVidRect *>(new CVidRect(-1,-1,-1,-1));
VMRALPHABITMAP VMRAlphaBitmap;
if(!m_pVMR){
hr = S_FALSE;
throw(hr);
}
hr = get__MixerBitmap(&PQIVMRMBitmap);
// If the VMRBitmap is not set on the VRM, if it is not make sure that the local one is set
if(SUCCEEDED(hr) ){
// QI for the Parameters
hr = PQIVMRMBitmap->GetAlphaBitmapParameters(&VMRAlphaBitmap);
// if it fails or they are not set make sure that the local copy is
if(SUCCEEDED(hr)){
// Make sure that the rDest points are valid top and left : [0,1)
// and right and bottom (0,1]
if(VMRAlphaBitmap.rDest.top >= 0 && VMRAlphaBitmap.rDest.left >= 0 &&
VMRAlphaBitmap.rDest.top < 1 && VMRAlphaBitmap.rDest.left < 1 &&
VMRAlphaBitmap.rDest.right <= 1 && VMRAlphaBitmap.rDest.bottom <= 1 &&
VMRAlphaBitmap.rDest.right > 0 && VMRAlphaBitmap.rDest.bottom > 0){
// Make sure the local copy of the normalized rect is upto date
m_rectPosition = VMRAlphaBitmap.rDest;
}
}
}
if( m_rectPosition.left < 0 || m_rectPosition.top < 0 ||
m_rectPosition.right < 0 || m_rectPosition.bottom < 0 ){
hr = S_FALSE;
throw(hr);
}
else{
// Convert and copy the values in the local copy of the normalized rect to the return rect
hr = PQIMSVRect->put_Top(static_cast<long> (m_rectPosition.top * m_rectDest.Height()));
if(FAILED(hr)){
hr = ImplReportError(__uuidof(T), IDS_OBJ_NO_INIT, __uuidof(IMSVidVideoRenderer), CO_E_NOTINITIALIZED);
throw(hr);
}
// bottom * height - top
hr = PQIMSVRect->put_Height(static_cast<long>((m_rectPosition.bottom * m_rectDest.Height())
- (m_rectPosition.top * m_rectDest.Height())));
if(FAILED(hr)){
hr = ImplReportError(__uuidof(T), IDS_OBJ_NO_INIT, __uuidof(IMSVidVideoRenderer), CO_E_NOTINITIALIZED);
throw(hr);
}
// right * width - left
hr = PQIMSVRect->put_Width(static_cast<long>(m_rectPosition.right * m_rectDest.Width()
- (m_rectPosition.left * m_rectDest.Width())));
if(FAILED(hr)){
hr = ImplReportError(__uuidof(T), IDS_OBJ_NO_INIT, __uuidof(IMSVidVideoRenderer), CO_E_NOTINITIALIZED);
throw(hr);
}
hr = PQIMSVRect->put_Left(static_cast<long>(m_rectPosition.left * m_rectDest.Width()));
if(FAILED(hr)){
hr = ImplReportError(__uuidof(T), IDS_OBJ_NO_INIT, __uuidof(IMSVidVideoRenderer), CO_E_NOTINITIALIZED);
throw(hr);
}
}
*ppIMSVRect = PQIMSVRect.Detach();
return S_OK;
}
catch(HRESULT hres){
if(FAILED(hres)){
return hres;
}
if(m_rectDest){
PQIMSVRect.Release();
PQIMSVRect = static_cast<IMSVidRect *>(new CVidRect(m_rectDest));
}
else{
PQIMSVRect.Release();
PQIMSVRect = static_cast<IMSVidRect *>(new CVidRect(-1,-1,-1,-1));
}
*ppIMSVRect = PQIMSVRect.Detach();
return S_FALSE;
}
catch(...){
return E_UNEXPECTED;
}
}
/**************************************************************************/
/* Function: put_MixerBitmapPositionRect */
/* Description: Lets script folk change the position of the overlay bitmap*/
/* the units are normalized vs the display rect so the values*/
/* should be between 0 and 1 though will be converted if they*/
/* are not */
/**************************************************************************/
STDMETHOD(put_MixerBitmapPositionRect)(/*[in]*/ IMSVidRect *pIMSVRect){
if(pIMSVRect){
NORMALIZEDRECT NormalizedRectStruct;
long lValue;
NormalizedRectStruct.left = -1.f;
NormalizedRectStruct.top = -1.f;
NormalizedRectStruct.right = -1.f;
NormalizedRectStruct.bottom = -1.f;
if(SUCCEEDED(pIMSVRect->get_Left(&lValue))){
if(m_rectDest.Width() != 0){
// check m_rectDest.Width() for zero
if(lValue > 0){
NormalizedRectStruct.left =
static_cast<float>(lValue)/static_cast<float>(m_rectDest.Width());
}
else{
NormalizedRectStruct.left = static_cast<float>(lValue);
}
}
}
if(SUCCEEDED(pIMSVRect->get_Top(&lValue))){
if(m_rectDest.Height() != 0){
if(lValue > 0){
NormalizedRectStruct.top =
static_cast<float>(lValue)/static_cast<float>(m_rectDest.Height());
}
else{
NormalizedRectStruct.top = static_cast<float>(lValue);
}
}
}
if(SUCCEEDED(pIMSVRect->get_Width(&lValue))){
if(m_rectDest.Width() != 0){
if(lValue > 0){
NormalizedRectStruct.right =
(static_cast<float>(lValue)/static_cast<float>(m_rectDest.Width()))
+ static_cast<float>(NormalizedRectStruct.left);
}
}
}
if(SUCCEEDED(pIMSVRect->get_Height(&lValue))){
if(m_rectDest.Width() != 0){
if(lValue > 0){
NormalizedRectStruct.bottom =
(static_cast<float>(lValue)/static_cast<float>(m_rectDest.Height()))
+ static_cast<float>(NormalizedRectStruct.top);
}
}
}
if(NormalizedRectStruct.top < 0 || NormalizedRectStruct.left < 0 ||
NormalizedRectStruct.top > 1 || NormalizedRectStruct.left > 1 ||
NormalizedRectStruct.right < 0 || NormalizedRectStruct.bottom < 0 ||
NormalizedRectStruct.right > 1 || NormalizedRectStruct.bottom > 1){
return ImplReportError(__uuidof(T), IDS_E_MIXERSRC, __uuidof(IMSVidVideoRenderer), CO_E_ERRORINAPP);
}
m_rectPosition = NormalizedRectStruct;
}
if(m_PQIPicture == NULL){
return S_OK;
}
else{
return SetupMixerBitmap(reinterpret_cast<IPictureDisp*>(-1));
}
}
/**************************************************************************/
/* Function: get_MixerBitmapOpacity */
/* Description: lets script access the opacity value */
/* should be between 0 and 100 (%) */
/**************************************************************************/
STDMETHOD(get_MixerBitmapOpacity)(/*[out,retval]*/ int *pwOpacity){
CComQIPtr<IVMRMixerBitmap> PQIVMRMBitmap;
VMRALPHABITMAP VMRAlphaBitmapStruct;
HRESULT hr = get__MixerBitmap(&PQIVMRMBitmap);
if(SUCCEEDED(hr)){
hr = PQIVMRMBitmap->GetAlphaBitmapParameters(&VMRAlphaBitmapStruct);
if(SUCCEEDED(hr)){
if(m_opacity != VMRAlphaBitmapStruct.fAlpha){
m_opacity = VMRAlphaBitmapStruct.fAlpha;
}
}
}
if(m_opacity == -1){
return ImplReportError(__uuidof(T), IDS_OBJ_NO_INIT, __uuidof(IMSVidVideoRenderer), CO_E_NOTINITIALIZED);
}
if(m_opacity > 1 || m_opacity < 0){
return E_UNEXPECTED;
}
*pwOpacity = static_cast<int>(m_opacity*100);
return S_OK;
}
/**************************************************************************/
/* Function: put_MixerBitmapOpacity */
/* Description: lets script set the value opacity */
/* should be between 0 and 100 (%) */
/**************************************************************************/
STDMETHOD(put_MixerBitmapOpacity)(/*[in]*/ int wOpacity){
// make sure the value is between 0 and 100
if(wOpacity >=0 && wOpacity <= 100){
if(wOpacity == 0){
//if it is 0 set it by hand instead of deviding by 0
m_opacity = static_cast<float>(wOpacity);
}
m_opacity = static_cast<float>(wOpacity)/100.f;
}
else{
return ImplReportError(__uuidof(T), IDS_E_OPACITY, __uuidof(IMSVidVideoRenderer), CO_E_ERRORINAPP);
}
if(!m_PQIPicture){
return S_OK;
}
else{
HRESULT hr = SetupMixerBitmap(reinterpret_cast<IPictureDisp*>(-1));
return hr;
}
}
/**************************************************************************/
/* Function: SetupMixerBitmap */
/* Description: big nasty function to set bitmap, opacity and the position*/
/* rect. It wraps everyting up in a mixer bitmap struct and */
/* then passes it off to put__MixerBitmap */
/* It is both a helper function and a automation method so */
/* that script people can make sure that transparent overlays*/
/* dont show up opaque for a few frames */
/* for reference the vmralphabitmap struct */
/* typedef struct _VMRALPHABITMAP { */
/* DWORD dwFlags;// flags word = VMRBITMAP_HDC */
/* HDC hdc; // DC for the bitmap to copy */
/* LPDIRECTDRAWSURFACE7 pDDS; // DirectDraw surface to copy IGNORED */
/* RECT rSrc; // rectangle to copy from the sourceR */
/* NORMALIZEDRECT rDest; // output rectangle in composition space*/
/* FLOAT fAlpha; // opacity of the bitmap */
/* } VMRALPHABITMAP, *PVMRALPHABITMAP; */
/**************************************************************************/
STDMETHOD(SetupMixerBitmap)(/*[in]*/ IPictureDisp* pIPDisp = NULL, /*[in]*/ long wOpacity = -1,
/*[in]*/ IMSVidRect *pIMSVRect = NULL){
VMRALPHABITMAP VMRAlphaBitmapStruct;
ZeroMemory(&VMRAlphaBitmapStruct, sizeof(VMRALPHABITMAP));
RECT rSource;
ZeroMemory(&rSource, sizeof(RECT));
long lPicHeight, lPicWidth;
HRESULT hr = S_OK;
try{
if(!pIPDisp){
if(m_PQIPicture){
m_PQIPicture.Release();
}
VMRAlphaBitmapStruct.dwFlags = VMRBITMAP_DISABLE;
return hr = put__MixerBitmap(&VMRAlphaBitmapStruct);
}
// Our input is a IPictureDisp which we need to massage into a VMRALPHABITMAP
// Problem is that it does not quite all go in but what does we will keep and pass on up
if(pIPDisp == reinterpret_cast<IPictureDisp*>(-1)){
CComQIPtr<IPicture>PQIPicture(m_PQIPicture);
if(!PQIPicture){
return S_OK;
}
}
else if(pIPDisp){
// QI for a IPicture
CComQIPtr<IPicture>PQIPicture(pIPDisp);
if(!PQIPicture){
return E_NOINTERFACE;
}
// Save the IPicture for possible use later
m_PQIPicture = PQIPicture;
}
// Get the source rect size (and for some reason ole returns the size
// in tenths of a millimeter so I need to convert it)
short shortType;
m_PQIPicture->get_Type(&shortType);
if(shortType != PICTYPE_BITMAP){
return ImplReportError(__uuidof(T), IDS_E_MIXERBADFORMAT, __uuidof(IMSVidVideoRenderer), E_INVALIDARG); // Need to add a the is not a valid picture string
}
hr = m_PQIPicture->get_Height(&lPicHeight);
if(FAILED(hr)){
return ImplReportError(__uuidof(T), IDS_E_IPICTURE, __uuidof(IMSVidVideoRenderer), CO_E_ERRORINAPP);
}
hr = m_PQIPicture->get_Width(&lPicWidth);
if(FAILED(hr)){
return ImplReportError(__uuidof(T), IDS_E_IPICTURE, __uuidof(IMSVidVideoRenderer), CO_E_ERRORINAPP);
}
SIZEL x, y;
AtlHiMetricToPixel((const SIZEL*)&lPicWidth, &(x));
AtlHiMetricToPixel((const SIZEL*)&lPicHeight, &(y));
// The AtlHiMetricToPixel function returns a size with the cx value set (no idea why)
rSource.right = x.cx;
rSource.bottom = y.cx;
// create a hdc to store the bitmap
HDC memHDC = CreateCompatibleDC(NULL);
// create a bitmap to store in the hdc
HBITMAP memHBIT = 0;
// pull out the bitmap from the IlPicture
hr = m_PQIPicture->get_Handle(reinterpret_cast<OLE_HANDLE*>(&memHBIT));
if(FAILED(hr)){
return ImplReportError(__uuidof(T), IDS_E_IPICTURE, __uuidof(IMSVidVideoRenderer), CO_E_ERRORINAPP);
}
// Stuff the bitmap into a hdc and keep handle to delete bitmap later
HBITMAP delHBIT = static_cast<HBITMAP>(SelectObject(memHDC, memHBIT));
// Put all of the collected info into a VMRBITMAP stuct and pass it on
VMRAlphaBitmapStruct.rSrc = rSource;
VMRAlphaBitmapStruct.hdc = memHDC;
VMRAlphaBitmapStruct.dwFlags = VMRBITMAP_HDC;
// If the wOpacity value is valid use it
if(wOpacity >=0 && wOpacity <= 100){
if(wOpacity == 0){
m_opacity = wOpacity;
}
m_opacity = static_cast<float>(wOpacity/100.f);
VMRAlphaBitmapStruct.fAlpha = static_cast<float>(m_opacity);
}
// wOpacity is not set so check other values
// if m_opacity is set use it, if not default to 50% (.5)
else if (wOpacity == -1){
if(m_opacity < 0){
VMRAlphaBitmapStruct.fAlpha = .5f;
}
else{
VMRAlphaBitmapStruct.fAlpha = m_opacity;
}
}
// Bad wOpacity value give them an error
else{
return ImplReportError(__uuidof(T), IDS_E_OPACITY, __uuidof(IMSVidVideoRenderer), CO_E_ERRORINAPP);
}
// If the m_rectPostion is set use it, else default to full screen
if(pIMSVRect){
NORMALIZEDRECT NormalizedRectStruct;
long lValue;
NormalizedRectStruct.left = -1.f;
NormalizedRectStruct.top = -1.f;
NormalizedRectStruct.right = -1.f;
NormalizedRectStruct.bottom = -1.f;
if(SUCCEEDED(pIMSVRect->get_Left(&lValue))){
if(m_rectDest.Width() != 0){
// check m_rectDest.Width() for zero
if(lValue > 0){
NormalizedRectStruct.left =
static_cast<float>(lValue)/static_cast<float>(m_rectDest.Width());
}
else{
NormalizedRectStruct.left = static_cast<float>(lValue);
}
}
}
if(SUCCEEDED(pIMSVRect->get_Top(&lValue))){
if(m_rectDest.Height() != 0){
if(lValue > 0){
NormalizedRectStruct.top =
static_cast<float>(lValue)/static_cast<float>(m_rectDest.Height());
}
else{
NormalizedRectStruct.top = static_cast<float>(lValue);
}
}
}
if(SUCCEEDED(pIMSVRect->get_Width(&lValue))){
if(m_rectDest.Width() != 0){
if(lValue > 0){
NormalizedRectStruct.right =
(static_cast<float>(lValue)/static_cast<float>(m_rectDest.Width()))
+ static_cast<float>(NormalizedRectStruct.left);
}
}
}
if(SUCCEEDED(pIMSVRect->get_Height(&lValue))){
if(m_rectDest.Width() != 0){
if(lValue > 0){
NormalizedRectStruct.bottom =
(static_cast<float>(lValue)/static_cast<float>(m_rectDest.Height()))
+ static_cast<float>(NormalizedRectStruct.top);
}
}
}
if(NormalizedRectStruct.top < 0 || NormalizedRectStruct.left < 0 ||
NormalizedRectStruct.top > 1 || NormalizedRectStruct.left > 1 ||
NormalizedRectStruct.right < 0 || NormalizedRectStruct.bottom < 0 ||
NormalizedRectStruct.right > 1 || NormalizedRectStruct.bottom > 1){
return ImplReportError(__uuidof(T), IDS_E_MIXERSRC, __uuidof(IMSVidVideoRenderer), CO_E_ERRORINAPP);
}
m_rectPosition = NormalizedRectStruct;
VMRAlphaBitmapStruct.rDest = m_rectPosition;
}
else{
if( m_rectPosition.left < 0 || m_rectPosition.top < 0 || m_rectPosition.right < 0 || m_rectPosition.bottom < 0 ){
VMRAlphaBitmapStruct.rDest.left = 0.f;
VMRAlphaBitmapStruct.rDest.top = 0.f;
VMRAlphaBitmapStruct.rDest.right = 1.f;
VMRAlphaBitmapStruct.rDest.bottom = 1.f;
}
else{
VMRAlphaBitmapStruct.rDest = m_rectPosition;
}
}
// If it is all valid then this is all good
hr = put__MixerBitmap(&VMRAlphaBitmapStruct);
if(!DeleteDC(memHDC)){
return ImplReportError(__uuidof(T), IDS_E_CANT_DELETE, __uuidof(IMSVidVideoRenderer), ERROR_DS_CANT_DELETE);
}
if(SUCCEEDED(hr)){
return S_OK;
}
else{
return hr;
}
}
catch(...){
return E_UNEXPECTED;
}
}
STDMETHOD(get_UsingOverlay)(/*[out, retval]*/ VARIANT_BOOL *pfUseOverlay) {
return get_UseOverlay(pfUseOverlay);
}
STDMETHOD(put_UsingOverlay)(/*[in]*/ VARIANT_BOOL fUseOverlayVal) {
return put_UseOverlay(fUseOverlayVal);
}
STDMETHOD(get_FramesPerSecond)(/*[out, retval]*/ long *pVal){
try{
if(pVal){
if(!m_pVMR){
throw(ImplReportError(__uuidof(T), IDS_OBJ_NO_INIT, __uuidof(IMSVidVideoRenderer), CO_E_NOTINITIALIZED));
}
IQualProp *IQProp = NULL;
HRESULT hr = m_pVMR->QueryInterface(IID_IQualProp, reinterpret_cast<void**>(&IQProp));
if(FAILED(hr)){
return hr;
}
if(!IQProp){
return E_NOINTERFACE;
}
hr = IQProp->get_AvgFrameRate(reinterpret_cast<int*>(pVal));
IQProp->Release();
return hr;
}
else{
return E_POINTER;
}
}
catch(...){
return E_UNEXPECTED;
}
}
STDMETHOD(put_DecimateInput)(/*[in]*/ VARIANT_BOOL bDeci){
try{
if(bDeci != VARIANT_TRUE && bDeci != VARIANT_FALSE){
return E_INVALIDARG;
}
m_Decimate = (bDeci == VARIANT_TRUE);
if(!m_pVMR){
return S_OK;
}
DWORD curPrefs;
DWORD deci;
CComQIPtr<IVMRMixerControl>PQIVMRMixer(m_pVMR);
if(!PQIVMRMixer){
return E_UNEXPECTED;
}
HRESULT hr = PQIVMRMixer->GetMixingPrefs(&curPrefs);
if(FAILED(hr)){
return hr;
}
deci = (m_Decimate?MixerPref_DecimateOutput:MixerPref_NoDecimation);
if(!(curPrefs&deci)){
hr = CleanupVMR();
if(FAILED(hr)){
return hr;
}
}
return NOERROR;
}
catch(...){
return E_UNEXPECTED;
}
}
STDMETHOD(get_DecimateInput)(/*[out,retval]*/ VARIANT_BOOL *pDeci){
try{
if(!pDeci){
return E_POINTER;
}
if(!m_pVMR){
throw(ImplReportError(__uuidof(T), IDS_OBJ_NO_INIT, __uuidof(IMSVidVideoRenderer), CO_E_NOTINITIALIZED));
}
DWORD curPrefs;
CComQIPtr<IVMRMixerControl>PQIVMRMixer(m_pVMR);
if(!PQIVMRMixer){
return E_UNEXPECTED;
}
HRESULT hr = PQIVMRMixer->GetMixingPrefs(&curPrefs);
if(FAILED(hr)){
return hr;
}
*pDeci = ((curPrefs&MixerPref_DecimateMask)==MixerPref_DecimateOutput)? VARIANT_TRUE : VARIANT_FALSE;
return NOERROR;
}
catch(...){
return E_UNEXPECTED;
}
}
STDMETHOD(ReComputeSourceRect)() {
switch (m_SourceSize) {
case sslFullSize: {
CSize sz;
CSize ar;
if(m_pVMRWC){
HRESULT hr = m_pVMRWC->GetNativeVideoSize(&sz.cx, &sz.cy, &ar.cx, &ar.cy);
if (FAILED(hr)) {
return hr;
}
TRACELSM(TRACE_PAINT, (dbgDump << "CMSVidVideoRenderer::ReComputeSourceRect() sslFullSize vmr sz = " << sz), "");
}
CRect r(0, 0, sz.cx, sz.cy);
TRACELSM(TRACE_DETAIL, (dbgDump << "CMSVidVideoRenderer::ReComputeSource() full = " << r), "");
return put_Source(r);
} break;
case sslClipByOverScan: {
CSize sz;
CSize ar;
if(m_pVMRWC){
HRESULT hr = m_pVMRWC->GetNativeVideoSize(&sz.cx, &sz.cy, &ar.cx, &ar.cy);
if (FAILED(hr)) {
return hr;
}
TRACELSM(TRACE_PAINT, (dbgDump << "CMSVidVideoRenderer::ReComputeSourceRect() sslClipByOverScan vmr sz = " << sz), "");
}
CRect r(0, 0, sz.cx, sz.cy);
CRect r2;
float fpct = m_lOverScan / 10000.0; // overscan is in hundredths of pct, i.e 1.75% == 175
long wcrop = (long)(r.Width() * fpct + 0.5);
long hcrop = (long)(r.Height() * fpct + 0.5);
r2.left = 0 + wcrop;
r2.top = 0 + hcrop;
r2.right = r2.left + r.Width() - (2.0 * wcrop);
r2.bottom = r2.top + r.Height() - (2.0 * hcrop);
TRACELSM(TRACE_DETAIL, (dbgDump << "CMSVidVideoRenderer::ReComputeSource() over = " << m_lOverScan <<
" w " << wcrop <<
" h " << hcrop), "");
TRACELSM(TRACE_DETAIL, (dbgDump << "CMSVidVideoRenderer::ReComputeSource() full = " << r << " clip = " << r2), "");
return put_Source(r2);
} break;
case sslClipByClipRect: {
TRACELSM(TRACE_DETAIL, (dbgDump << "CMSVidVideoRenderer::ReComputeSource() cliprect = " << m_ClipRect), "");
if(m_ClipRect.Width() == 0 && m_ClipRect.Height() == 0){
CSize sz;
CSize ar;
if(m_pVMRWC){
HRESULT hr = m_pVMRWC->GetNativeVideoSize(&sz.cx, &sz.cy, &ar.cx, &ar.cy);
if (FAILED(hr)) {
return hr;
}
TRACELSM(TRACE_PAINT, (dbgDump << "CMSVidVideoRenderer::ReComputeSourceRect() sslClipByClipRect vmr sz = " << sz), "");
}
CRect r(0, 0, sz.cx, sz.cy);
TRACELSM(TRACE_DETAIL, (dbgDump << "CMSVidVideoRenderer::ReComputeSource() full = " << r), "");
return put_Source(r);
} else{
TRACELSM(TRACE_PAINT, (dbgDump << "CMSVidVideoRenderer::ReComputeSourceRect() sslClipByClipRect cliprect = " << m_ClipRect), "");
return put_Source(m_ClipRect);
}
} break;
default:{
return E_INVALIDARG;
} break;
}
return NOERROR;
}
};
#endif //__MSVidVIDEORENDERER_H_