topical media & game development
hush-src-multi-DLL-MixerControl.cpp / cpp
//------------------------------------------------------------------------------
// File: MixerControl.cpp
//
// Desc: DirectShow sample code - Implementation of CMultiVMR9MixerControl
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------
include <stdafx.h>
include <MixerControl.h>
include <math.h>
****************************Public*Routine******************************\
CMultiVMR9MixerControl
constructor
\*************************************************************************
CMultiVMR9MixerControl::CMultiVMR9MixerControl(LPUNKNOWN pUnk, HRESULT *phr)
: CUnknown(NAME("MultiVMR9 Mixer Control"), pUnk)
, m_pOwner( NULL )
, m_FVF( MultiVMR9Mixer_DefaultFVF )
, m_BackgroundColor( RGB(0x00, 0x00, 0x00))
, m_bInitialized( FALSE )
{
}
****************************Public*Routine******************************\
~CMultiVMR9MixerControl
destructor
\*************************************************************************
CMultiVMR9MixerControl::~CMultiVMR9MixerControl()
{
CAutoLock Lock(&m_ObjectLock);
Clean_();
}
/////////////////// IUnknown ///////////////////////////////////
****************************Public*Routine******************************\
CreateInstance
\*************************************************************************
CUnknown* CMultiVMR9MixerControl::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
{
return new CMultiVMR9MixerControl(pUnk, phr);
}
****************************Public*Routine******************************\
NonDelegatingQueryInterface
\*************************************************************************
STDMETHODIMP
CMultiVMR9MixerControl::NonDelegatingQueryInterface(
REFIID riid,
void ** ppv)
{
HRESULT hr = E_NOINTERFACE;
*ppv = NULL;
if (riid == IID_IMultiVMR9MixerControl)
{
hr = GetInterface((IMultiVMR9MixerControl *)this, ppv);
}
else
{
hr = CUnknown::NonDelegatingQueryInterface(riid,ppv);
}
return hr;
}
/////////////////// IMultiVMR9MixerControl /////////////////////////
****************************Public*Routine******************************\
SetRenderEngineOwner
This method is called by IMultiVMR9RenderEngine during initialization,
sets IMultiVMR9RenderEngine object that manages this mixer control
pRenderEngine - render engine
Return error codes: none
\*************************************************************************
STDMETHODIMP CMultiVMR9MixerControl::SetRenderEngineOwner(
IMultiVMR9RenderEngine* pRenderEngine)
{
CAutoLock Lock(&m_ObjectLock);
RELEASE( m_pOwner );
if( pRenderEngine )
{
m_pOwner = pRenderEngine;
m_pOwner->AddRef();
}
return S_OK;
}
****************************Public*Routine******************************\
GetRenderEngineOwner
Call this method to obtain pointer to the IMultiVMR9RenderEngine that
manages this mixer control
ppRenderEngine - render engine
Return error codes: E_POINTER (ppRenderEngine is NULL)
VFW_E_NOT_FOUND (mixer control is not connected to any
render engine)
\*************************************************************************
STDMETHODIMP CMultiVMR9MixerControl::GetRenderEngineOwner(
IMultiVMR9RenderEngine** ppRenderEngine)
{
if( !ppRenderEngine )
{
return E_POINTER;
}
if( !m_pOwner )
{
return VFW_E_NOT_FOUND;
}
*ppRenderEngine = m_pOwner;
(*ppRenderEngine)->AddRef();
return S_OK;
}
****************************Public*Routine******************************\
Initialize
This method is called by the render engine when it creates Direct3D device
pDevice - render engine
Return error codes: E_POINTER (ppRenderEngine is NULL)
\*************************************************************************
STDMETHODIMP CMultiVMR9MixerControl::Initialize(
IDirect3DDevice9 *pDevice)
{
if( !pDevice )
{
return E_POINTER;
}
m_bInitialized = TRUE;
return S_OK;
}
****************************Public*Routine******************************\
BeginDeviceLoss
This method is called by the render engine when it loses Direct3D device
\*************************************************************************
STDMETHODIMP CMultiVMR9MixerControl::BeginDeviceLoss( void )
{
return S_OK;
}
****************************Public*Routine******************************\
EndDeviceLoss
This method is called by the render engine when it loses Direct3D device
\*************************************************************************
STDMETHODIMP CMultiVMR9MixerControl::EndDeviceLoss( IDirect3DDevice9* pDevice )
{
return S_OK;
}
****************************Public*Routine******************************\
Compose
This method allows to make necessary transformations of primitive's geometry
(coordinates). Method is always called from IMultiVMR9RenderEngine::Render with
specified in the render engine frame rate. By default, lpParam is render engine's
timer (time, in ms, since render engine started). You can use this timer for
animation. You can also modify IMultiVMR9RenderEngine::Render to send here
some other parameter.
Here, in the default implementation of IMultiVMR9MixerControl, we expand
IVMRMixerControl functionality on multi-graph environment, so we do not have
to make any routing coordinate transformations (animation). So this method
just copies frame vertices to correspondent vertex buffers
lpParam - application specific parameter (timer of the render engine by default)
Return error codes: S_FALSE (there were some errors during composing)
VFW_E_WRONG_STATE(mixer was not initialized)
\*************************************************************************
STDMETHODIMP CMultiVMR9MixerControl::Compose(void* lpParam)
{
HRESULT hr = S_OK;
if( !m_bInitialized )
{
return VFW_E_WRONG_STATE;
}
// when overrriding this method, make sure you are thread safe
CAutoLock Lock(&m_ObjectLock);
return hr;
}
****************************Public*Routine******************************\
Render
Method makes actual rendering of 3D primitives with applied textures that
can be video sources. This method is always called from
IMultiVMR9RenderEngine::Render with specified in the render engine frame rate.
Override this method to perform customized rendering.
Please note, that when this method is called, render engine already made
BeginScene() call to its Direct3D device. It will also call EndScene after
Mixer control and UI layer (if present) finish their rendering.
Do NOT call BeginScene() or EndScene() here!
In the default implementation of the method, we go through primitives specified
by list of MultiVMR9_Frame in Z-order and draw rectangular primitives (coupled
triangle strip) one by one. Frame's coordinates and alpha level are already set
in correspondent methods. By default, every frame occupies maximum area of the
back buffer and maintains aspect ratio, alpha level is 1; Z-order corresponds
to the order sources were connected to the wizard (last added will be on the front)
pDevice - IDirect3DDevice9 from the render engine
lpParam - application specific parameter (timer of the render engine by default,
as in Compose() above)
Return error codes: S_FALSE (there were errors during rendering)
E_POINTER (pDevice is NULL)
E_UNEXPECTED (unexpected error)
VFW_E_WRONG_STATE(mixer was not initialized)
\*************************************************************************
STDMETHODIMP CMultiVMR9MixerControl::Render(IDirect3DDevice9 *pDevice,
void* lpParam)
{
HRESULT hr = S_OK;
HRESULT hrRen = S_OK;
CMultiVMR9_Frame *pFrame = NULL;
IMultiVMR9Wizard* pHostWizard = NULL;
IDirect3DTexture9* pTexture = NULL;
if( !m_bInitialized )
{
return VFW_E_WRONG_STATE;
}
if( !pDevice )
{
::DbgMsg("CMultiVMR9MixerControl::Render: received NULL pointer");
return E_POINTER;
}
if( !m_pOwner )
{
::DbgMsg("CMultiVMR9MixerControl::Render: FATAL, cannot find IMultiVMR9RenderEngine owner");
return E_UNEXPECTED;
}
CAutoLock Lock(&m_ObjectLock);
try
{
CHECK_HR(
hr = m_pOwner->GetWizardOwner( &pHostWizard ),
::DbgMsg("CMultiVMR9MixerControl::Render: FATAL, cannot find IMultiVMR9Wizard owner, "\
"hr = 0x%08x, pWizard = 0x%08x", hr, pHostWizard));
list<CMultiVMR9_Frame*>::iterator start, end, it;
start = m_listFrames.begin();
end = m_listFrames.end();
for( it=start; it!=end; it++)
{
RELEASE( pTexture );
pFrame = (CMultiVMR9_Frame*)(*it);
CHECK_HR(
hr = pHostWizard->GetTexture( pFrame->m_dwID, &pTexture ),
::DbgMsg("CMultiVMR9MixerControl::Render: cannot find the texture!, "\
"ID = 0x%08x, hr = 0x%08x, pTexture = 0x%08x",
pFrame->m_dwID, hr, pTexture));
CHECK_HR(
hr = pDevice->SetTexture( 0, pTexture ),
::DbgMsg("CMultiVMR9MixerControl::Render: failed to set texture for "\
"ID = 0x%08x, hr = 0x%08x, pTexture = 0x%08x",
pFrame->m_dwID, hr, pTexture));
CHECK_HR(
hr = pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1),
::DbgMsg("CMultiVMR9MixerControl::Render: failed in SetTextureStageState(D3DTSS_ALPHAOP...), hr = 0x%08x", hr));
CHECK_HR(
hr = pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE),
::DbgMsg("CMultiVMR9MixerControl::Render: failed in SetTextureStageState(D3DTSS_ALPHAARG1...), hr = 0x%08x", hr));
CHECK_HR(
hr = pDevice->SetFVF(m_FVF),
::DbgMsg("CMultiVMR9MixerControl::Render: failed to set FVF "\
"ID = 0x%08x, hr = 0x%08x",
pFrame->m_dwID, hr));
// draw the primitive
CHECK_HR(
hr = pDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP,
2,
(LPVOID)(pFrame->m_coord),
sizeof(pFrame->m_coord[0])),
::DbgMsg("CMultiVMR9MixerControl::Render: failed to DrawPrimitive "\
"ID = 0x%08x, hr = 0x%08x",
pFrame->m_dwID, hr));
CHECK_HR(
hr = pDevice->SetTexture( 0, NULL ),
::DbgMsg("CMultiVMR9MixerControl::Render: failed to SetTexture(0,NULL) "\
"ID = 0x%08x, hr = 0x%08x",
pFrame->m_dwID, hr));
} // for all frames
}// try
catch( HRESULT hr1 )
{
hr = hr1;
}
RELEASE( pTexture );
RELEASE( pHostWizard );
return hr;
}
****************************Public*Routine******************************\
AddVideoSource
Upon this call, mixer control should allocate new primitive that
will be used to draw the source.
Override this method to use your own primitives. If you want to render something
other than video sources, make a relevant modification of the render engine.
In the default implementation, MultiVMR9_Frame is used to describe the primitive.
New frame is added to the end of the list and has least Z-order.
dwID - ID of the video source assigned in IMultiVMR9Wizard::Attach(). This ID
should be already registered with hosting wizard.
Return error codes: VFW_E_NOT_FOUND (unknown dwID)
E_UNEXPECTED (unexpected error)
VFW_E_WRONG_STATE(mixer was not initialized)
\*************************************************************************
STDMETHODIMP CMultiVMR9MixerControl::AddVideoSource(
DWORD_PTR dwID,
LONG lImageWidth,
LONG lImageHeight,
LONG lTextureWidth,
LONG lTextureHeight
)
{
HRESULT hr = S_OK;
IMultiVMR9Wizard* pHostWizard = NULL;
IDirect3DDevice9* pDevice = NULL;
IDirect3DSurface9* pBackBuffer = NULL;
CMultiVMR9_Frame *pFrame = NULL;
CMultiVMR9_Frame *pFrameNew = NULL;
LONG lRTWidth = 0L;
LONG lRTHeight = 0L;
D3DSURFACE_DESC ddsd;
if( !m_bInitialized )
{
return VFW_E_WRONG_STATE;
}
// sanity check
if( !m_pOwner )
{
::DbgMsg("CMultiVMR9MixerControl::AddVideoSource: FATAL, cannot find IMultiVMR9RenderEngine owner");
return E_UNEXPECTED;
}
try
{
CHECK_HR(
m_pOwner->GetWizardOwner( &pHostWizard ),
::DbgMsg("CMultiVMR9MixerControl::AddVideoSource: FATAL, cannot find IMultiVMR9Wizard owner"));
CHECK_HR(
m_pOwner->Get3DDevice( &pDevice ),
::DbgMsg("CMultiVMR9MixerControl::AddVideoSource: FATAL, cannot find IDirect3DDevice9"));
CHECK_HR(
hr = pDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer),
::DbgMsg("CMultiVMR9MixerControl::AddVideoSource: FATAL, cannot get back buffer, "\
"hr = 0x%08x", hr));
CHECK_HR(
hr = pBackBuffer->GetDesc( &ddsd ),
::DbgMsg("CMultiVMR9MixerControl::AddVideoSource: FATAL, cannot get back buffer description"\
"hr = 0x%08x", hr));
lRTWidth = ddsd.Width;
lRTHeight = ddsd.Height;
// check if wizard knows about this dwID
CHECK_HR(
hr = pHostWizard->VerifyID( dwID ),
::DbgMsg("CMultiVMR9MixerControl::AddVideoSource: received invalid dwID (video source is not found), "\
"hr = 0x%08x", hr));
CAutoLock Lock(&m_ObjectLock);
// check if we already have this frame
list<CMultiVMR9_Frame*>::iterator start, end, it;
start = m_listFrames.begin();
end = m_listFrames.end();
for( it=start; it!=end; it++)
{
CMultiVMR9_Frame* pCurFrame = (CMultiVMR9_Frame*)(*it);
if( pCurFrame )
{
if( pCurFrame->m_dwID == dwID )
{
pFrame = pCurFrame;
break;
}
}
}
if( pFrame )
{
CHECK_HR( pFrame->Reload( dwID,
lImageWidth,
lImageHeight,
lTextureWidth,
lTextureHeight,
lRTWidth,
lRTHeight ),
::DbgMsg("CMultiVMR9MixerControl::AddVideoSource: failed to reload frame"));
throw S_OK;
}
// ok, create new frame
pFrameNew = new CMultiVMR9_Frame();
CHECK_HR(
( !pFrameNew ) ? E_OUTOFMEMORY : S_OK,
::DbgMsg("CMultiVMR9MixerControl::AddVideoSource: memory allocation error"));
CHECK_HR(
hr = pFrameNew->Initialize( dwID,
lImageWidth,
lImageHeight,
lTextureWidth,
lTextureHeight,
lRTWidth,
lRTHeight,
1.f ),
::DbgMsg("CMultiVMR9MixerControl::AddVideoSource: failed in CMultiVMR9_Frame::Initialize, "\
"hr = 0x%08x", hr));
// now add the frame to the end of the list, incrementing Z-Order of already
// existing frames
start = m_listFrames.begin();
end = m_listFrames.end();
for( it=start; it!=end; it++)
{
(*it)->m_dwZOrder++;
}
pFrameNew->m_dwZOrder = 0;
m_listFrames.push_back( pFrameNew );
}// try
catch( HRESULT hr1 )
{
hr = hr1;
if( pFrameNew )
{
delete pFrameNew;
pFrameNew = NULL;
}
}
RELEASE( pDevice );
RELEASE( pHostWizard );
RELEASE( pBackBuffer );
return hr;
}
****************************Public*Routine******************************\
DeleteVideoSource
Upon this call, mixer control should deletes correspondent primitive from
the list
dwID - ID of the video source assigned in IMultiVMR9Wizard::Attach(). This ID
should be already registered with hosting wizard.
Return error codes: VFW_E_NOT_FOUND (unknown dwID)
E_UNEXPECTED (unexpected error)
VFW_E_WRONG_STATE(mixer was not initialized)
\*************************************************************************
STDMETHODIMP CMultiVMR9MixerControl::DeleteVideoSource(
DWORD_PTR dwID
)
{
HRESULT hr = S_OK;
CMultiVMR9_Frame *pFrameDelete = NULL;
CMultiVMR9_Frame *pFrame = NULL;
int nCounter;
if( !m_bInitialized )
{
return VFW_E_WRONG_STATE;
}
// we do not have to check if this dwID is registered with the wizard, so
// just go through the list and delete; decrease Z-order of all preceding frames
list<CMultiVMR9_Frame*>::iterator start, end, it;
start = m_listFrames.begin();
end = m_listFrames.end();
CAutoLock Lock(&m_ObjectLock);
for( it=start; it!=end; it++)
{
pFrame = (CMultiVMR9_Frame*)(*it);
if( dwID == pFrame->m_dwID )
{
pFrameDelete = pFrame;
break;
}
}
if( !pFrameDelete ) // we did not find the frame
{
::DbgMsg("CMultiVMR9MixerControl::DeleteVideoSource: cannot find frame for source 0x%08x", dwID);
return VFW_E_NOT_FOUND;
}
m_listFrames.remove( pFrameDelete );
start = m_listFrames.begin();
end = m_listFrames.end();
nCounter = m_listFrames.size()-1;
for( it=start; it!=end; it++)
{
pFrame = (CMultiVMR9_Frame*)(*it);
pFrame->m_dwZOrder = (DWORD)nCounter;
nCounter--;
}
delete pFrameDelete;
pFrameDelete = NULL;
return S_OK;
}
****************************Public*Routine******************************\
GetOutputRect
Call this method to get output rectangle of a video source, in normalized coordinates
with respect to the view area (which size can be obtained by
IMultiVMR9RenderEngine::GetViewPortSize()).
dwID - ID of the video source assigned in IMultiVMR9Wizard::Attach(). This ID
should be already registered with hosting wizard.
lpNormRect -- receives output rect
Return error codes: VFW_E_NOT_FOUND (unknown dwID)
E_POINTER (lpNormRect is NULL)
VFW_E_WRONG_STATE(mixer was not initialized)
\*************************************************************************
STDMETHODIMP CMultiVMR9MixerControl::GetOutputRect(
DWORD_PTR dwID,
NORMALIZEDRECT* lpNormRect)
{
CMultiVMR9_Frame *pFrameRequested = NULL;
CMultiVMR9_Frame *pFrame = NULL;
if( !m_bInitialized )
{
return VFW_E_WRONG_STATE;
}
if( !lpNormRect )
{
::DbgMsg("CMultiVMR9MixerControl::GetOutputRect: received NULL pointer");
return E_POINTER;
}
list<CMultiVMR9_Frame*>::iterator start, end, it;
start = m_listFrames.begin();
end = m_listFrames.end();
for( it = start; it != end; it++)
{
pFrame = (CMultiVMR9_Frame*)(*it);
if( dwID == pFrame->m_dwID )
{
pFrameRequested = pFrame;
break;
}
}
if( !pFrameRequested )
{
::DbgMsg("CMultiVMR9MixerControl::GetOutputRect: requested video source 0x%08x was not found",
dwID);
return VFW_E_NOT_FOUND;
}
memcpy( (void*)lpNormRect, (void*)&(pFrame->m_nrDst), sizeof(NORMALIZEDRECT));
return S_OK;
}
****************************Public*Routine******************************\
SetOutputRect
Call this method to set output rectangle of a video source, in normalized coordinates
with respect to the view area (which size can be obtained by
IMultiVMR9RenderEngine::GetViewPortSize()).
dwID - ID of the video source assigned in IMultiVMR9Wizard::Attach(). This ID
should be already registered with hosting wizard.
lpNormRect -- specifies output rect
Return error codes: VFW_E_NOT_FOUND (unknown dwID)
E_POINTER (lpNormRect is NULL)
VFW_E_WRONG_STATE(mixer was not initialized)
\*************************************************************************
STDMETHODIMP CMultiVMR9MixerControl::SetOutputRect(
DWORD_PTR dwID,
NORMALIZEDRECT* lpNormRect)
{
HRESULT hr = S_OK;
CMultiVMR9_Frame *pFrameRequested = NULL;
CMultiVMR9_Frame *pFrame = NULL;
if( !m_bInitialized )
{
return VFW_E_WRONG_STATE;
}
if( !lpNormRect )
{
::DbgMsg("CMultiVMR9MixerControl::SetOutputRect: received NULL pointer");
return E_POINTER;
}
list<CMultiVMR9_Frame*>::iterator start, end, it;
start = m_listFrames.begin();
end = m_listFrames.end();
for( it = start; it != end; it++)
{
pFrame = (CMultiVMR9_Frame*)(*it);
if( dwID == pFrame->m_dwID )
{
pFrameRequested = pFrame;
break;
}
}
if( !pFrameRequested )
{
::DbgMsg("CMultiVMR9MixerControl::SetOutputRect: requested video source 0x%08x was not found",
dwID);
return VFW_E_NOT_FOUND;
}
CAutoLock Lock(&m_ObjectLock);
hr = pFrame->UpdateDestination( *lpNormRect );
if( FAILED(hr))
{
::DbgMsg("CMultiVMR9MixerControl::SetOutputRect: failed in CMultiVMR9_Frame::UpdateDestination, "\
"hr = 0x%08x", hr);
}
return hr;
}
****************************Public*Routine******************************\
GetIdealOutputRect
Call this method to obtain an ideal normalized rectangle that takes
maximum space in screen coordinates of the area (dwWidth x dwHeight)
and maintains video's aspect ratio
dwID - ID of the video source assigned in IMultiVMR9Wizard::Attach(). This ID
should be already registered with hosting wizard.
dwWidth - width, in pixels, of the area where we want to fit the frame
dwHeight - height, in pixels, of the area where we want to fit the frame
lpNormRect -- [out] specifies ideal normalized output rect
Return error codes: VFW_E_NOT_FOUND (unknown dwID)
E_POINTER (lpNormRect is NULL)
E_INVALIDARG (dwWidth = 0, dwHeight=0)
VFW_E_WRONG_STATE(mixer was not initialized)
\*************************************************************************
STDMETHODIMP CMultiVMR9MixerControl::GetIdealOutputRect(
DWORD_PTR dwID,
DWORD dwWidth,
DWORD dwHeight,
NORMALIZEDRECT* lpNormRect
)
{
HRESULT hr = S_OK;
CMultiVMR9_Frame *pFrameRequested = NULL;
CMultiVMR9_Frame *pFrame = NULL;
float ww; // width in window coord
float wh; // height in window coord
float nw; // width in normalized coord
float nh; // height in normalized coord
if( !m_bInitialized )
{
return VFW_E_WRONG_STATE;
}
if( !lpNormRect )
{
::DbgMsg("CMultiVMR9MixerControl::GetIdealOutputRect: received NULL pointer");
return E_POINTER;
}
if( 0 == dwWidth )
{
::DbgMsg("CMultiVMR9MixerControl::GetIdealOutputRect: width of the area is 0");
return E_INVALIDARG;
}
if( 0 == dwHeight )
{
::DbgMsg("CMultiVMR9MixerControl::GetIdealOutputRect: width of the area is 0");
return E_INVALIDARG;
}
list<CMultiVMR9_Frame*>::iterator start, end, it;
start = m_listFrames.begin();
end = m_listFrames.end();
for( it = start; it != end; it++)
{
pFrame = (CMultiVMR9_Frame*)(*it);
if( dwID == pFrame->m_dwID )
{
pFrameRequested = pFrame;
break;
}
}
if( !pFrameRequested )
{
::DbgMsg("CMultiVMR9MixerControl::GetIdealOutputRect: requested video source 0x%08x was not found",
dwID);
return VFW_E_NOT_FOUND;
}
if( 0.f == pFrameRequested->m_ar )
{
::DbgMsg("CMultiVMR9MixerControl::GetIdealOutputRect: FATAL, aspect ratio of the source 0x%08x is 0.0",
dwID);
return E_UNEXPECTED;
}
// try fit horizontally
ww = (float)dwWidth;
wh = ww / ( pFrameRequested->m_ar );
if( wh > (float)dwHeight ) // we do not fit vertically
{
wh = (float)dwHeight;
ww = wh * ( pFrameRequested->m_ar );
}
// now map window coordinates to normalized coordinates
nw = ww / (float)dwWidth;
nh = wh / (float)dwHeight;
// for further calculations we need half-width and half-height
nw /= 2.f;
nh /= 2.f;
lpNormRect->left = 0.5f - nw;
lpNormRect->right = 0.5f + nw;
lpNormRect->top = 0.5f - nh;
lpNormRect->bottom = 0.5f + nh;
return S_OK;
}
****************************Public*Routine******************************\
GetZOrder
Call this method to get Z-Order of a video source, in normalized coordinates
with respect to the view area (which size can be obtained by
IMultiVMR9RenderEngine::GetViewPortSize()).
dwID - ID of the video source assigned in IMultiVMR9Wizard::Attach(). This ID
should be already registered with hosting wizard.
pdwZ -- receives Z-Order
Return error codes: VFW_E_NOT_FOUND (unknown dwID)
E_POINTER (pdwZ is NULL)
VFW_E_WRONG_STATE(mixer was not initialized)
\*************************************************************************
STDMETHODIMP CMultiVMR9MixerControl::GetZOrder(DWORD_PTR dwID, DWORD *pdwZ)
{
CMultiVMR9_Frame *pFrameRequested = NULL;
CMultiVMR9_Frame *pFrame = NULL;
if( !m_bInitialized )
{
return VFW_E_WRONG_STATE;
}
if( !pdwZ )
{
::DbgMsg("CMultiVMR9MixerControl::GetZOrder: received NULL pointer");
return E_POINTER;
}
list<CMultiVMR9_Frame*>::iterator start, end, it;
start = m_listFrames.begin();
end = m_listFrames.end();
for( it = start; it != end; it++)
{
pFrame = (CMultiVMR9_Frame*)(*it);
if( dwID == pFrame->m_dwID )
{
pFrameRequested = pFrame;
break;
}
}
if( !pFrameRequested )
{
::DbgMsg("CMultiVMR9MixerControl::GetZOrder: requested video source 0x%08x was not found",
dwID);
return VFW_E_NOT_FOUND;
}
*pdwZ = pFrame->m_dwZOrder;
return S_OK;
}
****************************Public*Routine******************************\
SetZOrder
Call this method to get Z-Order of a video source, in normalized coordinates
with respect to the view area (which size can be obtained by
IMultiVMR9RenderEngine::GetViewPortSize()).
dwID - ID of the video source assigned in IMultiVMR9Wizard::Attach(). This ID
should be already registered with hosting wizard.
dwZ -- specifies Z-Order. If dwZ is bigger than the number of primitives mixer
control is processing, it is truncated to the (size_of_the_list -1)
Return error codes: VFW_E_NOT_FOUND (unknown dwID)
VFW_E_WRONG_STATE(mixer was not initialized)
\*************************************************************************
STDMETHODIMP CMultiVMR9MixerControl::SetZOrder(DWORD_PTR dwID, DWORD dwZ)
{
CMultiVMR9_Frame *pFrameRequested = NULL;
CMultiVMR9_Frame *pFrame = NULL;
CMultiVMR9_Frame *pFrameTo = NULL;
int nCounter;
if( !m_bInitialized )
{
return VFW_E_WRONG_STATE;
}
if( dwZ > m_listFrames.size() - 1)
{
dwZ = m_listFrames.size() - 1;
}
list<CMultiVMR9_Frame*>::iterator start, end, it;
start = m_listFrames.begin();
end = m_listFrames.end();
for( it = start; it != end; it++)
{
pFrame = (CMultiVMR9_Frame*)(*it);
if( dwID == pFrame->m_dwID )
{
pFrameRequested = pFrame;
}
if( pFrame->m_dwZOrder == dwZ )
{
pFrameTo = pFrame;
}
}
if( !pFrameRequested )
{
::DbgMsg("CMultiVMR9MixerControl::SetZOrder: requested video source 0x%08x was not found",
dwID);
return VFW_E_NOT_FOUND;
}
CAutoLock Lock(&m_ObjectLock);
if( dwZ == pFrameRequested->m_dwZOrder )
{
return S_FALSE;
}
// 1. remove pFrameRequested
m_listFrames.remove( pFrameRequested);
// 2. insert
start = m_listFrames.begin();
end = m_listFrames.end();
for( it = start; it != end; it++)
{
pFrame = (CMultiVMR9_Frame*)(*it);
if( pFrame == pFrameTo )
{
if( dwZ < pFrameRequested->m_dwZOrder )
{
it++;
}
if( it == end )
{
m_listFrames.push_back( pFrameRequested );
}
else
{
m_listFrames.insert( it, pFrameRequested );
}
break;
}
}
nCounter = m_listFrames.size()-1;
start = m_listFrames.begin();
end = m_listFrames.end();
for( it = start; it != end; it++)
{
pFrame = (CMultiVMR9_Frame*)(*it);
pFrame->m_dwZOrder = (DWORD)nCounter;
nCounter--;
}
return S_OK;
}
****************************Public*Routine******************************\
GetAlpha
Call this method to get alpha-level (transparency) of a video source, normalized
to the range [0.0, 1.0]
dwID - ID of the video source assigned in IMultiVMR9Wizard::Attach(). This ID
should be already registered with hosting wizard.
pAlpha -- receives alpha-level
Return error codes: VFW_E_NOT_FOUND (unknown dwID)
E_POINTER (pAlpha is NULL)
VFW_E_WRONG_STATE(mixer was not initialized)
\*************************************************************************
STDMETHODIMP CMultiVMR9MixerControl::GetAlpha(DWORD_PTR dwID, float* pAlpha)
{
CMultiVMR9_Frame *pFrameRequested = NULL;
CMultiVMR9_Frame *pFrame = NULL;
if( !m_bInitialized )
{
return VFW_E_WRONG_STATE;
}
if( !pAlpha )
{
::DbgMsg("CMultiVMR9MixerControl::GetAlpha: received NULL pointer");
return E_POINTER;
}
list<CMultiVMR9_Frame*>::iterator start, end, it;
start = m_listFrames.begin();
end = m_listFrames.end();
for( it = start; it != end; it++)
{
pFrame = (CMultiVMR9_Frame*)(*it);
if( dwID == pFrame->m_dwID )
{
pFrameRequested = pFrame;
break;
}
}
if( !pFrameRequested )
{
::DbgMsg("CMultiVMR9MixerControl::GetAlpha: requested video source 0x%08x was not found",
dwID);
return VFW_E_NOT_FOUND;
}
*pAlpha = pFrame->m_alpha;
return S_OK;
}
****************************Public*Routine******************************\
SetAlpha
Call this method to set alpha-level (transparency) of a video source, normalized
to the range [0.0, 1.0]
dwID - ID of the video source assigned in IMultiVMR9Wizard::Attach(). This ID
should be already registered with hosting wizard.
Alpha -- specifies alpha-level. Value is always truncated to [0.0, 1.0] range
Return error codes: VFW_E_NOT_FOUND (unknown dwID)
VFW_E_WRONG_STATE(mixer was not initialized)
\*************************************************************************
STDMETHODIMP CMultiVMR9MixerControl::SetAlpha(DWORD_PTR dwID, float Alpha)
{
CMultiVMR9_Frame *pFrameRequested = NULL;
CMultiVMR9_Frame *pFrame = NULL;
if( !m_bInitialized )
{
return VFW_E_WRONG_STATE;
}
Alpha = (Alpha < 0.f ) ? 0.f : Alpha;
Alpha = (Alpha > 1.f ) ? 1.f : Alpha;
list<CMultiVMR9_Frame*>::iterator start, end, it;
start = m_listFrames.begin();
end = m_listFrames.end();
for( it = start; it != end; it++)
{
pFrame = (CMultiVMR9_Frame*)(*it);
if( dwID == pFrame->m_dwID )
{
pFrameRequested = pFrame;
break;
}
}
if( !pFrameRequested )
{
::DbgMsg("CMultiVMR9MixerControl::SetAlpha: requested video source 0x%08x was not found",
dwID);
return VFW_E_NOT_FOUND;
}
CAutoLock Lock(&m_ObjectLock);
pFrame->m_alpha = Alpha;
BYTE byteAlpha = (BYTE)(255.f * pFrame->m_alpha);
for( int i=0; i<4; i++)
{
pFrame->m_coord[i].color = D3DCOLOR_RGBA( 0xFF, 0xFF, 0xFF, byteAlpha);
}
return S_OK;
}
****************************Public*Routine******************************\
GetBackgroundColor
Call this method to get background color (as RGB value)
pColor -- receives background color
Return error codes: E_POINTER (pColor is NULL)
\*************************************************************************
STDMETHODIMP CMultiVMR9MixerControl::GetBackgroundColor(COLORREF* pColor)
{
if( !pColor )
{
::DbgMsg("CMultiVMR9MixerControl::GetBackgroundColor: received NULL pointer");
return E_POINTER;
}
*pColor = m_BackgroundColor;
return S_OK;
}
****************************Public*Routine******************************\
SetBackgroundColor
Call this method to set background color (as RGB value)
Color -- specifies background color
Return error codes: none
\*************************************************************************
STDMETHODIMP CMultiVMR9MixerControl::SetBackgroundColor(COLORREF Color)
{
CAutoLock Lock(&m_ObjectLock);
m_BackgroundColor = Color;
return S_OK;
}
///////////////// Private routine /////////////////////////////////
****************************Private*Routine*****************************\
Clean_
cleans data, releases interfaces
Return error codes: none
\*************************************************************************
void CMultiVMR9MixerControl::Clean_()
{
CMultiVMR9_Frame* pFrame = NULL;
// go clean the list
list<CMultiVMR9_Frame*>::iterator start, end, it;
start = m_listFrames.begin();
end = m_listFrames.end();
for( it = start; it!= end; it++)
{
pFrame = (CMultiVMR9_Frame*)(*it);
delete pFrame;
pFrame = NULL;
}
m_listFrames.clear();
RELEASE( m_pOwner );
}
****************************Private*Routine*****************************\
CMultiVMR9_Frame
constructor
\*************************************************************************
CMultiVMR9MixerControl::CMultiVMR9_Frame::CMultiVMR9_Frame()
: m_dwID( 0L )
, m_WidthAR( 0.f )
, m_HeightAR( 0.f )
, m_lImageWidth( 0L )
, m_lImageHeight( 0L )
, m_ar( 0.f )
, m_alpha( 1.f )
, m_dwZOrder( 0L )
{
ZeroMemory( m_coord, sizeof( m_coord[0]));
ZeroMemory( &m_nrDst, sizeof(NORMALIZEDRECT));
}
****************************Private*Routine*****************************\
~CMultiVMR9_Frame
destructor
\*************************************************************************
CMultiVMR9MixerControl::CMultiVMR9_Frame::~CMultiVMR9_Frame()
{
}
****************************Private*Routine*****************************\
CMultiVMR9_Frame::Initialize
\*************************************************************************
HRESULT CMultiVMR9MixerControl::CMultiVMR9_Frame::Initialize(
DWORD_PTR dwUserID,
LONG lWidth,
LONG lHeight,
LONG lTextureWidth,
LONG lTextureHeight,
LONG lRenderTargetWidth,
LONG lRenderTargetHeight,
float fAlpha)
{
HRESULT hr = S_OK;
NORMALIZEDRECT nrIdeal;
BYTE byteAlpha;
float rtw; // ideal width, in RenderTarget pixel coords
float rth; // ideal height, in RenderTarget pixel coords
float nw; // ideal width, in normalized coords
float nh; // ideal height, in normalized coords
m_dwID = dwUserID;
// truncate alpha
m_alpha = (fAlpha<0.f) ? 0.f : fAlpha;
m_alpha = (fAlpha>1.f) ? 1.f : fAlpha;
byteAlpha = (BYTE)(255.f * m_alpha);
// make sure sizes are positive
m_lImageWidth = (lWidth > 0) ? lWidth : -lWidth;
m_lImageHeight = (lHeight > 0) ? lHeight : -lHeight;
// calculate aspect ratio
if( 0 == m_lImageHeight )
{
::DbgMsg("CMultiVMR9_Frame::Initialize: FATAL, received image height = 0");
return E_UNEXPECTED;
}
if( 0 == m_lImageWidth )
{
::DbgMsg("CMultiVMR9_Frame::Initialize: FATAL, received image width = 0");
return E_UNEXPECTED;
}
if( 0 == lRenderTargetWidth)
{
::DbgMsg("CMultiVMR9_Frame::Initialize: FATAL, received render target width = 0");
return E_UNEXPECTED;
}
if( 0 == lRenderTargetHeight)
{
::DbgMsg("CMultiVMR9_Frame::Initialize: FATAL, received render target height = 0");
return E_UNEXPECTED;
}
if( 0 == lTextureWidth )
{
::DbgMsg("CMultiVMR9_Frame::Initialize: FATAL, received texture width = 0");
return E_UNEXPECTED;
}
if( 0 == lTextureHeight )
{
::DbgMsg("CMultiVMR9_Frame::Initialize: FATAL, received texture height = 0");
return E_UNEXPECTED;
}
m_ar = (float)m_lImageWidth / (float)m_lImageHeight;
// calculate ideal rect
// try to fit horiz.
rtw = (float)lRenderTargetWidth;
rth = rtw / m_ar;
if( rth > (float)lRenderTargetHeight )
{
// fit vert.
rth = (float)lRenderTargetHeight;
rtw = rth * m_ar;
}
// convert Render Target coords to normalized
nw = rtw / (float)lRenderTargetWidth;
nh = rth / (float)lRenderTargetHeight;
// for convinience, take half-width andf half-height
nw /= 2.f;
nh /= 2.f;
// calculate nrect - destination
nrIdeal.left = 0.5f - nw;
nrIdeal.right = 0.5f + nw;
nrIdeal.top = 0.5f - nh;
nrIdeal.bottom = 0.5f + nh;
m_WidthAR = (float)lWidth / (float)lTextureWidth;
m_HeightAR = (float)lHeight / (float)lTextureHeight;
// set texture source coords
m_coord[0].tu = 0.f; m_coord[0].tv = 0.f;
m_coord[1].tu = 1.f; m_coord[1].tv = 0.f;
m_coord[2].tu = 0.f; m_coord[2].tv = 1.f;
m_coord[3].tu = 1.f; m_coord[3].tv = 1.f;
// set diffuse color = white on all vertices
m_coord[0].color = D3DCOLOR_RGBA( 0xFF, 0xFF, 0xFF, byteAlpha);
m_coord[1].color = D3DCOLOR_RGBA( 0xFF, 0xFF, 0xFF, byteAlpha);
m_coord[2].color = D3DCOLOR_RGBA( 0xFF, 0xFF, 0xFF, byteAlpha);
m_coord[3].color = D3DCOLOR_RGBA( 0xFF, 0xFF, 0xFF, byteAlpha);
hr = UpdateDestination( nrIdeal );
return hr;
}
****************************Private*Routine*****************************\
CMultiVMR9_Frame::Reload
\*************************************************************************
HRESULT CMultiVMR9MixerControl::CMultiVMR9_Frame::Reload(
DWORD_PTR dwUserID,
LONG lWidth,
LONG lHeight,
LONG lTextureWidth,
LONG lTextureHeight,
LONG lRenderTargetWidth,
LONG lRenderTargetHeight )
{
HRESULT hr = S_OK;
BYTE byteAlpha = (BYTE)(255.f * m_alpha);
if( m_dwID != dwUserID )
return E_INVALIDARG;
// make sure sizes are positive
m_lImageWidth = (lWidth > 0) ? lWidth : -lWidth;
m_lImageHeight = (lHeight > 0) ? lHeight : -lHeight;
// calculate aspect ratio
if( 0 == m_lImageHeight )
{
::DbgMsg("CMultiVMR9_Frame::Reload: FATAL, received image height = 0");
return E_UNEXPECTED;
}
if( 0 == m_lImageWidth )
{
::DbgMsg("CMultiVMR9_Frame::Reload: FATAL, received image width = 0");
return E_UNEXPECTED;
}
if( 0 == lRenderTargetWidth)
{
::DbgMsg("CMultiVMR9_Frame::Reload: FATAL, received render target width = 0");
return E_UNEXPECTED;
}
if( 0 == lRenderTargetHeight)
{
::DbgMsg("CMultiVMR9_Frame::Reload: FATAL, received render target height = 0");
return E_UNEXPECTED;
}
if( 0 == lTextureWidth )
{
::DbgMsg("CMultiVMR9_Frame::Reload: FATAL, received texture width = 0");
return E_UNEXPECTED;
}
if( 0 == lTextureHeight )
{
::DbgMsg("CMultiVMR9_Frame::Reload: FATAL, received texture height = 0");
return E_UNEXPECTED;
}
m_ar = (float)m_lImageWidth / (float)m_lImageHeight;
m_WidthAR = (float)lWidth / (float)lTextureWidth;
m_HeightAR = (float)lHeight / (float)lTextureHeight;
hr = UpdateDestination( m_nrDst );
return hr;
}
****************************Private*Routine*****************************\
UpdateDestination
Updates destination normrect and (x,y) coordinates.
\*************************************************************************
HRESULT CMultiVMR9MixerControl::CMultiVMR9_Frame::UpdateDestination(
NORMALIZEDRECT& newnrect)
{
HRESULT hr = S_OK;
// coordinates in composition space [-1,1]x[1,-1]
float cl; // left
float ct; // top
float cr; // right
float cb; // bottom
memcpy( (void*)(&m_nrDst), (const void*)(&newnrect), sizeof(NORMALIZEDRECT));
// update composition space coordinates
// comp_space_x = 2. * norm_space_x - 1.;
// comp_space_x = 1. - 2. * norm_space_y;
cl = 2.f * m_nrDst.left - 1.f;
cr = 2.f * m_nrDst.right - 1.f;
ct = 1.f - 2.f * m_nrDst.top;
cb = 1.f - 2.f * m_nrDst.bottom;
m_coord[0].position.x = cl;
m_coord[0].position.y = ct;
m_coord[0].position.z = 0.5f;
m_coord[1].position.x = cr;
m_coord[1].position.y = ct;
m_coord[1].position.z = 0.5f;
m_coord[2].position.x = cl;
m_coord[2].position.y = cb;
m_coord[2].position.z = 0.5f;
m_coord[3].position.x = cr;
m_coord[3].position.y = cb;
m_coord[3].position.z = 0.5f;
return S_OK;
}
(C) Æliens
20/2/2008
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.