因为接下来要分析的漏洞CVE-2010-2553,涉及到AVI文件格式。
所以,有必要详细了解一下AVI文件格式,这样,才能知道怎样构造出能达到漏洞利用的样本。
——当你的才华还配不上你的野心时,请静下来好好努力!
1、AVI简介
1.1、AVI基本概念
AVI
是音频视频交错(Audio Video Interleaved
)的缩写,它是Microsoft
于1992年11月开发的一种符合RIFF文件规范
的多媒体容器格式,作为其Windows视频软件
的一部分。AVI文件
可以在文件容器
中同时包含音频
和视频
数据,该文件容器允许同步播放
音频和视频。
许多AVI文件
使用1996年2月由Matrox OpenDML组
开发的文件格式扩展名。这些文件受Microsoft
支持,并且被非正式地称为“AVI 2.0”
。2010年,美国政府
的国家档案
和记录管理局
将AVI定义为官方文件格式
,用于保存数字视频
。
AVI
文件格式是Resource Interchange File Format
(RIFF:资源交换文件格式)的子格式
。RIFF
是一种通用文件容器格式
,用于将数据
存储在带标签
的块中。它主要用于存储多媒体
,例如声音
和视频
,尽管它也可以用于存储任意数据
。RIFF文件
所包含的数据类型
由该文件的扩展名
来标识,能以RIFF文件
存储的数据包括:音频视频交错格式数据
(.AVI)、波形格式数据
(.WAV)、位图格式数据
(.RDI)、MIDI格式数据
(.RMI)、调色板格式数据
(.PAL)、多媒体电影格式数据
(.RMN)、动画光标格式数据
(.ANI)、其它RIFF文件
(.BND)。
可以查看AVI文件结构
的软件:
1、RIFF File Viewer - RIFFPad v0.73 by Menasoft
2、AtomicBrowser Version 2.0, Written by David Mojdehi
1.2、AVI文件类型
基本上,有3种类型
的AVI文件:
AVI1.0
: 原始的,旧的
AVI文件。Open-DML(AVI2.0)
: AVI文件格式的扩展
,版本1.02已在1996年2月28日推出。最重要的改进
是:
- 对
文件大小
几乎没有限制(例如,比NTFS所允许的要多得多)- 减少了33%的
开销
Hybride-Files
(混合文件): 出于兼容性
原因,Open-DML文件
包含附加的旧版索引
。这不是那些文件的“官方”
词汇,但它很好地描述了那种文件类型
。仅包含一个RIFF列表
的Hybride文件可以被视为任一文件类型
。
AVI 1.0
是最基本的格式,由于索引地址
与大小
用4字节
表示,所以最大支持4G容量
,而且与文件系统
类型有关,如下:1
2
3
4
5
6-- Video for Windows (AVI 1.0)
- FAT (FAT16): 4GB (2GB practical, safe)
- FAT32: 4GB (2GB practical, safe)
- NTFS: 4GB (2GB practical, safe)
为了安全一般限制为2G。
1.3、基本数据结构
1.3.1、RIFF文件的基本数据结构
Chunk
是组成RIFF文件的基本单元
,其基本结构
如下:
1 | struct chunk{ |
id
: 此块的标识符
,由4个ASCII字符
组成的FourCC
数据格式标识符,用以识别块中所包含的数据
。如:“RIFF”
、“LIST”
、“AVI ”
、“WAVE”
等等。size
: 存储在data域
中的数据的长度
,id
和size
域的大小不包括
在该值内。data
: 块内容,具有前一个字段
中给定大小的数据。其中的数据是以字(Word)为单位
排列的,如果该数据长度为奇数
,则在最后添加一个空字节(Null)
。
两个块标识符“RIFF”
和“LIST”
引入了可以包含子块
的块。而其它块仅能含有数据
。“RIFF”
和“LIST”
类型的Chunk结构
如下:
1 | struct chunk{ |
可以看出“RIFF”
和“LIST”
也是Chunk
,只是它的data
由type
和restdata
两部分组成。
type
: 由4个ASCII字符
组成的FourCC
数据格式标识符,代表“RIFF”
文件的类型,如:“WAVE”
、“AVI ”
;或者是“LIST”
块的类型,如AVI文件中的列表“hdrl”
、“movi”
。restdata
:data
中除type
所占的4个字节后剩余的数据
,包括块内容,包含若干“Chunk”
和“LIST”
。
FourCC:
FourCC
(“four-character code”)是四个字节
(通常为ASCII
)的序列,用于唯一标识数据格式
。在RIFF
文件格式中,FourCC
非常普遍,struct chunk
中的id
成员,“RIFF”
和“LIST”
的type
成员,起始标识
等信息都是用FourCC
表示的。FourCC
一般是四个字符,如'abcd'
这样的形式,也可以三个字符
包含一个空格
,如'abc '
这样的形式。AVI
文件格式使用FourCC
编码标识流类型
,数据块
,索引条目
和其他信息。
1.3.2、AVI文件的基本数据结构
在AVI文件
中,有两种基本单元“Chunks”
和“Lists”
,与RIFF文件
中的基本单元
差别不大,就是字段名称
稍有不同,其结构如下:
Chunks:
1
2
3
4
5typedef struct {
DWORD dwFourCC;
DWORD dwSize; //data
BYTE data[dwSize]; //contains headers or video/audio data
}CHUNK;
dwFourCC
: 标识本“CHUNK”
所包含的数据类型
,如:“avih”
(AVI Header)、“strh”
(Stream Header)、“strf”
(Stream Format)、“00dc”
(编号为00的视频数据块)。dwSize
: 本CHUNK所包含数据的大小
,不包括dwFourCC
和dwSize
所占的8个字节。data
: 本CHUNK所包含的数据
,大小由上一个字段dwSize
指定。可以为Header
、视频
/音频
数据。
Lists:
1
2
3
4
5
6typedef struct {
DWORD dwList;
DWORD dwSize; //dwFourCC+data
DWORD dwFourCC;
BYTE data[dwSize-4]; //contains Lists and Chunks
}LIST;
dwList
: LIST的类型
,其值可以为“RIFF”
(“RIFF-List”)或“LIST”
(“List”)。dwSize
: 本LIST所包含数据的大小
,嵌套List
和Chunk
的数据大小之和
。包含dwFourCC
和data
。dwFourCC
: 由4个ASCII字符
组成的FourCC
数据格式标识符,代表“RIFF”
文件的类型,如:“WAVE”
、“AVI ”
;或者是“LIST”
块的类型,如AVI文件
中的列表“hdrl”
、“movi”
。data
: 本LIST所包含的数据
,其大小为dwSize-4
。数据内容
可以是若干个List
和Chunk
。
2、AVI文件结构
2.1、AVI文件整体布局
我们用如下的方式来表示一个LIST块
(dwSize省略):
1 | LIST (dwFourCC (data)) |
可选块
我们用“[]”
括起来:
1 | ['idx1' (<AVI Index>) ] |
AVI文件格式
将文件的数据分为一个一个“Chunk”
,每个“Chunk”
都由FourCC
标签标识。AVI文件格式
采用RIFF格式
的文件中单个“Chunk”
的形式,然后细分为两个必须的“List Chunk”
(“hdrl”和“movi”)和一个可选的“Index Chunk”
(“idx1”)。下面是一个简化的
AVI文件布局:
1 | RIFF ('AVI ' |
“hdrl”列表
定义了本AVI文件所保存的数据的格式
,是第一个
必须的LIST块
。“movi”列表
保存的是AVI的音频/视频序列数据
,是第二个
必须的LIST块
。“idx1”
为“movi”列表
中包含的音频/视频序列数据块
在文件中位置
的列表
。
AVI文件的实际数据
中,使用了列表(List)
和块(Chunk)
的形式来组织。列表(List)
可以嵌套列表(List)
和块(Chunk)
。整个AVI文件
可以看成一个List数据块
,其dwList
为“RIFF”
,称为“RIFF-List”
块,其dwFourCC
为“AVI”
。一个AVI文件中只允许存在一个RIFF块
。RIFF块中包含一系列的子块
,其中有一种子块的dwList
为“LIST”
,称为LIST块
,LIST块
中可以再包含一系列的子块
,但除了LIST块
外的其他所有的子块
都不能再包含子块。
“hdrl”
和“movi”
LIST块使用子块
作为它们的数据
,我们将其展开,以下示例显示了一个较为完整的
AVI文件的布局:
1 | RIFF ('AVI ' |
每个AVI文件
都具有以下布局
:
1 | RIFF AVI //强制 |
将其中dwFourCC ='AVI'
的RIFF-List称为'RIFF-AVI-List'
,将其中dwFourCC ='AVIX'
的RIFF-List称为'RIFF-AVIX-List'
。
与uint32
(4字节)的表示范围
不同,这些列表的大小限制
不是4GB
,而是
- 对于
AVI 1.0
:大小(RIFF-AVI
) <2GB
- 对于
Open-DML
:
- size(
RIFF-AVI
) <1GB
(假设某些混合应用程序(例如VirtualDub!)为2GB)- size(
RIFF-AVIX
) <2GB
由于Windows XP
会在未找到旧索引
的情况下坚持读取整个第一个RIFF AVI列表
,并且由于旧索引
会导致开销
,因此建议创建尽可能小
的RIFF-AVI-List
。
2.2、hdrl List(Headerlist)
“hdrl List”
是AVI文件的文件头
,其中包含的数据是有关视频的MetaData
(元数据),例如其宽度
、高度
和帧频
。“hdrl List”
块包含两种子块
,一种是dwFourCC
为“avih”
的Chunk
,另一种是dwFourCC
为“strl”
的List
。
2.2.1、avih Chunk(AVI Header)
“avih”
块用于存储AVI文件的全局信息
,如:流的数量
、视频的宽度
和高度
等。此结构定义如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20typedef struct {
DWORD dwFourCC; // 必须为'avih'
DWORD dwSize; // 本数据结构的大小,不包括最初的8个字节(dwFourCC和dwSize两个字段)
BYTE data[dwSize]; // AVIMainHeader struct
}CHUNK;
typedef struct {
DWORD dwMicroSecPerFrame; // 每帧的持续时间(以毫秒ms为单位),定义avi的显示速率
DWORD dwMaxBytesPerSec; // 最大的数据传输率
DWORD dwPaddingGranularity; // 数据填充的粒度
DWORD dwFlages; // AVI文件的特殊属性,如是否包含索引块,音视频数据是否交叉存储
DWORD dwTotalFrame; // 文件中的总帧数
DWORD dwInitialFrames; // 说明在开始播放前需要多少桢
DWORD dwStreams; // 文件中包含的数据流个数
DWORD dwSuggestedBufferSize; // 建议使用的缓冲区的大小,
// 通常为存储一桢图像以及同步声音所需要的数据之和
DWORD dwWidth; // 图像宽
DWORD dwHeight; // 图像高
DWORD dwReserved[4]; // 保留值
} AVIMainHeader;
dwFourCC
: 标识此块为“avih”
,用于存储AVIMainHeader
结构体数据。dwSize
:AVIMainHeader
结构体的字节数
。dwMicroSecPerFrame
: 一个视频帧
的持续时间
(以微秒
为单位)。可以忽略
此值(请参阅Stream Header),但任何AVI编写器均应正确写入该值。
重要说明
:某些AVI修改软件,例如AVIFrate
,会将帧速率值
写入Stream Header
,而不是dwMicroSecPerFrame
。 因此,dwMicroSecPerFrame不应该
被认为是可靠的
!dwMaxBytesPerSec
: 指定文件的大致最大数据速率
。这个值表示系统每秒必须处理的字节数
,以显示AVI序列,该序列由Main Header
和Stream Header
块中包含的其他参数
指定。该值也不重要。其可靠性不应被高估。dwPaddingGranularity
: 指定数据对齐方式
(以字节
为单位)。将数据
填充为该值的倍数
。dwFlages
: 见下文。dwTotalFrame
: 指定文件中数据帧的总数
。包含在RIFF-AVI
列表中的视频帧数
(如果存在RIFF-AVIX-List
,则不应包含整个文件
中的帧总数
。某些声称处理AVI文件的工具
甚至假定了这一点,但它显然违反了Open-DML
文件格式规范。此类应用程序已损坏
。)。由于某些AVI文件muxer在此处写入了错误的值,因此不应认为此值是可靠的。dwInitialFrames
: 为交错格式
指定初始帧数
(非交错格式
应该指定为0
)。如果要创建交错文件
,请在该成员中的AVI序列的初始帧
之前指定文件中的帧数
。要为音频驱动程序
提供足够的音频以供使用,必须将交错文件
中的音频数据
相对于视频数据
倾斜。通常,音频数据
应向前
移动足够的帧,以允许大约0.75秒
的音频数据
被预加载
。dwInitialRecords
成员应设置为音频向前的帧数
。还要在音频流头
中为AVIStreamHeader
结构的dwInitialFrames
成员设置相同的值。dwStreams
: 文件中包含的数据流个数
。例如,一个带有音频
和视频
的文件有两个流
。dwSuggestedBufferSize
: 指定用于读取文件的建议缓冲区大小
。通常,此大小应足够大以包含文件中最大的块
。如果设置为零
,或者设置得太小
,则播放软件将不得不在播放过程
中重新分配内存
,这会降低性能
。对于交错文件
,缓冲区大小应足够大以读取整个记录
,而不仅仅是块
。dwWidth
: 视频流宽度
。以像素
为单位。dwHeight
: 视频流高度
。以像素
为单位。dwReserved
:保留
。将这个数组设置为0
。
dwFlages
中有效的Flags
:
AVIF_HASINDEX
: 该文件有索引
。AVIF_MUSTUSEINDEX
: 指示应用程序应该使用索引
,而不是文件中块的物理顺序
,来确定数据表示的顺序
。例如,这个标志可以用来创建一个帧列表
来编辑。AVIF_ISINTERLEAVED
: Stream适当的相互交错。
AVIF_WASCAPTUREFILE
: 表示AVI文件
是专门分配的用于实时视频采集
的文件。应用程序在对设置了该标志的文件进行写入之前
应该警告用户,因为用户可能会对该文件进行整理
。AVIF_COPYRIGHTED
: 表示AVI文件包含有版权的数据和软件
。当使用这个标志时,软件不应该允许复制数据
。AVIF_TRUSTCKTYPE
(Open-DML only!): 该标志表示索引
中的关键帧标志
(AVIIF_KEYFRAME)是可靠的。如果未在Open-DML
文件中设置此标志,则关键帧标志
可能存在缺陷
,而不会从技术上
使文件无效。
2.2.2、strl List(Stream Header List)
“strl List”
用于存储AVI文件中的数据流
(音频流
、视频流
、字幕流
)的相关信息。在“hdrl List”
中的“avih Chunk”
之后,有一个或多个“strl List”
。
- 1、AVI文件中有多少个
数据流
(视频流、音频流、字幕流),这里就对应有多少个“strl List”
。每个“strl List”
都包含AVI文件中一个数据流
的相关信息。- 2、每个
“strl List”
中至少包含一个“strh Chunk”
和一个“strf Chunk”
。- 3、
“strd Chunk”
和“strn Chunk”
是可选的。- 4、根据
“strl List”
在“hdrl List”
中的顺序,“hdrl List”
中的Stream Header
与“movi List”
中的Stream Data
是一一对应的。第一个“strl List”
应用于Stream 0
,第二个“strl List”
应用于Stream 1
,以此类推。
2.2.2.1、strh Chunk(Stream Header)
“strh Chunk”
用于描述“strl List”
对应的数据流
的相关信息。此Chunk
中的data
中存储的是AVIStreamHeader
结构体数据,其结构如下:
1 | typedef struct { |
dwFourCC
: 标识此块为“strh”
,用于存储AVIStreamHeader
结构体数据。dwSize
:AVIStreamHeader
结构体的字节数
。fccType
: 表示数据流的种类
,“vids”
(视频流)、“auds”
(音频流)、“mids”
(MIDI流)、“txts”
(字幕流)。fccHandler
: 要使用的编解码器
的FourCC
。dwFlags
: 数据流属性
,定义了以下标志:
AVISF_DISABLED
: 默认情况下不应激活
此数据流。AVISF_VIDEO_PALCHANGES
: Stream是使用调色板
的视频流
,其中在播放过程
中调色板
会发生变化。wPriority
: 此数据流的播放优先级
,当有多个相同类型的流
时优先级最高
的为默认流
。wLanguage
: 音频的语言代号
。dwInitalFrames
: 指定交错文件
中音频数据
在视频帧
之前的偏移量
。通常,这是大约0.75秒
。如果要创建交错文件
,请在该成员的AVI序列的初始帧
之前指定文件中的帧数
。有关更多信息,请参见AVIMainHeader
结构的dwInitialFrames
成员的备注。dwScale
:数据量
,视频
的每桢的大小
或者音频
的采样大小
。与dwRate
一起使用以指定此流
将使用的时间尺度
。将dwRate
除以dwScale
可得出每秒的采样数
。对于视频流
,这是帧速率
。对于音频流
,此速率对应于播放音频的nBlockAlign字节
所需的时间
,而对于PCM音频
,这只是采样速率
。dwScale和dwRate应该互质
。测试表明,例如10000000/400000
代替25/1
会导致文件在某些硬件MPEG4播放器
上不起作用。dwRate
: 参考dwScale。dwStart
: 指定此流的开始时间
。单位由AVIStreamHeader
中的dwRate
和dwScale
成员定义。通常,它是0
,但是它可以为不与文件同时启动的流
指定延迟时间
。对于VBR音频
,此值指示在流开始之前
要播放的无声帧数
。dwLength
: 指定流的长度
,以dwRate
和dwScale
定义的单位为单位。dwSuggestedBufferSize
: 指定应使用多大的缓冲区
来读取此流
。通常,它包含一个与流中存在的最大块
相对应的值。使用正确的缓冲区大小
可使播放效率更高
。如果您不知道正确的缓冲区大小
,请使用零
。可以
为0(在这种情况下,应用程序必须猜测
),但不应该
为0,因为Microsoft
的AVI解析器
在某些情况下无法正确处理
此情况(例如,Open-DML
文件中的MP3-CBR
)。dwQuality
: 指定流中数据质量
的指示符。质量表示为0到10000
之间的数字。对于压缩数据
,这通常表示传递给压缩软件的质量参数
的值。如果设置为–1
,驱动程序将使用默认质量值
。dwSampleSize
: 指定单个数据样本的大小
。如果样本大小不同
,则将其设置为0
。如果该数字不为0
,则可以将多个数据样本
分组到文件内的单个块
中。如果为0
,则每个数据样本
(例如视频帧
)必须位于单独的块
中。对于视频流
,此数字通常为0
,但如果所有视频帧的大小相同
,则可以为非0
。对于音频流
,此数字应与描述音频的WAVEFORMATEX
结构的nBlockAlign
成员相同。rcFrame
: 指定由AVIMainHeader
结构的dwWidth
和dwHeight
成员指定的影片矩形
内的字幕
或视频
流的目标矩形
。rcFrame
成员通常用于支持多个视频流
。将此矩形设置为与影片矩形
对应的坐标,以更新整个影片矩形
。该成员的单位是像素
。目标矩形
的左上角相对于影片矩形
的左上角。
该结构的某些成员也存在于AVIMainHeader
结构中。AVIMainHeader
结构中的数据应用于整个文件
,而AVIStreamHeader
结构中的数据应用于一个流
。
2.2.2.2、strf Chunk(Stream Format)
“strf Chunk”
紧跟在“strh Chunk”
之后,其描述了数据流中数据的格式
。此Chunk
中包含的数据取决于数据流的类型
。对于视频流
,该信息是BITMAPINFO
结构,包括适当的调色板
信息。对于音频流
,该信息是WAVEFORMATEX
结构。
视频流(BITMAPINFO)
BITMAPINFO
结构定义了一个DIB
(Device-Independent Bitmap:设备无关位图)的尺寸
和颜色
信息。
1 | typedef struct { |
dwFourCC
: 标识此块为“strf”
,用于存储BITMAPINFO
结构体数据。dwSize
:BITMAPINFO
结构体的字节数
。bmiHeader
: 一个BITMAPINFOHEADER
结构,包含关于DIB的尺寸
和颜色格式
的信息。bmiColors
: bmiColors成员包含以下之一:
RGBQUAD
的数组。数组元素组成了颜色表
。- 一个16位
无符号整数数组
,用于指定当前实现的逻辑调色板
中的索引
。对于使用DIB
的函数
,可以使用bmiColors
。数组中的条目数
取决于BITMAPINFOHEADER
结构的biBitCount
和biClrUsed
成员的值。bmiColors
表中的颜色按重要性
顺序显示。
DIB
(Device-Independent Bitmap:设备无关位图)由两个不同的部分
组成:描述位图的尺寸
和颜色
的BITMAPINFO
结构体,以及定义位图像素
的字节数组
。数组中的位
打包在一起,但是每条扫描线
必须用0
填充,以在LONG数据类型边界
上结束。如果位图的高度为正
,则位图为自下而上的DIB
,其原点为左下角
。如果高度为负
,则位图为自上而下的DIB
,其原点为左上角
。
当位图数组
紧跟在BITMAPINFO
头之后时,位图被压缩
。压缩的位图由单个指针
引用。对于压缩位图
,在使用DIB_PAL_COLORS
模式时,必须将biClrUsed
成员设置为偶数
,以使DIB位图数组
从DWORD边界
开始(对齐)。
BITMAPINFOHEADER
结构体包含了设备无关位图(DIB)
的尺寸
和颜色格式
的信息。
biSize
: 指定此结构所需的字节数
。如果它们被附加到此结构的末尾
,则此值不包括颜色表
的大小或颜色掩码
的大小。biWidth
: 指定位图的宽度
,以像素
为单位。biHeight
: 指定位图的高度
,以像素
为单位。
- 对于
未压缩
的RGB
位图,如果biHeight为正
,则该位图是自下而上的DIB
,其原点位于左下角
。如果biHeight为负
,则位图是自上而下的DIB
,其原点位于左上角
。- 对于
YUV
位图,无论biHeight
的符号如何,位图始终是自顶向下
的。解码器
应提供具有正biHeight
的YUV
格式,但为了向后兼容
,它们应接受具有正或负biHeight
的YUV
格式。- 对于
压缩
格式,biHeight
必须为正
,无论图像方向
如何。biPlanes
: 指定目标设备
的平面数
。此值必须设置为1
。biBitCount
: 指定每个像素的位数
(bits per pixel:bpp
)。对于未压缩
格式,此值为每个像素的平均位数
。对于压缩
格式,此值是在解码图像后未压缩图像
的隐含位深度
。biCompression
:
- 对于
压缩视频
和YUV
格式,此成员是FourCC
代码,指定为以小端序
排列的DWORD
。例如,YUYV
视频的FourCC
为“VYUY”
或0x56595559
。- 对于
未压缩
的RGB
格式,可以使用以下值:BI_RGB
(未压缩的RGB)、BI_BITFIELDS
(带颜色掩码的未压缩RGB。适用于16位和32位的位图。)- 对于
16-bpp
位图,如果biCompression
等于BI_RGB
,则格式始终为RGB555
。如果biCompression
等于BI_BITFIELDS
,则格式为RGB555
或RGB565
。使用AM_MEDIA_TYPE
结构中的子类型GUID
确定特定的RGB类型
。biSizeImage
: 指定图像的大小
(以字节
为单位)。对于未压缩
的RGB位图
,可以将其设置为0
。biXPelsPerMeter
: 指定位图目标设备的水平分辨率
(以像素每米
为单位)。biYPelsPerMeter
: 指定位图目标设备的垂直分辨率
(以像素每米
为单位)。biClrUsed
: 指定颜色表
中位图实际使用的颜色索引数
。biClrImportant
: 指定被认为对显示位图很重要
的颜色索引数
。如果该值为零
,则所有颜色都很重要
。
RGBQUAD
结构体成员含义:
rgbBlue
: 颜色中蓝色
的强烈程度。rgbGreen
: 颜色中绿色
的强烈程度。rgbRed
: 颜色中红色
的强烈程度。rgbReserved
: 该成员是保留
的,并且必须为零
。
音频流(WAVEFORMATEX)
WAVEFORMATEX
结构定义了波形音频数据
的格式。 该结构仅包括所有波形音频数据
格式共有的
格式信息。 对于需要附加信息
的格式,此结构作为附加信息
包括在另一个结构
中作为第一个成员
。
支持两个以上通道
或超过16位的样本大小
(更高的采样分辨率)的格式可以用WAVEFORMATEXTENSIBLE
结构来描述,该结构包括WAVEFORMATEX
结构。
1 | typedef struct { |
WAVEFORMATEX
结构体成员含义:
wFormatTag
:波形音频格式
类型。格式标签已向Microsoft Corporation
注册用于许多压缩算法
。可以在Mmreg.h
头文件中找到格式标签
的完整列表。 对于一个或两个通道
的PCM数据
,此值应为WAVE_FORMAT_PCM
。当此结构包含在WAVEFORMATEXTENSIBLE
结构中时,此值必须为WAVE_FORMAT_EXTENSIBLE
。nChannels
:波形音频数据
中的通道数
。单声道
数据使用一个通道
,立体声
数据使用两个通道
。nSamplesPerSec
:采样率
,以每秒采样数
(赫兹:hz)为单位。如果wFormatTag
为WAVE_FORMAT_PCM
,则nSamplesPerSec
的常用值为8.0kHz
,11.025kHz
,22.05kHz
和44.1kHz
。对于非PCM
格式,必须根据制造商
的格式标签规范
来计算此成员。nAvgBytesPerSec
: 格式标签所需的平均数据传输速率
,以字节每秒
为单位。如果wFormatTag
是WAVE_FORMAT_PCM
,则nAvgBytesPerSec
应该等于nSamplesPerSec
和nBlockAlign
的乘积。对于非PCM
格式,必须根据制造商
的格式标签规范
来计算此成员。nBlockAlign
:块对齐
,以字节
为单位。块对齐是wFormatTag
格式类型的最小数据原子单位
。如果wFormatTag
是WAVE_FORMAT_PCM
或WAVE_FORMAT_EXTENSIBLE
,则nBlockAlign
必须等于nChannels
和wBitsPerSample
的乘积除以8
(位/字节)。对于非PCM
格式,必须根据制造商
的格式标签规范
来计算此成员。软件必须一次处理多个nBlockAlign字节
数据。对设备的读写数据
必须始终从块的开头
开始。例如,在样本中间
(即在非块对齐边界
上)开始播放PCM数据
是非法
的。wBitsPerSample
:wFormatTag
格式类型的每个样本位数
。如果wFormatTag
是WAVE_FORMAT_PCM
,则wBitsPerSample
应该等于8或16
。对于非PCM
格式,必须根据制造商
的格式标签规范
设置此成员。如果wFormatTag
是WAVE_FORMAT_EXTENSIBLE
,则此值可以是8的任何整数倍
,并表示容器的大小
,不一定是样本的大小
;例如,一个20位样本
在24位容器
中。某些压缩方案
无法为wBitsPerSample
定义值,因此该成员可以为0
。cbSize
: 附加在WAVEFORMATEX
结构末尾的额外格式信息的大小
(以字节
为单位)。非PCM
格式可以使用此信息来存储wFormatTag
的其他属性
。如果wFormatTag
不需要其他信息,则必须将此成员设置为0
。对于WAVE_FORMAT_PCM
格式(仅WAVE_FORMAT_PCM格式),将忽略
此成员。当此结构包含在WAVEFORMATEXTENSIBLE
结构中时,该值必须至少为22
。
使用额外信息
的格式的一个示例是Microsoft自适应增量脉冲编码调制
(MS-ADPCM)格式。 MS-ADPCM
的wFormatTag
是WAVE_FORMAT_ADPCM
。cbSize
成员通常将设置为32
。为WAVE_FORMAT_ADPCM
存储的额外信息是编码和解码
波形音频数据所需的系数对
。
WAVEFORMATEXTENSIBLE
结构体成员含义:
Format
: 指定基本格式的WAVEFORMATEX
结构。wFormatTag
成员必须为WAVE_FORMAT_EXTENSIBLE
。cbSize
成员必须至少为22
。Samples
: 描述样本格式
的联合体(union)。
Samples.wValidBitsPerSample
: 信号中的精度位数
。通常等于WAVEFORMATEX.wBitsPerSample
。但是,wBitsPerSample
是容器大小
,并且必须是8的倍数
,而wValidBitsPerSample
可以是不超过容器大小
的任何值。例如,如果格式使用20位样本
,则wBitsPerSample
必须至少为24
,而wValidBitsPerSample
为20
。Samples.wSamplesPerBlock
: 一个音频数据压缩块
中包含的样本数
。此值用于缓冲区估计
。该值与压缩格式
一起使用,该压缩格式在每个块
中具有固定数量的样本
。如果每个压缩音频数据块
中包含可变数量的样本
,则可以将该值设置为0
。在这种情况下,需要以其他方式获得缓冲区估计
和位置信息
。Samples.wReserved
:保留
给操作系统内部使用。设置为0
。dwChannelMask
:通道掩码
,位掩码
,指定将流中的通道
分配给扬声器的位置
。SubFormat
: 数据的子格式
,例如KSDATAFORMAT_SUBTYPE_PCM
。子格式信息类似于WAVEFORMATEX
结构的wFormatTag
成员中的标签所提供的信息。
WAVEFORMATEXTENSIBLE
可以描述WAVEFORMATEX
可以描述的任何格式
,但可以为两个以上的通道
提供额外的支持,为了使每个样本的位数
更精确,并支持新的压缩方案
。
WAVEFORMATEXTENSIBLE
可以安全地强制转换为WAVEFORMATEX
,因为它仅配置WAVEFORMATEX.cbSize
指定的额外字节。
dwChannelMask
成员指定多通道流
中存在哪些通道
。最低有效位
对应于左前扬声器
,下一个最低有效位
对应于右前扬声器
,依此类推。这些位按意义顺序
定义如下。
Speaker Position | Flag Bit | Description |
---|---|---|
SPEAKER_FRONT_LEFT | 0x1 | 左前扬声器 |
SPEAKER_FRONT_RIGHT | 0x2 | 右前扬声器 |
SPEAKER_FRONT_CENTER | 0x4 | 前中扬声器 |
SPEAKER_LOW_FREQUENCY | 0x8 | 低频扬声器 |
SPEAKER_BACK_LEFT | 0x10 | 左后扬声器 |
SPEAKER_BACK_RIGHT | 0x20 | 右后扬声器 |
SPEAKER_FRONT_LEFT_OF_CENTER | 0x40 | 左前中置扬声器 |
SPEAKER_FRONT_RIGHT_OF_CENTER | 0x80 | 右前中置扬声器 |
SPEAKER_BACK_CENTER | 0x100 | 后中扬声器 |
SPEAKER_SIDE_LEFT | 0x200 | 左侧扬声器 |
SPEAKER_SIDE_RIGHT | 0x400 | 右侧扬声器 |
SPEAKER_TOP_CENTER | 0x800 | 上层中置扬声器 |
SPEAKER_TOP_FRONT_LEFT | 0x1000 | 上层左前扬声器 |
SPEAKER_TOP_FRONT_CENTER | 0x2000 | 上层前中扬声器 |
SPEAKER_TOP_FRONT_RIGHT | 0x4000 | 上层右前扬声器 |
SPEAKER_TOP_BACK_LEFT | 0x8000 | 上层左后扬声器 |
SPEAKER_TOP_BACK_CENTER | 0x10000 | 上层后中扬声器 |
SPEAKER_TOP_BACK_RIGHT | 0x20000 | 上层右后扬声器 |
dwChannelMask
中指定的通道必须以规定的顺序
显示(从最低有效位
开始)。例如,如果仅指定SPEAKER_FRONT_LEFT
和SPEAKER_FRONT_RIGHT
,则左前扬声器
的采样必须首先
出现在交错流
中。dwChannelMask
中设置的位数
应与WAVEFORMATEX.nChannels
中指定的通道数
相同。
为了向后兼容
,任何可以由独立的WAVEFORMATEX
结构指定的波形格式
也可以由WAVEFORMATEXTENSIBLE
结构定义。因此,mmreg.h
中的每个波形格式标签
都具有一个对应的SubFormat GUID
。下表显示了一些典型的波形格式标签
及其相应的SubFormat GUID
。这些GUID在Ksmedia.h
中定义。
Wave-Format Tag | SubFormat GUID |
---|---|
WAVE_FORMAT_PCM | KSDATAFORMAT_SUBTYPE_PCM |
WAVE_FORMAT_IEEE_FLOAT | KSDATAFORMAT_SUBTYPE_IEEE_FLOAT |
WAVE_FORMAT_DRM | KSDATAFORMAT_SUBTYPE_DRM |
WAVE_FORMAT_ALAW | KSDATAFORMAT_SUBTYPE_ALAW |
WAVE_FORMAT_MULAW | KSDATAFORMAT_SUBTYPE_MULAW |
WAVE_FORMAT_ADPCM | KSDATAFORMAT_SUBTYPE_ADPCM |
由于WAVEFORMATEXTENSIBLE
是WAVEFORMATEX
的扩展版本,因此它可以描述其他WAVEFORMATEX
无法单独描述
的格式。供应商
可以自由定义自己的SubFormat GUID
,以标识没有波形格式标签
的专有格式
。
对于特定的扩展格式
,以下结构定义为WAVEFORMATEXTENSIBLE
。
Definition | Value of SubFormat |
---|---|
WAVEFORMATIEEEFLOATEX | KSDATAFORMAT_SUBTYPE_IEEE_FLOAT |
WAVEFORMATPCMEX | KSDATAFORMAT_SUBTYPE_PCM |
2.2.2.3、strd Chunk(Stream Header Data / Additional Header Data)
“strd Chunk”
紧跟在“strf Chunk”
之后,保存的是可选的
额外的流的头信息
数据。如果存在Stream Header Data
(“strd”)块,则其遵循Stream Format
(“strf”)块。该块的格式和内容
由编解码器驱动程序
定义。通常,驱动程序
使用此信息进行配置
。读取和写入
AVI文件的应用程序不需要解释此信息
。他们简单地将其作为存储块
在驱动程序之间
来回传输。
2.2.2.4、strn Chunk(Stream Name)
可选的“strn”
块包含描述该流的以null结尾
的文本字符串
。该块包含流的名称
。该流名称仅应使用纯ASCII
,尤其不能使用UTF-8
。
2.2.2.5、indx Chunk(Super Index Chunk)
只有符合Open-DML(AVI2.0)
规范的AVI文件
才可能存在此块
。每个流在其Stream Header List
(“strl”)中都包含一个“indx”
块。该块是超级索引块
(Upper Level Index Chunk或Super Index Chunk),索引的索引
。
Upper Level Index
(“Super Index”)指向其他索引块
,并具有以下结构:
1 | typedef struct _avisuperindex { |
fcc
:FourCC
代码。与Chunk
结构体中的dwFourCC
相同。该值必须为'indx'
。cb
: 此结构体的大小
,与Chunk
结构体中的dwSize
相同。不包括初始的8个字节
(fcc和cb)。wLongsPerEntry
: 每个索引项的大小
,以4字节
为单位。此值必须为4
。每个aIndex[i]
的大小为4*wLongsPerEntry
个字节。(每个aIndex[i]
的结构取决于特定类型的索引
)bIndexSubType
:索引子类型
。必须为0
或AVI_INDEX_SUB_2FIELD
。bIndexType
:索引类型
。必须为AVI_INDEX_OF_INDEXES
。nEntriesInUse
: aIndex数组中有效的条目数
。aIndex[0]..aIndex[nEntriesInUse-1]
有效。dwChunkId
: 标识被索引
的对象的FourCC
。索引
指向的流的ID
,例如“00dc”
。因此,一个这样的索引块
只能指向同一个流
的数据。dwReserved
:保留
。将数组元素设置为0
。aIndex
: 包含下列成员的结构体数组。数组中的元素数量
是根据cb的值
计算的。
qwOffset
: 从文件开头
到该条目所指向的子索引块
的偏移量
,以字节
为单位。dwSize
:子索引块
的大小
(该条目指向的标准
或域
索引块的大小),以字节
为单位。dwDuration
:子索引
所覆盖的文件的持续时间
,以流节拍
(stream ticks)为测量单位,如在AVI Stream Header
中指出的(dwScale/dwRate
)。对于视频
或VBR音频
,通常指帧数
。
“indx Chunk”
(Super Index Chunk)的示意图如下:
2.3、INFO List
“INFO”
列表是已注册的全局表单
类型,可以存储有助于识别块内容
的信息。此信息很有用,但不会影响程序解释文件
的方式;例如版权信息
和注释
。“INFO”
列表是列表类型为“INFO”
的“LIST”
块。以下示例显示了示例“INFO”
列表块:
1 | LIST('INFO' INAM("Two Trees"Z) |
“INFO”
列表应仅包含以下块
。可以定义新的块
,但是应用程序应忽略
它不理解
的任何块。下面列出的块可能仅出现在“INFO”
列表中。每个块都包含一个ZSTR
或以null结尾
的文本字符串(所有文本字符串
必须对齐
)。
Chunk ID | Description |
---|---|
IARL | 存档位置(Archival Location)。指示文件主题的存档位置。 |
IART | 艺术家(Artist)。列出文件原始主题的艺术家;例如,“Michaelangelo.”。 |
ICMS | 受委托的(Commissioned)。列出受委托的文件主题的人员或组织的名称;例如“Pope Julian II.”。 |
ICMT | 注释(Comments)。提供有关文件或文件主题的一般注释。如果注释长几个句子,请以句号结尾每个句子。不要包含换行符。 |
ICOP | 版权(Copyright)。记录文件的版权信息;例如,“Copyright Encyclopedia International 1991.”。如果有多个版权,请用分号和空格隔开。 |
ICRD | 创建日期(Creation date)。指定创建文件主题的日期。以年-月-日格式列出日期,左边用0填充一位数的月和日;例如1553年5月3日的“1553-05-03”。 |
ICRP | 裁剪(Cropped)。描述图像是否已裁剪,如果已裁剪,则如何裁剪;例如“lower-right corner.”。 |
IDIM | 大小(Dimensions)。指定文件原始主题的大小;例如,“8.5 in h,11 in w” |
IDPI | 每英寸点数(Dots Per Inch)。存储用于生成文件的数字化转换器的每英寸点数设置,例如“300”。 |
IENG | 工程师(Engineer)。存储处理文件的工程师的姓名。如果有多个工程师,请用分号和空格分隔名称;例如,“Smith, John; Adams, Joe.” |
IGNR | 类型(Genre)。描述原始作品,例如“landscape,”、“portrait,”、“still life,”等。 |
IKEY | 关键字(Keywords)。提供引用文件或文件主题的关键字列表。用分号和空格分隔多个关键字;例如,“Seattle; aerial view; scenery.” |
ILGT | 亮度(Lightness)。描述生成文件所需的数字化转换器的亮度设置的更改。请注意,此信息的格式取决于所使用的硬件。 |
IMED | 媒介(Medium)。描述文件的原始主题,例如“computer image,”(计算机图片)、“drawing,”(绘画)、“lithograph,”(石板画)等。 |
INAM | 名称(Name)。存储文件主题的标题,例如“Seattle From Above.” |
IPLT | 调色板设置(Palette Setting)。指定数字化图像时要求的颜色数量,例如“256”。 |
IPRD | 产物(Product)。指定文件最初打算使用的标题的名称,例如“Encyclopedia of Pacific Northwest Geography.”。 |
ISBJ | 主题(Subject)。描述文件的内容,例如“Aerial view of Seattle.”。 |
ISFT | 软件(Software)。标识用于创建文件的软件包的名称,例如“Microsoft WaveEdit.”。 |
ISHP | 清晰度(Sharpness)。标识生成文件所需的数字化转换器的清晰度变化(格式取决于所使用的硬件)。 |
ISRC | 源(Source)。标识提供文件原始主题的人员或组织的名称;例如“Trey Research.”。 |
ISRF | 原始形式(Source Form)。标识被数字化的材料的原始形式,例如“slide,”、“paper,”、“map,”等。这不一定与IMED相同。 |
ITCH | 技术员(Technician)。标识将主题文件数字化的技术人员;例如“Smith, John.”。 |
2.4、movi List
头信息(hdrl List
)之后是一个“movi”
列表,其中包含流中的实际数据
,即视频帧
和音频样本
。数据块可以直接驻留
在“movi”
列表中,或者它们可能会被归类
到“rec”列表
中。“rec”
分组意味着应该一次性
从磁盘读取分组的块,并且该块旨在用于从CD-ROM交错播放
的文件。
1 | LIST movi |
将块分组为rec-Lists
可防止在使用Microsoft AVI Splitter
进行重放时过多的搜索
,但不允许在某些独立的重放设备
上进行播放。
流的最大块
大小应小于
相应的dwSuggestedBufferSize
值。否则,某些播放器,尤其是Microsoft AVI Splitter
,可能会发生故障
。
标识每个数据块的FourCC
包含一个两位数字
的流编号
,后面跟着的是一个用于定义块中信息的类型
的两个字符的编码
。
Two-Character Code | Description |
---|---|
..db | 未压缩视频帧数据块 |
..dc | 压缩视频帧数据块 |
..wb | 音频数据块 |
..tx | 字幕数据块 |
ix.. | 标准索引块 |
..pc | 调色板更换数据块 |
例如,如果Stream0
包含音频
,则该流的数据块将具有“00wb”
形式的FourCC
。如果Stream1
包含视频
,则该流的数据块将具有“01db”
或“01dc”
形式的FourCC
。视频数据块
还可以定义新的调色板条目
,以便在AVI序列
期间更新调色板
。每个调色板更换数据块
(“..pc”
)都包含一个AVIPALCHANGE
结构。如果流包含调色板更换数据块
(“..pc”),请在该流的AVISTREAMHEADER
结构的dwFlags
成员中设置AVISF_VIDEO_PALCHANGES
标志。文本流
可以使用任意Two-Character Code
。
AVIPALCHANGE
结构体定义了AVI文件中的调色板更换
的相关信息。
1 | typedef struct { |
bFirstEntry
: 指定要更改的第一个调色板条目
的索引。bNumEntries
: 指定要更改的调色板条目数
,或者指定零
以更改所有256个
调色板条目。wFlags
: 保留。peNew
: 指定大小为bNumEntries
的PALETTEENTRY
结构的数组。
PALETTEENTRY
结构指定逻辑调色板
中条目的颜色
和用法
。逻辑调色板由LOGPALETTE
结构定义。
peRed
: 调色板条目的红色
强度值。peGreen
: 调色板条目的绿色
强度值。peBlue
: 调色板条目的蓝色
强度值。peFlags
: 指示如何使用
调色板条目。
peFlags
可以设置为0
或以下值之一
。
Value | Meaning |
---|---|
PC_EXPLICIT | 说明逻辑调色板条目的低位字指定的是硬件调色板索引。该标志允许应用程序显示显示设备面板的内容。 |
PC_NOCOLLAPSE | 说明将颜色放置在系统调色板中的未使用条目中,而不是与系统调色板中的现有颜色匹配的条目中。如果系统调色板中没有未使用的条目,则颜色将正常匹配。一旦此颜色出现在系统调色板中,其他逻辑调色板中的颜色就可以与此颜色匹配。 |
PC_RESERVED | 说明将逻辑调色板条目用于调色板动画。该标志可防止其他窗口将颜色与调色板条目匹配,因为颜色经常变化。如果有未使用的系统调色板条目可用,则将颜色放置在该条目中。否则,该颜色不可用于动画。 |
LOGPALETTE
结构定义了一个逻辑调色板
。
palVersion
: 系统的版本号
。palNumEntries
: 逻辑面板中条目的数量
。palPalEntry
: 指定一组PALETTEENTRY
结构,这些结构定义逻辑调色板
中每个条目的颜色
和用法
。
调色板条目表
中的颜色应按重要性顺序
显示,因为逻辑调色板
中较前的条目
最有可能放置在系统调色板
中。
2.5、idx1 Chunk
2.5.1、AVI 1.0 index
可选索引块(“idx1”)
可以位于“movi”
列表之后。索引
包含数据块及其在文件中的位置
的列表
。它由一个AVIOLDINDEX
结构组成,该结构具有每个数据块
的条目(包括“rec”块
)。如果文件包含索引
,请在AVIMAINHEADER
结构的dwFlags
成员中设置AVIF_HASINDEX
标志。
AVIOLDINDEX
结构由初始RIFF块
(Chunk结构体:fcc和cb成员)和“movi”
列表中每个数据块
的一个索引条目
组成。AVIOLDINDEX
结构体的定义如下:
1 | typedef struct _avioldindex { |
fcc
: 指定FourCC
代码。必须为“idx1”
。cb
: 指定本结构体的大小
,与Chunk
结构体中的dwSize
相同。不包括初始的8个字节
(fcc和cb)。aIndex
: 包含下列成员的结构体的数组。
dwChunkId
: 指定用于标识AVI文件中流的FourCC
。FourCC
的格式必须为“xxyy”
,其中xx
是流编号
,而yy
是两个字符的代码,用于标识流的内容
。请看前面介绍“movi List”
时的内容。dwFlags
: 请看下文。dwOffset
: 指定数据块在文件中的位置
。该值应指定为距“movi”列表开头
的偏移量
(以字节
为单位);但是,在某些AVI文件中,它是距文件开头
的偏移量
。AVI文件解析器
必须能够处理两个版本
。dwSize
: 指定数据块的大小
,以字节
为单位。
dwFlags
指定以下标志的0个
或多个
的按位组合
:
Value | Meaning |
---|---|
AVIIF_KEYFRAME | 此条目所指的数据块是关键帧。 |
AVIIF_LIST | 此条目所指的数据块是一个“rec”列表。不是一个Chunk。 |
AVIIF_FIRSTPART | 此条目所指的数据块需要使用其后的帧;它不能单独存在。 |
AVIIF_LASTPART | 此条目所指的数据块需要使用其之前的帧;它不能单独存在。 |
AVIIF_NO_TIME | 此条目所指的数据块不影响流的计时。例如,应该为调色板更换数据块(“..pc”)设置这个标志。 |
如果既未设置AVIIF_FIRSTPART
也未设置AVIIF_LASTPART
,则该块可以单独使用
,换句话说,其相应的流至少有一个数据包
。这对于将VBR音频流
存储在AVI文件中非常重要。
“idx1 Chunk”
的标准形式示意图:
2.5.2、AVI 2.0 index(Open-DML)
AVI2.0索引
可以显示为单个块(“idx1”)
。或者,可以在“movi”
块中插入索引段(“ix..”)
。如果将索引段(“ix..”)
放置在“movi”
块中,则超级索引
(“Super Index Chunk”或“indx Chunk”)包含索引段(“ix..”)的索引
。AVIMETAINDEX
结构是索引段(“ix..”)
和超级索引(“indx”)
的基础结构。
AVIMETAINDEX
结构体是AVI2.0索引
的基本结构(“indx”
格式)。AVIMETAINDEX
结构体的定义如下(可参考“indx Chunk”
节):
1 | typedef struct _avimetaindex { |
fcc
:FourCC
代码。取值为“indx”
或“ix..”
,其中“..”
是流编号
。cb
: 指示此结构体的大小
,不包括初始的8个字节
(fcc和cb)。wLongsPerEntry
: 每个索引项的大小
,以4字节
为单位。bIndexSubType
:索引子类型
。含义取决于bIndexType
的值。bIndexType
: 请看下文。nEntriesInUse
: adwIndex数组中有效的条目数
。dwChunkId
: 标识被索引
的对象的FourCC
。如果索引的对象
是一个流
,则该成员与AVIOLDINDEX
结构的dwChunkId
成员具有相同的含义
。dwReserved
: 该成员的含义取决于索引类型
。adwIndex
:索引项的数组
。该数据的格式取决于索引类型
。
bIndexType
可以具有以下值:
Value | Meaning |
---|---|
AVI_INDEX_OF_INDEXES 0x00 |
每个索引条目都指向另一个索引。将AVIMETAINDEX结构视为AVISUPERINDEX结构。bIndexSubType的值必须为0。 |
AVI_INDEX_OF_CHUNKS 0x01 |
每个索引条目指向文件中的一个数据块。 1、如果bIndexSubType为0,将AVIMETAINDEX结构视为AVISTDINDEX结构。每个索引条目都是一个AVISTDINDEX_ENTRY结构。 2、如果bIndexSubType为AVI_INDEX_SUB_2FIELD,则该索引是一个域索引块(Field Index)。 DirectShow不支持域索引(Field Index)。 |
AVI_INDEX_IS_DATA 0x80 |
adwIndex数组包含一个数据表,而不是一个索引项列表。 |
2.6、JUNK Chunk
根据需要插入“JUNK”
块,可以在AVI文件中对齐数据
。应用程序应忽略“JUNK”块
的内容。