Android 端IjkPlayer交叉编译的逻辑分析

时间:2024-10-09 07:17:49

Android 端IjkPlayer交叉编译的逻辑分析

    • 交叉编译的原理
    • 为什么要交叉编译
    • 交叉编译的工具
    • Android NDK 支持的编译器
      • Android NDK 提供了两种编译器: GCC、Clang
    • Android平台的交叉编译
      • Android NDK 的目录结构
      • 高版本NDK toolchiains目录:
      • GCC 编译 FFmpeg
      • Clang 编译 FFmpeg
    • IjkPlayer的交叉编译
      • ijkplayer 交叉编译分析

交叉编译的原理

所谓交叉编译,就是一个平台(如PC)上生成另外一个平台(Android,iOS或者其他嵌入式设备)的可执行代码。

为什么要交叉编译

在一般的嵌入式设备开发系统中(Android,ios),运行程序的目标平台其存储空间和运算能力都是有限的。

交叉编译的工具

无论是PC机上的编译还是嵌入式设备中的编译,它们都会提供以下几个工具:CC、AS、AR、LD、NM、GDB。那么,这几个工具到底是做什么用的呢?下面就逐一解释下。

CC:编译器,对C源文件进行编译处理,生成汇编语言。

AS:将汇编语言生成目标文件.

AR:打包器,用于库操作,通过该工具从一个库中删除或者增加代码模块.

LD:连接器,将多个目标文件链接成一个库或者可执行文件.

GDB:调试工具.

STRIP:以最终可执行的文件或者库文件作为输入,然后消除掉其中的源码.

NM:查看静态库中的符号表.

Objdump:查看静态库或者动态库的方法签名.

Android NDK 支持的编译器

Android NDK 提供了两种编译器: GCC、Clang

Android NDK从r11开始建议大家切换到clang。并且把GCC标记为deprecated,将GCC版本锁定在GCC 4.9不再更新。

  • PSA: Everyone should be switching to Clang.
  • Clang has been updated to 3.8svn (r243773, build 2481030).
    • Time to start using Clang if you haven’t already. If you have
      problems with Clang, please file bugs!

    • The NDK will not be upgrading to , nor will we be accepting non-critical backports.
      Maintenance for miscompiles and internal compiler errors in 4.9 will be handled on a case by case basis.
      Note that this is now a nearly pure upstream clang.
      Also note that Clang packaged in the Windows 64 NDK is actually 32-bit.
      GCC in the NDK is now deprecated.

    • GCC 4.8 has been removed. All targets now use GCC 4.9.

    • Synchronized with google/gcc-4_9 to r224707 (from r214835).

Android平台的交叉编译

Android NDK 的目录结构

在这里插入图片描述
ndk-build: 该shell脚本用来构建项目动态库

ndk-gdb: 该shell脚本用GUN调试器调试Native代码

ndk-stack: 该shell脚本分析Native代码崩溃是的堆栈信息

build: 该目录包含NDK构建系统的所有模块

platform: 该目录包含支持不同Android目标版本的头文件和库文件,NDK构建系统会根据具体的配置来引用指定平台下的头文件和库文件

toolchiains:该目录包含目前NDK所支持的不同平台下的交叉编译器------ARM、x86、MIPS

高版本NDK toolchiains目录:

在这里插入图片描述
Clang 主要使用llvm 实现交叉编译

GCC 编译 FFmpeg

Android交叉编译主要使用android NDK目录结构中platform、toolchiains;

现在我主要讲解利用GCC编译器实现交叉编译,Clang编译器目前主要是在高版本的NDK中才支持,后面讲解如何利用Clang编译器交叉编译FFmpeg 4.0+;

建议GCC编译FFmpeg 4.0以下的版本,用Clang编译FFmpeg4.0以上的版本,否则你会发现用GCC编译FFmpeg4.0以上的版本会出现各种错误;

  • FFmpeg 下载 : / (下载3.2.14)
    修改FFmpeg的configure,下载FFmpeg源代码之后,首先需要对源代码中的
  • configure文件进行修改。由于编译出来的动态库文件名的版本号在.so之后(例如“.5.100.1”),而android平台不能识别这样文件名,所以需要修改这种文件名。在configure文件中找到下面几行代码:
SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'
SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR)$(SLIBNAME)'
  • 1
  • 2
  • 3
  • 4

替换为下面内容:

SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'
  • 1
  • 2
  • 3
  • 4
  • 生成FFmpeg的头文件和类库文件
cd ffmpeg-3.2.14
 
export NDK=/Users/videopls/android/android-ndk-r14b
export PREBUILT=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt
export PLATFORM=$NDK/platforms/android-9/arch-arm
export PREFIX=../ffmpeg_3.2.14_lib
build_one(){
  ./configure --target-os=linux --prefix=$PREFIX \
--enable-cross-compile \
--enable-runtime-cpudetect \
--disable-asm \
--arch=arm \
--cc=$PREBUILT/darwin-x86_64/bin/arm-linux-androideabi-gcc \
--cross-prefix=$PREBUILT/darwin-x86_64/bin/arm-linux-androideabi- \
--disable-stripping \
--nm=$PREBUILT/darwin-x86_64/bin/arm-linux-androideabi-nm \
--sysroot=$PLATFORM \
--enable-gpl --enable-shared --disable-static --enable-small \
--disable-ffprobe --disable-ffplay --disable-ffmpeg --disable-debug --disable-ffserver \
--extra-cflags="-fPIC -DANDROID -D__thumb__ -mthumb -Wfatal-errors -Wno-deprecated -mfloat-abi=softfp -marm -march=armv7-a"
}
 
build_one
 
make clean
make -j8
make install
 
cd ..
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • FFmpeg 的裁剪及链接x264、fdk_aac等第三方库这里就不讲解了,如果想了解的可以通过 ./configure -h
    查看每个参数的具体含义及网上搜索资料;

Clang 编译 FFmpeg

Clang 主要使用NDK → toolchiains → llvm 中的编译工具实现交叉编译 ;

  • clang 编译环境的位置: toolchains/llvm/prebuilt/darwin-x86_64
  • 编译工具的内容:toolchains/llvm/prebuilt/darwin-x86_64/bin
aarch64-linux-android-addr2line
aarch64-linux-android-ar
aarch64-linux-android-as
aarch64-linux-android-c++filt
aarch64-linux-android-dwp
aarch64-linux-android-elfedit
aarch64-linux-android-gprof
aarch64-linux-android-ld
aarch64-linux-android-ld.bfd
aarch64-linux-android-ld.gold
aarch64-linux-android-nm
aarch64-linux-android-objcopy
aarch64-linux-android-objdump
aarch64-linux-android-ranlib
aarch64-linux-android-readelf
aarch64-linux-android-size
aarch64-linux-android-strings
aarch64-linux-android-strip
aarch64-linux-android21-clang
aarch64-linux-android21-clang++
aarch64-linux-android22-clang
aarch64-linux-android22-clang++
aarch64-linux-android23-clang
aarch64-linux-android23-clang++
aarch64-linux-android24-clang
aarch64-linux-android24-clang++
aarch64-linux-android26-clang
aarch64-linux-android26-clang++
aarch64-linux-android27-clang
aarch64-linux-android27-clang++
aarch64-linux-android28-clang
aarch64-linux-android28-clang++
arm-linux-androideabi-addr2line
arm-linux-androideabi-ar
arm-linux-androideabi-as
arm-linux-androideabi-c++filt
arm-linux-androideabi-dwp
arm-linux-androideabi-elfedit
arm-linux-androideabi-gprof
arm-linux-androideabi-ld
arm-linux-androideabi-ld.bfd
arm-linux-androideabi-ld.gold
arm-linux-androideabi-nm
arm-linux-androideabi-objcopy
arm-linux-androideabi-objdump
arm-linux-androideabi-ranlib
arm-linux-androideabi-readelf
arm-linux-androideabi-size
arm-linux-androideabi-strings
arm-linux-androideabi-strip
armv7a-linux-androideabi16-clang
armv7a-linux-androideabi16-clang++
armv7a-linux-androideabi17-clang
armv7a-linux-androideabi17-clang++
armv7a-linux-androideabi18-clang
armv7a-linux-androideabi18-clang++
armv7a-linux-androideabi19-clang
armv7a-linux-androideabi19-clang++
armv7a-linux-androideabi21-clang
armv7a-linux-androideabi21-clang++
armv7a-linux-androideabi22-clang
armv7a-linux-androideabi22-clang++
armv7a-linux-androideabi23-clang
armv7a-linux-androideabi23-clang++
armv7a-linux-androideabi24-clang
armv7a-linux-androideabi24-clang++
armv7a-linux-androideabi26-clang
armv7a-linux-androideabi26-clang++
armv7a-linux-androideabi27-clang
armv7a-linux-androideabi27-clang++
armv7a-linux-androideabi28-clang
armv7a-linux-androideabi28-clang++
i686-linux-android-addr2line
i686-linux-android-ar
i686-linux-android-as
i686-linux-android-c++filt
i686-linux-android-dwp
i686-linux-android-elfedit
i686-linux-android-gprof
i686-linux-android-ld
i686-linux-android-ld.bfd
i686-linux-android-ld.gold
i686-linux-android-nm
i686-linux-android-objcopy
i686-linux-android-objdump
i686-linux-android-ranlib
i686-linux-android-readelf
i686-linux-android-size
i686-linux-android-strings
i686-linux-android-strip
i686-linux-android16-clang
i686-linux-android16-clang++
i686-linux-android17-clang
i686-linux-android17-clang++
i686-linux-android18-clang
i686-linux-android18-clang++
i686-linux-android19-clang
i686-linux-android19-clang++
i686-linux-android21-clang
i686-linux-android21-clang++
i686-linux-android22-clang
i686-linux-android22-clang++
i686-linux-android23-clang
i686-linux-android23-clang++
i686-linux-android24-clang
i686-linux-android24-clang++
i686-linux-android26-clang
i686-linux-android26-clang++
i686-linux-android27-clang
i686-linux-android27-clang++
i686-linux-android28-clang
i686-linux-android28-clang++
x86_64-linux-android-addr2line
x86_64-linux-android-ar
x86_64-linux-android-as
x86_64-linux-android-c++filt
x86_64-linux-android-dwp
x86_64-linux-android-elfedit
x86_64-linux-android-gprof
x86_64-linux-android-ld
x86_64-linux-android-ld.bfd
x86_64-linux-android-ld.gold
x86_64-linux-android-nm
x86_64-linux-android-objcopy
x86_64-linux-android-objdump
x86_64-linux-android-ranlib
x86_64-linux-android-readelf
x86_64-linux-android-size
x86_64-linux-android-strings
x86_64-linux-android-strip
x86_64-linux-android21-clang
x86_64-linux-android21-clang++
x86_64-linux-android22-clang
x86_64-linux-android22-clang++
x86_64-linux-android23-clang
x86_64-linux-android23-clang++
x86_64-linux-android24-clang
x86_64-linux-android24-clang++
x86_64-linux-android26-clang
x86_64-linux-android26-clang++
x86_64-linux-android27-clang
x86_64-linux-android27-clang++
x86_64-linux-android28-clang
x86_64-linux-android28-clang++
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 通过观察目录可以发现, toolchains/llvm/prebuilt/darwin-x86_64/bin中包含了aarch64、armv7a 、armv7a 、x86_64等CPU架构的编译工具;通过该工具可以编译出我们期望的库文件;
  • clang、 clang++ 是不仅分架构还分 Android 版本的,而其他工具只分架构
armv7a-linux-androideabi16-clang
armv7a-linux-androideabi16-clang++
armv7a-linux-androideabi17-clang
armv7a-linux-androideabi17-clang++
armv7a-linux-androideabi18-clang
armv7a-linux-androideabi18-clang++
armv7a-linux-androideabi19-clang
armv7a-linux-androideabi19-clang++
armv7a-linux-androideabi21-clang
armv7a-linux-androideabi21-clang++
armv7a-linux-androideabi22-clang
armv7a-linux-androideabi22-clang++
armv7a-linux-androideabi23-clang
armv7a-linux-androideabi23-clang++
armv7a-linux-androideabi24-clang
armv7a-linux-androideabi24-clang++
armv7a-linux-androideabi26-clang
armv7a-linux-androideabi26-clang++
armv7a-linux-androideabi27-clang
armv7a-linux-androideabi27-clang++
armv7a-linux-androideabi28-clang
armv7a-linux-androideabi28-clang++
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • clang 编译FFmpeg 4.2.2(最新版)
cd ffmpeg-4.2.2
 
export NDK=/Users/videopls/Library/Android/sdk/ndk-bundle
export API=22
export ARCH=aarch64
export PLATFORM=aarch64
export TARGET=$PLATFORM-linux-android
export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64/bin
#正确的sysroot
export SYSROOT=$NDK/toolchains/llvm/prebuilt/darwin-x86_64/sysroot
export CPU=aarch64
export PREFIX=../ffmpeg-4.2.2-lib
export CFLAG="-D__ANDROID_API__=$API -Os -fPIC -DANDROID "
 
./configure \
--prefix=$PREFIX \
--cc=$TOOLCHAIN/$TARGET$API-clang \
--cxx=$TOOLCHAIN/$TARGET$API-clang++ \
--target-os=android  \
--arch=$ARCH \
--cross-prefix=$TOOLCHAIN/$ARCH-linux-android- \
--disable-asm \
--enable-cross-compile \
--disable-shared \
--disable-doc \
--enable-runtime-cpudetect \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-decoders \
--disable-encoders \
--disable-devices \
--sysroot=$SYSROOT \
--extra-cflags="$CFLAG" \
--extra-ldflags=""
 
 
 
make clean
make -j8
make install
 
cd ..
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

IjkPlayer的交叉编译

  • ijkplayer github 地址: /bilibili/ijkplayer
  • Before Build
# install homebrew, git, yasm
ruby -e "$(curl -fsSL /Homebrew/install/master/install)"
brew install git
brew install yasm
 
# add these lines to your ~/.bash_profile or ~/.profile
# export ANDROID_SDK=<your sdk path>
# export ANDROID_NDK=<your ndk path>
 
# on Cygwin (unmaintained)
# install git, make, yasm
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • Build Android
git clone https://github.com/Bilibili/ijkplayer.git ijkplayer-android
cd ijkplayer-android
git checkout -B latest k0.8.8
 
./init-android.sh
 
cd android/contrib
./compile-ffmpeg.sh clean
./compile-ffmpeg.sh all
 
cd ..
./compile-ijk.sh all
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

ijkplayer 交叉编译分析

通过上面简简单单的几行代码,你会得到你想要的ijkplayer的库文件.但是如果我们对ijkplayer 有下面几个需求怎么办?

  • 修改FFmpeg 的版本
  • 对FFmpeg 进行裁剪
  • FFmpeg 引入 libx264 、fdk_aac

这个时候你就会感到迷茫,所以我们必须了解ijkplayer的编译逻辑,等了解清楚了我们就可以对它进行定制的编译符合自己的库文件.

ijkplayer编译脚本:

./init-android.sh
  
cd android/contrib
./compile-ffmpeg.sh clean
./compile-ffmpeg.sh all
  
cd ..
./compile-ijk.sh all
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
1.  把https://github.com/Bilibili/FFmpeg.git clone 到本地extra/ffmpeg;(所以如果修改FFmpeg源码,需要需要修改extra/ffmpeg里面的)
2. 把本地extra/ffmpeg更新到android/contrib/ffmpeg-armv5/armv7a/arm64/x86/x86_64中
3.
./init-config.sh
./init-android-libyuv.sh
./init-android-soundtouch.sh

3.1 init-config.sh 配置ffmpeg的裁剪,我们可以通过修改module.sh进行对ffmpeg的裁剪;

3.2 init-android-libyuv.sh 把远程库 https://github.com/Bilibili/libyuv.git clone 到本地extra/libyuv 然后把本地extra/libyuv更新到ijkmedia/ijkyuv中

3.3 init-android-soundtouch.sh 把远程库 https://github.com/Bilibili/soundtouch.git clone 到本地extra/soundtouch 然后把 本地extra/soundtouch更新到ijkmedia/ijksoundtouch中

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
1.开发环境检测,根据不同的PC环境获取不同的编译目录;不同的PC环境对应的的NDK交叉编译工具的目录是不一样的;
MAC: NDK → toolchains → arm-linux-androideabi-4.9 → prebuild → darwin-x86_64

Linux: NDK → toolchains → arm-linux-androideabi-4.9 → prebuild → linux-x86_64

Window: NDK → toolchains → arm-linux-androideabi-4.9 → prebuild →windows-x86_64

2.根据CPU架构配置不同的编译参数

3.GCC 编译FFmpeg (静态库)

4.把静态库打包成一个动态库
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • ./
1. cd ijkplayer/ijkplayer-$ARCH/src/main/jni

2. 执行 ndk-build, 会在ijkplayer/ijkplayer-$ARCH/src/main/jni/libs生成我

们需要的库文件.
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述