http://www.ieee.org.cn/dispbbs.asp?boardID=61&ID=47093


 

 

VI(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文件首先含有一个文件头结构。


最开始的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;

 

 AVI(Audio/Video Interleaved)文件是MS-Windows的视频文件,其文件扩展名为“.AVI”。它一般由三部分构成:信 息区、数据区和索引区(可缺省),即两个LIST快和一个idx1块。这些区域,通常由一些子块组成,它们多用于为播放软件提供更为系统的数据信息;或为 播放时进行快速数据定位及播放,并提供详细资料和识别手段(关于“区域”与“子块”具体包容关系请见图6)。 
说明:本例由“四部分”构成,即在两个LIST块中间夹了个JUNK块。这个JUNK块纯属人为添加的自定义块,即在AVI文件中从未有对此块的定义。换 句话说,我们也可以添加自己的决,只要遵循如下原则:在这三个标准块其中的某个后面,定义一个四字节的块识别码(不要与本文用到的识别码相同,最好字母用 大写),紧跟一个长整数来表示你自定义的块的大小,随后便可以在定义的大小范围内写入你想表述的信息。同样,在这三个标准块的内部,也可以用上述方法添加 自定义干块。 
注:下文的说明内容部分取自华中理工大学出版的<>一文和<>的HELP文件。 
以下就是作为例子的文件内容(数据D)及AVI文件标准结构图。 


1.从(00000000-000007F3)为一个WindowsAVI文件的信息区部分。 
它是文件的第一个LIST块。在它的内部记录着整个文件的系统构成,如告诉播放软件“我是一个AVI文件”;“在我的体内有几个数据流”;“每个数据流包 含着什么数据类型——图像、声音或其他”;“如果是图像数据流,那么它的大小、颜色、压缩方式、播放速度等,等是怎样规定的”;“如果是声音数据流,那么 它的压缩方式、播放效果等等又将有何规定”......在信息区中还有多个附属的LIST块,也就是我们前面提到的“子块”,它们用来记录每个数据流的全 部信息。而这些附间LIST块与数据流之间保持着—一对应的关系,即 
第一个附属LIST块对应于00号数据流;第二个附属LIST块对应于01号数据流......要想解释数据流,我们必须先了解AVI文件中数据块是什 么。在AVI文件中,数据块是被放置在数据区中的一个有起始标志(由“数据流识别码”和“数据块存储方式识别码"组成,请参见对数据区部分的说明),并指 明大小和数据内容的数据段.那么,数据流就是那些相互之间具有联系的同种数据类型的数据块集合. 

00000000-00000003 多媒体文件识别码:RIFF 
00000004-00000007 文件大小(10EDICh字节)-8字节 
00000008-0000000B AVI文件识别码 
0000000C-0000000F 第一个LIST块识别码 
00000010-00000013 第一个LIST块的大小(168h字节) 
00000014-00000017 hdrl部分识别码,以下数据记录着此文件的格式 
00000018-0000001B hdrl部分所包含的avih块识别码,此模块记录着本文件的初始化信息 
0000001C-0000001F avih块大小(38h字节) 

00000020-00000023 每帧画面显示所维持多少个百万分之一秒,本例为1046Bh,即66667百万分之一秒,约0.07秒。所以在播放此文件时,你看到的画面约每秒15帧

 

 

AVI视频文件
它的英文全称为Audio Video Interleaved,即音频视频交错格式。是将语音和影像同步组合在一起的文件格式。它对视频文件采用了一种 有损压缩方式,但压缩比较高,因此尽管面面质量不是太好,但其应用范围仍然非常广泛。AVI支持256色和RLE压缩。AVI信息主要应用在多媒体光盘 上,用来保存电视、电影等各种影像信息。 它于1992年被Microsoft公司推出,随Windows3.1一起被人们所认识和熟知。所谓“音频视频 交错”,就是可以将视频和音频交织在一起进行同步播放。这种视频格式的优点是图像质量好,可以跨多个平台使用,其缺点是体积过于庞大,而且更加糟糕的是压 缩标准不统一,最普遍的现象就是高版本Windows媒体播放器播放不了采用早期编码编辑的AVI格式视频,而低版本Windows媒体播放器又播放不了 采用最新编码编辑的AVI格式视频,所以我们在进行一些AVI格式的视频播放时常会出现由于视频编码问题而造成的视频不能播放或即使能够播放,但存在不能 调节播放进度和播放时只有声音没有图像等一些莫名其妙的问题,如果用户在进行AVI格式的视频播放时遇到了这些问题,可以通过下载相应的解码器来解决。是 目前视频文件的主流。 这种格式的文件随处可见,比如一些游戏、教育软件的片头,多媒体光盘中,都会有不少的 AVI 。   
  
现在,在WINDOWS 95或98里都能直接播放AVI,而且它自己的格式也有好几种,最常见的有 Intel Indeo(R)Video R3.2、Microsoft video 等。   
  

AVI 文件包含三部分:文件头、数据块和索引块。其中数据块包含实际数据流,即图像和声音序列数据。这是文件的主体,也是决定文件容量的主要部分。视频 文件的大小等于该文件的数据率乘以该视频播放的时间长度,索引块包括数据块列表和它们在文件中的位置,以提供文件内数据随机存取能力。文件头包括文件的通 用信息,定义数据格式,所用的压缩算法等参数

 

 

/ AVIMAINHEADER flags 
 public static readonly int AVIF_HASINDEX = 0x00000010; // Index at end of file? 
 public static readonly int AVIF_MUSTUSEINDEX = 0x00000020; 
 public static readonly int AVIF_ISINTERLEAVED = 0x00000100; 
 public static readonly int AVIF_TRUSTCKTYPE = 0x00000800; // Use CKType to find key frames 
 public static readonly int AVIF_WASCAPTUREFILE = 0x00010000; 
 public static readonly int AVIF_COPYRIGHTED = 0x00020000; 
 
 // AVISTREAMINFO flags 
 public static readonly int AVISF_DISABLED = 0x00000001; 
 public static readonly int AVISF_VIDEO_PALCHANGES = 0x00010000; 
 
 // AVIOLDINDEXENTRY flags 
 public static readonly int AVIIF_LIST = 0x00000001; 
 public static readonly int AVIIF_KEYFRAME = 0x00000010; 
 public static readonly int AVIIF_NO_TIME = 0x00000100; 
 public static readonly int AVIIF_COMPRESSOR = 0x0FFF0000; // unused? 
 
 // TIMECODEDATA flags 
 public static readonly int TIMECODE_SMPTE_BINARY_GROUP = 0x07; 
 public static readonly int TIMECODE_SMPTE_COLOR_FRAME = 0x08; 
 
 
 // AVI stream FourCC codes 
 public static readonly int streamtypeVIDEO = RiffParser.ToFourCC("vids"); 
 public static readonly int streamtypeAUDIO = RiffParser.ToFourCC("auds"); 
 public static readonly int streamtypeMIDI = RiffParser.ToFourCC("mids"); 
 public static readonly int streamtypeTEXT = RiffParser.ToFourCC("txts"); 
 
 // AVI section FourCC codes 
 public static readonly int ckidMainAVIHeader = RiffParser.ToFourCC("avih"); 
 public static readonly int ckidODML = RiffParser.ToFourCC("odml"); 
 public static readonly int ckidAVIExtHeader = RiffParser.ToFourCC("dmlh"); 
 public static readonly int ckidStreamList = RiffParser.ToFourCC("strl"); 
 public static readonly int ckidAVIStreamHeader = RiffParser.ToFourCC("strh"); 
 public static readonly int ckidStreamFormat = RiffParser.ToFourCC("strf"); 
 public static readonly int ckidAVIOldIndex = RiffParser.ToFourCC("idx1");