【数据压缩】WAV文件和AVI文件格式分析

一、WAV文件和AVI文件格式简介

WAV的英文全称是Waveform Audio File Format ,它采用 RIFF (Resource Interchange File Format)文件格式结构。通常用来保存 PCM 格式的原始音频数据,所以通常被称为无损音频。但是严格意义上来讲, WAV 也可以存储其它压缩格式的音频数据。

AVI的英文全称是Audio/Video Interleaved,被我们称为音频视频交错格式。它是一种音频视频交错在一起同步播放的文件格式,其中它对视频文件采用了一种有损压缩方式,尽管该文件在画面质量上不太好,但是应用范围也是比较广泛的。如主要应用在多媒体光盘上,用来保存电视、电影等各种影响信息。AVI是由Microsoft公司1992年11月推出的一种符合RIFF文件规范的数字音频与视频文件格式,经过发展后,也成为了常用的视频格式之一。

AVI与WAV文件都属于RIFF文件,因此都遵循RIFF文件的格式要求。

二、RIFF文件格式介绍

1、RIFF文件简介

RIFF的英文全称是Resource Interchange File Format(资源交互文件格式),是由Microsoft提出的一种多媒体文件存储方式,不同编码的视频、音频文件按照RIFF保存,当提取文件时,可以根据RIFF的规则解析文件。常见的RIFF文件有:
• 音频视频交错格式数据 .AVI
• 波形格式数据 .WAV
• 位图数据格式 .RDI
• MIDI格式数据 .RMI
• 调色板格式 .PAL
• 多媒体电影 .RMN
• 动画光标 .ANI
• 其他的RIFF文件 .BND

2、RIFF文件格式

RIFF格式是一种树状结构,主要由 FOURCC, CHUNK,LIST 组成。基本组成单元为LIST和CHUNK:LIST相当于目录,可以包含多个CHUNK或者多个LIST,包含关键字“LIST”。CHUNK是数据保存的基本单元,可用于保存音视频数据或者一些参数信息。RIFF文件结构最开始4个字节表示“RIFF”,接着4个字节表示该文件的大小,再下来的4个字节表示该文件的类型(AVI或者WAV等)。

2.1 CHUNK

CHUNK 是组成 RIFF 文件的基本单元,它的基本结构如下:

struct chunk {
	uint32_t id;         // 块标识符
    uint32_t size; 	     // 块大小
    uint8_t  data[size]; // 块内容
};
id 由 4 个 ASCII 字符组成,用于识别块中包含的数据,如:"RIFF", "LIST", "fmt", "data", "WAV", "AVI" ......,由于这种文件结构最初是由 Microsoft 和 IBM 为 PC 机所定义, RIFF 文件是按照小端字节顺序写入的。
size 表示 data 域的数据长度。
data 所包含的数据是以 word 为单位排列的,如果长度是奇数,则在最后添加一个空 (NULL) 字符。
    
Note: 如果 id 为 "RIFF""LIST", 则 data 域则包含 SUB_CHUNK。   

2.2 LIST

LIST 数据块结构如下:

struct list {
   uint32_t list_size;             // List 大小
   uint32_t list_type;             // List 类型
   uint8_t  list_data[list_size];  // List 数据
};

Note: list_data 是该 LIST 的数据内容,由 CHUNK 和 SUB_LIST 组成,它们的个数和组成次序可以是不确定的。

2.3 FOURCC

一个 FOURCC (four character code) 是占用 4 个字节的数据,一般表示 4 个 ASCII 字符。在 “RIFF” 文件格式中,块的起始标识等信息都是使用 FOURCC 表示的,如 “fmt”, “data”, “wav“等。

三、WAV文件格式介绍

1、WAV文件简介

wav是微软开发的一种音频文件格式,注意,wav文件格式是无损音频文件格式,相对于其他音频格式文件数据是没有经过压缩的,通常文件也相对比较大些。
通常使用三个参数来表示声音,量化位数,取样频率和采样点振幅。量化位数分为8位,16位,24位三种,声道有单声道和立体声之分,单声道振幅数据为n1矩阵点,立体声为n2矩阵点,取样频率一般有11025Hz(11kHz) ,22050Hz(22kHz)和44100Hz(44kHz) 三种,不过尽管音质出色,但在压缩后的文件体积过大,相对其他音频格式而言是一个缺点,其文件大小的计算方式为:

WAV格式文件所占容量(B) = (取样频率 X量化位数X 声道) X 时间 / 8 (字节= 8bit)

而采样率一般是44.1K,16bit采样精度,存储成
WAV格式大小 = 44.1KHz(采样率) X 16bit(采样位数) X 2(双声道) X 播放时间
每一分钟WAV格式的音频文件的大小为10MB,其大小不随音量大小及清晰度的变化而变化。

2、WAV文件格式

WAVE文件是非常简单的一种RIFF文件,它的格式类型为"WAVE"。
WAV文件遵循RIFF规则,其内容以区块(chunk)为最小单位进行存储。
WAV文件一般由3个区块组成:RIFF chunk、Format chunk和Data chunk。
另外,文件中还可能包含一些可选的区块,如:Fact chunk、Cue points chunk、Playlist chunk、Associated data list chunk等。

2.1 RIFF区块

【数据压缩】WAV文件和AVI文件格式分析_第1张图片

  • 以’RIFF’为标识
  • Size是整个文件的长度减去ID和Size的长度
  • Type是WAVE表示后面需要两个子块:Format区块和Data区块

2.2 FORMAT区块

【数据压缩】WAV文件和AVI文件格式分析_第2张图片

  • 以’fmt '为标识
  • Size表示该区块数据的长度(不包含ID和Size的长度)
  • AudioFormat表示Data区块存储的音频数据的格式,PCM音频数据的值为1
  • NumChannels表示音频数据的声道数,1:单声道,2:双声道
  • SampleRate表示音频数据的采样率
  • ByteRate每秒数据字节数 = SampleRate * NumChannels * BitsPerSample / 8
  • BlockAlign每个采样所需的字节数 = NumChannels * BitsPerSample / 8
  • BitsPerSample每个采样存储的bit数,8:8bit,16:16bit,32:32bit

2.3 DATA区块

【数据压缩】WAV文件和AVI文件格式分析_第3张图片

  • 以’data’为标识
  • Size表示音频数据的长度,N = ByteRate * seconds
  • Data音频数据

2.4 小端存储

WAV文件以小端形式来进行数据存储。

大端模式:数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
小端模式:数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中。

2.5 PCM数据在WAV文件中的bit位排列方式

【数据压缩】WAV文件和AVI文件格式分析_第4张图片

四、WAV文件格式实例分析

要分析的WAV文件的基本信息如下,用Visual Studio2022以二进制编辑器形式打开该WAV文件。
【数据压缩】WAV文件和AVI文件格式分析_第5张图片
WAV文件是在PCM纯音频样本数据的基础上添加了44字节的文件头。
在这里插入图片描述

各字节依次表示:
①资源交换文件标志(RIFF),4字节,52 49 46 46,固定写法;
②从下个地址(08)到WAV文件结尾的总字节数,4字节,7E 26 3A 00,整个WAV文件的大小就是该数值+8;
7E 26 3A 00(16)=3810942(10),与文件大小3810950正好差了8字节。
PCM音频样本总字节数+44−8=WAV文件字节数
③WAVE 文件标志 , 4字节,57 41 56 45 , 是 WAVE 四个字母的 ASCII 码 , 固定写法 ;
④波形格式标志 , 4字节,66 6D 74 20 , 一般都是 fmt , 其中 0x20 对应的字符是空格 ;
⑤过渡字节 , 4字节,12 00 00 00 , 不确定 , 有的时候是 10 00 00 00 ;
⑥格式种类 , 2字节,01 00 , 1 时表示线性 PCM 编码 ;
⑦通道数 , 2字节,02 00 , 1 表示单声道 , 2 表示立体声 ;
⑧采样频率 , 4字节,44 AC 00 00 , 44100Hz ;
⑨波形数据传输速率 , 即每秒中的字节数 , 4字节,10 B1 02 00 , 每秒传输 176400 字节 ;
计算公式 :
采样率×通道数×采样位数/8=44100×2×16/8=176400。
采样位数是16位 , 1字节8位 , 16位是2字节 , 即每个采样2字节 ;
⑩数据块调整长度 , 2字节,04 00 , 表示4 字节 ;
计算公式:
通道数×样本数据位数/8=2×16/8=4
⑪每个样本的数据位数 , 2字节,10 00 , 表示16位即2字节;

注:接下来是ffmpeg转码的数据表示ffmpeg转码的信息

在这里插入图片描述

⑫数据标记 , 4字节,64 61 74 61 , data 的 ASCII 码值 ;
⑬ PCM 数据总长度, 单位 字节 , 00 26 3A 00 , PCM 数据总长度为 3,810,816 字节 ;

五、AVI文件格式介绍

1、AVI文件简介

AVI是一种最复杂的RIFF文件,它能同时存储同步表现的音频视频数据。现在常用的AVI文件有2种:AVI-1, AVI-2。AVI-1中只包含一个DV数据流,占用较少的存储空间。AVI-2中通常包含一个视频流和一个音频流,只有一个视频流或者音频流也是合法的。
AVI层次划分如下图所示。

【数据压缩】WAV文件和AVI文件格式分析_第6张图片

2、AVI文件格式

AVI的RIFF块的形式类型是AVI,它包含3个子块,如下所述。

  1. 信息块——包括文件的通用信息,定义数据格式,所用的压缩算法等参数。
  2. 数据块——包含实际数据流,即图像和声音序列数据。这是文件的主体,也是决定文件容量的主要部分。视频文件的大小等于该文件的数据率乘以该视频播放的时间长度。
  3. 索引块——索引块包含数据块列表好它们在文件中的位置,以提供文件内数据随机存取能力。

2.1 信息块

信息块是ID为“hdrl”的LIST块,定义AVI文件的数据格式。
“hdrl”LIST块包含两个子块,一个是ID为“avih”的子块和一个是ID为”strl”的LIST块。
“avih”块结构:用于记录AVI文件的全局信息,比如流的数量,视频图像的宽和高等。

typedef struct
{
 DWORD ChunID;                // 必须为'avih'
 DWORD ChunkSize;             //本数据结构的大小,不包括最初的8個位元組(ID和Size兩個域)
 DWORD dwMicroSecPerFrame ;   //显示每帧所需的时间ns,定义avi的显示速率
 DWORD dwMaxBytesPerSec;      //最大的数据传输率
 DWORD dwPaddingGranularity;  //记录块的长度需为此值的倍数,通常是2048
 DWORD dwFlages;              //AVI文件的特殊属性,如是否包含索引块,音视频数据是否交叉存储
 DWORD dwTotalFrame;          //文件中的总帧数
 DWORD dwInitialFrames;       //说明在开始播放前需要多少桢
 DWORD dwStreams;             //文件中包含的数据流个数
 DWORD dwSuggestedBufferSize; //建议使用的缓冲区的大小,
                              //通常为存储一桢图像以及同步声音所需要的数据之和
 DWORD dwWidth;               //图像宽
 DWORD dwHeight;              //图像高
 DWORD dwReserved[4];         //保留值
}MainAVIHeader;

”avih”块的数据部分:一个或多个“strl”子列表

  1. 文件中有多少个流,这里就对应有多少个“strl”子列表。
  2. 每个“strl”字列表至少包含一个“strh”块和一个“strf”块,
  3. “strd”块(保存编解码器需要的一些配置信息)和“strn”块(保存流的名字)可选。
  4. 注意:“strl”子列表出现的顺序与媒体流的编号是对应的,比如第一个“strl”字列表说明的是第一个流(Stream 0),第二个“strl”字列表说明的是第二个流(Stream 1),以此类推。

“strh”块结构:用于说明这个“strl”LIST块对应的数据流的头信息:

typedef struct 
{
 FOURCC fccType;       //4字节,表示数据流的种类,vids 表示视频数据流,auds 音频数据流
 FOURCC fccHandler;    //4字节 ,表示数据流解压缩的驱动程序代号
 DWORD dwFlags;        //数据流属性
 WORD wPriority;       //此数据流的播放优先级
 WORD wLanguage;       //音频的语言代号
 DWORD dwInitalFrames; //说明在开始播放前需要多少桢
 DWORD dwScale;        //数据量,视频每桢的大小或者音频的采样大小
 DWORD dwRate;         //dwScale /dwRate = 每秒的采样数
 DWORD dwStart;        //数据流开始播放的位置,以dwScale为单位
 DWORD dwLength;       //数据流的数据量,以dwScale为单位
 DWORD dwSuggestedBufferSize; //建议缓冲区的大小
 DWORD dwQuality;     //解压缩质量参数,值越大,质量越好
 DWORD dwSampleSize;  //音频的采样大小
 RECT rcFrame;        //视频图像所占的矩形
}AVIStreamHeader;

“strf” 块结构:“strf”子块紧跟在“strh”子块之后,其结构是“strh”子块的类型而定,如下所述:

  • 如果strh子块是视频数据流,则strf子块的内容是一个BITMAPINFO结构,如下。
typedef struct tagBITMAPINFO
{
 BITMAPINFOHEADER bmiHeader;
 RGBQUAD bmiColors[1]; //颜色表
}BITMAPINFO;

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;
  • 如果strh子块是音频数据流,则strf子块的内容是一个WAVEFORMAT结构,如下:
typedef struct 
{
 WORD wFormatTag; 
 WORD nChannels;        //声道数
 DWORD nSamplesPerSec;  //采样率
 DWORD nAvgBytesPerSec; //WAVE声音中每秒的数据量
 WORD nBlockAlign;      //数据块的对齐标志
 WORD biSize;           //此结构的大小
}WAVEFORMAT

“strd”块结构:“strd”子块紧跟在strf子块后,存储供压缩驱动程序使用的参数,不一定存在,也没有固定的结构
“strl”List块定义的AVI数据流依次将“hdrl”LIST块中的数据流头结构与“movi”LIST块中的数据联系在一起,第一个数据流头结构用于数据流0,第二个用于数据流1,依次类推。

2.2 数据块

数据块是ID为“movi”的LIST块,包含AVI的音视频序列数据。
用于保存真正的媒体流数据(视频图像帧数据或音频采样数据等)。保存方式为:

  1. 将数据块直接嵌套在“movi”列表里面
  2. 将几个数据块分组成一个“rec”列表后再编排进“movi”列表

(注意:在读取AVI文件内容时,建议将一个“rec”列表中的所有数据块一次性读出)
但是,当文件中包含有多个流的时候,数据块与数据块之间如何来区别呢?于是数据块使用了一个四字符码来表征它的类型,这个四字符码由2个字节的类型码和2个字节的流编号组成。
“db”——非压缩视频
“dc”——压缩视频
“pc”——改用新的调色板
“wb”——音缩视频
比如:第一个流(Stream 0)是音频,则表征音频数据块的四字符码为“00wb”;
第二个流(Steam 1)是视频,则表征视频数据块的四字符码为“01db”或“01dc”。
对于视频数据来说,在AVI数据序列中间还可以定义一个新的调色板,每个改变的调色板数据块永“xxpc”来表征,新的调色板使用一个数据结构AVIPALCHANGE来定义。(注意:如果一个流的调色板中途改变,则应在这个流格式的描述中,也及时AVISTREMAHEADER结构的dwFlags中包含一个AVISF_VIDEO_PALCHANGES标记)另外,文字数据块可以使用随意的类型码表征。

2.3 索引块

索引块是ID为“idxl”的子块,定义“movi”LIST块的索引数据,是可选块。
最后紧跟在“hdr”列表块和“movi”列表块之后的,就是AVI文件可选的索引块。这个索引块为AVI文件中每一个媒体数据块进行索引,并且记录它们在文件中的偏移(可能相对于“movi”列表,也可能相对于AVI文件开头)。索引块使用一个四字符码“idxl”来表征,索引信息使用一个数据结构AVIOLDINDEXl来定义。

typedef struct _avioldindex {
  FOURCC fcc;                  // 必须为‘idx1’
  DWORD cb;                   // 本数据结构的大小,不包括最初的8个字节(fcc和cb两个域)
  struct _avioldindex_entry {
  DWORD dwChunkId;            // 表征本数据块的四字符码
  DWORD dwFlags;              // 说明本数据块是不是关键帧、是不是‘rec ’列表等信息
  DWORD dwOffset;             // 本数据块在文件中的偏移量
  DWORD dwSize;               // 本数据块的大小
  } aIndex[];                // 这是一个数组!为每个媒体数据块都定义一个索引信息
} AVIOLDINDEX;

注意:如果一个AVI文件包含有索引块,则应在AVI信息头的描述中,也即是AVIMAINHEADER结构的dwFlags中包含一个AVI_HASINDEX标记。
还有一种特殊的数据块,用一个四字符码“JUNK”来表征,它用于内部数据的对齐(填充),应用程序应该忽略这些数据块的实际意义。

六、AVI文件思考题

用MediaConch打开一个AVI文件,可以发现:
①AVI文件音频和视频的数据是交织放置的,这种按交替方式组织音频和视频数据的方式可使得读取视频数据流时能更有效地从存储媒介得到连续的信息。
②AVI文件的一个视频帧占据1个字节(?),一个音频帧占据32个字节,如下图所示。
【数据压缩】WAV文件和AVI文件格式分析_第7张图片
【数据压缩】WAV文件和AVI文件格式分析_第8张图片

七、总结

WAV文件是非常简单的一种RIFF文件,而AVI文件是一种较为复杂的RIFF文件,它们都按RIFF格式存储。
WAV文件是在PCM纯音频样本数据的基础上添加了44字节的文件头。文件头中包含量化位数,取样频率和通道数等信息。
AVI文件包含信息块、数据块和索引块三个子块,音视频数据是交织放置的。


参考

什么是AVI文件
WAV文件格式详解
RIFF 格式解析
AVI文件格式详解
wav音频文件格式解析【个人笔记】(自用)
WAV文件格式解析
【音频处理】WAV 文件格式分析 ( 逐个字节解析文件头 | 相关字段的计算公式 )

你可能感兴趣的:(数据压缩课程,音视频)