前言
本文重点关注如何对一帧音频数据进行编码和解码。
Android 官方的 MediaCodec API
首先,我们了解一下 Android 官方提供的音频编解码的 API,即 MediaCodec 类,该 API 是在 Andorid 4.1 (API 16) 版本引入的,因此只能工作于 Android 4.1 以上的手机上。
1. MediaCodec 基本介绍
- 提供了一套访问 Android 底层多媒体模块的接口,主要是音视频的编解码接口;
- Android 底层多媒体模块采用的是 OpenMax 框架,任何 Android 底层编解码模块的实现,都必须遵循 OpenMax 标准。Google 官方默认提供了一系列的软件编×××:包括:OMX.google.h264.encoder,OMX.google.h264.encoder, OMX.google.aac.encoder, OMX.google.aac.decoder 等等,而硬件编解码功能,则需要由芯片厂商依照 OpenMax 框架标准来完成,所以,一般采用不同芯片型号的手机,硬件编解码的实现和性能是不同的;
- Android 应用层统一由 MediaCodec API 来提供各种音视频编解码功能,由参数配置来决定采用何种编解码算法、是否采用硬件编解码加速等
2. MediaCodec 核心原理
MediaCodec 使用的基本流程是:
- createEncoderByType/createDecoderByType
- configure
- start
- while(1) {
- dequeueInputBuffer
- queueInputBuffer
- dequeueOutputBuffer
- releaseOutputBuffer
}
- stop
- release
由此可以看到,Buffer 队列的操作是其最核心的部分之一,关于 MediaCodec 的 Buffer 队列 ,示意图如下:
MediaCodec 架构上采用了2个缓冲区队列,异步处理数据,下面描述的 Client 和 MediaCodec 模块是并行工作的(注:这里的 Client 就是指 “开发者,API 的使用者”):
(1)Client 从 input 缓冲区队列申请 empty buffer [dequeueInputBuffer]
(2)Client 把需要编解码的数据拷贝到 empty buffer,然后放入 input 缓冲区队列 [queueInputBuffer]
(3)MediaCodec 模块从 input 缓冲区队列取一帧数据进行编解码处理
(4)编解码处理结束后,MediaCodec 将原始数据 buffer 置为 empty 后放回 input 缓冲区队列,将编解码后的数据放入到 output 缓冲区队列
(5)Client 从 output 缓冲区队列申请编解码后的 buffer [dequeueOutputBuffer]
(6)Client 对编解码后的 buffer 进行渲染/播放
(7)渲染/播放完成后,Client 再将该 buffer 放回 output 缓冲区队列 [releaseOutputBuffer]
MediaCodec 在架构上,其实是采用了一种基于“环形缓冲区”的“生产者-消费者”模式,它设计了 2 个基于 idx 序号的“环形缓冲区” ,注意,是 2 个,一个在 input 端, 一个在 output 端。
基于 idx 的环形缓冲区的总体示意图如下,图中,wp 代表 “写指针”,指向的是 “empty buffer”, 而 rp 代表 “读指针”,指向的是 “filled buffer”:
“生产者”和“消费者”其实是共用这一个缓冲区队列,“生产者”负责从队列中取出未使用的 Buffer,填入数据,然后放回队列,“消费者”则负责取出填入数据后的 Buffer,进行处理,处理结束后,再把 Buffer 标记为“空”,退回到队列中去以供“生产者”继续填充数据。
在 input 端,“Client”是这个环形缓冲区“生产者”,“MediaoCodec 模块”是“消费者”。
在 output 端,“MediaoCodec 模块”是这个环形缓冲区“生产者”,而“Client”则变成了“消费者”。
第三方音频编解码库
-
opus 编解码库
官网地址: https://www.opus-codec.org -
Speex 编解码库
官网地址: http://www.speex.org -
ffmpeg
官网地址: https://www.ffmpeg.org -
Android AAC Encoder
官网地址: https://github.com/timsu/android-aac-enc -
opencore-amr-android
Git 地址: https://github.com/kevinho/opencore-amr-android -
iLBC-Android
Git 地址: https://github.com/lukeweber/iLBC-Android