原创 利用VC++实现AVI文件的合成和分解收藏

新一篇: 基于DirectShow的MPEG-4视频传输系统的研究与实现(转载) | 旧一篇: 微软 DirectX—昨天,今天,明天!(转载)

 
摘要:本文详细的解析了AVI文件的存储结构,介绍了微软提供的用来操作AVI文件的一组API使用方法,并通过例子代码,演示了如何将一组静态Bmp图片合成一个avi视频文件以及如何将一个avi视频文件解析保存为一系列的bmp图像文件。
 
关键词:avi文件 bmp图像 vc
 
AVI是音频视频交错(Audio Video Interleaved)的英文缩写,它是Microsoft公司开发的一种符合RIFF文件规范的数字音频与视频文件格式,原先用于Microsoft Video for Windows (简称VFW)环境,现在已被Windows 95/98、OS/2等多数操作系统直接支持。AVI格式允许视频和音频交错在一起同步播放,支持256色和RLE压缩,但AVI文件并未限定压缩标准,因此,AVI文件格式只是作为控制界面上的标准,不具有兼容性,用不同压缩算法生成的AVI文件,必须使用相应的解压缩算法才能播放出来。常用的AVI播放驱动程序,主要是Microsoft Video for Windows或Windows 95/98中的Video 1,以及Intel公司的Indeo Video。
  在介绍AVI文件前,我们要先来看看RIFF文件结构。AVI文件采用的是RIFF文件结构方式,RIFF(Resource Interchange File Format,资源互换文件格式)是微软公司定义的一种用于管理windows环境中多媒体数据的文件格式,波形音频wave,MIDI和数字视频AVI都采用这种格式存储。构造RIFF文件的基本单元叫做数据块(Chunk),每个数据块包含3个部分,
1 4字节的数据块标记(或者叫做数据块的ID)
2 数据块的大小
3 数据
整个RIFF文件可以看成一个数据块,其数据块ID为RIFF,称为RIFF块。一个RIFF文件中只允许存在一个RIFF块。RIFF块中包含一系列的子块,其中有一种字块的ID为“LIST”,称为LIST,LIST块中可以再包含一系列的子块,但除了LIST块外的其他所有的子块都不能再包含子块。
   RIFF和LIST块分别比普通的数据块多一个被称为形式类型(Form Type)和列表类型(List Type)的数据域,其组成如下:
1 4字节的数据块标记(Chunk ID)
2 数据块的大小
3 4字节的形式类型或者列表类型
4 数据
 
下面我们看看AVI文件的结构。AVI文件是目前使用的最复杂的RIFF文件,它能同时存储同步表现的音频视频数据。AVI的RIFF块的形式类型是AVI,它包含3个子块,如下所述:
1信息块,一个ID为”hdrl”的LIST块,定义AVI文件的数据格式。
2数据块,一个ID为 “movi”的LIST块,包含AVI的音视频序列数据
3索引块,ID为 “idxl”的子块,定义 “movi”LIST块的索引数据,是可选块。
AVI文件的结构如下图所示,下面将具体介绍AVI文件的各子块构造。
1信息块,信息块包含两个子块,即一个ID为 avih 的子块和一个ID 为 strl 的LIST块。
 
“avih”子块的内容可由如下的结构定义:
 
typedef struct
{
 DWORD dwMicroSecPerFrame ; //显示每桢所需的时间ns,定义avi的显示速率
 DWORD dwMaxBytesPerSec; //      最大的数据传输率
 DWORD dwPaddingGranularity;    //记录块的长度需为此值的倍数,通常是2048
 DWORD dwFlages;                 //AVI文件的特殊属性,如是否包含索引块,音视频数据是否交叉存储
 DWORD dwTotalFrame;              //文件中的总桢数
 DWORD dwInitialFrames;           //说明在开始播放前需要多少桢
 DWORD dwStreams;                 //文件中包含的数据流种类
 DWORD dwSuggestedBufferSize; //建议使用的缓冲区的大小,
                              //通常为存储一桢图像以及同步声音所需要的数据之和
 DWORD dwWidth;                   //图像宽
 DWORD dwHeight;                   //图像高
 DWORD dwReserved[4];               //保留值
}MainAVIHeader;
 
“strl” LIST块用于记录AVI数据流,每一种数据流都在该LIST块中占有3个子块,他们的ID分别是”strh”,”strf”, “strd”;
“strh”子块由如下结构定义,
typedef struct
{
       FOURCC   fccType;      //4字节,表示数据流的种类 vids 表示视频数据流
                              //auds 音频数据流
       FOURCC   fccHandler;//4字节 ,表示数据流解压缩的驱动程序代号
       DWORD    dwFlags;      //数据流属性
   WORD     wPriority;    //此数据流的播放优先级
       WORD     wLanguage;    //音频的语言代号
       DWORD    dwInitalFrames;//说明在开始播放前需要多少桢
       DWORD    dwScale;       //数据量,视频每桢的大小或者音频的采样大小
       DWORD    dwRate;        //dwScale /dwRate = 每秒的采样数
       DWORD    dwStart;       //数据流开始播放的位置,以dwScale为单位
       DWORD    dwLength;      //数据流的数据量,以dwScale为单位
       DWORD    dwSuggestedBufferSize; //建议缓冲区的大小
       DWORD    dwQuality;      //解压缩质量参数,值越大,质量越好
       DWORD    dwSampleSize;   //音频的采样大小
       RECT     rcFrame;        //视频图像所占的矩形
}AVIStreamHeader;
“strf”子块紧跟在”strh”子块之后,其结构视”strh”子块的类型而定,如下所述;
如果 strh子块是视频数据流,则 strf子块的内容是一个与windows设备无关位图的BIMAPINFO结构,如下
typedef struct tagBITMAPINFO
{
       BITMAPINFOHEADER     bmiHeader;
       RGBQUAD              bmiColors[1]; //颜色表
}BITMAPINFO;
 
typedef struct tagBITMAPINFOHEADER
{
       DWORD biSize;
       LONG biWidth;
       LONG biHeight;
       WORD biPlanes;
       WORD biBitCount;
       DWORD biCompression;
       DWORD biSizeImage;
       LONG biXPelsPerMeter;
       LONG biYPelsPerMeter;
       DWORD biClrUsed;
       DWORD biClrImportant;
}BITMAPINFOHEADER;
如果 strh子块是音频数据流,则strf子块的内容是一个WAVEFORMAT结构,如下
typedef struct
{
        WORD   wFormatTag; 
        WORD   nChannels;   //声道数
        DWORD nSamplesPerSec; //采样率
        DWORD nAvgBytesPerSec; //WAVE声音中每秒的数据量
        WORD   nBlockAlign;     //数据块的对齐标志
        WORD   biSize;          //此结构的大小
}WAVEFORMAT
“strd”子块紧跟在strf子块后,存储供压缩驱动程序使用的参数,不一定存在,也没有固定的结构。
“strl” LIST块定义的AVI数据流依次将 “hdrl “ LIST 块中的数据流头结构与”movi” LIST块中的数据联系在一起,第一个数据流头结构用于数据流0,第二个用于数据流1,依次类推。
数据块中存储视频和音频数据流,数据可直接存于 “movi” LIST块中。数据块中音视频数据按不同的字块存放,其结构如下所述,
音频字块
 “##wb”
 Wave 数据流
视频子块中存储DIB数据,又分为压缩或者未压缩DIB,
 “##db”
 RGB数据流
 
 “##dc”
 压缩的图像数据流
 
看到了吧,avi文件的图像数据可以是压缩的,和非压缩格式的。对于压缩格式来说,也可采用不同的编码,也许你曾经遇到有些avi没法识别,就是因为编码方式不一样,如果没有相应的解码,你就没法识别视频数据。AVI的编码方式有很多种,比较常见的有 mpeg2,mpeg4, divx等。
索引块,索引快包含数据块在文件中的位置索引,能提高avi文件的读写速度,其中存放着一组AVIINDEXENTRY结构数据。如下,这个块并不是必需的,也许不存在。
typedef struct
 {
       DWORD ckid;          //记录数据块中子块的标记
       DWORD dwFlags;        //表示chid所指子块的属性
       DWORD dwChunkOffset;   //子块的相对位置
       DWORD dwChunkLength; //子块长度
};
Ok,现在我相信你肯定会对AVI的文件结构已经很清楚了,在介绍完了AVI文件结构后,我们就来看看如何对avi文件进行读写了,为了对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文件解析成一幅幅位图。
 示例程序界面如下:
 
下面的函数演示了如何将一个文件夹下面的所有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文件的介绍就到这里结束了
 
 

发表于 @ 2006年02月11日 01:01:00|评论(loading...)|编辑

新一篇: 基于DirectShow的MPEG-4视频传输系统的研究与实现(转载) | 旧一篇: 微软 DirectX—昨天,今天,明天!(转载)

评论

#双喜 发表于2006-02-15 09:40:00  IP: 61.144.42.*
研究中,本人也正在学习这方面的知识,请问有源码吗?
#santayao 发表于2006-02-19 11:51:00  IP: 218.249.160.*
更详细的代码可以参见随着本文附上的示例源码。
请问示例源码在哪儿
#laper 发表于2006-04-05 11:33:00  IP: 218.249.88.*
代码编译过程中到
hr = AVIStreamWrite(ps,nFrames,1,(LPBYTE)temp_buf,bmpInfoHdr.biSizeImage,AVIIF_KEYFRAME,NULL,NULL);
这句就会报错,Unhandled exception in AVITest.exe (AVIFIL32.dll):0xC0000005:Access violation
请问是什么问题啊 ?!当然发源码也可以我自己研究,在blog上没有贴..
#易磊 发表于2006-05-20 00:11:00  IP: 218.11.207.*
我很想请教你几个问题,可否给帮我一下
我最近在做一个屏幕录象系统,可bmp在转化avi时不知道怎么做,在网上找了好久都没找到方法!今天终于找到你的网站,真的很荣幸.看了你的解决方法,得到很大的帮助,懂了很多,不过还是有些不懂,不知你可否把这个bmp转化为avi的详细的代码传给我一下,在这里先谢了哈!我很想和你交个朋友,我是四川大学大二学生,我的邮箱是yixinglin@tom.com,QQ是249594738,如果你有空的话,就麻烦你传一下你的详细代码哈,谢谢,谢谢,多谢你看完我上面所写的哈!
#buaacen 发表于2006-06-08 23:42:00  IP: 219.239.227.*
我也在研究如何将avi文件中的一帧图象的所有像素信息提取出来!
"更详细的代码可以参见随着本文附上的示例源码。"
能给我看看吗?
#zyyoung 发表于2006-08-12 10:05:00  IP: 58.213.208.*
想请教一下使用divx压缩avi文件,怎么设计程式
谢谢
#zyyoung 发表于2006-08-12 10:06:00  IP: 58.213.208.*
联系zyyoung@sohu.com
谢谢
#lilong 发表于2006-09-04 12:57:00  IP: 220.163.15.*
你好,我急需详细代码,可否在危机时刻救我一把,我的邮箱是
lilong2588@163.com
#lilong 发表于2006-09-04 12:57:00  IP: 220.163.15.*
你好,我急需详细代码,可否在危机时刻救我一把,我的邮箱是
lilong2588@163.com
#zhiyuan 发表于2006-09-09 16:48:00  IP: 218.62.42.*
你好,我正在做这方面的论文,特想请教你几个问题.如果你有时间请加我QQ:11899629.如果你忙的话,能把代码发给我我也会非常感激.
邮箱是:zhiyuan253@yahoo.com.cn
如果你还是没有时间的话,希望你能在这再发一些相关的文章.我会关注的.谢谢!!!!
#hi 发表于2006-09-12 15:34:00  IP: 218.8.56.*
没有实现,给我传一份源码好吧,谢谢了qiuxu32006@126.com
#simon 发表于2006-10-11 10:59:00  IP: 61.141.152.*
我正研究这个,给我传份源码好吧,谢谢!simon968818@163.com
#simon 发表于2006-10-11 11:07:00  IP: 61.141.152.*
请给我传份源码好吧,谢谢!simon968818@163.com
#tina 发表于2006-11-09 08:59:00  IP: 124.42.1.*
能传一份源码吗?谢了。 zlf1127@sina.com
#k116shixian 发表于2007-01-16 16:38:58  IP:
你好,智慧的鱼,我最近开发一个项目,现在在学习DirectX方面的相关知识,通过链接进入了你的BLOG,仔细浏览了上面的文章,一个字,服!
你提供的这些资料对我非常有用,另外能够给我一些相关的源代码吗,结合代码再来看这些文档,应该更有收获。我的邮箱是:k116shixian@163.com
#linjiefeng 发表于2007-02-06 14:07:46  IP: 58.211.239.*
你好,智慧的魚。能傳一份源碼給我好嗎?謝謝!
#linjiefeng 发表于2007-02-06 14:08:15  IP: 58.211.239.*
我的郵箱是: yihuaxulin@163.com
#sz2007 发表于2007-03-12 16:52:00  IP:
真要命,大家要源代码的人,为什么不自己把那两个函数编译调试一下。这么简单的问题也在这里要代码。

搞不懂。
#Gorgr 发表于2007-05-14 11:03:30  IP: 218.17.227.*
请问智慧的鱼:
wave文件中16位pcm编码的数据具体是怎么存储的?
比如16位单声道数据,高八位和低八位分别代表什么?为什么我用你说的avi这些函数读wave文件后,数据只有matlab读出来的一半?
期待你的回复,谢谢!
#xinfeixiang1 发表于2007-05-25 21:47:30  IP: 219.239.227.*
这个程序光存BMP那里就明显有好几处错误,大家参考下就好了,真正做还是得好好看MSDN和书。
#litingan 发表于2007-05-30 17:37:29  IP: 219.239.227.*
你好,能不能给我发一份源代码,我是初学VC的,谢谢
#guoboxue 发表于2007-08-12 12:38:20  IP: 125.76.215.*
哪们大哥能帮我看一下,我的程序有什么问题,我是想读一个avi,然后再写到另一个AVI中,但为什么写入已后的文件只是保存了最后一帧,且大家只有一帧的大小 ,谢谢
AVIFileInit();
PAVIFILE avi,avi2;
AVIFileOpen(&avi,"e:\\day.avi",OF_READ,NULL);
AVIFileOpen(&avi2,"e:\\avi1.avi",OF_WRITE|OF_CREATE,NULL);
AVIFILEINFO avi_info;
AVIFileInfo(avi,&avi_info,sizeof(AVIFILEINFO));
PAVISTREAM pStream,pStream2;
AVIFileGetStream(avi,&pStream,streamtypeVIDEO,0);

int iNumFrame;int iFirstFrame;
iFirstFrame=AVIStreamStart(pStream);
iNumFrame=AVIStreamLength(pStream);
BITMAPINFOHEADER bih;
ZeroMemory(&bih,sizeof(BITMAPINFOHEADER));
bih.biBitCount=24;
bih.biClrImportant=0;
bih.biClrUsed=0;
bih.biCompression=BI_RGB;
bih.biPlanes=1;
bih.biSize=40;
bih.biXPelsPerMeter=0;
bih.biYPelsPerMeter=0;
bih.biWidth=400;
bih.biHeight=300;
bih.biSizeImage=300*400*3;
// PGETFRAME pFrame;
// pFrame=AVIStreamGetFrameOpen(pStream,NULL);
AVISTREAMINFO streaminfo;
AVIStreamInfo(pStream,&streaminfo,sizeof(AVISTREAMINFO));
long lsize=sizeof(bih);
int index=0;
AVIFileCreateStream(avi2,&pStream2,&streaminfo);

BYTE *Bits=new BYTE[400*300*3];
for (int i=iFirstFrame; i<iNumFrame;i++);
{
// index=i-iFirstFrame;
//BYTE *pDIB=(BYTE*)AVIStreamGetFrame(pFrame,i);

#GHP 发表于2008-07-19 18:53:56  IP: 222.83.44.*
智慧的鱼的文章总体是好的,但是有几个问题值得商榷:
文章中:"1信息块,一个ID为”hdrl”的LIST块,定义AVI文件的数据格式。
2数据块,一个ID为 “movi”的LIST块,包含AVI的音视频序列数据
3索引块,ID为 “idxl”的子块,定义 “movi”LIST块的索引数据,是可选块。" 的三个ID似乎不是ID,它们的ID都是"LIST",”hdrl”等三个都是LIST的列表类型.
两个函数没有大错,但是使用时一定注意:只适用24位真彩,且大小一样的位图,如果是256色则转化结果是不正确的,需要考虑调色板
#kevin_moon 发表于2008-08-01 16:23:48  IP: 222.240.153.*
探讨个问题,我读取一个avi文件使用你所述的数据结构,在STRF处总是出问题,虽然可以继续读下去,但是得到的biWidth等数据显示不对。
而用这样的结构可以读取且正确:
typedef struct _avivideoinfo{
FOURCC fccStrf;
DWORD cb;
BITMAPINFOHEADER bmiVideoInfor;
}AVIVIDEOINFO;
也就是去掉BITMAPINFO的调色板,而在fcc后面增加一个数据大小域。如果有时间,希望你能和我讨论一下。
qq:315567708
多谢。
#avibbs 发表于2008-09-03 10:51:49  IP: 222.223.118.*
sad
#avibbs 发表于2008-09-03 10:51:57  IP: 222.223.118.*
sad不错。。学习拉
#avibbs 发表于2008-09-03 10:51:59  IP: 222.223.118.*
sad不错。。学习拉
发表评论  


登录
Csdn Blog version 3.1a
Copyright © aoosang