[Cmake-Android]音视频总结:
-
[Cmake-Android音视频]SDK,NDK基本介绍
-
[Cmake-Android音视频]NDK-r14b编译ffmpeg3.4支持neon,硬解码
-
[Cmake-Android音视频]创建支持ffmpeg3.4的项目
-
[Cmake-Android音视频]ffmpeg3.4实现解封装
-
[Cmake-Android音视频]ffmpeg3.4软硬解码和多线程解码
-
[Cmake-Android音视频]ffmpeg3.4视频格式转换和显示
-
[Cmake-Android音视频]ffmpeg3.4音频重采样
-
[Cmake-Android音视频]OpenSLES音频播放
OpenSL ES 介绍
OpenSL ES 是一个针对嵌入式系统的开放硬件音频加速库,也可以将其视为一套针对嵌入式平台的音频标准,全称为: Open Sound Library for Embedded Systems ,它提供了一套高性能、 低延迟的音频功能实现方法,并且实现了软硬件音频性能的跨平台部署,大大降低了上层处理音频应用的开发难度。
在 Android 开发中,Google 官方从 Android 2.3 (API 9)开始,便支持了 OpenSL ES 标准 ,并且对其进行了扩展。本文介绍的 OpenSL ES 是针对 Android NDK 开发。
OpenSL ES 播放声音流程
代码实现:
在cmake文件中引入opensl es的库
target_link_libraries( # Specifies the target library.
native-lib
OpenSLES
# Links the target library to the log library
# included in the NDK.
${log-lib})
#include <jni.h>
#include <string>
#include <android/log.h>
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#define LOGTAG "native-lib"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOGTAG, __VA_ARGS__)
static SLObjectItf engineSL= NULL;
SLEngineItf CreateSL()
{
SLresult re;
SLEngineItf en;
re = slCreateEngine(&engineSL, 0, 0, 0, 0, 0);
if (re != SL_RESULT_SUCCESS) return NULL;
re = (*engineSL)->Realize(engineSL, SL_BOOLEAN_FALSE);
if (re != SL_RESULT_SUCCESS) return NULL;
re = (*engineSL)->GetInterface(engineSL, SL_IID_ENGINE, &en);
if (re != SL_RESULT_SUCCESS) return NULL;
return en;
}
//回调
void pcmCall(SLAndroidSimpleBufferQueueItf bf, void *content)
{
LOGI(" pcmCall");
static FILE *fp = NULL;
static char *buf = NULL;
if (!buf)
{
buf = new char[1024*1024];
}
if (!fp)
{
fp = fopen("/sdcard/output.pcm", "rb");
}
if (!fp) return;;
if (feof(fp) == 0)
{
int len = fread(buf, 1, 1024, fp);
if (len > 0)
{
(*bf)->Enqueue(bf, buf, len);
}
}
}
extern "C" JNIEXPORT jstring JNICALL
Java_lucas_testopensl_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
//1创建引擎
SLEngineItf eng = CreateSL();
if (eng)
{
LOGI("CreateSL success") ;
} else{
LOGI("CreateSL success");
}
//2.创建混音器
SLObjectItf mix = NULL;
SLresult re = 0;
re = (*eng)->CreateOutputMix(eng, &mix, 0, 0, 0);
if (re != SL_RESULT_SUCCESS)
{
LOGI("CreateOutputMix failed");
}
re = (*mix)->Realize(mix, SL_BOOLEAN_FALSE);
if (re != SL_RESULT_SUCCESS)
{
LOGI("mix Realize failed");
}
SLDataLocator_OutputMix out_mix = {SL_DATALOCATOR_OUTPUTMIX, mix};
SLDataSink audioSink = {&out_mix, 0};
//3配置音频信息
//缓冲队列
SLDataLocator_AndroidSimpleBufferQueue que = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 10};
//音频格式
SLDataFormat_PCM pcm = {
SL_DATAFORMAT_PCM,
2, //声道数
SL_SAMPLINGRATE_44_1,
SL_PCMSAMPLEFORMAT_FIXED_16,
SL_PCMSAMPLEFORMAT_FIXED_16,
SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT,
SL_BYTEORDER_LITTLEENDIAN //字节序 小端
};
SLDataSource dataSource = {&que, &pcm};
//4创建播放器
SLObjectItf player = NULL;
SLPlayItf iplayer = NULL;
SLAndroidSimpleBufferQueueItf pcmQue = NULL;
const SLInterfaceID ids[] = {SL_IID_BUFFERQUEUE};
const SLboolean req[] = {SL_BOOLEAN_TRUE};
re = (*eng)->CreateAudioPlayer(eng, &player, &dataSource, &audioSink, sizeof(ids)/sizeof(SLInterfaceID), ids, req);
if (re != SL_RESULT_SUCCESS)
{
LOGI("CreateAudioPlayer failed");
} else{
LOGI("CreateAudioPlayer success");
}
(*player)->Realize(player, SL_BOOLEAN_FALSE);
//获取player接口
re = (*player)->GetInterface(player, SL_IID_PLAY, &iplayer);
if (re != SL_RESULT_SUCCESS)
{
LOGI("GetInterface SL_IID_PLAY failed");
}else{
LOGI("GetInterface SL_IID_PLAY success");
}
//获取buffer队列接口
re = (*player)->GetInterface(player, SL_IID_BUFFERQUEUE, &pcmQue);
if (re != SL_RESULT_SUCCESS)
{
LOGI("GetInterface SL_IID_BUFFERQUEUE failed");
}else{
LOGI("GetInterface SL_IID_BUFFERQUEUE success");
}
//设置回调函数 在播放队列为空的时候调用 第一次必须先放点数据进去
(*pcmQue)->RegisterCallback(pcmQue, pcmCall, 0);
//设置为播放状态
(*iplayer)->SetPlayState(iplayer, SL_PLAYSTATE_PLAYING);
//启动队列回调
(*pcmQue)->Enqueue(pcmQue, "", 1);
return env->NewStringUTF(hello.c_str());
}