《macOS 下 NDK 环境中 FFmpeg、x264、fdk-aac、openssl 和 libmp3 编译教程》

498 阅读3分钟

前言

在移动应用开发中,常常需要使用多媒体处理库和加密库。FFmpeg 是一个强大的多媒体处理框架,x264 用于视频编码,fdk-aac 提供高质量的 AAC 音频编码,openssl 提供加密功能,而 libmp3 可以处理 MP3 音频文件。在 macOS 下,通过 NDK(Native Development Kit)环境进行这些库的交叉编译,可以生成适用于 Android 平台的动态库(.so文件)。本文将详细介绍在 macOS 下进行这些库的编译过程。

一、前期准备

(一)明确编译目标

确定需要编译的库的版本和功能需求,以及生成的 .so 文件将用于哪些 Android 平台(如 armeabi-v7a、arm64-v8a 等)。

(二)安装必要软件和工具

  1. 安装 NDK:下载并安装适用于 macOS 的 Android NDK(Native Development Kit)。选择合适的 NDK 版本,以确保与目标 Android 设备的兼容性。可以从 Android 官方网站下载 NDK。
  2. NDK此次编译选择的是21.4.7075529,AndroidStudio的 的 SDK Manager下载的
  3. 安装 Homebrew:Homebrew 是 macOS 上的包管理工具,可以方便地安装各种软件和库。打开终端,输入以下命令安装 Homebrew:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

二、安装必需的库和依赖库

(一)安装依赖库

  1. 安装 yasm:FFmpeg 在编译过程中可能需要 yasm 来进行汇编优化。使用 Homebrew 安装 yasm:
brew install yasm
  1. 安装 nasm:某些版本的 FFmpeg 可能需要 nasm。同样使用 Homebrew 安装:
brew install nasm

三、源代码下载

X264

官网下载 www.videolan.org/developers/…

fdk-aac

www.linuxfromscratch.org/blfs/view/s…

ffmpeg4.2.1

ffmpeg.org/releases/ff…

libmp3lame

spaghetticode.org/lame/

编译

交叉编译重要参数:

  • --prefix:安装的目录
  • --cross-prefix:交叉编译的前缀路径,后面会拼接gccld
  • --sysroot:编译过程会去这个目录下找依赖相关的类等
  • --enable-pic:生成与路径无关静/动态库
  • --extra-cflags:编译过程需要传递的参数,相关参数参考

编译x264

X264在NDK21使用clang编译(NDK在版本r17c之后使用clang编译)

1)x264默认使用gcc编译,我们需要修改修改x264库跟目录下的configure a. 找到CC="${CC-${cross_prefix}gcc}" 这里的CC是我们需要添加到环境变量的clang编译器路径,我们直接在脚本里定义CC变量即可。 b. 把全局的${cross_prefix}gcc-改成${cross_prefix}-;也就是把拼接中的gcc去掉。 2)脚本文件:创建一个名为 build_x264.sh 的脚本文件

#!/bin/bash

# 定义变量

NDK=/Users/dabao/Library/Android/sdk/ndk/21.4.7075529
# 定义 NDK 的路径,这里存放了 Android 原生开发工具包。

SYSROOT=$NDK/toolchains/llvm/prebuilt/darwin-x86_64/sysroot
# 定义系统根目录,用于指定编译过程中使用的系统头文件和库文件的位置。

TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64
# 定义工具链的路径,包含了编译 Android 应用所需的各种工具。

API=21
# 定义 Android API 级别。

build_x264() {
  cd /Users/dabao/Desktop/build/ffmpeg/ffmpeg/ffmpeg_build/x264-master
  # 切换到 x264 源代码目录。
  
    local android_cpu="$1"
    # 接收传入的参数,代表 Android CPU 架构名称。

    local arch_prefix="$2"
    # 接收传入的参数,代表架构前缀。

    local optimize_cflags="$3"
    # 接收传入的参数,代表优化编译标志。

    local prefix_tag="$4"
    # 接收传入的参数,代表前缀标签。

    PREFIX=/Users/dabao/Desktop/build/ffmpeg/ffmpeg/ffmpeg_build/output/x264/$android_cpu
    # 定义输出目录的路径,根据不同的 Android CPU 架构进行区分。

    export CC=$TOOLCHAIN/bin/$arch_prefix$API-clang
    # 设置 C 编译器环境变量,指定特定架构和 API 级别的 clang 编译器。

    export CXX=$TOOLCHAIN/bin/$arch_prefix$API-clang++
    # 设置 C++编译器环境变量,指定特定架构和 API 级别的 clang++编译器。

    CROSS_PREFIX=$TOOLCHAIN/bin/$prefix_tag
    # 定义交叉编译前缀,用于在编译过程中指定工具的路径。

    EXTRA_CFLAGS="-D__ANDROID_API__=$API -isysroot $NDK/sysroot -I$NDK/sysroot/usr/include/$arch_prefix -Os -fPIC $optimize_cflags"
    # 设置额外的编译标志,包括定义 Android API 级别、指定系统根目录、包含特定架构的头文件路径、进行优化以及启用位置无关代码。

   
    if [ "$android_cpu" = "armv8-a" ]; then
       HOST=aarch64-linux-android
    else
       HOST=arm-linux
    fi
    # 根据传入的 Android CPU 架构名称设置主机名称。如果是 "armv8-a",则设置为主机为 aarch64-linux-android,否则为 arm-linux。

 ./configure \
    --prefix=${PREFIX} \
    --cross-prefix=${CROSS_PREFIX} \
    --sysroot=$SYSROOT \
    --host=${HOST} \
    --disable-asm \
    --enable-shared \
    --enable-static \
    --disable-opencl \
    --enable-pic \
    --disable-cli \
    --extra-cflags="$EXTRA_CFLAGS" || exit 0
    # 运行 x264 的配置脚本,设置各种编译选项,包括输出目录、交叉编译前缀、系统根目录、主机名称、禁用汇编、启用共享库和静态库、禁用 OpenCL、启用位置无关代码以及设置额外的编译标志。如果配置失败,则退出脚本。

  make clean
  # 清理之前的编译结果。

  make -j8
  # 进行编译,使用 8 个并发任务加快编译速度。

  make install V=1
  # 安装编译结果,并输出详细的安装过程信息。

  echo -e "building for android $android_cpu completed "
  # 输出编译完成的提示信息 
}



build_x264 "armeabi-v7a" "armv7a-linux-androideabi" "-march=armv7-a" "arm-linux-androideabi-"
# 调用 build_x264 函数,传入参数以编译 armeabi-v7a 架构的 x264。

build_x264 "armv8-a" "aarch64-linux-android"  "-march=armv8-a" "aarch64-linux-android-"
# 调用 build_x264 函数,传入参数以编译 armv8-a 架构的 x264。
  • 运行 chmod +x build_x264.sh 赋予脚本可执行权限。
  • 运行 ./build_x264.sh 执行脚本进行编译。

编译 fdk-aac

重要参数跟x264的差不过的。

编译前的操作

libfdkaac/libSBRdec/src/lpp_tran.cpp中的__ANDROID__改成__ANDROID_OFF__;也就是去掉log/log.h,因为ndk中没有这玩意。