项目地址,求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的代码

  1. private AudioTrack audioTrack;
  2. // 这个方法 是C进行调用 通道数
  3. public void createTrack(int sampleRateInHz,int nb_channals) {
  4.  
  5. int channaleConfig;//通道数
  6. if (nb_channals == 1) {
  7. channaleConfig = AudioFormat.CHANNEL_OUT_MONO;
  8. } else if (nb_channals == 2) {
  9. channaleConfig = AudioFormat.CHANNEL_OUT_STEREO;
  10. }else {
  11. channaleConfig = AudioFormat.CHANNEL_OUT_MONO;
  12. }
  13. int buffersize=AudioTrack.getMinBufferSize(sampleRateInHz,
  14. channaleConfig, AudioFormat.ENCODING_PCM_16BIT);
  15. audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,sampleRateInHz,channaleConfig,
  16. AudioFormat.ENCODING_PCM_16BIT,buffersize,AudioTrack.MODE_STREAM);
  17. audioTrack.play();
  18. }
  19.  
  20. //C传入音频数据
  21. public void playTrack(byte[] buffer, int lenth) {
  22. if (audioTrack != null && audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
  23. audioTrack.write(buffer, 0, lenth);
  24. }
  25. }

我们再来看看c++的代码

首先注册组件,然后得到音频流

  1. av_register_all();
  2. AVFormatContext *pFormatCtx = avformat_alloc_context();
  3. //open
  4. if (avformat_open_input(&pFormatCtx, input, NULL, NULL) != 0) {
  5. LOGE("%s","打开输入视频文件失败");
  6. return;
  7. }
  8. //获取视频信息
  9. if(avformat_find_stream_info(pFormatCtx,NULL) < 0){
  10. LOGE("%s","获取视频信息失败");
  11. return;
  12. }
  13. int audio_stream_idx=-1;
  14. int i=0;
  15. for (int i = 0; i < pFormatCtx->nb_streams; ++i) {
  16. if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
  17. LOGE(" 找到音频id %d", pFormatCtx->streams[i]->codec->codec_type);
  18. audio_stream_idx=i;
  19. break;
  20. }
  21. }

获取解码器

  1. //获取解码器上下文
  2. AVCodecContext *pCodecCtx=pFormatCtx->streams[audio_stream_idx]->codec;
  3. //获取解码器
  4. AVCodec *pCodex = avcodec_find_decoder(pCodecCtx->codec_id);
  5. //打开解码器
  6. if (avcodec_open2(pCodecCtx, pCodex, NULL)<0) {
  7. }

设置缓存区,保存解码前后的数据

  1. //申请avpakcet,装解码前的数据
  2. AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));
  3. //申请avframe,装解码后的数据
  4. AVFrame *frame = av_frame_alloc();

设置解码出的声音一系列的属性,比如:单声道、双声道、采集点大小、采集率,还可以在这里对声音添加特效,

  1. //得到SwrContext ,进行重采样,具体参考http://blog.csdn.net/jammg/article/details/52688506
  2. SwrContext *swrContext = swr_alloc();
  3. //缓存区
  4. uint8_t *out_buffer = (uint8_t *) av_malloc(44100 * 2);
  5. //输出的声道布局(立体声)
  6. uint64_t out_ch_layout=AV_CH_LAYOUT_STEREO;
  7. //输出采样位数 16位
  8. enum AVSampleFormat out_formart=AV_SAMPLE_FMT_S16;
  9. //输出的采样率必须与输入相同
  10. int out_sample_rate = pCodecCtx->sample_rate;
  11.  
  12. //swr_alloc_set_opts将PCM源文件的采样格式转换为自己希望的采样格式
  13. swr_alloc_set_opts(swrContext, out_ch_layout, out_formart, out_sample_rate,
  14. pCodecCtx->channel_layout, pCodecCtx->sample_fmt, pCodecCtx->sample_rate, 0,
  15. NULL);
  16.  
  17. swr_init(swrContext);
  18. // 获取通道数 2
  19. int out_channer_nb = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);

通过反射能够运行java函数

  1. // 反射得到Class类型
  2. jclass david_player = env->GetObjectClass(instance);
  3. // 反射得到createAudio方法
  4. jmethodID createAudio = env->GetMethodID(david_player, "createTrack", "(II)V");
  5. // 反射调用createAudio
  6. env->CallVoidMethod(instance, createAudio, 44100, out_channer_nb);
  7. jmethodID audio_write = env->GetMethodID(david_player, "playTrack", "([BI)V");

在一边解码的时候一边给数据给AudioTrack播放

  1. while (av_read_frame(pFormatCtx, packet) >= 0) {
  2. if (packet->stream_index == audio_stream_idx) {
  3. // 解码 mp3 编码格式frame----pcm frame
  4. avcodec_decode_audio4(pCodecCtx, frame, &got_frame, packet);
  5. if (got_frame) {
  6. LOGE("解码");
  7. swr_convert(swrContext, &out_buffer, 44100 * 2, (const uint8_t **) frame->data, frame->nb_samples);
  8. // 缓冲区的大小
  9. int size = av_samples_get_buffer_size(NULL, out_channer_nb, frame->nb_samples,
  10. AV_SAMPLE_FMT_S16, 1);
  11. jbyteArray audio_sample_array = env->NewByteArray(size);
  12. env->SetByteArrayRegion(audio_sample_array, 0, size, (const jbyte *) out_buffer);
  13. env->CallVoidMethod(instance, audio_write, audio_sample_array, size);
  14. env->DeleteLocalRef(audio_sample_array);
  15. }
  16. }
  17. }

释放资源

  1. av_frame_free(&frame);
  2. swr_free(&swrContext);
  3. avcodec_close(pCodecCtx);
  4. avformat_close_input(&pFormatCtx);
  5. env->ReleaseStringUTFChars(input_, input);

FFmpeg只是音视频处理的工具,他没有播放视频和音频的能力,所以我们需要SurfaceView显示视频,AudioTrack播放声音,而且OpenGLES也能播放声音,这个后面说

下一次就是说如何将视频的声音给听换掉,也就是将音视频的解码和编码都来搞一次

Android 音视频深入 十一 FFmpeg和AudioTrack播放声音(附源码下载)的更多相关文章

  1. Android中Canvas绘图基础详解(附源码下载) (转)

    Android中Canvas绘图基础详解(附源码下载) 原文链接  http://blog.csdn.net/iispring/article/details/49770651   AndroidCa ...

  2. Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO

    距离上次发布(android高仿系列)今日头条 --新闻阅读器 (二) 相关的内容已经半个月了,最近利用空闲时间,把今日头条客户端完善了下.完善的功能一个一个全部实现后,就放整个源码.开发的进度就是按 ...

  3. Android 音视频开发(三):使用 AudioTrack 播放PCM音频

    一.AudioTrack 基本使用 AudioTrack 类可以完成Android平台上音频数据的输出任务.AudioTrack有两种数据加载模式(MODE_STREAM和MODE_STATIC),对 ...

  4. Android 音视频深入 二十 FFmpeg视频压缩(附源码下载)

    项目源码https://github.com/979451341/FFmpegCompress 这个视频压缩是通过类似在mac终端上输入FFmpeg命令来完成,意思是我们需要在Android上达到能够 ...

  5. Android 音视频深入 六 使用FFmpeg播放视频(附源码下载)

    本篇项目地址,求starhttps://github.com/979451341/Audio-and-video-learning-materials/tree/master/FFmpeg%E6%92 ...

  6. Android 音视频深入 十六 FFmpeg 推流手机摄像头,实现直播 (附源码下载)

    源码地址https://github.com/979451341/RtmpCamera/tree/master 配置RMTP服务器,虽然之前说了,这里就直接粘贴过来吧 1.配置RTMP服务器 这个我不 ...

  7. Android 音视频深入 十五 FFmpeg 推流mp4文件(附源码下载)

    源码地址https://github.com/979451341/Rtmp 1.配置RTMP服务器 这个我不多说贴两个博客分别是在mac和windows环境上的,大家跟着弄 MAC搭建RTMP服务器h ...

  8. Android 音视频深入 十九 使用ijkplayer做个视频播放器(附源码下载)

    项目地址https://github.com/979451341/Myijkplayer 前段时候我觉得FFmpeg做个视频播放器好难,虽然播放上没问题,但暂停还有通过拖动进度条来设置播放进度,这些都 ...

  9. Android 音视频深入 八 小视频录制(附源码下载)

    本篇项目地址,求starthttps://github.com/979451341/Audio-and-video-learning-materials/tree/master/%E5%B0%8F%E ...

随机推荐

  1. 队列ADT

    队列 队列是FIFO表,使用队列时在队尾(rear)插入元素,称之为入队(enqueue),以及在对头(front)删除并返回元素值,称之为出队(dequeue). 任何表的实现都可以用于实现队列结构 ...

  2. 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 ...

  3. 创建servlet程序知识点详解---servlet-day01

    方法调用完后,其中的所有局部变量都会消失 ###网络架构 -CS:Client Server  客户端服务器 特点:每种平台都需要开发相对应的app, 开发成本高  功能升级需要下载最新的客户端,用户 ...

  4. java线程学习之线程创建

    线程是程序控制的一个内部数据流.线程的状态转化如下 或者 在java中创建线程有两种方式: 1.实现runnable接口(这个比较好,推荐这个.原因是:用的时候比较灵活,相比较继承Thread类,用接 ...

  5. MySQL5.7 Dockerfile

    #Dockerfile for mysql5.7 FROM centos COPY ["src","/src"] RUN groupadd -g 1003 my ...

  6. nginx和tomcat的优化

    测试脚本(服务器414报错)#!/bin/bashurl=http://192.168.4.5/for i in {1..5000}do url=${url}v$i=idoneecho $url #a ...

  7. 开源列式存储引擎Parquet和ORC

    转载自董的博客 相比传统的行式存储引擎,列式存储引擎具有更高的压缩比,更少的IO操作而备受青睐(注:列式存储不是万能高效的,很多场景下行式存储仍更加高效),尤其是在数据列(column)数很多,但每次 ...

  8. New需谨慎

    New is Glue When you’re working in a strongly typed language like C# or Visual Basic, instantiating ...

  9. python版 mapreduce 矩阵相乘

    参考张老师的mapreduce 矩阵相乘. 转载请注明:来自chybot的学习笔记http://i.cnblogs.com/EditPosts.aspx?postid=4541939 下面是我用pyt ...

  10. Python标准模块--concurrent.futures(进程池,线程池)

    python为我们提供的标准模块concurrent.futures里面有ThreadPoolExecutor(线程池)和ProcessPoolExecutor(进程池)两个模块. 在这个模块里他们俩 ...