523 lines
11 KiB
C++
523 lines
11 KiB
C++
|
// File: ichnlvid.cpp
|
|||
|
|
|||
|
#include "precomp.h"
|
|||
|
#include "ichnlvid.h"
|
|||
|
|
|||
|
typedef struct
|
|||
|
{
|
|||
|
DWORD *pdwCapDevIDs;
|
|||
|
LPTSTR pszCapDevNames;
|
|||
|
DWORD dwNumCapDev;
|
|||
|
} ENUM_CAP_DEV;
|
|||
|
|
|||
|
static HRESULT OnNotifyStateChanged(IUnknown *pChannelNotify, PVOID pv, REFIID riid);
|
|||
|
static HRESULT OnNotifyPropertyChanged(IUnknown *pChannelNotify, PVOID pv, REFIID riid);
|
|||
|
|
|||
|
static const IID * g_apiidCP[] =
|
|||
|
{
|
|||
|
{&IID_INmChannelNotify},
|
|||
|
{&IID_INmChannelVideoNotify}
|
|||
|
};
|
|||
|
|
|||
|
CNmChannelVideo * CNmChannelVideo::m_pPreviewChannel = NULL;
|
|||
|
|
|||
|
|
|||
|
CNmChannelVideo::CNmChannelVideo(BOOL fIncoming) :
|
|||
|
CConnectionPointContainer(g_apiidCP, ARRAY_ELEMENTS(g_apiidCP)),
|
|||
|
m_VideoPump(!fIncoming /* fLocal */),
|
|||
|
m_cMembers (0),
|
|||
|
m_fIncoming(fIncoming),
|
|||
|
m_pMediaChannel(NULL),
|
|||
|
m_pCommChannel(NULL),
|
|||
|
m_MediaFormat(INVALID_MEDIA_FORMAT)
|
|||
|
{
|
|||
|
if (NULL != g_pH323UI)
|
|||
|
{
|
|||
|
IH323CallControl * pH323CallControl = g_pH323UI->GetH323CallControl();
|
|||
|
IMediaChannelBuilder * pMCProvider = g_pH323UI->GetStreamProvider();
|
|||
|
IVideoDevice *pVideoDevice=NULL;
|
|||
|
ASSERT((NULL != pH323CallControl) && (NULL != pMCProvider));
|
|||
|
pMCProvider->CreateMediaChannel(MCF_VIDEO | (fIncoming ? MCF_RECV : MCF_SEND), &m_pMediaChannel);
|
|||
|
if (m_pMediaChannel)
|
|||
|
{
|
|||
|
pMCProvider->QueryInterface(IID_IVideoDevice, (void**)&pVideoDevice);
|
|||
|
m_VideoPump.Initialize(pH323CallControl, m_pMediaChannel, pVideoDevice, (DWORD_PTR)this, FrameReadyCallback);
|
|||
|
pVideoDevice->Release();
|
|||
|
}
|
|||
|
pMCProvider->Release();
|
|||
|
}
|
|||
|
|
|||
|
DbgMsg(iZONE_OBJECTS, "Obj: %08X created CNmChannelVideo", this);
|
|||
|
}
|
|||
|
|
|||
|
CNmChannelVideo::~CNmChannelVideo()
|
|||
|
{
|
|||
|
if (!m_fIncoming)
|
|||
|
{
|
|||
|
// make sure we're no longer capturing
|
|||
|
m_VideoPump.EnableXfer(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
if (this == m_pPreviewChannel)
|
|||
|
{
|
|||
|
m_pPreviewChannel = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (NULL != m_pCommChannel)
|
|||
|
{
|
|||
|
m_pCommChannel->Release();
|
|||
|
}
|
|||
|
if (NULL != m_pMediaChannel)
|
|||
|
{
|
|||
|
m_pMediaChannel->Release();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DbgMsg(iZONE_OBJECTS, "Obj: %08X destroyed CNmChannelVideo", this);
|
|||
|
}
|
|||
|
|
|||
|
VOID CNmChannelVideo::CommChannelOpened(ICommChannel *pCommChannel)
|
|||
|
{
|
|||
|
ASSERT(NULL == m_pCommChannel);
|
|||
|
m_pCommChannel = pCommChannel;
|
|||
|
m_pCommChannel->AddRef();
|
|||
|
}
|
|||
|
|
|||
|
VOID CNmChannelVideo::CommChannelActive(ICommChannel *pCommChannel)
|
|||
|
{
|
|||
|
ASSERT(m_pCommChannel == pCommChannel);
|
|||
|
m_VideoPump.OnChannelOpened(pCommChannel);
|
|||
|
OnStateChange();
|
|||
|
}
|
|||
|
|
|||
|
VOID CNmChannelVideo::CommChannelClosed()
|
|||
|
{
|
|||
|
if (NULL != m_pCommChannel)
|
|||
|
{
|
|||
|
m_pCommChannel->Release();
|
|||
|
m_pCommChannel = NULL;
|
|||
|
|
|||
|
m_VideoPump.OnChannelClosed();
|
|||
|
OnStateChange();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
CNmChannelVideo * CNmChannelVideo::CreateChannel(BOOL fIncoming)
|
|||
|
{
|
|||
|
if (fIncoming)
|
|||
|
{
|
|||
|
return new CNmChannelVideo(TRUE /* fIncoming */);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (NULL != m_pPreviewChannel)
|
|||
|
{
|
|||
|
m_pPreviewChannel->AddRef();
|
|||
|
}
|
|||
|
return m_pPreviewChannel;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
CNmChannelVideo * CNmChannelVideo::CreatePreviewChannel()
|
|||
|
{
|
|||
|
ASSERT(NULL == m_pPreviewChannel);
|
|||
|
m_pPreviewChannel = new CNmChannelVideo(FALSE /* fIncoming */);
|
|||
|
if (NULL != m_pPreviewChannel)
|
|||
|
{
|
|||
|
if (!m_pPreviewChannel->IsCaptureAvailable())
|
|||
|
{
|
|||
|
delete m_pPreviewChannel;
|
|||
|
m_pPreviewChannel = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
return m_pPreviewChannel;
|
|||
|
}
|
|||
|
|
|||
|
VOID CNmChannelVideo::OnMemberAdded(CNmMember *pMember)
|
|||
|
{
|
|||
|
// Don't add to the channel if we already belong.
|
|||
|
if (0 != (pMember->GetNmchCaps() & NMCH_VIDEO))
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
++m_cMembers;
|
|||
|
|
|||
|
pMember->AddNmchCaps(NMCH_VIDEO);
|
|||
|
|
|||
|
CConfObject *pco = ::GetConfObject();
|
|||
|
pco->OnMemberUpdated(pMember);
|
|||
|
|
|||
|
NotifySink((INmMember *) pMember, OnNotifyChannelMemberAdded);
|
|||
|
}
|
|||
|
|
|||
|
VOID CNmChannelVideo::OnMemberRemoved(CNmMember *pMember)
|
|||
|
{
|
|||
|
// If member does not belong to this channel, don't remove it.
|
|||
|
if (0 == (pMember->GetNmchCaps() & NMCH_VIDEO))
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
--m_cMembers;
|
|||
|
|
|||
|
pMember->RemoveNmchCaps(NMCH_VIDEO);
|
|||
|
|
|||
|
CConfObject *pco = ::GetConfObject();
|
|||
|
pco->OnMemberUpdated(pMember);
|
|||
|
|
|||
|
NotifySink((INmMember *) pMember, OnNotifyChannelMemberRemoved);
|
|||
|
}
|
|||
|
|
|||
|
VOID CNmChannelVideo::OnMemberUpdated(CNmMember *pMember)
|
|||
|
{
|
|||
|
NotifySink((INmMember *) pMember, OnNotifyChannelMemberUpdated);
|
|||
|
}
|
|||
|
|
|||
|
VOID CNmChannelVideo::OnStateChange()
|
|||
|
{
|
|||
|
NM_VIDEO_STATE state;
|
|||
|
GetState(&state);
|
|||
|
NotifySink((PVOID) state, OnNotifyStateChanged);
|
|||
|
}
|
|||
|
|
|||
|
VOID CNmChannelVideo::OnFrameAvailable()
|
|||
|
{
|
|||
|
NotifySink((PVOID) NM_VIDPROP_FRAME, OnNotifyPropertyChanged);
|
|||
|
}
|
|||
|
|
|||
|
VOID CNmChannelVideo::Open()
|
|||
|
{
|
|||
|
ASSERT(m_MediaFormat != INVALID_MEDIA_FORMAT);
|
|||
|
m_VideoPump.Open(m_MediaFormat);
|
|||
|
}
|
|||
|
|
|||
|
VOID CNmChannelVideo::Close()
|
|||
|
{
|
|||
|
m_VideoPump.Close();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
STDMETHODIMP_(ULONG) CNmChannelVideo::AddRef(void)
|
|||
|
{
|
|||
|
return RefCount::AddRef();
|
|||
|
}
|
|||
|
|
|||
|
STDMETHODIMP_(ULONG) CNmChannelVideo::Release(void)
|
|||
|
{
|
|||
|
return RefCount::Release();
|
|||
|
}
|
|||
|
|
|||
|
STDMETHODIMP CNmChannelVideo::QueryInterface(REFIID riid, PVOID *ppv)
|
|||
|
{
|
|||
|
HRESULT hr = S_OK;
|
|||
|
|
|||
|
if ((riid == IID_INmChannelVideo) || (riid == IID_INmChannel) || (riid == IID_IUnknown))
|
|||
|
{
|
|||
|
*ppv = (INmChannel *)this;
|
|||
|
DbgMsgApi("CNmChannelVideo::QueryInterface()");
|
|||
|
}
|
|||
|
else if (riid == IID_IConnectionPointContainer)
|
|||
|
{
|
|||
|
*ppv = (IConnectionPointContainer *) this;
|
|||
|
DbgMsgApi("CNmChannelVideo::QueryInterface(): Returning IConnectionPointContainer.");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
hr = E_NOINTERFACE;
|
|||
|
*ppv = NULL;
|
|||
|
DbgMsgApi("CNmChannelVideo::QueryInterface(): Called on unknown interface.");
|
|||
|
}
|
|||
|
|
|||
|
if (S_OK == hr)
|
|||
|
{
|
|||
|
AddRef();
|
|||
|
}
|
|||
|
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
STDMETHODIMP CNmChannelVideo::IsSameAs(INmChannel *pChannel)
|
|||
|
{
|
|||
|
return (((INmChannel *) this) == pChannel) ? S_OK : S_FALSE;
|
|||
|
}
|
|||
|
|
|||
|
STDMETHODIMP CNmChannelVideo::IsActive()
|
|||
|
{
|
|||
|
return (NULL != m_pCommChannel) ? S_OK : S_FALSE;
|
|||
|
}
|
|||
|
|
|||
|
STDMETHODIMP CNmChannelVideo::SetActive(BOOL fActive)
|
|||
|
{
|
|||
|
return E_FAIL;
|
|||
|
}
|
|||
|
|
|||
|
STDMETHODIMP CNmChannelVideo::GetConference(INmConference **ppConference)
|
|||
|
{
|
|||
|
return ::GetConference(ppConference);
|
|||
|
}
|
|||
|
|
|||
|
STDMETHODIMP CNmChannelVideo::GetInterface(IID *piid)
|
|||
|
{
|
|||
|
HRESULT hr = E_POINTER;
|
|||
|
|
|||
|
if (NULL != piid)
|
|||
|
{
|
|||
|
*piid = IID_INmChannelVideo;
|
|||
|
hr = S_OK;
|
|||
|
}
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
STDMETHODIMP CNmChannelVideo::GetNmch(ULONG *puCh)
|
|||
|
{
|
|||
|
HRESULT hr = E_POINTER;
|
|||
|
|
|||
|
if (NULL != puCh)
|
|||
|
{
|
|||
|
*puCh = NMCH_VIDEO;
|
|||
|
hr = S_OK;
|
|||
|
}
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
STDMETHODIMP CNmChannelVideo::EnumMember(IEnumNmMember **ppEnum)
|
|||
|
{
|
|||
|
HRESULT hr = E_POINTER;
|
|||
|
if (NULL != ppEnum)
|
|||
|
{
|
|||
|
int cMembers = 0;
|
|||
|
COBLIST MemberList;
|
|||
|
COBLIST* pPartList = ::GetMemberList();
|
|||
|
if (NULL != pPartList)
|
|||
|
{
|
|||
|
POSITION pos = pPartList->GetHeadPosition();
|
|||
|
while (pos)
|
|||
|
{
|
|||
|
CNmMember * pMember = (CNmMember *) pPartList->GetNext(pos);
|
|||
|
ASSERT(NULL != pMember);
|
|||
|
|
|||
|
if (NMCH_AUDIO & pMember->GetNmchCaps())
|
|||
|
{
|
|||
|
MemberList.AddTail(pMember);
|
|||
|
pMember->AddRef();
|
|||
|
cMembers++;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
*ppEnum = new CEnumNmMember(&MemberList, cMembers);
|
|||
|
|
|||
|
while (!MemberList.IsEmpty())
|
|||
|
{
|
|||
|
INmMember *pMember = (INmMember *) (CNmMember *) MemberList.RemoveHead();
|
|||
|
pMember->Release();
|
|||
|
}
|
|||
|
hr = (NULL != *ppEnum)? S_OK : E_OUTOFMEMORY;
|
|||
|
}
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
STDMETHODIMP CNmChannelVideo::GetMemberCount(ULONG * puCount)
|
|||
|
{
|
|||
|
HRESULT hr = E_POINTER;
|
|||
|
if (NULL != puCount)
|
|||
|
{
|
|||
|
*puCount = m_cMembers;
|
|||
|
hr = S_OK;
|
|||
|
}
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
STDMETHODIMP CNmChannelVideo::IsIncoming(void)
|
|||
|
{
|
|||
|
return m_fIncoming ? S_OK : S_FALSE;
|
|||
|
}
|
|||
|
|
|||
|
STDMETHODIMP CNmChannelVideo::GetState(NM_VIDEO_STATE *puState)
|
|||
|
{
|
|||
|
HRESULT hr = E_POINTER;
|
|||
|
if (NULL != puState)
|
|||
|
{
|
|||
|
*puState = m_VideoPump.GetState();
|
|||
|
hr = S_OK;
|
|||
|
}
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
STDMETHODIMP CNmChannelVideo::GetProperty(NM_VIDPROP uID, ULONG_PTR *puValue)
|
|||
|
{
|
|||
|
HRESULT hr = S_OK;
|
|||
|
|
|||
|
switch (uID)
|
|||
|
{
|
|||
|
case NM_VIDPROP_PAUSE:
|
|||
|
*puValue = m_VideoPump.IsPaused();
|
|||
|
break;
|
|||
|
case NM_VIDPROP_IMAGE_PREFERRED_SIZE:
|
|||
|
*puValue = m_VideoPump.GetFrameSize();
|
|||
|
break;
|
|||
|
case NM_VIDPROP_IMAGE_QUALITY:
|
|||
|
if (m_fIncoming)
|
|||
|
{
|
|||
|
*puValue = m_VideoPump.GetReceiveQuality();
|
|||
|
}
|
|||
|
break;
|
|||
|
case NM_VIDPROP_CAMERA_DIALOG:
|
|||
|
*puValue = 0;
|
|||
|
if (m_VideoPump.HasSourceDialog())
|
|||
|
{
|
|||
|
*puValue |= NM_VIDEO_SOURCE_DIALOG;
|
|||
|
}
|
|||
|
if (m_VideoPump.HasFormatDialog())
|
|||
|
{
|
|||
|
*puValue |= NM_VIDEO_FORMAT_DIALOG;
|
|||
|
}
|
|||
|
break;
|
|||
|
case NM_VIDPROP_IMAGE_SIZES:
|
|||
|
// get all the sizes, not just a size for one video format
|
|||
|
*puValue = m_VideoPump.GetFrameSizes(INVALID_MEDIA_FORMAT);
|
|||
|
break;
|
|||
|
case NM_VIDPROP_FRAME:
|
|||
|
{
|
|||
|
FRAMECONTEXT *pfc = (FRAMECONTEXT*) puValue;
|
|||
|
hr = m_VideoPump.GetFrame(pfc);
|
|||
|
break;
|
|||
|
}
|
|||
|
case NM_VIDPROP_NUM_CAPTURE_DEVS:
|
|||
|
*puValue = m_VideoPump.GetNumCapDev();
|
|||
|
break;
|
|||
|
case NM_VIDPROP_CAPTURE_DEV_ID:
|
|||
|
*puValue = m_VideoPump.GetCurrCapDevID();
|
|||
|
break;
|
|||
|
case NM_VIDPROP_MAX_CAPTURE_NAME:
|
|||
|
*puValue = m_VideoPump.GetMaxCapDevNameLen();
|
|||
|
break;
|
|||
|
case NM_VIDPROP_CAPTURE_LIST:
|
|||
|
{
|
|||
|
ENUM_CAP_DEV *pEnumCapDev = (ENUM_CAP_DEV *)puValue;
|
|||
|
|
|||
|
if(m_VideoPump.EnumCapDev(pEnumCapDev->pdwCapDevIDs,
|
|||
|
pEnumCapDev->pszCapDevNames,
|
|||
|
pEnumCapDev->dwNumCapDev))
|
|||
|
{
|
|||
|
hr = E_FAIL;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
default:
|
|||
|
hr = E_INVALIDARG;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
STDMETHODIMP CNmChannelVideo::SetProperty(NM_VIDPROP uID, ULONG_PTR uValue)
|
|||
|
{
|
|||
|
HRESULT hr = S_OK;
|
|||
|
|
|||
|
switch (uID)
|
|||
|
{
|
|||
|
case NM_VIDPROP_PAUSE:
|
|||
|
m_VideoPump.Pause(uValue);
|
|||
|
OnStateChange();
|
|||
|
break;
|
|||
|
case NM_VIDPROP_IMAGE_PREFERRED_SIZE:
|
|||
|
switch(uValue)
|
|||
|
{
|
|||
|
case NM_VIDEO_SMALL:
|
|||
|
case NM_VIDEO_MEDIUM:
|
|||
|
case NM_VIDEO_LARGE:
|
|||
|
m_VideoPump.SetFrameSize(uValue);
|
|||
|
break;
|
|||
|
default:
|
|||
|
hr = E_INVALIDARG;
|
|||
|
break;
|
|||
|
}
|
|||
|
break;
|
|||
|
case NM_VIDPROP_IMAGE_QUALITY:
|
|||
|
if /* ((uValue >= NM_VIDEO_MIN_QUALITY) || Always True */ ((uValue <= NM_VIDEO_MAX_QUALITY))
|
|||
|
{
|
|||
|
if (m_fIncoming)
|
|||
|
{
|
|||
|
m_VideoPump.SetReceiveQuality(uValue);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
hr = E_INVALIDARG;
|
|||
|
}
|
|||
|
break;
|
|||
|
case NM_VIDPROP_CAMERA_DIALOG:
|
|||
|
switch(uValue)
|
|||
|
{
|
|||
|
case NM_VIDEO_SOURCE_DIALOG:
|
|||
|
m_VideoPump.ShowSourceDialog();
|
|||
|
break;
|
|||
|
case NM_VIDEO_FORMAT_DIALOG:
|
|||
|
m_VideoPump.ShowFormatDialog();
|
|||
|
break;
|
|||
|
default:
|
|||
|
hr = E_INVALIDARG;
|
|||
|
break;
|
|||
|
}
|
|||
|
break;
|
|||
|
case NM_VIDPROP_SUSPEND_CAPTURE:
|
|||
|
m_VideoPump.SuspendCapture(uValue);
|
|||
|
break;
|
|||
|
case NM_VIDPROP_FRAME:
|
|||
|
hr = m_VideoPump.ReleaseFrame((FRAMECONTEXT *)uValue);
|
|||
|
break;
|
|||
|
case NM_VIDPROP_CAPTURE_DEV_ID:
|
|||
|
m_VideoPump.SetCurrCapDevID(uValue);
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
hr = E_INVALIDARG;
|
|||
|
break;
|
|||
|
}
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
VOID __stdcall CNmChannelVideo::FrameReadyCallback(DWORD_PTR dwMyThis)
|
|||
|
{
|
|||
|
CNmChannelVideo *pChannel = (CNmChannelVideo *)dwMyThis;
|
|||
|
if (NULL != pChannel)
|
|||
|
{
|
|||
|
pChannel->OnFrameAvailable();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* O N N O T I F Y S T A T E C H A N G E D */
|
|||
|
/*-------------------------------------------------------------------------
|
|||
|
%%Function: OnNotifyStateChanged
|
|||
|
|
|||
|
-------------------------------------------------------------------------*/
|
|||
|
HRESULT OnNotifyStateChanged(IUnknown *pChannelNotify, PVOID pv, REFIID riid)
|
|||
|
{
|
|||
|
ASSERT(NULL != pChannelNotify);
|
|||
|
if (IID_INmChannelVideoNotify == riid)
|
|||
|
{
|
|||
|
((INmChannelVideoNotify*)pChannelNotify)->StateChanged((NM_VIDEO_STATE) (DWORD)((DWORD_PTR)pv));
|
|||
|
}
|
|||
|
return S_OK;
|
|||
|
}
|
|||
|
|
|||
|
/* O N N O T I F Y P R O P E R T Y C H A N G E D */
|
|||
|
/*-------------------------------------------------------------------------
|
|||
|
%%Function: OnNotifyPropertyChanged
|
|||
|
|
|||
|
-------------------------------------------------------------------------*/
|
|||
|
HRESULT OnNotifyPropertyChanged(IUnknown *pChannelNotify, PVOID pv, REFIID riid)
|
|||
|
{
|
|||
|
ASSERT(NULL != pChannelNotify);
|
|||
|
if (IID_INmChannelVideoNotify == riid)
|
|||
|
{
|
|||
|
((INmChannelVideoNotify*)pChannelNotify)->PropertyChanged((DWORD)((DWORD_PTR)pv));
|
|||
|
}
|
|||
|
return S_OK;
|
|||
|
}
|
|||
|
|