AVI文件格式完整解析

首先AVI是一种RIFF文件,所以先介绍一下RIFF文件

一、RIFF文件简介

RIFF是Microsoft提出的一种多媒体文件的存储方式,不同编码的音频、视频文件,可以按照它定义的存储规则保存、记录各自不同的数据,如:数据内容、采集信息、显示尺寸、编码方式等。在播放器或者其它提取工具读取文件的时候,就可以根据RIFF的规则来分析文件,合理的解析出音频、视频信息,正确进行播放。常见的RIFF文件有WAV文件和AVI文件,它们都是遵循RIFF格式保存播放信息和播放数据的。

 

二、RIFF文件的组织结构

在RIFF的文件存储规则中,主要有几个重要的概念需要理解,它们是FOURCC, CHUNK, LIST。下面会对这几个概念进行详细解释。

RIFF格式是一种树状的结构,其基本组成单元为LIST和CHUNK,CHUNK类似文件存放实际的数据,LIST类似目录,可嵌套目录或包含文件。

1、FOURCC

一个FOURCC(four character code)是一个占4个字节的数据,一般表示4个ASCII字符。在RIFF文件格式中,FOURCC非常普遍。FOURCC一般是四个字符,如”abcd”这样的形式,也可以三个字符包含一个空格,如”abc ”这样的形式。

可用如下结构体来表示:

typedef struct FOURCC

{

char tag1;

char tag2;

char tag3;

char tag4;

}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对应的结构如下

typedef struct _avimainheader{

FOURCC fcc;//avih

DWORD cb;//本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)structsize

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;

fcc就是“avih”

cb也就是图中S3部分,为AVIMAINHEADER结构大小减去8.恒为56.

具体也可参看http://msdn.microsoft.com/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结构体如下

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;

这里fcc为“strh”,cb恒为56.

其他参数值参看http://msdn.microsoft.com/en-us/library/windows/desktop/dd318183(v=vs.85).aspx

Strf这个结构体对于视频流如下:

typedef struct tagBITMAPINFOHEADER {

  FOURCC fcc;//必须为‘strf’

  DWORD cb;//本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)

  DWORD biSize;

  LONG  biWidth;

  LONG  biHeight;

  WORD  biPlanes;

  WORD  biBitCount;

  DWORD biCompression;

  DWORD biSizeImage;

  LONG  biXPelsPerMeter;

  LONG  biYPelsPerMeter;

  DWORD biClrUsed;

  DWORD biClrImportant;

} BITMAPINFOHEADER;

Fcc为“strf”,cb恒为40.这里我没有考虑后面跟color table的情况,

具体可参看http://msdn.microsoft.com/en-us/library/windows/desktop/dd318229(v=vs.85).aspx


对于音频流

typedef struct {

  FOURCC fcc;//必须为‘strf’

  DWORD cb;//本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)

  WORD  wFormatTag;

  WORD  nChannels;

  DWORD nSamplesPerSec;

  DWORD nAvgBytesPerSec;

  WORD  nBlockAlign;

  WORD  wBitsPerSample;

  WORD  cbSize;//2  

} WAVEFORMATEX;

WORD  cbData;//

这里cbSize的值是cbDate的大小,cbSize和cbDate可根据情况调整

Fcc为“strf”,cb为其后至结构结束的大小,包括cbData。

具体参看http://msdn.microsoft.com/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,表示其后跟的数据长度,后面跟上若干个如下结构的数据:

typedef struct

{

FOURCC ckid; //记录数据块中子块的标记

DWORD dwFlags; //表示chid所指子块的属性

DWORD dwChunkOffset; //子块的相对位置

DWORD dwChunkLength; //子块长度

}INDEXHEADER;

这是用来对movi中的帧数据进行索引的,所以

ckid的值与movi中的“00db”,“01wb对应”;


dwFlags对于关键桢和音频帧一般置为AVIIF_KEYFRAME(#define AVIIF_KEYFRAME      0x00000010L),

对于普通桢置为AVIIF_NONE(#define AVIIF_NONE          0x00000000L);


dwChunkOffset即对应的帧距离图中S10的偏移;


dwChunkLength即帧数据的长度


比如在movi中帧信息如下:

[“00db”,0x0B,xxxxxxxxxxx]

那么在idx部分的索引信息为:

[“00db”,AVIIF_KEYFRAME,some_offset,0x0B]


============================================

结束



 
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值