AVI文件和AVI函数

来源:互联网 发布:身份证号码识别软件 编辑:程序博客网 时间:2024/04/26 07:59

AVI(Audio Video Interleaved的缩写)是一种RIFF(Resource Interchange File Format的缩写)文件格式,多用于音视频捕捉、编辑、回放等应用程序中。通常情况下,一个AVI文件可以包含多个不同类型的媒体流(典型的情况下有一个音频流和一个视频流),不过含有单一音频流或单一视频流的AVI文件也是合法的。AVI可以算是Windows操作系统上最基本的、也是最常用的一种媒体文件格式。

 

先来介绍RIFF文件格式。RIFF文件使用四字符码FOURCC(four-character code)来表征数据类型,比如‘RIFF’、‘AVI ’、‘LIST’等。注意,Windows操作系统使用的字节顺序是little-endian,因此一个四字符码‘abcd’实际的DWORD值应为 0x64636261。另外,四字符码中像‘AVI ’一样含有空格也是合法的。


RIFF文件首先含有一个如图3.31的文件头结构。


 

图3.31 RIFF文件结构

 

最开始的4个字节是一个四字符码‘RIFF’,表示这是一个RIFF文件;紧跟着后面用4个字节表示此RIFF文件的大小;然后又是一个四字符码说明文件的具体类型(比如AVI、WAVE等);最后就是实际的数据。注意文件大小值的计算方法为:实际数据长度 + 4(文件类型域的大小);也就是说,文件大小的值不包括‘RIFF’域和“文件大小”域本身的大小。

 

RIFF 文件的实际数据中,通常还使用了列表(List)和块(Chunk)的形式来组织。列表可以嵌套子列表和块。其中,列表的结构为:‘LIST’ listSize listType listData ——‘LIST’是一个四字符码,表示这是一个列表;listSize占用4字节,记录了整个列表的大小;listType也是一个四字符码,表示本列表的具体类型;listData就是实际的列表数据。注意listSize值的计算方法为:实际的列表数据长度 + 4(listType域的大小);也就是说listSize值不包括‘LIST’域和listSize域本身的大小。再来看块的结构:ckID ckSize ckData ——ckID是一个表示块类型的四字符码;ckSize占用4字节,记录了整个块的大小;ckData为实际的块数据。注意ckSize值指的是实际的块数据长度,而不包括ckID域和ckSize域本身的大小。(注意:在下面的内容中,将以LIST ( listType ( listData ) )的形式来表示一个列表,以ckID ( ckData )的形式来表示一个块,如[ optional element ]中括号中的元素表示为可选项。)


接下来介绍AVI文件格式。AVI文件类型用一个四字符码‘AVI ’来表示。整个AVI文件的结构为:一个RIFF头 + 两个列表(一个用于描述媒体流格式、一个用于保存媒体流数据) + 一个可选的索引块。AVI文件的展开结构大致如下:


RIFF (‘AVI ’
      LIST (‘hdrl’
            ‘avih’(主AVI信息头数据)
            LIST (‘strl’
                  ‘strh’ (流的头信息数据)
                  ‘strf’ (流的格式信息数据)
                  [‘strd’ (可选的额外的头信息数据) ]
                  [‘strn’ (可选的流的名字) ]
                  ...
                 )
             ...
           )
      LIST (‘movi’
            { SubChunk | LIST (‘rec ’
                              SubChunk1
                              SubChunk2
                              ...
                             )
               ...
            }
            ...
           )
      [‘idx1’ (可选的AVI索引块数据) ]
     )

 

首先,RIFF (‘AVI ’…)表征了AVI文件类型。然后就是AVI文件必需的第一个列表——‘hdrl’列表,用于描述AVI文件中各个流的格式信息(AVI文件中的每一路媒体数据都称为一个流)。‘hdrl’列表嵌套了一系列块和子列表——首先是一个‘avih’块,用于记录AVI文件的全局信息,比如流的数量、视频图像的宽和高等,可以使用一个AVIMAINHEADER数据结构来操作:

 

typedef struct _avimainheader {
    FOURCC fcc;   // 必须为‘avih’
    DWORD cb;    // 本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)
    DWORD dwMicroSecPerFrame;   // 视频帧间隔时间(以毫秒为单位)
    DWORD dwMaxBytesPerSec;     // 这个AVI文件的最大数据率
    DWORD dwPaddingGranularity; // 数据填充的粒度
    DWORD dwFlags;         // AVI文件的全局标记,比如是否含有索引块等
    DWORD dwTotalFrames;   // 总帧数
    DWORD dwInitialFrames; // 为交互格式指定初始帧数(非交互格式应该指定为0)
    DWORD dwStreams;       // 本文件包含的流的个数
    DWORD dwSuggestedBufferSize; // 建议读取本文件的缓存大小(应能容纳最大的块)
    DWORD dwWidth;         // 视频图像的宽(以像素为单位)
    DWORD dwHeight;        // 视频图像的高(以像素为单位)
    DWORD dwReserved[4];   // 保留
} AVIMAINHEADER;

 

然后,就是一个或多个‘strl’子列表。(文件中有多少个流,这里就对应有多少个‘strl’子列表。)每个‘strl’子列表至少包含一个‘strh’ 块和一个‘strf’块,而‘strd’块(保存编解码器需要的一些配置信息)和‘strn’块(保存流的名字)是可选的。首先是‘strh’块,用于说明这个流的头信息,可以使用一个AVISTREAMHEADER数据结构来操作:

 

typedef struct _avistreamheader {
     FOURCC fcc; // 必须为‘strh’
     DWORD cb;   // 本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)
FOURCC fccType;    // 流的类型:‘auds’(音频流)、‘vids’(视频流)、
                   //‘mids’(MIDI流)、‘txts’(文字流)
     FOURCC fccHandler; // 指定流的处理者,对于音视频来说就是解码器
     DWORD dwFlags;    // 标记:是否允许这个流输出?调色板是否变化?
     WORD   wPriority; // 流的优先级(当有多个相同类型的流时优先级最高的为默认流)
     WORD   wLanguage;
     DWORD dwInitialFrames; // 为交互格式指定初始帧数
     DWORD dwScale;   // 这个流使用的时间尺度
     DWORD dwRate;
     DWORD dwStart;   // 流的开始时间
     DWORD dwLength; // 流的长度(单位与dwScale和dwRate的定义有关)
     DWORD dwSuggestedBufferSize; // 读取这个流数据建议使用的缓存大小
     DWORD dwQuality;    // 流数据的质量指标(0 ~ 10,000)
     DWORD dwSampleSize; // Sample的大小
     struct {
         short int left;
         short int top;
         short int right;
         short int bottom;
} rcFrame; // 指定这个流(视频流或文字流)在视频主窗口中的显示位置
             // 视频主窗口由AVIMAINHEADER结构中的dwWidth和dwHeight决定
} AVISTREAMHEADER;

 

然后是‘strf’块,用于说明流的具体格式。如果是视频流,则使用一个BITMAPINFO数据结构来描述;如果是音频流,则使用一个WAVEFORMATEX数据结构来描述。

 

当 AVI文件中的所有流都使用一个‘strl’子列表说明了以后(注意:‘strl’子列表出现的顺序与媒体流的编号是对应的,比如第一个‘strl’子列表说明的是第一个流(Stream 0),第二个‘strl’子列表说明的是第二个流(Stream 1),以此类推),‘hdrl’列表的任务也就完成了,随后跟着的就是AVI文件必需的第二个列表——‘movi’列表,用于保存真正的媒体流数据(视频图像帧数据或音频采样数据等)。那么,怎么来组织这些数据呢?可以将数据块直接嵌在‘movi’列表里面,也可以将几个数据块分组成一个‘rec ’列表后再编排进‘movi’列表。(注意:在读取AVI文件内容时,建议将一个‘rec ’列表中的所有数据块一次性读出。)但是,当AVI文件中包含有多个流的时候,数据块与数据块之间如何来区别呢?于是数据块使用了一个四字符码来表征它的类型,这个四字符码由2个字节的类型码和2个字节的流编号组成。标准的类型码定义如下:‘db’(非压缩视频帧)、‘dc’(压缩视频帧)、‘pc’(改用新的调色板)、‘wb’(音缩视频)。比如第一个流(Stream 0)是音频,则表征音频数据块的四字符码为‘00wb’;第二个流(Stream 1)是视频,则表征视频数据块的四字符码为‘00db’或‘00dc’。对于视频数据来说,在AVI数据序列中间还可以定义一个新的调色板,每个改变的调色板数据块用‘xxpc’来表征,新的调色板使用一个数据结构AVIPALCHANGE来定义。(注意:如果一个流的调色办中途可能改变,则应在这个流格式的描述中,也就是AVISTREAMHEADER结构的dwFlags中包含一个AVISF_VIDEO_PALCHANGES标记。)另外,文字流数据块可以使用随意的类型码表征。


最后,紧跟在‘hdrl’列表和‘movi’列表之后的,就是AVI文件可选的索引块。这个索引块为AVI文件中每一个媒体数据块进行索引,并且记录它们在文件中的偏移(可能相对于‘movi’列表,也可能相对于AVI文件开头)。索引块使用一个四字符码‘idx1’来表征,索引信息使用一个数据结构来 AVIOLDINDEX定义。


typedef struct _avioldindex {
   FOURCC fcc; // 必须为‘idx1’
   DWORD   cb;   // 本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)
   struct _avioldindex_entry {
      DWORD   dwChunkId;   // 表征本数据块的四字符码
      DWORD   dwFlags;     // 说明本数据块是不是关键帧、是不是‘rec ’列表等信息
      DWORD   dwOffset;    // 本数据块在文件中的偏移量
      DWORD   dwSize;      // 本数据块的大小
} aIndex[]; // 这是一个数组!为每个媒体数据块都定义一个索引信息
} AVIOLDINDEX;

 

注意:如果一个AVI文件包含有索引块,则应在主AVI信息头的描述中,也就是AVIMAINHEADER结构的dwFlags中包含一个AVIF_HASINDEX标记。

 

还有一种特殊的数据块,用一个四字符码‘JUNK’来表征,它用于内部数据的队齐(填充),应用程序应该忽略这些数据块的实际意义。

 

转自:http://blog.csdn.net/maojudong/archive/2009/07/22/4368975.aspx

 

 

 

avi函数:

 

总共50个函数,他们的用途主要有两类,一个是avi文件的操作,一类是数据流streams的操作。下面分别解析。

  1文件操作

  1.1打开和关闭文件

  AVIFileOpen ,AVIFileAddRef,

  AVIFileRelease

  1.2从文件中读取文件信息

  通过AVIFileInfo可以获取avi文件的一些信息,这个函数返回一个AVIFILEINFO结构

  通过AVIFileReadData可以用来获取AVIFileInfo函数得不到的信息。这些信息也许不包含在文件的头部,比如拥有file的公司和个人的名称。

  1.3写入文件信息

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

  1.4使用粘贴板

  AVIPutFileOnClipboard函数可以将一个avi复制到粘贴板上

  AVIGetFromClipboard函数可以将粘贴板上的avi写入到内存或者硬盘中。

  AVIClearClipboard用来清除粘贴板

  2数据流操作

  2.1打开和关闭一个流

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

  如果你想操作文件的某一个单独的流,你可以采用AVIStreamOpenFromFile函数,这个函数综合了AVIFileOpen和AVIFileGetStream函数。

  如果你想操作文件中的多个数据流,你就要首先AVIFileOpen,然后AVIFileGetStream。

  可以通过AVIStreamAddRef来增加stream接口的引用。

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

  2.2从流中读取数据和信息

  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函数来释放资源。

  2.3操作压缩的视频数据

  如果你要演示一祯或者几祯压缩视频图像时,你可以调用AVIStreamRead函数,将获取的数据传递给DrawDib函数来显示图像。这些函数可以显示压缩和未压缩的图像。

  AVIFile也提供了一个函数AVIStreamGetFrameOpen,来获取未压缩的视频祯,这个函数创建了内存来获取未压缩的数据。也可以通过AVIStreamGetFrame函数来解压缩一个单独的视频祯。这个函数可以解压缩某一祯图像,然后将数据以一个BIMAPINFOHEADER结构返回。当你调用完AVIStreamGetFrame函数后,要调用AVIStreamGetFrameClose函数释放上一个函数申请的资源。

  2.4根据已存在的数据流创建文件

  创建一个包含多个数据流的文件的方法就是整合多个数据流,将其写入一个新文件。这些数据流可以是内存中的数据,也可以是存在于另一个文件中。

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

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

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

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

  通过AVIMakeFileFromStreams函数我们可以创建一个虚拟的文件句柄,其他的avi函数可以通过这个虚拟的文件句柄来操作文件中的数据流,操作完毕要记得调用AVIFileRelease释放。

  2.5向文件写入一个数据流

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

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

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

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

  2.6数据流中的祯的位置

  寻找起始祯:

  可以通过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转换成毫秒。对于视频,这个值代表的是这个祯开始播放的时间,

  AVIStreamTimeToSample

  2.7 创建临时的streams

  我们可以通过AVIStreamCreate函数在内存中创建一个临时数据流,

  我们可以从一个未压缩的数据流创建一个压缩的数据流,采用AVIMakeCompressedStream函数,

  当我们使用完 avistreamcreate或者avimakecompressedstream创建的数据流,要一定使用AVIStreamRelease函数来关闭数据流。

  2.8对数据流进行编辑

  我们可以通过CreateEditableStream函数来创建一个用于编辑的数据流。这个函数初始化了编辑流的环境,这些包含

  EditStreamCut

  EditStreamCopy

  EditStreamPaste

  EditStreamClone

  EditStreamSetInfo

  EditStreamSetName

  1AVIBuildFilter

  2AVIClearClipboard

  3AVIFileAddRef

  4AVIFileCreateStream

  5AVIFileEndRecord

  6AVIFileExit

  7AVIFileGetStream

  STDAPI AVIFileGetStream(

  PAVIFILE pfile,

  PAVISTREAM * ppavi,

  DWORD fccType,

  LONG lParam

  );

  avi的文件是可以有多个stream的.比如video,audio,text等等.

  你可以通过这个参数获得你想要的stream的指针.在进行一些操作

  摘自MSDN;

  // gcpavi - count of the number of streams in an AVI file // gapavi[] = array of stream-interface pointers

  // Open the streams until a stream is not available.

  for (i = gcpavi; i < MAXNUMSTREAMS; i++) {

  gapavi[i] = NULL;

  if (AVIFileGetStream(pfile, &gapavi[i], 0L, i - gcpavi)

  != AVIERR_OK)

  break;

  if (gapavi[i] == NULL)

  break;

  }

  PAVIFILE avi;

  PAVISTREAM pStream;

  AVIFileGetStream(avi, &pStream, streamtypeVIDEO /*video stream*/,

  0 /*first stream*/);

  8AVIFileInfo

  api函数名(function):AVIFileInfo

  AVIFileInfo 别名(alias):

  AVIFileInfo 库名(library):avifil32

  AVIFileInfo 操作系统(os):Requires Windows NT 3.1 or later; Requires Windows 95 or later

  AVIFileInfo 参数表(parameter):

  ?pfile

  Handle of an open AVI file.

  ?pfi

  Address of the structure used to return file information. Typically, this parameter points to an AVIFILEINFO structure.

  ?lSize

  Size, in bytes, of the structure.

  AVIFileInfo 返回值(return):

  Returns zero if successful or an error otherwise.

  AVIFileInfo 说明(description):

  The AVIFileInfo function obtains information about an AVI file.

  AVIFileInfo 声明(declare):

  Declare Function AVIFileInfo Lib "avifil32" Alias "AVIFileInfoA" (ByVal pfile As Long, pfi As AVIFILEINFO, ByVal lSize As Long) As Long

  PAVIFILE avi;

  AVIFILEINFO avi_info;

  AVIFileInfo(avi, &avi_info, sizeof(AVIFILEINFO));

  9AVIFileInit

  10AVIFileOpen

  api函数名(function):AVIFileOpen

  AVIFileOpen 别名(alias):

  AVIFileOpen 库名(library):avifil32

  AVIFileOpen 操作系统(os):Requires Windows NT 3.1 or later; Requires Windows 95 or later

  AVIFileOpen 参数表(parameter):

  ?ppfile

  Address to contain the new file interface pointer.

  ?szFile

  Null-terminated string containing the name of the file to open.

  ?mode

  Access mode to use when opening the file. The default access mode is OF_READ. The following access modes can be specified with AVIFileOpen:

  OF_CREATE

  Creates a new file. If the file already exists, it is truncated to zero length.

  OF_SHARE_DENY_NONE

  Opens the file nonexclusively. Other processes can open the file with read or write access. AVIFileOpen fails if another process has opened the file in compatibility mode.

  OF_SHARE_DENY_READ

  Opens the file nonexclusively. Other processes can open the file with write access. AVIFileOpen fails if another process has opened the file in compatibility mode or has read access to it.

  OF_SHARE_DENY_WRITE

  Opens the file nonexclusively. Other processes can open the file with read access. AVIFileOpen fails if another process has opened the file in compatibility mode or has write access to it.

  OF_SHARE_EXCLUSIVE

  Opens the file and denies other processes any access to it. AVIFileOpen fails if any other process has opened the file.

  OF_READ

  Opens the file for reading.

  OF_READWRITE

  Opens the file for reading and writing.

  OF_WRITE

  Opens the file for writing.

  ?pclsidHandler

  Address of a class identifier of the standard or custom handler you want to use. If the value is NULL, the system chooses a handler from the registry based TYPE="audio/mpeg">

http://live.83683.cn

 

转自: http://hi.baidu.com/vvwiowv/blog/item/75867e2e3b0396355243c12c.html