AVI封装格式解析
一、AVI简介
AVI(Audio Video Interleaved的缩写) 是一种RIFF文件格式,多用于音视频捕捉、编辑、回放等应用程序中。通常情况下,一个AVI文件可以包含多个不同类型的媒体流(典型的情况下有一个音频流和一个视频流),不过含有单一音频流或单一视频流的AVI文件也是合法的。AVI可以算是Windows操作系统上最基本的、也是最常用的一种媒体文件格式。
RIFF(Resource Interchange File Format资源交互文件格式) ,是由Microsoft提出的一种多媒体文件存储方式,不同编码的视频、音频文件按照RIFF保存,当提取文件时,可以根据RIFF的规则解析文件。常见的RIFF文件有:WAV、AVI等。
RIFF文件使用四字符码FOURCC(four-character code)来表征数据类型,比如‘RIFF’、‘AVI ’、‘LIST’等。注意,Windows操作系统使用的字节顺序是little-endian,因此一个四字符码‘abcd’实际的DWORD值应为0x64636261。另外,四字符码中像‘AVI ’一样含有空格也是合法的。
二、AVI格式示意图

1. 信息块——包括文件的通用信息,定义数据格式,所用的压缩算法等参数
2. 数据块——包含实际数据流,即图像和声音序列数据。这是文件的主体,也是决定文件容量的主要部分。视频文件的大小等于该文件的数据率乘以该视频播放的时间长度
3. 索引块——索引块包含数据块列表好它们在文件中的位置,以提供文件内数据随机存取能力。
三、各部分详细介绍
RIFF格式 是一种树状结构,基本组成单元为LIST和CHUNK:LIST相当于目录,可以包含多个CHUNK或者多个LIST,包含关键字“LIST”。CHUNK是数据保存的基本单元,可用于保存音视频数据或者一些参数信息。RIFF文件结构最开始4个字节表示“RIFF”,接着4个字节表示该文件的大小,再下来的4个字节表示该文件的类型(AVI或者WAV等)。
LIST结构:
- ‘LIST’,一个四字符码,表示这是一个列表;
- listSize,占用4字节,记录了整个列表的大小;
- listType,一个四字符码,表示本列表的具体类型;
- listData,实际的列表数据。
CHUNK结构:
- ckID,一个表示块类型的四字符码;
- ckSize,占用4字节,记录了整个块的大小;
- ckData,实际的块数据。
AVI文件通常有如下几个子块组成:
- RIFF文件头:块的数据类型是AVI;
- “hdrl” list:音视频信息,描述媒体流信息;
- “info” list:编码该AVI的程序信息;
- “junk” chunk:无用数据,用于字节对齐;
- “movi” list:交错排列的音视频数据;
- “idxl” chunk:音视频排列的索引数据。
以片源B004_720P_AVC_MPEG_5M_30F.avi为例,详细介绍AVI各部分。下图为该码流基本信息:

1、RIFF文件头
RIFF(‘AVI’…) 表明AVI文件的格式。
2、“hdrl” list
hdrl列表: 嵌套了一系列块和子列表,一个avih块,一个或多个strl子列表。如下图:

(1)avih块: 记录AVI文件的全局信息,使用AVIMAINHEADER数据结构来操作:
typedef struct
{
DWORD dwMicroSecPerFrame; //显示每帧所需的时间ns,定义avi的显示速率
DWORD dwMaxBytesPerSec; // 最大数据传输率
DWORD dwPaddingGranularity; //记录块的长度须为此值的倍数,通常是2048
DWORD dwFlags; // AVI文件的特殊属性,包含文件中的任何标志字。如:有无索引块,是否是interlaced,是否含版权信息等
DWORD dwTotalFrames; // 数据帧的总数
DWORD dwInitialFrames; // 在开始播放前需要的帧数
DWORD dwStreams; //文件中包含的数据流种类
DWORD dwSuggestedBufferSize;//建议使用的缓冲区的大小,通常为存储一帧图像以及同步声音所需要的数据之和,大于最大的CHUNK的大小
DWORD dwWidth; //图像宽,像素
DWORD dwHeight; //图像高,像素
DWORD dwReserved[4]; //保留值dwScale,dwRate,dwStart,dwLength
} MainAVIHeader;
由上图的码流数据可计算出MainAVIHeader各成员的值:
‘avih’,size 56 bytes
microsec/frame:33333
max bytes/sec:0
reserved:0
flags:$00000910
#frames:3091
init frame:0
#streams:2
sug.bufsize:0
width:1280
height:720
scale:0
rate:0
start:0
length:0
(2)strl子列表: 一个strl子列表中至少包含一个strh块和一个strf块,而‘strd’块(保存编解码器需要的一些配置信息)和‘strn’块(保存流的名字)是可选的。文件中有多少个流,就对应有多少个strl子列表,strl子列表在hdrl中的次序就是流的序号。
‘strh’块,说明这个流的头信息,长度为64字节,使用AVISTREAMHEADER数据结构来操作:
typedef struct {
FOURCC fccType; //4字节,表示数据流的种类,“vids”表示视频数据流,“auds”表示音频数据流
FOURCC fccHandler; //4字节,描述数据所用编解码算法
DWORD dwFlags; //数据流的属性
WORD wPriority; //此数据流播放的优先级别
WORD wLanguage; //音频的语言代号
DWORD dwInitialFrames; //用于interlaced文件,开始播放前所需帧数
DWORD dwScale; //数据量,视频每帧的大小或者音频的采样大小
DWORD dwRate; // dwRate/dwScale = =samples/second(每秒采样数)
DWORD dwStart; //数据流开始播放的位置,单位:dwScale
DWORD dwLength; //数据流的数据量,单位:dwScale
DWORD dwSuggestedBufferSize; //建议缓冲区的大小
DWORD dwQuality; //解压缩质量参数,值越大,质量越好(0~10000)
DWORD dwSampleSize; //音频的采样大小
RECT rcFrame{
short int left;
short int top;
short int right;
short int bottom;
}; //视频数据图像所占的矩形。即这个流在视频主窗口显示的位置。
}AVIStreamHeader;
‘strf’ 块,用于说明流的具体格式。如果是视频流,则使用一个BITMAPINFOHEADER数据结构来描述;如果是音频流,则使用一个WAVEFORMAT数据结构来描述。
// strf:strh子块是视频数据流
typedef struct tagBITMAPINFO
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1]; //颜色表
}BITMAPINFO;
typedef struct{
DWORD dwSize;
DWORD dwWidth;
DWORD dwHeight;
WORD wPlanes;
WORD wBitCount;
DWORD dwCompression;
DWORD dwSizeImage;
DWORD dwXPelsPerMeter;
DWORD dwYPelsPerMeter;
DWORD dwClrUsed;
DWORD dwClrImportant;
}BITMAPINFOHEADER;
typedef struct {
BYTE rgbBlue; // 蓝色分量
BYTE rgbGreen; // 绿色分量
BYTE rgbRed; // 红色分量
BYTE rgbReserved; // 保留字节(用作Alpha通道或忽略)
} RGBQUAD;
// strf:strh子块是音频数据流
typedef struct
{
WORD wFormatTag;
WORD wChannels; //声道数
DWORD dwSamplesPerSec; //采样率
DWORD dwAvgBytesPerSec; //WAVE声音中每秒的数据量
WORD wBlockAlign; //数据块的对齐标志
WORD wBitsPerSample; //每次采样的数据量
WORD wSize; //此结构的大小
}WAVEFORMAT;
由上图的码流数据可计算出AVIStreamHeader和BITMAPINFOHEADER各成员的值:
‘strl’(‘LIST’ container),size 192 bytes
‘strh’,size 56 bytes
fccType:vids
fccHandler:avc1
flags:0
priority:0
language:0
init frames:0
scale:1
rate:30
start:0
length:3091
sug bufsize:293279
quality:0
sample size:0
left:0
top:0
right:1280
bottom:720
‘strf’,size 40 bytes
size:40
width:1280
height:720
planes:1
bit count:24
compression:avc1
size image:$002A3000
XPelsPerMeter:0
YPelsPerMeter:0
clr used:0
clr important:0
音频对应的strl列表同理,此处省略。
3、“info” list和"junk" chunk
“junk” chunk,一种特殊的数据块,用一个四字符码‘JUNK’来表征,它用于内部数据的对齐(填充),应用程序应该忽略这些数据块的实际意义。

4、“movi” list
“junk” chunk后是movi列表,movi列表中存储流的实际数据(视频图像帧数据或音频采样数据等),movi列表中数据子块的种类有:##db,##dc,##pc,##wb。
##表示数据所属的流的序号;
db:未压缩的视频帧(RGB数据流);
dc:压缩的视频帧;
wb:音频未压缩数据(Wave数据流);
wc:音频压缩数据(压缩的Wave数据流);
pc:改用新的调色板。(新的调色板使用一个数据结构AVIPALCHANGE来定义。如果一个流的调色板中途可能改变,则应在这个流格式的描述中,也就是AVISTREAMHEADER结构的dwFlags中包含一个AVISF_VIDEO_PALCHANGES标记。)

5、“idx1” chunk
最后,紧跟在‘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标记。
index flag = 1 表示关键帧

四、总结

AVI是基于RIFF文件格式的多媒体容器,包含音视频流信息。RIFF由LIST和CHUNK组成,AVI文件包括RIFF文件头、hdrl(音视频信息)、info(编码信息)、junk(填充数据)、movi(音视频数据)和idx1(索引数据)。strl子列表中的strh和strf块分别描述流头信息和格式。索引块idx1提供媒体数据快速访问。
1万+

被折叠的 条评论
为什么被折叠?



