关于

准备工作

正文

和视频播放一样我们依照流程图来实现,从这个流程图可以看出,音频播放和视频播放的大概流程并没有多大差别,只是细节之处需要处理。

依照流程来实现

1.注册组件,打开音频文件并获取内容,找到音频流:

av_register_all();

AVFormatContext *pFormatCtx = avformat_alloc_context();

//open

if (avformat_open_input(&pFormatCtx, input, NULL, NULL) != 0) {

LOGE("%s","打开输入视频文件失败");

return;

}

//获取视频信息

if(avformat_find_stream_info(pFormatCtx,NULL) < 0){

LOGE("%s","获取视频信息失败");

return;

}

int audio_stream_idx=-1;

int i=0;

for (int i = 0; i < pFormatCtx->nb_streams; ++i) {

if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {

LOGE(" 找到音频id %d", pFormatCtx->streams[i]->codec->codec_type);

audio_stream_idx=i;

break;

}

}

2.获取解码的装置,申请avframe和avpacket:

//获取解码的装置上下文

AVCodecContext *pCodecCtx=pFormatCtx->streams[audio_stream_idx]->codec;

//获取解码的装置

AVCodec *pCodex = avcodec_find_decoder(pCodecCtx->codec_id);

//打开解码的装置

if (avcodec_open2(pCodecCtx, pCodex, NULL)<0) {

}

//申请avpakcet,装解码前的数据

AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));

//申请avframe,装解码后的数据

AVFrame *frame = av_frame_alloc();

3.初始化SwrContext,进行重采样

//得到SwrContext ,进行重采样,具体参考http://blog.csdn.net/jammg/article/details/52688506

SwrContext *swrContext = swr_alloc();

//缓存区

uint8_t *out_buffer = (uint8_t *) av_malloc(44100 * 2);

//输出的声道布局(立体声)

uint64_t out_ch_layout=AV_CH_LAYOUT_STEREO;

//输出采样位数 16位

enum AVSampleFormat out_formart=AV_SAMPLE_FMT_S16;

//输出的采样率必须与输入相同

int out_sample_rate = pCodecCtx->sample_rate;

//swr_alloc_set_opts将PCM源文件的采样格式转换为自己希望的采样格式

swr_alloc_set_opts(swrContext, out_ch_layout, out_formart, out_sample_rate,

pCodecCtx->channel_layout, pCodecCtx->sample_fmt, pCodecCtx->sample_rate, 0,

NULL);

swr_init(swrContext);

4.通过while循环读取内容,并通过AudioTrack进行播放:

// 获取通道数 2

int out_channer_nb = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);

// 反射得到Class类型

jclass david_player = env->GetObjectClass(instance);

// 反射得到createAudio方法

jmethodID createAudio = env->GetMethodID(david_player, "createTrack", "(II)V");

// 反射调用createAudio

env->CallVoidMethod(instance, createAudio, 44100, out_channer_nb);

jmethodID audio_write = env->GetMethodID(david_player, "playTrack", "([BI)V");

int got_frame;

while (av_read_frame(pFormatCtx, packet) >= 0) {

if (packet->stream_index == audio_stream_idx) {

// 解码 mp3 编码格式frame----pcm frame

avcodec_decode_audio4(pCodecCtx, frame, &got_frame, packet);

if (got_frame) {

LOGE("解码");

swr_convert(swrContext, &out_buffer, 44100 * 2, (const uint8_t **) frame->data, frame->nb_samples);

// 缓冲区的大小

int size = av_samples_get_buffer_size(NULL, out_channer_nb, frame->nb_samples,

AV_SAMPLE_FMT_S16, 1);

jbyteArray audio_sample_array = env->NewByteArray(size);

env->SetByteArrayRegion(audio_sample_array, 0, size, (const jbyte *) out_buffer);

env->CallVoidMethod(instance, audio_write, audio_sample_array, size);

env->DeleteLocalRef(audio_sample_array);

}

}

}

5.释放需要释放的资源:

av_frame_free(&frame);

swr_free(&swrContext);

avcodec_close(pCodecCtx);

avformat_close_input(&pFormatCtx);

env->ReleaseStringUTFChars(input_, input);

java层创建AudioTrack方法。

jni通过调用java层的audiotrack方法来实现播放,但是java层的audiotrack方法又是通过调用底层的openesl es来进行播放,相当于绕了一个圈,所以在下篇文章中将实现使用opensl es来直接播放音频。

public class MusicPlay {

static{

System.loadLibrary("avcodec-56");

System.loadLibrary("avdevice-56");

System.loadLibrary("avfilter-5");

System.loadLibrary("avformat-56");

System.loadLibrary("avutil-54");

System.loadLibrary("postproc-53");

System.loadLibrary("swresample-1");

System.loadLibrary("swscale-3");

System.loadLibrary("native-lib");

}

public native void playSound(String input);

private AudioTrack audioTrack;

// 这个方法 是C进行调用

public void createTrack(int sampleRateInHz,int nb_channals) {

int channaleConfig;//通道数

if (nb_channals == 1) {

channaleConfig = AudioFormat.CHANNEL_OUT_MONO;

} else if (nb_channals == 2) {

channaleConfig = AudioFormat.CHANNEL_OUT_STEREO;

}else {

channaleConfig = AudioFormat.CHANNEL_OUT_MONO;

}

int buffersize=AudioTrack.getMinBufferSize(sampleRateInHz,

channaleConfig, AudioFormat.ENCODING_PCM_16BIT);

audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,sampleRateInHz,channaleConfig,

AudioFormat.ENCODING_PCM_16BIT,buffersize,AudioTrack.MODE_STREAM);

audioTrack.play();

}

//C传入音频数据

public void playTrack(byte[] buffer, int lenth) {

if (audioTrack != null && audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {

audioTrack.write(buffer, 0, lenth);

}

}

}

小结

按照流程,使用AudioTrack播放音频就是这么回事。通过和上篇的播放视频相比较,流程就差不多了:注册->解封装->获取流->解码->播放。

源码地址

ffmpeg 音乐循环_Android使用FFmpeg(四)--ffmpeg实现音频播放(使用AudioTrack进行播放)相关推荐

  1. ffmpeg 音乐循环_自媒体良器:音频文件批处理,FFmpeg一行搞定!果断收藏

    引言 FFMpeg 是众多多媒体应用程序的核心,但该程序本身不具备一次转换多个文件的能力. 但也拦不住,FFMpeg 本身是命令行程序,可编写脚本,借助 Bash 轻松快速地构建自动化程序. 1 - ...

  2. ffmpeg 音乐循环_[宜配屋]听图阁

    ffmpeg -i out3.mp4 -i music3D.wav -filter_complex [1:a]aloop=loop=-1:size=2e+09[out];[out][0:a]amix  ...

  3. 音视频开发(四)——编码音频

    基于QT+FFMPEG的音视频开发(四)--编码音频 一.编码一般步骤 二.编码 2.1 创建编码器(本文创建AAC) 2.2 核心编码 三.源码 我的大部分学习都来自雷神,没有基础去雷神博客转转,每 ...

  4. FFmpeg Visual Studio开发(四):音频解码

    上一篇文章我们学习了如何通过FFmpeg解码视频帧,本篇文章我们来学习如何解码音频帧.文章分段讲解视频解码的各个步骤,接着会贴上完整代码,最后进行测试. 准备工作 在开始学习前,我们先准备一个文件夹( ...

  5. 【FFmpeg】ffmpeg工具源码分析(四):filter(过滤器、滤镜)详解

    1.简介 FFmpeg用来处理音视频,实现处理功能的核心就是filter(滤镜),和我们使用的美颜功能的滤镜意思差不多,FFmpeg的filter(滤镜)不仅可以处理视频,还能处理音频.字幕等. 官方 ...

  6. java ffmpeg 合并视频_android ffmpeg视频剪切与合并

    android-ffmpeg-java-demo 说明 以前一直希望可以做一个播放器,所以当时就接触了ffmpeg这个库,当时打算使用JNI的方式进行底层的调用,无奈整个逻辑比较麻烦,因此进度一再搁浅 ...

  7. ffempge 循环_群晖安装 FFMPEG, 支持 VideoStation 播放 DTS EAC3, 解锁 DS1621+

    用1621+编译,耗时2.5小时,CPU占用率约为13% 使用 Docker 编译了 DS1621+ 可用的 ffmpeg,版本4.3.1-34,适配 DSM 6.2.2 系统 下载并安装ffmpeg ...

  8. ffmpeg命令转音乐为wav格式,wav格式与PCM数据相互转换,ffplay播放PCM数据

    1.卸载ffmpeg: brew uninstall ffmpeg 2.安装ffmpeg和ffplay brew install ffmpeg --with-ffplay 3.转MP3为wav ffm ...

  9. FFmpeg开发笔记(七):ffmpeg解码音频保存为PCM并使用软件播放

    若该文为原创文章,转载请注明原文出处 本文章博客地址:https://blog.csdn.net/qq21497936/article/details/108799279 各位读者,知识无穷而人力有穷 ...

  10. 【Android FFMPEG 开发】音视频基础 和 FFMPEG 编译 ( 音视频基础 | MPEG-4 标准 | Android 开发环境 | FFMPEG 交叉编译 | 安卓项目导入配置 )

    本篇博客代码及资源下载 : https://download.csdn.net/download/han1202012/10382762 文章目录 一. 音视频基础 1. 音频基础 (1) 声音要素 ...

最新文章

  1. 10个比较艰难的Java面试题与答案!
  2. 最新elasticsearch 8.0 安装配置
  3. Django之templates模板
  4. linux-practice(23-24)
  5. Java 12字符串方法
  6. 关于AndroidStudio结合百度地图Api开发的SHA1获取
  7. 插值法综合实例用matlab解决,matlab 插值法
  8. 有关自己人事档案(学籍)怎么查询攻略
  9. [转]色度抽样(4:2:0)到底是什么意思?
  10. 隔段时间网络就会变差,重启路由器恢复,这是为什么
  11. 职称计算机word中文字处理,职称计算机Word2003中文字处理考试大纲
  12. linux之mail命令发邮件
  13. 奇迹服务器数据修改,奇迹Mu商业服务端 客户端装备外观修改说明!
  14. 计算机专硕毕业论文写什么,最新硕士毕业论文进度安排怎么写
  15. 【电子书推荐】这几年看过的不错的电子书单
  16. i9 12900k参数 i9 12900k核显相当于什么水平
  17. F. Equalize the Array【学习进度条2】
  18. 网络性能衡量指标总结
  19. 什么是DNS?DNS的作用?
  20. 代码随想录训练营day8

热门文章

  1. 纯C实现的词法分析和lex实现的词法分析的对比
  2. CSS.DIV网页样式与布局学习总结
  3. An ac a day,keep wa away
  4. C#设计模式系列:抽象工厂模式(AbstractFactory)
  5. POJ_2828 Buy Ticket(线段树)
  6. 使用WUCDCreator将SCSI、RAID、SATA、SAS驱动程序集成到光盘中
  7. 用css实现了一个精致的纵向导航菜单
  8. getmenuiteminfo无法读取内存_简单科普系列—内存为什么需要组双通道原理及其作用...
  9. 在Lua中“优雅”地使用Protobuf
  10. @value取不到值_Bamboo window上环境变量 HOMEDRIVE 及 HOMEPATH 获取不到的问题