• Shell生成支持x264的ffmpeg安卓全平台so


    安卓 FFmpeg系列

    第一章 Ubuntu生成ffmpeg安卓全平台so
    第二章 Windows生成ffmpeg安卓全平台so
    第三章 生成支持x264的ffmpeg安卓全平台so(本章)
    第四章 部署ffmpeg安卓全平台so并使用



    前言

    前两章实现了ffmpeg全平台so的生成,但是ffmpeg依赖的第三方库是需要另外编译的,所以本章将提供编译x264库并加入ffmpeg的方法。本章提供的脚本在ubuntu以及windows的wsl、msys2都适用。


    一、实现步骤

    定义交叉编译相关变量

    #ndk api版本 -可配置
    API=24
    #cpu 架构 -可配置 :armv7-a、armv8-a、i686、x86-64
    CPU=x86-64
    #msys则可设置为windows
    OS=linux
    #需要ANDROID_NDK_HOME指定ndk目录
    TOOLCHAIN=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/$OS-x86_64
    echo $TOOLCHAIN
    SYSROOT=$TOOLCHAIN/sysroot
    PREFIX=$(pwd)/output/ffmpeg${FFMPEG_VERSION}/${API}/${CPU}
    PACKAGE_PREFIX=$PACKAGE_SOURCE_DIR/.output/${API}/${CPU}
    export CC=${CROSS_PREFIX}clang
    export CXX=${CROSS_PREFIX}clang++
    case $CPU in
    armv7-a)
      ARCH=arm
      CROSS_PREFIX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-
      ;;
    armv8-a)
      ARCH=arm64
      CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android$API-
      ;;
    i686)
      ARCH=x86
      CROSS_PREFIX=$TOOLCHAIN/bin/i686-linux-android$API-
      FFMPEG_EXTRA_CONFIGURE_FLAGS=--disable-asm
      ;;
    x86-64)
      ARCH=x86_64
      CROSS_PREFIX=$TOOLCHAIN/bin/x86_64-linux-android$API-
      ;;
    

    1、下载x264源码

     wget https://code.videolan.org/videolan/x264/-/archive/master/x264-master.tar.bz2
     tar -xf $PACKET_X264.tar.bz2
    

    2、交叉编译生成.a

    在x264源码目录执行如下操作。其中X264_OUTPUT_DIR 为输出目录,ARCH为cpu架构

    ./configure \
        --prefix=$X264_OUTPUT_DIR \
        --enable-static \
        --enable-pic \
        --host=$ARCH-linux \
        --disable-opencl \
        --disable-cli \
        --cross-prefix=$CROSS_PREFIX \
        --sysroot=$SYSROOT \
        FFMPEG_EXTRA_CONFIGURE_FLAGS
    
    make -j$(nproc) 
    
    make install
    

    3、加入x264配置

    FFMPEG_EXTRA_CFLAGS="$FFMPEG_EXTRA_CFLAGS -I$X264_OUTPUT_DIR/include"
    FFMPEG_EXTRA_LDFLAGS="$FFMPEG_EXTRA_LDFLAGS -L$X264_OUTPUT_DIR/lib"
    FFMPEG_EXTRA_CONFIGURE_FLAGS="$FFMPEG_EXTRA_CONFIGURE_FLAGS --enable-encoder=libx264 --enable-libx264"
    export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$X264_OUTPUT_DIR/lib/pkgconfig"
    

    4、编译ffmpeg

     ./configure --target-os=android \
        --prefix=$PREFIX \
        --arch=$ARCH \
        --cpu=$CPU \
        --cc=$CC \
        --cxx=$CXX \
        --disable-ffmpeg \
        --disable-ffplay \
        --disable-ffprobe \
        --enable-gpl \
        --cross-prefix=$CROSS_PREFIX \
        --enable-cross-compile \
        --enable-jni \
        --enable-mediacodec \
        --enable-decoder=h264_mediacodec \
        --enable-decoder=hevc_mediacodec \
        --enable-decoder=vp8_mediacodec \
        --enable-decoder=vp9_mediacodec \
        --enable-decoder=mpeg2_mediacodec \
        --enable-decoder=mpeg4_mediacodec \
        --sysroot=$SYSROOT \
        --extra-cflags="-Os -fpic -DVK_ENABLE_BETA_EXTENSIONS=0 -march=$CPU $FFMPEG_EXTRA_CFLAGS" \
        --extra-ldflags="$FFMPEG_EXTRA_LDFLAGS" \
        --pkg-config="pkg-config --static" \
        $SHARED_OR_STATIC_FLAG \
        $FFMPEG_EXTRA_CONFIGURE_FLAGS
    
    make -j$(nproc)
    
    make install
    

    二、完整代码

    下列代码可以在ubuntu、wsl ubuntu、msys2中执行。无需任何额外操作,只需调用脚本即可生成so。可以指定cpu、安卓api、以及ffmpeg版本号。如果没有指定ANDROID_NDK_HOME会自动下载ndk,x264源码也会自动下载以及ffmpeg源码也会自动下载,然后自动生成so。同时还会生成libffmpeg.so,是ffmpeg可执行程序,笔者将其生成了so,其内包含的main符号可以直接调用,以输入命令行
    注:合并所有库到libffmpeg.so的方式本文暂不提供。
    下列代码可复制保存为build.sh直接执行。

    set -e
    show_usage() {
      echo "usage:
          -a is android api number
          -b is abi (armeabi-v7a、arm64-v8a、x86、x86_64)  
          -f is ffmpeg version
          -h is help
       "
    }
    #ffmpeg版本 -可配置
    FFMPEG_VERSION=4.3.6
    #ndk api版本 -可配置
    API=24
    #abi  -可配置 :armeabi-v7a、 、x86、x86_64
    ABI=armeabi-v7a
    while getopts "f:a:b:h" arg; do
      case $arg in
      b)
        ABI=$OPTARG
        ;;
      a)
        API=$OPTARG
        ;;
      f)
        FFMPEG_VERSION=$OPTARG
        ;;
      h)
        show_usage
        exit 1
        ;;
      ?)
        echo "unkonw argument"
        show_usage
        exit 1
        ;;
      esac
    done
    OS=$(uname -o)
    echo $OS
    if [ $OS == "Msys" ]; then
      OS="windows"
      NDK_URL="https://googledownloads.cn/android/repository/android-ndk-r26d-windows.zip"
      NDK_SHA1="c7ea35ffe916082876611da1a6d5618d15430c29"
    else
      OS="linux"
      NDK_URL=" https://googledownloads.cn/android/repository/android-ndk-r26d-linux.zip"
      NDK_SHA1="fcdad75a765a46a9cf6560353f480db251d14765"
    
    fi
    echo "************************************Build Info*********************************"
    echo "Host os :$OS"
    echo "Android api :$API"
    echo "Target abi :$ABI"
    echo "FFmpeg version :$FFMPEG_VERSION"
    echo "************************************Build Info End*****************************"
    PACKAGE_SOURCE_DIR=$(pwd)/.package
    #下载NDK
    if [ ! -d "$PACKAGE_SOURCE_DIR" ]; then
      mkdir $PACKAGE_SOURCE_DIR
    fi
    if [ ! -d "$ANDROID_NDK_HOME" ]; then
      pushd $PACKAGE_SOURCE_DIR
      if [ ! -d "ndk" ]; then
        if [ -e "ndk.zip" ]; then
          sha1=$(sha1sum ndk.zip)
        fi
        sha1=($sha1)
        echo "${sha1[0]}"
        if [ "$sha1" != "$NDK_SHA1" ]; then
          if [ -e "ndk.zip" ]; then
            rm ndk.zip
          fi
          echo ndk Downloading...
          wget $NDK_URL -O ndk.zip
        fi
        if [ -d "ndk" ]; then
          rm -rf ndk
        fi
        unzip ndk.zip -d ndk
      fi
      ANDROID_NDK_HOME=$PACKAGE_SOURCE_DIR/ndk/$(ls ndk)
      popd
    fi
    #下载NDK -end
    TOOLCHAIN=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/$OS-x86_64
    echo $TOOLCHAIN
    SYSROOT=$TOOLCHAIN/sysroot
    case $ABI in
    armeabi-v7a)
      CPU=armv7-a
      ARCH=arm
      CROSS_PREFIX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-
      USR_LIB=$SYSROOT/usr/lib/armv7a-linux-androideabi/$API
      ;;
    arm64-v8a)
      CPU=armv8-a
      ARCH=arm64
      CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android$API-
      USR_LIB=$SYSROOT/usr/lib/aarch64-linux-android/$API
      ;;
    x86)
      CPU=i686
      ARCH=x86
      CROSS_PREFIX=$TOOLCHAIN/bin/i686-linux-android$API-
      USR_LIB=$SYSROOT/usr/lib/i686-linux-android/$API
      FFMPEG_EXTRA_CONFIGURE_FLAGS=--disable-asm
      ;;
    x86_64)
      CPU=x86-64
      ARCH=x86_64
      CROSS_PREFIX=$TOOLCHAIN/bin/x86_64-linux-android$API-
      USR_LIB=$SYSROOT/usr/lib/x86_64-linux-android/$API
      ;;
    esac
    PREFIX=$(pwd)/output/ffmpeg${FFMPEG_VERSION}/${API}/${ABI}
    PACKAGE_PREFIX=$PACKAGE_SOURCE_DIR/.output/${API}/${ABI}
    export CC=${CROSS_PREFIX}clang
    export CXX=${CROSS_PREFIX}clang++
    CROSS_PREFIX=$TOOLCHAIN/bin/llvm-
    #x264
    pushd $PACKAGE_SOURCE_DIR
    PACKET_X264=x264-master
    X264_OUTPUT_DIR=$PACKAGE_PREFIX/x264
    FFMPEG_EXTRA_LINK_LIBRARY="$FFMPEG_EXTRA_LINK_LIBRARY $X264_OUTPUT_DIR/lib/libx264.a"
    FFMPEG_EXTRA_CFLAGS="$FFMPEG_EXTRA_CFLAGS -I$X264_OUTPUT_DIR/include"
    FFMPEG_EXTRA_LDFLAGS="$FFMPEG_EXTRA_LDFLAGS -L$X264_OUTPUT_DIR/lib"
    FFMPEG_EXTRA_CONFIGURE_FLAGS="$FFMPEG_EXTRA_CONFIGURE_FLAGS --enable-encoder=libx264 --enable-libx264"
    export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$X264_OUTPUT_DIR/lib/pkgconfig"
    if [ ! -e "$X264_OUTPUT_DIR/lib/libx264.a" ]; then
      if [ ! -d "$PACKET_X264" ]; then
        echo x264 Downloading...
        wget https://code.videolan.org/videolan/x264/-/archive/master/x264-master.tar.bz2
        tar -xf $PACKET_X264.tar.bz2
      fi
      if [ "$ARCH" != "x64" ]; then
        PACKET_X264_EXTRA_CONFIGURE_FLAG="--disable-asm"
      fi
      echo x264 Configuring...
      pushd $PACKET_X264
      ./configure \
        --prefix=$X264_OUTPUT_DIR \
        --enable-static \
        --enable-pic \
        --host=$ARCH-linux \
        --disable-opencl \
        --disable-cli \
        --cross-prefix=$CROSS_PREFIX \
        --sysroot=$SYSROOT \
        $PACKET_X264_EXTRA_CONFIGURE_FLAG
      echo x264 Building...
      if [ -e "Makefile" ]; then
        make clean
      fi
      make -j$(nproc) -s
      echo x264 Installing...
      make install
      popd
      popd
    fi
    #x264 -end
    #ffmpeg
    pushd $PACKAGE_SOURCE_DIR
    FFMPEG_SOURCE_DIR=$(pwd)/ffmpeg$FFMPEG_VERSION
    if [ ! -d "$FFMPEG_SOURCE_DIR" ]; then
      echo ffmpeg Downloading...
      git clone -b n$FFMPEG_VERSION --depth 1 https://git.ffmpeg.org/ffmpeg.git $FFMPEG_SOURCE_DIR
    fi
    pushd $FFMPEG_SOURCE_DIR
    build_ffmpeg() {
      #./configure -h
      # echo ffmpeg surport decoders...
      # ./configure --list-decoders
      # echo ffmpeg surport hwaccels...
      # ./configure --list-hwaccels
      echo ffmpeg Configuring...
      ./configure --target-os=android \
        --prefix=$PREFIX \
        --arch=$ARCH \
        --cpu=$CPU \
        --cc=$CC \
        --cxx=$CXX \
        --disable-ffmpeg \
        --disable-ffplay \
        --disable-ffprobe \
        --enable-gpl \
        --cross-prefix=$CROSS_PREFIX \
        --enable-cross-compile \
        --enable-pthreads \
        --enable-jni \
        --enable-mediacodec \
        --enable-decoder=h264_mediacodec \
        --enable-decoder=hevc_mediacodec \
        --enable-decoder=vp8_mediacodec \
        --enable-decoder=vp9_mediacodec \
        --enable-decoder=mpeg2_mediacodec \
        --enable-decoder=mpeg4_mediacodec \
        --sysroot=$SYSROOT \
        --extra-cflags="-Os -fpic -DVK_ENABLE_BETA_EXTENSIONS=0 -march=$CPU $FFMPEG_EXTRA_CFLAGS" \
        --extra-ldflags="$FFMPEG_EXTRA_LDFLAGS" \
        --pkg-config="pkg-config --static" \
        $SHARED_OR_STATIC_FLAG \
        $FFMPEG_EXTRA_CONFIGURE_FLAGS
      echo ffmpeg Building...
      if [ -e "Makefile" ]; then
        make clean
      fi
      make -j$(nproc)
      echo ffmpeg Installing...
      make install
    }
    # SHARED_OR_STATIC_FLAG="--disable-shared --enable-static"
    # echo "ffmpeg build static library"
    # build_ffmpeg
    SHARED_OR_STATIC_FLAG="--enable-shared  --disable-static"
    echo "ffmpeg build shared library"
    build_ffmpeg
    $CC -shared -fPIC \
      $(find $FFMPEG_SOURCE_DIR/fftools -name '*.c' -and -not -name 'ffplay.c' -and -not -name 'ffprobe.c' -and -not -name 'ffplay_renderer.c' -and -not -name 'ffmpeg_qsv.c' -and -not -name 'ffmpeg_videotoolbox.c') \
      -I$FFMPEG_SOURCE_DIR -lm \
      $(find $PREFIX/lib -name "*.so" -and -not -name 'libffmpeg.so' -type f -print) \
      -o $PREFIX/lib/libffmpeg.so
    #mv -v $PREFIX/lib/*.so $PREFIX
    # pushd $PREFIX/lib
    # for file in *.so; do
    #   ln -s "$PREFIX/lib/$file" "$PREFIX/$file"
    # done
    # popd
    popd
    popd
    echo "Generated files in: $PREFIX"
    #ffmpeg -end
    

    三、生成好的包

    已加入第二章生成好的包里。


    四、使用示例

    1、基本用法

    创建一个ffmpeg-android目录,将完整代码复制保存为build.sh

    (1)查看用法

    ./build.sh -h
    

    在这里插入图片描述

    (2)确认ffmpeg版本

    ffmpeg版本参考:https://git.ffmpeg.org/ffmpeg.git 去掉前缀n
    在这里插入图片描述

    (3)生成so

    arm

    ./build.sh -b armeabi-v7a -a 24 -f 6.1.1
    

    arm64

    ./build.sh -b arm64-v8a -a 24 -f 6.1.1
    

    x86

    ./build.sh -b x86 -a 24 -f 6.1.1
    

    x64

    ./build.sh -b x86_64 -a 24 -f 6.1.1
    

    生成好的so在build.sh脚本所在目录的output文件夹下
    在这里插入图片描述

    2、ubuntu中使用

    wsl、虚拟机都可以。参考第一章安装必要的工具。

    sudo apt install git unzip
    
    ./build.sh -b armeabi-v7a -a 24 -f 6.1.1
    

    3、windows msys2中使用

    在msys2生成需要参考第二章配置环境,以及安装必要的工具。

    pacman -S unzip git
    
    ./build.sh -b armeabi-v7a -a 24 -f 6.1.1
    

    总结

    以上就是今天讲述的内容,生成ffmpeg安卓so其实并不难,如果熟悉交叉编译以及shell,编译起来还是比较简单的,尤其是想生成最小或者完整依赖的包,最好还是自己生成。

  • 相关阅读:
    操作系统简陋复习
    浅谈UI自动化测试
    统信UOS操作系统aarch64 1060e版制作openssh 9.4p1 rpm包 —— 筑梦之路
    人工智能基础 | 机器学习介绍(一)
    服务拓扑串联难?eBPF为滴滴可观测带来解题新思路
    【Go语言从入门到实战】基础篇
    构建工具vite/webpack
    ES6的模块化管理
    贪心算法之最优装船问题
    Worthington羧基转移丨碳酸酐酶的应用和文献参考
  • 原文地址:https://blog.csdn.net/u013113678/article/details/138590619