Android FFmpeg + OpenSL ES 音频解码播放
2023-10-15 02:24:13
Android 音视频开发打怪升级:FFmpeg 音视频编解码篇
四、Android FFmpeg + OpenSL ES 音频解码播放
前言
在上一篇文章中,我们详细介绍了 FFmepg 的播放流程,以及抽象了解码流程框架,整合视频和音频解码流程的共同点,形成了 BaseDecoder 类。通过继承 BaseDecoder 实现了视频解码子类 VideoDeocder,并整合到了 Player 中,实现了视频的播放渲染。
本篇将介绍音频的解码流程,并基于 FFmpeg 与 OpenSL ES 实现音频的播放。
音频解码流程
音频解码流程与视频解码流程基本相似,总体流程如下:
- 打开音频解码器,获取解码器相关信息
- 分配并初始化解码器上下文
- 分配音频重采样上下文
- 读取音视频数据包,并进行解码
- 将解码后的数据进行重采样(若有必要)
- 将重采样后的音频数据发送到音频播放器
FFmpeg 解码音频
FFmpeg 提供了丰富的解码器库,我们可以使用 avcodec_find_decoder()
函数查找支持的音频解码器。在获取解码器后,使用 avcodec_open2()
函数打开解码器,并获取解码器上下文信息。
AVCodec *codec = avcodec_find_decoder(codec_id);
if (!codec) {
LOGE("Unsupported audio codec: %d", codec_id);
return -1;
}
int ret = avcodec_open2(codec_ctx, codec, NULL);
if (ret < 0) {
LOGE("Open audio codec failed: %s", av_err2str(ret));
return ret;
}
OpenSL ES 播放音频
OpenSL ES 是 Android 平台提供的音频处理 API,它提供了丰富的音频播放功能。在使用 OpenSL ES 播放音频前,需要先初始化 OpenSL ES 引擎。
SLresult result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
if (result != SL_RESULT_SUCCESS) {
LOGE("Create OpenSL ES engine failed: %d", result);
return -1;
}
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS) {
LOGE("Realize OpenSL ES engine failed: %d", result);
return -1;
}
播放音频
在初始化好 OpenSL ES 引擎后,就可以创建音频播放器并播放音频数据了。这里使用 OpenSL ES 创建一个播放器对象,并设置播放器参数。
SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
SLDataSink audioSink = {&outputMix, NULL};
SLDataSource audioSrc = {SL_DATAFORMAT_PCM, numChannels, sampleRate, SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, NULL};
SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND, SL_IID_VOLUME};
SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
result = (*playerObject)->CreateAudioPlayer(playerObject, &playerPlay, &audioSrc, &audioSink, 3, ids, req);
if (result != SL_RESULT_SUCCESS) {
LOGE("Create audio player failed: %d", result);
return -1;
}
重采样音频
在某些情况下,解码后的音频数据格式与播放器支持的格式不一致,需要进行重采样。FFmpeg 提供了重采样 API,我们可以使用 swr_alloc_set_opts()
函数创建重采样上下文,并使用 swr_convert()
函数进行重采样。
SwrContext *swrCtx = swr_alloc_set_opts(NULL, output_channel_layout, output_sample_fmt, output_sample_rate,
input_channel_layout, input_sample_fmt, input_sample_rate, 0, NULL);
if (!swrCtx) {
LOGE("Create resample context failed");
return -1;
}
int ret = swr_init(swrCtx);
if (ret < 0) {
LOGE("Init resample context failed: %s", av_err2str(ret));
return ret;
}
音频播放流程
整合音频解码、重采样和 OpenSL ES 播放,形成音频播放流程:
- 打开音频解码器,并获取解码器上下文信息
- 初始化 OpenSL ES 引擎和播放器
- 读取音视频数据包,并进行解码
- 将解码后的数据进行重采样(若有必要)
- 将重采样后的音频数据发送到 OpenSL ES 播放器
总结
本篇介绍了 Android 平台上使用 FFmpeg 和 OpenSL ES 进行音频解码和播放的流程。通过整合解码、重采样和播放,实现了音频数据的播放渲染。在下一篇文章中,我们将介绍视频渲染技术。