Android FFMPEG编解码实践(三):Ubuntu 22.04 NDK r21e编译libx265,并集成到ffmpeg

libx265交叉编译并集成应该是整个交叉编译系列中最后一部分也是最复杂的一部分了。

NDK版本 r21e

libx265版本 2.5

由于编译目标是android21,更高的265版本使用了高于21的方法(ftello与fseeko等方法,这些在21的头文件中没有声明,可以尝试添加头文件定义编译试一下,这里笔者直接决定使用2.5版本)。

一、交叉编译libx265

1.工具安装

先安装一下编译需要的工具

sudo apt install yasm cmake cmake-curses-gui

再安装一个工具

sudo apt install -y build-essential

这个工具不安装的话,会一直报错说找不到编译器,就像这样。

Android FFMPEG编解码实践(三):Ubuntu 22.04 NDK r21e编译libx265,并集成到ffmpeg_第1张图片

继续安装交叉编译器,安装交叉编译器是为了后续编译脚本设置的时候方便,略过此步骤应该也可以,但是要注意后续编译器使用绝对路径。

安装交叉编译器需要先安装python,22.04应该是自带python3的(笔者没有安装过,但是有对应命令)。虽然系统中有python3,但是没有python,所以创建个软链接python链接到python3,命令如下:

whereis python3 //先看看python3装在哪里,再创建链接

sudo ln /usr/bin/python3 /usr/bin/python //创建链接

 接下来进入ndk r21e的build/tools目录下(笔者已经将此目录加入系统路径,不用使用 ./ 执行),执行如下命令提取交叉编译器

提取32位交叉编译器:

make-standalone-toolchain.sh --arch=arm --platform=android-21 --install-dir=/home/selivert/ndktoolchain32

提取64位交叉编译器:

make-standalone-toolchain.sh --arch=arm64 --platform=android-21 --install-dir=/home/selivert/ndktoolchain64

命令执行完后,对应安装目录下的bin目录下可以找到对应的交叉编译器,笔者也将这两个路径加入系统PATH,后续修改编译脚本时直接写名称就好。

32位交叉编译工具名称

arm-linux-androideabi-gcc

arm-linux-androideabi-g++

64位交叉编译工具名称

aarch64-linux-android-gcc

aarch64-linux-android-g++

 2.修改脚本与源文件内容

打开x265文件目录下source/common/cpu.cpp文件,修改cpu_detect()函数

331 uint32_t cpu_detect(void)
332 {   
333     int flags = 0;
334 
335 #if HAVE_ARMV6
336     flags |= X265_CPU_ARMV6;
337 
338     // don't do this hack if compiled with -mfpu=neon
339 #if !HAVE_NEON
340     static void (* oldsig)(int);
341     oldsig = signal(SIGILL, sigill_handler);
342     if (sigsetjmp(jmpbuf, 1))
343     {
344         signal(SIGILL, oldsig);
345         return flags;
346     }
347 
348     canjump = 1;
349     PFX(cpu_neon_test)();
350     canjump = 0;
351     signal(SIGILL, oldsig);
352 #endif // if !HAVE_NEON
353 
354     flags |= X265_CPU_NEON;
355 
356     // fast neon -> arm (Cortex-A9) detection relies on user access to the
357     // cycle counter; this assumes ARMv7 performance counters.
358     // NEON requires at least ARMv7, ARMv8 may require changes here, but
359     // hopefully this hacky detection method will have been replaced by then.
360     // Note that there is potential for a race condition if another program or
361     // x264 instance disables or reinits the counters while x264 is using them,
362     // which may result in incorrect detection and the counters stuck enabled.
363     // right now Apple does not seem to support performance counters for this test
364 #ifndef __MACH__
365     flags |= PFX(cpu_fast_neon_mrc_test)() ? X265_CPU_FAST_NEON_MRC : 0;
366 #endif
367     // TODO: write dual issue test? currently it's A8 (dual issue) vs. A9 (fast mrc)
368 #endif // if HAVE_ARMV6
369  
370     return flags;
371 } 

uint32_t cpu_detect(void)
{
    int flags = 0;
    return flags;
}

此处不修改在后续关闭汇编情况下编译时,会出现找不到汇编文件内函数的错误。

接着修改build目录下arm-linux下crosscompile.cmake文件,此处笔者建议复制该目录,另外创建32位与64位交叉编译目录(直接复制arm-linux文件夹,并在该目录下粘贴、重命名)。

32位修改如下:

...
set(CROSS_COMPILE_ARM 1)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR armv6l)

# specify the cross compiler
set(CMAKE_C_COMPILER "arm-linux-androideabi-gcc")
set(CMAKE_CXX_COMPILER "arm-linux-androideabi-g++")

# specify the target environment
SET(CMAKE_FIND_ROOT_PATH  "/home/selivert/ndktoolchaon")

64位修改如下

...
set(CROSS_COMPILE_ARM 1)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR armv6l)

# specify the cross compiler
set(CMAKE_C_COMPILER "aarch64-linux-android-gcc")
set(CMAKE_CXX_COMPILER "aarch64-linux-android-g++")

# specify the target environment
SET(CMAKE_FIND_ROOT_PATH  "/home/selivert/ndk-toolchain")

然后修改同目录下的make-Makefiles.bash文件(32位与64位修改一致)

#!/bin/bash
# Run this from within a bash shell

cmake -DCMAKE_TOOLCHAIN_FILE=crosscompile.cmake -G "Unix Makefiles" ../../source && ccmake ../../source

修改完成后执行make-Makefiles.bash文件,会出现如下选项

Android FFMPEG编解码实践(三):Ubuntu 22.04 NDK r21e编译libx265,并集成到ffmpeg_第2张图片

 CLI是命令行工具,咱们是交叉编译给android运行的,用不到也可以关掉。

LIBDL 完整路径为

  /home/selivert/ndk/android-ndk-r21e/platforms/android-21/arch-arm/usr/lib/libdl.so (32位)

 /home/selivert/ndk/android-ndk-r21e/platforms/android-21/arch-arm64/usr/lib/libdl.so (64位)

ps:关于关闭汇编选项,如果不关闭该选项,后续编译过程中会出现汇编文件(.S)编译成.o文件时指令错误(非交叉编译没有此问题)。

随后 输入c   输入e  输入g 关闭窗口并生成make脚本。

此时已经可以make编译了,但是编译出的so带尾巴,libx264.so.130,这个编入ffmpeg的时候没有问题,但是弄到android里就不行了,接下来就去掉这个尾巴。

修改文件/build/arm-linux/CMakeFiles/x265-shared.dir/link.txt,找到里面的libx265.so.130 改成libx265.so

/home/selivert/ndk-toolchain/bin/aarch64-linux-android-g++ -fPIC -O3 -DNDEBUG -Wl,-Bsymbolic,-znoexecstack -shared -Wl,-soname,libx265.so.130 -o libx265.so.130 

改成

/home/selivert/ndk-toolchain/bin/aarch64-linux-android-g++ -fPIC -O3 -DNDEBUG -Wl,-Bsymbolic,-znoexecstack -shared -o libx265.so 

修改文件/build/arm-linux/CMakeFiles/cli.dir/link.txt,找到里面的libx265.so.130 改成libx265.so

修改文件/build/arm-linux/CMakeFiles/x265-shared.dir/build.make,将里面的libx265.so.130 改成libx265.so,libx265.so 改成libx265.so.130,改完如下:

...
"/home/selivert/x265_2.5/build/arm-linux/common/CMakeFiles/common.dir/quant.cpp.o" \
"/home/selivert/x265_2.5/build/arm-linux/common/CMakeFiles/common.dir/deblock.cpp.o"

libx265.so: encoder/CMakeFiles/encoder.dir/analysis.cpp.o
libx265.so: encoder/CMakeFiles/encoder.dir/search.cpp.o
libx265.so: encoder/CMakeFiles/encoder.dir/bitcost.cpp.o
libx265.so: encoder/CMakeFiles/encoder.dir/motion.cpp.o
libx265.so: encoder/CMakeFiles/encoder.dir/slicetype.cpp.o
libx265.so: encoder/CMakeFiles/encoder.dir/frameencoder.cpp.o
libx265.so: encoder/CMakeFiles/encoder.dir/framefilter.cpp.o
libx265.so: encoder/CMakeFiles/encoder.dir/level.cpp.o
libx265.so: encoder/CMakeFiles/encoder.dir/nal.cpp.o
libx265.so: encoder/CMakeFiles/encoder.dir/sei.cpp.o
libx265.so: encoder/CMakeFiles/encoder.dir/sao.cpp.o
libx265.so: encoder/CMakeFiles/encoder.dir/entropy.cpp.o
libx265.so: encoder/CMakeFiles/encoder.dir/dpb.cpp.o
libx265.so: encoder/CMakeFiles/encoder.dir/ratecontrol.cpp.o
libx265.so: encoder/CMakeFiles/encoder.dir/reference.cpp.o
libx265.so: encoder/CMakeFiles/encoder.dir/encoder.cpp.o
libx265.so: encoder/CMakeFiles/encoder.dir/api.cpp.o
libx265.so: encoder/CMakeFiles/encoder.dir/weightPrediction.cpp.o
libx265.so: encoder/CMakeFiles/encoder.dir/__/x265-extras.cpp.o
libx265.so: common/CMakeFiles/common.dir/primitives.cpp.o
libx265.so: common/CMakeFiles/common.dir/pixel.cpp.o
libx265.so: common/CMakeFiles/common.dir/dct.cpp.o
libx265.so: common/CMakeFiles/common.dir/ipfilter.cpp.o
libx265.so: common/CMakeFiles/common.dir/intrapred.cpp.o
libx265.so: common/CMakeFiles/common.dir/loopfilter.cpp.o
libx265.so: common/CMakeFiles/common.dir/constants.cpp.o
libx265.so: common/CMakeFiles/common.dir/cpu.cpp.o
libx265.so: common/CMakeFiles/common.dir/version.cpp.o
libx265.so: common/CMakeFiles/common.dir/threading.cpp.o
libx265.so: common/CMakeFiles/common.dir/threadpool.cpp.o
libx265.so: common/CMakeFiles/common.dir/wavefront.cpp.o
libx265.so: common/CMakeFiles/common.dir/md5.cpp.o
libx265.so: common/CMakeFiles/common.dir/bitstream.cpp.o
libx265.so: common/CMakeFiles/common.dir/yuv.cpp.o
libx265.so: common/CMakeFiles/common.dir/shortyuv.cpp.o
libx265.so: common/CMakeFiles/common.dir/picyuv.cpp.o
libx265.so: common/CMakeFiles/common.dir/common.cpp.o
libx265.so: common/CMakeFiles/common.dir/param.cpp.o
libx265.so: common/CMakeFiles/common.dir/frame.cpp.o
libx265.so: common/CMakeFiles/common.dir/framedata.cpp.o
libx265.so: common/CMakeFiles/common.dir/cudata.cpp.o
libx265.so: common/CMakeFiles/common.dir/slice.cpp.o
libx265.so: common/CMakeFiles/common.dir/lowres.cpp.o
libx265.so: common/CMakeFiles/common.dir/piclist.cpp.o
libx265.so: common/CMakeFiles/common.dir/predict.cpp.o
libx265.so: common/CMakeFiles/common.dir/scalinglist.cpp.o
libx265.so: common/CMakeFiles/common.dir/quant.cpp.o
libx265.so: common/CMakeFiles/common.dir/deblock.cpp.o
libx265.so: CMakeFiles/x265-shared.dir/build.make
libx265.so: x265.def
libx265.so: CMakeFiles/x265-shared.dir/link.txt
	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --bold --progress-dir=/home/selivert/x265_2.5/build/arm-linux/CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Linking CXX shared library libx265.so"
	$(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/x265-shared.dir/link.txt --verbose=$(VERBOSE)
	$(CMAKE_COMMAND) -E cmake_symlink_library libx265.so libx265.so libx265.so.130

libx265.so.130: libx265.so
	@$(CMAKE_COMMAND) -E touch_nocreate libx265.so.130
...

这个时候,32位的就可以 make&&make install了,但是64位的会报错,说编译器不支持 

-march=armv6

 不支持的话,不要这个选项,查一下哪里添加了这个选项

Android FFMPEG编解码实践(三):Ubuntu 22.04 NDK r21e编译libx265,并集成到ffmpeg_第3张图片

到这些文件里面挨个去掉 -march=armv6 ,然后make&&make install

部分设备在编译的时候会遇到如下错误:

Android FFMPEG编解码实践(三):Ubuntu 22.04 NDK r21e编译libx265,并集成到ffmpeg_第4张图片

 打开上图红框目录下的link.txt文件,删除里面的 -lpthread编译选项即可。(没有关闭CLI的,在cli.dir下的link.txt内部也需要删除)

至此,x265就编译完成了,到输出目录下查看文件

Android FFMPEG编解码实践(三):Ubuntu 22.04 NDK r21e编译libx265,并集成到ffmpeg_第5张图片

二、将x265交叉编译进ffmpeg

修改ffmpeg编译脚本,添加libx265选项

...
build() {
  APP_ABI=$1
  CFLAG264=-I/home/selivert/x264/android/$APP_ABI/include
  LDFLAG264=-L/home/selivert/x264/android/$APP_ABI/lib
  CFLAG265=-I/home/selivert/x265_2.5/out/$APP_ABI/include   //添加
  LDFLAG265=-L/home/selivert/x265_2.5/out/$APP_ABI/lib      //添加
  CFLAGAAC=-I/home/selivert/fdk-aac-2.0.2/android/$APP_ABI/include 
  LDFLAGAAC=-L/home/selivert/fdk-aac-2.0.2/android/$APP_ABI/lib
...

 ./configure ${CONFIGURATION} \
  --pkg-config="pkg-config --static" \            //添加
  --extra-cflags="$EXTRA_CFLAGS$CFLAG264 $CFLAG265 $CFLAGAAC" \    //修改
  --extra-ldflags="$EXTRA_LDFLAGS$LDFLAG264 $LDFLAG265 $LDFLAGAAC"  //修改


  echo "-------- > Start make $APP_ABI with -j1"
  make -j1

  echo "-------- > Start install $APP_ABI"
  make install
  echo "++++++++ > make and install $APP_ABI complete."
}
...

  COMMON_OPTIONS="$COMMON_OPTIONS --enable-libfdk-aac"
  COMMON_OPTIONS="$COMMON_OPTIONS --enable-encoder=libfdk_aac"
  COMMON_OPTIONS="$COMMON_OPTIONS --enable-libx265" #添加
  #COMMON_OPTIONS="$COMMON_OPTIONS --enable-avresample"
  COMMON_OPTIONS="$COMMON_OPTIONS --enable-encoder=libx264"

改完之后,开始编译,然后出现 x265 not found using pkg-config 错误,导致无法编译。

解决步骤:

1.检查是否安装了pkg-config工具,没装的话,安装一下

2.在命令行执行  export PKG_CONFIG_PATH=/home/selivert/x265_2.5/out/arm64-v8a/lib/pkgconfig(对应64位),并注释掉ffmpeg编译脚本中32位编译函数调用

...
 

  echo "COMMON_OPTIONS=$COMMON_OPTIONS"
  echo "PREFIX=$PREFIX"
  echo "CONFIG_LOG_PATH=$CONFIG_LOG_PATH"
  mkdir -p ${CONFIG_LOG_PATH}
#  build "armeabi-v7a"                //关闭编译32位
  build "arm64-v8a"
  #build "x86"
  #build "x86_64"
}

...

编译32位时注释掉64位的编译函数,并声明32位的pkgconfig

至此,支持x264,x265,fdk-aac编码器的ffmpeg就编好啦。

Android FFMPEG编解码实践(三):Ubuntu 22.04 NDK r21e编译libx265,并集成到ffmpeg_第6张图片

后面我们研究一下,怎么把这些个编码器给用起来进行编码。

你可能感兴趣的:(android)