vc++实现avi文件的操作

时间:2022-12-08 22:35:25
为了对avi进行读写,微软提供了一套API,总共50个函数,他们的用途主要有两类,一个是avi文件的操作,一类是数据流streams的操作。

  1、打开和关闭文件

  AVIFileOpen ,AVIFileAddRef, AVIFileRelease

  2、从文件里读取文件信息

  通过AVIFileInfo能够获取avi文件的一些信息,这个函数返回一个AVIFILEINFO结构,通过AVIFileReadData能够用来获取AVIFileInfo函数得不到的信息。

这些信息或许不包括在文件的头部,比方拥有file的公司和个人的名称。

  3、写入文件信息

  能够通过AVIFileWriteData函数来写入文件的一些额外信息。

  4、打开和关闭一个流

  打开一个数据流就跟打开文件一样,你能够通过 AVIFileGetStream函数来打开一个数据流,这个函数创建了一个流的接口。然后在该接口中保存了一个句柄。

  假设你想操作文件的某一个单独的流,你能够採用AVIStreamOpenFromFile函数,这个函数综合了AVIFileOpen和AVIFileGetStream函数。

  假设你想操作文件里的多个数据流,你就要首先AVIFileOpen。然后AVIFileGetStream。

  能够通过AVIStreamAddRef来添加stream接口的引用。

  通过AVIStreamRelease函数来关闭数据流。这个函数用来降低streams的引用计数,当计数降低为0时。删除。

  5、从流中读取数据和信息

  AVIStreamInfo函数能够获取数据的一些信息,该函数返回一个AVISTREAMINFO结构,该结构包括了数据的类型压缩方法。建议的buffersize,回放的rate,以及一些description。

  假设数据流另一些其它的额外的信息,你能够通过AVIStreamReadData函数来获取。应用程序分配一个内存,传递给这个函数,然后这个函数会通过这个内存返回数据流的信息。额外的信息可能包括数据流的压缩和解压缩的方法。你能够通过AVIStreamDataSize宏来回去须要申请内存块的大小。

  能够通过AVIStreamReadFormat函数获取数据流的格式信息。这个函数通过指定的内存返回数据流的格式信息,比方对于视频流,这个buffer包括了一个BIMAPINFO结构。对于音频流,内存块包括了WAVEFORMATEX或者PCMAVEFORMAT结构。你能够通过给AVIStreamReadFormat传递一个空buffer就能够获取buffer的大小。也能够通过AVIStreamFormatSize宏。

  能够通过AVIStreamRead函数来返回多媒体的数据。这个函数将数据拷贝到应用程序提供的内存中,对于视频流,这个函数返回图像祯,对于音频流,这个函数返回音频的sample数据。能够通过给AVIStreamRead传递一个NULL的buffer来获取须要的buffer的大小。也能够通过AVIStreamSampleSize宏来获取buffer的大小。

  有些AVI数据流句柄可能须要在启动数据流的前要做一下准备工作,此时,我们能够调用AVIStreamBeginStreaming函数来告知AVI数据流handle来申请分配它须要的一些资源。

在完成后。调用AVIStreamEndStreamming函数来释放资源。

  6、操作压缩的视频数据

  假设你要演示一祯或者几祯压缩视频图像时,你能够调用AVIStreamRead函数,将获取的数据传递给DrawDib函数来显示图像。

这些函数能够显示压缩和未压缩的图像。

  AVIFile也提供了一个函数AVIStreamGetFrameOpen,来获取未压缩的视频祯,这个函数创建了内存来获取未压缩的数据。也能够通过AVIStreamGetFrame函数来解压缩一个单独的视频祯。

这个函数能够解压缩某一祯图像,然后将数据以一个BIMAPINFOHEADER结构返回。当你调用完AVIStreamGetFrame函数后。要调用AVIStreamGetFrameClose函数释放上一个函数申请的资源。

  7、依据已存在的数据流创建文件

  创建一个包括多个数据流的文件的方法就是整合多个数据流。将其写入一个新文件。

这些数据流能够是内存中的数据,也能够是存在于另一个文件里。

  我们能够用AVISave这个函数来build一个文件。这个函数能够创建一个文件,而且将指定的多个数据流依照指定的顺序写入文件,你也能够通过AVISaveV函数来创建一个新的文件。这个函数的功能和AVISave的功能一样。主要差别是AVISaveV採用的数据流数组,而AVISave是单个的数据流,多次保存。

  我们能够调用AVISaveOptions函数来显示一个对话框,能够让用户来选择压缩方式。

  我们能够在调用AVISave和AVISaveV函数时指定一个回调函数,用来显示avi文件的生成进度,能够让用户随时地取消生成avi文件。

  我们能够调用GetSaveFileNamePreview函数来显示保存的对话框让用户选择保存的文件名称。

  通过AVIMakeFileFromStreams函数我们能够创建一个虚拟的文件句柄。其它的avi函数能够通过这个虚拟的文件句柄来操作文件里的数据流。操作完成要记得调用AVIFileRelease释放。

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文件解析成一幅幅位图。

  演示样例程序界面例如以下:

vc++实现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<iNumFrames; 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文件的操作的更多相关文章

  1. VC&plus;&plus; 实现INI文件读写操作

    转载:https://blog.csdn.net/fan380485838/article/details/73188420 在实际项目开发中,会用ini配置文件,在此总结一下对ini读写操作 一:读 ...

  2. (转)AVI文件格式解析&plus;AVI文件解析工具

    AVI文件解析工具下载地址:http://download.csdn.net/detail/zjq634359531/7556659 AVI(Audio Video Interleaved的缩写)是一 ...

  3. 使用VC&plus;&plus;压缩解压缩文件夹

    前言   项目中要用到一个压缩解压缩的模块, 看了很多文章和源代码,  都不是很称心, 现在把我自己实现的代码和大家分享. 要求: 1.使用Unicode(支持中文). 2.使用源代码.(不使用静态或 ...

  4. VC档&lpar;夹&rpar;文件夹路径的经营方针和代码

    ***********************************************声明*************************************************** ...

  5. 如何让nextcloud支持avi文件在线播放

    默认的nextcloud是不支持avi文件播放的,google查了一圈,都说是没法支持. 然而我觉得都是html5写的,为啥偏偏不支持. 查了一些资料,发现还是官方的代码少写了东西,可能是没考虑那么全 ...

  6. python 的基础学习 第九天 文件的操作

    1,文件操作 参数:1,文件路径  2,编码方式,3,执行动作(打开方式),只读,只写,,读写,追加和读写. 1  打开文件,得到文件句柄并赋值给一个变量.2. 通过句柄对文件进行操作.3. 关闭文件 ...

  7. 模糊测试之AVI文件分析

    本次试验主要是针对AVI的处理,了解AVI的基本概念,并且掌握AVI文件常用的程序读写方法.知道AVI视频文件的帧的读取方法,以及了解BMP和AVI的基本关系. 本文作者:i春秋签约作家——天天 一  ...

  8. &lbrack;转&rsqb;VC&plus;&plus;中对文件的写入和读取

    本文转自:http://blog.csdn.net/fanghb_1984/article/details/7425705 本文介绍两种方法对文件进行读取和写入操作:1.采用fstream类:2.采用 ...

  9. 记录我的 python 学习历程-Day08 文件的操作

    文件操作的初识 用 python 代码对文件进行各种操作. 基本构成: 文件路径:path 打开方式:读.写.追加.读写.写读-- 编码方式:utf-8 / gbk / gb2312-- f = op ...

随机推荐

  1. 学习EXT&period;JS5时的重点载图

    组件实例化的五种方式,最后一种不建议了 MVVM的图示,及controller的生存周期和MVC的不一样. VIEWCONTROLLER如何得到VIEW的实例呢,注意LOOKUPREFERENCE的使 ...

  2. css3 animation-fill-mode 对布局的影响

    问题描述:在小米手机上,animation-fill-mode设置为 both时,在手机上的web页面会超出屏幕宽度,出现滚动条. 解决方法:animation-fill-mode设为none. .p ...

  3. Theano3&period;2-练习之数据集及目标函数介绍

    来自http://deeplearning.net/tutorial/gettingstarted.html#gettingstarted 一.下载 在后续的每个学习算法上,都需要下载对应的文档,如果 ...

  4. spawn-fcgi

    spawn-fcgi与PHP-FPM 前面介绍过,FastCGI接口方式在脚本解析服务器上启动一个或者多个守护进程对动态脚本进行解析,这些进程就是FastCGI进程管理器,或者称为FastCGI引擎. ...

  5. Linux-某电商网站流量劫持案例分析与思考

    [前言] 自腾讯与京东建立了战略合作关系之后,笔者网上购物就首选京东了.某天在家里访问京东首页的时候突然吃惊地发现浏览器突然跳到了第三方网站再回到京东,心里第一个反应就是中木马了. 竟然有这样的事,一 ...

  6. PeopleCode 处理压缩文件

     PeopleSoft中对文件附件的处理都是单个文件处理的,虽然在8.52版本新增了MAddAttachment(URLDestination, DirAndFilePrefix, Prompts, ...

  7. MySQL----cluster安装

    第一步.下载MySQL cluster: http://cdn.mysql.com/Downloads/MySQL-Cluster-7.4/mysql-cluster-gpl-7.4.7-linux- ...

  8. 浅谈IOS8之size class 分类: ios技术 2015-02-05 19&colon;06 62人阅读 评论&lpar;0&rpar; 收藏

    文章目录 1. 简介 2. 实验 3. 实战 3.1. 修改 Constraints 3.2. 安装和卸载 Constraints 3.3. 安装和卸载 View 3.4. 其他 4. 后话 以前和安 ...

  9. Spring使用MappingJackson2MessageConverter发送接收ActiveMQ消息

    一.Spring使用JmsTemplate简化对JMS的访问 在JAVA对JMS队列访问中,使用默认的JMS支持将存在大量的检查型异常.通过Spring的支持,可以将所有的JMS的检查型异常转换为运行 ...

  10. Oracle死锁导致的tomcat抛损坏的管道异常

    今天遇到个问题,就是由于清空数据库的数据,设备采集客户端一直在往服务器上发采集回来的数据,但是由于某种原因,数据库的某语句死锁了. 数据库的死锁语句是通过这个SQL查出来的:select sql_te ...