AVI封装格式解析

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

一、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文件通常有如下几个子块组成:

  1. RIFF文件头:块的数据类型是AVI;
  2. “hdrl” list:音视频信息,描述媒体流信息;
  3. “info” list:编码该AVI的程序信息;
  4. “junk” chunk:无用数据,用于字节对齐;
  5. “movi” list:交错排列的音视频数据;
  6. “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 表示关键帧
在这里插入图片描述

四、总结

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值