分享

VC++关于的VFW视频采集方案(续)

 涉水I 2011-05-07

2.2.6  视频录像设计方案

在VFW中,可以有3种方式实现视频录像。其中,最简单的方式是调用capFileSetCaptureFile函数和capCaptureSequence函数。该种方式存在许多缺点,例如,在录像时无法响应用户界面,无法实现视频压缩等。第二种方式是调用capCaptureSetSetup函数,将CAPTUREPARMS结构的fYield成员设置为TRUE,启动后台线程来实现录像,然后调用capDlgVideoCompression函数让用户选择压缩器进行压缩,最后调用capFileSetCaptureFile函数和capCaptureSequence函数开始录像。第二种方式的缺点是每次录像时都需要弹出一个对话框,让用户选择一种压缩器。第三种方式是注册回调函数capSetCallbackOnVideoStream,在回调函数中压缩数据并写入AVI文件。相对于前两种方式,第三种方式更为灵活和实用,因此在进行视频录像时,通常采用该种方式实现。具体实现过程如下:

(1)定义一个回调函数,该回调函数实现数据压缩,并将压缩的数据写入文件流中。

(2)调用capSetCallbackOnVideoStream注册回调函数。

(3)调用ICOpen函数打开一个压缩器,并调用ICCompressBegin函数开始压缩。

(4)调用AVIFileOpen函数打开一个AVI文件,并调用AVIFileCreateStream函数创建文件流。

(5)调用capCaptureSequenceNoFile函数开始录像。

下面以一个具体实例介绍如何采用第三种方式实现视频录像。效果如图2.8所示。

 

图2.8  视频录像设计方案

  实例位置光盘mr.2.2.6

(1)创建一个基于对话框的工程,在对话框中添加按钮、图像控件,如图2.9所示。

 

图2.9  对话框资源设计

(2)在对话框的头文件中引用“vfw.h”头文件,并导入“vfw32.lib”库文件。

#include "vfw.h"

#pragma comment (lib,"vfw32")

(3)向对话框类中添加成员变量。

DWORD           m_Frame;              //记录帧数

COMPVARS        m_Com;                //压缩参数

BITMAPINFO     m_InInfo,m_OutInfo; //位图格式

PAVIFILE        m_pFile;              //AVI文件

AVISTREAMINFO  strhdr;               //AVI流信息

PAVISTREAM      ps;                   //AVI流指针

BOOL             m_Captured;          //是否开始捕捉

(4)定义一个回调函数,在流捕捉时执行。

LRESULT WINAPI EncodeCallback(HWND hWnd, LPVIDEOHDR lpVHdr)

{

   CVideoEncodeDlg* pDlg = (CVideoEncodeDlg*)AfxGetMainWnd();

   if ((pDlg->m_Captured) && (lpVHdr->dwFlags&VHDR_DONE))

   {

       char* buffer = new char [lpVHdr->dwBytesUsed+1];

       memset(buffer,0,lpVHdr->dwBytesUsed+1);

       DWORD dwCkID         ;

       DWORD dwCompFlags    ;

       DWORD dwQuality = 100;

      

       //视频压缩

       if (ICCompress(pDlg->m_Com.hic, 0, &pDlg->m_OutInfo.bmiHeader, buffer,

 &pDlg->m_InInfo.bmiHeader,

              (unsigned char *)lpVHdr->lpData, &dwCkID, &dwCompFlags,

 pDlg->m_Frame++,0, dwQuality, NULL, NULL) == ICERR_OK)

       {

              AVIStreamSetFormat(pDlg->ps,pDlg->m_Frame,&pDlg->m_OutInfo,

sizeof(pDlg->m_OutInfo));

              AVIStreamWrite(pDlg->ps,pDlg->m_Frame ,1, (LPBYTE)  buffer,

pDlg->m_OutInfo.bmiHeader.biSizeImage ,AVIIF_KEYFRAME,NULL,NULL);

       }

       delete []buffer;

   }

    return 1;

}

(5)在对话框初始化时开始视频预览,设置视频参数。

m_Captured = FALSE;

m_hWndVideo = capCreateCaptureWindow(NULL,WS_POPUP,1,1,10,10,m_hWnd,0);

//连接驱动程序

if (capDriverConnect(m_hWndVideo,0))

   ::SetParent(m_hWndVideo,*this);

   ::SetWindowLong(m_hWndVideo,GWL_STYLE,WS_CHILD);

   CRect wndRC;

   m_Panel.GetClientRect(wndRC);

   m_Panel.MapWindowPoints(this,wndRC);

   wndRC.DeflateRect(1,1,1,1);

   ::SetWindowPos(m_hWndVideo,NULL,wndRC.left,wndRC.top,wndRC.Width(),

wndRC.Height(),SWP_NOZORDER);

   ::ShowWindow(m_hWndVideo,SW_SHOW);

   CAPDRIVERCAPS caps;

   capDriverGetCaps(m_hWndVideo,sizeof(caps),&caps);

   if (caps.fHasOverlay)

       capOverlay(m_hWndVideo,TRUE);

   CAPTUREPARMS params;

   capCaptureGetSetup(m_hWndVideo,¶ms,sizeof(params));

   params.fYield           = TRUE;

   params.fAbortLeftMouse  = FALSE;

   params.fAbortRightMouse = FALSE;

   params.fLimitEnabled    = FALSE;

   params.vKeyAbort        = FALSE;

   params.fCaptureAudio    = FALSE;

  

   capCaptureSetSetup(m_hWndVideo,¶ms,sizeof(params));

   capSetCallbackOnVideoStream(m_hWndVideo,EncodeCallback);

   capPreviewRate(m_hWndVideo,30);

   capPreview(m_hWndVideo,TRUE);

}

(6)向对话框中添加InitCompress方法,设置压缩参数信息。

void CVideoEncodeDlg::InitCompress()

{

   capGetVideoFormat(m_hWndVideo,&m_InInfo ,sizeof(BITMAPINFO));

   capGetVideoFormat(m_hWndVideo,&m_OutInfo,sizeof(BITMAPINFO));

   memset(&m_Com,0,sizeof(COMPVARS)); 

   m_Com.cbSize=sizeof(m_Com);

   //利用代码选择压缩器

   m_Com.dwFlags=ICMF_COMPVARS_VALID; 

   m_Com.fccHandler=mmioFOURCC('x','v','i','d');

   m_Com.fccType=ICTYPE_VIDEO;  

   m_Com.lFrame=0;  

   m_Com.lKey=15;  

   m_Com.lKeyCount=0; 

   m_Com.lDataRate = 780;

   m_Com.lpbiOut=(BITMAPINFO*)&m_OutInfo;  

   m_Com.hic= ICOpen(ICTYPE_VIDEO,mmioFOURCC('x','v','i','d'),ICMODE_COMPRESS);

   m_Com.cbState = 1180;

   //利用对话框选择压缩器

   // ICCompressorChoose(NULL,ICMF_CHOOSE_ALLCOMPRESSORS ,

(LPVOID)&m_InInfo,NULL,&m_Com,"选择压缩类型");

   ICCompressGetFormat(m_Com.hic,&m_InInfo.bmiHeader,&m_OutInfo.bmiHeader);

   //开始压缩

   int ret = ICCompressBegin(m_Com.hic,(BITMAPINFO*)&m_InInfo,

(BITMAPINFO*)&m_OutInfo);

   if (ret!=ICERR_OK )

       MessageBox("压缩失败");

}

(7)处理“录像”按钮的单击事件,开始视频录像。

void CVideoEncodeDlg::OnOK()

{

   CString filename;

   CFileDialog FileDlg(FALSE,"avi");

   if (FileDlg.DoModal()==IDOK)

   {

       filename = FileDlg.GetPathName();

       capGetVideoFormat(m_hWndVideo,&m_InInfo,sizeof(m_InInfo));

       m_Frame = 0 ;

       //AVI文件初始化

       AVIFileInit() ;

       //设置压缩参数

       InitCompress();

       //打开文件

       AVIFileOpen(&m_pFile,filename,OF_WRITE | OF_CREATE,NULL);

       memset(&strhdr, 0, sizeof(strhdr)) ;

       strhdr.fccType    = streamtypeVIDEO;

       strhdr.fccHandler = 0  ;

       strhdr.dwScale    = 1  ;

       strhdr.dwRate     = 15 ;

       strhdr.dwSuggestedBufferSize = m_InInfo.bmiHeader.biSizeImage;

       SetRect(&strhdr.rcFrame, 0, 0, m_InInfo.bmiHeader.biWidth,

 m_InInfo.bmiHeader.biHeight);

       ps = NULL;

       //文件文件流

       AVIFileCreateStream(m_pFile,&ps,&strhdr);

       m_Captured = TRUE;

       //开始捕捉

       capCaptureSequenceNoFile(m_hWndVideo);

   }

}

(8)在对话框关闭时停止视频录像。

void CVideoEncodeDlg::OnCancel()

{

   //终止回调函数

   capSetCallbackOnVideoStream(m_hWndVideo,NULL);

   //结束数据压缩

   ICCompressEnd(m_Com.hic);

   //关闭压缩句柄

   ICClose(m_Com.hic);

   if (m_Captured)

   {

       //关闭AVI文件流

       AVIStreamClose(ps);

       if(m_pFile != NULL)

              AVIFileRelease(m_pFile);

       AVIFileExit();  

   }

   //停止捕捉

   capCaptureStop(m_hWndVideo);

   //断开驱动程序连接

   capDriverDisconnect(m_hWndVideo);

   CDialog::OnCancel();

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多