抓取屏幕保存为AVI文件

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; }

这样做之后能够适当的减少误差
 
如果想做到真正的同步,可以在网上查找相关开源软件进行代码研究


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值