首先AVI是一种RIFF文件,所以先介绍一下RIFF文件
一、RIFF文件简介
RIFF是Microsoft提出的一种多媒体文件的存储方式,不同编码的音频、视频文件,可以按照它定义的存储规则保存、记录各自不同的数据,如:数据内容、采集信息、显示尺寸、编码方式等。在播放器或者其它提取工具读取文件的时候,就可以根据RIFF的规则来分析文件,合理的解析出音频、视频信息,正确进行播放。常见的RIFF文件有WAV文件和AVI文件,它们都是遵循RIFF格式保存播放信息和播放数据的。
二、RIFF文件的组织结构
在RIFF的文件存储规则中,主要有几个重要的概念需要理解,它们是FOURCC,CHUNK,LIST。下面会对这几个概念进行详细解释。
RIFF格式是一种树状的结构,其基本组成单元为LIST和CHUNK,CHUNK类似文件存放实际的数据,LIST类似目录,可嵌套目录或包含文件。
1、FOURCC
一个FOURCC(fourcharactercode)是一个占4个字节的数据,一般表示4个ASCII字符。在RIFF文件格式中,FOURCC非常普遍。FOURCC一般是四个字符,如”abcd”这样的形式,也可以三个字符包含一个空格,如”abc”这样的形式。
可用如下结构体来表示:
typedefstructFOURCC
{
chartag1;
chartag2;
chartag3;
chartag4;
}FOURCC;
2、CHUNK
一个CHUNK数据块的数据结构如下:
从上到下依次为ChunkID,ChunkSize,ChunkData
ChunkID是一个FOURCC,标识该CHUNK的名称,类似于文件名的作用。ChunkSize占用4个字节,表示ChunkData部分的数据内容大小(注意不包括ChunkID,ChunkSize部分),以字节为单位。ChunkData则是CHUNK中实质性的内容,保存的是CHUNK的具体数据内容。一个CHUNK保存的数据可以是关于声音文件的编码方式、音视频采样等信息,也可以是音频或视频数据。具体表示的是哪类数据则通过ChunkID来区别。
3、LIST
一个LIST数据块的数据结构如下:
从上到下依次为“LIST”,ListSize,ListType,ListData
“LIST”也是一个FOURCC,而且是固定的,每个LIST都是以“LIST”为开头。ListSize占用4个字节,表示ListType和ListData两部分加在一起的大小。ListType是一个FOURCC,是对LIST具体包含的数据内容的标识。而ListData则是该LIST的数据内容区,有CHUNK和子LIST组成,它们的个数和组成次序可以是不确定的。
LIST和CHUNK的大小是不确定的,所以对他们只能定义头部分的结构,整体的结构无法定义
4、RIFF文件头
RIFF文件头的数据结构如下:
从上到下依次为“RIFF”,FileSize,FileType,FileData
“RIFF”也是一个FOURCC,用于标识该文件是一个RIFF格式的文件。FileSize是一个4字节的数据,给出文件的大小,但仅包括FileType和FileData两部分。FileType是一个FOURCC,用来说明文件类型,如”WAV”,“AVI”等。FileData部分表示文件的具体内容,可以是LIST也可以是CHUNK.
==============================
下面来看AVI文件的结构图:
共有4部分组成,一个RIFF文件头,一个“hdrl”的LIST,一个“movi”的LIST,和一个“idx1”的CHUNK。
这里我对照图从上往下讲:
1、RIFF文件头
12个字节,4字节的“RIFF”,4字节的SIZE,4字节的“AVI”(有个空格的)。
其中SIZE部分也就是图中S1部分的值为整个文件的大小减去8;
或者说是S1之后开始到文件结尾的大小;
或者说是hdrl这个LIST的大小加上movi这个LIST的大小加上idx1这个CHUNK的大小加上“AVI”这4字节。
2、hdrl这个LIST
这个LIST包含一个avih和若干个子LIST,每个子LIST表示一种码流的参数信息。
所以hdrl这个LIST的SIZE部分也就是图中S2部分的值是从“hdrl”开始到这个LIST结束的大小。
3、avih这个CHUNK
这个CHUNK对应的结构如下
typedefstruct_avimainheader{
FOURCCfcc;//avih
DWORDcb;//本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)structsize
DWORDdwMicroSecPerFrame;//视频帧间隔时间(以毫秒为单位)
DWORDdwMaxBytesPerSec;//这个AVI文件的最大数据率
DWORDdwPaddingGranularity;//数据填充的粒度
DWORDdwFlags;//AVI文件的全局标记,比如是否含有索引块等
DWORDdwTotalFrames;//总帧数
DWORDdwInitialFrames;//为交互格式指定初始帧数(非交互格式应该指定为0)
DWORDdwStreams;//本文件包含的流的个数
DWORDdwSuggestedBufferSize;//建议读取本文件的缓存大小(应能容纳最大的块)
DWORDdwWidth;//视频图像的宽(以像素为单位)
DWORDdwHeight;//视频图像的高(以像素为单位)
DWORDdwReserved[4];//保留
}AVIMAINHEADER;
fcc就是“avih”
cb也就是图中S3部分,为AVIMAINHEADER结构大小减去8.恒为56.
具体也可参看/en-us/library/windows/desktop/dd318180(v=vs.85).aspx
4、strl这个LIST
同样的,SIZE部分表示的是“strl”到LIST结束的大小
这个LIST内部可包含“strh”,“strf”,“strd”,“strn”四种CHUNK,其中“strd”,“strn”是可选的,可以没有就不讲了,讲一下strh和strf。
Strh结构体如下
typedefstruct_avistreamheader{
FOURCCfcc;//必须为‘strh’
DWORDcb;//本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)
FOURCCfccType;//流的类型:‘auds’(音频流)、‘vids’(视频流)、‘mids’(MIDI流)、‘txts’(文字流)
FOURCCfccHandler;//指定流的处理者,对于音视频来说就是解码器
DWORDdwFlags;//标记:是否允许这个流输出?调色板是否变化?
WORDwPriority;//流的优先级(当有多个相同类型的流时优先级最高的为默认流)
WORDwLanguage;
DWORDdwInitialFrames;//为交互格式指定初始帧数
DWORDdwScale;//这个流使用的时间尺度
DWORDdwRate;
DWORDdwStart;//流的开始时间
DWORDdwLength;//流的长度(单位与dwScale和dwRate的定义有关)
DWORDdwSuggestedBufferSize;//读取这个流数据建议使用的缓存大小
DWORDdwQuality;//流数据的质量指标(0~10,000)
DWORDdwSampleSize;//Sample的大小
struct{
shortintleft;
shortinttop;
shortintright;
shortintbottom;
}rcFrame;//指定这个流(视频流或文字流)在视频主窗口中的显示位置
//视频主窗口由AVIMAINHEADER结构中的dwWidth和dwHeight决定
}AVISTREAMHEADER;
这里fcc为“strh”,cb恒为56.
其他参数值参看/en-us/library/windows/desktop/dd318183(v=vs.85).aspx
Strf这个结构体对于视频流如下:
typedefstructtagBITMAPINFOHEADER{
FOURCCfcc;//必须为‘strf’
DWORDcb;//本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)
DWORDbiSize;
LONGbiWidth;
LONGbiHeight;
WORDbiPlanes;
WORDbiBitCount;
DWORDbiCompression;
DWORDbiSizeImage;
LONGbiXPelsPerMeter;
LONGbiYPelsPerMeter;
DWORDbiClrUsed;
DWORDbiClrImportant;
}BITMAPINFOHEADER;
Fcc为“strf”,cb恒为40.这里我没有考虑后面跟colortable的情况,
具体可参看/en-us/library/windows/desktop/dd318229(v=vs.85).aspx
对于音频流
typedefstruct{
FOURCCfcc;//必须为‘strf’
DWORDcb;//本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)
WORDwFormatTag;
WORDnChannels;
DWORDnSamplesPerSec;
DWORDnAvgBytesPerSec;
WORDnBlockAlign;
WORDwBitsPerSample;
WORDcbSize;//2
}WAVEFORMATEX;
WORDcbData;//
这里cbSize的值是cbDate的大小,cbSize和cbDate可根据情况调整
Fcc为“strf”,cb为其后至结构结束的大小,包括cbData。
具体参看/en-us/library/windows/desktop/dd390970(v=vs.85).aspx
5、JUNK这个CHUNK
JUNK这个部分包含4字节的“JUNK”,后跟4字节的SIZE,再后面跟一串字节,比如SIZE为100,则后跟100字节的数据,这部分数据是无意义的数据,可随意写入,只要SIZE部分正确即可
6、movi这个LIST
这个LIST包括4字节的“LIST”,4字节的SIZE,4字节的“movi”后跟若干个CHUNK。
这些CHUNK的格式为4字节的头,4字节的SIZE,加上具体的码流数据,比如:
[“00db”,0x08,xxxxxxxx]表示一个视频帧;[“01wb”,0x03,xxx]表示一个音频帧。
如果帧数据长度是奇数,那么SIZE部分还是奇数,但是在码流数据后面要补一个0,使下一个CHUNK从偶数位开始。
7、idx1这个CHUNK
这个CHUNK包括4字节的“idx1”和4字节的SIZE,表示其后跟的数据长度,后面跟上若干个如下结构的数据:
typedefstruct
{
FOURCCckid;//记录数据块中子块的标记
DWORDdwFlags;//表示chid所指子块的属性
DWORDdwChunkOffset;//子块的相对位置
DWORDdwChunkLength;//子块长度
}INDEXHEADER;
这是用来对movi中的帧数据进行索引的,所以
ckid的值与movi中的“00db”,“01wb对应”;
dwFlags对于关键桢和音频帧一般置为AVIIF_KEYFRAME(#defineAVIIF_KEYFRAME0x00000010L),
对于普通桢置为AVIIF_NONE(#defineAVIIF_NONE0x00000000L);
dwChunkOffset即对应的帧距离图中S10的偏移;
dwChunkLength即帧数据的长度
比如在movi中帧信息如下:
[“00db”,0x0B,xxxxxxxxxxx]
那么在idx部分的索引信息为:
[“00db”,AVIIF_KEYFRAME,some_offset,0x0B]
============================================
结束