1. 程式人生 > >FFmpeg(七)音訊的播放

FFmpeg(七)音訊的播放

一、Open SL ES播放聲音流程

  簡單說明

  Open SL ES是android內部的介面,本身可以解碼音訊,但是我們用FFmpeg,,也可以來錄音 。

  SL引擎:上下文

  混音器:兩路聲音的混合

  Play:控制播放 ,  有一個佇列來儲存播放的資料,設定一個回撥的方法,播放之後調一下回調方法拿資料,

二、函式說明

  1.初始化引擎
    SLresult re; //存放引擎本身,上下文
    SLEngineItf en; //存放引擎的介面
    slCreateEngine(&engineSL,0,0,0,0,0);//建立物件
    Realize(engineSL,SL_BOOLEAN_FALSE);//例項化(內部的資料分配記憶體) 都是這個模式,先建立,然後例項化,在獲取介面
    GetInterface(engineSL,SL_IID_ENGINE,&en);//獲取介面SLEngineItf ,通過第二個引數獲取對應的介面
  2.輸出裝置
    SLObjectItf mix = NULL;
    SLresult re = 0;
    CreateOutputMix(eng,&mix,0,0,0);//建立輸出裝置
    Realize(mix,SL_BOOLEAN_FALSE);//例項化
    //下面兩個是儲存
    SLDataLocator_OutputMix outmix = {SL_DATALOCATOR_OUTPUTMIX,mix};
    SLDataSink audioSink= {&outmix,0};
  3.配置音訊資訊
    SLDataLocator_AndroidSimpleBufferQueue que = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,10}; //以什麼樣的方式互動
    //音訊格式
    SLDataFormat_PCM pcm = {
        SL_DATAFORMAT_PCM,//支援PCM格式的資料
        2,// 聲道數
        SL_SAMPLINGRATE_44_1,//44100Hz的頻率(取樣率)
        SL_PCMSAMPLEFORMAT_FIXED_16, //位數
        SL_PCMSAMPLEFORMAT_FIXED_16,//和位數一支即可
        SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT,//立體聲(前作前右)
        SL_BYTEORDER_LITTLEENDIAN //位元組序,小端還是大端,預設小端 (高位還是地位在前)
    };
    SLDataSource ds = {&que,&pcm};//包裝成配置資訊
  4.建立播放器
    SLObjectItf player = NULL;
    SLPlayItf iplayer = NULL;
    CreateAudioPlayer(eng,&player,&ds,&audioSink,sizeof(ids)/sizeof(SLInterfaceID),ids,req);//利用前面的配置來建立
    Realize(player,SL_BOOLEAN_FALSE);//例項化
    GetInterface(player,SL_IID_PLAY,&iplayer); // 獲取介面
    GetInterface(player,SL_IID_BUFFERQUEUE,&pcmQue);//緩衝佇列
    (*pcmQue)->RegisterCallback(pcmQue,PcmCall,0);//設定回撥函式,播放佇列空呼叫
    (*iplayer)->SetPlayState(iplayer,SL_PLAYSTATE_PLAYING); //設定為播放狀態play狀態、暫停狀態、
    (*pcmQue)->Enqueue(pcmQue,"",1); //啟動佇列回撥 先壓入一點資料

  

程式碼展示:

#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_ERROR,"ywl5320",FORMAT,##__VA_ARGS__);

//1 建立引擎
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 *contex) { LOGD("PcmCall"); static FILE *fp = NULL; static char *buf = NULL; if(!buf) { buf = new char[1024*1024]; } if(!fp) { fp = fopen("/sdcard/test.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_aplay_testopensl_MainActivity_stringFromJNI( JNIEnv *env, jobject /* this */) { std::string hello = "Hello from C++"; //1 建立引擎 SLEngineItf eng = CreateSL(); if(eng){ LOGD("CreateSL success! "); }else{ LOGD("CreateSL failed! "); } //2 建立混音器 SLObjectItf mix = NULL; SLresult re = 0; re = (*eng)->CreateOutputMix(eng,&mix,0,0,0); if(re !=SL_RESULT_SUCCESS ) { LOGD("SL_RESULT_SUCCESS failed!"); } re = (*mix)->Realize(mix,SL_BOOLEAN_FALSE); if(re !=SL_RESULT_SUCCESS ) { LOGD("(*mix)->Realize failed!"); } SLDataLocator_OutputMix outmix = {SL_DATALOCATOR_OUTPUTMIX,mix}; SLDataSink audioSink= {&outmix,0}; //3 配置音訊資訊 //緩衝佇列 SLDataLocator_AndroidSimpleBufferQueue que = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,10}; //以什麼樣的方式互動 //音訊格式 SLDataFormat_PCM pcm = { SL_DATAFORMAT_PCM,//支援PCM格式的資料 2,// 聲道數 SL_SAMPLINGRATE_44_1,//44100Hz的頻率(取樣率) SL_PCMSAMPLEFORMAT_FIXED_16, //位數 SL_PCMSAMPLEFORMAT_FIXED_16,//和位數一支即可 SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT,//立體聲(前作前右) SL_BYTEORDER_LITTLEENDIAN //位元組序,小端還是大端,預設小端 (高位還是地位在前) }; SLDataSource ds = {&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,&ds,&audioSink,sizeof(ids)/sizeof(SLInterfaceID),ids,req);//利用前面的配置來建立 if(re !=SL_RESULT_SUCCESS ) { LOGD("CreateAudioPlayer failed!"); } else{ LOGD("CreateAudioPlayer success!"); } (*player)->Realize(player,SL_BOOLEAN_FALSE);//例項化 //獲取player介面 re = (*player)->GetInterface(player,SL_IID_PLAY,&iplayer); // 獲取介面 if(re !=SL_RESULT_SUCCESS ) { LOGD("GetInterface SL_IID_PLAY failed!"); } re = (*player)->GetInterface(player,SL_IID_BUFFERQUEUE,&pcmQue);//緩衝佇列 if(re !=SL_RESULT_SUCCESS ) { LOGD("GetInterface SL_IID_BUFFERQUEUE failed!"); } //設定回撥函式,播放佇列空呼叫 (*pcmQue)->RegisterCallback(pcmQue,PcmCall,0);//斷音,很快的一個操作 //設定為播放狀態 (*iplayer)->SetPlayState(iplayer,SL_PLAYSTATE_PLAYING); // play狀態、暫停狀態、 //啟動佇列回撥 (*pcmQue)->Enqueue(pcmQue,"",1); // 先壓入一點資料 return env->NewStringUTF(hello.c_str()); } /** 1.初始化引擎 SLresult re; //存放引擎本身,上下文 SLEngineItf en; //存放引擎的介面 slCreateEngine(&engineSL,0,0,0,0,0);//建立物件 Realize(engineSL,SL_BOOLEAN_FALSE);//例項化(內部的資料分配記憶體) 都是這個模式,先建立,然後例項化,在獲取介面 GetInterface(engineSL,SL_IID_ENGINE,&en);//獲取介面SLEngineItf ,通過第二個引數獲取對應的介面 2.輸出裝置 SLObjectItf mix = NULL; SLresult re = 0; CreateOutputMix(eng,&mix,0,0,0);//建立輸出裝置 Realize(mix,SL_BOOLEAN_FALSE);//例項化 //下面兩個是儲存 SLDataLocator_OutputMix outmix = {SL_DATALOCATOR_OUTPUTMIX,mix}; SLDataSink audioSink= {&outmix,0}; 3.配置音訊資訊 SLDataLocator_AndroidSimpleBufferQueue que = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,10}; //以什麼樣的方式互動 //音訊格式 SLDataFormat_PCM pcm = { SL_DATAFORMAT_PCM,//支援PCM格式的資料 2,// 聲道數 SL_SAMPLINGRATE_44_1,//44100Hz的頻率(取樣率) SL_PCMSAMPLEFORMAT_FIXED_16, //位數 SL_PCMSAMPLEFORMAT_FIXED_16,//和位數一支即可 SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT,//立體聲(前作前右) SL_BYTEORDER_LITTLEENDIAN //位元組序,小端還是大端,預設小端 (高位還是地位在前) }; SLDataSource ds = {&que,&pcm};//包裝成配置資訊 4.建立播放器 SLObjectItf player = NULL; SLPlayItf iplayer = NULL; CreateAudioPlayer(eng,&player,&ds,&audioSink,sizeof(ids)/sizeof(SLInterfaceID),ids,req);//利用前面的配置來建立 Realize(player,SL_BOOLEAN_FALSE);//例項化 GetInterface(player,SL_IID_PLAY,&iplayer); // 獲取介面 GetInterface(player,SL_IID_BUFFERQUEUE,&pcmQue);//緩衝佇列 (*pcmQue)->RegisterCallback(pcmQue,PcmCall,0);//設定回撥函式,播放佇列空呼叫 (*iplayer)->SetPlayState(iplayer,SL_PLAYSTATE_PLAYING); //設定為播放狀態play狀態、暫停狀態、 (*pcmQue)->Enqueue(pcmQue,"",1); //啟動佇列回撥 先壓入一點資料 */
View Code