FFmpeg 集成 x265 编译及解码

x265 是一个免费的软件库和应用程序,用于将视频流编码为 H.265/MPEG-H HEVC 压缩格式,并在 GNU GPL 条款下发布。

FFmpeg 为了支持 H.265 编、解码可以集成 x265 编译,在编译 FFmpeg 之前需要先编译 x265,但并不是所有的版本都能直接使用,比如笔者同时编译 Android、Window 和 Linux 三个平台时,使用 Android NDK r21e 会遇到很多报错,符号缺失,无法编译 .S 文件都是可能遇到的问题。

一、x265 编译

下面的编译统一都使用 ubuntu 18.04 版本进行。编译目录结构如下:

在这里插入图片描述

其中 i686 & x86_64 和平台相关,这里是 window 平台示例。 Android 上 arm 平台是 armeabi-v7a & arm64-v8a。x265 目录内放置 x265 的源码。

编译的时候 cd x265 工程 & ./build_x265.sh 即可。然后同级的 build 目录会输出相应的编译产物。

1. 交叉编译 Android 使用的 x265

前置条件使用 android-ndk-r21e linux 版本。编译脚本内容如下:

build_x265.sh

rm -rf $(pwd)/x265/build/android
rm -rf $(pwd)/build

mkdir x265/build/android
cp -rf build_script/* x265/build/android

export NDK_ROOT=/home/snake/Android/android-ndk-r21e # 换成自己的实际 NDK 路径
export ANDROID_API_VERSION=21
export NUMBER_OF_CORES=4
export OUTPUT_PREFIX=$(pwd)/build

pushd x265/build/android/armeabi-v7a
bash build.sh
popd

pushd x265/build/android/arm64-v8a
bash build.sh
popd

build_script/armeabi-v7a/build.sh

cmake ../../../source \
  -DCMAKE_SYSTEM_NAME=Android \
  -DCMAKE_SYSTEM_VERSION=${ANDROID_API_VERSION} \
  -DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a \
  -DCMAKE_ANDROID_NDK=${NDK_ROOT} \
  -DCMAKE_ANDROID_STL_TYPE=c++_static \
  -DNEON_ANDROID=1

sed -i 's/-lpthread/-pthread/g' CMakeFiles/cli.dir/link.txt
sed -i 's/-lpthread/-pthread/g' CMakeFiles/x265-shared.dir/link.txt
sed -i 's/-lpthread/-pthread/g' CMakeFiles/x265-static.dir/link.txt

make -j${NUMBER_OF_CORES}
make DESTDIR=${OUTPUT_PREFIX}/armeabi-v7a install

build_script/arm64-v8a/build.sh

cmake ../../../source \
  -DCMAKE_SYSTEM_NAME=Android \
  -DCMAKE_SYSTEM_VERSION=${ANDROID_API_VERSION} \
  -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a \
  -DCMAKE_ANDROID_NDK=${NDK_ROOT} \
  -DCMAKE_ANDROID_STL_TYPE=c++_static \
  -DNEON_ANDROID=1

sed -i 's/-lpthread/-pthread/g' CMakeFiles/cli.dir/link.txt
sed -i 's/-lpthread/-pthread/g' CMakeFiles/x265-shared.dir/link.txt
sed -i 's/-lpthread/-pthread/g' CMakeFiles/x265-static.dir/link.txt

make -j${NUMBER_OF_CORES}
make DESTDIR=${OUTPUT_PREFIX}/arm64-v8a install

同时为了支持 NEON,需要修改 x265 的源码可参考:https://github.com/kimsan0622/libx265-android/commit/cda6b5eac8f293b7f8264e98b722fd4fb252b072

在这里插入图片描述在这里插入图片描述

首先编译 x265 Release_3.5 版本,armeabi-v7a 编译的时候会出现符号缺失的问题(ftello、fseeko…):

在这里插入图片描述

fseeko 和 ftello

  1. fseeko
int fseeko(FILE *stream, off_t offset, int whence);
  1. ftell
off_t ftello(FILE *stream);

fseeko 和 ftello 两个函数的存在,就是为了解决 fseek 和 ftell 这两个函数中文件 2G 大小限制的历史遗留问题。NDK r21e 中无法导出(ANDROID_API_VERSION=21)armeabi-v7a 内的 fseeko、ftello 符号。

arm64-v8a 编译则会报 .S 文件里的各种符号错误,因此 r21e ndk 是无法正常编译 x265 Release_3.5 版本的。

在这里插入图片描述

经过实验,2.6 版本的 x265 是可以正常编译的! 下面的 Window & Linux 版本编译同样使用 x265 2.6 版本。

2. 交叉编译 Windows 使用的 x265

编译环境搭建可以使用 mingw-w64-build:https://github.com/Zeranoe/mingw-w64-build

build_x265.sh

rm -rf $(pwd)/x265/build/windows
rm -rf $(pwd)/build

mkdir $(pwd)/x265/build/windows
cp -rf build_script/* x265/build/windows


export TOOLCHAIN_ROOT=/home/snake/.zeranoe/mingw-w64 # 换成自己的实际 mingw-w64 路径
export NUMBER_OF_CORES=4
export OUTPUT_PREFIX=$(pwd)/build

pushd x265/build/windows/i686
bash build.sh
popd

pushd x265/build/windows/x86_64
bash build.sh
popd

build_script/i686/build.sh

cmake ../../../source \
  -DCMAKE_SYSTEM_NAME=Windows \
  -DCMAKE_C_COMPILER=${TOOLCHAIN_ROOT}/i686/bin/i686-w64-mingw32-gcc \
  -DCMAKE_CXX_COMPILER=${TOOLCHAIN_ROOT}/i686/bin/i686-w64-mingw32-g++ \
  -DCMAKE_RANLIB=${TOOLCHAIN_ROOT}/i686/bin/i686-w64-mingw32-ranlib \
  -DCMAKE_STRIP=${TOOLCHAIN_ROOT}/i686/bin/i686-w64-mingw32-strip \
  -DCMAKE_AR=${TOOLCHAIN_ROOT}/i686/bin/i686-w64-mingw32-ar \
  -DCMAKE_LD=${TOOLCHAIN_ROOT}/i686/bin/i686-w64-mingw32-ld \
  -DCMAKE_NM=${TOOLCHAIN_ROOT}/i686/bin/i686-w64-mingw32-nm \
  -DCMAKE_RC_COMPILER=${TOOLCHAIN_ROOT}/i686/bin/i686-w64-mingw32-windres

make -j${NUMBER_OF_CORES}
make DESTDIR=${OUTPUT_PREFIX}/i686 install

build_script/x86_64/build.sh

cmake ../../../source \
  -DCMAKE_SYSTEM_NAME=Windows \
  -DCMAKE_C_COMPILER=${TOOLCHAIN_ROOT}/x86_64/bin/x86_64-w64-mingw32-gcc \
  -DCMAKE_CXX_COMPILER=${TOOLCHAIN_ROOT}/x86_64/bin/x86_64-w64-mingw32-g++ \
  -DCMAKE_RANLIB=${TOOLCHAIN_ROOT}/x86_64/bin/x86_64-w64-mingw32-ranlib \
  -DCMAKE_STRIP=${TOOLCHAIN_ROOT}/x86_64/bin/x86_64-w64-mingw32-strip \
  -DCMAKE_AR=${TOOLCHAIN_ROOT}/x86_64/bin/x86_64-w64-mingw32-ar \
  -DCMAKE_LD=${TOOLCHAIN_ROOT}/x86_64/bin/x86_64-w64-mingw32-ld \
  -DCMAKE_NM=${TOOLCHAIN_ROOT}/x86_64/bin/x86_64-w64-mingw32-nm \
  -DCMAKE_RC_COMPILER=${TOOLCHAIN_ROOT}/x86_64/bin/x86_64-w64-mingw32-windres

make -j${NUMBER_OF_CORES}
make DESTDIR=${OUTPUT_PREFIX}/x86_64 install

3. 编译 Linux 使用的 x265

此处只编译 x86_64 版本。

build_x265.sh

rm -rf $(pwd)/x265/build/linux-out
rm -rf $(pwd)/build

mkdir $(pwd)/x265/build/linux-out
cp -rf build_script/* x265/build/linux-out


export TOOLCHAIN_ROOT=/usr/bin
export NUMBER_OF_CORES=4
export OUTPUT_PREFIX=$(pwd)/build

pushd x265/build/linux-out/x86_64
bash build.sh
popd

build_script/x86_64/build.sh

cmake ../../../source \
  -DCMAKE_SYSTEM_NAME=Linux \
  -DCMAKE_C_COMPILER=${TOOLCHAIN_ROOT}/x86_64-linux-gnu-gcc \
  -DCMAKE_CXX_COMPILER=${TOOLCHAIN_ROOT}/x86_64-linux-gnu-g++ \
  -DCMAKE_RANLIB=${TOOLCHAIN_ROOT}/x86_64-linux-gnu-ranlib \
  -DCMAKE_STRIP=${TOOLCHAIN_ROOT}/x86_64-linux-gnu-strip \
  -DCMAKE_AR=${TOOLCHAIN_ROOT}/x86_64-linux-gnu-ar \
  -DCMAKE_LD=${TOOLCHAIN_ROOT}/x86_64-linux-gnu-ld \
  -DCMAKE_NM=${TOOLCHAIN_ROOT}/x86_64-linux-gnu-gcc-nm

make -j${NUMBER_OF_CORES}
make DESTDIR=${OUTPUT_PREFIX}/x86_64 install

二、FFmpeg 集成 x265 编译

下面是 Linux FFmpeg 编译脚本修改点,增加以下差异点即可。

+ # x265的目录
+ X265_INCLUDE=${ROOT_SOURCE}/x265_git_2.6/build/x86_64/usr/local/include
+ X265_LIB=${ROOT_SOURCE}/x265_git_2.6/build/x86_64/usr/local/lib
+ X265_LIB_PKG_CONFIG=${ROOT_SOURCE}/x265_git_2.6/build/x86_64/usr/local/lib/pkgconfig

+ export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$X264_LIB/pkgconfig:$FDK_AAC_LIB/pkgconfig:$X265_LIB_PKG_CONFIG
echo PKG-CONFIG-PATH=$PKG_CONFIG_PATH

./configure \
......
+ --extra-cflags="-I${X264_INCLUDE} -I${FDK_AAC_INCLUDE} -I${X265_INCLUDE} -I/usr/include" \
+ --extra-ldflags="-L${X264_LIB} -L${FDK_AAC_LIB} -L${X265_LIB}" \
......
+ --enable-libx265 \
+ --enable-encoder=libx265 \
+ --enable-muxer=hevc \
+ --enable-decoder=hevc \
+ --enable-demuxer=hevc \
+ --enable-parser=hevc \

三、H.265 解码

FFmpeg 解码 H.265 码流整体并不难,重点需要注意下,avcodec_find_decoder(…) 入参传入 AV_CODEC_ID_HEVC,然后 avcodec_send_packet 送入 packet 需要拼装 VPS + SPS + PPS + IDR 后一起送入。

猜你喜欢

转载自blog.csdn.net/tyyj90/article/details/128623712