You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
FFmpegAndroid/app/src/main/cpp/openSL_audio_player.cpp

283 lines
9.6 KiB

//
// Created by frank on 2018/2/1.
//
#include <jni.h>
#include <string.h>
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavutil/samplefmt.h"
#include "libavutil/opt.h"
#include "ffmpeg_jni_define.h"
#ifdef __cplusplus
}
#endif
#define TAG "OpenSLPlayer"
//object of engine
SLObjectItf engineObject = nullptr;
SLEngineItf engineEngine;
//object of mixer
SLObjectItf outputMixObject = nullptr;
SLEnvironmentalReverbItf outputMixEnvironmentalReverb = nullptr;
//object of buffer
SLObjectItf bqPlayerObject = nullptr;
SLPlayItf bqPlayerPlay;
SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
SLEffectSendItf bqPlayerEffectSend;
SLVolumeItf bqPlayerVolume;
//audio effect
const SLEnvironmentalReverbSettings reverbSettings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;
void *openBuffer;
size_t bufferSize;
uint8_t *outputBuffer;
size_t outputBufferSize;
AVPacket packet;
int audioStream;
AVFrame *aFrame;
SwrContext *swr;
AVFormatContext *aFormatCtx;
AVCodecContext *aCodecCtx;
int frame_count = 0;
int createAudioPlayer(int *rate, int *channel, const char *file_name);
int releaseAudioPlayer();
int getPCM(void **pcm, size_t *pcmSize);
//callback by player
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bufferQueueItf, void *context) {
bufferSize = 0;
getPCM(&openBuffer, &bufferSize);
if (nullptr != openBuffer && 0 != bufferSize) {
SLresult result;
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, openBuffer, bufferSize);
if (result < 0) {
LOGE(TAG, "Enqueue error...");
} else {
LOGI(TAG, "decode frame count=%d", frame_count++);
}
}
}
//create the engine of OpenSLES
void createEngine() {
SLresult result;
result = slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr);
LOGI(TAG, "slCreateEngine=%d", result);
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
LOGI(TAG, "engineObject->Realize=%d", result);
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
LOGI(TAG, "engineObject->GetInterface=%d", result);
result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, 0, 0);
LOGI(TAG, "CreateOutputMix=%d", result);
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
LOGI(TAG, "outputMixObject->Realize=%d", result);
result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,
&outputMixEnvironmentalReverb);
LOGI(TAG, "outputMixObject->GetInterface=%d", result);
if (SL_RESULT_SUCCESS == result) {
result = (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(
outputMixEnvironmentalReverb, &reverbSettings);
}
LOGI(TAG, "SetEnvironmentalReverbProperties=%d", result);
}
void createBufferQueueAudioPlayer(int rate, int channel, int bitsPerSample) {
SLresult result;
//config audio source
SLDataLocator_AndroidSimpleBufferQueue buffer_queue = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
2};
SLDataFormat_PCM format_pcm;
format_pcm.formatType = SL_DATAFORMAT_PCM;
format_pcm.numChannels = (SLuint32) channel;
format_pcm.bitsPerSample = (SLuint32) bitsPerSample;
format_pcm.samplesPerSec = (SLuint32) (rate * 1000);
format_pcm.containerSize = 16;
if (channel == 2)
format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
else
format_pcm.channelMask = SL_SPEAKER_FRONT_CENTER;
format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
SLDataSource audioSrc = {&buffer_queue, &format_pcm};
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
SLDataSink audioSnk = {&loc_outmix, nullptr};
const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND, SL_IID_VOLUME};
const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,
3, ids, req);
LOGI(TAG, "CreateAudioPlayer=%d", result);
result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
LOGI(TAG, "bqPlayerObject Realize=%d", result);
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
LOGI(TAG, "GetInterface bqPlayerPlay=%d", result);
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
&bqPlayerBufferQueue);
LOGI(TAG, "GetInterface bqPlayerBufferQueue=%d", result);
result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, nullptr);
LOGI(TAG, "RegisterCallback=%d", result);
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_EFFECTSEND,
&bqPlayerEffectSend);
LOGI(TAG, "GetInterface effect=%d", result);
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
LOGI(TAG, "GetInterface volume=%d", result);
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
LOGI(TAG, "SetPlayState=%d", result);
}
int createAudioPlayer(int *rate, int *channel, const char *file_name) {
av_register_all();
aFormatCtx = avformat_alloc_context();
if (avformat_open_input(&aFormatCtx, file_name, nullptr, nullptr) != 0) {
LOGE(TAG, "Couldn't open file:%s\n", file_name);
return -1;
}
if (avformat_find_stream_info(aFormatCtx, nullptr) < 0) {
LOGE(TAG, "Couldn't find stream information.");
return -1;
}
int i;
audioStream = -1;
for (i = 0; i < aFormatCtx->nb_streams; i++) {
if (aFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
audioStream < 0) {
audioStream = i;
}
}
if (audioStream == -1) {
LOGE(TAG, "Couldn't find audio stream!");
return -1;
}
aCodecCtx = aFormatCtx->streams[audioStream]->codec;
AVCodec *aCodec = avcodec_find_decoder(aCodecCtx->codec_id);
if (!aCodec) {
fprintf(stderr, "Unsupported codec!\n");
return -1;
}
if (avcodec_open2(aCodecCtx, aCodec, nullptr) < 0) {
LOGE(TAG, "Could not open codec.");
return -1;
}
aFrame = av_frame_alloc();
swr = swr_alloc();
av_opt_set_int(swr, "in_channel_layout", aCodecCtx->channel_layout, 0);
av_opt_set_int(swr, "out_channel_layout", aCodecCtx->channel_layout, 0);
av_opt_set_int(swr, "in_sample_rate", aCodecCtx->sample_rate, 0);
av_opt_set_int(swr, "out_sample_rate", aCodecCtx->sample_rate, 0);
av_opt_set_sample_fmt(swr, "in_sample_fmt", aCodecCtx->sample_fmt, 0);
av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
swr_init(swr);
outputBufferSize = 8196;
outputBuffer = (uint8_t *) malloc(sizeof(uint8_t) * outputBufferSize);
*rate = aCodecCtx->sample_rate;
*channel = aCodecCtx->channels;
return 0;
}
int getPCM(void **pcm, size_t *pcmSize) {
while (av_read_frame(aFormatCtx, &packet) >= 0) {
int frameFinished = 0;
//is audio stream
if (packet.stream_index == audioStream) {
avcodec_decode_audio4(aCodecCtx, aFrame, &frameFinished, &packet);
//decode success
if (frameFinished) {
int data_size = av_samples_get_buffer_size(
aFrame->linesize, aCodecCtx->channels,
aFrame->nb_samples, aCodecCtx->sample_fmt, 1);
if (data_size > outputBufferSize) {
outputBufferSize = (size_t) data_size;
outputBuffer = (uint8_t *) realloc(outputBuffer,
sizeof(uint8_t) * outputBufferSize);
}
swr_convert(swr, &outputBuffer, aFrame->nb_samples,
(uint8_t const **) (aFrame->extended_data),
aFrame->nb_samples);
*pcm = outputBuffer;
*pcmSize = (size_t) data_size;
return 0;
}
}
}
return -1;
}
int releaseAudioPlayer() {
av_packet_unref(&packet);
av_free(outputBuffer);
av_free(aFrame);
avcodec_free_context(&aCodecCtx);
avformat_close_input(&aFormatCtx);
return 0;
}
AUDIO_PLAYER_FUNC(void, playAudio, jstring filePath) {
int rate, channel;
const char *file_name = env->GetStringUTFChars(filePath, nullptr);
LOGI(TAG, "file_name=%s", file_name);
createAudioPlayer(&rate, &channel, file_name);
createEngine();
createBufferQueueAudioPlayer(rate, channel, SL_PCMSAMPLEFORMAT_FIXED_16);
bqPlayerCallback(bqPlayerBufferQueue, nullptr);
}
AUDIO_PLAYER_FUNC(void, stop) {
if (bqPlayerObject != nullptr) {
(*bqPlayerObject)->Destroy(bqPlayerObject);
bqPlayerObject = nullptr;
bqPlayerPlay = nullptr;
bqPlayerBufferQueue = nullptr;
bqPlayerEffectSend = nullptr;
bqPlayerVolume = nullptr;
}
if (outputMixObject != nullptr) {
(*outputMixObject)->Destroy(outputMixObject);
outputMixObject = nullptr;
outputMixEnvironmentalReverb = nullptr;
}
if (engineObject != nullptr) {
(*engineObject)->Destroy(engineObject);
engineObject = nullptr;
engineEngine = nullptr;
}
releaseAudioPlayer();
}