zoukankan      html  css  js  c++  java
  • 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
    天助自助者
  • 相关阅读:
    安卓手机!用swiper做轮播效果,两张图片之间会有一个像素的空白
    手机端swiper快速滑动会有白屏
    axios请求下载excel文件
    人人都能学会的webpack5搭建vue3项目(二)配置Vue
    人人都能学会的webpack5搭建vue3.0项目,可应用于生产环境 (一)
    mybatis 生成 mapper文件
    超强工具类系列
    mybatis 自动生成mapper文件
    面试
    linux安装mysql8.0.25
  • 原文地址:https://www.cnblogs.com/ZeGod/p/10010475.html
Copyright © 2011-2022 走看看