五、OpenSL ES音频播放
来源:互联网 发布:sqlserver 按月统计 编辑:程序博客网 时间:2024/05/14 16:11
本文基于以下文章进行的开发:
一、FFMPEG源码编译
二、AndroidStudio集成FFMPEG
三、FFMPEG视频解码及播放四、FFMPEG播放音频
开发出色的音频应用
OpenSL ES API 可以帮助您制定和提升应用的音频性能。 某些典型用例包括以下组成部分:
- 数字音频工作站 (DAW)。
- 合成器。
- 电子鼓。
- 音乐学习应用。
- 卡拉 OK 应用。
- DJ 混合。
- 音频效果。
- 视频/音频会议。
OpenSL ES 入门指南
1.cpp目录下新建FFmpegMusic.h和FFmpegMusic.cpp
FFmpegMusic.h
//// Created by ygdx_lk on 17/11/3.//#ifndef FFMPEG_FFMPEGMUSIC_H#define FFMPEG_FFMPEGMUSIC_H#include <jni.h>#include <string>#include <android/log.h>extern "C" {//编码#include "libavcodec/avcodec.h"//封装格式处理#include "libavformat/avformat.h"#include "libswresample/swresample.h"//像素处理#include "libswscale/swscale.h"#include <android/native_window_jni.h>#include <unistd.h>}#define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,"jason",FORMAT,##__VA_ARGS__);#define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,"jason",FORMAT,##__VA_ARGS__);int createFFmpeg(int *rate,int *channel);int getPcm(void **pcm,size_t *pcm_size);void realseFFmpeg();#endif //FFMPEG_FFMPEGMUSIC_H
FFmpegMusic.h
//// Created by ygdx_lk on 17/11/3.//#include "FFmpegMusic.h"AVFormatContext *avFormatContext;AVCodecContext *avCodecContext;AVCodec *aVCodec;AVPacket *packet;AVFrame *frame;SwrContext *swrContext;uint8_t *out_buffer;int out_channer_nb;int audio_stream_idx = -1;int createFFmpeg(int *rate,int *channel){ av_register_all(); char *input = "/sdcard/input.mp3"; avFormatContext = avformat_alloc_context(); //0 on success, a negative AVERROR on failure if(avformat_open_input(&avFormatContext, input, NULL, NULL) < 0){ LOGE("%s", "打开输入音频失败"); return -1; } //>=0 if OK if(avformat_find_stream_info(avFormatContext, NULL) < 0){ LOGE("%s", "获取资源信息失败"); return -1; } for (int i = 0; i < avFormatContext->nb_streams; ++i) { if(avFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO){ audio_stream_idx = i; break; } } avCodecContext = avFormatContext->streams[audio_stream_idx]->codec; aVCodec = avcodec_find_decoder(avCodecContext->codec_id); //zero on success, a negative value on error if(avcodec_open2(avCodecContext, aVCodec, NULL) < 0){ LOGE("%s", "打开解码器失败"); return -1; } //设置输入输出转换信息// struct SwrContext *swr_alloc_set_opts(struct SwrContext *s,// int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,// int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate,// int log_offset, void *log_ctx); swrContext = swr_alloc(); int64_t out_ch_layout = AV_CH_LAYOUT_STEREO;//立体声 enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;//输出采样率16位 int out_sample_rate = avCodecContext->sample_rate; swr_alloc_set_opts(swrContext, out_ch_layout, out_sample_fmt, out_sample_rate, avCodecContext->channel_layout, avCodecContext->sample_fmt, avCodecContext->sample_rate, 0, NULL); swr_init(swrContext); //获取声道数 out_channer_nb = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO); *rate = avCodecContext->sample_rate; *channel = avCodecContext->channels; packet = (AVPacket *) av_malloc(sizeof(AVPacket)); frame = av_frame_alloc(); out_buffer = (uint8_t *) av_malloc(44100 * 2); return 0;}int getPcm(void **pcm,size_t *pcm_size){ LOGI("%s", "getPcm--"); int got_frame; //0 if OK, < 0 on error or end of file while (av_read_frame(avFormatContext, packet) == 0){ LOGI("%s", "getPcm——read_frame") if(packet->stream_index == audio_stream_idx){// int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame,// int *got_frame_ptr, const AVPacket *avpkt); avcodec_decode_audio4(avCodecContext, frame, &got_frame, packet); if(got_frame){// int swr_convert(struct SwrContext *s, uint8_t **out, int out_count,// const uint8_t **in , int in_count); swr_convert(swrContext, &out_buffer, 44100 * 2, (const uint8_t **) frame->data, frame->nb_samples);// int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples,// enum AVSampleFormat sample_fmt, int align); int size = av_samples_get_buffer_size(NULL, out_channer_nb, frame->nb_samples, AV_SAMPLE_FMT_S16, 1); *pcm = out_buffer; *pcm_size = size; break; } } } return 0;}void realseFFmpeg(){ av_free_packet(packet); av_free(out_buffer); av_frame_free(&frame); swr_free(&swrContext); avcodec_close(avCodecContext); avformat_close_input(&avFormatContext);}
2.native-lib.h添加如下代码
#include <SLES/OpenSLES.h>#include <SLES/OpenSLES_Android.h>
3.修改CMakeLists.txt
add_library添加:src /main/cpp/FFmpegMusic.cpp
修改前:
add_library( native-lib SHARED src/main/cpp/native-lib.cpp )
修改后:
add_library( native-lib SHARED src/main/cpp/native-lib.cpp src/main/cpp/FFmpegMusic.cpp )
target_link_libraries添加OpenSLES:
修改前:
target_link_libraries( native-lib avcodec-56 avdevice-56 avformat-56 avutil-54 swresample-1 swscale-3 -landroid ${log-lib} )修改后:
target_link_libraries( native-lib avcodec-56 avdevice-56 avformat-56 avutil-54 swresample-1 swscale-3 OpenSLES -landroid ${log-lib} )
4.native-lib.h中添加方法:
JNIEXPORT void JNICALL Java_com_test_ffmpeg_AudioPlayer_openSlesPlay(JNIEnv *env, jobject instance);
5.native-lib.cpp实现
SLObjectItf slObjectItf = NULL;SLEngineItf slEngineItf = NULL;//混音器SLObjectItf pMix = NULL;SLEnvironmentalReverbItf slEnvironmentalReverbItf = NULL;SLEnvironmentalReverbSettings settings = SL_I3DL2_ENVIRONMENT_PRESET_DEFAULT;//播放器SLObjectItf bgPlayerObject;SLPlayItf bqPlayerPlay;//队列缓冲区SLAndroidSimpleBufferQueueItf bqPlayerQueue;//音量对象SLVolumeItf bqPalyerVolume;//只要喇叭一读完 就会回调此函数,添加pcm数据到缓冲区void *buffer;size_t bufferSize = 0;void bqPlayerCallBack(SLAndroidSimpleBufferQueueItf bq, void *context){ bufferSize = 0; getPcm(&buffer, &bufferSize); if(buffer != NULL && 0 != bufferSize){ //播放的关键地方 SLresult sLresult = (*bqPlayerQueue)->Enqueue(bqPlayerQueue, buffer, bufferSize); LOGI("正在播放 %d", bufferSize); } else{ LOGI("播放结束 %d", bufferSize) realseFFmpeg(); }};void JNICALL Java_com_test_ffmpeg_AudioPlayer_openSlesPlay(JNIEnv *env, jobject instance) { //初始化一个引擎 SLresult sLresult;// SL_API SLresult SLAPIENTRY slCreateEngine(// SLObjectItf *pEngine,// SLuint32 numOptions,// const SLEngineOption *pEngineOptions,// SLuint32 numInterfaces,// const SLInterfaceID *pInterfaceIds,// const SLboolean * pInterfaceRequired// ); slCreateEngine(&slObjectItf, 0, NULL, 0, NULL, NULL); (*slObjectItf)->Realize(slObjectItf, SL_BOOLEAN_FALSE);// SLresult (*GetInterface) (// SLObjectItf self,// const SLInterfaceID iid,// void * pInterface// ); //获取引擎接口 sLresult = (*slObjectItf)->GetInterface(slObjectItf, SL_IID_ENGINE, &slEngineItf); LOGI("引擎地址%p sLresult %d", slEngineItf, sLresult); //创建混音器// SLresult (*CreateOutputMix) (// SLEngineItf self,// SLObjectItf * pMix,// SLuint32 numInterfaces,// const SLInterfaceID * pInterfaceIds,// const SLboolean * pInterfaceRequired// ); (*slEngineItf)->CreateOutputMix(slEngineItf, &pMix, 0, 0, 0); (*pMix)->Realize(pMix, SL_BOOLEAN_FALSE); //设置环境混响 sLresult = (*pMix)->GetInterface(pMix, SL_IID_ENVIRONMENTALREVERB, &slEnvironmentalReverbItf); LOGI("sLresult 1 %d", sLresult); if(SL_RESULT_SUCCESS == sLresult){// SLresult (*SetEnvironmentalReverbProperties) (// SLEnvironmentalReverbItf self,// const SLEnvironmentalReverbSettings *pProperties// ); (*slEnvironmentalReverbItf)->SetEnvironmentalReverbProperties(slEnvironmentalReverbItf, &settings); } //初始化ffmpeg int rate; int channels; createFFmpeg(&rate, &channels); LOGI("%s", "初始化FFMPEG完毕"); SLDataLocator_AndroidBufferQueue androidBufferQueue = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};// typedef struct SLDataFormat_PCM_ {// SLuint32 formatType;// SLuint32 numChannels;// SLuint32 samplesPerSec;// SLuint32 bitsPerSample;// SLuint32 containerSize;// SLuint32 channelMask;// SLuint32endianness;// } SLDataFormat_PCM; SLDataFormat_PCM pcm = { SL_DATAFORMAT_PCM, channels, SL_SAMPLINGRATE_44_1, SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT, SL_BYTEORDER_LITTLEENDIAN };// typedef struct SLDataSource_ {// void *pLocator;// void *pFormat;// } SLDataSource; SLDataSource slDataSource = {&androidBufferQueue, &pcm}; //设置混音器// typedef struct SLDataLocator_OutputMix {// SLuint32 locatorType;// SLObjectItfoutputMix;// } SLDataLocator_OutputMix; SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX, pMix};// typedef struct SLDataSink_ {// void *pLocator;// void *pFormat;// } SLDataSink; 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}; //混音器关联 //创建一个播放器// SLresult (*CreateAudioPlayer) (// SLEngineItf self,// SLObjectItf * pPlayer,// SLDataSource *pAudioSrc,// SLDataSink *pAudioSnk,// SLuint32 numInterfaces,// const SLInterfaceID * pInterfaceIds,// const SLboolean * pInterfaceRequired// ); sLresult = (*slEngineItf)->CreateAudioPlayer(slEngineItf, &bgPlayerObject, &slDataSource, &audioSnk, 3, ids, req); sLresult = (*bgPlayerObject)->Realize(bgPlayerObject, SL_BOOLEAN_FALSE); //创建一个播放器接口 sLresult = (*bgPlayerObject)->GetInterface(bgPlayerObject, SL_IID_PLAY, &bqPlayerPlay); //注册缓冲区 sLresult = (*bgPlayerObject)->GetInterface(bgPlayerObject, SL_IID_BUFFERQUEUE, &bqPlayerQueue); //设置接口回调 sLresult = (*bqPlayerQueue)->RegisterCallback(bqPlayerQueue, bqPlayerCallBack, NULL); (*bgPlayerObject)->GetInterface(bgPlayerObject, SL_IID_VOLUME, &bqPalyerVolume); (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING); //播放第一帧 bqPlayerCallBack(bqPlayerQueue, NULL);}
6.AudioPlayer添加native方法
public native void openSlesPlay();
7.MainActivity调用:
new Thread(new Runnable() { @Override public void run() { new AudioPlayer().openSlesPlay(); } }).start();
阅读全文
0 0
- 五、OpenSL ES音频播放
- Android 音频 OpenSL ES URI播放
- Android 音频 OpenSL ES PCM数据播放
- Android+FFmpeg+OpenSL ES音频解码播放
- Android+FFmpeg+OpenSL ES音频解码播放
- OpenSL ES 进行音频解码播放
- Android+FFmpeg+OpenSL ES音频解码播放
- android使用opensl es进行简单的音频播放
- Android通过OpenSL ES播放音频套路详解
- Android 音频 OpenSL ES 录音
- Android 音频 OpenSL ES 录音 采集
- Android中如何实现播放音频设置不同的播放速率(MediaPlayer SoundPool AudioTrack OpenSL ES)
- 调用OpenSL ES NDK播放声音
- 调用OpenSL ES NDK播放声音
- OpenSL ES
- OpenSL音频
- Android 音频 Native API OpenSL ES 简要介绍
- Android音频开发之使用OpenSL ES API
- RGB数据转换Bitmap
- DiskFileItemFactory 文件上传存储
- Windows网络编程入门:简单的客户端和服务器通信程序调试
- 百万数据查询优化技巧三十则
- 史上最详细bitbucket入门手册,手把手操作指南
- 五、OpenSL ES音频播放
- mac上修改截图默认保存
- 几种常用的特征选择方法
- ios两个图片合成为一张
- CSS Mastery摘要(8)--Styling Forms and Data Tables
- Elasticsearch 安装ik分词工具
- python线程指南---[转]
- msf学习笔记(5)
- Java日期转换及计算