在上一篇里,简单介绍了windows VFW库的情况,使用VFW处理还是比较简单的,但是也非常不容易控制,而且,即便仔细看文档的介绍,还是要摸着石头过河。
在CodeForge网站上搜了好长时间,总算从网上找到一个以前人写的 VFWImage的工具类,算是完整封装了VFW的宏和API,于是我把我的项目中,和图像、视频采集的程序使用这个类重写了,重写之后,的确控制起来方便多了。
现在把这个类附上,有需要的朋友可以直接下载来使用,使用方式以后慢慢贴上来吧。
使用这个类,可以非常简单,做到在一个窗口(可以是对话框或各类控件)中显示采集到的活动图像,在用户选择“拍照”时,用上一篇博文中的保存JPG的方法,即可保存为JPG图片。
视频的录制稍微麻烦一些,普通的做法,使用VFW 宏,支持直接保存视频文件,但是只支持AVI(太大了),即便设置的压缩和品质很低,15秒还是能达到10M~20M,受不了。最可恶的是,调用VFW录制时,还会向C盘根目录下写一个视频文件??!!
这里我想了一个办法,也许是笨办法,希望朋友们能有以教我一些更好的方法。
不开启VFW的保存视频功能,只打开活动图像的预览。
启动一个线程,在线程中,一张一张采集图像,将图像写入AVI(虽然还是AVI,但是经过处理,不会太大)
从开始采集起始,开始录音,视频采集完成,停止录音,录音写入WAV
将AVI和WAV合成新的AVI
直接上示例:
HWND hWnd=pDlg->m_VFWImageProc.GetCapWindow(); CString myfname("e:\\new12222.avi"); HDC hDisplayDC = GetDC(hWnd); CAVI Avi; CString csPathName; CString csTempPath; //没有声音的AVI以及声音WAV保存在临时目录 TCHAR * pTempPath = csTempPath.GetBufferSetLength(MAX_PATH + 1); GetTempPath(MAX_PATH + 1,pTempPath); csTempPath.ReleaseBuffer(); TCHAR * pTempFile = csPathName.GetBufferSetLength(MAX_PATH + 1); GetTempFileName(csTempPath,_T("FRC"),0,pTempFile); csPathName.ReleaseBuffer(); CFileStatus FileStatus; if (CFile::GetStatus(csPathName,FileStatus)) CFile::Remove(csPathName); csPathName.Replace(_T(".tmp"),_T(".wav")); CString cswavFile = csPathName; //视频每秒的帧数 // Open for recording Avi.Open(10); // Setup capturing the screen int cxWidth = 0;//GetSystemMetrics(SM_CXVIRTUALSCREEN); int cyHeight = 0;//GetSystemMetrics(SM_CYVIRTUALSCREEN); RECT rr; ::GetWindowRect( hWnd,&rr); cxWidth = rr.right-rr.left; cyHeight = rr.bottom-rr.top; CRect DIBRect = CRect(0,0,cxWidth,cyHeight); // Device dependent bitmap CDIBFrame DIB(0,0,8); DIB.Init(cxWidth,cyHeight); //录音 MCIDEVICEID id=0; MCI_OPEN_PARMS open; open.lpstrDeviceType=(LPCSTR)MCI_DEVTYPE_WAVEFORM_AUDIO; open.lpstrElementName=_T(""); open.wDeviceID=id; mciSendCommand(NULL,MCI_OPEN,MCI_WAIT|MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID |MCI_OPEN_ELEMENT, (DWORD)(LPVOID)&open); id=open.wDeviceID; MCI_RECORD_PARMS record; mciSendCommand(id,MCI_RECORD,NULL,(DWORD)(LPVOID)&record); //开始图像采集 int frames=0; //for (int iFrame = 1;iFrame <= 150;++iFrame) //外部在需要时停止录制 while( !stopped ) { // Capture the desktop BitBlt(DIB,0,0,DIBRect.Width(),DIBRect.Height (),hDisplayDC,DIBRect.left,DIBRect.top,SRCCOPY); // Add a frame Avi.AddFrame(DIB); //每隔100毫秒采集1此,也就是每秒10帧 Sleep(100); frames++; } CString filename; MCI_SAVE_PARMS save; save.lpfilename=cswavFile;// "e:\\t1111.wav";// cswavFile;//_T( fname+"_wav.wav" ); mciSendCommand(id,MCI_SAVE,MCI_SAVE_FILE|MCI_WAIT,(DWORD)(LPVOID)&save); mciSendCommand(id,MCI_CLOSE,NULL,NULL); CString csaviFile = Avi.Close(); // Delete the dc's ReleaseDC(hWnd,hDisplayDC); 合并AVI和WAV Merge_Video_And_Sound_File( csaviFile,cswavFile, myfname ); |
大体上就是这样,其中使用到了一个CAVI的类,如果有需要的情给我留言,留下邮箱即可。