Lame开源库
Lame是一款优秀的mp3开源跨平台编码库,可以将音频裸PCM数据编码成mp3。
先去官方下载Lame源代码: Lame下载地址
然后编译静态库,这里呢不再累述,可以自己写编译脚本,也可以去Github上下载编译脚本。脚本下载链接: lame-build-script
这里呢我已经编译好了Lame静态库,包含了x86,arm64架构,需要的童鞋可以直接下载,Lame版本是最新的V3.100。网盘下载地址: iOSLame静态库
PCM
PCM(Pulse Code Modulation):脉码编码调制。是没有压缩的音频数据,也可以叫音频裸数据。我们经常可以看到音频参数中有44100HZ 16bit,或者是22050HZ 8bit。
这里呢其实是两个参数
采样率:自然界的音频即声波转换为数字数据保存,即模-》数,单位时间采样个数即采样率。很明显,采样率越高,精确度越大。人对频率的识别范围是 20HZ - 20000HZ。所以22050的采样频率是常用的音频采样率,而44100采样率即是CD级别。
16bit pcm意味着使用两个字节去保存采样值。
采样数据记录的是振幅, 采样精度取决于储存空间的大小:
1 字节(也就是8bit) 256, 也就是只能将振幅划分成 256 个等级;
2 字节(也就是16bit) 65536个等级 , CD级别,16bit pcm就是最常见的。
4 字节(也就是32bit) 能把振幅细分到 4294967296 个等级, 一般不常用。
双声道
裸数据的音频存在双声道,即左右耳,我们看下PCM双声道的存储结构。
我们可与看到16bit的PCM和8Bit的PCM双声道都是左右声道交替存储的,所不同的是,16位是每两个字节存储一个声道数据,而8位是一个字节,然后再交替存储。
这里了解下PCM存储结构是为了后面我们从文件流取出对应声道数据。
本地PCM文件转码为Mp3文件
本地PCM文件,我在上面的网盘保存了一份,需要的可以下载,也可以自己通过FFMpeg指令生成PCM裸数据,以MP3转PCM为例
ffmpeg -i test.mp3 -f s16le -ar 8000 test.pcm
实际项目中音视频相关的底层接口通常是跨平台设计的,为了兼容iOS/Android/Windows/Linux等,通常底层接口使用C++编写封装。
这里我们写一个简单的C++类 Mp3Encoder
使用Objective-C也是同样的接口调用,在Demo中也存放了一个OC封装类,需要的可以下载查看。
1 | class Mp3Encoder { |
初始化Mp3Encoder类
1 | int Mp3Encoder::Init(const char *pcmFilePath, const char *mp3FilePath, int sampleRate, int channels, int bitRate){ |
转码Mp3
1 | void Mp3Encoder::EncodeLocalFile(){ |
转码Mp3这里有几点注意事项
- PCM数据头有四个字节的头信息,这里我们跳过,避免编码产生头噪音
- 我们设置了一个Buffer 为256 *1024大小,从文件流每次读取一定数量buffer转码MP3写入,直到全部读取完文件流
- 需要特别注意的是下面我们从文件流每次读取两个字节的数据,依次存入buffer,这里由于demo处理的是16位PCM数据,所以左右声道各占两个字节,如果是8bit或者32bit则需要分别读取1个字节和4个字节数据。这样才能分离出左右声道数据
readBufferSize = fread(buffer, 2, bufferSize/2, pcmFile)
- 编码Mp3区分左右声道
lame_encode_buffer(lameClient, (short int *)leftBuffer, (short int *)rightBuffer, (int)(readBufferSize / 2), mp3_buffer, bufferSize)
- 编码完成之后,写入Mp3的VBR tag,如果不写入的话,可能会导致某些播放器播放时获取时长出现问题,所以建议写入。(VBR Tag这里不再介绍,需要了解的可以自行查阅Mp3封装格式哈)
//写入Mp3 VBR Tag,不是必须的步骤 lame_mp3_tags_fid(lameClient, mp3File);
最后外部调用编码接口
1 | //异步转换本地PCM文件 |
至此我们就实现了简单的PCM文件本地编码成Mp3文件
实时录音编码Mp3实现
其实实时录音实现流程如下
其实和本地编码保存不同的是,我们需要循环读取源文件的PCM数据,直到录音结束,停止循环,保存最终mp3,核心代码如下
1 | class Mp3Encoder { |
这里使用AVAudioRecord录制音频
录音核心参数如下
1 | /** |
源代码
项目源代码github地址:iOS-Record-Transcoding-mp3-lameDemo