PCM数据
首先准备一个PCM音频数据
提取PCM数据
ffmpeg -i out.mp4 -vn -ar 44100 -ac 2 -f s16le out.pcm
播放PCM
ffplay -ar 44100 -ac 2 -f s16le -i out.pcm
PCM转WAV
ffmpeg -f s16be -ar 8000 -ac 2 -acodec pcm_s16be -i input.raw output.wav
CMakeLists.txt中引入OpenSLES
#将avcodec混合编译到native-lib中
target_link_libraries(
native-lib
OpenSLES
${log-lib}
avcodec#1
avdevice#2
avfilter#3
avformat#4
avutil#5
postproc#6
swresample#7
swscale#8
)
MainActivity.java
package com.zhangyu.androidopensl;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
private PermisionUtil permisionUtil = new PermisionUtil(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
permisionUtil.requestAllPermission();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
permisionUtil.onRequestPermissionsResult(requestCode,permissions,grantResults);
}
public native void playPCM(String url);
public void onClick(View view) {
String uri = Environment.getExternalStorageDirectory()+"/1/out.pcm";
playPCM(uri);
}
}
native-lib.cpp
#include <jni.h>
#include <string>
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#include <android/log.h>
#define LOGD(FORMAT, ...) __android_log_print(ANDROID_LOG_DEBUG,"zhangyu123",FORMAT,##__VA_ARGS__);
#define LOGE(FORMAT, ...) __android_log_print(ANDROID_LOG_ERROR,"zhangyu123",FORMAT,##__VA_ARGS__);
// 引擎接口
SLObjectItf engineObject = NULL;
SLEngineItf engineEngine = NULL;
//混音器
SLObjectItf outputMixObject = NULL;
SLEnvironmentalReverbItf outputEnvironmentalReverbItf = NULL;
SLEnvironmentalReverbSettings reverbSettings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;
//pcm
SLObjectItf pcmPlayerObject = NULL;
SLPlayItf pcmPlayerPlay = NULL;
SLVolumeItf pcmPlayerVolume = NULL;
//缓冲器队列接口
SLAndroidSimpleBufferQueueItf pcmBufferQueue;
FILE *pcmFile;
void *buffer;
uint8_t *out_buffer;
int getPcmData(void **pcm) {
int size = 0;
while (!feof(pcmFile)) {
size = fread(out_buffer, 1, 44100 * 2 * 2, pcmFile);
if (out_buffer == NULL) {
LOGD("%s", "read end");
break;
} else {
LOGD("%s", "reading");
}
*pcm = out_buffer;
break;
}
return size;
}
void pcmBufferCallBack(SLAndroidSimpleBufferQueueItf bf, void *context) {
//assert(NULL == context);
int size = getPcmData(&buffer);
// for streaming playback, replace this test by logic to find and fill the next buffer
if (NULL != buffer) {
SLresult result;
// enqueue another buffer
result = (*pcmBufferQueue)->Enqueue(pcmBufferQueue, buffer, size);
// the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
// which for this code example would indicate a programming error
}
}
extern "C"
JNIEXPORT void JNICALL
Java_com_zhangyu_androidopensl_MainActivity_playPCM(JNIEnv *env, jobject thiz, jstring url_) {
const char *url = env->GetStringUTFChars(url_, 0);
// TODO
//读取pcm文件
pcmFile = fopen(url, "r");
if (pcmFile == NULL) {
LOGE("%s", "fopen file error");
return;
}
//分配一个内存空间,44100 采样率,16位存储=2字节,2个声道数
out_buffer = (uint8_t *) malloc(44100 * 2 * 2);
//第一步,创建引擎对象------------------------------------------
//1.创建
slCreateEngine(&engineObject, 0, 0, 0, 0, 0);
//2.实现
(*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
//3.得到具体的接口
(*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
//第二步,创建混音器-------------------------------------------
const SLInterfaceID slitfids[1] = {SL_IID_ENVIRONMENTALREVERB};
const SLboolean slitfreqs[1] = {SL_BOOLEAN_FALSE};
//创建混音器
(*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, slitfids, slitfreqs);
//实现混音器
(*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
//得到具体的接口
(*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,
&outputEnvironmentalReverbItf);
//设置环境属性
(*outputEnvironmentalReverbItf)->SetEnvironmentalReverbProperties(outputEnvironmentalReverbItf,
&reverbSettings);
SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
// 第三步--------------------------------------------
// 创建播放器
SLDataLocator_AndroidSimpleBufferQueue android_queue = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
2};
//pcm格式信息
SLDataFormat_PCM pcm = {
SL_DATAFORMAT_PCM,//播放pcm格式的数据
2,//2个声道(立体声)
SL_SAMPLINGRATE_44_1,//44100hz的频率
SL_PCMSAMPLEFORMAT_FIXED_16,//位数 16位
SL_PCMSAMPLEFORMAT_FIXED_16,//和位数一致就行
SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,//立体声(前左前右)
SL_BYTEORDER_LITTLEENDIAN//结束标志
};
//数据源,队列,pcm
SLDataSource slDataSource = {&android_queue, &pcm};
SLDataSink audioSnk = {&outputMix, NULL};
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};
(*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject, &slDataSource, &audioSnk, 3,
ids, req);
(*pcmPlayerObject)->Realize(pcmPlayerObject, SL_BOOLEAN_FALSE);
(*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_PLAY, &pcmPlayerPlay);
//第四步,创建缓冲区和回调函数---------------------------------------
(*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_BUFFERQUEUE, &pcmBufferQueue);
//缓冲接口回调
(*pcmBufferQueue)->RegisterCallback(pcmBufferQueue, pcmBufferCallBack, NULL);
//获取音量接口
(*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_VOLUME, &pcmPlayerVolume);
//第五步,设置播放状态----------------------------------------
(*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_PLAYING);
//第六步,主动调用回调函数开始工作----------------------------------------
pcmBufferCallBack(pcmBufferQueue, NULL);
//释放
env->ReleaseStringUTFChars(url_, url);
}