ExoPlayer FFmpeg扩展的编译和使用

3,041 阅读2分钟

编译环境

编译平台:ubuntu 16.04LTS

ffmpeg版本:release/4.2(exoplayer2.18.0版本官方推荐的)

ndk版本:android-ndk-r21e(exoplayer2.18.0版本官方进行过测试)

这里主要是参考官方的文档来进行编译的,我这一篇是参考2.18.0版本官方文档编译的。

如果这里和官方文档不一致,大家按照官方文档进行编译。

拉取ExoPlayer代码和ffmpeg代码

clone ExoPlayer

git clone https://github.com/google/ExoPlayer.git

clone ffmpeg 然后切换分支

git clone git://source.ffmpeg.org/ffmpeg
cd ffmpeg
git checkout release/4.2

最好是能科学上网要不然这拉取代码的速度真的是栓Q

配置终端的变量

刚clone下来的ExoPlay项目ffmpeg扩展对应的路径

cd "<path to EXOPlayer project checkout>"
FFMPEG_MODULE_PATH="$(pwd)/extensions/ffmpeg/src/main"

NDK的路径

NDK_PATH="<path to Android NDK>"

配置系统环境

HOST_PLATFORM="linux-x86_64"

配置ffmpeg的路径

FFMPEG_PATH="<这里是刚刚clone下来的ffmpeg4.2版本的路径>"

配置要支持音频格式

ExoPlayer FFmpeg 扩展支持的所有音频格式

Sample formatDecoder name(s)
Vorbisvorbis
Opusopus
FLACflac
ALACalac
PCM μ-lawpcm_mulaw
PCM A-lawpcm_alaw
MP1, MP2, MP3mp3
AMR-NBamrnb
AMR-WBamrwb
AACaac
AC-3ac3
E-AC-3eac3
DTS, DTS-HDdca
TrueHDmlp truehd

看到这里我一脸懵逼,上面除了mp3和pcm其他的我都不认识。 然后就在网上找到了这个,对这些格式有个简单的了解吧。

名称无损压缩文件扩展名
Monkey's Audio✔️.ape
FLAC(Free Lossless Audio Codec)✔️.flac
ALAC(Apple Lossless Audio Codec)✔️.m4a/.caf
MP3(MPEG Audio Layer III).mp3
WMA(Windows Media Audio).wma
AAC(Advanced Audio Coding).acc/.mp4/.m4a
Vorbis.ogg
Speex.spx
Opus.opus
Ogg .ogg
WAV(Waveform Audio File Format) .wav
AIFF(Audio Interchange File Format) .aiff、.aif

配置要支持音频格式

这里就这样配置吧,大家就按照自己的需求配置,也可以全部写上。

ENABLED_DECODERS=(vorbis opus flac alac mp3 aac ac3 eac3)

创建ffmpeg源码的链接

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

编辑build_ffmpeg.sh(可选)

打开build_ffmpeg.sh 可以编辑它,选择你要编译的平台armeabi-v7aarm64-v8ax86 and x86_64

这里全部都要,就不编辑它了。

最后编译

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

可能会碰到的问题:

xxx/toolchains/llvm/prebuilt/linux-x86_64/xxx   not found

我碰到这个问题的原因是我没去官网下载对应的NDK,我是直接用AndroidStudio 里的SdkManadager下载对应的Ndk,然后找到AndroidStudio对应的SDK里面找到对应的ndk版本的路径。

一定要去官网下载对应的NDK

image.png

然后重新配置NDK的路径,最后编译就好了。

编译得到ExoPlayer ffmpeg 扩展的aar

在AndroidStudio中打开ExoPlayer这个项目(就是最开始clone的Exoplayer的路径),然后在终端(用ubuntu终端也行)输入下面命令:

./gradlew extension-ffmpeg:assembleRelease

最后编译完成,在下图可以找到编译出来的aar,然后拿到你自己的项目当中取用

image.png

编译可能会出现的问题:

> Failed to apply plugin 'com.android.internal.application'.
   > Android Gradle plugin requires Java 11 to run. You are currently using Java 1.8.
     Your current JDK is located in  /usr/lib/jvm/java-8-openjdk-amd64/jre
     You can try some of the following options:
       - changing the IDE settings.
       - changing the JAVA_HOME environment variable.
       - changing `org.gradle.java.home` in `gradle.properties`.

可以在工程的gradle.properties加上配置:

org.gradle.java.home=<jdk 11 版本的路径>

可以不用下载直接用androidStudio的路径

org.gradle.java.home=/home/jackiehou/Android_studio/AS/android-studio/jre

下一个问题:ERROR: CMake '3.21.0' or higher was not found in SDK

image.png

这里CMake最高只有3.18.0,androidStudio也是最新版本,如果sdkmanager有高版本的cmake,大家直接在这里安装就行了。

如果没有就要去CMake的官网下载对应的cmake,这里我们用3.23.2版本的

image.png

下载上图选中的地方,然后解压。

配置特定版本的 CMake

将其添加到项目的 local.properties 文件中,如下所示。

# If you set this property, Gradle no longer uses PATH to find CMake.
cmake.dir = "path-to-cmake"

在自己的项目中使用编译好的aar

依赖之前编译好的aar

implementation files('libs/extension-ffmpeg-release.aar')

添加FfmpegAudioRenderer,并打开这个扩展

private val mRenderFactory =
    object : DefaultRenderersFactory(MyApp.instance.applicationContext) {
        override fun buildAudioRenderers(
            context: Context,
            extensionRendererMode: Int,
            mediaCodecSelector: MediaCodecSelector,
            enableDecoderFallback: Boolean,
            audioSink: AudioSink,
            eventHandler: Handler,
            eventListener: AudioRendererEventListener,
            out: ArrayList<Renderer>
        ) {
            //添加FfmpegAudioRenderer
            out.add(FfmpegAudioRenderer())
            super.buildAudioRenderers(
                context,
                extensionRendererMode,
                mediaCodecSelector,
                enableDecoderFallback,
                audioSink,
                eventHandler,
                eventListener,
                out
            )
        }
    }.apply {
        setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER)
    }

播放器实例化

val player: ExoPlayer by lazy {
    Log.d("ExoPlayer", "${FfmpegLibrary.isAvailable()}")
    if (FfmpegLibrary.isAvailable() && useFfmpeg) {
        ExoPlayer.Builder(MyApp.instance.applicationContext, mRenderFactory)
    } else {
        ExoPlayer.Builder(MyApp.instance.applicationContext)
    }
   .build()
        .also {
            it.addAnalyticsListener(EventLogger())
            it.addListener(listener)
        }
}

播放

//这里用exoPlayer Demo里找了一个没使用扩展无法播放的资源
val url = "https://storage.googleapis.com/exoplayer-test-media-1/flac/play.flac"
val mediaItem: MediaItem = MediaItem.fromUri(url)
player.setMediaItem(mediaItem)
player.prepare()
player.play()