macos NDK 交叉编译X264
x264是一个开源的H.264/MPEG-4 AVC视频编码函数库,是最好的有损视频编码器之一。 它将作为我们直播数据的视频编码库。
FFmpeg中同样实现了H.264的编码,同时FFmpeg也能够集成X264。本次我们将直接使用X264来进行视 频编码而不是FFmpeg
[X264 主页]
Source
The latest x264 source code is available through git repository:
# git clone https://code.videolan.org/videolan/x264.git
You can browse the source on-line.
存在configure,这时候我们第一反应一定是执行help
./configure --help
Usage: ./configure [options]
Help:
-h, --help print this message
Standard options:
--prefix=PREFIX install architecture-independent files in PREFIX
[/usr/local]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
[PREFIX]
--bindir=DIR install binaries in DIR [EPREFIX/bin]
--libdir=DIR install libs in DIR [EPREFIX/lib]
--includedir=DIR install includes in DIR [PREFIX/include]
--extra-asflags=EASFLAGS add EASFLAGS to ASFLAGS
--extra-cflags=ECFLAGS add ECFLAGS to CFLAGS
--extra-ldflags=ELDFLAGS add ELDFLAGS to LDFLAGS
--extra-rcflags=ERCFLAGS add ERCFLAGS to RCFLAGS
Configuration options:
--disable-cli disable cli
--system-libx264 use system libx264 instead of internal
--enable-shared build shared library
--enable-static build static library
--disable-bashcompletion disable installation of bash-completion script
--enable-bashcompletion force installation of bash-completion script
--bashcompletionsdir=DIR install bash-completion script in DIR [auto]
--disable-opencl disable OpenCL features
--disable-gpl disable GPL-only features
--disable-thread disable multithreaded encoding
--disable-win32thread disable win32threads (windows only)
--disable-interlaced disable interlaced encoding support
--bit-depth=BIT_DEPTH set output bit depth (8, 10, all) [all]
--chroma-format=FORMAT output chroma format (400, 420, 422, 444, all) [all]
Advanced options:
--disable-asm disable platform-specific assembly optimizations
--enable-lto enable link-time optimization
--enable-debug add -g
--enable-gprof add -pg
--enable-strip add -s
--enable-pic build position-independent code
Cross-compilation:
--host=HOST build programs to run on HOST
--cross-prefix=PREFIX use PREFIX for compilation tools
--sysroot=SYSROOT root of cross-build tree
External library support:
--disable-avs disable avisynth support
--disable-swscale disable swscale support
--disable-lavf disable libavformat support
--disable-ffms disable ffmpegsource support
--disable-gpac disable gpac support
--disable-lsmash disable lsmash support
-
--prefix
设置编译结果输出目录,一般规范都会存在这个参数 -
--exec-prefix
参数表示我们可以借助这个对编译器(gcc/clang)设置选项 「类似javac设置-classpath」 -
--disable-cli
这个配置是关闭编译命令行工具,在Android,是自己编译代码,用不到,也可以不管,倒库的是后不用就好 -
--enable-shared &
编译成静态库是动态库.so -
--enable-static
编译成静态库.a -
--enable-debug & --enable-gprof & --enable-strip
给编译器传递参数 相当 gcc -g / clang -g -
--enable-pic
如果编译Android使用的动态库,使用PIC 指令。有的--with-pic. 一些脚本没有提供那么我们可以加上gcc -fPIC 通过 CFLAGS 变量 CFLAGS=“-g -fPIC -xxx" 开启 x264 还给我们提供了跨平台的参数Configuration options:--cross-prefix
--cross-prefix=前缀- 那么我们相当于使用“gcc xxx.c” 就会用 “前缀-gcc xxxx.c” 编译--sysroot
查找库,有点类似-L 使用。但是有区别--extra-cflags
作为传递给编译器的参数,所以就算有些库没有--extra-cflags配置,我们也可以自己创建变量cFLAGS传参
虽然x264提供了交叉编译配置:--cross-prefix,如--corss-prefix=/NDK/arm-linux-androideabi-
那么则会使用 /NDK/arm-linux-androideabi-gcc 来编译
然而ndk19开始gcc已经被移除,由clang替代。
小常识:一般的库都会使用$CC 变量来保存编译器,我们自己设置CC变量的值为clang。
export CC=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang
export CXX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++
mac 脚本
#!/bin/bash
# NDK目录
NDK_ROOT=/Users/jiangbin/Library/Android/sdk/ndk/21.1.6352462
#编译后安装位置 pwd表示当前目录
PREFIX=`pwd`/android/armeabi-v7a
#目标平台版本,我们将兼容到android-21
API=21
#编译工具链目录
TOOLCHAIN=$NDK_ROOT/toolchains/llvm/prebuilt/darwin-x86_64
#小技巧,创建一个AS的NDK工程,执行编译,
#然后在 app/.cxx/cmake/debug(release)/自己要编译的平台/ 目录下自己观察 build.ninja与 rules.ninja
# 虽然x264提供了交叉编译配置:--cross-prefix,如--corss-prefix=/NDK/arm-linux-androideabi-
# 那么则会使用 /NDK/arm-linux-androideabi-gcc 来编译
# 然而ndk19开始gcc已经被移除,由clang替代。
# 小常识:一般的库都会使用$CC 变量来保存编译器,我们自己设置CC变量的值为clang。
export CC=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang
export CXX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++
#--extra-cflags会附加到CFLAGS 变量之后,作为传递给编译器的参数,所以就算有些库没有--extra-cflags配置,我们也可以自己创建变量cFLAGS传参
FLAGS="--target=armv7-none-linux-androideabi21 --gcc-toolchain=${TOOLCHAIN} -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -march=armv7-a -mthumb -Wformat -Werror=format-security -Oz -DNDEBUG -fPIC "
# echo ${FLAGS}
# prefix: 指定编译结果的保存目录 `pwd`: 当前目录
./configure --prefix=${PREFIX} \
--disable-cli \
--enable-static \
--enable-pic=no \
--host=arm-linux \
--cross-prefix=${TOOLCHAIN}/bin/arm-linux-androideabi- \
--sysroot=${TOOLCHAIN}/sysroot \
--extra-cflags=$FLAGS
make install
编译脚本修改,编译 armeabi-v7a arm64-v8a x86_64
x86编译不成功
脚本文件目录结构如下:
config.sh
#NDK路径
export ANDROID_NDK_ROOT=/Users/jiangbin/Library/Android/sdk/ndk/21.1.6352462
export AOSP_TOOLCHAIN_SUFFIX=4.9
export AOSP_API="android-21"
#目标平台版本,我们将兼容到android-21
API=21
#架构
if [ "$#" -lt 1 ]; then
THE_ARCH=armv7
else
THE_ARCH=$(tr [A-Z] [a-z] <<< "$1")
fi
#根据不同架构配置环境变量
case "$THE_ARCH" in
armv7a|armeabi-v7a)
TOOLCHAIN_BASE="arm-linux-androideabi"
TOOLNAME_BASE="arm-linux-androideabi"
AOSP_ABI="armeabi-v7a"
AOSP_ARCH="arch-arm"
HOST="arm-linux-androideabi"
AOSP_FLAGS="-march=armv7-a -mthumb -mfpu=vfpv3-d16 -mfloat-abi=softfp -Wl,--fix-cortex-a8 -funwind-tables -fexceptions -frtti"
FF_EXTRA_CFLAGS="-DANDROID -fPIC -ffunction-sections -funwind-tables -fstack-protector -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -fomit-frame-pointer -fstrict-aliasing -funswitch-loops -finline-limit=300 "
FF_CFLAGS="-O3 -Wall -pipe -ffast-math -fstrict-aliasing -Werror=strict-aliasing -Wno-psabi -Wa,--noexecstack -DANDROID "
;;
armv8|armv8a|aarch64|arm64|arm64-v8a)
TOOLCHAIN_BASE="aarch64-linux-android"
TOOLNAME_BASE="aarch64-linux-android"
AOSP_ABI="arm64-v8a"
AOSP_ARCH="arch-arm64"
HOST="aarch64-linux"
AOSP_FLAGS="-funwind-tables -fexceptions -frtti"
FF_EXTRA_CFLAGS=""
FF_CFLAGS="-O3 -Wall -pipe -ffast-math -fstrict-aliasing -Werror=strict-aliasing -Wno-psabi -Wa,--noexecstack -DANDROID "
;;
x86)
TOOLCHAIN_BASE="x86"
TOOLNAME_BASE="i686-linux-android"
AOSP_ABI="x86"
AOSP_ARCH="arch-x86"
HOST="i686-linux"
AOSP_FLAGS="-march=i686 -mtune=intel -mssse3 -mfpmath=sse -funwind-tables -fexceptions -frtti"
FF_EXTRA_CFLAGS="-O3 -DANDROID -Dipv6mr_interface=ipv6mr_ifindex -fasm -Wno-psabi -fno-short-enums -fno-strict-aliasing -fomit-frame-pointer -march=k8 "
FF_CFLAGS="-O3 -Wall -pipe -ffast-math -fstrict-aliasing -Werror=strict-aliasing -Wno-psabi -Wa,--noexecstack -DANDROID "
;;
x86_64|x64)
TOOLCHAIN_BASE="x86_64"
TOOLNAME_BASE="x86_64-linux-android"
AOSP_ABI="x86_64"
AOSP_ARCH="arch-x86_64"
HOST="x86_64-linux"
AOSP_FLAGS="-march=x86-64 -msse4.2 -mpopcnt -mtune=intel -funwind-tables -fexceptions -frtti"
FF_EXTRA_CFLAGS="-O3 -DANDROID -Dipv6mr_interface=ipv6mr_ifindex -fasm -Wno-psabi -fno-short-enums -fno-strict-aliasing -fomit-frame-pointer -march=k8 "
FF_CFLAGS="-O3 -Wall -pipe -ffast-math -fstrict-aliasing -Werror=strict-aliasing -Wno-psabi -Wa,--noexecstack -DANDROID "
;;
*)
echo "ERROR: Unknown architecture $1"
[ "$0" = "$BASH_SOURCE" ] && exit 1 || return 1
;;
esac
echo "TOOLCHAIN_BASE="$TOOLCHAIN_BASE
echo "TOOLNAME_BASE="$TOOLNAME_BASE
echo "AOSP_ABI="$AOSP_ABI
echo "AOSP_ARCH="$AOSP_ARCH
echo "AOSP_FLAGS="$AOSP_FLAGS
echo "HOST="$HOST
build_x264.sh
#!/bin/bash
ARCH=$1
#目标平台版本,我们将兼容到android-21
API=21
source config.sh $ARCH
LIBS_DIR=$(cd `dirname $0`; pwd)/libs/libx264
echo "LIBS_DIR="$LIBS_DIR
#echo "ANDROID_NDK_ROOT="$ANDROID_NDK_ROOT
cd x264
PREFIX=$LIBS_DIR/$AOSP_ABI
TOOLCHAIN=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/darwin-x86_64
SYSROOT=${TOOLCHAIN}/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/$TOOLNAME_BASE-
#根据不同架构配置环境变量
case "$THE_ARCH" in
armv7a|armeabi-v7a)
export CC=${TOOLCHAIN}/bin/armv7a-linux-androideabi$API-clang
export CXX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++
;;
armv8|armv8a|aarch64|arm64|arm64-v8a)
export CC=${TOOLCHAIN}/bin/aarch64-linux-android$API-clang
export CXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++
;;
x86)
export CC=${TOOLCHAIN}/bin/i686-linux-android$API-clang
export CXX=$TOOLCHAIN/bin/i686-linux-android$API-clang++
;;
x86_64|x64)
export CC=${TOOLCHAIN}/bin/x86_64-linux-android$API-clang
export CXX=$TOOLCHAIN/bin/x86_64-linux-android$API-clang++
;;
*)
echo "ERROR: Unknown architecture $1"
[ "$0" = "$BASH_SOURCE" ] && exit 1 || return 1
;;
esac
# echo "TOOLCHAIN="$TOOLCHAIN
# echo "CC="$CC
# echo "CXX="$CXX
./configure --prefix=$PREFIX \
--enable-static \
--enable-pic \
--disable-cli \
--host=$HOST \
--cross-prefix=${TOOLCHAIN}/bin/arm-linux-androideabi- \
--sysroot=$SYSROOT \
--extra-cflags="-Os -fpic" \
--extra-ldflags=""
make clean
make -j4
make install
cd ..
build_x264_all
for arch in armeabi-v7a arm64-v8a x86_64
do
bash build_x264.sh $arch
done
运行编译
#编译指定平台
bash build_x264.sh armeabi-v7a
#编译全平台
bash build_all_x264.sh
tree ✔ 1530 14:18:10
.
└── libx264
├── arm64-v8a
│ ├── include
│ │ ├── x264.h
│ │ └── x264_config.h
│ └── lib
│ ├── libx264.a
│ └── pkgconfig
│ └── x264.pc
├── armeabi-v7a
│ ├── include
│ │ ├── x264.h
│ │ └── x264_config.h
│ └── lib
│ ├── libx264.a
│ └── pkgconfig
│ └── x264.pc
└── x86_64
├── include
│ ├── x264.h
│ └── x264_config.h
└── lib
├── libx264.a
└── pkgconfig
└── x264.pc
13 directories, 12 files
生成libx264目录结果
x86平台
bash build_x264.sh x86
In file included from ./common/common.h:808:
./common/x86/util.h:134:9: error: inline assembly requires more registers than available
"movq (%2), %%mm5 \n"
^
./common/x86/util.h:198:9: error: inline assembly requires more registers than available
"movq (%2), %%mm5 \n"
^
2 errors generated.
加入编译选项
--disable-asm