先放上这张图片,是让大家有一个直观的感受,avi就像一个容器,只要按照这个框架依次读取数据,就能很好的解析出数据来。鉴于本人习惯,我喜欢看图说话,所以接来下会放上很多avi格式的二进制图片,以便更好详细说明读取过程的信息。
(图1)
如图(1)所示,这是avi的二进制图,AVI文件利用AVI RIFF格式(RIFF(Resource Interchange FileFormat,资源互换文件格式)是微软公司定义的一种用于管理windows环境中多媒体数据的文件格式,)
构造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大小。注
意:文件是从右往左读取,故而是(08 99 2B B6)=144255926字节~而我打开文件实际字节是144,255,934,这是因为前面的"RIFF"和本身这四个表示大小的数据字节没有算进去,故144255926+8=144 255 934。
紧接着后面四个字节表示AVI说明这是一个AVI格式的视频。
所有的AVI文件必须包含两个LIST块。这些块定义流格式和stream数据。AVI文件也可能包含一个索引块,此块定义文件中的数据块位置。包含上述组件的AVI文件的格式为:
RIFF ('AVI '
LIST ('hdrl'
)
LIST ('movi'
.
)
['idx1'<AVI Index>]
)
(3)
紧接着是就是一个LIST块:后面四个字节表示这个LISI的大小E0 0F 02 00===135 136字节怎么验证我说的对不对了。。。呵呵呵。。。看图说话.见图(4)这是下一个LIST块。他所在的字节处20FF0H=135152,由于是在该行的第四字节出,还需往后移动4字节:135156
,刚刚表示第一个LIST大小的四字节所在位置是:20字节处,故20+135 136(第一个LIST块大小)=135 156(第二个LIST块处得字节数)
(4)
接下来再回到图(3)
正如我们所说LIST"hdrl" 和LIST "movi"块用子块来表示其数据。接下来先介绍hdrl块
LIST ('hdrl'
'avih'(<Main AVI Header>)
LIST ('strl'
'strh'(<Streamheader>)
'strf'(<Streamformat>)
'strd'(additional headerdata)
.
)
(5)
列表的结构为:‘LIST’: listSize listType:listData,所以我们看到在LIST后面是大小,接着是本列表的具体类型hdrl,
再来看块的结构:ckID ckSize ckData ——ckID是一个表示块类型的四字符码;ckSize占用4字节,记录了整个块的大小;ckData为实际的块数据
所以,ckID在这里指的是avih,接着就是大小38 00 00 00=56字节,其实打开任何avi格式,你都可以发现此处都是38 00 00 00,因为。。。格式固定。。。如下:
typedefstruct {
DWORD dwMicroSecPerFrame; //定义视频帧之间的时间间隔,这个值确定文件的总体时速。
DWORD dwMaxBytesPerSec; //定义文件的大致数据率,这个值确定要显示由此Main Header及流的Header chunks所含其他参数定义的AVI系列,系统必
须达到的传输速率(每秒字节数)
DWORD dwReserved1; //保留字
DWORD dwFlags; //包含文件中的任何标志字。(如有无”idx1”块,为确定数据的显示次序所要用到的索引,AVI文件是否Interlaced,是否含版权
信息等)
DWORD dwTotalFrames; //文件中含的数据帧个数。
DWORD dwInitialFrames; //对interlaced文件,确定在文件中在AVI系列初始帧之前所含的数据帧的个数。
DWORD dwStreams; //文件中所含流的个数,如既有视频又有音频的文件含两个流。
DWORD dwSuggestedBufferSize; //定义读文件所建议的Buff大小,大于最大的Chunk的大小。
DWORD dwWidth; //定义AVI文件就像素而言的宽与高
DWORD dwHeight; //
DWORD dwScale; //与dwRate一起定义文件所要用到的通用时间刻度,dwRate/dwSale为每秒的采样时间刻度。
DWORD dwRate; //
DWORD dwStart; //定义AVI文件的起始时间。通常设为0
DWORD dwLength; //定义AVI文件的长度。
}MainAVIHeader;
dwFlags
对应:
AVIF_HASINDEX:标明该AVI文件有"idx1"块
AVIF_MUSTUSEINDEX:标明必须根据索引表来指定数据顺序
AVIF_ISINTERLEAVED:标明该AVI文件是interleaved格式的
AVIF_WASCAPTUREFILE:标明该AVI文件是用捕捉实时视频专门分配的文件
AVIF_COPYRIGHTED:标明该AVI文件包含有版权信息
(6)
主文件头后紧跟一个或几个"strl"块(每个数据流需要一个"strl" 块)。
每个"strl"块必须包含一个Stream头和Stream格式块。
Stream头由四个字符"strh"标记,Stream格式块由四个字符"strf"标记,此外"strl"块也可能包含一个流数据块,流数据块由四个字符”strd”来标识。
如图(6)LIST(列表)后面是表示大小,然后是strl,表示一条流,接着strh,表示stream头标识,接着是大小,一定是56字节,。。。格式固定嘛。。。
从vids开始后面表示的是数据,格式如下
Stream头的数据格式定义为:
typedefstruct {
FOURCC fccType; //若此流含的是video数据,此域值为"vids",若为audio数据,则为”auds”.
//‘mids’(MIDI流)、‘txts’(文字流)
FOURCC fccHandler; //为四个字符,描述数据所用的压缩、解压缩算法。
DWORD dwFlags; //包含流数据所用的任何标志字(如此流数据用到变化的调色板,只有在用户显式说明时才对此流数据进行render)
// 标记:是否允许这个流输出?调色板是否变化?
DWORD dwReserved1; //保留字// 流的优先级(当有多个相同类型的流时优先级最高的为默认流)
DWORD dwInitialFrames; //用于interlaced文件,定义在文件中在AVI系列初始帧之前所含的数据帧的个数。
DWORD dwScale; //与dwRate一起定义回放速率。
DWORD dwRate; //dwScale /dwRate = 每秒的采样数
DWORD dwStart; //系列的起始时间
DWORD dwLength; //系列的长度
DWORD dwSuggestedBufferSize; //回放所需的Buff大小 // 读取这个流数据建议使用的缓存大小
DWORD dwQuality; //数据质量标志字// 流数据的质量指标(0~ 10,000)
DWORD dwSampleSize; //采样大小
}AVIStreamHeader;
依据我的经验,
FOURCC fccHandler;如果显示的是V210 就表示该视频未经过压缩,是一个未压缩的avi视频
在stream头(”strh”)块之后紧接着出现的是stream格式块("strf") ,它描述流中数据的格式。对视频流而言,这一块中的信息为一个BITMAPINFO结构(包含调色板信息),对音频流而言,这一块中的信息为一个WAVEFORMATEX或PCMWAVEFORMAT结构(WAVEFORMATEX结构为WAVEFORMAT结构的扩展版本)。
如果 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 |
//以上两幅图可以忽略。。。以免影响看文章的心情。。。
"strl"块也可能包含一个流数据块("strd"chunk),它一般在stream格式块("strf")之后,这一块的格式和内容由压缩或解压缩的驱动程序来定义。一般驱动程序利用这些信息来配置读写RIFF文件的应用程序,而不必解码它们。
接下来我们来看后面的
此处我也不太懂,,,望知道的留言解释,没有相关资料提到过这个indx块...不过貌似他很像索引。。。但是索引块是在最后啊,而且他后面的数据都是00000000000.。。。。。。通过他后面的四字节大小可以知道是00 00 FF F8=65528
我们就直接跨过65528字节大小到 下一处.
可以看到这是到了音频。。。你看到那个auds了吗?哈哈~~~其他都一样了~~
在此处强调一个细节:
AVI播放器将LIST "hdrl"块中的Stream头结构与LIST"movi"块中的stream数据通过利用"strl"块的次序联系起来.第一个"strl"块用于stream 0, 第二个用于stream 1,依次下去。例如,如果第一个"strl" 块描述wave audio数据,则wave audio数据在stream 0中。同样,如果第二个"strl" 块描述video数据,则此video数据在stream 1中。
所以你会看到第一个视频流中strl中:后面有一个标志是"00db",而这里是第二个strl,表示音频,固有一个"01wb"
接下来是就可以跳到数据部分了“movi”。。。好累啊~~改天写吧。。。