void create_video()
{
CRect rc;
CBitmap m_mem_bmp;
BITMAP m_bit_map;
CDC* pDeskDC = NULL;
CDC m_mem_dc;
pDeskDC = m_pWnd->GetDC();
m_pWnd->GetClientRect(rc);
m_mem_dc.CreateCompatibleDC(pDeskDC);//创建一个兼容的画布
m_mem_bmp.CreateCompatibleBitmap(pDeskDC,rc.Width(),rc.Height());//创建兼容位图
m_mem_dc.SelectObject(&m_mem_bmp);//选中位图对象
m_mem_bmp.GetBitmap(&m_bit_map);
m_mem_dc.BitBlt(0,0,m_bit_map.bmWidth,m_bit_map.bmHeight,pDeskDC,0,0,SRCCOPY);
DWORD size = m_bit_map.bmWidthBytes * m_bit_map.bmHeight;//屏幕图像的总像素数
BYTE* lpData = new BYTE[size];
//记录调色板大小
int panelsize = 0;
//判断是否为真彩色位图
if(m_bit_map.bmBitsPixel < 16)
panelsize = (int)pow((long double)2,(long double)m_bit_map.bmBitsPixel * sizeof(RGBQUAD));
//定义位图信息头结构体
BITMAPINFOHEADER *pBInfo = new BITMAPINFOHEADER;
//初始化位图信息头
pBInfo->biSize = sizeof(BITMAPINFOHEADER);
pBInfo->biWidth = m_bit_map.bmWidth;
pBInfo->biHeight = m_bit_map.bmHeight;
pBInfo->biPlanes = m_bit_map.bmPlanes;
pBInfo->biBitCount = m_bit_map.bmBitsPixel;
pBInfo->biCompression = 0;
pBInfo->biSizeImage = m_bit_map.bmWidthBytes * m_bit_map.bmHeight;
pBInfo->biXPelsPerMeter = 0;
pBInfo->biYPelsPerMeter = 0;
pBInfo->biClrImportant = 0;
//定义位图信息结构体
BITMAPINFO bInfo;
bInfo.bmiHeader = *pBInfo;//初始化
GetDIBits(m_mem_dc.m_hDC,m_mem_bmp,0,pBInfo->biHeight,lpData,&bInfo,DIB_RGB_COLORS);
HRESULT hr;
//如果是第一帧
if(0x00 == m_nframes)
{
CString vide_fname = convert_string_ex(m_fname);
int av_ret = AVIFileOpen(&pfile,vide_fname,OF_WRITE | OF_CREATE,NULL);
if(av_ret != 0x00)
{
APP_LOG("AVIFileOpen create failed ......");
return ;
}
//初始化信息头为0
memset(&strhdr, 0, sizeof(strhdr));
if(m_dwrate <= 0x00)
m_dwrate = 21;
//初始化AVI视频流信息结构体
strhdr.fccType = streamtypeVIDEO;
strhdr.fccHandler = 0;
strhdr.dwScale = 1;
strhdr.dwRate = m_dwrate;
strhdr.dwSuggestedBufferSize = pBInfo->biSizeImage;
SetRect(&strhdr.rcFrame,0,0,pBInfo->biWidth,pBInfo->biHeight);
{
APP_LOG("[CAPTURE ###########============] DWRATE:%d",strhdr.dwRate);
}
//创建AVI文件流
hr = AVIFileCreateStream(pfile,&ps,&strhdr);
AVICOMPRESSOPTIONS FAR * opts[1] = {&pCompressOption};
opts[0]->fccType = streamtypeVIDEO;
opts[0]->fccHandler = mmioStringToFOURCC(L"MSVC", 0);
opts[0]->dwKeyFrameEvery = 200;
opts[0]->dwQuality = 10000;
opts[0]->dwBytesPerSecond = 0;
opts[0]->dwFlags = AVICOMPRESSF_VALID || AVICOMPRESSF_KEYFRAMES;
opts[0]->lpFormat = 0;
opts[0]->cbFormat = 0;
opts[0]->dwInterleaveEvery = 0;
hr = AVIMakeCompressedStream(&pComStream,ps,&pCompressOption,NULL);
hr = AVIStreamSetFormat(pComStream,0,pBInfo,sizeof(BITMAPINFOHEADER));
delete pBInfo;
delete [] lpData;
}
else
{
av_data_struct* av_obj = new av_data_struct();
av_obj->avi_stream = lpData;
av_obj->head = pBInfo;
av_obj->number = m_nframes;
m_av_data_ve.push_back(av_obj);
}
m_nframes++;
}
void save_video()
{
if(m_av_data_ve.empty())
return ;
av_data_struct* obj = m_av_data_ve.front();
m_av_data_ve.pop_front();
if(obj && obj->avi_stream && obj->head && obj->number >= 0x00)
AVIStreamWrite(pComStream,obj->number ,1,(LPBYTE)obj->avi_stream,
obj->head->biSizeImage,AVIIF_KEYFRAME,NULL,NULL);
delete obj;
}
注:m_av_data_ve为数据队列,save_video作为独立的线程保存图片数据到文件 问题:当前遇到的问题主要是和之前发布的音频录制的音频文件不同步,太专业的问题。 有个偷懒的办法,如果按照每秒25帧左右的速度存取,在单独的线程中调用create_video函数来制造数据,利用类似 WaitForSingleObject(m_event_handle,wait_val),来反复调用create_video。wait_val的数值大约可以定在40左右,表示40毫秒。 如: class time_counter { public: time_counter();//在构造函数内部保存当前时间 long get_span();//计算当前时间,并与m_span计算时间差,毫秒级别 private: long m_span; };
LONG fun_create_video_thread(LPARAM param) { CVideoApp* pObj = (CVideoApp*)param; if(NULL == pObj) return 0x01;
long index = 0x00;
int wait_val = 40; bool b_wait = true; while(1) {
if(b_wait) ::WaitForSingleObject(pObj->m_ev_handle,wait_val); if(pObj->m_b_start == false) break; { time_counter tobj; pObj->create_video(); b_wait = (tobj.get_span() <= wait_val) ; } } return 0x00; }
这样做之后能够适当的减少误差 如果想做到真正的同步,可以在网上查找相关开源软件进行代码研究