Android 编译FFmpeg4.3.1并集成x264

编译前的准备

Ubuntu 20.04.6 LTS

Android NDK r21e(21.2.6472646)需要准备Linux版本和Windows版本

FFmpeg-4.3.1

x264

编译过程及脚本

主要流程:先编译好准备的第三方库,生成相应的动态库文件,最后在编译FFmpeg时关联起来。在实际应用中可能还需要编译不同的ABI才能在不同的设备上使用,本文FFmpeg以编译arm64-v8a为例。

存储目录结构

Shell 复制代码
home
 ├── ffmpeg_build
 │    └── out
 │        └── arm64-v8a
 └── ffmpeg_sources
     ├── ffmpeg-4.3.1
     ├── ndk
     ├── x264 
     └── other_libs # 存储第三方库编译的动态库文件
         └── x264

编译第三方库

x264

Shell 复制代码
#!/bin/bash
set -e

NDK=# 实际ndk路径
X264_SRC=# 实际X264源码路径
INSTALL_BASE=# 实际存储第三方库编译的动态库文件路径

API=21
ABIS=("armeabi-v7a" "arm64-v8a" "x86" "x86_64")

TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64

for ABI in "${ABIS[@]}"; do
    echo "============================="
    echo " 正在构建 ABI: $ABI"
    echo "============================="

    case $ABI in
        armeabi-v7a)
            TARGET=armv7a-linux-androideabi
            ARCH=arm
            CROSS_PREFIX=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/arm-linux-androideabi-
            CC=$TOOLCHAIN/bin/armv7a-linux-androideabi${API}-clang
            ;;
        arm64-v8a)
            TARGET=aarch64-linux-android
            ARCH=arm64
            CROSS_PREFIX=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-
            CC=$TOOLCHAIN/bin/aarch64-linux-android${API}-clang
            ;;
        x86)
            TARGET=i686-linux-android
            ARCH=x86
            CROSS_PREFIX=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/i686-linux-android-
            CC=$TOOLCHAIN/bin/i686-linux-android${API}-clang
            ;;
        x86_64)
            TARGET=x86_64-linux-android
            ARCH=x86_64
            CROSS_PREFIX=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android-
            CC=$TOOLCHAIN/bin/x86_64-linux-android${API}-clang
            ;;
        *)
            echo " Unsupported ABI: $ABI"
            exit 1
            ;;
    esac

    BUILD_DIR=$X264_SRC/build/$ABI
    INSTALL_DIR=$INSTALL_BASE/$ABI/x264
    mkdir -p "$BUILD_DIR" "$INSTALL_DIR"

    rm -rf "$BUILD_DIR"/*
    cd "$BUILD_DIR"

    echo " 配置 x264 for $ABI"

    # 设置 sysroot 为 llvm 自带的 sysroot,兼容新 NDK
    SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot

    # 设置环境变量,指定交叉编译器和 sysroot
    export CC=$CC
    export CFLAGS="--sysroot=$SYSROOT"
    export LDFLAGS="--sysroot=$SYSROOT"

    $X264_SRC/configure \
        --prefix="$INSTALL_DIR" \
        --host=$TARGET \
        --enable-shared \
        --disable-cli \
        --enable-pic \
        --disable-asm \
        --sysroot="$SYSROOT"

    echo " 编译 x264 动态库"
    make -j$(nproc)
    make install

    echo " 静态库完成: $INSTALL_DIR/lib/libx264.a"
    echo
done

echo " 所有 ABI 构建完成,输出在: $INSTALL_BASE/<abi>/x264"

随后切换到FFmpeg目录下,新建以下脚本

Shell 复制代码
#!/bin/bash

set -e

NDK=/home/puffy/sang/ffmpeg_sources/ndk/21.2.6472646/android-ndk-r21e
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64
API=21
ARCH=arm64-v8a
CPU=armv8-a
PLATFORM=aarch64-linux-android
PREFIX=/home/puffy/sang/ffmpeg_build/out/$ARCH
X264_PATH=/home/puffy/sang/ffmpeg_sources/other_libs/$ARCH/x264

export CC=$TOOLCHAIN/bin/${PLATFORM}${API}-clang
export CXX=$TOOLCHAIN/bin/${PLATFORM}${API}-clang++
export AR=$TOOLCHAIN/bin/aarch64-linux-android-ar
export LD=$TOOLCHAIN/bin/aarch64-linux-android-ld
export NM=$TOOLCHAIN/bin/aarch64-linux-android-nm
export STRIP=$TOOLCHAIN/bin/aarch64-linux-android-strip

export PKG_CONFIG_PATH=$X264_PATH/lib/pkgconfig

./configure \
    --prefix=$PREFIX \
    --target-os=android \
    --arch=aarch64 \
    --cpu=$CPU \
    --enable-cross-compile \
    --cross-prefix=$TOOLCHAIN/bin/aarch64-linux-android- \
    --cc=$CC \
    --cxx=$CXX \
    --sysroot=$TOOLCHAIN/sysroot \
    --enable-gpl \
    --enable-libx264 \
    --enable-shared \
    --disable-static \
    --disable-doc \
    --disable-programs \
    --disable-symver \
    --extra-cflags="-I$X264_PATH/include -march=$CPU" \
    --extra-ldflags="-L$X264_PATH/lib"

make -j$(nproc)
make install

#  拷贝 libx264.so
X264_SO=$X264_PATH/lib/libx264.so
DEST_SO_DIR=$PREFIX/lib

if [ -f "$X264_SO" ]; then
    echo " 拷贝 libx264.so 到 FFmpeg 输出目录:$DEST_SO_DIR"
    cp -v "$X264_SO" "$DEST_SO_DIR/"
else
    echo " 未找到 libx264.so,请确认 x264 已正确编译:$X264_SO"
    exit 1
fi

#  拷贝 include 头文件
X264_INCLUDE_DIR=$X264_PATH/include
DEST_INCLUDE_DIR=$PREFIX/include/x264

if [ -d "$X264_INCLUDE_DIR" ]; then
    echo " 拷贝 x264 include 头文件到:$DEST_INCLUDE_DIR"
    mkdir -p "$DEST_INCLUDE_DIR"
    cp -v "$X264_INCLUDE_DIR"/*.h "$DEST_INCLUDE_DIR/"
else
    echo " 未找到 x264 include 目录,请确认路径:$X264_INCLUDE_DIR"
    exit 1
fi


echo " 编译完成,所有文件已就绪"

如果需要编译其他ABI或别的第三方库可参看github

编译成功后可在输出文件得到以下内容

在新建Native C++ 项目后,将ndk配置为和之前在Linux编译的ndk版本一致,新建jniLibs/arm64-v8a,lib文件下的so文件拷贝到此处

include下的文件拷贝到cpp/ffmpeg/include下

随后在CMakeList引入FFmpeg

txt 复制代码
# 支持gnu++11
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 -g")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g")
set(CMAKE_BUILD_TYPE Debug)

# 1. 定义so库和头文件所在目录,方面后面使用
set(ffmpeg_lib_dir ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})
set(ffmpeg_head_dir ${CMAKE_SOURCE_DIR}/ffmpeg)

# 2. 添加头文件目录
include_directories(${ffmpeg_head_dir}/include)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-rpath=$ORIGIN") #注意:告诉 CMake 不要使用 .so 的 SONAME

# 3. 添加ffmpeg相关的so库
add_library(avutil
        SHARED
        IMPORTED)
set_target_properties(avutil
        PROPERTIES IMPORTED_LOCATION
        ${ffmpeg_lib_dir}/libavutil.so)

add_library(swresample
        SHARED
        IMPORTED)
set_target_properties(swresample
        PROPERTIES IMPORTED_LOCATION
        ${ffmpeg_lib_dir}/libswresample.so)

add_library(avcodec
        SHARED
        IMPORTED)
set_target_properties(avcodec
        PROPERTIES IMPORTED_LOCATION
        ${ffmpeg_lib_dir}/libavcodec.so)

add_library(avfilter
        SHARED
        IMPORTED)
set_target_properties(avfilter
        PROPERTIES IMPORTED_LOCATION
        ${ffmpeg_lib_dir}/libavfilter.so)

add_library(swscale
        SHARED
        IMPORTED)
set_target_properties(swscale
        PROPERTIES IMPORTED_LOCATION
        ${ffmpeg_lib_dir}/libswscale.so)

add_library(avformat
        SHARED
        IMPORTED)
set_target_properties(avformat
        PROPERTIES IMPORTED_LOCATION
        ${ffmpeg_lib_dir}/libavformat.so)

add_library(avdevice
        SHARED
        IMPORTED)
set_target_properties(avdevice
        PROPERTIES IMPORTED_LOCATION
        ${ffmpeg_lib_dir}/libavdevice.so)

add_library(postproc
        SHARED
        IMPORTED)
set_target_properties(postproc
        PROPERTIES
        IMPORTED_LOCATION
        ${ffmpeg_lib_dir}/libpostproc.so
)

add_library(x264 SHARED IMPORTED)
set_target_properties(x264
        PROPERTIES
        IMPORTED_LOCATION ${ffmpeg_lib_dir}/libx264.so
        IMPORTED_NO_SONAME TRUE
        #注意
        #未设置 IMPORTED_NO_SONAME
        #如果第三方库是外部提供的 .so 文件(例如手动编译的 libx264.so),而你又不希望 CMake 写入 .so 的完整路径(而是仅写成 libx264.so),你应该显式关闭 SONAME:
)

# 查找代码中使用到的系统库
find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)

# 配置目标so库编译信息
add_library( # Sets the name of the library.
        native-lib


        SHARED

)

target_link_libraries(
        native-lib
        -landroid

        # 打开opensl es支持
        OpenSLES
        -lEGL
        -lGLESv2

        postproc

        avutil
        swresample
        avcodec
        avfilter
        swscale
        avformat
        avdevice
        x264
        ${log-lib}
)

后续

如果因为配置原因无法安装虚拟机,也可以在Windows环境下配置msys2 进行以上步骤

相关推荐
Harrison_zhu42 分钟前
在Android13上添加系统服务的好用例子
android
CV资深专家6 小时前
在 Android 框架中,接口的可见性规则
android
daifgFuture10 小时前
Android 3D球形水平圆形旋转,旋转动态更换图片
android·3d
二流小码农11 小时前
鸿蒙开发:loading动画的几种实现方式
android·ios·harmonyos
爱吃西红柿!12 小时前
fastadmin fildList 动态下拉框默认选中
android·前端·javascript
悠哉清闲13 小时前
工厂模式与多态结合
android·java
大耳猫13 小时前
Android SharedFlow 详解
android·kotlin·sharedflow
火柴就是我14 小时前
升级 Android Studio 后报错 Error loading build artifacts from redirect.txt
android
androidwork15 小时前
掌握 MotionLayout:交互动画开发
android·kotlin·交互
奔跑吧 android15 小时前
【android bluetooth 协议分析 14】【HFP详解 1】【案例一: 手机侧显示来电,但车机侧没有显示来电: 讲解AT+CLCC命令】
android·hfp·aosp13·telecom·ag·hf·headsetclient