AVI(Audio Video Interleaved)是微软于1992年推出的多媒体容器格式,是Windows平台最经典的音视频封装格式之一。其名称“交错”直指核心设计思想:将音频数据与视频数据交替存储,使得播放器在读取时能够连续、低延迟地回放。下面从格式结构、数据组织、局限性与扩展、工程实践等方面详细分析。
1. 文件结构基础:RIFF 与 AVI
AVI 基于 RIFF(Resource Interchange File Format) 体系,这是微软为多媒体数据定义的一种通用容器规范。RIFF 文件由若干 块(Chunk) 组成,每个块包含:
- 块标识(4字节 ASCII)
- 块大小(4字节,小端序)
- 块数据(长度由块大小指定)
AVI 文件整体是一个 RIFF 块,其类型标识为 'AVI '(注意空格),结构如下:
RIFF ('AVI '
hdrl LIST ...
movi LIST ...
idx1 (可选)
)
即:
- 一个 RIFF 头部,类型为
AVI - 包含三个主要子块:
hdrl列表、movi列表、可选的idx1块
2. 主要块详解
2.1 hdrl 列表(Header List)
hdrl 是存放所有元数据的列表,其子块包括:
2.1.1 avih —— AVI 主头部
一个固定大小的结构体(56字节),定义文件全局属性:
| 字段 | 类型 | 说明 |
|---|---|---|
dwMicroSecPerFrame | DWORD | 每帧的微秒数,决定了视频帧率 |
dwMaxBytesPerSec | DWORD | 最大数据传输率(字节/秒) |
dwPaddingGranularity | DWORD | 填充粒度(通常为0) |
dwFlags | DWORD | 标志位(如是否包含索引、是否交错等) |
dwTotalFrames | DWORD | 视频总帧数 |
dwInitialFrames | DWORD | 初始帧数(用于音视频同步,通常为0) |
dwStreams | DWORD | 文件中的流数量(至少1个视频流) |
dwSuggestedBufferSize | DWORD | 建议的解码缓冲区大小 |
dwWidth / dwHeight | DWORD | 视频宽高(像素) |
dwReserved | DWORD[4] | 保留字段 |
2.1.2 strl 列表(Stream List)
每个媒体流对应一个 strl 列表,包含流的头部、格式、名称等子块。
-
strh(Stream Header):定义流类型(视频vids、音频auds、文本等)、处理方式、缓冲区大小、帧率(对于视频)等。关键字段:fccType:流类型(如vids、auds)fccHandler:编解码器四字符码(如'DIB '、'H264'、'XVID')dwScale/dwRate:定义时间刻度(如视频为dwRate/dwScale = 帧率)dwStart/dwLength:起始帧和总帧数(对于音频为样本数)
-
strf(Stream Format):流格式结构,直接存放编解码器所需的数据结构:- 对于视频流:通常是
BITMAPINFOHEADER(包含宽、高、位深度、压缩类型等) - 对于音频流:通常是
WAVEFORMATEX(包含采样率、声道数、比特率等)
- 对于视频流:通常是
-
strn(可选):流的名称
2.1.3 其他可选子块
odml:用于 OpenDML 扩展,支持大于4GB的文件(见后文)。vprp:视频属性(如逐行/隔行)。
2.2 movi 列表(Movie Data)
movi 列表存放所有实际的音视频数据。其内部由一系列 数据块(data chunk) 组成,每个数据块具有如下格式:
| 字段 | 大小 | 说明 |
|---|---|---|
| 块标识 | 4字节 | 如 00dc(视频帧)、00wb(音频帧) |
| 块大小 | 4字节 | 数据长度(不含块标识和大小字段) |
| 数据 | 可变 | 编码后的帧数据(如 H.264 NAL 单元、PCM 数据) |
块标识规则:
- 前两个字符表示流索引(
00表示第一个流,01表示第二个,依此类推) - 后两个字符表示数据类型:
dc:视频压缩数据(compressed video)db:视频未压缩数据(uncompressed video)wb:音频压缩/未压缩数据pc:调色板数据(palette change)
交错存储:AVI 的核心特性。在 movi 中,音频和视频数据块按照时间顺序交替放置,例如:
00dc (视频帧1)
00wb (音频数据块对应视频帧1)
00dc (视频帧2)
00wb (音频数据块对应视频帧2)
...
这种交错使得播放器在读取时,无需大量缓冲即可实现音视频同步,也适合 CD-ROM 等顺序读取设备。
2.3 idx1 块(Index)
idx1 是可选的索引块,位于文件末尾(或 movi 之后),为每个数据块记录其在文件中的位置、大小和类型,用于快速随机访问。索引条目结构:
| 字段 | 类型 | 说明 |
|---|---|---|
ckid | DWORD | 数据块的标识(如 00dc) |
dwFlags | DWORD | 标志位(指示该块是否为关键帧) |
dwChunkOffset | DWORD | 数据块相对于文件起始的偏移 |
dwChunkLength | DWORD | 数据块的大小 |
如果 AVI 文件没有索引,播放器只能顺序播放,无法快进快退。
3. 数据组织与播放流程
一个典型的 AVI 文件播放流程如下:
- 解析
hdrl列表,获取流数量、编解码器信息、全局参数。 - 初始化解码器(使用
strf中的格式结构)。 - 定位到
movi列表,开始顺序读取数据块:- 根据块标识判断流类型,将数据送入对应解码器。
- 解码后的帧按时间戳(根据
dwScale/dwRate计算)送显/播放。
- 如果存在
idx1,支持跳转到任意帧(通过索引查找该帧的数据块位置)。 - 播放结束。
由于 AVI 没有显式的 PTS/DTS 字段(只有帧序号),且缺乏对 B 帧的明确支持,因此早期编码器通常避免使用 B 帧,或者通过特殊约定来处理。
4. 局限性及 OpenDML 扩展
4.1 标准 AVI 的局限
- 文件大小限制:由于使用 32 位块大小字段,单个 RIFF 块最大为 4GB(实际可用约 2GB 左右),无法存储大型视频。
- 时间戳不精确:仅依靠帧序号和帧率计算时间,无法精确表示可变帧率或复杂的 DTS/PTS 关系。
- B 帧支持差:缺少显式的解码/显示时间戳,导致 B 帧处理困难(需依赖解码器约定)。
- 不支持流媒体:头部必须在文件开头,且需要完整索引才能随机访问,不适合流式传输。
- 编解码器配置受限:
strf只能容纳有限的格式结构,对于现代编解码器(如 H.265)需要额外扩展。
4.2 OpenDML(AVI 2.0)
为了解决大文件问题,微软联合 IBM 于 1996 年推出 OpenDML 扩展(即 AVI 2.0)。主要改进:
- 引入
dmlh块(位于hdrl中),提供 64 位索引支持。 - 允许使用多个
movi块,或使用ixxx索引块代替idx1,使文件可以突破 4GB 限制。 - 增强时间戳和 B 帧支持(但仍不如 MP4 完善)。
目前大多数现代 AVI 文件(尤其是超过 2GB 的)实际都是 OpenDML AVI。
5. 与 MP4、ASF 的对比
| 特性 | AVI | MP4 | ASF |
|---|---|---|---|
| 设计初衷 | 本地播放(尤其是 Windows 平台) | 通用存储与流媒体 | 流媒体传输 |
| 文件结构 | RIFF 块 + movi 数据列表 | ISO BMFF(盒子嵌套) | 对象(GUID) |
| 交错方式 | 数据块按时间顺序交错 | 样本按时间顺序存放,索引表单独 | 固定大小数据包,可交错 |
| 索引 | idx1 或 OpenDML 索引 | stbl 系列表 | 简单索引对象 |
| 时间戳支持 | 基于帧序号,无独立 DTS/PTS | 精确 DTS/PTS | 数据包内嵌时间戳 |
| B 帧支持 | 弱(依赖解码器约定) | 完整支持 | 完整支持 |
| 文件大小限制 | 标准 AVI <4GB,OpenDML 无限制 | 无限制 | 无限制 |
| 流媒体友好 | 差(需完整索引) | 一般(需 moov 前置) | 优秀 |
| 编解码器支持 | 通过 strf 扩展(有限) | 通过 avcC、hvcC 等盒子 | 通过流属性对象 |
| 现代应用 | 老旧设备、数字摄像机、游戏录屏 | 通用 Web/移动端 | 传统 Windows 生态 |
6. 工程实践
6.1 FFmpeg 中的 AVI 支持
FFmpeg 通过 libavformat/avidec.c 和 libavformat/avienc.c 实现 AVI 的读写。
常用命令:
# 封装为 AVI
ffmpeg -i input.mp4 -c copy output.avi
# 生成带索引的 AVI(默认)
ffmpeg -i input.mp4 -c copy -write_idx 1 output.avi
# 强制使用 OpenDML(支持大文件)
ffmpeg -i input.mkv -c copy -f avi -openglobal 1 output.avi
6.2 生成兼容性最好的 AVI
为了让 AVI 在老旧播放器上兼容,通常建议:
- 使用简单视频编解码器(如 MJPEG、DivX、Xvid)
- 音频使用 PCM 或 MP3
- 避免 B 帧(使用
-bf 0) - 使用
-packetsize控制数据块大小
6.3 工具与库
- Avilib:一个轻量级 C 库,专门用于读写 AVI 文件,常被嵌入到游戏或嵌入式设备中。
- VirtualDub:经典的 AVI 处理工具,支持滤镜、重编码、索引修复等。
- Windows 原生 API:如
AVIFile系列函数(avifile.dll),用于创建和读取 AVI。
6.4 现代应用场景
尽管 AVI 在 Web 和移动端已基本被 MP4 取代,但在以下场景仍有应用:
- 数字摄像机/采集卡:许多设备仍输出 AVI 格式(尤其是未压缩 AVI)
- 游戏录屏:一些游戏录制软件默认使用 AVI(如 Fraps)
- 教学视频/光盘:部分老旧教学光盘使用 AVI 格式
- 简单嵌入式系统:资源受限的设备使用 avilib 等轻量库处理 AVI
7. 总结
AVI 作为多媒体容器格式的先行者,其“音频视频交错”的设计思想深刻影响了后续容器(如 MP4、MKV)。尽管在现代互联网流媒体环境中已不再主流,但它结构简单、实现容易,在特定领域(如嵌入式、遗留系统)仍具生命力。理解 AVI 的结构,有助于掌握 RIFF 体系、数据交错原理以及早期多媒体开发的技术脉络。
对于今天的音视频工程师,当需要处理老旧 AVI 文件或为嵌入式设备设计封装格式时,AVI 依然是一个值得熟练掌握的格式。