Android NDK开发之libvpx的编译

853 阅读5分钟

前言

libvpx是一款开源的vp8、vp9编码器,其主要作用是提供VP8/VP9视频编码/解码功能。VP8和VP9是Google开发的两种视频编解码标准,它们被设计为提供更好的压缩效率和更低的带宽需求,尤其是在网络环境下播放高清视频。libvpx库就是为了让开发者能够更容易地在各种应用中使用这两种视频编解码标准而提供的。

开始编译libvpx

编译libvpx没有什么太多难度,不废话直接上步骤

编译libvpx系统环境

本人使用的编译环境如下,其他环境请自行测试(本教程目前仅NDK18可以正常编译)

Ubuntu20.04.3 + android-ndk-r18b-linux-x86_64 + libvpx v1.14.1

准备编译脚本开始编译libvpx动态库

  1. 创建build_libyuv文件夹
  2. build_libyuv文件夹下创建init_libvpx.sh脚本文件
#!/bin/bash
#
# Copyright 2016 Eng Chong Meng
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

if [[ $# -eq 1 ]]; then
  LIB_GIT=$1
else
  LIB_GIT=v1.14.1
fi

LIB_VPX="libvpx"

if [[ -d ${LIB_VPX} ]] && [[ -f "${LIB_VPX}/build/make/version.sh" ]]; then
  version=`"${LIB_VPX}/build/make/version.sh" --bare "${LIB_VPX}"`
  if [[ (${LIB_GIT} == "${version}") ]]; then
    echo -e "\n========== Current libvpx source is: ${LIB_VPX} (${version}) =========="
    exit 0
  fi
fi

# Delete LIB_VPX and uncomment below to use master main repository with the same LIB_GIT version
# LIB_GIT=f6de5b5
LIB_GIT=main

rm -rf ${LIB_VPX}
echo -e "\n========== Fetching library source for: ${LIB_VPX} (${LIB_GIT}) =========="
## wget -O- https://github.com/webmproject/libvpx/archive/refs/tags/${LIB_GIT}.tar.gz | tar xz --strip-components=1 --one-top-level=${LIB_VPX}
wget -O- https://github.com/webmproject/libvpx/archive/${LIB_GIT}.tar.gz | tar xz --strip-components=1 --one-top-level=${LIB_VPX}

echo -e "========== Completed libvpx library source update =========="

#下载并且解压NDK
NDK_VERSION=android-ndk-r18b
if [ ! -e ${NDK_VERSION}-linux-x86_64.zip ]
 then
    echo "ndk 压缩包不存在"
    wget https://dl.google.com/android/repository/${NDK_VERSION}-linux-x86_64.zip
    #ndk23+后缀不区分x86_64
    #wget https://dl.google.com/android/repository/${NDK_VERSION}-linux.zip
fi

if [ ! -d ${NDK_VERSION} ]
 then
    echo "ndk 目录不存在"
    unzip ${NDK_VERSION}-linux-x86_64.zip
    #ndk23+后缀不区分x86_64
    #unzip ${NDK_VERSION}-linux.zip
fi
  1. build_libyuv文件夹下创建_settings.sh脚本文件
#!/bin/bash
#
# Copyright 2016 Eng Chong Meng
# 
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
#     http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Uncomment the line below to see all script echo to terminal
# set -x

# 注意改成自己的NDK路径
export ANDROID_NDK=/home/roc/桌面/build_libvpx/android-ndk-r18b
if [[ -z $ANDROID_NDK ]] || [[ ! -d $ANDROID_NDK ]] ; then
	echo "You need to set ANDROID_NDK environment variable, exiting"
	echo "Use: export ANDROID_NDK=/your/path/to/android-ndk-rxx"
	echo "e.g.: export ANDROID_NDK=/opt/android/android-ndk-r18b"
	exit 1
fi

set -u

# Never mix two api level to build static library for use on the same apk.
# Set to API:21 for aTalk 64-bit architecture support
# Does not build 64-bit arch if ANDROID_API is less than 21 i.e. the minimum supported API level for 64-bit.
ANDROID_API=21

# Do not change naming convention of the ABIS; see:
# https://developer.android.com/ndk/guides/abis.html#Native code in app packages
# Android recommended architecture support; others are deprecated
ABIS=("armeabi-v7a" "arm64-v8a" "x86" "x86_64")

BASEDIR=`pwd`
NDK=${ANDROID_NDK}
HOST_NUM_CORES=$(nproc)

# https://gcc.gnu.org/onlinedocs/gcc-4.9.1/gcc/Optimize-Options.html
# Note: vpx with ABIs x86 and x86_64 build has error with option -fstack-protector-all
# Note: final libraries built is 20~33% bigger in size when below additional options are specified
# CFLAGS_="-DANDROID -fpic -fpie -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -fno-strict-overflow -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2"
CFLAGS_="-DANDROID -fpic -fpie"
# Enable report-all for earlier detection of errors instead at later stage
# /home/cmeng/workspace/ndk/vpx-android/armeabi-v7a-android-toolchain/bin/arm-linux-androideabi-ld: -Wl,-z,defs -Wl,--unresolved-symbols=report-all: unknown option
# Not compatible with libvpx v.1.8.2+
# LDFLAGS_="-Wl,-z,defs -Wl,--unresolved-symbols=report-all"
LDFLAGS_=""

# Do not modify any of the NDK_ARCH, CPU and -march unless you are very sure.
# The settings are used by <ARCH>-linux-android-gcc and submodule configure
# https://en.wikipedia.org/wiki/List_of_ARM_microarchitectures
# $NDK/toolchains/llvm/prebuilt/...../includellvm/ARMTargetParser.def etc
# ARCH - should be one from $ANDROID_NDK/platforms/android-$API/arch-* [arm / arm64 / mips / mips64 / x86 / x86_64]"
# https://gcc.gnu.org/onlinedocs/gcc/AArch64-Options.html

configure() {
  ABI=$1;

  case $ABI in
    # Standalone toolchains error.
    # /home/cmeng/workspace/ndk/vpx-android/armeabi-v7a-android-toolchain/bin/arm-linux-androideabi-ld: -Wl,--fix-cortex-a8: unknown option
    armeabi-v7a)
      NDK_ARCH="arm"
      NDK_ABIARCH="arm-linux-androideabi"
      # clang70: warning: -Wl,--fix-cortex-a8: 'linker' input unused [-Wunused-command-line-argument]
      # CFLAGS="${CFLAGS_} -Wl,--fix-cortex-a8 -march=${CPU} -mfloat-abi=softfp -mfpu=neon -mtune=cortex-a8 -mthumb -D__thumb__"
      # CFLAGS="${CFLAGS_} -Os -march=armv7-a -mfloat-abi=softfp -mfpu=neon -mtune=cortex-a8 -mthumb -D__thumb__"
      CFLAGS="${CFLAGS_} -Os -march=armv7-a"
      LDFLAGS="${LDFLAGS_} -march=armv7-a" # -Wl,--fix-cortex-a8" not valid option
      ASFLAGS="-c"

    # 1. -march=${CPU} flag targets the armv7 architecture.
    # 2. -mfloat-abi=softfp enables hardware-FPU instructions while ensuring that the system passes
    #     floating-point parameters in core registers, which is critical for ABI compatibility
    # 3. -mfpu=neon setting forces the use of VFPv3-D32, per the ARM specifications
    # 4. -mthumb forces the generation of 16-bit Thumb-2 instructions (Thumb-1 for armeabi).
    #     If omitted, the toolchain will emit 32-bit ARM instructions.
    # 5. -Wl,--fix-cortex-a8 is required as a workaround for a CPU bug in some Cortex-A8 implementation
    #     (x264 flags as warning) Standalone toolchains does not accept this option. SDK toolchains (gcc/cg++) is ok.
    #    /home/cmeng/workspace/ndk/ffmpeg-android/toolchain-android/bin/arm-linux-androideabi-ld: -Wl,--fix-cortex-a8: unknown option
    # LDFLAGS="-Wl,--fix-cortex-a8"
    ;;
    arm64-v8a)
      # Valid cpu = armv8-a cortex-a35, cortex-a53, cortec-a57 etc. but -march=armv8-a is required
      # x264 build has own undefined references e.g. x264_8_pixel_sad_16x16_neon - show up when build ffmpeg 
      NDK_ARCH="arm64"
      NDK_ABIARCH="aarch64-linux-android"
      CFLAGS="${CFLAGS_} -O3-march=armv8-a"
      # Supported emulations: aarch64linux aarch64elf aarch64elf32 aarch64elf32b aarch64elfb armelf armelfb
      # aarch64linuxb aarch64linux32 aarch64linux32b armelfb_linux_eabi armelf_linux_eabi
	  #-march=armv8-a or arch64linux: all are not valid for libvpx v1.8.2 build with standalone toolchains
      LDFLAGS="${LDFLAGS_}" # -march=arch64linux" not valid also
      ASFLAGS=""
    ;;
    x86)
      NDK_ARCH="x86"
      NDK_ABIARCH="i686-linux-android"
      CFLAGS="${CFLAGS_} -O3 -march=i686 -mtune=intel -msse3 -mfpmath=sse -m32 -fPIC"
      LDFLAGS="-m32"
      ASFLAGS="-D__ANDROID__"

    ;;
    x86_64)
      NDK_ARCH="x86_64"
      NDK_ABIARCH="x86_64-linux-android"
      CFLAGS="${CFLAGS_} -O3 -march=x86-64 -mtune=intel -msse4.2 -mpopcnt -m64 -fPIC"
      LDFLAGS=""
      ASFLAGS="-D__ANDROID__"
    ;;
  esac

  TOOLCHAIN_PREFIX=${BASEDIR}/android-toolchain
  NDK_SYSROOT=${TOOLCHAIN_PREFIX}/sysroot

  if [[ ! -e ${TOOLCHAIN_PREFIX}/${NDK_ABIARCH} ]]; then
      rm -rf ${TOOLCHAIN_PREFIX}
  fi

  # cmeng: must ensure AS JNI uses the same STL library or "system"
  [[ -d ${TOOLCHAIN_PREFIX} ]] || python3 ${NDK}/build/tools/make_standalone_toolchain.py \
     --arch ${NDK_ARCH} \
     --api ${ANDROID_API} \
     --stl libc++ \
     --install-dir=${TOOLCHAIN_PREFIX}

  # Define the install-directory of the libs and include files etc
  # PREFIX=${BASEDIR}/output/android/${ABI}

  # Directly install to aTalk ./jni/vpx
  PREFIX=${BASEDIR}/out_vpx/android/${ABI}

  # Add the standalone toolchain to the search path.
  export PATH=${TOOLCHAIN_PREFIX}/bin:$PATH
  export CROSS_PREFIX=${TOOLCHAIN_PREFIX}/bin/${NDK_ABIARCH}-
  export CFLAGS="${CFLAGS}"
  export CPPFLAGS="${CFLAGS}"
  export CXXFLAGS="${CFLAGS} -std=c++11"
  export ASFLAGS="${ASFLAGS}"
  export LDFLAGS="${LDFLAGS} -L${NDK_SYSROOT}/usr/lib"

  export AR="${CROSS_PREFIX}ar"
  export AS="${CROSS_PREFIX}clang"
  export CC="${CROSS_PREFIX}clang"
  export CXX="${CROSS_PREFIX}clang++"
  export LD="${CROSS_PREFIX}ld"
  export STRIP="${CROSS_PREFIX}strip"
  export RANLIB="${CROSS_PREFIX}ranlib"
  export CPP="${CROSS_PREFIX}cpp"
  export NM="${CROSS_PREFIX}nm"

#  export APP_CFLAGS="-fsanitize=address -fno-omit-frame-pointer"
#  export APP_LDFLAGS="-fsanitize=address"

  echo "**********************************************"
  echo "### Use NDK=${NDK}"
  echo "### Use ANDROID_API=${ANDROID_API}"
  echo "### Install directory: PREFIX=${PREFIX}"
  echo "**********************************************"
}
  1. build_libyuv文件夹下创建build-vpx4android.sh脚本文件
#!/bin/bash
#
# Copyright 2016 Eng Chong Meng
# 
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
#     http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# (20210521) aTalk v2.6.1 uses libvpx-1.10.0, and the scripts are verified for this version only
#set -x
set -u
. _settings.sh

LIB_VPX="libvpx"
LIB_GIT=v1.14.1

# Auto fetch and unarchive libvpx from online repository
./init_libvpx.sh ${LIB_GIT}

# Applying required patches to libvpx-1.10.0
#./libvpx_patch.sh ${LIB_VPX}

if [[ -f "${LIB_VPX}/build/make/version.sh" ]]; then
  version=`"${LIB_VPX}/build/make/version.sh" --bare "${LIB_VPX}"`
fi

# Unarchive library, then configure and make for specified architectures
configure_make() {
  pushd "${LIB_VPX}" || exit
  ABI=$1;
  echo -e "\n** BUILD STARTED: ${LIB_VPX} (${version}) for ${ABI} **"

  configure "$@"
  case ${ABI} in
	armeabi-v7a)
      # TARGET="armv7-android-gcc --enable-neon --disable-neon-asm"
      TARGET="armv7-android-gcc"
    ;;
    arm64-v8a)
      TARGET="arm64-android-gcc"
    ;;
    x86)
      TARGET="x86-android-gcc"
    ;;
    x86_64)
      TARGET="x86_64-android-gcc"
    ;;
  esac

  if [[ -f "config.log" ]]; then
      config_target="$(grep "Configuring for target" < "config.log" | sed "s/^.* '\(.*\)'$/\1/")"
      if [[ ${TARGET} != "${config_target}" ]]; then
        make clean
      fi
  else
    make clean
  fi

  # Directly install to aTalk ./jni/vpx
#     --enable-bitstream-debug \
  PREFIX=${BASEDIR}/out_vpx/android/${ABI}

  ./configure \
    --prefix=${PREFIX} \
    --target=${TARGET} \
    --as=yasm \
    --enable-pic \
    --disable-docs \
    --enable-static \
    --enable-libyuv \
    --disable-examples \
    --disable-tools \
    --disable-debug \
    --disable-unit-tests \
    --enable-realtime-only \
    --enable-vp8 --enable-vp9 \
    --enable-vp9-postproc \
    --enable-vp9-highbitdepth \
    --enable-better-hw-compatibility \
    --disable-webm-io || exit 1

  make -j${HOST_NUM_CORES} install
  popd || true
}

for ((i=0; i < ${#ABIS[@]}; i++))
do
  if [[ $# -eq 0 ]] || [[ "$1" == "${ABIS[i]}" ]]; then
    # Do not build 64 bit arch if ANDROID_API is less than 21 which is
    # the minimum supported API level for 64 bit.
    [[ ${ANDROID_API} -lt 21 ]] && ( echo "${ABIS[i]}" | grep 64 > /dev/null ) && continue;
    configure_make "${ABIS[i]}"
    echo -e "** BUILD COMPLETED: ${LIB_VPX} for ${ABIS[i]} **\n\n"
  fi
done
  1. 准备好上面几个脚本后打开终端,在终端输入命令
./build-vpx4android.sh
  • 注意:如果提示bash: ./build-vpx4android.sh: 权限不够说明没有打开作为程序执行开关,文件右键属性里面打开开关 image.png
  • 再次运行./build-vpx4android.sh命令,如果Android NDK路径和libvpx版本没有配置错会看到正常执行编译的输出
  • 等待几分钟编译执行完毕后在当前目录会生成一个out_vpx文件夹,里面对应有编译出来的各ABI架构的库文件和头文件

image.png

image.png

参考来源:github.com/cmeng-git/a… 感谢提供的脚本