我酷下载
您的位置:首页-> 技术文章-> -> Visual C++-> 利用VC++实现AVI文件的合成和分解(3)

阅读排行




利用VC++实现AVI文件的合成和分解(3)

作者未知 来源未知 加入时间:2006-2-19 人气:261

  8、向文件写入一个数据流

  我们可以通过AVIFileCreateStream函数来在一个新文件或者已经存在的文件中创建一个数据流。这个函数根据AVISTREAMINFO结构定义了新的数据流,并为新的数据流创建一个接口,返回接口的指针。

  在写入新的数据前,一定要指定流的格式信息,通过AVIStreamSetFormat函数,当设置一个视频流的时候,一定要使用BIMAPINFO结构来设置,音频就用WAVEFORMAT。

  然后我们就可以通过AVIStreamWrite函数将我们的多媒体数据写入数据流了。这个函数将应用程序提供的内存数据复制到指定的流。缺省的avi handler将数据写入流的最后。

  如果你有其他额外的信息需要写入流,你可以调用AVIFileWriteData或者AVIStreamWriteData,最后记得在完成数据写入后,要调用AVIStreamRelease。

  9、数据流中的祯的位置

  寻找起始祯:

  可以通过AVIStreamStart函数来获取第一祯包含的sample number。也可以通过AVIStreamInfo函数来获取这个信息,这个函数的AVISTREAMINFO结构中包含了dwStart,可以通过AVIStreamStartTime宏来获取第一个sample。

  可以通过AVIStreamLength函数来获取流的长度。这个函数返回流中的sample的数目。也可以通过AVIStreamInfo函数来获取这些信息,可以通过AVIStreamLengthTime宏来获取流的长度,毫秒。

  在视频流中,一个sample对应着一祯图像,所以,有时这些sample中没有视频数据,如果你调用AVIStreamRead函数来数据,可能返回NULL,也可以通过AVIStreamFindSample通过指定FIND_ANY标志来查找指定的sample。

  查找关键祯

  通过AVIStreamFindSample函数查找符合要寻找的sample,然后可以通过下面的宏判断是否关键祯。

  在time和sample间互相切换。

  AVIStreamSampleToTime这个函数可以将smaple转换成毫秒。对于视频,这个值代表的是这个祯开始播放的时间。

  在了解了上面的知识后,我们对avi的文件结构以及如何操作avi文件心里就明白了,下面我们可以开始我们的编程了。我们要做两件事情:

  1、如何将一组静态的bmp位图合成一个avi的视频文件;

  2、如何将一个未压缩的avi文件解析成一幅幅位图。

  示例程序界面如下:

  下面的函数演示了如何将一个文件夹下面的所有bmp文件都保存为一个avi文件,函数的第一个参数是要生成的AVI的文件名,第二个参数是存放bmp文件的文件夹名,这个函数会枚举该文件夹下的所有bmp文件,合成一个AVI文件。

void Cbmp2aviDlg::AVItoBmp(CString strAVIFileName, CString strBmpDir)
{
 // TODO: 在此添加控件通知处理程序代码
 AVIFileInit();
 PAVIFILE avi;
 int res=AVIFileOpen(&avi, strAVIFileName, OF_READ, NULL);
 int n = GetLastError();
 if (res!=AVIERR_OK)
 {
  //an error occures
  if (avi!=NULL)
   AVIFileRelease(avi);
  return ;
 }
 AVIFILEINFO avi_info;
 AVIFileInfo(avi, &avi_info, sizeof(AVIFILEINFO));
 PAVISTREAM pStream;
 res=AVIFileGetStream(avi, &pStream, streamtypeVIDEO /*video stream*/,
   0 /*first stream*/);
 if (res!=AVIERR_OK)
 {
  if (pStream!=NULL)
   AVIStreamRelease(pStream);
   AVIFileExit();
  return ;
 }

 //do some task with the stream
 int iNumFrames;
 int iFirstFrame;
 iFirstFrame=AVIStreamStart(pStream);
 if (iFirstFrame==-1)
 {
  //Error getteing the frame inside the stream
  if (pStream!=NULL)
   AVIStreamRelease(pStream);
  AVIFileExit();
  return ;
 }
 iNumFrames=AVIStreamLength(pStream);
 if (iNumFrames==-1)
 {
  //Error getteing the number of frames inside the stream
  if (pStream!=NULL)
   AVIStreamRelease(pStream);
  AVIFileExit();
  return ;
 }

 //getting bitmap from frame
 BITMAPINFOHEADER bih;
 ZeroMemory(&bih, sizeof(BITMAPINFOHEADER));

 bih.biBitCount=24; //24 bit per pixel
 bih.biClrImportant=0;
 bih.biClrUsed = 0;
 bih.biCompression = BI_RGB;
 bih.biPlanes = 1;
 bih.biSize = 40;
 bih.biXPelsPerMeter = 0;
 bih.biYPelsPerMeter = 0;
 //calculate total size of RGBQUAD scanlines (DWORD aligned)
 bih.biSizeImage = (((bih.biWidth * 3) + 3) & 0xFFFC) * bih.biHeight ;

 PGETFRAME pFrame;
 pFrame=AVIStreamGetFrameOpen(pStream, NULL );

 AVISTREAMINFO streaminfo;
 AVIStreamInfo(pStream,&streaminfo,sizeof(AVISTREAMINFO));

 //Get the first frame
 BITMAPINFOHEADER bih2;
 long lsize = sizeof(bih2);
 int index=0;
 for (int i=iFirstFrame; i {
  index= i-iFirstFrame;
  BYTE* pDIB = (BYTE*) AVIStreamGetFrame(pFrame, index); //
  AVIStreamReadFormat(pStream,index,&bih2,&lsize);
  BITMAPFILEHEADER stFileHdr;

  BYTE* Bits=new BYTE[bih2.biSizeImage];
  AVIStreamRead(pStream,index,1,Bits,bih2.biSizeImage,NULL,NULL);
  //RtlMoveMemory(Bits, pDIB + sizeof(BITMAPINFOHEADER), bih2.biSizeImage);

  bih2.biClrUsed =0;
  stFileHdr.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
  stFileHdr.bfSize=sizeof(BITMAPFILEHEADER);
  stFileHdr.bfType=0x4d42;

  CString FileName;
  FileName.Format("Frame-%05d.bmp", index);
  CString strtemp = strBmpDir;
  strtemp += "\\";
  strtemp += FileName;
  FILE* fp=_tfopen(strtemp ,_T("wb"));
  fwrite(&stFileHdr,1,sizeof(BITMAPFILEHEADER),fp);
  fwrite(&bih2,1,sizeof(BITMAPINFOHEADER),fp);
  int ff = fwrite(Bits,1,bih2.biSizeImage,fp);
  int e = GetLastError();
  fclose(fp);
  /////
  delete Bits;
  //CreateFromPackedDIBPointer(pDIB, index);
 }

 AVIStreamGetFrameClose(pFrame);

 //close the stream after finishing the task
 if (pStream!=NULL)
  AVIStreamRelease(pStream);
 AVIFileExit();
}

  下面的这个函数演示了如何将AVI文件中的每一桢图像单独取出来,保存为bmp文件。函数的头一个参数是avi文件名,第二个参数是存放bmp文件的文件夹。

//生成avi
void Cbmp2aviDlg::BMPtoAVI(CString szAVIName, CString strBmpDir)
{
 CFileFind finder;
 strBmpDir += _T("\\*.*");
 AVIFileInit();
 AVISTREAMINFO strhdr;
 PAVIFILE pfile;
 PAVISTREAM ps;
 int nFrames =0;
 HRESULT hr;

 BOOL bFind = finder.FindFile(strBmpDir);
 while(bFind)
 {
  bFind = finder.FindNextFile();
  if(!finder.IsDots() && !finder.IsDirectory())
  {
   CString str = finder.GetFilePath();
   FILE *fp = fopen(str,"rb");
   BITMAPFILEHEADER bmpFileHdr;
   BITMAPINFOHEADER bmpInfoHdr;
   fseek( fp,0,SEEK_SET);
   fread(&bmpFileHdr,sizeof(BITMAPFILEHEADER),1, fp);
   fread(&bmpInfoHdr,sizeof(BITMAPINFOHEADER),1, fp);

   BYTE *tmp_buf = NULL;
   if(nFrames ==0 )
   {
    AVIFileOpen(&pfile,szAviName,OF_WRITE | OF_CREATE,NULL);
    _fmemset(&strhdr, 0, sizeof(strhdr));
    strhdr.fccType = streamtypeVIDEO;// stream type
    strhdr.fccHandler = 0;
    strhdr.dwScale = 1;
    strhdr.dwRate = 15; // 15 fps
    strhdr.dwSuggestedBufferSize = bmpInfoHdr.biSizeImage ;
    SetRect(&strhdr.rcFrame, 0, 0, bmpInfoHdr.biWidth, bmpInfoHdr.biHeight);

    // And create the stream;
    hr = AVIFileCreateStream(pfile,&ps,&strhdr);
    // hr = AVIStreamSetFormat(ps,nFrames,&bmpInfoHdr,sizeof(bmpInfoHdr));
   }
   tmp_buf = new BYTE[bmpInfoHdr.biWidth * bmpInfoHdr.biHeight * 3];
   fread(tmp_buf, 1, bmpInfoHdr.biWidth * bmpInfoHdr.biHeight * 3, fp);
   hr = AVIStreamSetFormat(ps,nFrames,&bmpInfoHdr,sizeof(bmpInfoHdr));
   hr = AVIStreamWrite(ps, // stream pointer
      nFrames , // time of this frame
      1, // number to write
      (LPBYTE) tmp_buf,
      bmpInfoHdr.biSizeImage , // size of this frame
      AVIIF_KEYFRAME, // flags....
      NULL,
      NULL);

   nFrames ++;
   fclose(fp);
  }
 }

 AVIStreamClose(ps);

 if(pfile != NULL)
  AVIFileRelease(pfile);
 AVIFileExit();
}

  结束语:

  以上代码在 vc 6.0 和windows xp平台调试通过。这两个函数你可以直接在你的程序中使用,更详细的代码可以参见随着本文附上的示例源码。这里我要指出的是,这个AVI文件和bmp互相转换过程中,avi中的视频数据都是存放的是没有压缩的数据,如果你要分解AVI文件是经过压缩编码,比如,DVSD,MPEG4编码,首先你要采用相应的解码器对视频数据解码,然后将解码过的数据保存为bmp文件。好了,关于avi文件的介绍就到这里结束了。


相关文章
  • 利用VC++实现AVI文件的合成和分解(2)
  • 利用VC++实现AVI文件的合成和分解(1)
  • 相关软件

    联系我们 广告服务 友情链接 版权说明 软件发布 下载帮助

    CopyRight
    2005-2016 www.5qcn.net All Rights Reserved 版权所有 【我酷】下载