懒人李冰

记录我的生活、学习

媒体文件格式分析之AVI

AVI 是音视频交错(Audio Video Interleaved)的缩写,它是 Microsoft 公司开发的一种符合 RIFF 文件规范的数字音频与视频文件格式。

基本数据结构

AVI 文件中有两种类型结构:Chunks 和 Lists。

1
2
3
4
5
6
7
8
9
10
11
12
13
//Chunks
typedef struct {
    DWORD dwFourCC;
    DWORD dwSize;
    BYTE  data[dwSize];
}CHUNK;
//Lists
typedef struct{
    DWORD dwList;
    DWORD dwSize;
    DWORD dwFourCC;
    BYTE  data[dwSize - 4];
}LIST;

一个包含了videoaudiosubtitle数据的chunk使用一个dwFourCCdwFourCC包含 2 个十六进制数字表示 stream number,2 个字母表示数据类型( dc 表示 video, wb 表示 audio, tx 表示 text)。 dwFourCCdwSizeChunksLists中有相同的含义。

dwFourCC描述chunk 的类型(如hdrl表示 header list),dwSize表示该 chunk 或 list 的大小, 包含dwSize后的所有 byte。在 List 中,dwSize包含了dwFourCC所占有的4 bytes.

dwList的值可以是RIFF(RIFF-ListLIST(List)

AVI 文件类型

通常来讲,有 3 种类型的 AVI 文件:

  • AVI 1.0, 最初始的 AVI 文件类型。
  • Open-DML, AVI 文件格式的扩展。1.02版本相对于1.0版本有两个提高:基本没有文件大小的限制、负载降低了33%。
  • Hybride-Files,Open-DML 文件因为兼容的原因有个额外的限制,Hybride-Files 虽然不是官方致命的文件类型,但确实是一个不错的类型。

AVI 文件布局

一个dwFourCC=AVIRIFF-List称为RIFF-AVI-List, 一个dwFourCC=AVIXRIFF-List称为RIFF-AVIX-List

每个 AVI 文件都有如下布局:

1
2
RIFF AVI    //mandatory
{RIFF AVIX} //only for Open-DML files

并非之受限于 uint32 的限制,文件大小的极限并非 4G,而是

  • 对于 AVI 1.0: sizeof(RIFF-AVI) < 2G
  • 对于 Open-DML, sizeof(RIFF-AVI) < 1G(!!), sizeof(RIFF-AVIX) < 2G

一般来讲,RIFF-AVI-Lists被创建的越小越好。

MainAVIHeader(avih)

avih结构定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typedef struct
{
    DWORD dwMicroSecPerFrame;   //frame display rate(or 0)
    DWORD dwMaxBytesPerSec;     //max transfer rate
    DWORD dwPaddingGranularity; //pad to multiples of this size
    DWORD dwFlags               //the ever-present flags
    DWORD dwTotalFrames;        //frames in file
    DWORD dwInitialFrames;
    DWORD dwStreams;
    DWORD dwSuggestedBufferSize;

    DWORD dwWidth;
    DWORD dwHeight;

    DWORD dwReserved[4];
}MainAVIHeader;
  • dwMicroSecPerFrame 以微妙为单位,包含了一个视频帧的持续时间。该值可以被忽略。注意,某些程序中可能会把它写成 framerate 值,因此 dwMicroSecPerFrame 并不可靠。
  • dwMaxBytesPerSec 文件中最大的数据率,该值同样的不是特别重要。
  • dwPaddingGranularity 填充的数据。
  • dwFlags AVIF_HASINDEX(该文件有index)、AVIF_MUSTUSEINDEX()、AVIF_ISINTERLEAVED AVIF_WASCAPTUREFILE AVIF_COPYRIGHTED AVIF_TRUSTCKTYPE
  • dwTotalFrames 包含了RIFF-AVI list中视频帧数。如果文件中包含RIFF-AVIX-Lists,它不会包含其中的视频帧。因为某些muxer会写一些错误的值,因此该值同样的不可靠。
  • dwInitialFrames 忽略
  • dwStreams 文件中streams的数量。
  • dwSuggestedBufferSize 文件chunks 所需要的内存大小。同样不要高估它的可靠性。
  • dwWidth 视频的宽。
  • dwHeight 视频的高。

Stream Header List

针对每个stream都有一个strl,如果strl的数量与MainAVIHeader::dwStreams不同,就需要发出一个fatal error report

Stream Header List Element(strh)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typedef struct{
    FOURCC fccType;
    FOURCC fccHandler;
    DWORD  dwFlags;
    WORD   wPriority;
    WORD   wLanguage;
    DWORD  dwInitialFrames;
    DWORD  dwScale;
    DWORD  dwRate;  // dwRate / dwScale == samples /second
    DWORD  dwStart;
    DWORD  dwLength;  //In units above
    DWORD  dwSuggestedBufferSize;
    DWORD  dwQuality;
    DWORD  dwSampleSize;
    RECT   rcFrame;
}AVIStreamHeader;
  • fccType vids代表 video, auds代表 audio, txts代表 subtitle。
  • fccHandler
  • dwFlags AVISF_DISABLED AVISF_VIDEO_PALCHANGES
  • dwInitialFrames
  • dwRate / dwScale = samples / second(audio) or frames / second(video)
  • dwStart
  • dwLength
  • dwSuggestedBufferSize
  • dwQuality
  • dwSampleSize

Stream Header List Element(strf)

strf的结构依据媒体类型。对于 video,使用BITMAPINFOHEADER结构,而 audion,使用WAVEFORMATEX结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct tagBITMAPINFOHEADER{
    DWORD biSize;
    LONG  biWidth;
    LONG  biHeight;
    WORD  biPlanes;
    WORD  biBitCount;
    DWORD biCompression;
    DWORD biSizeImage;
    LONG  biXPelsPerMeter;
    LONG  biYPelsPerMeter;
    DWORD biClrUsed;
    DWORD biClrImportant;
}BITMAPINFOHEADER, *PBITMAPINFOHEADER;
  • biSize 该结构体所需要的 byte 大小。
  • biWidth 图像的宽度。如果biCompressionBI_JPEGBI_PNGbiWidth成员相应的指解压缩后的JPEGPNG图像文件的宽。
  • biHeight 位图的高度。如果biHeight是正数,位图是自底向上的DIB,它的原点是右下角地点;。如果biHeight是正数,位图是自顶向下的DIB,它的原点是右上角地点; 如果biHeight是负数,biCompression要么是BI_RGBBI_BITFIELDS,自顶向下的DIB不能被压缩。 如果biCompressionBI_JPEGBI_PNG,则biHeight程序分别指解压缩后的JPEGPNG图像的高。
  • biPlanes 目标设备的planes的数量,该值必须是1。
  • biBitCount 每个像素所用的 bit 数,BITMAPINFOHEADER的成员biBitCount决定了每个 pixel 所占的 bit 数、以及位图中表示颜色所能用到的最大数。该值可以是0/1/4/8/16/24/32
  • biCompression 压缩的自底向上的位图的压缩类型,可以是BI_RGBBI_RLE8BI_RLE4BI_BITFIELDSBI_JPEGBI_PNG.
  • biSizeImage 图像的大小,单位 byte。如果是BI_RGB位图,该值被设置为0。如果biCompressionBI_JPEGBI_PNG,该值分别指示 JPEG 或 PNG 图像的大小。
  • biXPelsPerMeter 水平分辨率。
  • biYPelsPerMeter 垂直分辨率。
  • biClrUsed 颜色表中该位图实际使用的颜色指针。
  • biClrImportant
1
2
3
4
5
6
7
8
9
typedef struct{
    WORD  wFormatTag;
    WORD  nChannels;
    DWORD nSamplesPerSec;
    DWORD nAvgBytesPerSec;
    WORD  nBlocAlign;
    WORD  wBitsPerSample;
    WORD  cbSize;
}WAVEFORMATEX;

(待续…)

Stream Header List Element(indx)

该结构请看下面的AVI index小结。

Stream Header List Element(strn)

该部分包含了stream的的名字。该名字只能使用标准的ASCII,尤其不能使用UTF-8

AVI Indexes

old style index

1
2
3
4
5
6
7
AVIINDEXENTRY index_entry[n]  
typedef struct{
    DWORD ckid;
    DWORD dwFlags;
    DWORD dwChunkOffset;
    DWORD dwChunkLength;
}AVIINDEXENTRY;

Open-DML Index

1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct _aviindex_chunk{
    FOURCC fcc;
    DWORD  cb;
    WORD   wLongsPerEntry;
    BYTE   bIndexSubType;
    BYTE   bIndexType;
    DWORD  nEntriesInUse;
    DWORD  dwChunkId;
    DWORD  dwReserved[3];
    struct _aviindex_entry{
        DWORD adw[wLongsPerEntry];
    }aIndex[];
}AVIINDEXCHUNK;

Using the Open-DML index

The movi - Lists

Movi-List包含VideoAudioSubtitleindex data。它们可以打包进rec-List。如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
LIST movi
    LIST rec
        01wb
        02wb
        03dc
    LIST rec
        01wb
        02wb
    LIST rec
        ...
        ...
        ix01
        ix02
        ...

其中的chunks ID 分别定义如下:

  • ..wb : audio chunk
  • ..dc : video chunk
  • ..tx : subtitle chunk
  • ix.. : standard index block

参考文献

  1. What is avi?
  2. BETA DOCUMENTATION OF RIFF-AVI FILE FORMAT
  3. Audio Video Interleave
  4. AVI 文件格式
  5. AVI 文件解析
  6. FFmpeg AVI