Android 音视频深入 十一 FFmpeg和AudioTrack播放声音(附源码下载)
项目地址,求star
https://github.com/979451341/AudioVideoStudyCodeTwo/tree/master/FFmpeg%E6%92%AD%E6%94%BE%E9%9F%B3%E4%B9%90%EF%BC%88%E4%BF%9D%E7%A8%8B%E5%BA%8F%E4%B8%8D%E6%AD%BB%EF%BC%89
这个是FFmpeg解码出音频,给AudioTrack播放,这回才算是java与c语言之间合作
这回我们将会从c++里调用java函数,下面就是关于c++使用AudioTrack的代码
- 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);
- }
- }
我们再来看看c++的代码
首先注册组件,然后得到音频流
- 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;
- }
- }
获取解码器
- //获取解码器上下文
- 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();
设置解码出的声音一系列的属性,比如:单声道、双声道、采集点大小、采集率,还可以在这里对声音添加特效,
- //得到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);
- // 获取通道数 2
- int out_channer_nb = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);
通过反射能够运行java函数
- // 反射得到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");
在一边解码的时候一边给数据给AudioTrack播放
- 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);
- }
- }
- }
释放资源
- av_frame_free(&frame);
- swr_free(&swrContext);
- avcodec_close(pCodecCtx);
- avformat_close_input(&pFormatCtx);
- env->ReleaseStringUTFChars(input_, input);
FFmpeg只是音视频处理的工具,他没有播放视频和音频的能力,所以我们需要SurfaceView显示视频,AudioTrack播放声音,而且OpenGLES也能播放声音,这个后面说
下一次就是说如何将视频的声音给听换掉,也就是将音视频的解码和编码都来搞一次
Android 音视频深入 十一 FFmpeg和AudioTrack播放声音(附源码下载)的更多相关文章
- Android中Canvas绘图基础详解(附源码下载) (转)
Android中Canvas绘图基础详解(附源码下载) 原文链接 http://blog.csdn.net/iispring/article/details/49770651 AndroidCa ...
- Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO
距离上次发布(android高仿系列)今日头条 --新闻阅读器 (二) 相关的内容已经半个月了,最近利用空闲时间,把今日头条客户端完善了下.完善的功能一个一个全部实现后,就放整个源码.开发的进度就是按 ...
- Android 音视频开发(三):使用 AudioTrack 播放PCM音频
一.AudioTrack 基本使用 AudioTrack 类可以完成Android平台上音频数据的输出任务.AudioTrack有两种数据加载模式(MODE_STREAM和MODE_STATIC),对 ...
- Android 音视频深入 二十 FFmpeg视频压缩(附源码下载)
项目源码https://github.com/979451341/FFmpegCompress 这个视频压缩是通过类似在mac终端上输入FFmpeg命令来完成,意思是我们需要在Android上达到能够 ...
- Android 音视频深入 六 使用FFmpeg播放视频(附源码下载)
本篇项目地址,求starhttps://github.com/979451341/Audio-and-video-learning-materials/tree/master/FFmpeg%E6%92 ...
- Android 音视频深入 十六 FFmpeg 推流手机摄像头,实现直播 (附源码下载)
源码地址https://github.com/979451341/RtmpCamera/tree/master 配置RMTP服务器,虽然之前说了,这里就直接粘贴过来吧 1.配置RTMP服务器 这个我不 ...
- Android 音视频深入 十五 FFmpeg 推流mp4文件(附源码下载)
源码地址https://github.com/979451341/Rtmp 1.配置RTMP服务器 这个我不多说贴两个博客分别是在mac和windows环境上的,大家跟着弄 MAC搭建RTMP服务器h ...
- Android 音视频深入 十九 使用ijkplayer做个视频播放器(附源码下载)
项目地址https://github.com/979451341/Myijkplayer 前段时候我觉得FFmpeg做个视频播放器好难,虽然播放上没问题,但暂停还有通过拖动进度条来设置播放进度,这些都 ...
- Android 音视频深入 八 小视频录制(附源码下载)
本篇项目地址,求starthttps://github.com/979451341/Audio-and-video-learning-materials/tree/master/%E5%B0%8F%E ...
随机推荐
- 队列ADT
队列 队列是FIFO表,使用队列时在队尾(rear)插入元素,称之为入队(enqueue),以及在对头(front)删除并返回元素值,称之为出队(dequeue). 任何表的实现都可以用于实现队列结构 ...
- Codeforces Round #505 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Final)
A : A. Doggo Recoloring time limit per test 1 second memory limit per test 256 megabytes input stand ...
- 创建servlet程序知识点详解---servlet-day01
方法调用完后,其中的所有局部变量都会消失 ###网络架构 -CS:Client Server 客户端服务器 特点:每种平台都需要开发相对应的app, 开发成本高 功能升级需要下载最新的客户端,用户 ...
- java线程学习之线程创建
线程是程序控制的一个内部数据流.线程的状态转化如下 或者 在java中创建线程有两种方式: 1.实现runnable接口(这个比较好,推荐这个.原因是:用的时候比较灵活,相比较继承Thread类,用接 ...
- MySQL5.7 Dockerfile
#Dockerfile for mysql5.7 FROM centos COPY ["src","/src"] RUN groupadd -g 1003 my ...
- nginx和tomcat的优化
测试脚本(服务器414报错)#!/bin/bashurl=http://192.168.4.5/for i in {1..5000}do url=${url}v$i=idoneecho $url #a ...
- 开源列式存储引擎Parquet和ORC
转载自董的博客 相比传统的行式存储引擎,列式存储引擎具有更高的压缩比,更少的IO操作而备受青睐(注:列式存储不是万能高效的,很多场景下行式存储仍更加高效),尤其是在数据列(column)数很多,但每次 ...
- New需谨慎
New is Glue When you’re working in a strongly typed language like C# or Visual Basic, instantiating ...
- python版 mapreduce 矩阵相乘
参考张老师的mapreduce 矩阵相乘. 转载请注明:来自chybot的学习笔记http://i.cnblogs.com/EditPosts.aspx?postid=4541939 下面是我用pyt ...
- Python标准模块--concurrent.futures(进程池,线程池)
python为我们提供的标准模块concurrent.futures里面有ThreadPoolExecutor(线程池)和ProcessPoolExecutor(进程池)两个模块. 在这个模块里他们俩 ...