本文字数:1872字
预计阅读时间:8分钟
常用的播放文件,如 mp3、aac 都是已经封装的音频格式,将它们的文件提供到系统音频库或者第三方音频库,如 AVPlayer、IJKPlayer 等这些框架和播放器,然后声音就会由扬声器或耳机播放出来。如果读者对这些神奇的过程有兴趣,那就进入本次的了解旅程。
《iOS 视音频入门系列》
之前的都是针对图像,而本次来聊聊音频。
前言
本次将基于 iOS 实现对aac(ADTS)文件的播放来讲解音频的播放流程。它将包括如下内容,可能大伙对这些名称有所耳闻:解封装、解编码等。流媒体的播放其实就是基于这些步骤来实现的。
_______ ______________ ________
| | | | | |
| aac | demuxer | audio | decoder | audio |
| file | ---------> | encoded data | ---------> | raw |
|_______| |______________| |________|
AAC
aac 的应用很广泛,在直播 rtmp 和 http-flv 中也使用的此音频格式。
❝AAC,全称Advanced Audio Coding,是一种专为声音数据设计的文件压缩格式。与MP3不同,它采用了全新的算法进行编码,更加高效,具有更高的“性价比”。利用AAC格式,可使人感觉声音质量没有明显降低的前提下,更加小巧。
Demo 使用的 aac 音频信息如下:
Input #0, aac, from 'video.aac':
Duration: 00:00:30.45, bitrate: 133 kb/s
Stream #0:0: Audio: aac (LC), 44100 Hz, stereo, fltp, 133 kb/s
解封装
解封装的最重要的目的是将 音频 的 音频的信息 & 音频的编码数据 分离出来。
而 aac 是由多个 header + es body 组成。header 固定 7 个字节,所以只需每次读取 7 个字节,然后再读出 size,就能得到得到对应块的数据,从而得到 raw 数据。
// 读取 header
int head_buf_size = 7;
int *head_buf = malloc(head_buf_size);
fread(head_buf, 1, head_buf_size, _in_file);
// 读取 size
int s1 = ((int)(*(((uint8_t *)head_buf) + 3))&0x3) << 11;
int s2 = ((int)(*(((uint8_t *)head_buf) + 4))) << 3;
int s3 = (int)(*(((uint8_t *)head_buf) + 5)) >> 5;
int size = s1 + s2 + s3;
// 读取 raw
int raw_buf_size = size - head_buf_size;
int *raw_buf = malloc(raw_buf_size);
fread(raw_buf, 1, raw_buf_size, _in_file);