返回

Android FFmpeg + OpenSL ES 音频解码播放

Android

Android 音视频开发打怪升级:FFmpeg 音视频编解码篇

四、Android FFmpeg + OpenSL ES 音频解码播放

前言

在上一篇文章中,我们详细介绍了 FFmepg 的播放流程,以及抽象了解码流程框架,整合视频和音频解码流程的共同点,形成了 BaseDecoder 类。通过继承 BaseDecoder 实现了视频解码子类 VideoDeocder,并整合到了 Player 中,实现了视频的播放渲染。

本篇将介绍音频的解码流程,并基于 FFmpeg 与 OpenSL ES 实现音频的播放。

音频解码流程

音频解码流程与视频解码流程基本相似,总体流程如下:

  1. 打开音频解码器,获取解码器相关信息
  2. 分配并初始化解码器上下文
  3. 分配音频重采样上下文
  4. 读取音视频数据包,并进行解码
  5. 将解码后的数据进行重采样(若有必要)
  6. 将重采样后的音频数据发送到音频播放器

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 播放,形成音频播放流程:

  1. 打开音频解码器,并获取解码器上下文信息
  2. 初始化 OpenSL ES 引擎和播放器
  3. 读取音视频数据包,并进行解码
  4. 将解码后的数据进行重采样(若有必要)
  5. 将重采样后的音频数据发送到 OpenSL ES 播放器

总结

本篇介绍了 Android 平台上使用 FFmpeg 和 OpenSL ES 进行音频解码和播放的流程。通过整合解码、重采样和播放,实现了音频数据的播放渲染。在下一篇文章中,我们将介绍视频渲染技术。

附录