音频文件格式解析与编解码
一、音频格式总览
说到语音技术就不得不说起音频数据,从硬件设备采集语音信号,语音信号的处理,到语音信号A/D转换得到原始数据(raw data),再到对原始数据进行编码得到音频文件,对音频文件解码进行播放。那么为什么会出现如此多的音频格式?使用最多的几种音频格式有MP3、WMA、WAV、AAC、FLAC、APE、WV、ASF、VQF、MID、OGG、M4A、eAAC+。目前只用到了其中三种,故详细分析WAV、MP3、OGG。
二、原始数据(raw data,以PCM编码为例)
模拟音频信号经模数转换(A/D变换)直接形成的二进制序列,该文件没有附加的文件头和文件结束标志。而PCM(Pulse-code Modulation,脉冲编码调制)是一种模拟信号的数字化方法,常被用于数字电信系统中,非常频繁地,PCM编码以一种串行通信的形式,使数字传讯由一点至下一点变得更容易——不论在已给定的系统内,或物理位置。
PCM过程放在ALSA的实践中作为理论部分呈现,这里给出多通道音频数据的比特位特征。
图1 多通道音频数据的比特流格式
如图1所示,单通道音频数据以采样位数(bit)串行记录在比特流中:
1) 8 bit 采样位数: 意味着每个采样值能占据1个字节大小;
+------+------+------+------+------+------+------+------+------+
| 500 | 300 | -100 | -20 | -300 | 900 | -200 | -50 | 250 |
+------+------+------+------+------+------+------+------+------+
2)16 bit 采样位数:分为两个字节以小端(little-endian)方式存储在比特流中;
双通道及多通道数据音频数据以采样位数组织如下(n 为采样位数):
+-- n bit---+---n bit---+-----+---n bit---+---n bit--+------+--n bit---+---n bit---+----------+| channel1 | channel2 | ... | channel1 | channel2 | ... | channel1 | channel2 | ... | +----------+----------+---------+----------+---------+----------+---------+----------+----------+
PCM的每个样本值包含在一个整数i中,i的长度为容纳指定样本长度所需的最小字节数。首先存储低有效字节,表示样本幅度的位放在i的高有效位上,剩下的位置为0。
计算机读入原始音频数据的方式与打开二进制文件相同。
#include <stdio.h>
#include <stdlib.h>int main()
{char *fn;char *data;FILE *fp;int len;fn = "./test.pcm";fp = fopen(fn, "rb");if(!fp) {printf("file open failed.\n");exit(1);}fseek(fp, 0, SEEK_END);len = ftell(fp);if(!len) {printf("file is null.\n");fclose(fp);exit(1);}printf("file len = %d\n",len);data = (char *)malloc(len);fseek(fp, 0, SEEK_SET);fread(data, sizeof(__int16_t), len/sizeof(__int16_t), fp);fclose(fp);printf("%.*s\n",1,data);free(data);return 0;
}
三、wav文件
wav(Waveform Audio FIle Format),即波形声音文件,由微软公司开发,是最早的数字音频格式,音质与CD相差无几,但缺点是wav文件非常庞大,不利于数据传输。
struct waitor_wav_format
{
#pragma pack(1)char riff_id[4]; // "RIFF",big-endian__uint32_t file_len; // file length,little-endianchar wave_id[4]; // "WAVE“,big-endianchar fmt_id[4]; // "fmt",big-endian,beginning of fmt chunkchar transition[4]; // size of fmt chunk__uint16_t fmt_type; // 1-PCM__uint16_t channel; // 通道数__uint16_t sample_rate; // 采样率__uint32_t avg_bytes_per_sec; // sample_rate * block_align__uint16_t block_align; // 每次采样大小__uint16_t bit_per_second; // 采样精度//__uint16_t cbsize // 附加数据大小char data_id[4]; // "data"__uint32_t audio_len; // 音频数据的长度
#pragma pack()
};
wav文件分为3个(或4个)chunk,每个chunk基本格式为 chunk_id + chunk_size + chunk_data。总体结构为 文件头 wav_hdr + 音频数据 PCM格式。在解析wav文件时,可能会由于不同系统不同调制方式方式的不同增加几个额外的字节,这时应在数据结构中加入#pragma pack(1),以设置对齐的方式空出额外长度。
int main()
{waitor_wav_t *w;char *fn, *audio;// char buffer[4096];int ret;FILE *fp = fopen("./enc.ogg", "wb");fn = "../data/test.wav";w = waitor_wav_read(audio, fn); // 解析wav文件格式,转为二进制流voiceif(!w) {printf("wavfile read failed.\n");fclose(fp);free(w);exit(1);}printf(" chunk_id1 : %.*s\n", 4, w->riff_id);printf(" file len : %d\n", w->file_len);printf(" fomat : %.*s\n", 4, w->wave_id);printf(" sub chunk id : %.*s\n", 4, w->fmt_id);printf(" fmt type : %d\n", w->fmt_type);printf(" channel : %d.\n", w->channel);printf(" sample_rate : %d \n", w->sample_rate);fclose(fp);free(w);return 0;
}
四、MP3文件
MP3(Moving Picture Experts Group Audio Layer III),是利用同名压缩技术,将音乐以1:10甚至1:12的压缩率压缩成容量较小的文件,并且能够保证损失音质极少,也因此成为网络音乐传输的主要格式。特点:兼具少损音质和小体积的特点,缺点是最高比特率是320K,高频部分一刀切,音质不高。
MPEG压缩有
MP3音频压缩包含编码和解码两个部分。编码是将WAV文件中的数据转换成高压缩率的位流形式,解码是接受位流并将其重建到WAV文件中。
MP3采用了感知音频编码(Perceptual Audio Coding)这一失真算法。人耳感受声音的频率范围是20Hz-220kHz,MP3截掉了大量的冗余信号和无关的信号,编码器通过混合滤波器组将原始声音变换到频率域,利用心理声学模型,估算刚好能被察觉到的噪声水平,再经过量化,转换成Huffman编码,形成MP3位流。解码器要简单得多,它的任务是从编码后的谱线成分中,经过反量化和逆变换,提取出声音信号。
在压缩音频数据时,先将原始声音数据分成固定的分块,然后作顺向MDCT变换,MDCT本身并不进行数据压缩,只是将一组时域数据转换成频域数据,以得知时域变化情况,顺向MDCT将每块的值转换为512个MDCT系数。量化使数据得到压缩,在对量化后的变换样值进行比特分配时要考虑使整个量化块最小,这就成为有损压缩了。解压时,经反向MDCT将512个系数还原成原始声音数据,前后的原始声音数据是不一致的,因为在压缩过程中,去掉了冗余和不相关数据。
MP3文件的详细格式参见以下两个博客:
MP3文件格式全解
MP3文件结构解析(超详细)
libmad库常被用来作为mp3解码器,不需要自己造轮子,基于libmad的mp3解码播放器参见:
基于libmad的解码播放器
接下来总结MP3文件的格式与libmad解码应用过程。
1、MPEG压缩格式
MP3文件格式分为三个部分:
标签头和标签帧数据结构,每个ID3V2都包含一个标签头和若干标签帧,而标签帧由帧头和至少一个字节的内容组成。
ID3V2有四个版本,但流行的只有ID3V2.3:
/* ID3V2 的标签头结构 */
struct ID3V2Header
{
#pragma pack(1)unsigned char Header[3]; /* 保存的值比如为"ID3"表示是ID3V2 */unsigned char Version; /* 如果是ID3V2.3则保存3,如果是ID3V2.4则保存4 */unsigned char Revision; /* 副版本号 */unsigned char Flag; /* 标志,使用高三位,其它位为0 */unsigned char Size[4]; /* 整个标签帧大小,除去本结构体的 10 个字节 */
#pragma pack()
};/* 标签帧帧头的结构 */
struct ID3V2Frame
{
#pragma pack(1)unsigned char id[4]; /* 标志帧,说明其内容,例如作者/标题等*/char size[4]; /* 标志帧大小 */char flags[2]; /* 标志帧,只定义了6位 */
#pragma pack()
}
ID3V1:
/* ID3V1信息结构 */
struct ID3V1
{char Header[3]; /* 标签头"TAG",标识ID3V1 */char Title[30]; /* 歌名 */char Artist[30]; /* 作者 */char Album[30]; /* 专辑 */char Year[4]; /* 年份 */char Comment[30]; /* 备注 */char Genre; /* 类型 */
}
音频数据帧由帧头和音频数据组成:
struct DataFrameHeader
{unsigned int bzFrameSyncFlag1:8; /* 全为 1 */unsigned int bzProtectBit:1; /* CRC */unsigned int bzVersionInfo:4; /* 包括 mpeg 版本,layer 版本 */unsigned int bzFrameSyncFlag2:3; /* 全为 1 */unsigned int bzPrivateBit:1; /* 私有 */unsigned int bzPaddingBit:1; /* 是否填充,1 填充,0 不填充layer1 是 4 字节,其余的都是 1 字节 */unsigned int bzSampleIndex:2; /* 采样率索引 */unsigned int bzBitRateIndex:4; /* bit 率索引 */unsigned int bzExternBits:6; /* 版权等,不关心 */ unsigned int bzCahnnelMod:2; /* 通道* 00 - Stereo 01 - Joint Stereo* 10 - Dual 11 - Single*/
};
2、MPEG解码(以libmad-0.15.1b源代码为例)
libmad运行demo为minimad.c,从其中的用法可以看出需要用户设置几个回调函数已控制程序运行。分别为input, output,header,filter 和error 。其中input实现mp3文件输入并转换为mad_stream,output实现根据用户需求对数据的再处理。
使用libmad几个封装好的基本结构如下:
/* 存储未解码的比特流 */
struct mad_stream {unsigned char const *buffer; /* input bitstream buffer */unsigned char const *bufend; /* end of buffer */unsigned long skiplen; /* bytes to skip before next frame */int sync; /* stream sync found */unsigned long freerate; /* free bitrate (fixed) */unsigned char const *this_frame; /* start of current frame */unsigned char const *next_frame; /* start of next frame */struct mad_bitptr ptr; /* current processing bit pointer */struct mad_bitptr anc_ptr; /* ancillary bits pointer */unsigned int anc_bitlen; /* number of ancillary bits */unsigned char (*main_data)[MAD_BUFFER_MDLEN];/* Layer III main_data() */unsigned int md_len; /* bytes in main_data */int options; /* decoding options (see below) */enum mad_error error; /* error code (see above) */
};/* 数据帧帧头 */
struct mad_header {enum mad_layer layer; /* audio layer (1, 2, or 3) */enum mad_mode mode; /* channel mode (see above) */int mode_extension; /* additional mode info */enum mad_emphasis emphasis; /* de-emphasis to use (see above) */unsigned long bitrate; /* stream bitrate (bps) */unsigned int samplerate; /* sampling frequency (Hz) */unsigned short crc_check; /* frame CRC accumulator */unsigned short crc_target; /* final target CRC checksum */int flags; /* flags (see below) */int private_bits; /* private bits (see below) */mad_timer_t duration; /* audio playing time of frame */
};/* 有效数据帧 */
struct mad_frame {struct mad_header header; /* MPEG audio header */int options; /* decoding options (from stream) */mad_fixed_t sbsample[2][36][32]; /* synthesis subband filter samples */mad_fixed_t (*overlap)[2][32][18]; /* Layer III block overlap data */
};/* 采样后的PCM音频数据 */
struct mad_pcm {unsigned int samplerate; /* sampling frequency (Hz) */unsigned short channels; /* number of channels */unsigned short length; /* number of samples per channel */mad_fixed_t samples[2][1152]; /* PCM output samples [ch][sample] */
};/* 解码后的音频数据 */
struct mad_synth {mad_fixed_t filter[2][2][2][16][8]; /* polyphase filterbank outputs *//* [ch][eo][peo][s][v] */unsigned int phase; /* current processing phase */struct mad_pcm pcm; /* PCM output */
};/* 解码过程控制 */
enum mad_flow {MAD_FLOW_CONTINUE = 0x0000, /* continue normally */MAD_FLOW_STOP = 0x0010, /* stop decoding normally */MAD_FLOW_BREAK = 0x0011, /* stop decoding and signal an error */MAD_FLOW_IGNORE = 0x0020 /* ignore the current frame */
};
libmad的示例程序流程如下,用户可以直接使用回调机制使用libmad,也可以使用decoder.c的接口按照需求获取中间数据。
五、OGG 文件 (参考:RFC 3533)
OGG(OGG Vobis)是一种新的音频压缩格式,类似于MP3等现有的音乐格式。完全免费,没有专利限制。Vorbis 是这种音频压缩机制的名字,OGG是一个计划的名字,该计划意图设计一个完全开放的多媒体系统,OGG Vorbis是该计划的一部分。
特点:支持多声道;现在创建的OGG文件可以在未来的任何播放器上播放,因此,这种文件格式可以不断地进行大小和音质的改良,而不影响既有的编码器和播放器;目前最好的有损格式之一,最高比特率500K。
1、相关概念
stream : 分为逻辑流与物理流,Ogg封装的结果称作物理流,一个物理流包含一个或多个逻辑流,这些逻辑流由ogg编码器创建,每个物理流中的逻辑流以一个特殊的页开始 -- bos,以一个特殊的页结束 -- eos;
physical bitstream with pages ofdifferent logical bitstreams grouped and chained-------------------------------------------------------------|*A*|*B*|*C*|A|A|C|B|A|B|#A#|C|...|B|C|#B#|#C#|*D*|D|...|#D#|-------------------------------------------------------------bos bos bos eos eos eos bos eos
bos : beginning of stream; eos : end of stream
图中有两个物理流,第一个时序上有三个逻辑流ABC,分别以bos和eos为头尾;第二个只有一个逻辑流D
packet : 一个解码单元,或是一帧数据;
segment : 由 packet 分割而成,一个segment 最多包含255格式bytes,segment没有header ;
page : 是 ogg 文件格式的基本组成单元,是对 segment 的封装,为几个连续的 segment 添加 header 构成 page;
2、音频格式剖析:
OGG文件基本构成单位是页(Page),编码过程是由物理流向页转换的过程,OGG编码的主要过程如下:
逻辑流由若干个packet组成-----------------------------------------------------------------> | packet_1 | packet_2 | packet_3 | <-----------------------------------------------------------------|每个packet可以分成若干个segmentvpacket_1 (5 segments) packet_2 (4 segs) p_3 (2 segs)------------------------------ -------------------- ------------.. |seg_1|seg_2|seg_3|seg_4|s_5 | |seg_1|seg_2|seg_3|| |seg_1|s_2 | ..------------------------------ -------------------- ------------| 给连续的几个segment加上page header就组成了pagevpage_1 (packet_1 data) page_2 (pket_1 data) page_3 (packet_2 data)
------------------------ ---------------- ------------------------
|H|------------------- | |H|----------- | |H|------------------- |
|D||seg_1|seg_2|seg_3| | |D|seg_4|s_5 | | |D||seg_1|seg_2|seg_3| | ...
|R|------------------- | |R|----------- | |R|------------------- |
------------------------ ---------------- ------------------------|
pages of |
other --------| |
logical -------
bitstreams | MUX |-------|vpage_1 page_2 page_3------ ------ ------- ----- -------... || | || | || | || | || | ...------ ------ ------- ----- -------physical Ogg bitstream
1)从编码器获得逻辑流的各个packet;
2)将packet分割成Segment,分片;
3)将Segment 打包成Page,页封装;
4)将多个已经封装 page 完毕的逻辑流按应用要求的时序关系合成物理流,从而获得 OGG文件,对于只包含一个 stream 的文件,这个过程可以没有;
3、OGG页结构
0 1 2 30 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1| Byte
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| capture_pattern: Magic number for page start "OggS" | 0-3
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| version | header_type | granule_position | 4-7
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | 8-11
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | bitstream_serial_number | 12-15
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | page_sequence_number | 16-19
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | CRC_checksum | 20-23
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |page_segments | segment_table | 24-27
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ... | 28-
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1) 0~3字节:magic numbers,标识page开始;
2) version: 1字节;
3) page头类型:1字节:
位 0x01 : 1-该页包含前一页的连续的packet ;0- 该页和前后页无联系;
位 0x02 : 1- 该页为bos ; 0- 该页不是 bos;
位 0x04 : 1-该页为eos ; 0- 该页不是 eos ;
4) 位置信息: 8字节,对于音频
5) serial number: 4字节,唯一标识stream;
6) page sequence number: 4 字节,page序列号,为解码器提供页丢失标识,每个逻辑流中递增;
7) CRC校验和: 4字节;
8) number_page_segment : 1字节,segment table 中segment的个数;
9) segment table: 长度为 number_page_segment字节,每个字节对应一个segment的长度。
六、总结
总的来说,我了解了三种主流的音频文件格式,在以后的开发中打好了基础,但依然有一些不足,细节上不够深入,后续在接触后更新。libogg编解码ogg文件源码阅读进行中...
参考资料
1、 维基百科-WAV
2、 音频格式比较
3、 https://blog.csdn.net/ljxt523/article/details/52068241
4、 MP3:https://wenku.baidu.com/view/a071bf4e852458fb770b56a0.html
5、 OGG:https://blog.csdn.net/yu_yuan_1314/article/details/16884313
音频文件格式解析与编解码相关推荐
- wav音频文件格式解析
wav是微软开发的一种音频文件格式,注意,wav文件格式是无损音频文件格式,相对于其他音频格式文件数据是没有经过压缩的,通常文件也相对比较大些. 文件格式如图所示: 解析代码如下: #include ...
- 全面解析视频编解码:原理、策略、实现
远程桌面,本质就是将桌面进行连续截屏.编码压缩,经网络传输后,再解码还原成画面的过程.可见编解码技术在其中扮演了举足轻重的作用. 继上一篇介绍了远程桌面的五大核心指标后,本篇我们将揭秘高质量远程桌面的 ...
- FFmpeg之视频封装格式、流媒体协议、视频编解码协议和传输流格式、时间戳和时间基、视频像素数据
通用视频分析工具:Mediainfo.Elecard StreamEye(视频编码分析工具); 视频封装格式: ********************MP4****************** MP ...
- Android 音视频编解码 MediaCodec
MediaCodec 简介 Android中的MediaCodec是一个用于音视频编解码功能的API,使用它可以实现对音视频数据进行压缩.解压缩.编辑和转换.以下是MediaCodec的主要功能: 支 ...
- 【一起读论文系列1】基于压缩感知的语音编解码方向研究
[一起读论文系列1]基于压缩感知的语音编解码方向研究 2109,李俊鑫,基于压缩感知的快速语音编解码方法研究 1207,李尚靖,基于压缩感知的语音数字编码技术研究 引申资料 搜索关键词:compres ...
- Android视频编解码之MediaCodec简单入门
本篇只是简单入门,后面会继续写文章详细讲解: 由于MediaCodec涉及内容众多,原本想一篇文章把所有内容概括,但是后来发现不太可能,限于自己能力,想要考虑全面太难,我也是刚开始学习需要借助网上的代 ...
- FFMPEG视音频编解码零基础学习方法
总结]FFMPEG视音频编解码零基础学习方法 在CSDN上的这一段日子,接触到了很多同行业的人,尤其是使用FFMPEG进行视音频编解码的人,有的已经是有多年经验的"大神",有的是刚 ...
- 音视频开发(5)---FFMPEG视音频编解码零基础学习方法
FFMPEG视音频编解码零基础学习方法 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/leixiaohua1020/article/details/ ...
- [总结]FFMPEG视音频编解码零基础学习方法
在CSDN上的这一段日子,接触到了很多同行业的人,尤其是使用FFMPEG进行视音频编解码的人,有的已经是有多年经验的"大神",有的是刚开始学习的初学者.在和大家探讨的过程中,我忽然 ...
- 音频技术操作(重采样,增减益,混流,编解码及实际应用)
本人的个人网站已恢复,欢迎访问:www.jackchen.world或www.jackchen.work.之所以有时会出现访问不了的情况,主要是因为本人所用的设备是物理设备并非租用,放在自己老家,家里 ...
最新文章
- [jQuery]JQuery一个对象可以同时绑定多个事件,这是如何实现的?
- 宝塔asp php,宝塔Windows面板部署ASP、ASPX程序WEB网站环境方法
- SQL Server 开发指南(经典教程)
- 没有bug队——加贝——Python 45,46
- SpringBoot2 Redis连接池
- 腾讯X5webview集成
- IDEA连接GitHub
- MobileNet_V3—SSD网络模型图文详解
- html 毛笔书写效果,利用canvas实现毛笔字帖(三)
- python画图旋转图形_python简单实现旋转图片的方法
- Android虚拟机的理解和内存管理
- Pycharm 恢复到默认设置
- 【生成密钥免密登陆服务器】
- EXCEL 2016常用知识--Excel数据透视表
- Activiti7.0 EL NullPoint问题
- 使用UltraISO软碟通离线安装Centos8.3.2011过程中遇到的问题
- 深入浅出GUI线程安全(三)
- 【肌电信号】基于matlab GUI脉搏信号分析(去噪+特征提取)【含Matlab源码 862期】
- 微信商城html 模板,jquery-weui微信商城全套页面模板
- 2022-2027年中国品牌连锁酒店行业发展前景及投资战略咨询报告