mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1629 lines
33 KiB
1629 lines
33 KiB
// File: videview.cpp
|
|
|
|
#include "precomp.h"
|
|
|
|
#include "vidview.h"
|
|
#include "resource.h"
|
|
#include "confman.h"
|
|
#include "rtoolbar.h"
|
|
#include "pfndrawd.h"
|
|
#include "NmManager.h"
|
|
#include "cmd.h"
|
|
|
|
#define DibHdrSize(lpbi) ((lpbi)->biSize + (int)(lpbi)->biClrUsed * sizeof(RGBQUAD))
|
|
#define DibDataSize(lpbi) ((lpbi)->biSizeImage)
|
|
#define DibSize(lpbi) (DibHdrSize(lpbi) + DibDataSize(lpbi))
|
|
|
|
typedef struct
|
|
{
|
|
DWORD *pdwCapDevIDs;
|
|
LPTSTR pszCapDevNames;
|
|
DWORD dwNumCapDev;
|
|
} ENUM_CAP_DEV;
|
|
|
|
CSimpleArray<CVideoWindow *> *CVideoWindow::g_pVideos;
|
|
BOOL CVideoWindow::g_fMirror = FALSE;
|
|
BOOL CVideoWindow::g_bLocalOneTimeInited = FALSE;
|
|
|
|
static const TCHAR REGVAL_VIDEO_QUALITY[] = TEXT("ImageQuality");
|
|
|
|
static const UINT VIDEO_ZOOM_MIN = 50;
|
|
static const UINT VIDEO_ZOOM_MAX = 400;
|
|
|
|
static const UINT QCIF_WIDTH = 176;
|
|
static const UINT QCIF_HEIGHT = 144;
|
|
|
|
CVideoWindow::CVideoWindow(VideoType eType, BOOL bEmbedded) :
|
|
m_dwFrameSize(NM_VIDEO_MEDIUM),
|
|
m_hdd(NULL),
|
|
#ifdef DISPLAYFPS
|
|
m_cFrame (0),
|
|
m_dwTick (GetTickCount()),
|
|
#endif // DISPLAYFPS
|
|
m_pActiveChannel(NULL),
|
|
m_dwCookie(0),
|
|
m_dwImageQuality(NM_VIDEO_MIN_QUALITY),
|
|
m_pNotify(NULL),
|
|
m_fLocal(REMOTE!=eType),
|
|
m_hBitmapMirror(NULL),
|
|
m_hDCMirror(NULL),
|
|
m_fZoomable(TRUE),
|
|
m_bEmbedded(bEmbedded),
|
|
m_hGDIObj(NULL)
|
|
{
|
|
if (NULL == g_pVideos)
|
|
{
|
|
g_pVideos = new CSimpleArray<CVideoWindow*>;
|
|
}
|
|
if (NULL != g_pVideos)
|
|
{
|
|
CVideoWindow* p = static_cast<CVideoWindow*>(this);
|
|
g_pVideos->Add(p);
|
|
}
|
|
|
|
m_sizeVideo.cx = 0;
|
|
m_sizeVideo.cy = 0;
|
|
|
|
RegEntry reAudio(AUDIO_KEY); // HKCU
|
|
RegEntry reVideo( IsLocal() ? VIDEO_LOCAL_KEY : VIDEO_REMOTE_KEY,
|
|
HKEY_CURRENT_USER );
|
|
|
|
DWORD dwFrameSizeDefault = FRAME_QCIF;
|
|
DWORD dwImageQualityDefault = NM_VIDEO_DEFAULT_QUALITY;
|
|
int nVideoWidthDefault = VIDEO_WIDTH_QCIF;
|
|
int nVideoHeightDefault = VIDEO_HEIGHT_QCIF;
|
|
|
|
UINT uBandWidth = reAudio.GetNumber(REGVAL_TYPICALBANDWIDTH, BW_DEFAULT);
|
|
if (uBandWidth == BW_144KBS)
|
|
{
|
|
dwImageQualityDefault = NM_VIDEO_MIN_QUALITY;
|
|
}
|
|
|
|
m_dwFrameSize = reVideo.GetNumber(
|
|
REGVAL_VIDEO_FRAME_SIZE, dwFrameSizeDefault );
|
|
|
|
if (!IsLocal())
|
|
{
|
|
m_dwImageQuality = reVideo.GetNumber(
|
|
REGVAL_VIDEO_QUALITY, dwImageQualityDefault );
|
|
}
|
|
|
|
m_nXferOnConnect =
|
|
IsLocal() ? VIDEO_SEND_CONNECT_DEFAULT :
|
|
VIDEO_RECEIVE_CONNECT_DEFAULT;
|
|
|
|
|
|
m_nXferOnConnect = reVideo.GetNumber(
|
|
REGVAL_VIDEO_XFER_CONNECT,
|
|
m_nXferOnConnect);
|
|
|
|
m_zoom = 100;
|
|
}
|
|
|
|
VOID CVideoWindow::OnNCDestroy()
|
|
{
|
|
// remote channel will get released upon the NM_CHANNEL_REMOVED
|
|
// notification. The preview channel needs to be released here,
|
|
// and not in the destructor because of a circular ref count
|
|
if (NULL != m_pActiveChannel)
|
|
{
|
|
NmUnadvise(m_pActiveChannel, IID_INmChannelVideoNotify, m_dwCookie);
|
|
m_dwCookie = 0;
|
|
m_pActiveChannel->Release();
|
|
m_pActiveChannel = NULL;
|
|
}
|
|
|
|
if (NULL != m_pNotify)
|
|
{
|
|
m_pNotify->Release();
|
|
m_pNotify = NULL;
|
|
}
|
|
}
|
|
|
|
CVideoWindow::~CVideoWindow()
|
|
{
|
|
CVideoWindow* p = static_cast<CVideoWindow*>(this);
|
|
g_pVideos->Remove(p);
|
|
if (0 == g_pVideos->GetSize())
|
|
{
|
|
delete g_pVideos;
|
|
g_pVideos = NULL;
|
|
}
|
|
|
|
if (NULL != m_hdd)
|
|
{
|
|
DRAWDIB::DrawDibClose(m_hdd);
|
|
}
|
|
// BUGBUG PhilF: Does DrawDibClose() nuke the selected palette?
|
|
|
|
|
|
// release resources related to mirror preview
|
|
UnInitMirroring();
|
|
}
|
|
|
|
BOOL CVideoWindow::Create(HWND hwndParent, HPALETTE hpal, IVideoChange *pNotify)
|
|
{
|
|
if (FAILED(DRAWDIB::Init()))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
if (!CGenWindow::Create(
|
|
hwndParent,
|
|
0,
|
|
IsLocal() ? TEXT("NMLocalVideo") : TEXT("NMRemoteVideo"),
|
|
WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
|
|
WS_EX_CLIENTEDGE))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
SetWindowPos(GetWindow(), NULL, 0, 0, m_sizeVideo.cx, m_sizeVideo.cy,
|
|
SWP_NOZORDER|SWP_NOACTIVATE);
|
|
|
|
// We do NOT own this palette
|
|
m_hPal = hpal;
|
|
|
|
m_hdd = DRAWDIB::DrawDibOpen();
|
|
if (NULL != m_hdd)
|
|
{
|
|
// Use the Indeo palette in 8 bit mode only if the decompressed
|
|
// video data is H.261 or H.263. We will create this palette as
|
|
// an identity palette.
|
|
|
|
// PhilF: If the user is utilizing an installable codec, do we still want to do this?
|
|
|
|
// Update the palette in the DrawDib surface
|
|
if (NULL != hpal)
|
|
{
|
|
DRAWDIB::DrawDibSetPalette(m_hdd, hpal);
|
|
}
|
|
}
|
|
|
|
if (NULL != pNotify)
|
|
{
|
|
m_pNotify = pNotify;
|
|
m_pNotify->AddRef();
|
|
}
|
|
|
|
if (IsLocal())
|
|
{
|
|
// need to get PreviewChannel;
|
|
INmManager2 *pManager = CConfMan::GetNmManager();
|
|
ASSERT (NULL != pManager);
|
|
pManager->GetPreviewChannel(&m_pActiveChannel);
|
|
pManager->Release();
|
|
|
|
if (m_pActiveChannel)
|
|
{
|
|
NmAdvise(m_pActiveChannel, static_cast<INmChannelVideoNotify*>(this),
|
|
IID_INmChannelVideoNotify, &m_dwCookie);
|
|
|
|
DWORD_PTR dwFrameSize = GetFrameSize();
|
|
if (g_bLocalOneTimeInited)
|
|
{
|
|
m_pActiveChannel->GetProperty(NM_VIDPROP_IMAGE_PREFERRED_SIZE, &dwFrameSize);
|
|
}
|
|
else
|
|
{
|
|
DWORD dwSizes = GetFrameSizes();
|
|
|
|
// if frame size is not valid
|
|
if (!(m_dwFrameSize & dwSizes))
|
|
{
|
|
// find an alternate size
|
|
if (FRAME_QCIF & dwSizes)
|
|
{
|
|
dwFrameSize = FRAME_QCIF;
|
|
}
|
|
else if (FRAME_SQCIF & dwSizes)
|
|
{
|
|
dwFrameSize = FRAME_SQCIF;
|
|
}
|
|
else if (FRAME_CIF & dwSizes)
|
|
{
|
|
dwFrameSize = FRAME_CIF;
|
|
}
|
|
}
|
|
|
|
RegEntry reVideo( IsLocal() ? VIDEO_LOCAL_KEY : VIDEO_REMOTE_KEY,
|
|
HKEY_CURRENT_USER );
|
|
SetMirror(reVideo.GetNumber(REGVAL_VIDEO_MIRROR, TRUE));
|
|
|
|
g_bLocalOneTimeInited = TRUE;
|
|
}
|
|
|
|
SetFrameSize((DWORD)dwFrameSize);
|
|
}
|
|
}
|
|
|
|
ResizeWindowsToFrameSize();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD CVideoWindow::GetFrameSizes()
|
|
{
|
|
DWORD_PTR dwSizes = 0;
|
|
if (NULL != m_pActiveChannel)
|
|
{
|
|
m_pActiveChannel->GetProperty(NM_VIDPROP_IMAGE_SIZES, &dwSizes);
|
|
}
|
|
|
|
return (DWORD)dwSizes;
|
|
}
|
|
|
|
VOID CVideoWindow::SetFrameSize(DWORD dwSize)
|
|
{
|
|
DWORD dwPrevSize = m_dwFrameSize;
|
|
|
|
m_dwFrameSize = dwSize;
|
|
if (IsLocal())
|
|
{
|
|
if (NULL != m_pActiveChannel)
|
|
{
|
|
m_pActiveChannel->SetProperty(NM_VIDPROP_IMAGE_PREFERRED_SIZE, dwSize);
|
|
}
|
|
}
|
|
|
|
if (dwPrevSize != dwSize)
|
|
{
|
|
if ((NULL == m_pActiveChannel) ||
|
|
(!IsLocal() && (S_OK != m_pActiveChannel->IsActive())) ||
|
|
(IsLocal() && IsPaused()))
|
|
{
|
|
ResizeWindowsToFrameSize();
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID CVideoWindow::ResizeWindowsToFrameSize()
|
|
{
|
|
SIZE size;
|
|
|
|
switch(m_dwFrameSize)
|
|
{
|
|
case FRAME_SQCIF:
|
|
size.cx = VIDEO_WIDTH_SQCIF;
|
|
size.cy = VIDEO_HEIGHT_SQCIF;
|
|
break;
|
|
case FRAME_CIF:
|
|
if (IsLocal())
|
|
{
|
|
size.cx = VIDEO_WIDTH_CIF;
|
|
size.cy = VIDEO_HEIGHT_CIF;
|
|
break;
|
|
}
|
|
// else fall through to QCIF
|
|
case FRAME_QCIF:
|
|
default:
|
|
size.cx = VIDEO_WIDTH_QCIF;
|
|
size.cy = VIDEO_HEIGHT_QCIF;
|
|
break;
|
|
}
|
|
|
|
SetVideoSize(&size);
|
|
}
|
|
|
|
STDMETHODIMP CVideoWindow::QueryInterface(REFIID riid, PVOID *ppv)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if ((riid == IID_INmChannelVideoNotify) || (riid == IID_IUnknown))
|
|
{
|
|
*ppv = static_cast<INmChannelVideoNotify *>(this);
|
|
DbgMsgApi("CVideoWindow::QueryInterface()");
|
|
}
|
|
else
|
|
{
|
|
hr = E_NOINTERFACE;
|
|
*ppv = NULL;
|
|
DbgMsgApi("CVideoWindow::QueryInterface(): Called on unknown interface.");
|
|
}
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
AddRef();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CVideoWindow::NmUI(CONFN uNotify)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CVideoWindow::MemberChanged(NM_MEMBER_NOTIFY uNotify, INmMember *pMember)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CVideoWindow::StateChanged(NM_VIDEO_STATE uState)
|
|
{
|
|
InvalidateRect(GetWindow(), NULL, TRUE);
|
|
|
|
if (NULL != m_pNotify)
|
|
{
|
|
m_pNotify->StateChange(this, uState);
|
|
}
|
|
|
|
CNmManagerObj::VideoChannelStateChanged(uState, !m_fLocal);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CVideoWindow::PropertyChanged(DWORD dwReserved)
|
|
{
|
|
if (NM_VIDPROP_FRAME == dwReserved)
|
|
{
|
|
OnFrameAvailable();
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CVideoWindow::OnChannelChanged(NM_CHANNEL_NOTIFY uNotify, INmChannel *pChannel)
|
|
{
|
|
INmChannelVideo* pChannelVideo;
|
|
if (SUCCEEDED(pChannel->QueryInterface(IID_INmChannelVideo, (void**)&pChannelVideo)))
|
|
{
|
|
BOOL bIncoming = (S_OK == pChannelVideo->IsIncoming());
|
|
if ((bIncoming && !IsLocal()) || (!bIncoming && IsLocal()))
|
|
{
|
|
switch (uNotify)
|
|
{
|
|
case NM_CHANNEL_ADDED:
|
|
if (NULL == m_pActiveChannel)
|
|
{
|
|
pChannelVideo->AddRef();
|
|
m_pActiveChannel = pChannelVideo;
|
|
NmAdvise(m_pActiveChannel,static_cast<INmChannelVideoNotify*>(this),
|
|
IID_INmChannelVideoNotify, &m_dwCookie);
|
|
|
|
SetImageQuality(m_dwImageQuality);
|
|
}
|
|
|
|
if (!_Module.InitControlMode())
|
|
{
|
|
switch(m_nXferOnConnect)
|
|
{
|
|
case VIDEO_XFER_START:
|
|
if (IsPaused())
|
|
{
|
|
Pause(FALSE);
|
|
}
|
|
break;
|
|
|
|
case VIDEO_XFER_STOP:
|
|
Pause(TRUE);
|
|
break;
|
|
|
|
default:
|
|
if (!IsLocal())
|
|
{
|
|
Pause(TRUE);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case NM_CHANNEL_REMOVED:
|
|
if (!IsLocal() && (pChannel == m_pActiveChannel))
|
|
{
|
|
NmUnadvise(m_pActiveChannel, IID_INmChannelVideoNotify, m_dwCookie);
|
|
m_pActiveChannel->Release();
|
|
m_pActiveChannel = NULL;
|
|
m_dwCookie = 0;
|
|
|
|
ResizeWindowsToFrameSize();
|
|
}
|
|
}
|
|
|
|
// just in case we missed a notification
|
|
// (in final version this should not be the case)
|
|
// m_VideoWindow.OnStateChange();
|
|
}
|
|
|
|
pChannelVideo->Release();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CVideoWindow::SetImageQuality(DWORD dwQuality)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
m_dwImageQuality = dwQuality;
|
|
if (NULL != m_pActiveChannel)
|
|
{
|
|
hr = m_pActiveChannel->SetProperty(NM_VIDPROP_IMAGE_QUALITY, dwQuality);
|
|
|
|
CNmManagerObj::VideoPropChanged(NM_VIDPROP_IMAGE_QUALITY, !IsLocal());
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CVideoWindow::SetCameraDialog(ULONG ul)
|
|
{
|
|
if(IsLocal())
|
|
{
|
|
return m_pActiveChannel->SetProperty(NM_VIDPROP_CAMERA_DIALOG, ul);
|
|
CNmManagerObj::VideoPropChanged(NM_VIDPROP_CAMERA_DIALOG, IsLocal());
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT CVideoWindow::GetCameraDialog(ULONG* pul)
|
|
{
|
|
HRESULT hr;
|
|
DWORD_PTR dwPropVal;
|
|
|
|
if(IsLocal())
|
|
{
|
|
hr = m_pActiveChannel->GetProperty(NM_VIDPROP_CAMERA_DIALOG, &dwPropVal);
|
|
*pul = (ULONG)dwPropVal;
|
|
return hr;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
BOOL CVideoWindow::IsXferAllowed()
|
|
{
|
|
if (IsLocal())
|
|
{
|
|
return FIsSendVideoAllowed() && (NULL != m_pActiveChannel);
|
|
}
|
|
else
|
|
{
|
|
return FIsReceiveVideoAllowed();
|
|
}
|
|
}
|
|
|
|
BOOL CVideoWindow::IsAutoXferEnabled()
|
|
{
|
|
return(VIDEO_XFER_START == m_nXferOnConnect);
|
|
}
|
|
|
|
BOOL CVideoWindow::IsXferEnabled()
|
|
{
|
|
if (NULL != m_pActiveChannel)
|
|
{
|
|
NM_VIDEO_STATE state;
|
|
if (SUCCEEDED(m_pActiveChannel->GetState(&state)))
|
|
{
|
|
switch (state)
|
|
{
|
|
case NM_VIDEO_PREVIEWING:
|
|
case NM_VIDEO_TRANSFERRING:
|
|
case NM_VIDEO_REMOTE_PAUSED:
|
|
return TRUE;
|
|
case NM_VIDEO_IDLE:
|
|
case NM_VIDEO_LOCAL_PAUSED:
|
|
case NM_VIDEO_BOTH_PAUSED:
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT CVideoWindow::GetVideoState(NM_VIDEO_STATE* puState)
|
|
{
|
|
if(m_pActiveChannel)
|
|
{
|
|
return m_pActiveChannel->GetState(puState);
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
VOID CVideoWindow::Pause(BOOL fPause)
|
|
{
|
|
if (NULL != m_pActiveChannel)
|
|
{
|
|
m_pActiveChannel->SetProperty(NM_VIDPROP_PAUSE, (ULONG)fPause);
|
|
|
|
CNmManagerObj::VideoPropChanged(NM_VIDPROP_PAUSE, !IsLocal());
|
|
}
|
|
}
|
|
|
|
BOOL CVideoWindow::IsPaused()
|
|
{
|
|
if (NULL != m_pActiveChannel)
|
|
{
|
|
ULONG_PTR uPause;
|
|
if (SUCCEEDED(m_pActiveChannel->GetProperty(NM_VIDPROP_PAUSE, &uPause)))
|
|
{
|
|
return (BOOL)uPause;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CVideoWindow::IsConnected()
|
|
{
|
|
if (NULL != m_pActiveChannel)
|
|
{
|
|
NM_VIDEO_STATE state;
|
|
if (SUCCEEDED(m_pActiveChannel->GetState(&state)))
|
|
{
|
|
switch (state)
|
|
{
|
|
case NM_VIDEO_LOCAL_PAUSED:
|
|
case NM_VIDEO_TRANSFERRING:
|
|
case NM_VIDEO_BOTH_PAUSED:
|
|
case NM_VIDEO_REMOTE_PAUSED:
|
|
return TRUE;
|
|
case NM_VIDEO_IDLE:
|
|
case NM_VIDEO_PREVIEWING:
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD CVideoWindow::GetNumCapDev()
|
|
{
|
|
DWORD_PTR dwNumDevs = 0;
|
|
if (NULL != m_pActiveChannel)
|
|
{
|
|
m_pActiveChannel->GetProperty(NM_VIDPROP_NUM_CAPTURE_DEVS, &dwNumDevs);
|
|
}
|
|
return (DWORD)dwNumDevs;
|
|
}
|
|
|
|
DWORD CVideoWindow::GetMaxCapDevNameLen()
|
|
{
|
|
DWORD_PTR dwLen = 0;
|
|
if (NULL != m_pActiveChannel)
|
|
{
|
|
m_pActiveChannel->GetProperty(NM_VIDPROP_MAX_CAPTURE_NAME, &dwLen);
|
|
}
|
|
return (DWORD)dwLen;
|
|
}
|
|
|
|
DWORD CVideoWindow::GetCurrCapDevID()
|
|
{
|
|
DWORD_PTR dwID = 0;
|
|
if (NULL != m_pActiveChannel)
|
|
{
|
|
m_pActiveChannel->GetProperty(NM_VIDPROP_CAPTURE_DEV_ID, &dwID);
|
|
}
|
|
return (DWORD)dwID;
|
|
}
|
|
|
|
VOID CVideoWindow::SetCurrCapDevID(DWORD dwID)
|
|
{
|
|
if (NULL != m_pActiveChannel)
|
|
{
|
|
m_pActiveChannel->SetProperty(NM_VIDPROP_CAPTURE_DEV_ID, dwID);
|
|
InvalidateRect(GetWindow(), NULL, TRUE);
|
|
}
|
|
}
|
|
|
|
VOID CVideoWindow::EnableAutoXfer(BOOL fEnable)
|
|
{
|
|
m_nXferOnConnect = fEnable ? VIDEO_XFER_START : VIDEO_XFER_NOP;
|
|
|
|
RegEntry reXfer( IsLocal() ? VIDEO_LOCAL_KEY : VIDEO_REMOTE_KEY,
|
|
HKEY_CURRENT_USER );
|
|
|
|
reXfer.SetValue ( REGVAL_VIDEO_XFER_CONNECT, m_nXferOnConnect);
|
|
}
|
|
|
|
VOID CVideoWindow::EnumCapDev(DWORD *pdwCapDevIDs, LPTSTR pszCapDevNames, DWORD dwNumCapDev)
|
|
{
|
|
ENUM_CAP_DEV enumCapDev;
|
|
enumCapDev.pdwCapDevIDs = pdwCapDevIDs;
|
|
enumCapDev.pszCapDevNames = pszCapDevNames;
|
|
enumCapDev.dwNumCapDev = dwNumCapDev;
|
|
|
|
if (NULL != m_pActiveChannel)
|
|
{
|
|
m_pActiveChannel->GetProperty(NM_VIDPROP_CAPTURE_LIST, (DWORD_PTR *)&enumCapDev);
|
|
}
|
|
}
|
|
|
|
VOID CVideoWindow::GetDesiredSize(SIZE *ppt)
|
|
{
|
|
ppt->cx = m_sizeVideo.cx*m_zoom/100;
|
|
ppt->cy = m_sizeVideo.cy*m_zoom/100;
|
|
|
|
if (m_bEmbedded)
|
|
{
|
|
ppt->cx = min(ppt->cx, QCIF_WIDTH);
|
|
ppt->cy = min(ppt->cy, QCIF_HEIGHT);
|
|
}
|
|
|
|
SIZE sGen;
|
|
CGenWindow::GetDesiredSize(&sGen);
|
|
|
|
ppt->cx += sGen.cx;
|
|
ppt->cy += sGen.cy;
|
|
}
|
|
|
|
VOID CVideoWindow::SetVideoSize(LPSIZE lpsize)
|
|
{
|
|
m_sizeVideo = *lpsize;
|
|
|
|
OnDesiredSizeChanged();
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
DWORD g_fDisplayFPS = FALSE;
|
|
|
|
#ifdef DISPLAYFPS
|
|
VOID CVideoWindow::UpdateFps(void)
|
|
{
|
|
DWORD dwTick = GetTickCount();
|
|
m_cFrame++;
|
|
// Update display every 4 seconds
|
|
if ((dwTick - m_dwTick) < 4000)
|
|
return;
|
|
|
|
TCHAR sz[32];
|
|
wsprintf(sz, "%d FPS", m_cFrame / 4);
|
|
SetWindowText(m_hwndParent, sz);
|
|
|
|
m_cFrame = 0;
|
|
m_dwTick = dwTick;
|
|
}
|
|
#endif /* DISPLAYFPS */
|
|
#endif // DEBUG
|
|
|
|
VOID CVideoWindow::OnFrameAvailable(void)
|
|
{
|
|
::InvalidateRect(GetWindow(), NULL, FALSE);
|
|
|
|
#ifdef DISPLAYFPS
|
|
if (g_fDisplayFPS)
|
|
{
|
|
UpdateFps();
|
|
}
|
|
#endif // DISPLAYFPS
|
|
}
|
|
|
|
|
|
VOID CVideoWindow::PaintDib(HDC hdc, FRAMECONTEXT *pFrame)
|
|
{
|
|
RECT rcVideo;
|
|
GetClientRect(GetWindow(), &rcVideo);
|
|
|
|
HPALETTE hpOld = NULL;
|
|
|
|
if (NULL != m_hPal)
|
|
{
|
|
hpOld = SelectPalette(hdc, m_hPal, FALSE);
|
|
RealizePalette(hdc);
|
|
}
|
|
|
|
// create the bitmap object, only if it doesn't exist
|
|
// and if the mirror bitmap object isn't the right size
|
|
if (!ShouldMirror() || !InitMirroring(rcVideo))
|
|
{
|
|
// ISSUE: (ChrisPi 2-19-97) should we use DDF_SAME_HDC?
|
|
DRAWDIB::DrawDibDraw(m_hdd,hdc,
|
|
rcVideo.left,
|
|
rcVideo.top,
|
|
RectWidth(rcVideo),
|
|
RectHeight(rcVideo),
|
|
&pFrame->lpbmi->bmiHeader,
|
|
pFrame->lpData,
|
|
pFrame->lpClipRect->left,
|
|
pFrame->lpClipRect->top,
|
|
RectWidth(pFrame->lpClipRect),
|
|
RectHeight(pFrame->lpClipRect),
|
|
0);
|
|
}
|
|
else
|
|
{
|
|
if (NULL != m_hPal)
|
|
{
|
|
SelectPalette(m_hDCMirror, m_hPal, FALSE);
|
|
RealizePalette(m_hDCMirror);
|
|
}
|
|
|
|
DRAWDIB::DrawDibDraw(m_hdd,
|
|
m_hDCMirror,
|
|
0,
|
|
0,
|
|
RectWidth(rcVideo),
|
|
RectHeight(rcVideo),
|
|
&pFrame->lpbmi->bmiHeader,
|
|
pFrame->lpData,
|
|
pFrame->lpClipRect->left,
|
|
pFrame->lpClipRect->top,
|
|
RectWidth(pFrame->lpClipRect),
|
|
RectHeight(pFrame->lpClipRect),
|
|
0);
|
|
|
|
::StretchBlt(hdc,
|
|
rcVideo.right,
|
|
rcVideo.top,
|
|
-RectWidth(rcVideo),
|
|
RectHeight(rcVideo),
|
|
m_hDCMirror,
|
|
0,
|
|
0,
|
|
RectWidth(rcVideo),
|
|
RectHeight(rcVideo),
|
|
SRCCOPY);
|
|
|
|
// HACKHACK georgep; don't worry about deselecting the palette in
|
|
// the temp DC
|
|
}
|
|
|
|
if (NULL != hpOld)
|
|
{
|
|
SelectPalette(hdc, hpOld, FALSE);
|
|
}
|
|
}
|
|
|
|
/* P A I N T L O G O */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: PaintLogo
|
|
|
|
Display the 256 color NetMeeting logo in the video window.
|
|
-------------------------------------------------------------------------*/
|
|
VOID CVideoWindow::PaintLogo(HDC hdc, UINT idbLargeLogo, UINT idbSmallLogo)
|
|
{
|
|
RECT rcVideo;
|
|
GetClientRect(GetWindow(), &rcVideo);
|
|
|
|
::FillRect(hdc, &rcVideo, (HBRUSH)::GetStockObject(WHITE_BRUSH));
|
|
|
|
// Create the memory DC
|
|
HDC hdcMem = ::CreateCompatibleDC(hdc);
|
|
if (NULL == hdcMem)
|
|
{
|
|
ERROR_OUT(("PaintLogo: Unable to CreateCompatibleDC"));
|
|
return;
|
|
}
|
|
|
|
// Load the bitmap (LoadBitmap doesn't work for 256 color images)
|
|
HANDLE hBitmap = LoadImage(::GetInstanceHandle(),
|
|
MAKEINTRESOURCE(idbLargeLogo), IMAGE_BITMAP, 0, 0,
|
|
LR_CREATEDIBSECTION);
|
|
|
|
if (NULL != hBitmap)
|
|
{
|
|
BITMAP bitmap;
|
|
::GetObject(hBitmap, sizeof(bitmap), &bitmap);
|
|
int cx = bitmap.bmWidth;
|
|
int cy = bitmap.bmHeight;
|
|
|
|
if (RectWidth(rcVideo) < cx || RectHeight(rcVideo) < cy)
|
|
{
|
|
HANDLE hNew = LoadImage(::GetInstanceHandle(),
|
|
MAKEINTRESOURCE(idbSmallLogo), IMAGE_BITMAP, 0, 0,
|
|
LR_CREATEDIBSECTION);
|
|
if (NULL != hNew)
|
|
{
|
|
DeleteObject(hBitmap);
|
|
hBitmap = hNew;
|
|
|
|
::GetObject(hBitmap, sizeof(bitmap), &bitmap);
|
|
cx = bitmap.bmWidth;
|
|
cy = bitmap.bmHeight;
|
|
}
|
|
}
|
|
|
|
HBITMAP hBmpTmp = (HBITMAP)::SelectObject(hdcMem, hBitmap);
|
|
|
|
// Select and realize the palette
|
|
HPALETTE hPalette = m_hPal;
|
|
if (NULL != hPalette)
|
|
{
|
|
SelectPalette(hdcMem, hPalette, FALSE);
|
|
RealizePalette(hdcMem);
|
|
SelectPalette(hdc, hPalette, FALSE);
|
|
RealizePalette(hdc);
|
|
}
|
|
|
|
int x = rcVideo.left + (RectWidth(rcVideo) - cx) / 2;
|
|
int y = rcVideo.top + (RectHeight(rcVideo) - cy) / 2;
|
|
::BitBlt(hdc, x, y, cx, cy, hdcMem, 0, 0, SRCCOPY);
|
|
|
|
::SelectObject(hdcMem, hBmpTmp);
|
|
::DeleteObject(hBitmap);
|
|
}
|
|
::DeleteDC(hdcMem);
|
|
}
|
|
|
|
|
|
VOID CVideoWindow::OnPaint()
|
|
{
|
|
PAINTSTRUCT ps;
|
|
HDC hdc;
|
|
|
|
hdc = ::BeginPaint(GetWindow(), &ps);
|
|
|
|
if( hdc )
|
|
{
|
|
if( RectWidth(ps.rcPaint) && RectHeight(ps.rcPaint) )
|
|
{
|
|
// This means that we have a non-zero surface area ( there may be something to paint )
|
|
|
|
DBGENTRY(CVideoWindow::ProcessPaint);
|
|
|
|
// paint the video rect
|
|
FRAMECONTEXT fc;
|
|
if ((S_OK == GetFrame(&fc)))
|
|
{
|
|
if (!IsPaused())
|
|
{
|
|
SIZE vidSize =
|
|
{
|
|
RectWidth(fc.lpClipRect),
|
|
RectHeight(fc.lpClipRect)
|
|
} ;
|
|
|
|
if ((vidSize.cx != m_sizeVideo.cx) || (vidSize.cy != m_sizeVideo.cy))
|
|
{
|
|
// save the new image size
|
|
SetVideoSize(&vidSize);
|
|
}
|
|
}
|
|
|
|
PaintDib(hdc, &fc);
|
|
|
|
ReleaseFrame(&fc);
|
|
}
|
|
else
|
|
{
|
|
PaintLogo(hdc, IDB_VIDEO_LOGO, IDB_VIDEO_LOGO_SMALL);
|
|
}
|
|
|
|
// check to see if needs painting outside the video rect
|
|
#if FALSE
|
|
// Currently just stretching the video to the window size
|
|
if (ps.rcPaint.left < m_rcVideo.left ||
|
|
ps.rcPaint.top < m_rcVideo.top ||
|
|
ps.rcPaint.right > m_rcVideo.right ||
|
|
ps.rcPaint.bottom > m_rcVideo.bottom)
|
|
{
|
|
HFONT hfOld;
|
|
int nBkModeOld;
|
|
RECT rc, rcClient;
|
|
|
|
::GetClientRect(GetWindow(), &rcClient);
|
|
|
|
// erase the background if requested
|
|
if (ps.fErase)
|
|
{
|
|
::ExcludeClipRect(hdc,
|
|
m_rcVideo.left,
|
|
m_rcVideo.top,
|
|
m_rcVideo.right,
|
|
m_rcVideo.bottom);
|
|
::FillRect(hdc, &rcClient, ::GetSysColorBrush(COLOR_BTNFACE));
|
|
}
|
|
|
|
nBkModeOld = ::SetBkMode(hdc, TRANSPARENT);
|
|
hfOld = (HFONT)::SelectObject(hdc, g_hfontDlg);
|
|
|
|
// paint the status text
|
|
// first erase the old text if not already done
|
|
if (!ps.fErase)
|
|
{
|
|
::FillRect(hdc, &m_rcStatusText, ::GetSysColorBrush(COLOR_BTNFACE));
|
|
}
|
|
TCHAR szState[MAX_PATH];
|
|
if (GetState(szState, CCHMAX(szState)))
|
|
{
|
|
COLORREF crOld;
|
|
|
|
crOld = ::SetTextColor(hdc, ::GetSysColor(COLOR_BTNTEXT));
|
|
|
|
rc = m_rcStatusText;
|
|
rc.left += STATUS_MARGIN;
|
|
::DrawText(hdc,
|
|
szState,
|
|
-1,
|
|
&rc,
|
|
DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX);
|
|
::SetTextColor(hdc, crOld);
|
|
}
|
|
|
|
// paint border around video
|
|
rc = m_rcVideo;
|
|
::InflateRect(&rc,
|
|
::GetSystemMetrics(SM_CXEDGE),
|
|
::GetSystemMetrics(SM_CYEDGE));
|
|
::DrawEdge(hdc, &rc, EDGE_SUNKEN , BF_RECT);
|
|
|
|
// restore DC stuff
|
|
::SelectObject(hdc, hfOld);
|
|
::SetBkMode(hdc, nBkModeOld);
|
|
}
|
|
#endif // FALSE
|
|
|
|
DBGEXIT(CVideoWindow::ProcessPaint);
|
|
}
|
|
|
|
::EndPaint(GetWindow(), &ps);
|
|
}
|
|
|
|
}
|
|
|
|
VOID CVideoWindow::SetZoom(UINT zoom)
|
|
{
|
|
if (m_zoom == zoom)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_zoom = zoom;
|
|
OnDesiredSizeChanged();
|
|
}
|
|
|
|
void CVideoWindow::OnCommand(int idCmd)
|
|
{
|
|
|
|
switch (idCmd)
|
|
{
|
|
case IDM_VIDEO_GETACAMERA:
|
|
CmdLaunchWebPage(idCmd);
|
|
break;
|
|
|
|
case IDM_VIDEO_COPY:
|
|
CopyToClipboard();
|
|
break;
|
|
|
|
case IDM_VIDEO_FREEZE:
|
|
Pause(!IsPaused());
|
|
break;
|
|
|
|
case IDM_VIDEO_UNDOCK:
|
|
CMainUI::NewVideoWindow(GetConfRoom());
|
|
break;
|
|
|
|
case IDM_VIDEO_ZOOM1:
|
|
SetZoom(100);
|
|
break;
|
|
|
|
case IDM_VIDEO_ZOOM2:
|
|
SetZoom(200);
|
|
break;
|
|
|
|
case IDM_VIDEO_ZOOM3:
|
|
SetZoom(300);
|
|
break;
|
|
|
|
case IDM_VIDEO_ZOOM4:
|
|
SetZoom(400);
|
|
break;
|
|
|
|
case IDM_VIDEO_PROPERTIES:
|
|
LaunchConfCpl(GetWindow(), OPTIONS_VIDEO_PAGE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CVideoWindow::UpdateVideoMenu(HMENU hMenu)
|
|
{
|
|
EnableMenuItem(hMenu, IDM_VIDEO_COPY, MF_BYCOMMAND|(CanCopy() ? MF_ENABLED : MF_GRAYED|MF_DISABLED));
|
|
EnableMenuItem(hMenu, IDM_VIDEO_UNDOCK, MF_BYCOMMAND|(IsLocal() ? MF_ENABLED : MF_GRAYED|MF_DISABLED));
|
|
|
|
if (!FIsSendVideoAllowed() && !FIsReceiveVideoAllowed())
|
|
{
|
|
EnableMenuItem(hMenu, IDM_VIDEO_FREEZE, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED);
|
|
EnableMenuItem(hMenu, IDM_VIDEO_PROPERTIES, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED);
|
|
EnableMenuItem(hMenu, IDM_VIDEO_GETACAMERA, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED);
|
|
}
|
|
else
|
|
{
|
|
CheckMenuItem(hMenu, IDM_VIDEO_FREEZE, MF_BYCOMMAND|(IsPaused() ? MF_CHECKED : MF_UNCHECKED));
|
|
|
|
UINT uEnable = ::CanShellExecHttp() ? MF_ENABLED : MF_GRAYED;
|
|
::EnableMenuItem(hMenu, IDM_VIDEO_GETACAMERA, uEnable);
|
|
}
|
|
|
|
int nZoom = GetZoom();
|
|
int idZoom;
|
|
if (350 < nZoom) idZoom = IDM_VIDEO_ZOOM4;
|
|
else if (250 < nZoom) idZoom = IDM_VIDEO_ZOOM3;
|
|
else if (150 < nZoom) idZoom = IDM_VIDEO_ZOOM2;
|
|
else idZoom = IDM_VIDEO_ZOOM1;
|
|
|
|
UINT uFlags = IsZoomable() && !m_bEmbedded
|
|
? MF_ENABLED : MF_GRAYED|MF_DISABLED;
|
|
for (int id=IDM_VIDEO_ZOOM1; id<=IDM_VIDEO_ZOOM4; ++id)
|
|
{
|
|
EnableMenuItem(hMenu, id, MF_BYCOMMAND|uFlags);
|
|
CheckMenuItem(hMenu, id, MF_BYCOMMAND|MF_UNCHECKED);
|
|
}
|
|
CheckMenuItem(hMenu, idZoom, MF_BYCOMMAND|MF_CHECKED);
|
|
|
|
uFlags = CanLaunchConfCpl()
|
|
? MF_ENABLED : MF_GRAYED|MF_DISABLED;
|
|
EnableMenuItem(hMenu, IDM_VIDEO_PROPERTIES, MF_BYCOMMAND|uFlags);
|
|
|
|
|
|
|
|
}
|
|
|
|
void CVideoWindow::OnContextMenu(HWND hwnd, HWND hwndContext, UINT xPos, UINT yPos)
|
|
{
|
|
HMENU hmLoad = LoadMenu(_Module.GetModuleInstance(), MAKEINTRESOURCE(IDR_VIDEO_POPUP));
|
|
if (NULL != hmLoad)
|
|
{
|
|
HMENU hmPopup = GetSubMenu(hmLoad, 0);
|
|
ASSERT(NULL != hmPopup);
|
|
|
|
UpdateVideoMenu(hmPopup);
|
|
|
|
int idCmd = TrackPopupMenu(hmPopup, TPM_RETURNCMD|TPM_RIGHTBUTTON,
|
|
xPos, yPos, 0, hwnd, NULL);
|
|
|
|
if (0 != idCmd)
|
|
{
|
|
OnCommand(idCmd);
|
|
}
|
|
|
|
DestroyMenu(hmLoad);
|
|
}
|
|
}
|
|
|
|
LRESULT CVideoWindow::ProcessMessage(HWND hwnd, UINT message,
|
|
WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (message)
|
|
{
|
|
HANDLE_MSG(hwnd, WM_CONTEXTMENU, OnContextMenu);
|
|
|
|
case WM_ERASEBKGND:
|
|
return 0;
|
|
|
|
case WM_PAINT:
|
|
OnPaint();
|
|
return 0;
|
|
|
|
case WM_NCDESTROY:
|
|
OnNCDestroy();
|
|
return 0;
|
|
|
|
case WM_SIZE:
|
|
// Need to redraw the whole window
|
|
InvalidateRect(GetWindow(), NULL, FALSE);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return CGenWindow::ProcessMessage(hwnd, message, wParam, lParam) ;
|
|
}
|
|
|
|
#if FALSE
|
|
int CVideoWindow::GetState(LPTSTR lpszState, int nStateMax)
|
|
{
|
|
int uStringID;
|
|
|
|
NM_VIDEO_STATE state = NM_VIDEO_IDLE;
|
|
|
|
if (NULL != m_pActiveChannel)
|
|
{
|
|
m_pActiveChannel->GetState(&state);
|
|
}
|
|
|
|
if (IsLocal())
|
|
{
|
|
switch (state)
|
|
{
|
|
case NM_VIDEO_PREVIEWING:
|
|
uStringID = IDS_VIDEO_STATE_PREVIEWING;
|
|
break;
|
|
case NM_VIDEO_TRANSFERRING:
|
|
uStringID = IDS_VIDEO_STATE_SENDING;
|
|
break;
|
|
case NM_VIDEO_REMOTE_PAUSED:
|
|
uStringID = IDS_VIDEO_STATE_REMOTEPAUSED;
|
|
break;
|
|
case NM_VIDEO_LOCAL_PAUSED:
|
|
case NM_VIDEO_BOTH_PAUSED:
|
|
uStringID = IDS_VIDEO_STATE_PAUSED;
|
|
break;
|
|
case NM_VIDEO_IDLE:
|
|
default:
|
|
uStringID = IDS_VIDEO_STATE_NOTSENDING;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (state)
|
|
{
|
|
case NM_VIDEO_TRANSFERRING:
|
|
uStringID = IDS_VIDEO_STATE_RECEIVING;
|
|
break;
|
|
case NM_VIDEO_REMOTE_PAUSED:
|
|
uStringID = IDS_VIDEO_STATE_REMOTEPAUSED;
|
|
break;
|
|
case NM_VIDEO_LOCAL_PAUSED:
|
|
case NM_VIDEO_BOTH_PAUSED:
|
|
uStringID = IDS_VIDEO_STATE_PAUSED;
|
|
break;
|
|
case NM_VIDEO_IDLE:
|
|
case NM_VIDEO_PREVIEWING:
|
|
default:
|
|
uStringID = IDS_VIDEO_STATE_NOTRECEIVING;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ::LoadString(
|
|
::GetInstanceHandle(),
|
|
uStringID,
|
|
lpszState,
|
|
nStateMax);
|
|
}
|
|
#endif // FALSE
|
|
|
|
// Return value will be TRUE if Windows can handle the format
|
|
static BOOL IsKnownDIBFormat(BITMAPINFOHEADER *pbmih)
|
|
{
|
|
if (sizeof(BITMAPINFOHEADER) != pbmih->biSize)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
if (1 != pbmih->biPlanes)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
int bits = pbmih->biBitCount;
|
|
int comp = pbmih->biCompression;
|
|
|
|
switch (bits)
|
|
{
|
|
case 1:
|
|
if (BI_RGB == comp)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
if (BI_RGB == comp || BI_RLE4 == comp)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
break;
|
|
|
|
case 8:
|
|
if (BI_RGB == comp || BI_RLE8 == comp)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
break;
|
|
|
|
case 16:
|
|
if (BI_RGB == comp || BI_BITFIELDS == comp)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
break;
|
|
|
|
case 24:
|
|
case 32:
|
|
if (BI_RGB == comp)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
#ifdef TryPaintDIB
|
|
BOOL CVideoWindow::CopyToClipboard()
|
|
{
|
|
FRAMECONTEXT fc;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
// Get the current frame and open the clipboard
|
|
if (S_OK == GetFrame(&fc))
|
|
{
|
|
HWND hwnd = GetWindow();
|
|
|
|
if (OpenClipboard(hwnd))
|
|
{
|
|
// Allocate memory that we will be giving to the clipboard
|
|
BITMAPINFOHEADER *pbmih = &fc.lpbmi->bmiHeader;
|
|
|
|
BOOL bCopy = IsKnownDIBFormat(pbmih);
|
|
|
|
// BUGBUG georgep; I think this doesn't work for 15 or 16 bit DIBs
|
|
int nColors = pbmih->biClrUsed;
|
|
if (0 == nColors && pbmih->biBitCount <= 8)
|
|
{
|
|
nColors = 1 << pbmih->biBitCount;
|
|
}
|
|
// Special case for 16-bit bitfield bitmaps
|
|
if (16 == pbmih->biBitCount && BI_BITFIELDS == pbmih->biCompression)
|
|
{
|
|
nColors = 3;
|
|
}
|
|
int nHdrSize = pbmih->biSize + nColors * sizeof(RGBQUAD);
|
|
|
|
int bitsPer = pbmih->biBitCount;
|
|
if (!bCopy)
|
|
{
|
|
bitsPer *= pbmih->biPlanes;
|
|
if (bitsPer > 24)
|
|
{
|
|
bitsPer = 32;
|
|
}
|
|
// LAZYLAZY georgep: Skipping 16-bit format
|
|
else if (bitsPer > 8)
|
|
{
|
|
bitsPer = 24;
|
|
}
|
|
else if (bitsPer > 4)
|
|
{
|
|
bitsPer = 8;
|
|
}
|
|
else if (bitsPer > 1)
|
|
{
|
|
bitsPer = 4;
|
|
}
|
|
else
|
|
{
|
|
bitsPer = 1;
|
|
}
|
|
}
|
|
|
|
int nDataSize = bCopy ? pbmih->biSizeImage : 0;
|
|
if (0 == nDataSize)
|
|
{
|
|
// Make an uncompressed DIB
|
|
int nByteWidth = (pbmih->biWidth*bitsPer+7) / 8;
|
|
nDataSize = ((nByteWidth + 3)&~3) * pbmih->biHeight;
|
|
}
|
|
|
|
// Allocate the total memory for the DIB
|
|
HGLOBAL hCopy = GlobalAlloc(GHND, nHdrSize + nDataSize);
|
|
if (NULL != hCopy)
|
|
{
|
|
BITMAPINFO *lpvCopy = reinterpret_cast<BITMAPINFO*>(GlobalLock(hCopy));
|
|
|
|
CopyMemory(lpvCopy, pbmih, nHdrSize);
|
|
|
|
// Create a temporary DC for drawing into
|
|
HDC hdc = GetDC(hwnd);
|
|
if (NULL != hdc)
|
|
{
|
|
HDC hdcTemp = CreateCompatibleDC(hdc);
|
|
ReleaseDC(hwnd, hdc);
|
|
hdc = hdcTemp;
|
|
}
|
|
|
|
if (NULL != hdc)
|
|
{
|
|
if (bCopy)
|
|
{
|
|
if (ShouldMirror())
|
|
{
|
|
// Create a DIB section for drawing into
|
|
LPVOID pData;
|
|
HBITMAP hDIB = CreateDIBSection(hdc, lpvCopy, DIB_RGB_COLORS, &pData, NULL, 0);
|
|
if (NULL != hDIB)
|
|
{
|
|
// Draw into the DIB, and then copy the bits
|
|
HGDIOBJ hOld = SelectObject(hdc, hDIB);
|
|
|
|
RECT rc = { 0, 0, pbmih->biWidth, pbmih->biHeight };
|
|
StretchDIBits(hdc, 0, 0, pbmih->biWidth, pbmih->biHeight,
|
|
pbmih->biWidth, 0, -pbmih->biWidth, pbmih->biHeight,
|
|
fc.lpData, lpvCopy, DIB_RGB_COLORS, SRCCOPY);
|
|
|
|
CopyMemory(&lpvCopy->bmiColors[nColors], pData, nDataSize);
|
|
|
|
// Start cleaning up
|
|
SelectObject(hdc, hOld);
|
|
DeleteObject(hDIB);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CopyMemory(&lpvCopy->bmiColors[nColors], fc.lpData, nDataSize);
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
}
|
|
else
|
|
{
|
|
lpvCopy->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
lpvCopy->bmiHeader.biPlanes = 1;
|
|
lpvCopy->bmiHeader.biBitCount = bitsPer;
|
|
lpvCopy->bmiHeader.biCompression = BI_RGB;
|
|
lpvCopy->bmiHeader.biSizeImage = nDataSize;
|
|
|
|
// Create a DIB section for drawing into
|
|
LPVOID pData;
|
|
HBITMAP hDIB = CreateDIBSection(hdc, lpvCopy, DIB_RGB_COLORS, &pData, NULL, 0);
|
|
if (NULL != hDIB)
|
|
{
|
|
// Draw into the DIB, and then copy the bits
|
|
HGDIOBJ hOld = SelectObject(hdc, hDIB);
|
|
|
|
RECT rc = { 0, 0, pbmih->biWidth, pbmih->biHeight };
|
|
PaintDib(hdc, &fc, &rc);
|
|
|
|
CopyMemory(&lpvCopy->bmiColors[nColors], pData, nDataSize);
|
|
|
|
// Start cleaning up
|
|
SelectObject(hdc, hOld);
|
|
DeleteObject(hDIB);
|
|
|
|
fSuccess = TRUE;
|
|
}
|
|
}
|
|
|
|
DeleteDC(hdc);
|
|
}
|
|
|
|
GlobalUnlock(hCopy);
|
|
|
|
if (fSuccess)
|
|
{
|
|
// Set the DIB into the clipboard
|
|
EmptyClipboard();
|
|
fSuccess = (NULL != SetClipboardData(CF_DIB, (HANDLE)hCopy));
|
|
}
|
|
|
|
if (!fSuccess)
|
|
{
|
|
GlobalFree(hCopy);
|
|
}
|
|
}
|
|
|
|
CloseClipboard();
|
|
}
|
|
|
|
ReleaseFrame(&fc);
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
#else // TryPaintDIB
|
|
BOOL CVideoWindow::CopyToClipboard()
|
|
{
|
|
FRAMECONTEXT fc;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
if (S_OK == GetFrame(&fc))
|
|
{
|
|
if (OpenClipboard(GetWindow()))
|
|
{
|
|
EmptyClipboard();
|
|
{
|
|
HGLOBAL hCopy;
|
|
BITMAPINFOHEADER *pbmih;
|
|
|
|
pbmih = &fc.lpbmi->bmiHeader;
|
|
hCopy = GlobalAlloc(GHND, DibSize(pbmih));
|
|
if (NULL != hCopy)
|
|
{
|
|
LPVOID lpvCopy = GlobalLock(hCopy);
|
|
int nHdrSize = DibHdrSize(pbmih);
|
|
CopyMemory(lpvCopy, pbmih, nHdrSize);
|
|
CopyMemory((LPBYTE)lpvCopy + nHdrSize, fc.lpData, DibDataSize(pbmih));
|
|
GlobalUnlock(hCopy);
|
|
fSuccess = (NULL != SetClipboardData(CF_DIB, (HANDLE)hCopy));
|
|
if (!fSuccess)
|
|
{
|
|
GlobalFree(hCopy);
|
|
}
|
|
}
|
|
}
|
|
CloseClipboard();
|
|
}
|
|
ReleaseFrame(&fc);
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
#endif // TryPaintDIB
|
|
|
|
HRESULT CVideoWindow::GetFrame(FRAMECONTEXT *pFrameContext)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (NULL != m_pActiveChannel)
|
|
{
|
|
hr = m_pActiveChannel->GetProperty(NM_VIDPROP_FRAME, (DWORD_PTR *)pFrameContext);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CVideoWindow::ReleaseFrame(FRAMECONTEXT *pFrameContext)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (NULL != m_pActiveChannel)
|
|
{
|
|
hr = m_pActiveChannel->SetProperty(NM_VIDPROP_FRAME, (DWORD_PTR)pFrameContext);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
void CVideoWindow::SaveSettings()
|
|
{
|
|
RegEntry re( IsLocal() ? VIDEO_LOCAL_KEY : VIDEO_REMOTE_KEY,
|
|
HKEY_CURRENT_USER );
|
|
|
|
re.SetValue(REGVAL_VIDEO_FRAME_SIZE, m_dwFrameSize);
|
|
|
|
if (!IsLocal())
|
|
{
|
|
re.SetValue(REGVAL_VIDEO_QUALITY, m_dwImageQuality);
|
|
}
|
|
else
|
|
{
|
|
re.SetValue(REGVAL_VIDEO_MIRROR, GetMirror());
|
|
}
|
|
}
|
|
|
|
VOID CVideoWindow::ForwardSysChangeMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_PALETTECHANGED:
|
|
OnPaletteChanged();
|
|
break;
|
|
}
|
|
}
|
|
|
|
VOID CVideoWindow::OnPaletteChanged(void)
|
|
{
|
|
::RedrawWindow(GetWindow(), NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
|
|
}
|
|
|
|
BOOL CVideoWindow::HasDialog(DWORD dwDialog)
|
|
{
|
|
DWORD_PTR dwDialogs = 0;
|
|
if (NULL != m_pActiveChannel)
|
|
{
|
|
m_pActiveChannel->GetProperty(NM_VIDPROP_CAMERA_DIALOG, &dwDialogs);
|
|
}
|
|
return (BOOL)(dwDialogs & dwDialog);
|
|
}
|
|
|
|
VOID CVideoWindow::ShowDialog(DWORD dwDialog)
|
|
{
|
|
if (NULL != m_pActiveChannel)
|
|
{
|
|
m_pActiveChannel->SetProperty(NM_VIDPROP_CAMERA_DIALOG, dwDialog);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL CVideoWindow::InitMirroring(RECT &rcVideo)
|
|
{
|
|
HDC hdcWindow;
|
|
|
|
if ((m_hBitmapMirror != NULL) &&
|
|
(RectWidth(rcVideo) == m_sizeBitmapMirror.cx) &&
|
|
(RectHeight(rcVideo) == m_sizeBitmapMirror.cy))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
hdcWindow = ::GetDC(NULL);
|
|
|
|
UnInitMirroring();
|
|
|
|
m_hBitmapMirror = ::CreateCompatibleBitmap(hdcWindow, RectWidth(rcVideo), RectHeight(rcVideo));
|
|
|
|
if (m_hBitmapMirror == NULL)
|
|
{
|
|
ReleaseDC(NULL, hdcWindow);
|
|
return FALSE;
|
|
}
|
|
|
|
m_hDCMirror = ::CreateCompatibleDC(hdcWindow);
|
|
|
|
if (m_hDCMirror == NULL)
|
|
{
|
|
UnInitMirroring();
|
|
ReleaseDC(NULL, hdcWindow);
|
|
return FALSE;
|
|
}
|
|
|
|
// preserve the handle of the object being replaced
|
|
m_hGDIObj = ::SelectObject(m_hDCMirror, m_hBitmapMirror);
|
|
::SetMapMode(m_hDCMirror, GetMapMode(hdcWindow));
|
|
|
|
m_sizeBitmapMirror.cx = RectWidth(rcVideo);
|
|
m_sizeBitmapMirror.cy = RectHeight(rcVideo);
|
|
ReleaseDC(NULL, hdcWindow);
|
|
return TRUE;
|
|
}
|
|
|
|
VOID CVideoWindow::UnInitMirroring()
|
|
{
|
|
if (m_hBitmapMirror)
|
|
{
|
|
if (m_hDCMirror)
|
|
{
|
|
::SelectObject(m_hDCMirror, m_hGDIObj);
|
|
}
|
|
::DeleteObject(m_hBitmapMirror);
|
|
m_hBitmapMirror = NULL;
|
|
}
|
|
|
|
if (m_hDCMirror)
|
|
{
|
|
::DeleteObject(m_hDCMirror);
|
|
m_hDCMirror = NULL;
|
|
}
|
|
}
|
|
|
|
VOID CVideoWindow::InvalidateAll()
|
|
{
|
|
for(int i = g_pVideos->GetSize()-1; i >= 0 ; --i)
|
|
{
|
|
CVideoWindow *pVideo = (*g_pVideos)[i];
|
|
HWND hwnd = pVideo->GetWindow();
|
|
if (NULL != hwnd)
|
|
{
|
|
InvalidateRect(hwnd, NULL, FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID CVideoWindow::SetMirror(BOOL bMirror)
|
|
{
|
|
bMirror = bMirror != FALSE;
|
|
|
|
if (g_fMirror != bMirror)
|
|
{
|
|
g_fMirror = bMirror;
|
|
InvalidateAll();
|
|
}
|
|
}
|
|
|
|
BOOL CVideoWindow::CanCopy()
|
|
{
|
|
BOOL bCopy = (IsXferEnabled() && IsLocal()) || IsConnected();
|
|
if (bCopy)
|
|
{
|
|
bCopy = FALSE;
|
|
|
|
FRAMECONTEXT fc;
|
|
if (S_OK == GetFrame(&fc))
|
|
{
|
|
BITMAPINFOHEADER *pbmih = &fc.lpbmi->bmiHeader;
|
|
|
|
bCopy = IsKnownDIBFormat(pbmih);
|
|
|
|
ReleaseFrame(&fc);
|
|
}
|
|
}
|
|
|
|
return(bCopy);
|
|
}
|
|
|
|
BOOL CVideoWindow::FDidNotDisplayIntelLogo()
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
VOID CVideoWindow::DisplayIntelLogo( BOOL bDisplay )
|
|
{
|
|
}
|