当前位置: 首页 > news >正文

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

 

转载于:https://www.cnblogs.com/ZeGod/p/10010475.html

相关文章:

  • AI创业公司“一览群智”完成1.5亿元融资,经纬中国、策源资本投资
  • HTTP API 自动化测试从手工测试到平台的演变
  • JS 中的深拷贝与浅拷贝
  • 理解React Hooks
  • Django的Rbac介绍3
  • 毫秒级从百亿大表任意维度筛选数据,是怎么做到的...
  • 网上流传的那些关于链表的面试问题
  • JavaScript的使用你知道几种?(上)
  • 根据开始日期和当前日期,获取当前是第几周
  • 服务发现全量配置整理(更新中)
  • MySql版本查看
  • 业务员类别窗体的制作
  • lucene 思维导图,让搜索引擎不再难懂
  • “如何让团队成员获得成长?”四名高段位 CTO 为你解惑
  • 二叉树应用
  • 【Leetcode】104. 二叉树的最大深度
  • WinRAR存在严重的安全漏洞影响5亿用户
  • 包装类对象
  • 从0实现一个tiny react(三)生命周期
  • 从零到一:用Phaser.js写意地开发小游戏(Chapter 3 - 加载游戏资源)
  • 从伪并行的 Python 多线程说起
  • 复习Javascript专题(四):js中的深浅拷贝
  • 工作踩坑系列——https访问遇到“已阻止载入混合活动内容”
  • 计算机常识 - 收藏集 - 掘金
  • 蓝海存储开关机注意事项总结
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 探索 JS 中的模块化
  • 为什么要用IPython/Jupyter?
  • 我有几个粽子,和一个故事
  • 新手搭建网站的主要流程
  • 回归生活:清理微信公众号
  • 浅谈sql中的in与not in,exists与not exists的区别
  • 如何在招聘中考核.NET架构师
  • ​2020 年大前端技术趋势解读
  • ​软考-高级-信息系统项目管理师教程 第四版【第19章-配置与变更管理-思维导图】​
  • ### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException
  • #我与Java虚拟机的故事#连载03:面试过的百度,滴滴,快手都问了这些问题
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • (Matalb回归预测)PSO-BP粒子群算法优化BP神经网络的多维回归预测
  • (二)springcloud实战之config配置中心
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (三)Honghu Cloud云架构一定时调度平台
  • (四)图像的%2线性拉伸
  • (算法设计与分析)第一章算法概述-习题
  • **CI中自动类加载的用法总结
  • ./configure,make,make install的作用
  • .axf 转化 .bin文件 的方法
  • .bashrc在哪里,alias妙用
  • .Net 4.0并行库实用性演练
  • .NET CORE 第一节 创建基本的 asp.net core
  • .NET 读取 JSON格式的数据
  • .net 后台导出excel ,word
  • .NET/C# 解压 Zip 文件时出现异常:System.IO.InvalidDataException: 找不到中央目录结尾记录。
  • .NET/C# 使用反射调用含 ref 或 out 参数的方法
  • .NET大文件上传知识整理