最新版本Exoplayer扩展FFmpeg音频软解码保姆级教程

发布于:2025-02-22 ⋅ 阅读:(15) ⋅ 点赞:(0)

ExoPlayer 是一个开源的 Android 媒体播放库,由 Google 开发和维护,用于替代 Android 系统自带的 MediaPlayer。它提供了更强大的功能、更好的性能和更高的灵活性,适用于各种复杂的媒体播放场景。所以被广泛用于各种播放器场景。

最近项目中也使用了Exoplayer进行歌曲播放,但遇到报错:

02-14 18:26:05.078  2194  3425 I ACodec  : codec does not support config operating rate (err -2147483648)                                                                                              
02-14 18:26:05.085  1958  3430 E SoftMP3 : mp3 decoder returned error 1                                                                                                                                
02-14 18:26:05.085  2194  3425 E ACodec  : [OMX.google.mp3.decoder] ERROR(0x80001001)                                                                                                                  
02-14 18:26:05.085  2194  3425 E ACodec  : signalError(omxError 0x80001001, internalError -2147483648)                                                                                                 
02-14 18:26:05.085  2194  3425 E MediaCodec: Codec reported err 0x80001001, actionCode 0, while in state 6                                                                                             
02-14 18:26:05.086  2194  2290 E MediaCodecAudioRenderer: Audio codec error                                                                                                                            
02-14 18:26:05.086  2194  2290 E MediaCodecAudioRenderer:   java.lang.IllegalStateException                                                                                                            
02-14 18:26:05.086  2194  2290 E MediaCodecAudioRenderer:       at android.media.MediaCodec.native_dequeueInputBuffer(Native Method)                                                                   
02-14 18:26:05.086  2194  2290 E MediaCodecAudioRenderer:       at android.media.MediaCodec.dequeueInputBuffer(MediaCodec.java:2505)                                                                   
02-14 18:26:05.086  2194  2290 E MediaCodecAudioRenderer:       at androidx.media3.exoplayer.mediacodec.SynchronousMediaCodecAdapter.dequeueInputBufferIndex(SynchronousMediaCodecAdapter.java:101)    
02-14 18:26:05.086  2194  2290 E MediaCodecAudioRenderer:       at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.feedInputBuffer(MediaCodecRenderer.java:1224)                               
02-14 18:26:05.086  2194  2290 E MediaCodecAudioRenderer:       at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:818)                                         
02-14 18:26:05.086  2194  2290 E MediaCodecAudioRenderer:       at androidx.media3.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:1047)                                         
02-14 18:26:05.086  2194  2290 E MediaCodecAudioRenderer:       at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:522)                                       
02-14 18:26:05.086  2194  2290 E MediaCodecAudioRenderer:       at android.os.Handler.dispatchMessage(Handler.java:98)                                                                                 
02-14 18:26:05.086  2194  2290 E MediaCodecAudioRenderer:       at android.os.Looper.loop(Looper.java:154)                                                                                             
02-14 18:26:05.086  2194  2290 E MediaCodecAudioRenderer:       at android.os.HandlerThread.run(HandlerThread.java:61)                                                                                 
02-14 18:26:05.088  2194  2290 E ExoPlayerImplInternal: Playback error

android设备系统自带的mp3解码器报错[OMX.google.mp3.decoder],在不同的平台上测试结果都报一样的错, 硬解码不行那就只能想办法进行软解了。查资料得知Exoplayer是支持通过扩展FFmpeg进行音频软解码的,官方扩展模块说明文档为decoder_ffmpeg,那么接下来就是按照官方文档进行集成扩展了。

decoder_ffmpeg模块最终会被编译打包成aar文件供Android调用,由于依赖FFmpeg,先要下载FFmpeg源码进行编译得到所依赖的库才能成功打包aar。下面详细介绍整个流程:参考该文章ExoPlayer(AndroidX Media3) 扩展ffmpeg实现音频软解码

环境准备:
1.Ubuntu 20.04.4 LTS
2.AndroidNDK版本r26C
3.AndroidStudio 2023.1.1(配置好SDK和JDK 17.0.10)
4.ffmpeg6.0源码
5.ExoPlayer源码,AndroidX Media release分支版本

 由于一般都是在Windows上进行安卓开发,所以还需要先安装虚拟机,然后在虚拟机上安装Ubuntu,通过linux系统完成整个编译过程。

一、安装虚拟机

Wmware下载看这里WM秘钥

安装教程看这里WM安装教程

破解秘钥:

秘钥许可证
4A4RR-813DK-M81A9-4U35H-06KND

NZ4RR-FTK5H-H81C1-Q30QH-1V2LA

JU090-6039P-08409-8J0QH-2YR7F

4Y09U-AJK97-089Z0-A3054-83KLA

4C21U-2KK9Q-M8130-4V2QH-CF810

MC60H-DWHD5-H80U9-6V85M-8280D

ZA30U-DXF84-4850Q-UMMXZ-W6K8F

AC590-2XW97-48EFZ-TZPQE-MYHEA

YF39K-DLFE5-H856Z-6NWZE-XQ2XD

AC15R-FNZ16-H8DWQ-WFPNV-M28E2

CZ1J8-A0D82-489LZ-ZMZQT-P3KX6

YA11K-6YE8H-H89ZZ-EXM59-Y6AR0

 二、安装虚Ubuntu

参考Ubuntu下载安装教程 

Ubuntu与Windows共享文件夹和复制粘贴

三、下载Exoplayer和FFmpeg最新源码

目前官方已废弃Exopler2,代码已经迁移到AndroidX Media,下载完成设置FFMPEG_MODULE_PATH变量

在Ubuntu的File根目录创建Android/Project目录存放各种资源,根据自己实际放任意创建位置即可

打开ubuntu终端窗口,进入到上面新建的目录下:

cd Android/Project
git clone https://github.com/androidx/media
cd media && FFMPEG_MODULE_PATH="$(pwd)/libraries/decoder_ffmpeg/src/main"

 echo $FFMPEG_MODULE_PATH /home/xxx/Android/Project/media/libraries/decoder_ffmpeg/src/main

没有安装git的话根据提示进行安装即可。

四、下载NDK并配置NDK环境

1.官网下载NDK,根据官方说明,需要选择NDK版本ndk-linux-r26d.zip,虚拟机下载较慢,可在windows上先下好拷贝到虚拟机Ubuntu上,并解压到/Android/Project/目录下

2.下载完成后解压,设置NDK_PATH变量

cd Android/Project
unzip android-ndk-r26d-linux.zip
cd android-ndk-r26c && NDK_PATH="$(pwd)"

echo $NDK_PATH /home/xxx/Android/Project/android-ndk-r26d

3.在当前NDK目录下,执行设置编译环境指令

//设置编译平台Lunux为
HOST_PLATFORM="linux-x86_64"

//设置最小支持Android版本,通常为项目设置的minSDK版本,NDKr26最小支持SDK为21
ANDROID_ABI=21

 五、下载FFmpeg源码并配置环境变量

进入Android/Project目录进行ffmpeg源码下载,MediaX中的Exoplayer要求FFmpeg版本6.0

git clone git://source.ffmpeg.org/ffmpeg 
cd ffmpeg 
//拉取与最新Exoplayer匹配的版本
git checkout release/6.0 
//配置环境变量
FFMPEG_PATH="$(pwd)"

echo $FFMPEG_PATH /home/xxx/Android/Project/ffmpeg

六、配置所需要支持的音频解码器类型

ffmpeg所支持音频格式官方说明点击这里查看 

//在ffmpeg目录下执行
ENABLED_DECODERS=(aac ac3 mp3 flac)

七、Exoplayer源码关联FFmpeg源码

将ExoPlayer源码中ffmpeg模块jni与ffmpeg源码关联,关联成功后会在jni目录中生成一个快捷方式指向ffmpeg源码目录

//在ffmpeg目录下执行关联指令

cd "${FFMPEG_MODULE_PATH}/jni"
ln -s "$FFMPEG_PATH" ffmpeg 

八、编译FFmpeg

Exoplayer源码中已经帮我们配好了编译脚本build_ffmpeg.sh,执行即可,带上之前配置的环境变量

//在Exoplayer源码decoder_ffmpeg模块,jni目录下执行编译

./build_ffmpeg.sh \ "${FFMPEG_MODULE_PATH}" "${NDK_PATH}" "${HOST_PLATFORM}" "${ANDROID_ABI}" "${ENABLED_DECODERS[@]}"

编译过程可能报错,基本根据报错信息处理就可以了,我碰到的问题是关联的ffmpeg目录找不到,实际上是关联成功了的,脚本中直接把关联路径改成绝对路径就可以了,报错的位置如下:

 编译成功后,会在ffmepg目录下生成一个android-libs目录 

 里面有各个不同架构平台的库,默认生成的是.a静态库文件,android上要用动态so库文件,修改一下编译脚本重新编译即可:

结果如下:

 九、编译decoder_ffmpge模块打包成aar文件供android调用

进入到Exoplayer源码更目录执行编译打包指令

./gradlew lib-decoder-ffmpeg:assembleRelease

报错的话更近提示进行处理即可,大概率就是JDK和SDK没有安装或者环境没有配置对

Ubuntu安装android sdk教程

Ubuntu安装JDK教程

编译成功后会在\libraries\decoder_ffmpeg\buildout\outputs\aar\目录生成aar包 

十、Android项目中使用aar实现音频软解码 

复制生成的aar包到项目libs目录,修改app下的build.gradle文件,引用aar包
implementation(files("libs/extension-ffmpeg-release.aar"))
自定义DefaultRenderersFactory,构造ExoPlayer实例时传入,日志中有ffmpeg相关信息代表加载成功。

    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);
        }
    }


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

 Android中使用可能出现编译不通过问题,大概率是Android项目使用的各种编译环境版本与编译aar时使用的不一致,Exoplayer源码使用如下配置:

建议尽量使用相同配置 ,还有就是我Ubuntu配置的JDK是17.0.14版本,所以AndroidStudio编译也要使用 相同版本JDK

至此大功告成! 

下一篇介绍Exoplayer+FFmpeg实现K歌场景中的切换原伴唱功能K歌中单双音轨实现原伴唱