拿到音频的 路径 ,然后根据 jni 发送数据到C语言的方法

然后,开始解析

    avcodec_register_all();avformat_network_init();pPlayer->pFormatContext = avformat_alloc_context();int openInput = avformat_open_input(&pPlayer->pFormatContext, url, NULL, NULL);if (openInput != 0) {LOGE("打开失败 %s", url);return;}int streamInfo = avformat_find_stream_info(pPlayer->pFormatContext, NULL);if (streamInfo < 0) {LOGE("寻找流失败 %s", url);return;}for (int i = 0; i < pPlayer->pFormatContext->nb_streams; ++i) {if (pPlayer->pFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {pPlayer->stream_index = i;pPlayer->setSampleRate(pPlayer->pFormatContext->streams[i]->codecpar->sample_rate);pPlayer->codecpar = pPlayer->pFormatContext->streams[i]->codecpar;break;}}if (pPlayer->stream_index == -1) {LOGE("寻找流失败 %s", url);return;}AVCodec *pCodec = avcodec_find_decoder(pPlayer->codecpar->codec_id);if (!pCodec) {LOGE("寻找解码器失败 ");return;}pPlayer->pCodeContext = avcodec_alloc_context3(pCodec);if (!pPlayer->pCodeContext) {LOGE("请求空间失败 ");return;}int ret = avcodec_parameters_to_context(pPlayer->pCodeContext, pPlayer->codecpar);if (ret < 0) {LOGE("复制失败 ");return;}int open2 = avcodec_open2(pPlayer->pCodeContext, pCodec, NULL);if (open2 != 0) {return;}

到目前为止,已经把文件打开并且把音频流有关数据保存起来。

然后介绍几个有关方法。

1.把音频数据放入队列

int BugQueue::putPacket(AVPacket *packet) {pthread_mutex_lock(&mutex);myQueue.push(packet);pthread_cond_signal(&cond);pthread_mutex_unlock(&mutex);return 0;
}

2.把音频数据从队列取出

int BugQueue::getPacket(AVPacket *packet) {pthread_mutex_lock(&mutex);while (pStatue != NULL && !pStatue->exit) {if (myQueue.size() > 0) {AVPacket *pPacket = myQueue.front();if (av_packet_ref(packet, pPacket) == 0) {myQueue.pop();}av_packet_free(&pPacket);av_free(pPacket);pPacket = NULL;LOGE("取出队列  队列有%d条数据", myQueue.size())break;} else {pthread_cond_wait(&cond, &mutex);}}pthread_mutex_unlock(&mutex);return 0;
}

3.用上面那个方法把数据从队列取出,并且重采样

int BugPlayer::run() {int dataSize;while (pQueue->pStatue != NULL && !pQueue->pStatue->exit) {LOGE("1123132")AVPacket *pPacket = av_packet_alloc();if (pQueue->getPacket(pPacket) != 0) {av_packet_free(&pPacket);av_free(pPacket);pPacket = NULL;continue;}int ret;ret = avcodec_send_packet(pCodeContext, pPacket);LOGE("   cccc     %d", ret)if (ret != 0) {av_packet_free(&pPacket);av_free(pPacket);pPacket = NULL;continue;}AVFrame *pFrame = av_frame_alloc();ret = avcodec_receive_frame(pCodeContext, pFrame);if (ret != 0) {av_packet_free(&pPacket);av_free(pPacket);pPacket = NULL;av_frame_free(&pFrame);av_free(pFrame);pFrame = NULL;continue;}if (pFrame->channel_layout == 0 && pFrame->channels > 0) {pFrame->channel_layout = av_get_default_channel_layout(pFrame->channels);} else if (pFrame->channels == 0 && pFrame->channel_layout > 0) {pFrame->channels = av_get_channel_layout_nb_channels(pFrame->channel_layout);}SwrContext *sclz;sclz = swr_alloc_set_opts(NULL,AV_CH_LAYOUT_STEREO,AV_SAMPLE_FMT_S16,pFrame->sample_rate,pFrame->channel_layout,static_cast<AVSampleFormat>(pFrame->format),pFrame->sample_rate,NULL, NULL);if (!sclz || swr_init(sclz) < 0) {av_packet_free(&pPacket);av_free(pPacket);pPacket = NULL;av_frame_free(&pFrame);av_free(pFrame);pFrame = NULL;swr_free(&sclz);continue;}int nb = swr_convert(sclz, &buffer, pFrame->nb_samples,(const uint8_t **) (pFrame->data), pFrame->nb_samples);int outchannels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);dataSize = nb * outchannels * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);fwrite(buffer, 1, dataSize, outFile);av_packet_free(&pPacket);av_free(pPacket);pPacket = NULL;av_frame_free(&pFrame);av_free(pFrame);pFrame = NULL;swr_free(&sclz);break;}fclose(outFile);return dataSize;
}

4.OPEN SL ES 的一个回调,用了上面那个方法,取出数据并播放

void pcmBufferCallback(SLAndroidSimpleBufferQueueItf buff, void *context) {BugPlayer *bugPlayer = static_cast<BugPlayer *>(context);int size = bugPlayer->run();LOGE("pcmBufferCallback   %d", size)if (size > 0) {(*bugPlayer->slDataLocatorAndroidSimpleBufferQueue)->Enqueue(bugPlayer->slDataLocatorAndroidSimpleBufferQueue, (char *) bugPlayer->buffer, size);}
}

5.这是初始化openSLES的代码,并在里面调用了上面那个方法

void BugPlayer::init() {SLresult result;slCreateEngine(&enginObj, 0, 0, 0, 0, 0);(*enginObj)->Realize(enginObj, SL_BOOLEAN_FALSE);(*enginObj)->GetInterface(enginObj, SL_IID_ENGINE, &enginEngin);const SLInterfaceID mid[1] = {SL_IID_ENVIRONMENTALREVERB};const SLboolean req[1] = {SL_BOOLEAN_FALSE};result = (*enginEngin)->CreateOutputMix(enginEngin, &outObj, 1, mid, req);result = (*outObj)->Realize(outObj, SL_BOOLEAN_FALSE);result = (*outObj)->GetInterface(outObj, SL_IID_ENVIRONMENTALREVERB, &outItf);if (SL_RESULT_SUCCESS == result) {result = (*outItf)->SetEnvironmentalReverbProperties(outItf, &outSetting);}SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX, outObj};SLDataLocator_AndroidSimpleBufferQueue androidSimpleBufferQueue = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};SLDataFormat_PCM pcm = {SL_DATAFORMAT_PCM,2,(SLuint32) getCurrentSampleRateForOpensles(),SL_PCMSAMPLEFORMAT_FIXED_16,SL_PCMSAMPLEFORMAT_FIXED_16,SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,SL_BYTEORDER_LITTLEENDIAN};SLDataSource slDataSource = {&androidSimpleBufferQueue, &pcm};SLDataSink sink = {&outputMix, NULL};SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND, SL_IID_VOLUME};SLboolean req2[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};result = (*enginEngin)->CreateAudioPlayer(enginEngin, &pcmObj, &slDataSource, &sink, 3, ids,req2);(*pcmObj)->Realize(pcmObj, SL_BOOLEAN_FALSE);(*pcmObj)->GetInterface(pcmObj, SL_IID_PLAY, &pcmPlay);(*pcmObj)->GetInterface(pcmObj, SL_IID_BUFFERQUEUE, &slDataLocatorAndroidSimpleBufferQueue);(*slDataLocatorAndroidSimpleBufferQueue)->RegisterCallback(slDataLocatorAndroidSimpleBufferQueue, pcmBufferCallback, this);(*pcmObj)->GetInterface(pcmObj, SL_IID_VOLUME, &pcmVol);(*pcmPlay)->SetPlayState(pcmPlay, SL_PLAYSTATE_PLAYING);pcmBufferCallback(slDataLocatorAndroidSimpleBufferQueue, this);
}

这是第五个方法需要的声明

    SLObjectItf enginObj;SLEngineItf enginEngin;SLObjectItf outObj;SLEnvironmentalReverbItf outItf;SLEnvironmentalReverbSettings outSetting;SLObjectItf pcmObj;SLPlayItf pcmPlay;SLVolumeItf pcmVol;SLAndroidSimpleBufferQueueItf slDataLocatorAndroidSimpleBufferQueue ;

现在,调用一个方法,实现音频的播放

在这个方法里,上面那几个方法都会走一遍

void BugFfmpeg::start() {pPlayer->play();while (pPlayer->pQueue->pStatue != NULL && !pPlayer->pQueue->pStatue->exit) {AVPacket *pPacket = av_packet_alloc();if (av_read_frame(pPlayer->pFormatContext, pPacket) == 0) {if (pPacket->stream_index == pPlayer->stream_index) {pPlayer->pQueue->putPacket(pPacket);} else {av_packet_free(&pPacket);av_free(pPacket);pPacket = NULL;}} else {av_packet_free(&pPacket);av_free(pPacket);pPacket = NULL;while (pPlayer->pQueue->pStatue != NULL && !pPlayer->pQueue->pStatue->exit) {if (pPlayer->pQueue->getQueueSize() > 0) {continue;} else {pPlayer->pQueue->pStatue->exit = true;}}}}
}

工具方法

int BugPlayer::getCurrentSampleRateForOpensles() {int rate = 0;switch (sampleRate) {case 8000:rate = SL_SAMPLINGRATE_8;break;case 11025:rate = SL_SAMPLINGRATE_11_025;break;case 12000:rate = SL_SAMPLINGRATE_12;break;case 16000:rate = SL_SAMPLINGRATE_16;break;case 22050:rate = SL_SAMPLINGRATE_22_05;break;case 24000:rate = SL_SAMPLINGRATE_24;break;case 32000:rate = SL_SAMPLINGRATE_32;break;case 44100:rate = SL_SAMPLINGRATE_44_1;break;case 48000:rate = SL_SAMPLINGRATE_48;break;case 64000:rate = SL_SAMPLINGRATE_64;break;case 88200:rate = SL_SAMPLINGRATE_88_2;break;case 96000:rate = SL_SAMPLINGRATE_96;break;case 192000:rate = SL_SAMPLINGRATE_192;break;default:rate = SL_SAMPLINGRATE_44_1;}return rate;
}

Ffmpeg + OpenSL ES + Android 播放音频相关推荐

  1. Android直播开发之旅(13):使用FFmpeg+OpenSL ES播放PCM音频

    文章目录 1. OpenSL ES原理 1.1 OpenSL ES核心API讲解 1.1.1 对象(Object)与接口(Interface) 1.1.2 [OpenSL ES的状态机制](https ...

  2. Android音视频学习系列(十) — 基于FFmpeg + OpenSL ES实现音频万能播放器

    系列文章 Android音视频学习系列(一) - JNI从入门到精通 Android音视频学习系列(二) - 交叉编译动态库.静态库的入门 Android音视频学习系列(三) - Shell脚本入门 ...

  3. 音视频开发之旅(36) -FFmpeg +OpenSL ES实现音频解码和播放

    目录 OpenSL ES基本介绍 OpenSL ES播放音频流程 代码实现 遇到的问题 资料 收获 上一篇我们通过AudioTrack实现了FFmpeg解码后的PCM音频数据的播放,在Android上 ...

  4. 【Android FFMPEG 开发】OpenSLES 播放音频 ( 创建引擎 | 输出混音设置 | 配置输入输出 | 创建播放器 | 获取播放/队列接口 | 回调函数 | 开始播放 | 激活回调 )

    文章目录 I . FFMPEG 播放视频流程 II . OpenSLES 播放音频流程 III . OpenSLES 播放参考 Google 官方示例 IV . OpenSL ES 播放代码 ( 详细 ...

  5. NDK--利用OpenSL ES实现播放FFmpeg解码后的音频流

    OpenSL ES全称为Open Sound Library for Embedded Systems.OpenSL ES是无授权费.跨平台.针对嵌入式系统 精心优化的硬件音频加速API.当然安卓也使 ...

  6. android: 播放音频

    在 Android 中播放音频文件一般都是使用 MediaPlayer 类来实现的,它对多种格式的音 频文件提供了非常全面的控制方法,从而使得播放音乐的工作变得十分简单.下表列出了 MediaPlay ...

  7. FFmpeg学习3:播放音频

    参考dranger tutorial,本文将介绍如何使用FFmpeg解码音频数据,并使用SDL将解码后的数据输出. 本文主要包含以下几方面的内容: 关于播放音频的需要的一些基础知识介绍 使用SDL2播 ...

  8. Android播放音频之按钮控制

    控制音量和播放 良好的用户体验是可预测的. 如果您的应用程式播放媒体,您的使用者必须使用装置,蓝牙耳机或耳机的硬体或软体音量控制来控制应用程式的音量. 类似地,在适当和可用的情况下,播放,停止,暂停, ...

  9. android 播放声音文件,AudioPlayerDemo android 播放音频文件

    [实例简介] 该PCM 参数如下: rm-channels_2 frame_4096(纯PCM数据每帧长度4096) freq_44100 bits_16 480X234_1700kbps.rm是源音 ...

最新文章

  1. 在Microsoft Word中,Node是如何替代宏的
  2. 【深度学习】卷积神经网络实现图像多分类的探索
  3. Python图像处理库PIL从入门到精通
  4. Linux运维:常用的压缩解压缩命令(zip、tar)
  5. OS / 几个常用的操作系统进程调度算法
  6. openshift_在OpenShift上托管的WildFly实例上进行Arquillian测试
  7. 函数中的apply,call入门介绍
  8. cocos2d c 调用java_cocos2d-x之C++ 调用Java函数并接收返回值
  9. 信息学奥赛一本通 2022:【例4.7】最小n值
  10. 图论 —— AOE 网与关键路径
  11. 9:38 2009-7-29
  12. 如何让你的数据库定时自动备份(2000SQL)
  13. 异步发电机 matlab仿真,基于MATLABSIMULINK异步电机矢量控制系统的仿真.pdf
  14. PL/SQL数据类型
  15. 访问oracle数据库语句,Oracle数据库SQL ——Select 语句使用方法
  16. 入门系列之在Ubuntu上使用Netdata设置实时性能监控
  17. GoogleEarth的安装与使用
  18. 迅雷高速通道破解教程
  19. C++ P1091 合唱队形[DP]
  20. Linux中关于安装包的分析。——Arvin

热门文章

  1. 把消费者变成品牌传播主体
  2. 【人工智能】禅与计算机程序设计艺术评论:我的大模型世界观(陆奇)
  3. u8 服务器配置文档,u8服务器的配置
  4. Win8系统的机器如何改装Win7系统
  5. Caused by: java.lang.IllegalArgumentException: Invalid <url-pattern> [url] in servlet mapping
  6. 开启线程_beginthreadex()和停止线程_endthreadex()
  7. MFC 打印调试 信息 OutputDebugString
  8. mov格式转换成mp4,mov转换mp4格式的步骤
  9. 裸辞20天,10个offer
  10. linux上的壁纸软件下载,Ubuntu 17.10上安装开源壁纸工具Wallch 4.0