最新版本Exoplayer(MediaX)实现K歌原伴唱包括单音轨和双音轨

news/2025/2/23 6:08:20

在做K歌类项目中,原伴唱切换是必不可少的基础功能,一般一首完整的歌曲要包含MV视频+原唱音频+伴唱音频+歌词。

而原伴唱音频有两种形式:

1.双音轨:音轨一是原唱,音轨二是伴唱

2.单音轨:左声道是原唱,右声道是伴唱

至于哪个音轨或声道是原唱还是伴唱由制作歌曲的时候觉得,不同的文件可能是反的,所以一般的做法是人工对歌曲列表做标识,标明该歌曲哪一个音轨或者声道是原唱,在切换原伴唱时先获取该标识就可以知道该使用哪个音轨或者声道了。

使用Exoplayer实现原伴唱切换功能,对于双音轨歌曲很简单,有现成的接口调用进行音轨切换就可以了,对于单音轨歌曲要切换左右声道Exoplayer并没有提供现成的接口,网上也有一些方法实现,但基本上都用不了了,要么是接口被舍弃了,要么就是达不到想要的效果。

这里提供一种切实可行的方式实现单音轨音频实现切换左右声道。

因为Exoplayer支持FFmpeg扩展进行音频软解码,那么就可以在FFmpeg进行音频解码的时候对元数据进行处理来实现:仅播放左声道、仅播放右声道、播放立体声、交换左右声道,当然就有了原伴唱效果。

在上一篇文章中详细介绍了Exoplayer如何扩展FFmpeg实现音频软解码最新版本Exoplayer扩展FFmpeg音频软解码保姆级教程

那么可以在此基础上进行修改,加上单音轨原伴唱功能,上一篇文件最终我们是得到了extension-ffmpeg-release.aar来工AndroId调用,那么久还是需要修改Exoplayer中的decoder_ffpeg模块源码。先来说大致流程:

1.修改ffmpeg_jni.cc,decodePacket()函数中增加单音轨文件声道处理逻辑,并增加setChannelMode()开放给Android调用

2.修改FfmpegLibrary.java,新增native方法setChannelMode()对应JNI函数,供Exoplayer播放时调用

3.重新编译Exoplayer中的decoder_ffpeg模块,得到修改后的extension-ffmpeg-release.aar

3.Android集成aar,在播放器(一般对Exoplayer进行封装,实现自己的播放逻辑,比如我封装了ExoPlayerImpl.java)中实现切换原伴唱逻辑

这里贴出ExoPlayerImpl.java切换原伴唱部分源码供参考:

    @Override
    public void playVoice(int selectedTrackIndex,int singleMode) {
        /** singlemode 得到歌曲的原伴唱信息(单音轨---1:右声道原唱;2:左声道原唱    多音轨---1:第一音轨原唱;2:第二音轨原唱)
         * selectedTrackIndex 设置原唱或者伴唱: 0:yuan chang  1:ban chang  2:STEREO 3: L/R exchange
         */
        Log.i(TAG, "=selectedTrackIndex=" + selectedTrackIndex +"=singleMode="+singleMode+ "=audioList size=" + audioList.size());
        //切换原伴唱mode: 0-原唱,1-伴唱
        int rendererIndex = 1; // 音频渲染器的索引通常是 1
        //  int selectedTrackIndex = 1; // 需要切换到的音轨索引
        // 获取音轨列表
        MappingTrackSelector.MappedTrackInfo currentMappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
        TrackGroupArray trackGroups = currentMappedTrackInfo.getTrackGroups(rendererIndex);
        if (audioList.size() > 1) { //多音轨切换
            // 用户选择第 index 个音轨
            TrackGroup selectedGroup = trackGroups.get(selectedTrackIndex);
            // 需要切换到的音轨索引
            TrackSelectionOverride override = new TrackSelectionOverride(selectedGroup, 0);
            // 应用新音轨
            TrackSelectionParameters params = mExoPlayer.getTrackSelectionParameters()
                    .buildUpon()
                    .setOverrideForType(override)
                    .build();
            mExoPlayer.setTrackSelectionParameters(params);
        } else {//单音轨,切换左右声道
           // mExoPlayer.getAudioComponent().setVolume(selectedTrackIndex == 1 ? 0.3f : 1f);
           /* enum ChannelMode {
                CHANNEL_MODE_NORMAL,    // 正常播放 0
                CHANNEL_MODE_LEFT_ONLY, // 仅左声道 1
                CHANNEL_MODE_RIGHT_ONLY,// 仅右声道 2
                CHANNEL_MODE_SWAP       // 交换左右声道 3
            };*/
            switch (selectedTrackIndex){
                case 0: //原唱
                    ffmpegAudioRenderer.setChannelMode(singleMode==1?2:1);
                    break;
                case 1: //伴唱
                    ffmpegAudioRenderer.setChannelMode(singleMode==1?1:2);
                    break;
                case 2: //立体声
                    ffmpegAudioRenderer.setChannelMode(0);
                    break;
                case 3: //交换左右声道
                    ffmpegAudioRenderer.setChannelMode(3);
                    break;
            }
        }
    }
    public class PluginRenderFactory extends DefaultRenderersFactory {
        /**
         * @param context A {@link Context}.
         */
        public PluginRenderFactory(Context context) {
            super(context);
        }

        @Override
        protected void buildAudioRenderers(Context context, int extensionRendererMode, MediaCodecSelector mediaCodecSelector, boolean enableDecoderFallback, AudioSink audioSink, Handler eventHandler, AudioRendererEventListener eventListener, ArrayList<Renderer> out) {
            ffmpegAudioRenderer = new FfmpegAudioRenderer(eventHandler, eventListener, audioSink);
            out.add(ffmpegAudioRenderer);
            super.buildAudioRenderers(context, extensionRendererMode, mediaCodecSelector, enableDecoderFallback, audioSink, eventHandler, eventListener, out);
        }
    }
    // 初始化 ExoPlayer
        trackSelector = new DefaultTrackSelector(context);
        DefaultRenderersFactory renderersFactory = new PluginRenderFactory(context)
                .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON);

        mExoPlayer = new ExoPlayer.Builder(context, renderersFactory)
                .setTrackSelector(trackSelector)
                .build();

编译好的aar或源码点击这里


http://www.niftyadmin.cn/n/5863073.html

相关文章

Web自动化中Selenium下Chrome与Edge的Webdriver常用Options参数

目录 引言 说明 Add_argument() 添加方式 常用参数 Add_experimental_option() 添加方式 常用方法 任务结束后仍然保持浏览器打开 禁用“Chrome 正受到自动测试软件的控制”提示 设置下载路径 禁用弹窗拦截 禁用图片加载 禁用 JavaScript 注意 引言 …

UITextView删除原有字符串时,光标会上移并且光标会变高

代码运行效果如图&#xff1a; import Foundationclass TestVC: UIViewController {override func viewDidLoad() {super.viewDidLoad()let testV MyCustomTextView(frame: CGRect(x: 0, y: 130, width: SCREEN_WIDTH - 50, height: 170))self.view.addSubview(testV)testV.ba…

23种设计模式之《桥接模式(Bridge)》在c#中的应用及理解

程序设计中的主要设计模式通常分为三大类&#xff0c;共23种&#xff1a; 1. 创建型模式&#xff08;Creational Patterns&#xff09; 单例模式&#xff08;Singleton&#xff09;&#xff1a;确保一个类只有一个实例&#xff0c;并提供全局访问点。 工厂方法模式&#xff0…

近地面无人机遥感:如何利用高光谱数据反演植被生理参数?

文章目录 前言专题一、近十年近地面无人机植被遥感文献分析、传感器选择、观测方式及质量控制要点1.1. 近十余年无人机植被遥感文献分析1.2. 无人机遥感的特点及与卫星遥感的差异1.3. 无人机传感器类型、特点及选择1.4. 无人机遥感观测方式、特点与质量控制 二、辐射度量与地物…

buu-ciscn_2019_n_5-好久不见41

由于目标程序的 BSS 段&#xff08;包含 name 变量&#xff09;权限是全开的&#xff08;可读、可写、可执行&#xff09;&#xff0c;并且没有启用 NX&#xff08;No Execute&#xff0c;非执行&#xff09;保护机制&#xff0c;因此可以直接在 BSS 段上构造 Shellcode&#x…

Eclipse2024中文汉化教程(图文版)

对应Eclipse,部分人需要中文汉化,本章教程,介绍如何对Eclipse进行汉化的具体步骤。 一、汉化前的Eclipse 默认安装Eclipse的时候,默认一般都是English的,我当前版本是使用的是2024-06版本的Eclipse。 二、汉化详细步骤 点击上方菜单选项卡,Hep——Install New Software……

ARM Linux下FFmpeg+Nginx+RTMP 视频监控

一、流媒体协议 RTSP&#xff08;Real-Time Stream Protocol&#xff09;由 Real Networks 和 Netscape 共同提出的&#xff0c;基于文本的多媒体播放 控制协议。RTSP 定义流格式&#xff0c;流数据经由 RTP 传输&#xff1b;RTSP 实时效果非常好&#xff0c;适合视频聊天&…

vue中将el-table导出为excel文件

在 Vue Element UI 中&#xff0c;el-table 数据导出 Excel 文件&#xff0c;可以使用 xlsx&#xff08;SheetJS&#xff09;库进行处理。以下是详细的实现方法&#xff0c;包括安装依赖、代码示例和优化建议。 1. 安装依赖 首先&#xff0c;安装 xlsx 库&#xff1a; 复制…