利用VC实现AVI文件的图像截取

来源:互联网 发布:360域名多少钱买的 编辑:程序博客网 时间:2024/05/23 19:10

avi->bmp:        
      void       CMyAviTttDlg::OnOK()            
      {        
      //SetTimer       (       1,       1000,       NULL)       ;        
      //   CString       strOpenFileType       =       "位图文件       (*.bmp;*.dib)|*.bmp;        
      //   *.dib|All       Files       (*.*)|*.*||";        
      //打开avi视频文件        
      CFileDialog       FileDlg(TRUE,       "*.avi",       NULL,            
      OFN_HIDEREADONLY       |       OFN_OVERWRITEPROMPT,            
      _T("视频文件(*.avi)|*.avi|"));        
      CString       m_avifile;        
      if(FileDlg.DoModal()       ==       IDOK){        
           
      m_avifile=FileDlg.GetPathName();        
           
      //初始化,以及提取信息        
                      PAVIFILE       pfile;//Pointer       to       a       buffer       that       receives       the       new       IAVIFile       interface       pointer.        
      AVIFILEINFO           pfi;        
      PAVISTREAM           pavi;        
      PGETFRAME       pgf;        
      long       length,       start;        
           
      //initializes       the       AVIFile       library,同AVIFileExit()对应。        
      //Call       AVIFileInit()       before       using       any       other       AVIFile       functions        
      AVIFileInit();        
      AVIFileOpen(&pfile,m_avifile,OF_READ|OF_SHARE_DENY_NONE,NULL);        
           
      //obtains       information       about       an       AVI       file        
      AVIFileInfo(pfile,&pfi,sizeof(AVIFILEINFO));        
      AVIFileGetStream(pfile,&pavi,streamtypeVIDEO,0);        
      length=AVIStreamLength(pavi);        
      start=AVIStreamStart(pavi);        
           
      AVISTREAMINFO       si;        
      AVIStreamInfo(pavi,       &si,       sizeof(si));        
           
      pgf       =       AVIStreamGetFrameOpen(pavi,       NULL);        
      //先获取第一帧        
      LPBITMAPINFOHEADER       bmp1;        
      bmp1=       (LPBITMAPINFOHEADER)AVIStreamGetFrame(pgf,       1);        
      CClientDC       dc(this);        
           
      //定义位图信息头和文件头        
      BITMAPINFOHEADER       bmih;        
                      memset(&bmih,0,sizeof(BITMAPINFOHEADER));        
      bmih.biBitCount=bmp1->biBitCount;        
      bmih.biSize       =       sizeof(BITMAPINFOHEADER);        
      bmih.biWidth       =       pfi.dwWidth;        
      bmih.biHeight       =       pfi.dwHeight;        
      bmih.biPlanes       =bmp1->biPlanes;        
      bmih.biCompression       =BI_RGB;        
      bmih.biXPelsPerMeter       =       0;        
      bmih.biYPelsPerMeter       =       0;        
           
      BITMAPFILEHEADER       bmfh;        
                      bmfh.bfSize       =       sizeof(bmfh);        
                      bmfh.bfOffBits       =       sizeof(bmfh)       +       sizeof(bmih);        
                      bmfh.bfType       =       (int)'M'       *       256       +       'B';        
                      bmfh.bfReserved1       =       0;        
                      bmfh.bfReserved2       =       0;        
           
      BYTE       *lpbuffa;        
      lpbuffa=NULL;        
      //分配位图内存        
      //lpbuffa=new       BYTE[320*240*3];        
      lpbuffa=new       BYTE[pfi.dwWidth       *       pfi.dwHeight       *       3];        
      BYTE*       lpbuff;        
           
           
      //避免生成的位图过多,限制到100        
      //   if       (pfi.dwLength>100)        
      //   pfi.dwLength=100;        
      for(LONG       i=1;i<(LONG)pfi.dwLength;i++)        
      {        
      lpbuff=lpbuffa;        
      lpbuff=(BYTE       *)AVIStreamGetFrame(pgf,i);//提取i单帧        
      lpbuff+=40;        
      //TranslationDIB1(lpbuff,bmih.biWidth,bmih.biHeight,10,50);//自己定义的平移函数        
      char       name1[50];        
      strcpy(name1,"d://avi//b");//目标地址        
           
      /*   //不用name2方案:b1.bmp~b99.bmp        
      static       char       name2[10]="0";        
      static       int       name2=0;        
      *name2=*name2+1;        
      name2++;        
      char       namebuf[10];        
      _itoa(name2,namebuf,10);        
      strcat(name1,namebuf);        
      strcat(name1,".bmp");        
      */        
      //name3方案:b00001.bmp~b00099.bmp        
      TCHAR       name3[50];        
      wsprintf(name3,       TEXT("Bitmap%5.5ld.bmp/0"),       long(       i       )       );        
      strcat(name1,name3);        
      //写入文件。        
      CFile       ff(name1,       CFile::modeWrite       |       CFile::modeCreate);       //写位图        
      ff.Write(&bmfh,       sizeof(bmfh));//bmfh-->ff        
      ff.Write(&bmih,       40);        
      ff.Write(lpbuff,       pfi.dwWidth       *       pfi.dwHeight       *       3);        
      ff.Close();        
           
           
           
      Sleep(10);        
      }        
           
           
                      //关闭文件        
                      AVIStreamGetFrameClose(pgf);        
      AVIFileRelease(pfile);        
           
      //Use       the       AVIFileExit()       function       to       release       the       AVIFile       library            
      //and       decrement       the       reference       count.同AVIFileInit()对应。        
      AVIFileExit();        
      ReleaseDC(&dc);        
      //CDialog::OnOK();        
      }        
      }    
PAVIFILE   等在   vfw.h        
     
  编译需要:vfw32.lib

__________________________________________

AVI文件就是我们所说的多媒体文件,所谓的AVI图像就是视频图像,该文件是一个RIFF说明文件,它用于获取、编辑、演示音频、视频序列。一般的AVI文件包含音频流和视频流,有的特殊的AVI还包含一个控制路径或MIDI路径作为附加的数据流。

  现在播放AVI文件的软件很多,但大多无法从AVI视频文件中读取一帧图像并生成BMP格式的文件。笔者在使用AVI文件开发项目过程中对AVI文件的操作积累了一些经验,对于如何实现从AVI视频流中获取任意帧的图像数据并存储成BMP文件,其中最关键的是要从AVI文件中获取具体某一帧的图像数据,为此我利用Windows提供的API函数实现了自定义的CAvi类,用于操作AVI文件。

  在使用API函数操作AVI文件时,一定要注意用AVIFileInit()来初始化AVI库,程序结束时用AVIFileExit()释放AVI库,否则API函数无法使用。现以操作包含真彩色图像的AVI文件为例,给出Cavi类的部分函数的具体实现,其中CaviCreate()函数用于读取AVI文件信息并初始化Cavi类的成员,例如根据AVI文件信息定义每帧图像的宽、高、每帧图像的信息头结构等等;函数AviRead(int mFrame)用于从AVI文件中读取第mFrame帧。实现代码显示如下:

//Cavi类头文件定义;
class CAvi
file://AVI类,处理AVI文件
{
 public:
 int cy;//图象高
 int cx;//图象宽
 
file://long m_maxFrame;
 BYTE *pData;//寸储图象数据
 BITMAPINFO *m_pBMI;//位图文件信息头
 PAVISTREAM pavi;//AVI流
 PAVIFILE pfile;//AVI文件指针
 AVIFILEINFO * pfi;
file://AVI信息
 BOOL AviRead(int mFrame);//读AVI文件的第mFrame帧
 CAvi();//标准构造函数
 CAviCreate(CString &string);//用文件名初始化AVI类的成员
 virtual ~CAvi();
};
//Cavi类文件实现部分;
CAvi::CAvi()
{ AVIFileInit();//初始化AVI库
 cx=0;//定义图象宽、高、等成员
 cy=0;
 m_pBMI=NULL;
 pData=NULL;
 
file://m_maxFrame=0;
 pfi=NULL;
}
CAvi::~CAvi()//析构、释放指针
{
 // AVIFileClose(pfile);
 AVIFileExit();
 if(pData!=NULL)
  delete pData;
  pData=NULL;

 if(m_pBMI!=NULL)
  delete m_pBMI;
  m_pBMI=NULL;
  if(pfi!=NULL)
   delete pfi;
   pfi=NULL;
}

CAvi::CAviCreate(CString &string)//读文件初始化该类
{
 HRESULT hr;
 pfi=new AVIFILEINFO;
 hr = AVIFileOpen(&pfile, // returned file pointer
 string, // file name
 OF_READ, // mode to open file with
 NULL);
 hr= AVIFileInfo(pfile, file://获取AVI信息,放入pfi中
 pfi,
 sizeof(AVIFILEINFO)
);
cx=pfi->dwWidth;//图象宽、高
cy=pfi->dwHeight;
hr=AVIFileGetStream(//将AVI变成视频流
pfile,
&pavi,
streamtypeVIDEO,
0//LONG lParam
);
m_pBMI=new BITMAPINFO;//定义BMP信息头
m_pBMI->bmiHeader.biBitCount=24;
m_pBMI->bmiHeader.biClrImportant=0;
m_pBMI->bmiHeader.biClrUsed=0;
m_pBMI->bmiHeader.biCompression=BI_RGB;
m_pBMI->bmiHeader.biHeight=cy;
m_pBMI->bmiHeader.biWidth=cx;
m_pBMI->bmiHeader.biPlanes=1;
m_pBMI->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
m_pBMI->bmiHeader.biXPelsPerMeter=0;
m_pBMI->bmiHeader.biYPelsPerMeter=0;
m_pBMI->bmiHeader.biSizeImage=cx*cy*3;
pData=(BYTE*)new char[cx*cy*3];//根据AVI中BMP图象的信息定义缓冲区
}
BOOL CAvi::AviRead(int mFrame)//将AVI文件的M帧数据读入PData缓冲区
{
HRESULT hr;
hr= AVIStreamRead( pavi,
mFrame,
1,
pData,
cx*cy*3,
NULL,
NULL
);
if(hr==0)
return TRUE;
else
return FALSE;
}

 

 

  上述Cavi类实现部分所涉及到的API函数可以参考微软提供的MSDN。Cavi类中的pData缓冲区存放AVI文件中的具体某一帧图像数据,同时Cavi类的m_pBMI为BMP图像文件信息结构,这时可以根据图像的大小定义BMP图像文件头结构,关于BMP文件的存储,由于篇幅的原因,我不在多讲了,有兴趣的读者可以参见笔者的拙作"Visual C++6.0开发灰度位图处理"(天极网软件栏目2001.9.10发表),该文里面讲述了如何存取BMP文件。以上程序在Windows2000、Visual C++6.0环境下顺利编译通过,运行正常。

_____________________________________________________

原创粉丝点击