www.gusucode.com > 一个可以在局域网进行视频聊天的源代码 > 一个可以在局域网进行视频聊天的源代码/VoIP/VideoCapture.cpp

    ////////////////////////////////////////////////////////////////////////////
//
//
//    Project     : VideoNet version 1.1.
//    Description : Peer to Peer Video Conferencing over the LAN.
//	  Author      :	Nagareshwar Y Talekar ( nsry2002@yahoo.co.in)
//    Date        : 15-6-2004.
//
//
//    File description : 
//    Name    :  VideoCapture.cpp
//    Details :  Captures the frames from webcam.
//
//
/////////////////////////////////////////////////////////////////////////////


#include "Stdafx.h"
#include "VideoCapture.h"

#include <afxmt.h>


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#pragma comment(lib,"vfw32")
#pragma comment(lib,"winmm")


// Global varialbes...
int count=0;
unsigned char cdata[10000];
int cbuffer_size=10000;
unsigned char rgbdata[80000];
int buffersize=80000;

// Callback function gets invoked during compression...
// It returns the compressed data byte by byte...
void OwnWriteFunction(int byte)
{
	if(count<cbuffer_size)
		cdata[count]=(unsigned char)byte;
	
	count++;
	
}


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

VideoCapture::VideoCapture()
{
	m_capwnd			= NULL;
	isOver				= FALSE;
	m_OnCaptureVideo	= NULL;
	
	log.Open("videocapture.log",CFile::modeCreate | CFile::modeWrite);
}


VideoCapture::~VideoCapture()
{
}


BOOL VideoCapture::Initialize()
{
	char devname[100],devversion[100];
	char str[200];
	int index=0;
	
	// 初始化压缩编码器
	InitCompressor();
	
	// 创建摄像头句柄
	m_capwnd = capCreateCaptureWindow("Capture",WS_POPUP,0,0,1,1,0,0);
	if(m_capwnd==NULL)
	{
		log.WriteString("\n Unable to create capture window");
		return FALSE;
	}

	// 连接摄像头设备	
	capSetUserData( m_capwnd, this );
	
	// 显示视频设置对话框,进行配置视频的大小、颜色位数等。
	capDlgVideoFormat( m_capwnd );

	// 取得视频图像数据头,后面压缩时需要用到
	capGetVideoFormat( m_capwnd, &m_bmpinfo, sizeof(BITMAPINFO) );
	
	// 设置回调函数
	capSetCallbackOnVideoStream( m_capwnd, OnCaptureVideo );
	
	capGetDriverDescription(index,devname,100,devversion,100);
	
	sprintf(str,"\n Driver name = %s version = %s ",devname,devversion);
	log.WriteString(str);
	
	// Connect to webcam driver
	if( ! capDriverConnect(m_capwnd,index) )
	{
		
		// Device may be open already or it may not have been
		// closed properly last time.
		AfxMessageBox("Unable to open Video Capture Device");
		log.WriteString("\n Unable to connect driver to the window");
		m_capwnd=NULL;
		return FALSE;
	}
	
	// Set the capture parameters
	if(SetCapturePara()==FALSE)
	{
		log.WriteString("\n Setting capture parameters failed");
		capDriverDisconnect(m_capwnd);
		return FALSE;
	}


	return TRUE;
}




/**
*   Start capturing frames from webcam
*
*/

BOOL VideoCapture::StartCapture(HDC	BackDC)
{
	m_LocalScreenDC	= BackDC;
	
	// 初始化视频回放对象
	m_hdib	= ::DrawDibOpen();
	if( m_hdib != NULL )
	{
		::DrawDibBegin(
			m_hdib,
			m_LocalScreenDC,
			-1,				// don't stretch
			-1,				// don't stretch
			&m_bmpinfo.bmiHeader,
			IMAGE_WIDTH,         // width of image
			IMAGE_HEIGHT,        // height of image
			0				
			);
	}
	
	// 开始视频采集
	if(capCaptureSequenceNoFile(m_capwnd)==FALSE)
	{
		log.WriteString("\n Failed to capture Sequence ..");
		return FALSE;
	}
	
	return TRUE;
	
}





/**
*   Stop the capturing process
*
*/

BOOL VideoCapture::StopCapture()
{
	
	capCaptureStop(m_capwnd);
	capCaptureAbort(m_capwnd);
	Sleep(500);	
	
	return TRUE;
}






/**
*   Stop the catpure process and disconnect the driver
*
*/
void VideoCapture::Destroy()
{
	
	if(m_capwnd==NULL) return;
    
    // Stop the capturing process    
	capCaptureAbort(m_capwnd);
	
    // Disable the callback function..
	capSetCallbackOnVideoStream(m_capwnd, NULL);
	
	Sleep(300);		// This delay is important...
	
	// Finally disconnect the driver
    capDriverDisconnect(m_capwnd);
}








/**
*
*     Set various capture parameters...
*
*/

BOOL  VideoCapture::SetCapturePara()
{
	CAPTUREPARMS CapParms={0};	
	
	
	capCaptureGetSetup(m_capwnd,&CapParms,sizeof(CapParms));
	
	CapParms.fAbortLeftMouse = FALSE;
	CapParms.fAbortRightMouse = FALSE;
	CapParms.fYield = TRUE;
	CapParms.fCaptureAudio = FALSE;
	CapParms.wPercentDropForError = 50;
	CapParms.dwRequestMicroSecPerFrame = (DWORD) ( 1.0e6 / 15.0 );
	
	if(capCaptureSetSetup(m_capwnd,&CapParms,sizeof(CapParms))==FALSE)
	{
		log.WriteString("\n Failed to set the capture parameters ");
		return FALSE;
	}
	
	// Set Video Format 
	
	capGetVideoFormat(m_capwnd,&m_bmpinfo,sizeof(m_bmpinfo));
	
	m_bmpinfo.bmiHeader.biWidth=IMAGE_WIDTH;
	m_bmpinfo.bmiHeader.biHeight=IMAGE_HEIGHT;
	
	BOOL ret=capSetVideoFormat(m_capwnd,&m_bmpinfo,sizeof(m_bmpinfo));
	
	if(ret==TRUE)
		log.WriteString("\n Video parameters set properly");
	
	return TRUE;
}




/**
*
*  Allocate Memory for DIB image buffer
* 
*/

int VideoCapture::AllocateMemory(PBITMAPINFO &bmpinfo)
{
	int size1,size2,size;
	BITMAPINFO tbmp;
	char  str[200];
	
	capGetVideoFormat(m_capwnd,&tbmp,sizeof(tbmp));
	
	size1 = getFormatSize ( tbmp );
	size2 = getImageSize ( tbmp );
	size = size1 + size2;
	
	
	sprintf(str,"\n Formatsize = %d imagesize = %d , fun_size = %d ",
		size1,size2, capGetVideoFormatSize(m_capwnd));
	log.WriteString(str);
	
	bmpinfo=(BITMAPINFO *) new BYTE[size];
	
	
	if(bmpinfo==NULL)
	{
		AfxMessageBox("Unable to allocate memory");
		return -1;
	}
	
	memset(bmpinfo,0,sizeof(*bmpinfo));
	
	capGetVideoFormat(m_capwnd,bmpinfo,sizeof(*bmpinfo));
	return size1;
}




/**
*
*   Calculates the Format Size for DIB image
*
*/

int VideoCapture::getFormatSize(BITMAPINFO bmp)
{
	int size;
	size=(bmp.bmiHeader.biSize!=0)?bmp.bmiHeader.biSize :sizeof(BITMAPINFOHEADER);
	
	//return (size+ bmp.bmiHeader.biClrUsed *sizeof(RGBQUAD));
	
	return size; //RGBQUAD is absent for 24 bit bmp image.
}



/**
*	Calculates the Size of Image
*
*/

int VideoCapture::getImageSize(BITMAPINFO bmp)
{
	int size;
	BITMAPINFOHEADER head=bmp.bmiHeader;
	
	
	if( head.biSizeImage==0 )
	{
		size=( head.biWidth * head.biHeight * head.biBitCount)/8;
	}
	else
		size = head.biSizeImage;
	
	return size;
	
}


//////////////////////////////////////////////////////////////////////////
//
// 设置采集数据回调接口
//
void VideoCapture::SetOnCaptureVideoCallback(CALLBACKFUNC OnCaptureVideo, void* pParam)
{
	m_OnCaptureVideo	= OnCaptureVideo;
	m_pParam			= pParam;
}

/**
*    Invoked when the video frame is captured by the driver
*
*
*/

LRESULT CALLBACK OnCaptureVideo(HWND mwnd,LPVIDEOHDR lphdr)
{
	
	VideoCapture *vidcap=(VideoCapture *)capGetUserData(mwnd);
	
	if( vidcap!=NULL )
	{
		vidcap->DrawLocalScreen( lphdr );
		vidcap->CompressFrame( lphdr );
//		if ( vidcap->m_OnCaptureVideo != NULL )
//		{
//			(*vidcap->m_OnCaptureVideo)( mwnd, lphdr );
//			vidcap->DrawLocalScreen( lphdr );
//			vidcap->CompressFrame( lphdr );
//		}
	}
	
	return TRUE;
}


void VideoCapture::CompressFrame(LPVIDEOHDR lphdr)
{
//	BOOL		bKeyFrame;
//	DWORD		OutActSize;
//	BYTE*		Buf;
//	
//	OutActSize	= m_bmpinfo.bmiHeader.biSizeImage;
//	bKeyFrame	= 0;
//	
//	Buf			= (BYTE*)ICSeqCompressFrame( &m_CV,0,lphdr->lpData,&bKeyFrame,(long*)&OutActSize);

	Bits bits;		// Various count about compression

	//Convert the data from rgb format to YUV format	
	ConvertRGB2YUV( IMAGE_WIDTH,IMAGE_HEIGHT, lphdr->lpData, yuv );

	// Reset the counter
	count=0;
	
	// 压缩数据
	cparams.format=CPARAM_QCIF;
	cparams.inter = CPARAM_INTRA;  
	cparams.Q_intra = 8;
	cparams.data=yuv;		//  Data in YUV format...
	::CompressFrame(&cparams, &bits);

	// 传送数据
	m_pCommClient->SendPacket( (char*)cdata, count, PACKET_VIDEO );
}

void VideoCapture::InitCompressor()
{
//    memset( &m_CV,0,sizeof(COMPVARS) );
//	m_CV.cbSize		= sizeof( m_CV );
//	ICCompressorChoose( m_capwnd, 0, NULL, NULL, &m_CV, "Choose a Compressor" );
	
	// Initialize table for RGB to YUV conversion
	InitLookupTable();

	// Initialize the compressor
	cparams.format = CPARAM_QCIF;
	InitH263Encoder(&cparams);

	// Set up the callback function
	WriteByteFunction = OwnWriteFunction;
	
	// Initialize decompressor
	InitH263Decoder();
	
	return;
}

//////////////////////////////////////////////////////////////////////////
//
// 回放本地视频
//
void VideoCapture::DrawLocalScreen(LPVIDEOHDR lphdr)
{
	::DrawDibDraw(
		m_hdib,
		m_LocalScreenDC,
		0,		// dest : left pos
		0,		// dest : top pos
		-1,					 // don't zoom x
		-1,					 // don't zoom y
		&m_bmpinfo.bmiHeader,			 // bmp header info
		lphdr->lpData,					 // bmp data
		0,					 // src :left
		0,					 // src :top
		IMAGE_WIDTH,				 // src : width
		IMAGE_HEIGHT,				 // src : height
		DDF_SAME_DRAW			 // use prev params....
		);
}

//////////////////////////////////////////////////////////////////////////
//
// 设置通信接口
//
void VideoCapture::SetCommClient(CCommClient *pClient)
{
	m_pCommClient	= pClient;
}

//////////////////////////////////////////////////////////////////////////
//
// 回放远程视频
//
void VideoCapture::DrawRemoteScreen(char *data, UINT size, HDC hScreenDC)
{
	int			iErrorCode;
	int			iDataSize;
	u_char*		upData;

	iDataSize	= size;
	upData		= (u_char*)data;

	iErrorCode	= DecompressFrame( upData, iDataSize, rgbdata, buffersize );

	if ( iErrorCode == 0 ) return;

	::DrawDibDraw(
		m_hdib,
		hScreenDC,
		0,		// dest : left pos
		0,		// dest : top pos
		-1,					 // don't zoom x
		-1,					 // don't zoom y
		&m_bmpinfo.bmiHeader,			 // bmp header info
		rgbdata,					 // bmp data
		0,					 // src :left
		0,					 // src :top
		IMAGE_WIDTH,				 // src : width
		IMAGE_HEIGHT,				 // src : height
		DDF_SAME_DRAW			 // use prev params....
		);
}