零基础也能学会!Android 端 FFmpeg 6.1 编译保姆级教程(Linux 版)

48 阅读8分钟

先唠唠:为啥要编译 FFmpeg?

FFmpeg 就像音视频开发的 “万能工具箱”—— 做视频播放、直播推流、剪视频都得用它。但它默认不能直接在安卓手机上用,得用 Linux 系统把它 “改造” 成安卓能识别的文件,这个 “改造” 过程就是 “编译”。

咱们这次要做的:用 Linux 系统(我用的 Ubuntu 20.04),把 FFmpeg 6.1 改成适配安卓的版本,还能兼容最新的 Android 15 手机,开启视频硬件加速。

准备工作:先搞懂 3 个 “基础工具”(小白别慌,超简单)

  1. 终端:Linux 系统里敲命令的地方;
  2. NDK:谷歌出的 “安卓编译工具包”,没有它改不了 FFmpeg;
  3. FFmpeg 源码:就是 FFmpeg 的 “原始代码”,咱们要改的就是它。

第一步:安装编译需要的 “基础配件”(复制粘贴就行)

打开终端(Ctrl+Alt+T),先装几个必须的工具,少一个都可能报错。

操作步骤:

  1. 终端里输入下面这行命令,按回车(输入时可以直接复制,终端粘贴是 Ctrl + Shift + V,不是普通的 Ctrl+V!):

bash

运行

sudo apt update && sudo apt install -y curl tar make gcc binutils
  1. 可能会让你输电脑密码(输的时候终端不会显示,输完直接回车就行),等它跑完,没红色 “error” 就说明装好了。

小白解惑:

  • sudo:就是 “获取管理员权限”,装软件必须用;
  • 这些工具的作用:curl是下载文件、tar是解压文件、make/gcc是干活的 “编译器”,不用记,复制就行。

第二步:下载 NDK 27(关键!版本错了必翻车)

NDK 必须用 27 版本(低版本不支持新手机),我教你最简单的下载方式:

操作步骤:

  1. 终端输入下面的命令,回车(自动下载 NDK 到当前文件夹):

bash

运行

curl -O https://dl.google.com/android/repository/android-ndk-r27b-linux.zip
  1. 下载完后,输入下面的命令解压(解压需要 1-2 分钟):

bash

运行

# 先建个专门放NDK的文件夹,避免找不着
mkdir -p ~/Android/Sdk/ndk
# 解压NDK到这个文件夹
unzip android-ndk-r27b-linux.zip -d ~/Android/Sdk/ndk/
  1. 验证是否解压成功:输入下面的命令,能看到 “android-ndk-r27b” 就对了:

bash

运行

ls ~/Android/Sdk/ndk/

避坑:

  • 如果下载太慢(curl 命令卡着不动):可以手动下载 —— 打开浏览器,输入链接 https://dl.google.com/android/repository/android-ndk-r27b-linux.zip,下载完后,把文件拖到桌面,再在终端里输入 mv ~/桌面/android-ndk-r27b-linux.zip ~/,再执行上面的解压命令就行;
  • 记住 NDK 的路径:~/Android/Sdk/ndk/android-ndk-r27b(后面要用到,别改这个路径!)。

第三步:下载 FFmpeg 源码(就 2 行命令)

选 6.1.1 版本(稳定,不容易出问题),还是在终端里操作:

  1. 输入命令下载源码包:

bash

运行

curl -O https://ffmpeg.org/releases/ffmpeg-6.1.1.tar.xz
  1. 输入命令解压:

bash

运行

tar -xf ffmpeg-6.1.1.tar.xz
  1. 进入解压后的文件夹(后续所有操作都在这个文件夹里):

bash

运行

cd ffmpeg-6.1.1

小白解惑:

  • 解压后会在 “主文件夹” 里看到一个叫 “ffmpeg-6.1.1” 的文件夹,后续编译都在这里面做,别乱跑文件夹!

第四步:写编译脚本(小白只改 1 个地方,其余复制)

编译 FFmpeg 需要一堆复杂参数,我已经把所有坑都踩过,写好了现成的脚本,你只需要复制粘贴,改 1 个路径就行。

操作步骤:

  1. 终端里输入下面的命令,新建一个脚本文件(会打开一个简单的编辑器):

bash

运行

nano build_ffmpeg_android.sh
  1. 把下面的脚本完整复制(复制后,在编辑器里按 Ctrl + Shift + V 粘贴):
#!/bin/bash
# 纯小白专用 FFmpeg 编译脚本
# 不用改任何参数,只确认第10行的NDK路径对不对!

# ======================= 只看这一行!确认路径对不对 =======================
NDK_27_PATH="/opt/android-ndk-r27d" 
# ========================================================================

# 下面的都不用改!
FFMPEG_VERSION="6.1.1"
API=24  # 最低支持安卓7.0,改高了老手机用不了
set -e  # 出错就停,避免越错越远

TOOLCHAIN="$NDK_27_PATH/toolchains/llvm/prebuilt/linux-x86_64"
SYSROOT="$TOOLCHAIN/sysroot"

echo "===== 开始准备编译啦 ====="
echo "NDK路径:$NDK_27_PATH"
echo "最低支持安卓7.0"

# 不同手机版本的优化(不用懂)
configure_arch_specific_options() {
    local arch_specific_options=""
    case "$ANDROID_ABI" in
        "arm64-v8a")
            arch_specific_options="--enable-neon --enable-asm"
            ;;
        "armeabi-v7a")
            arch_specific_options="--enable-neon --enable-thumb --enable-vfp --extra-cflags=-march=armv7-a"
            ;;
        "x86_64")
            arch_specific_options="--disable-neon --disable-asm --extra-cflags=-march=x86-64"
            ;;
    esac
    echo "$arch_specific_options"
}

# 适配Android15的16K页大小(必须有)
configure_link_options() {
    local link_options=""
    case "$ANDROID_ABI" in
        "arm64-v8a"|"armeabi-v7a"|"x86_64")
            link_options="-Wl,-z,max-page-size=16384 -Wl,-z,separate-loadable-segments"
            ;;
    esac
    echo "$link_options"
}

# 核心编译功能(不用懂)
build_android() {
    echo -e "\n===== 开始编译 $ANDROID_ABI 版本 ====="

    local CC="$TOOLCHAIN/bin/${HOST}${API}-clang"
    local CXX="$TOOLCHAIN/bin/${HOST}${API}-clang++"
    local NM="$TOOLCHAIN/bin/llvm-nm"
    local AR="$TOOLCHAIN/bin/llvm-ar"
    local RANLIB="$TOOLCHAIN/bin/llvm-ranlib"
    local STRIP="$TOOLCHAIN/bin/llvm-strip"

    local PREFIX="$(pwd)/android/$ANDROID_ABI"
    mkdir -p "$PREFIX"

    # 检查C++20是否能用(我当初栽在这!)
    echo "检查工具是否能用..."
    cat > /tmp/cpp20_check.cpp << 'EOF'
#include <version>
#if __cplusplus >= 202002L
int main() { return 0; }
#else
#error "工具版本不对,检查NDK!"
#endif
EOF
    if ! "$CXX" -std=c++20 -c /tmp/cpp20_check.cpp -o /tmp/cpp20_check.o 2>/dev/null; then
        echo "❌ 出错了!大概率是NDK路径写错了,回头看第二步!"
        rm -f /tmp/cpp20_check.cpp /tmp/cpp20_check.o
        exit 1
    fi
    rm -f /tmp/cpp20_check.cpp /tmp/cpp20_check.o
    echo "✅ 工具没问题!"

    local ARCH_OPTS=$(configure_arch_specific_options)
    local LINK_OPTS=$(configure_link_options)

    # FFmpeg核心配置(修复了参数行格式问题!)
    ./configure \
        --prefix="$PREFIX" \
        --target-os=android \
        --arch="$ARCH" \
        --cpu="$CPU" \
        --cc="$CC" \
        --cxx="$CXX" \
        --nm="$NM" \
        --ar="$AR" \
        --ranlib="$RANLIB" \
        --strip="$STRIP" \
        --cross-prefix="$TOOLCHAIN/bin/${HOST}-" \
        --sysroot="$SYSROOT" \
        $ARCH_OPTS \
        --enable-cross-compile \
        --enable-pic \
        --enable-static \
        --disable-shared \
        --disable-debug \
        --disable-programs \
        --disable-doc \
        --disable-avdevice \
        --disable-postproc \
        --disable-avfilter \
        --enable-swscale \
        --disable-iconv \
        --disable-vulkan \
        --enable-network \
        --enable-zlib \
        --enable-jni \
        --enable-mediacodec \
        --enable-hwaccels \
        --enable-swresample \
        --enable-protocol=file,http,https,tcp,udp,rtp,rtsp,rtmp \
        --enable-demuxer=rtsp,rtp,sdp,mov,mp4,matroska,flv,h264,hevc,aac,mp3 \
        --enable-muxer=mp4,mov,matroska,flv \
        --enable-decoder=h264,hevc,mpeg4,aac,mp3,pcm_s16le,h264_mediacodec,hevc_mediacodec \
        --enable-encoder=aac,pcm_s16le \
        --enable-bsf=h264_mp4toannexb,hevc_mp4toannexb,aac_adtstoasc \
        --extra-cflags="-Os -fPIC -DANDROID -fno-sanitize=all -DGWP_ASAN_HOOKS=0" \
        --extra-cxxflags="-Os -fPIC -DANDROID -std=c++20 -fno-sanitize=all" \
        --extra-ldexeflags="-pie" \
        --extra-ldflags="-L$SYSROOT/usr/lib/$HOST/$API -landroid -lmediandk -lm -llog -lz $LINK_OPTS" || {
            echo "❌ 配置失败!看上面的红色报错,大概率是路径错了"
            exit 1
        }

    # 开始编译(等几分钟就行)
    echo "开始编译啦,耐心等~"
    make clean
    make -j$(nproc) || { echo "❌ 编译失败!"; exit 1; }
    make install || { echo "❌ 安装失败!"; exit 1; }

    # 检查有没有编译出文件
    local LIB_AVCODEC="$PREFIX/lib/libavcodec.a"
    if [ -f "$LIB_AVCODEC" ]; then
        echo "✅ $ANDROID_ABI 编译成功!文件大小:$(du -h $LIB_AVCODEC | awk '{print $1}')"
    else
        echo "❌ 没找到编译后的文件,失败了!"
        exit 1
    fi

    echo -e "===== $ANDROID_ABI 搞定!文件在:$PREFIX =====\n"
}

# 编译64位手机版本(主流)
ARCH="aarch64"
CPU="armv8-a"
HOST="aarch64-linux-android"
ANDROID_ABI="arm64-v8a"
build_android

# 编译32位手机版本(老手机)
ARCH="arm"
CPU="armv7-a"
HOST="armv7a-linux-androideabi"
ANDROID_ABI="armeabi-v7a"
build_android

# 编译模拟器版本(测试用)
ARCH="x86_64"
CPU="x86-64"
HOST="x86_64-linux-android"
ANDROID_ABI="x86_64"
build_android

echo "🎉 所有版本都编译完啦!"
echo "📁 文件在:$(pwd)/android/ 文件夹里"
echo "💡 能在安卓7.0+手机用,支持视频硬件加速、直播推流!"
  1. 关键检查:确认脚本里第 10 行的 NDK_27_PATH 和你第二步的 NDK 路径一致(默认就是 ~/Android/Sdk/ndk/android-ndk-r27b,不用改);
  2. 保存并退出编辑器:按 Ctrl + O → 按回车 → 按 Ctrl + X(这三步别错!)。

避坑:

  • 粘贴脚本时如果乱码 / 少行:先把终端窗口放大,再重新复制粘贴;
  • 编辑器里别乱改其他内容,哪怕多删一个空格,都可能编译失败!

第五步:运行脚本,坐等编译完成(最轻松的一步)

  1. 终端里输入命令,给脚本 “运行权限”:

bash

运行

chmod +x build_ffmpeg_android.sh
  1. 输入命令开始编译(编译需要 5-10 分钟,看电脑快慢,别关终端!):

bash

运行

./build_ffmpeg_android.sh
  1. 等终端最后显示 🎉 所有版本都编译完啦!,就说明成功了!

小白解惑:

  • 编译时终端会刷很多字,不用看,只要没有红色的 “error”“❌” 就没事;
  • 如果中途卡住:别关终端,等 10 分钟,大概率是电脑在干活,不是卡了。

第六步:找编译好的文件

  • 打开 Linux 文件管理器,进入 “主文件夹”;

  • 找到 “ffmpeg-6.1.1” 文件夹,内部会新增 “android” 目录;

  • “android” 文件夹包含 3 个架构目录(arm64-v8a/armeabi-v7a/x86_64),每个架构目录下有两个核心文件夹:

    • lib:存放 .a 后缀的 FFmpeg 静态库文件(程序运行的核心);
    • include:存放 FFmpeg 的头文件(代码开发时必须引用,否则无法调用 FFmpeg 的 API);
    • 补充说明:arm64-v8a 适配 64 位 Android 手机(主流设备),armeabi-v7a 适配 32 位 Android 手机(旧设备),x86_64 适配 Android 模拟器(开发测试用);
  • 集成到 Android 项目的完整步骤

    • 第一步:在 Android 项目的 src/main/ 目录下,新建 jniLibs 文件夹,再按架构新建子文件夹(arm64-v8a/armeabi-v7a/x86_64);
    • 第二步:将各架构目录下 lib 文件夹中的 .a 文件,分别复制到 jniLibs 对应架构的子文件夹中;
    • 第三步:在 Android 项目的 src/main/ 目录下,新建 cpp 文件夹(若无),将各架构目录下 include 文件夹中的所有文件,复制到 cpp 目录下(所有架构的 include 内容一致,复制一份即可);
    • 第四步:在项目的 CMakeLists.txt(或 Android.mk)中,配置头文件路径和链接静态库,即可调用 FFmpeg 的 API。

小白最常踩的 5 个坑(我全踩过!)

坑 1:终端粘贴用 Ctrl+V 没反应

  • 解决:Linux 终端粘贴是 Ctrl + Shift + V,复制是 Ctrl + Shift + C(和普通软件不一样!);

坑 2:编译时提示 “C++20 工具不对”

  • 原因:NDK 路径错了 / NDK 版本不是 27;
  • 解决:回到第二步,重新检查 NDK 路径,确保是 27 版本;

坑 3:Android 15 手机运行崩溃

  • 原因:没适配 16K 页大小(脚本里已经加了,不用改);
  • 解决:确认脚本里有 max-page-size=16384 这行;

坑 4:终端提示 “权限不够”

  • 解决:命令前加 sudo(比如 sudo chmod +x build_ffmpeg_android.sh),输密码就行;

坑 5:编译完找不到文件

  • 原因:没进入 ffmpeg-6.1.1 文件夹就运行脚本;
  • 解决:先输 cd ffmpeg-6.1.1,再运行脚本。

总结

  1. 全程只需要复制粘贴命令,不用懂任何专业知识;
  2. 唯一要确认的:NDK 路径是 ~/Android/Sdk/ndk/android-ndk-r27b
  3. 编译成功后,android 文件夹里的 .a 文件就是能用的库;
  4. 遇到报错先看终端里的红色字,大概率是路径错了 / 没装依赖。

真的不用怕!我第一次弄的时候,光是终端粘贴就试了 10 次,现在回头看,其实就是 “复制→粘贴→等” 三步。如果还是卡壳,评论区问我,我看到就回~

最后打个广告,低延迟播放器就是基于此打造的项目地址:https://github.com/anwz0611/android-ffmpeg-stream-player 有需求的小伙伴star一下 谢谢关注~