android基于ffmpeg的简单视频播发器 音频播放

2024-05-11 06:32

本文主要是介绍android基于ffmpeg的简单视频播发器 音频播放,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

音频播放没啥好说的,直接复制这篇文章http://www.jianshu.com/p/68cdbee598cd

上代码

java

private void init() {setContentView(R.layout.activity_main);
        SurfaceView surfaceView = findViewById(R.id.surface_view);

        surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {@Override
            public void surfaceCreated(SurfaceHolder holder) {}@Override
            public void surfaceChanged(final SurfaceHolder holder, int format, int width, int height) {Thread thread = new Thread(){@Override
                    public void run() {super.run();
                        String videoPath = "/storage/emulated/0/baiduNetdisk/season09.mp4";
//                        videoPlay(videoPath,holder.getSurface());
                        audioPlay(videoPath);
                    }};
                thread.start();
            }@Override
            public void surfaceDestroyed(SurfaceHolder holder) {}});
    }public AudioTrack createAudio(int sampleRateInHz, int nb_channels) {int channelConfig;
        if (nb_channels == 1) {channelConfig = AudioFormat.CHANNEL_OUT_MONO;
        } else if (nb_channels == 2) {channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
        } else {channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
        }int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
        int minBufferSize = AudioTrack.getMinBufferSize(sampleRateInHz,
                channelConfig, audioFormat);

        AudioTrack audio = new AudioTrack(AudioManager.STREAM_MUSIC, // 指定流的类型
                sampleRateInHz, // 设置音频数据的采样率 32k,如果是44.1k就是44100
                channelConfig, // 设置输出声道为双声道立体声,而CHANNEL_OUT_MONO类型是单声道
                audioFormat, // 设置音频数据块是8位还是16位,这里设置为16位。好像现在绝大多数的音频都是16位的了
                minBufferSize, AudioTrack.MODE_STREAM // 设置模式类型,在这里设置为流类型,另外一种MODE_STATIC貌似没有什么效果
        );
        // audio.play(); // 启动音频设备,下面就可以真正开始音频数据的播放了
        return audio;
    }
调用c++代码

public native void audioPlay(String path);
c++代码

#define MAX_AUDIO_FRME_SIZE 48000 * 4
extern "C"
JNIEXPORT void JNICALL
Java_com_example_ffmpegrun_MainActivity_audioPlay(JNIEnv *env, jobject instance, jstring path_) {const char *path = env->GetStringUTFChars(path_, 0);

    // TODO

    av_register_all();
    AVFormatContext *fmt_ctx = avformat_alloc_context();
    if (avformat_open_input(&fmt_ctx, path, NULL, NULL) < 0) {return;
    }if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {return;
    }AVStream *avStream = NULL;
    int audio_stream_index = -1;
    for (int i = 0; i < fmt_ctx->nb_streams; i++) {if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {avStream = fmt_ctx->streams[i];
            audio_stream_index = i;
            break;
        }}if (audio_stream_index == -1) {return;
    }AVCodecContext *codec_ctx = avcodec_alloc_context3(NULL);
    avcodec_parameters_to_context(codec_ctx, avStream->codecpar);

    AVCodec *avCodec = avcodec_find_decoder(codec_ctx->codec_id);
    if (avcodec_open2(codec_ctx, avCodec, NULL) < 0) {return;
    }SwrContext *swr_ctx = swr_alloc();

    enum AVSampleFormat in_sample_fmt = codec_ctx->sample_fmt;

    enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;

    int in_sample_rate = codec_ctx->sample_rate;

    int out_sample_rate = in_sample_rate;

    uint64_t in_ch_layout = codec_ctx->channel_layout;

    uint64_t out_ch_layout = AV_CH_LAYOUT_STEREO;


    swr_alloc_set_opts(swr_ctx,
                       out_ch_layout, out_sample_fmt, out_sample_rate,
                       in_ch_layout, in_sample_fmt, in_sample_rate,
                       0, NULL);
    swr_init(swr_ctx);

    int out_channel_nb = av_get_channel_layout_nb_channels(out_ch_layout);

    jclass player_class = env->GetObjectClass(instance);
    jmethodID create_audio_track_mid = env->GetMethodID(player_class, "createAudio",
                                                        "(II)Landroid/media/AudioTrack;");
    jobject audio_track = env->CallObjectMethod(instance, create_audio_track_mid,
                                                out_sample_rate, out_channel_nb);


    jclass audio_track_class = env->GetObjectClass(audio_track);
    jmethodID audio_track_play_mid = env->GetMethodID(audio_track_class, "play", "()V");
    jmethodID audio_track_stop_mid = env->GetMethodID(audio_track_class, "stop", "()V");
    env->CallVoidMethod(audio_track, audio_track_play_mid);

    jmethodID audio_track_write_mid = env->GetMethodID(audio_track_class, "write",
                                                       "([BII)I");


    uint8_t *out_buffer = (uint8_t *) av_malloc(MAX_AUDIO_FRME_SIZE);

    AVPacket *pkt = (AVPacket *) malloc(sizeof(AVPacket));
    int ret;
    while (1) {if (av_read_frame(fmt_ctx, pkt) < 0){av_packet_unref(pkt);
            break;
        }ret = avcodec_send_packet(codec_ctx, pkt);
        if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {av_packet_unref(pkt);
            continue;
        }AVFrame *frame = av_frame_alloc();

        ret = avcodec_receive_frame(codec_ctx, frame);
        if (ret < 0 && ret != AVERROR_EOF) {av_packet_unref(pkt);
            av_frame_free(&frame);
            continue;
        }swr_convert(swr_ctx, &out_buffer, MAX_AUDIO_FRME_SIZE,
                    (const uint8_t **) frame->data,
                    frame->nb_samples);
        int out_buffer_size = av_samples_get_buffer_size(NULL, out_channel_nb,
                                                         frame->nb_samples, out_sample_fmt,
                                                         1);

        jbyteArray audio_sample_array = env->NewByteArray(out_buffer_size);
        jbyte *sample_bytep = env->GetByteArrayElements(audio_sample_array, NULL);

        memcpy(sample_bytep, out_buffer, (size_t) out_buffer_size);
        env->ReleaseByteArrayElements(audio_sample_array, sample_bytep, 0);


        env->CallIntMethod(audio_track, audio_track_write_mid,
                           audio_sample_array, 0, out_buffer_size);

        env->DeleteLocalRef(audio_sample_array);

        av_frame_free(&frame);

        av_packet_unref(pkt);
    }env->CallVoidMethod(audio_track, audio_track_stop_mid);
    av_free(out_buffer);
    swr_free(&swr_ctx);
    avcodec_close(codec_ctx);
    avformat_close_input(&fmt_ctx);

    env->ReleaseStringUTFChars(path_, path);
}
引入的包

extern "C" {
#include "libavformat/avformat.h"
#include "libavfilter/avfiltergraph.h"
#include <libswresample/swresample.h>
}
AudioTrack还是挺好的,可以正常播放声音,不需要进行其他设置,看别人有用opensl来播放音频,没研究过,听说很强大













这篇关于android基于ffmpeg的简单视频播发器 音频播放的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/978761

相关文章

2.1/5.1和7.1声道系统有什么区别? 音频声道的专业知识科普

《2.1/5.1和7.1声道系统有什么区别?音频声道的专业知识科普》当设置环绕声系统时,会遇到2.1、5.1、7.1、7.1.2、9.1等数字,当一遍又一遍地看到它们时,可能想知道它们是什... 想要把智能电视自带的音响升级成专业级的家庭影院系统吗?那么你将面临一个重要的选择——使用 2.1、5.1 还是

利用Python编写一个简单的聊天机器人

《利用Python编写一个简单的聊天机器人》这篇文章主要为大家详细介绍了如何利用Python编写一个简单的聊天机器人,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 使用 python 编写一个简单的聊天机器人可以从最基础的逻辑开始,然后逐步加入更复杂的功能。这里我们将先实现一个简单的

Python视频处理库VidGear使用小结

《Python视频处理库VidGear使用小结》VidGear是一个高性能的Python视频处理库,本文主要介绍了Python视频处理库VidGear使用小结,文中通过示例代码介绍的非常详细,对大家的... 目录一、VidGear的安装二、VidGear的主要功能三、VidGear的使用示例四、VidGea

使用IntelliJ IDEA创建简单的Java Web项目完整步骤

《使用IntelliJIDEA创建简单的JavaWeb项目完整步骤》:本文主要介绍如何使用IntelliJIDEA创建一个简单的JavaWeb项目,实现登录、注册和查看用户列表功能,使用Se... 目录前置准备项目功能实现步骤1. 创建项目2. 配置 Tomcat3. 项目文件结构4. 创建数据库和表5.

使用PyQt5编写一个简单的取色器

《使用PyQt5编写一个简单的取色器》:本文主要介绍PyQt5搭建的一个取色器,一共写了两款应用,一款使用快捷键捕获鼠标附近图像的RGB和16进制颜色编码,一款跟随鼠标刷新图像的RGB和16... 目录取色器1取色器2PyQt5搭建的一个取色器,一共写了两款应用,一款使用快捷键捕获鼠标附近图像的RGB和16

四种简单方法 轻松进入电脑主板 BIOS 或 UEFI 固件设置

《四种简单方法轻松进入电脑主板BIOS或UEFI固件设置》设置BIOS/UEFI是计算机维护和管理中的一项重要任务,它允许用户配置计算机的启动选项、硬件设置和其他关键参数,该怎么进入呢?下面... 随着计算机技术的发展,大多数主流 PC 和笔记本已经从传统 BIOS 转向了 UEFI 固件。很多时候,我们也

基于Qt开发一个简单的OFD阅读器

《基于Qt开发一个简单的OFD阅读器》这篇文章主要为大家详细介绍了如何使用Qt框架开发一个功能强大且性能优异的OFD阅读器,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 目录摘要引言一、OFD文件格式解析二、文档结构解析三、页面渲染四、用户交互五、性能优化六、示例代码七、未来发展方向八、结论摘要

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

MyBatis框架实现一个简单的数据查询操作

《MyBatis框架实现一个简单的数据查询操作》本文介绍了MyBatis框架下进行数据查询操作的详细步骤,括创建实体类、编写SQL标签、配置Mapper、开启驼峰命名映射以及执行SQL语句等,感兴趣的... 基于在前面几章我们已经学习了对MyBATis进行环境配置,并利用SqlSessionFactory核

Android WebView的加载超时处理方案

《AndroidWebView的加载超时处理方案》在Android开发中,WebView是一个常用的组件,用于在应用中嵌入网页,然而,当网络状况不佳或页面加载过慢时,用户可能会遇到加载超时的问题,本... 目录引言一、WebView加载超时的原因二、加载超时处理方案1. 使用Handler和Timer进行超