用clang进行ffmpeg动态库编译

8/27/2022 ndk

# ndk下载和配置

# 1. 下载最新ndk

$ wget https://dl.google.com/android/repository/android-ndk-r23c-linux.zip
$ unzip android-ndk-r23c-linux.zip

# 2. 配置环境变量

export NDK=/.../android-ndk-r23c
export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64

export API=21
export TARGET=aarch64-none-linux-android #模拟器使用x86_64替代

export AR=$TOOLCHAIN/bin/llvm-ar
export CC="$TOOLCHAIN/bin/clang --target=$TARGET$API"
export CXX="$TOOLCHAIN/bin/clang++ --target=$TARGET$API"
export AS=$TOOLCHAIN/bin/llvm-as
export LD=$TOOLCHAIN/bin/ld
export RANLIB=$TOOLCHAIN/bin/llvm-ranlib
export STRIP=$TOOLCHAIN/bin/llvm-strip

# 测试clang打包

# 1. 编写源文件

// testget.h
#include <stdio.h>
int testget();

// testget.c
#include <stdio.h>
int testget() {
    return 123;
}

# 2. 编写编译脚本

$ vim pkg.sh
#!bin/bash

export SYSROOT="--sysroot=$TOOLCHAIN/sysroot"
echo `$CC $SYSROOT -fPIC -c $1.c`
echo `$CC $SYSROOT -fPIC -shared -Wl,-soname,lib$1.so -o lib$1.so $1.o`

给脚本增加执行权限并执行脚本

$ sudo chmod 755 pkg.sh
$ bash pkg.sh testget

此时会生成libtestget.so动态库文件

# 3. 将动态库引入Native工程

首先创建一个Android的Native C++工程

libtestget.so导入cpp/libs/shared/lib/arm64-v8a目录下,testget.h导入cpp/libs/shared/include目录下

配置CMakeList.txt,加入动态库的依赖

set(shared ${CMAKE_CURRENT_SOURCE_DIR}/libs/shared)

add_library(testget SHARED IMPORTED)
set_target_properties(testget PROPERTIES IMPORTED_LOCATION
        ${shared}/lib/${ANDROID_ABI}/libtestget.so)

target_include_directories(
   ...  
   ${shared}/include
)

target_link_libraries(
        ...
        testget
        ...)

build.gradle中指定ndk版本为最新版本

android {
    ...
    ndkVersion '25.0.8775105'

native-lib.cpp中引入头文件

extern "C" {
#include "testget.h"
}

并修改的jni方法

Java_com_example_testso_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    int res = testget();
    const char *str = hello.c_str();
    char *buf = new char[strlen(str) + sizeof(res)];
    sprintf(buf, "%s%d", str, res);
    return env->NewStringUTF(buf);
}

运行并查看结果

# ffmpeg下载和编译

# 1. 下载最新ffmpeg

$ wget https://ffmpeg.org/releases/ffmpeg-snapshot.tar.bz2
$ tar -xjf ffmpeg-snapshot.tar.bz2

# 2. 编写编译脚本

$ vim compile.sh
#!/bin/bash


export TMPDIR=/.../ffmpeg/tmp
PLATFORM=/.../android-ndk-r23c/toolchains/llvm/prebuilt/linux-x86_64

function build
{
        CPU=$1
        PREFIX="/.../ffmpeg/output-$CPU"
        TOOLCHAIN="/.../android-ndk-r23c/toolchains/llvm/prebuilt/linux-x86_64"
        echo "Cpu is $CPU"
        echo "Output is $PREFIX"


        ./configure \
                --prefix=$PREFIX \
                --target-os=android \
                --arch=$CPU \
                --enable-shared \
                --disable-static \
                --disable-doc \
                --disable-ffmpeg \
                --disable-ffplay \
                --disable-ffprobe \
                --disable-avdevice \
                --disable-symver \
                --enable-cross-compile \
                --sysroot=$TOOLCHAIN/sysroot \
                --cross-prefix=$TOOLCHAIN/bin/llvm- \
                --cc=$TOOLCHAIN/bin/$CPU-linux-android21-clang \
                --cxx=$TOOLCHAIN/bin/$CPU-linux-android21-clang++ \
                --extra-cflags="-I$TOOLCHAIN/sysroot/usr/include -fpic" \
                --extra-ldflags="-L$TOOLCHAIN/sysroot/usr/lib"

        make clean
        make -j4
        make install
}

build x86_64

安装yasm工具后切换到root用户下,并执行脚本

$ sudo yum install yasm
$ su - root
$ nohup bash compile.sh > run.log &

查看进程是否正在运行,并查看日志确定是否已完成

$ ps -aux | grep compile
$ tail -f -n 300 run.log

压缩并导出编译后的成果

$ zip -r os-x86_64.zip output-x86_64