//
// CAVICAP.CPP
// (c) Vadim Gorbatenko, 1996-99
// gvv@mail.tomsknet.ru
// All rights reserved
//
// CAviCap window
// Started: 11.09.96
// Release: 0999
//___________________________________________________________________________________________
// Last revision: 10.10.99
//
#include "stdafx.h"
#include "cavicap.h"
#pragma comment(lib, "winmm.lib")
#pragma comment(lib, "vfw32.lib")
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
BEGIN_MESSAGE_MAP(CAviCap, CWnd)
//{{AFX_MSG_MAP(CAviCap)
ON_WM_PAINT()
ON_WM_DESTROY()
ON_WM_TIMER()
ON_WM_ERASEBKGND()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONDBLCLK()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//Optional: specify required priority for capturing
#ifdef CAPTURE_PRIORITY_CONTROL
#define UP_THR() {oldpr=GetThreadPriority(GetCurrentThread()); \
SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL);}
#define DN_THR() {SetThreadPriority(GetCurrentThread(),oldpr);}
#else
#define UP_THR()
#define DN_THR()
#endif
//granularity for testing
#define DEF_FRAMESIZE_GRAN_X 20 //pixels
#define DEF_FRAMESIZE_GRAN_Y 15 //pixels
#define NOW() timeGetTime()
#define PALSZ (sizeof(RGBQUAD))
#define _XXXX() (int)HIWORD(_formats[i])
#define CHECKWIN() {if(!GetSafeHwnd()) {iLastError=CAP_CALLNOWINDOW;return FALSE;}}
#define CHECKCNCT() {if(_curDriver==-1) {iLastError=CAP_CALLNOCONNECTION;return FALSE;}}
//some forward definitions
LRESULT FAR PASCAL _1FrameCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr);
LRESULT FAR PASCAL _defaultFrameCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr);
LRESULT FAR PASCAL _timerFrameCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr);
void _dumpHdr(LPBITMAPINFOHEADER);
// default notification strings
LPSTR lpNotify01= "Testing resolutions...";
LPSTR lpNotify02= "Seaching for NTSC formats...";
LPSTR lpNotify020="Seaching for PAL/SECAM formats...";
LPSTR lpNotify03= "Seaching for buffers...";
// static implementation
FRAMECALLBACK _UserFrameCallBack=NULL;
LPVIDEOHDR _lpLastVHdr = NULL;
DWORD _frameStarted = 0;
DWORD _frameDelta = 0;
BOOL _frameFinished = FALSE;
DWORD _bufferSize = 0;
int _InternalBufCnt = 0;
int oldpr;
//
// Constructor
//
CAviCap::CAviCap()
{
_selfInit();
}
CAviCap::~CAviCap()
{
Disconnect();
}
BOOL CAviCap::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, BOOL fAutoSize)
{
ASSERT(!GetSafeHwnd());
if(GetSafeHwnd()) {
iLastError=CAP_CREATE_DUP;
return FALSE; //already connected, can't connect twice!
}
_autosize = fAutoSize;
HWND hWnd=capCreateCaptureWindow("AviCap_Basic",
dwStyle, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
pParentWnd->GetSafeHwnd(), AVICAP_WINDOW_ID);
if(!hWnd)
{
TRACE("CAviCap Window creation failed\n");
iLastError=CAP_WINCREATION_FAILED;
return FALSE;
}
//subclass standard window
SubclassWindow(hWnd);
::SetClassLong(hWnd, GCL_STYLE, ::GetClassLong(hWnd,GCL_STYLE)|CS_DBLCLKS);
#ifdef ON_CONNECT_CHECK_DRIVERLIST
_getDrvList();
#endif
return TRUE;
}
//
// Connect with capture driver
// ==============================
// Important notes:
// Unfortunately, Capture drivers are always 16 bit programs.
// Because of this, driver will "locked" in memory after abnormal capture
// program termination. When this happens, we can't connect with capture driver again.
// There is no standard and simple way to make sure is this driver installed
// and "locked" or actually not exists or disabled. :-((((
//
BOOL CAviCap::ConnectWithDriver(LPCSTR Name)
{
_capAbort=FALSE;
if(!Name) // Connect to default Driver!
// N 1 in system list
return _connect2Driver(0);
//find
if(!_totalDrv())
{
iLastError=CAP_NO_CAPDEVICE_INSTALLED;
return FALSE;
}
for(int i=0;i<_totalDrv();i++)
if(lstrcmp(Name,_drvNames[i])==0 )
return _connect2Driver(i);
iLastError=CAP_DRIVERNAME_NOT_FOUND;
return FALSE;
}
// Connect with capture driver
// ==============================
// Same as previouse, but use index from system list
BOOL CAviCap::ConnectWithDriver(int indx)
{
if(indx == ANY_DRIVER)
indx=0;
return _connect2Driver(indx);
}
//
// Get capture device summary
// Return TRUE if OK
//
BOOL CAviCap::GetDriverInfo(CAPDRVINFO *cdi)
{
CHECKCNCT();
if(!cdi) return FALSE;
lstrcpy(cdi->psName,GetDriverName());
cdi->dwInternalBufCnt= _internalBufCnt;
cdi->dwCurBiBitCount = ((LPBITMAPINFOHEADER)_bmpInfo)->biBitCount;
cdi->dwBiBitsCountSupported=_biBitsCountSupported;
cdi->dwCompressed =((LPBITMAPINFOHEADER)_bmpInfo)->biCompression;
cdi->szFrameSize.cx=(int)((LPBITMAPINFOHEADER)_bmpInfo)->biWidth;
cdi->szFrameSize.cy=(int)((LPBITMAPINFOHEADER)_bmpInfo)->biHeight;
cdi->fFormatDlgSup=_capDriverCaps.fHasDlgVideoFormat;
cdi->fSourceDlgSup=_capDriverCaps.fHasDlgVideoSource;
cdi->fDisplayDlgSup=_capDriverCaps.fHasDlgVideoDisplay;
cdi->fNTSC = FALSE;//default == PAL
//NB: valid NTSC formats : 640x480, 320x240, 160x120 etc.
// valid PAL formats : 768x576, 384x288, 196x144 etc.
#define FX cdi->szFrameSize.cx
if(_formats.GetSize())
{
for(int i=0;i<_formats.GetSize();i++)
//any from follow
if(_XXXX()==320||_XXXX()==640||_XXXX()==160||_XXXX()==400)
{cdi->fNTSC =TRUE; break;}
}
else
if(FX==320||FX==640||FX==160||FX==400)
cdi->fNTSC =TRUE;
return TRUE;
}
// Disconnection
// No comments
BOOL CAviCap::Disconnect()
{
CHECKWIN();
CHECKCNCT();
capSetCallbackOnFrame(GetSafeHwnd(), NULL);
capSetCallbackOnVideoStream(GetSafeHwnd(), NULL);
StartSeq(FALSE);
if(_curDriver!=-1&&GetSafeHwnd())
if(capDriverDisconnect(GetSafeHwnd()))
_curDriver=-1;
if(_bmpInfo) {delete _bmpInfo;
_bmpInfo=NULL;}
if(_curDriver==-1)
return TRUE;
else return FALSE;
}
//
// Standard AVIcap window message
// macro: capPreview
BOOL CAviCap::StartPreview(BOOL offOn)
{
CHECKWIN();
CHECKCNCT();
if(_fPreviewIsOn==offOn) return TRUE;
if(capPreview(GetSafeHwnd(), offOn))
{
_fPreviewIsOn=offOn;
return TRUE;}
return FALSE;
}
// Standard AVIcap window message
// macro: capOverlay
BOOL CAviCap::StartOverlay(BOOL offOn)
{
CHECKWIN();
CHECKCNCT();
if(_fOverlayIsOn==offOn) return TRUE;
if(capOverlay(GetSafeHwnd(), offOn))
{_fOverlayIsOn=offOn;return TRUE;}
return FALSE;
}
// Standard AVIcap window message
// macro: capCaptureSequenceNoFile && capCaptureStop
BOOL CAviCap::StartSeq(BOOL offOn)
{
CHECKWIN();
CHECKCNCT();
if(offOn)
{
if(_fSeqIsOn) return TRUE;
_getSetup();
_captureParms.fYield = TRUE; // Watch out!
_setSetup();
return capCaptureSequenceNoFile(GetSafeHwnd()) ;
}
if(_fSeqIsOn)
capCaptureStop(GetSafeHwnd());
_fSeqIsOn=offOn;
return TRUE;
}
//
// Clean up internal driver cache(if exists)
// Just grab and do not call users callback
void CAviCap::ResetCache()
{
if(!GetSafeHwnd()||
_curDriver==-1 ||
_internalBufCnt<2) return;
//disable user callback
FRAMECALLBACK ofc = _UserFrameCallBack;
_UserFrameCallBack = NULL;
for(int i=0;i<_internalBufCnt;i++)
capGrabFrameNoStop(GetSafeHwnd());
_UserFrameCallBack =ofc;
}
// Capture single frame.
// You must install frame callback using SetFrameCallBack method
// if you need image buffer
BOOL CAviCap::GrabOneFrame()
{
CHECKWIN();
CHECKCNCT();
_capAbort=FALSE;
#ifdef DEFAULT_FORCE_SINGLE_FRAME
if(!_UserFrameCallBack) return FALSE;
_frameFinished = FALSE;
_frameStarted = 0;
_InternalBufCnt=_internalBufCnt;
UP_THR()
for(int i=0;i<MAX_VALID_BUFFERS_COUNT;i++)
{
if(_capAbort) {_capAbort=FALSE; break;}
capGrabFrameNoStop(GetSafeHwnd());
if(_frameFinished) {
DN_THR();
return TRUE;}
}
DN_THR()
return FALSE;
#else