剑痴乎

  • 首页
  • 文章分类
    • 音视频
    • WebRTC
    • 编程之美
    • Linux
    • Windows
    • 生活点滴
    • 校园生活
  • 参考
    • API参考
    • 实用工具
    • 测试音视频
    • 文档
  • 留言板
  • 关于
剑痴乎
代码为剑,如痴如醉
  1. 首页
  2. 音视频
  3. 正文

AVI文件详细解析

2016年2月23日 6148点热度 3人点赞 7条评论

最近在做视频文件的解析,需要将视频文件中封装的视频与音频解析出来,然后用自己的解码器解码。这个过程专业点叫做叫做Demultiplex,视频播放器中负责这部分的叫做Demuxer。我们平时看到的各种格式视频,比如:avi,mp4,mkv等相当于一种容器,里面包含了音视频,字幕的信息以及数据,Demuxer的工作就是解析视频文件,取出里面的音视频或者字幕送到指定的解码器解码。

我刚开始接触的avi文件的解析。首先介绍下AVI文件。AVI英文全称为Audio Video Interleaved,即音视频交错格式,AVI基于RIFF文件结构。

一.基本数据单元

在AVI中有两种最基本的数据单元,一个是chunk,一个是list。这两种结构如下:

Chunks
typedef struct {
DWORD dwFourCC
DWORD dwSize      //data
BYTE data[dwSize] // contains headers or video/audio data
} CHUNK;

Lists
typedef struct {
DWORD dwList
DWORD dwSize        //dwFourcc + data
DWORD dwFourCC
BYTE data[dwSize-4] // contains Lists and Chunks
} LIST;

可知chunk由三部分组成:4字节的标记ID,4字节大小(指数据大小),以及数据。
list由四部分组成,4字节“list”,4字节大小(指后面两部分),4字节列表类型,数据。

二.AVI文件类型

1.AVI 1.0 最基本的格式,由于索引地址与大小用4字节表示,所以最大支持4G容量,而且与文件系统类型有关,如下:
--Video for Windows (AVI 1.0)
-FAT (FAT16): 4 GB (2 GB practical, safe)
-FAT32: 4 GB (2 GB practical, safe)
-NTFS: 4 GB (2 GB practical, safe)
为了安全一般限制为2G(参考链接1)
2.AVI 2.0(Open—DML) AVI的扩展格式,解决AVI 1.0大小限制(AVI2.0详细资料见参考链接2)

本文主要讨论AVI 1.0,AVI2.0解析后续再做研究。

三.AVI结构

一个AVI文件通常有如下几个子块组成:
1)ID为"hdrl"的list,包含了音视频信息,描述媒体流信息
2)ID为"info"的list,包含编码该AVI的程序信息
3)ID为"junk"的chunk,都是些无用的数据
4)ID为"movi"的list,包含了交错排列的音视频数据
5)ID为"idxl"的chunk,包含音视频排列的索引数据(可选块)

四.详细解析

1.RIFF文件头

用UltraEdit(或者其他文本编辑器)打开一个AVI文件(本文分析用到的avi文件下载地址)
avi解析
可以看到前4个字节为"RIFF",接着4字节RIFF文件大小(0x01811050即25235536字节,因为AVI文件以小端方式存储数据),再接着4字节为RIFF文件类型"avi"

2.hdrl列表

1)hdrl list头部
avi解析
可以看到接下来为hdrl list。首先是4字节的"list",然后4字节list大小,接着是4字节list类型"hdrl"。

2)avih块
avi解析
用于描述主信息头。
4字节的"avih"标识,4字节大小(0x38即56),接下来是56个字节数据。该块可以用如下结构体表示:

// AVI主头部
typedef struct
{
    FourCC fcc;                  // 必须为 avih
    DWORD cb;                    // 本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)
    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;

3)strl list头部
avi解析
一个strl list中至少包含一个strh块和一个strf块。文件中有多少个流,就对应有多少个strl list。
上图可知依次为4字节"list",4字节的list大小,4字节"strl"标识。

4)strh块
avi解析
用于描述流的头信息。
4字节"strh",4字节"strh"块大小(0x38即56),后面是56字节大小数据。该块用如下结构体表示:

// AVI流头部
typedef struct
{
    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;               // dwScale/dwRate,每秒采样率
    DWORD dwStart;              // 流的开始时间
    DWORD dwLength;             // 流的长度(单位与dwScale和dwRate的定义有关)
    DWORD dwSuggestedBufferSize;// 读取这个流数据建议使用的缓存大小
    DWORD dwQuality;            // 流数据的质量指标(0 ~ 10,000)
    DWORD dwSampleSize;         // Sample的大小
    RECT rcFrame;               // 指定这个流(视频流或文字流)在视频主窗口中的显示位置,视频主窗口由AVIMAINHEADER结构中的dwWidth和dwHeight决定
} AVIStreamHeader;

5)strf块
avi解析
该块用于描述流的具体信息。如果是视频流(vids,由strh块得知),用一个BitmapInfo结构体表示,如果是音频流(auds),用WaveFormatEx结构体表示。

// 位图头
typedef struct
{
    DWORD  biSize;
    LONG   biWidth;
    LONG   biHeight;
    WORD   biPlanes;
    WORD   biBitCount;
    DWORD  biCompression;
    DWORD  biSizeImage;
    LONG   biXPelsPerMeter;
    LONG   biYPelsPerMeter;
    DWORD  biClrUsed;
    DWORD  biClrImportant;
} BitmapInfoHeader;

// 位图信息
typedef struct
{
    BitmapInfoHeader bmiHeader;   // 位图头
    RGBQUAD bmiColors[1];         // 调色板
} BitmapInfo;

// 音频波形信息
typedef struct
{
    WORD wFormatTag;
    WORD nChannels;               // 声道数
    DWORD nSamplesPerSec;         // 采样率
    DWORD nAvgBytesPerSec;        // 每秒的数据量
    WORD nBlockAlign;             // 数据块对齐标志
    WORD wBitsPerSample;          // 每次采样的数据量
    WORD cbSize;                  // 大小
} WaveFormatEx;

该块首先4字节"strf"标识,4字节大小0x28即40,接着的数据用一个40字节大小的BitmapInfo结构体表示。

6)strd块与strn块
strd:可选的额外的头信息数据
strn:可选的流的名字
这两个块是可选的,本AVI文件不包含,故不分析。

7)strl list
avi解析
由于该AVI文件有两个流,所以有两个strl list。该strl list用于描述音频流信息。具体分析同上。

3.info list

avi 解析
该list用于描述编码该AVI文件的程序信息,包含一个isft块。

4.junk块

avi解析
该块都是一些垃圾填充数据,用于内部数据的队齐(填充),直接跳过。

5.movi list

avi解析
该list存储音视频数据块,音视频数据块在该list中交错方式存放着。
movi lst中音视频数据子块的种类有:##db,##dc,##pc,##wb。
--##表示数据所属的流的序号(由于第一个流是视频(第一个hdrl list描述视频),故音频用01wb表示,视频用00dc或00db)
--db:未压缩的视频帧
--dc:压缩的视频帧
--wb:音频数据
--pc:改用新的调色板

6.idx1块

avi解析
该块是可选的,描述音视频数据的索引块信息。索引块可用如下结构体表示:

// 索引节点信息
typedef struct
{
    DWORD dwChunkId;   // 本数据块的四字符码(00dc 01wb)
    DWORD dwFlags;     // 说明本数据块是不是关键帧、是不是‘rec ’列表等信息
    DWORD dwOffset;    // 本数据块在文件中的偏移量
    DWORD dwSize;      // 本数据块的大小
} AVIIndexEntry;

在AVIMainHeader的dwFlags中指出是否包含索引块。有了索引块可以方便文件快进,如果没有索引块,在对AVI进行快进时需要计算位置,会很耗时。

五.程序编写

通过如上分析对AVI结构有了清楚了解。在这基础上自己写了个AVI解析程序,可以解析AVI1.0格式文件,同时生成对应的视频与音频文件。
我用ffmpeg自带的ffplay测试解析生成的h264视频文件,可以正常播放。
avi解析

参考链接
1)http://www.myvideoproblems.com/Tutorials/dv-aviFiles.htm
2)odmlff2.pdf:https://pan.baidu.com/s/1CXiargLfspQwaWoRYjqHqw 提取码: haj8

本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可
标签: 音视频
最后更新:2020年8月22日

Jeff

管理员——代码为剑,如痴如醉

打赏 点赞
< 上一篇
下一篇 >

文章评论

  • 陈群

    楼主。。您好。。最近在分析AVI文件格式。。有文中提到的AVI2.0相关的文档参考下嘛??请给我一份。。谢谢了。。

    2016年9月9日
    回复
    • Jianchihu

      @陈群 这是官方文档OpenDML AVI File Format Extensions:http://jchblog.u.qiniudn.com/doc/odmlff2.pdf 你可以参考下

      2016年9月10日
      回复
      • 陈群

        @Jianchihu 恩恩。。好的谢谢楼主。。

        2016年9月14日
        回复
  • 樊聪

    楼主你好,请问能否发一份你的AVI解析程序我啊?我这边想参考一下,麻烦了,谢谢!

    2018年1月8日
    回复
    • Jianchihu

      @樊聪 这个给不了,公司写的代码。你可以参考ffmepg或vlc源码。

      2018年1月17日
      回复
  • 没有昵称

    博主你好,最近在研究avi格式,看了你的文章很受启发。
    但是发现文章中有几处错误。
    1.首先是第一幅avi结构的那个图,信息块中,那个avih和下面的LIST,应该是并列关系,而不是包含。因为chunk不可能再包含LIST
    2.还是那幅图,数据块中的LIST,标识应该是“movi”,而不是图中的“move”
    3.在“四.详细解析”的“6)strd块与strh块”,目测应该是 strn,而不是strh,应该是笔误。

    2020年8月22日
    回复
    • Jeff

      @没有昵称 感谢指正,那张图是网上盗的图,为了不误导人家,我还是删了吧。

      2020年8月22日
      回复
  • razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
    取消回复

    这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理。

    文章目录
    • 一.基本数据单元
    • 二.AVI文件类型
    • 三.AVI结构
    • 四.详细解析
      • 1.RIFF文件头
      • 2.hdrl列表
      • 3.info list
      • 4.junk块
      • 5.movi list
      • 6.idx1块
    • 五.程序编写
    相关文章
    • 音视频开发入门:视频基础
    • 大话WebRTC
    • WebRTC音视频传输基础:NAT穿透
    • Intel平台硬件加速视频编解码开发
    • 音视频开发入门:音频基础

    COPYRIGHT © 2025 jianchihu.net. ALL RIGHTS RESERVED.

    Theme Kratos Made By Seaton Jiang