大家好,欢迎来到IT知识分享网。
编解码:AVI格式解析
1 音视频及AVI知识
一个完整的音视频文件格式有mp4、mov、flv、avi、rmvb、mkv、ts等,它们是封装数据的容器,包括音频、视频、字幕、基础元信息等,通过一些特定的编码算法,对各种信息进行编码压缩过后得到的。视频文件的封装格式并不影响视频的画质,影响视频画面质量的是视频的编码格式。
H264、HEVC、VP9、AV1等就是视频编码格式,MP3、AAC、AC-3等就是音频编码格式,SRT、SSA等就是字幕编码格式。
例如:将一个视频流以Xvid格式编码、一个音频流以MP3格式编码、一个字幕流以SRT格式进行编码,按AVI封装标准封装以后,就得到一个AVI视频文件。
AVI即Audio Video Interleaved,音视频交错格式,基于RIFF文件结构。多用于音视频捕捉、编辑、回放等应用程序中。通常情况下,一个AVI文件可以包含多个不同类型的媒体流(典型的情况下有一个音频流和一个视频流),不过含有单一音频流或单一视频流的AVI文件也是合法的。AVI可以算是Windows操作系统上最基本的、也是最常用的一种媒体文件格式。
RIFF即Resource Interchange File Format,资源交互文件格式 。是由Microsoft提出的一种多媒体文件存储方式,不同编码的视频、音频文件按照RIFF保存,当提取文件时,可以根据RIFF的规则解析文件。常见的RIFF文件有:WAV、AVI等。
2 最基本的数据单元
//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;
Chunks由三部分组成:4字节的数据流格式ID,4字节的数据大小,数据。
Lists由四部分组成:4字节LIST(LIST块中可以再包含一系列的子块),4字节数据加fourCC大小,4字节数据流格式ID,数据。
3 AVI主要结构介绍
一个AVI文件通常有如下几个子块组成:
- ID为”AVI”的RIFF,文件头
- ID为”hdrl”的list,信息块,包含了音视频信息,描述媒体流信息
- ID为”info”的list,包含编码该AVI的程序信息
- ID为”junk”的chunk,无用的数据,用于字节对齐
- ID为”movi”的list,数据块,包含了交错排列的音视频数据
- ID为”idxl”的chunk,索引块,包含音视频排列的索引数据(可选块,不存在时seek会慢很多)
文件信息:
分析工具分别是MediaInfo以及MediaConch。
4 AVI主要结构解析
1.RIFF文件头
4个字节的”RIFF”,4字节的RIFF文件大小(字节),4字节为RIFF文件类型”AVI”
2.hdrl列表
1)hdrl列表头
4字节的”LIST”描述信息,4字节list大小(8952字节),4字节list类型”hdrl”
2)avih块
用于描述主信息,该块可以用如下结构体表示
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;
3)strl list头部
一个strl list中至少包含一个strh块和一个strf块。文件中有多少个流,就对应有多少个strl list。
上图可知存在两个流,Stream info 0,Stream info 1。
4)strh块
// 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块
该块用于描述流的具体信息
- 视频流,fccType = “vids”
// 位图头 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;
- 音频流,fccType = “auds”
// 音频波形信息 typedef struct {
WORD wFormatTag; WORD nChannels; // 声道数 DWORD nSamplesPerSec; // 采样率 DWORD nAvgBytesPerSec; // 每秒的数据量 WORD nBlockAlign; // 数据块对齐标志 WORD wBitsPerSample; // 每次采样的数据量 WORD cbSize; // 大小 } WaveFormatEx;
6)strd块与strn块
strd:可选的额外的头信息数据
strn:可选的流的名字
这两个块是可选的,本AVI文件不包含,故不分析。
3.info列表
该list用于描述编码该AVI文件的程序信息,包含一个isft块。
4.junk块
一些垃圾填充数据,用于内部数据的队齐(填充),直接跳过。
5.movi列表
存储音视频数据,音视频数据在其中以交错方式存放着,视频clip,n音频clip,视频clip,n音频clip…方便seek。
音视频数据子块的种类有:db,dc,pc,wb。
–:数据所属的流的序号,视频是00dc或00db,音频是01wb。
–db:未压缩的视频帧
–dc:压缩的视频帧
–wb:音频数据
–pc:改用新的调色板
6.idx1块
该块是可选的,描述音视频数据的索引块信息,在AVIMainHeader的dwFlags中指出是否包含索引块。有了索引块可以方便文件快进,如果没有索引块,在对AVI进行快进时需要计算位置,会很耗时。索引块可用如下结构体表示:
// 索引节点信息 typedef struct {
DWORD dwChunkId; // 本数据块的四字符码(00dc 01wb) DWORD dwFlags; // 说明本数据块是不是关键帧、是不是‘rec ’列表等信息 DWORD dwOffset; // 本数据块在文件中的偏移量 DWORD dwSize; // 本数据块的大小 } AVIIndexEntry;
5 总结
可以编译FFmpeg源码,对AVI文件进行解码,在分离器Demuxer中进一步研究其格式,会有更清晰的认识。
RIFF ('AVI' LIST('hdrl' 'avih'(主 AVI 信息头数据) LIST('strl' 'strh' (流的头信息数据) 'strf' (流的格式信息数据) ['strd' (可选的额外的头信息数据)] ['strn' (可选的流的名字) ] ) ... // 其他流信息 ) LIST('movi' {
// 媒体流数据 SubChunk | LIST ('rec' SubChunk1 SubChunk2 ... } ) ['idx1' (可选的 AVI 索引块数据) ] )
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/115721.html