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歌中单双音轨实现原伴唱