V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
glumess
V2EX  ›  Android

老生常谈 -- Android FFmpeg 动态库的编译问题轻松搞定

  •  
  •   glumess · 2021-10-30 13:35:53 +08:00 · 4992 次点击
    这是一个创建于 899 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前几天发了一篇 FFmpeg 调用 Android MediaCodec 进行硬解码 的文章,这里面的技术点不算太难,也还是调用 FFmpeg 的常用接口操作,但重点在于 FFmpeg 的版本选择以及编译选项要开启 MediaCodec 才行。

    关于 FFmpeg 的编译,是个老生常谈的话题了,很多初学者都会卡在怎么编译动态库 so 的问题上,这其实也是 Android 开发转音视频的一大拦路虎,一行 FFmpeg 代码都没来得及写呢,就得先折腾好久编译问题。

    当然了,编译麻烦肯定是 FFmpeg 的锅。因为它的不断升级,从早期 2.x 版本到现在的 4.x 版本,调用接口发生了变化,编译选项也调整了不少,但网上的各种 Android so 动态库编译文章可没有对应更新哦,有的教程还停留在 2.x 版本上,如果你照着去编译了,这里面肯定会有兼容性问题的。

    举几个例子:

    • FFmpeg 源码里面的文件要修改吗?

    早期的编译版本还要在 FFmpeg 里面修改一些源码才行,最常见的就是下面的代码:

    SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'
    LIB_INSTALL_EXTRA_CMD='?(RANLIB)"$(LIBDIR)/$(LIBNAME)"'
    SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'
    SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR)$(SLIBNAME)'
    

    以前需要修改编译后库名字的连接方式,但是在最新版本中是不用了(最新版指的是 ffmpeg 的 release/4.4 分支版本)。

    另外,在实际编译中也不需要修改任何 FFmpeg 源码的。

    • Android NDK 要用哪个版本?

    这也是个常见的兼容性问题。

    选择 NDK 版本实际上是在选择编译器,早先编译可能用的是 GCC 编译,后来 Google 在 NDK r18b 版本移除了 GCC 编译工具,具体可以参考如下链接:

    NDK 修订历史记录

    所以现在最新的动态库编译都是用 Clang 进行操作的,为了跟上时代步伐,也就不要用之前的 NDK 版本了,直接上最新的。


    为了避免大家把精力消耗在 FFmpeg 的编译上,直接就给出一个 Github Repo ,将编译脚本都放在这个仓库上了。

    地址如下:

    https://github.com/glumes/ffmpeg_android

    FFmpeg 编译

    其中 FFmpeg 源码是作为该仓库的一个子模块 Submodules 的形式加载进来的,在下载时要注意一下:

    git clone --recursive https://github.com/glumes/ffmpeg_android
    

    下载后,进入到 build_android.sh 文件中,将 NDK 替换成你自己的路径,最好也用 r20b 版本的,保持一致。

    #!/bin/bash
     
    #你的 NDK 路径
    NDK=/Users/glumes/Downloads/android-ndk-r20b
    TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64
    API=21
    

    替换后,给脚本可执行权限就能运行了,编译后的动态库在 ffmpeg_library 文件夹中,目前仅编译了 armeabi-v7a 架构的。

    android 文件夹内对应加载 so 的 Android 工程,也是 FFmpeg 调用 Android MediaCodec 的源码。

    这个工程目录也是不需要修改 FFmpeg 的,并且关于 FFmpeg 的很多编译选项开关放在了 config-env.sh 目录中,有需要可以在文件内做修改,不影响主的编译脚本运行。

    顺便贴一下源码:

    这里是具体执行编译的函数,函数用到的一些参数要在外面定义好:

    function build_android
    {
    echo "Compiling FFmpeg for $CPU"
    
    ./configure \
        --prefix=$PREFIX \
        --libdir=$LIB_DIR \
        --enable-shared \
        --disable-static \
        --enable-jni \
        --disable-doc \
        --disable-symver \
        --disable-programs \
        --target-os=android \
        --arch=$ARCH \
        --cpu=$CPU \
        --cc=$CC \
        --cxx=$CXX \
        --enable-cross-compile \
        --sysroot=$SYSROOT \
        --extra-cflags="-Os -fpic $OPTIMIZE_CFLAGS" \
        --extra-ldflags="$ADDI_LDFLAGS" \
        --disable-asm \
        # 这些编译参数在 config-env.sh 文件中定义了
        $COMMON_FF_CFG_FLAGS
    make clean
    make -j8 # 这里是定义用几个 CPU 编译
    make install
    echo "The Compilation of FFmpeg for $CPU is completed"
    }
    

    接下来定义好相关参数,就可以执行了:

    // 编译的 configure 可执行文件在 ffmpeg 源码目录中,要先进入到目录里
    cd ffmpeg
    
    // 定义好编译的架构
    OUTPUT_FOLDER="armeabi-v7a"
    ARCH="arm"
    CPU="armv7-a"
    TOOL_CPU_NAME=armv7a
    TOOL_PREFIX="$TOOLCHAIN/bin/arm-linux-androideabi"
     
    CC="$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang"
    CXX="$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++"
    SYSROOT="$NDK/toolchains/llvm/prebuilt/darwin-x86_64/sysroot"
    PREFIX="${PWD}/../ffmpeg_library/android/$OUTPUT_FOLDER"
    LIB_DIR="${PWD}/../ffmpeg_library/android/libs/$OUTPUT_FOLDER"
    OPTIMIZE_CFLAGS="-march=$CPU"
    build_android
    

    由于我们的编译脚本不放在 FFmpeg 源码目录中,所以要对路径做一些修改,这样可以绝对地不改动任何 FFmpeg 内容了。

    通过上述的参数设定,应该就可以编译出正确的 Android 动态库了,如果你在编译过程中有任何问题,欢迎加我微信 ezglumes 联系我,及时调整保证轻松搞定编译过程。

    6 条回复    2021-11-01 10:17:18 +08:00
    771007147
        1
    771007147  
       2021-10-30 16:41:37 +08:00
    正好做音视频,关注了
    glumess
        2
    glumess  
    OP
       2021-10-30 22:44:36 +08:00
    @771007147 感谢老铁
    waruqi
        3
    waruqi  
       2021-10-31 13:34:22 +08:00 via Android
    直接用 xrepo install -p android --ndk=/xx/android-ndk-r20b ffmpeg 就行了

    或者直接走 xmake 的 add_requires("ffmpeg") 一键编译集成 ffmpeg 库
    glumess
        4
    glumess  
    OP
       2021-10-31 20:51:40 +08:00
    @waruqi 我擦,现在都这么流弊了哇,太进步了,一键搞定啊
    Cassius
        5
    Cassius  
       2021-11-01 00:31:17 +08:00 via Android
    话说硬编码的有没有相关文章,目前在学习这部分内容,各版本编码问题简直一把泪
    happyhou
        6
    happyhou  
       2021-11-01 10:17:18 +08:00
    点赞
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1007 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 22:03 · PVG 06:03 · LAX 15:03 · JFK 18:03
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.