[sound Ming]

First of all, the article is based on their own understanding and practice, there may be wrong places, welcome to correct.

Second, this is an article documenting the problems encountered in the FFmpeg compilation process and the solutions.

Finally, in the process of writing the article, I will refer to the articles shared by others, which will be listed at the end of the article, thanks to these authors for sharing.

Code word is not easy to reprint, please indicate the source!

Practical Achievements: [Making portal】

preparation

  1. Download the Android – the NDK
  2. Download the FFmpeg source code

Note: I compiled with NDK-21 and FFMPEG-4.4, which may vary depending on the version. Test: MAC and Ubuntu ndK20-NDK22 and FFMPEG 4.0-FFMPEG 4.4, can be used.

You can read about it in this article

  • NDK20 – Main directory of cross-compile toolchains provided by NDK22
  • useclangThe libffmpeg.so library is cross-compiled for the Android platform
  • Partial compilation details

The NDK provides the main directory and file for cross-compiling the tool chain

The directory structure of the NDK20 – NDK22 tool chain is basically the same as the NDK21 directory.



As shown in the figure above, these are the directories that are used to compile FFmpeggccLibraries inAarch64, ARM, X86_64, x86Among these folders, here’s a look at how these names relate to different platform libraries in Android.

Aarch64: Directories with this prefix are associated with arm64-v8a libraries arm: directories with this prefix are associated with armeabi-v7a libraries x86_64: directories with this prefix are associated with x86_64 libraries x86: directories with this prefix are associated with x86 libraries

1. Clang compilation tool

LLVM ->prebuilt->darwin-x86_64->bin -> LLVM ->prebuilt->darwin-x86_64->bin Clang is used to compile C files, and clang++ is used to compile C ++ files.

  • Note here:21 and i686
  • 21: indicates the lowest version of Android supported by the compiled library
  • I686: indicates the compiler tool that compiles the x86 library platform

The NDK directory names are as follows: MAC: Darwin-x86_64 Linux: linux-x86_64 Windows: Windows-x86_64 Note: The NDK directories in the MAC operating system are described as follows

2. Compile environment, needed libraries

The directory where the library and header files are located isdarwin-x86_64Under thesysrootDirectory where header files are locatedincludeDirectory, library inlibDirectory, and once you know that, you can start compiling.

Second, the use ofclangThe libffmpeg.so library is cross-compiled for the Android platform

Go to the FFmpeg source root directory

1. Create the build_ffmpeg_android.sh script

The script is as follows:

#! /bin/sh
# Path where NDK is locatedThe NDK = / Users/MAC/Library/Android/SDK/the NDK / 21.4.7075529Arm64-v8a = arm64-V8A = arm64-V8A = arm64-V8A
ARCH=aarch64
# Lowest Supported Android API
API=21
/android/arm64-v8a /android/arm64-v8a
OUTPUT=$(pwd)/android/arm64-v8a
# Path where the NDK cross-compile tool chain is locatedTOOLCHAIN = / Users/MAC/Library/Android/SDK/the NDK / 21.4.7075529 / toolchains/LLVM/prebuilt/Darwin - x86_64build() {
  ./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
Copy the code

This shell script, by and large, is actually pretty easy to understand, For example –disabble-static disables the output of static libraries –enable-shared outputs of dynamic libraries –arch specifies the architecture of the output so library –prefix specifies the path to the output so library enable-cross-compile Enable multi-platform compilation, which means you can compile libraries for multiple platforms. More options can be found on the website, which will not be covered here.

Let’s focus on a few options:

  • target-os

– target – OS = android: In older versions of FFmpeg, the support for Android was not perfect. There was no Android target, so some older articles mentioned that you need to modify configure to build so libraries for Android. Otherwise, it will be in accordance with the Linux standard output so library, its naming method and Android so is not the same, Android is unable to load, so when compiling, FFmpeg source version and the author of the best choice.

Problem 1: The so library output under Linux cannot be loaded under Android

  • sysroot

–sysroot=$TOOLCHAIN/sysroot: configures the root path of the cross-compile environment. By default, this path is used to look for usr/include usr/lib to find related header files and libraries. The ndK20-NDK22 system header and library files are in $SYSYROOT/usr/include and $SYSYROOT/usr/lib.

  • extra-cflags

To the compiler to specify some compilation flags, such as: set the header file path: format – I head file path set compiled binaries to position-independent code files: format -fpic as to why you need to compile the position-independent code files, because the packaging so library is composed of multiple position-independent code of binary files.

  • extra-ldflags

Set the path to the library to be linked: format -l Library file path to the output library and set the name: format -o Library name To set the library to be linked: format -L Library name The a-O library name needs to be prefixed with lib, and the part of the suffix with.so/.a, such as -o liba.so-l library name is not prefixed with lib, and the part with.so/.a, such as -la

For more information on compiling and linking flags, see here.

  • cross-prefix

The prefix of the compiler tool for configuring cross-compilation is the prefix of the file name in the directory where the cross-compilation related file is located, such as: Armeabi-v7a is arm-linux-Androideabi. For details, check the bin directory in the cross-compilation tool chain.

  • cc
  • cxx

These two items are to configure the above mentioned use Android clang tool specific path.

2. Start compiling

Go to the FFmpeg source root directory through the terminal and run the compile script that you just wrote.

sh build_ffmpeg_android.sh
Copy the code

The result is as follows

As shown in the figure above, the red box is all the files we compiled, but it is also troublesome to use so many files, so we need to put thempackagingSo file.

3. Package multiple libraries into one library
  • Modify the compilation script as follows
#! /bin/sh # ... Omit the part of the same SYSROOT_L = $TOOLCHAIN/sysroot/usr/lib/aarch64 - Linux - android GCC_L = $the 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 uses /system/bin/linker} build package_libraryCopy the code

Clang builds static libraries -> Use Android’s linker to package the compiled static libraries into a dynamic library

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.
Copy the code

Above is the official introduction, here I dare to summarize in one sentence, may not be quite accurate, but can understand the line: This is a flag passed to the linker. When we use a library that has dependencies, we need to package according to the dependencies, otherwise we will report an error. If we use this flag, we only need to set the directory of the library, we don’t need to manage the dependencies.

  • -soname

Add an alias to the library. You can refer to the library by an alias. Because we started with multiple static libraries, the static library already has its own name, if you do not use the same alias mapping, you will find that you can not find the library file, you can give it a try.

  • –dynamic-linker

This option is used to set the dynamic linker. Remember from the first question above, to solve this problem, we set it to the linker used by Android, which is /system/bin/linker.

4. Compile again

The result is as follows

At this point, we are finished compiling FFmpeg.

Iii. Introduction to script usage

The author encapsulates the compilation script to facilitate the compilation of so libraries of various Android platforms. The script link is at the beginning of this article, and the following steps are introduced:

  1. Place the script in the FFmpeg source root directory
  2. Open the script as text and simply modify the parameters listed below
# Build on MAC: Darwin, Linux: Linux, Windows: Windows OS_TYPE = # Darwin himself the machine the NDK directory the NDK = / Users/MAC/Library/Android/SDK/the NDK / 21.4.7075529 # target output file directory, The default is the Android directory OUTPUT=$(PWD)/ Android /$ABI in the current directoryCopy the code
  1. Open the terminal, go to the FFmpeg source directory, and run the script: sh build_ffmpeg_android.sh 1

After executing rules sh build_ffmpeg_android. Sh can with 1, 2, 3, 4 of the below illustrate the significance of these four 1: build arm64 – v8a architecture of the library files 2: build armeabi – v7a architecture of the library files: Build libraries for x86_64 architecture 4: Build libraries for x86 architecture If you want to build multiple platforms, you can add multiple files separated by a space. For example, run sh build_ffmpeg_android.sh 1 2 3 4

Iv. Problems encountered

  1. Run the script to show no permissions

Change the file permission and run again: chmod 777 build_ffmpeg_android.sh

  1. When the script is run, unrecognized characters exist in the script

Solution 1: Replace notepad with Visual Studio Code and edit it again. Solution 2: Install dos2UNIX for MAC: Brew install dos2UNIX for Ubuntu: Sudo apt install dos2UNIX: dos2UNIX build_ffmpeg_android.sh and run again

  1. compilex86Error: error: error: error: error

–disable-asm –disable-asm –disable-asm –disable-asm –disable-asm –disable-asm –disable-asm –disable-asm

  1. Used when packaging multiple librariesgccThe library is also available in other directories

If I may joke here, I think it’s a giant pit… Because I used GCC in other directories at the beginning of the packaging process, the packaging of some platforms is normal, but the packaging of Armeabi-V7a platform has not been successful. After trying for a long time, I found that the current directory also has GCC, and it is ok. If you have the same problem, use GCC for the directory I’ve shown you.

Five, the summary

  1. Most of the compilation problems on The Android side are due to the fact that you are not familiar with the directory of the compilation tool chain and cannot find the corresponding library
  2. If a library is missing at compile time, just go to the above directory and add it at compile time
  3. Put your hands into practice and you will find out the truth of the saying “books are the best.

Finally, if you found this post helpful, just give it a like

Refer to the article

How to compile a file that can be executed on Android FFmpeg x86 compiler problem linker -rpath introduction FFmpeg into a libffmpeg.so library