Android-NDK-clang compiles FFmpeg

Early preparation

  1. Download  Android-NDK
  2. Download  FFmpeg source code  Note: The author uses  NDK-21 and  ffmpeg-4.4 to compile, if the version is different, it may be different.
    Test: Both mac and ubuntu NDK20 - NDK22 can  ffmpeg 4.0 - ffmpeg 4.4be used.


In this article you can learn

  • NDK20 - The main directory of the cross-compilation toolchain provided by NDK22
  • Use  clang cross-compilation to generate the libffmpeg.so library that can be used on the Android platform
  • Partial compilation details

1. The main directories and files of the cross-compilation toolchain provided by NDK

The directory structure of the compilation toolchain from NDK20 - NDK22 has basically remained the same, here we use NDK21 as a demonstration (the directories of NDK in windows, linux, and mac are basically the same)

As shown in the figure above, these directories are mainly used, and the  gcc libraries needed to compile FFmpeg are in  aarch64、arm、x86_64、x86 these folders. Here we first introduce the connection of these names in different platform libraries in Android.

aarch64: directories with this prefix are related to arm64-v8a library
arm: directories with this prefix are related to armeabi-v7a library
x86_64: directories with this prefix are related to x86_64 library
x86: directories with this prefix Both are related to the x86 library

1. clang compilation tools

Entering the directory  llvm->prebuilt->darwin-x86_64->bin contains files related to cross-compilation. We can  clang compile them, so the main focus is on  clang、clang++ the files at the end, clang which are used for compiling  c 文件and clang++ compiling  c++ files.
 

  • The things to note here are:21 和 i686
  • 21: Indicates the minimum Android version supported by the compiled library
  • i686: Indicates the compilation tool for compiling the x86 library platform

The corresponding form of the above NDK directory name on each system:
mac: darwin-x86_64
linux: linux-x86_64
windows: windows-x86_64
Note: The following are all introductions based on the NDK directory under the mac system

2. Compilation environment, what needs to be used library
 

The directory where the library and header files are located darwin-x86_64 is  sysroot the directory below, where the header file is in  include the directory, and the library is in  lib the directory. After understanding these, you can start compiling.

2. Use  clang cross-compilation to generate the libffmpeg.so library that can be used on the Android platform

Enter the FFmpeg source code root directory
 

1. Create a compilation script: build_ffmpeg_android.sh

The main content of the script is as follows:

#!/bin/sh
# NDK 所在的路径
NDK=/Users/mac/Library/Android/sdk/ndk/21.4.7075529
# 需要编译出的平台,这里是 arm64-v8a
ARCH=aarch64
# 支持的最低 Android API
API=21
# 编译后输出目录,在 ffmpeg 源码目录下的 /android/arm64-v8a
OUTPUT=$(pwd)/android/arm64-v8a
# NDK 交叉编译工具链所在路径
TOOLCHAIN=/Users/mac/Library/Android/sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/darwin-x86_64

build() {
  ./configure \
  --target-os=android \
  --prefix=$OUTPUT \
  --arch=$ARCH \
  --sysroot=$TOOLCHAIN/sysroot \
  --disable-static \
  --disable-ffmpeg \
  --disable-ffplay \
  --disable-ffprobe \
  --disable-debug \
  --disable-doc \
  --disable-avdevice \
  --enable-shared \
  --enable-cross-compile \
  --cross-prefix=$TOOLCHAIN/bin/aarch64-linux-android- \
  --cc=$TOOLCHAIN/bin/aarch64-linux-android$API-clang \
  --cxx=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++ \
  --extra-cflags="-fpic"

  make clean all
  make -j12
  make install
}

build

This shell script is generally easy to understand. For example,
--disabble-static it is forbidden to output static libraries
--enable-shared and output dynamic libraries.
--arch What is the architecture of the so library used to configure the output?
--prefix The storage path of the so library used to configure the output
enable-cross-compile enables multi-platform compilation, that is, it can Compile libraries for multiple platforms
For more options, please refer to the introduction on the official website, so I won’t say more here.

Let's focus on a few options:

  • target-os  --target-os=android: In the old version  FFmpeg , the support for the Android platform is not perfect, and there is no  android such target, so it is mentioned in some older articles that compiling the so library of the Android platform needs to be  configure modified, otherwise The so library will be  linux output in a standard way, and its naming method is different from Android's so, which cannot be loaded on Android, so when compiling, it is best to FFmpeg choose the source code version that is consistent with the author's.

Question 1: The so library exported under Linux cannot be loaded under Android

  • sysroot  --sysroot=$TOOLCHAIN/sysroot: It is used to configure the cross-compilation environment  根路径 . When compiling, it will search for these two paths from this path by default  usr/includeusr/lib , and then find the relevant header files and library files.
    NDK20-NDK22 The header files and library files of the system are in  $SYSYROOT/usr/include and  $SYSYROOT/usr/lib in.

extra-cflags specifies some compilation flags for the compiler, for example:
设置头文件路径: format  -I头文件路径
设置编译出的二进制文件为位置无关码文件: format  -fpic
As for why it is necessary to compile position-independent code files, it is because  打包 the output so library is composed of multiple position-independent code binary files.

extra-ldflags specifies some linking flags for the linker, for example: :
设置需要链接的库的路径format  -L库文件路径
输出库并设置名字: format  -o 库名
设置需要链接的库: format Note  -l库名
here:
Assume that the library name: a
-o 库名  needs to be  lib prefixed, and  .so/.a the part with the suffix, -o liba.so
-l库名 if it is  without lib the prefix,  .so/.a the part with the suffix, such as  -la

Regarding the issue of compiling and linking flags, if you want to know more details, you can check here .

  • cross-prefix Configure the prefix of the cross-compilation compilation tool, which is the prefix of the file name in the directory where the cross-compilation-related files described above are located, such as: compiling the arm64-v8a platform, and compiling the armeabi-v7a  aarch64-linux-android-platform  arm-linux-androideabi-. Specifically,  bin you can check it in the directory under the cross-compilation toolchain directory.
  • cc
  • These two items of cxx are the usage mentioned above  Android 自带的 clang 工具的具体路径.

2. Start compiling

Enter through the terminal  FFmpeg 源码根目录and run the compiled script just written,

sh build_ffmpeg_android.sh

The result of the operation is as follows

As shown in the picture above, the red box is all the files we compiled, but it is troublesome to use so many so files, so we need to make them 打包into one so file.

3. Package multiple libraries into one library

  • Modify the compilation script as follows
#!/bin/sh

# ...省略了不变的部分
SYSROOT_L=$TOOLCHAIN/sysroot/usr/lib/aarch64-linux-android
GCC_L=$NDK/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/lib/gcc/aarch64-linux-android/4.9.x

build() {
  # ...省略了不变的部分
  --disable-shared \
  --enable-static \
  --extra-cflags="-fpic -I$OUTPUT/include" \
  --extra-ldflags="-lc -ldl -lm -lz -llog -lgcc -L$OUTPUT/lib"
  
  # ...省略了不变的部分
}

package_library() {
  $TOOLCHAIN/bin/aarch64-linux-android-ld -L$OUTPUT/lib -L$GCC_L \
    -rpath-link=$SYSROOT_L/$API -L$SYSROOT_L/$API -soname libffmpeg.so \
    -shared -nostdlib -Bsymbolic --whole-archive --no-undefined -o $OUTPUT/libffmpeg.so \
    -lavcodec -lpostproc -lavfilter -lswresample -lavformat -lavutil -lswscale -lgcc \
    -lc -ldl -lm -lz -llog \
    --dynamic-linker=/system/bin/linker
    # 设置动态链接器,不同平台的不同,android 使用的是/system/bin/linker
}

build
package_library

The above list is just a snippet of code, and only the parts that have been changed are listed. The general process is:
clang 编译出静态库 -> 使用 Android 自带的链接器将编译出的静态库打包成一个动态库

Let's focus on a few options:

  • -rpath-link
When using ELF or SunOS, one shared library may require another. This happens when
an `"ld -shared"` link includes a shared library as one of the input files.

When the linker encounters such a dependency when doing a non-shared, non-relocatable 
link, it will automatically try to locate the required shared library and include it in 
the link, if it is not included explicitly. In such a case, the **-rpath-link** option 
specifies the first set of directories to search. The **-rpath-link** option may 
specify a sequence of directory names either by specifying a list of names separated by 
colons, or by appearing multiple times.

The above is the official introduction . Here I dare to summarize it in one sentence. It may not be accurate, but it is enough to understand:
this is a sign passed to the linker. 依赖关系When , it needs to be packaged according to 依赖关系Do it, otherwise an error will be reported. With this flag, we only need to set the directory of the library, and we don’t need to manage dependencies. The linker will handle it for us when linking.

  • -soname The interpretation of this option is: add an alias to the library, that is 可以通过别名引用库, why an alias? Because we first created multiple static libraries at the beginning, the static library already has its own name, if you don’t do alias mapping for them uniformly, you will find that when you load the library, you keep reporting an error, saying that the one you specified cannot be found. Library file, you can try it if you don’t believe me^^.
  • --dynamic-linker This option is used to set the dynamic linker, remember the above mentioned 问题一, in order to solve this problem, here is set to the linker used by Android, that is /system/bin/linker, about this, you can see here

4. Compile again

The result of the operation is as follows

So far, we have completed the compilation of FFmpeg.

3. Introduction to the use of the script
The author encapsulates the compilation script to adapt to the convenience of compiling the so library of each Android platform. The script link is at the beginning of the article. The following describes the usage steps:

  1. Put the script in the FFmpeg source code root directory
  2. Open the script in text mode, simply modify the few parameters listed below
# 构建的最低支持 API 等级
API=21
# 在什么系统上构建,mac:darwin,linux:linux,windows:windows
OS_TYPE=darwin
# 自己本机 NDK 所在目录
NDK=/Users/mac/Library/Android/sdk/ndk/21.4.7075529
# 目标文件输出目录,默认是当前目录下的 android 目录
OUTPUT=$(pwd)/android/$ABI

  1. Open the terminal, enter the FFmpeg source code directory, and execute the script: sh build_ffmpeg_android.sh 1

After executing the rule
sh build_ffmpeg_android.sh, four items 1, 2, 3, and 4 can be attached. The meaning of these four items is explained below.
1: Build the library file of the arm64-v8a architecture
2: Build the library file of the armeabi-v7a architecture
3 : Build the library file of the x86_64 architecture
4: Build the library file of the x86 architecture
If you want to build multiple platforms, you can attach multiple items, separated by spaces, such as building all platforms:
sh build_ffmpeg_android.sh 1 2 3 4

4. Problems encountered

  1. Running the script shows no permission
Modify the file permissions and run again: chmod 777 build_ffmpeg_android.sh

  1. Run the script, it shows that there are unrecognized characters in the script and cannot run

Solution 1:
Visual Studio Code  instead of Notepad, re-edit
Solution 2:
Install dos2unix software
mac: brew install dos2unix
ubuntu: sudo apt install dos2unix
Use: dos2unix build_ffmpeg_android.sh
and then run it again. When

compiling the library, an error is reported. x86The error is as follows

At this time, you only need to add: --disable-asm after ./configure, and then recompile will be fine, because the  x86 platform removes the register, if you do not disable this item, an error will be reported. The detailed reason is here .

  1. The libraries used when packaging multiple libraries  gcc are also in other directories

Allow me to complain here, I think it is a huge pit... Because when I packaged it, I used gcc in another directory at the beginning. The packaging of some platforms is normal, but the packaging of the armeabi-v7a platform has been unsuccessful. After trying for a long time, I found that the current directory also has it, and there is no problem. If you also encounter the same problem, it will be no problem to replace it with the gcc in the directory I introduced.

V. Summary

  1. Compilation problems on the Android side are often caused by unfamiliarity with the directory of the compilation toolchain and the corresponding library cannot be found
  2. When compiling, if you encounter a library that is missing, go to the directory introduced above to find it and add it when compiling.
  3. Practice more, and you will find the true meaning of the saying "What you learn in the book will eventually make you feel shallow" Finally, if you think this article is helpful to you, please give it a thumbs up ^w^

reference article

FFmpeg so library compilation
How to cross-platform compile files that can be executed on Android
FFmpeg x86 compilation problem
Linker -rpath introduction
Compile FFmpeg into a libffmpeg.so library

Android-NDK-clang compiles FFmpeg - Nuggets 

★The business card at the end of the article can receive free audio and video development learning materials, including (FFmpeg, webRTC, rtmp, hls, rtsp, ffplay, srs) and audio and video learning roadmaps, etc.

see below!

 

Guess you like

Origin blog.csdn.net/yinshipin007/article/details/131405928