zoukankan      html  css  js  c++  java
  • Android音视频学习第7章:使用OpenSL ES进行音频解码

    这里写图片描写叙述
    /*
    *
    *这里使用了transcode-1.1.7对wav文件进行解码。然后使用opensl es进行播放
    *
    */


    //用到的变量和结构体

    WAV wav; //wav文件指针
    SLObjectItf engineObject; //引擎对象
    SLEngineItf engineInterface; //引擎接口
    SLObjectItf outputMixObject; //混音器
    SLObjectItf audioPlayerObject; //播放器对象
    SLAndroidSimpleBufferQueueItf andioPlayerBufferQueueItf;    //缓冲器队列接口
    SLPlayItf audioPlayInterface;   //播放接口
    
    
    unsigned char *buffer; //缓冲区
    size_t bufferSize;     //缓冲区大小
    
    //上下文
    struct PlayerContext{
        WAV wav;
        unsigned char *buffer;
        size_t bufferSize;
    
        PlayerContext(WAV wav,
                unsigned char *buffer,
                size_t bufferSize){
            this->wav = wav;
            this->buffer = buffer;
            this->bufferSize = bufferSize;
        }
    };
    //实现对象
    void RealizeObject(SLObjectItf object){
        //非异步(堵塞)
        (*object)->Realize(object,SL_BOOLEAN_FALSE);
    }

    详细实现流程:

    1.打开文件

    WAV wav = OpenWaveFile(env,jFileName);
    //打开文件
    WAV OpenWaveFile(JNIEnv *env,jstring jFileName){
        const char *cFileName = env->GetStringUTFChars(jFileName,JNI_FALSE);
        WAVError err;
        WAV wav = wav_open(cFileName,WAV_READ,&err);
    
        LOGI("%d",wav_get_bitrate(wav));
        env->ReleaseStringUTFChars(jFileName,cFileName);
        if(wav == 0){
            LOGE("%s",wav_strerror(err));
        }
        return wav;
    }

    2.创建OpenSL ES引擎

    //OpenSL ES在Android平台下默认是线程安全的,这样设置是为了为了兼容其它平台
        SLEngineOption options[] = {
            {(SLuint32)SL_ENGINEOPTION_THREADSAFE, (SLuint32)SL_BOOLEAN_TRUE}
        };
        slCreateEngine(&engineObject,ARRAY_LEN(engineObject),options,0,0,0); //没有接口
    
    //实例化对象
        //对象创建之后。处于未实例化状态,对象尽管存在但未分配不论什么资源,使用前先实例化(使用完之后destroy)
        RealizeObject(engineObject);

    3.获取引擎接口

    (*engineObject)->GetInterface(engineObject,SL_IID_ENGINE,&engineInterface);

    4.创建输出混音器

    (*engineInterface)->CreateOutputMix(engineInterface,&outputMixObject,0,0,0); //没有接口
        //实例化混音器
        RealizeObject(outputMixObject);

    5.创建缓冲区保存读取到的音频数据库

    //缓冲区的大小
        bufferSize = wav_get_channels(wav) * wav_get_rate(wav) * wav_get_bits(wav);
        buffer = new unsigned char[bufferSize];
    

    6.创建带有缓冲区队列的音频播放器

    CreateBufferQueueAudioPlayer(wav,engineInterface,outputMixObject,audioPlayerObject);
        //实例化音频播放器
        RealizeObject(audioPlayerObject);

    CreateBufferQueueAudioPlayer.cpp

    extern "C" {
    #include "wavlib.h"
    }
    #include <SLES/OpenSLES.h>
    #include <SLES/OpenSLES_Android.h>
    #include <android/log.h>
    
    #define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
    //创建音频播放对象
    void CreateBufferQueueAudioPlayer(
            WAV wav,
            SLEngineItf engineEngine,
            SLObjectItf outputMixObject,
            SLObjectItf &audioPlayerObject){
    
        // Android针对数据源的简单缓冲区队列定位器
        SLDataLocator_AndroidSimpleBufferQueue dataSourceLocator = {
            SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, // 定位器类型
            1                                        // 缓冲区数
        };
    
        // PCM数据源格式
        SLDataFormat_PCM dataSourceFormat = {
            SL_DATAFORMAT_PCM,        // 格式类型
            wav_get_channels(wav),    // 通道数
            wav_get_rate(wav) * 1000, // 毫赫兹/秒的样本数
            wav_get_bits(wav),        // 每一个样本的位数
            wav_get_bits(wav),        // 容器大小
            SL_SPEAKER_FRONT_CENTER,  // 通道屏蔽
            SL_BYTEORDER_LITTLEENDIAN // 字节顺序
        };
    
        // 数据源是含有PCM格式的简单缓冲区队列
        SLDataSource dataSource = {
            &dataSourceLocator, // 数据定位器
            &dataSourceFormat   // 数据格式
        };
    
        // 针对数据接收器的输出混合定位器
        SLDataLocator_OutputMix dataSinkLocator = {
            SL_DATALOCATOR_OUTPUTMIX, // 定位器类型
            outputMixObject           // 输出混合
        };
    
        // 数据定位器是一个输出混合
        SLDataSink dataSink = {
            &dataSinkLocator, // 定位器
            0                 // 格式
        };
    
        // 须要的接口
        SLInterfaceID interfaceIds[] = {
            SL_IID_BUFFERQUEUE
        };
    
        // 须要的接口,假设所须要的接口不要用。请求将失败
        SLboolean requiredInterfaces[] = {
            SL_BOOLEAN_TRUE // for SL_IID_BUFFERQUEUE
        };
    
        // 创建音频播放器对象
        SLresult result = (*engineEngine)->CreateAudioPlayer(
                engineEngine,
                &audioPlayerObject,
                &dataSource,
                &dataSink,
                ARRAY_LEN(interfaceIds),
                interfaceIds,
                requiredInterfaces);
    }
    

    查看全文

  • 相关阅读:
    转:Redis 3.2.1集群搭建
    转:GET和POST两种基本请求方法的区别
    web.xml中 /和/*的区别
    java main方法里调用mapper
    Java定时任务
    @Resource与@Autowired注解的区别
    解决Eclipse EE部署web项目在Tomcat webapp目录下没有工程文件的问题
    get方式中文参数乱码解决方法
    生成excel并发送给客户端
    java把汉字转换成拼音
  • 原文地址:https://www.cnblogs.com/lxjshuju/p/7298237.html
Copyright © 2011-2022 走看看