Mac下编译FFmpeg(Android平台)

    说在前面的话:之前一直在iOS平台上面做音视频开发,用得较多的是iOS的FFmpeg编译以及裁减等。因工作需要,现在要编译Android环境下的FFmpeg,本想偷懒直接使用网上现成的资源,后发现现成的脚本针对NDK或FFmpeg版本较低。为了统一不同平台(iOS、Android、arm嵌入式等)之间的代码及版本之间的兼容性,自己动手写了一份,不需要配置复杂环境,大家可做参考。

    整个流程主要包括3个部分:FFmpeg脚本、FFmpeg修改脚本、FFmpeg修改补丁(4个文件),将这些文件文本放在同一个目录下,最后执行build-ffmpeg-android.sh脚本即可。

    注意

        1、不需要自己手动下载FFmpeg源码;

        2、不需要下载Android Studio,需要下载脚本中对应NDK

        3、Android API版本必须大等于21,即至少需要填写21(因5.0以下版本不支持arm64);

       4、将build-ffmpeg-android.sh脚本中NDK=/Users/lzj/Desktop/Resources/android-ndk-r17修改成你下载的NDK文件路径;

    若CSDN积分富裕,可直接下载脚本按照上面注意事项修改之后进行编译FFmpeg脚本x264脚本


编译环境

FFmpeg:3.4.2

Mac:10.13.5

NDK:android-ndk-r17

Android API:28


FFmpeg编译脚本

#!/bin/bash

#需要编译FFpmeg版本号
FF_VERSION="3.4.2"
SOURCE="ffmpeg-$FF_VERSION"
SHELL_PATH=`pwd`
FF_PATH=$SHELL_PATH/$SOURCE
#输出路径
PREFIX=$SHELL_PATH/FFmpeg_android
COMP_BUILD=$1

#需要编译的Android API版本,需大等于21
ANDROID_API=21
#需要编译的NDK路径,NDK版本需大等于r15c
NDK=/Users/lzj/Library/Android/sdk/ndk-bundle

#x264库路径
x264=$SHELL_PATH/x264_android
if [ "$x264" ] && [[ $FF_VERSION == 3.0.* ]] || [[ $FF_VERSION == 3.1.* ]] 
then
echo "Use low version x264"
sh $SHELL_PATH/build-x264-android.sh
elif [ "$x264" ]
then
sh $SHELL_PATH/build-x264-android.sh last $ANDROID_API $NDK
fi

#需要编译的平台:arm arm64 x86 x86_64,可传入平台单独编译对应的库
ARCHS=(arm arm64 x86 x86_64)
TRIPLES=(arm-linux-androideabi aarch64-linux-android i686-linux-android x86_64-linux-android)
TRIPLES_PATH=(arm-linux-androideabi-4.9 aarch64-linux-android-4.9 x86-4.9 x86_64-4.9)

FF_CONFIGURE_FLAGS="--enable-static --disable-shared --enable-pic --enable-gpl --enable-postproc --disable-stripping --enable-small --enable-version3"

rm -rf "$SOURCE"
if [ ! -r $SOURCE ]
then
    echo "$SOURCE source not found, Trying to download..."
    curl http://www.ffmpeg.org/releases/$SOURCE.tar.bz2 | tar xj || exit 1
fi

#若使用android-ndk-r15c及以上NDK需要打此补丁(修改FFmepg与NDK代码冲突)
sh $SHELL_PATH/build-ffmpeg-patch.sh $FF_PATH

cd $FF_PATH
export TMPDIR=$FF_PATH/tmpdir
mkdir $TMPDIR
for i in "${!ARCHS[@]}";
do
    ARCH=${ARCHS[$i]}
    TOOLCHAIN=$NDK/toolchains/${TRIPLES_PATH[$i]}/prebuilt/darwin-x86_64
    SYSROOT=$NDK/platforms/android-$ANDROID_API/arch-$ARCH/
    ISYSROOT=$NDK/sysroot
    ASM=$ISYSROOT/usr/include/${TRIPLES[$i]}
    CROSS_PREFIX=$TOOLCHAIN/bin/${TRIPLES[$i]}-
    PREFIX_ARCH=$PREFIX/$ARCH

    if [ "$COMP_BUILD" = "" -o "$COMP_BUILD" = "$ARCH" ]
    then
        if [ "$ARCH" = "arm" ]
        then
            FF_EXTRA_CONFIGURE_FLAGS="--disable-asm"
            FF_EXTRA_CFLAGS="-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"
        elif [ "$ARCH" = "arm64" ]
        then
            FF_EXTRA_CONFIGURE_FLAGS="--enable-asm"
            FF_EXTRA_CFLAGS=""
            ARCH="aarch64"
        elif [ "$ARCH" = "x86" -o "$ARCH" = "x86_64" ]
        then
            FF_EXTRA_CONFIGURE_FLAGS="--disable-asm"
            FF_EXTRA_CFLAGS="-Dipv6mr_interface=ipv6mr_ifindex -fasm -Wno-psabi -fno-short-enums -fno-strict-aliasing -fomit-frame-pointer -march=k8"
        else
            echo "Unrecognized arch:$ARCH"
            exit 1
        fi

        if [ "$x264" ]
        then
            FF_EXTRA_CONFIGURE_FLAGS="$FF_EXTRA_CONFIGURE_FLAGS --enable-libx264 --enable-encoder=libx264"
            FF_EXTRA_CFLAGS="$FF_EXTRA_CFLAGS -I$x264/${ARCHS[$i]}/include"
            FF_LDFLAGS="-L$x264/${ARCHS[$i]}/lib"
        else
            FF_LDFLAGS=""
        fi
    else
        continue
    fi
    FF_CFLAGS="-I$ASM -isysroot $ISYSROOT -D__ANDROID_API__=$ANDROID_API -U_FILE_OFFSET_BITS -O3 -pipe -Wall -ffast-math -fstrict-aliasing -Werror=strict-aliasing -Wno-psabi -Wa,--noexecstack -DANDROID"

    ./configure \
    --prefix=$PREFIX_ARCH \
    --sysroot=$SYSROOT \
    --target-os=android \
    --arch=$ARCH \
    --cross-prefix=$CROSS_PREFIX \
    --enable-cross-compile \
    --disable-runtime-cpudetect \
    --disable-doc \
    --disable-debug \
    --disable-ffmpeg \
    --disable-ffprobe \
    --disable-ffserver \
    $FF_CONFIGURE_FLAGS \
    $FF_EXTRA_CONFIGURE_FLAGS \
    --extra-cflags="$FF_EXTRA_CFLAGS $FF_CFLAGS" \
    --extra-ldflags="$FF_LDFLAGS" \
    $ADDITIONAL_CONFIGURE_FLAG || exit 1
    make -j3 install || exit 1
    make distclean
    rm -rf "$PREFIX_ARCH/share"
    rm -rf "$PREFIX_ARCH/lib/pkgconfig"
done

echo "Android FFmpeg bulid success!"




将上述内容写入build-ffmpeg-android.sh,并修改文件权限:

sudo chmod 777 build-ffmpeg-android.sh


FFmpeg补丁脚本

#!/bin/bash

FF_PATH=$1
SHELL_PATH=`pwd`

set -x
patch  -p0 -N --dry-run --silent -f $FF_PATH/libavcodec/aaccoder.c < $SHELL_PATH/ffmpeg_modify_aacoder.patch 1>/dev/null
if [ $? -eq 0 ]; then
patch -p0 -f $FF_PATH/libavcodec/aaccoder.c < $SHELL_PATH/ffmpeg_modify_aacoder.patch
fi

patch  -p0 -N --dry-run --silent -f $FF_PATH/libavcodec/hevc_mvs.c < $SHELL_PATH/ffmpeg_modify_hevc_mvs.patch 1>/dev/null
if [ $? -eq 0 ]; then
patch -p0 -f $FF_PATH/libavcodec/hevc_mvs.c < $SHELL_PATH/ffmpeg_modify_hevc_mvs.patch
fi

patch  -p0 -N --dry-run --silent -f $FF_PATH/libavcodec/opus_pvq.c < $SHELL_PATH/ffmpeg_modify_opus_pvq.patch 1>/dev/null
if [ $? -eq 0 ]; then
patch -p0 -f $FF_PATH/libavcodec/opus_pvq.c < $SHELL_PATH/ffmpeg_modify_opus_pvq.patch
fi

patch  -p0 -N --dry-run --silent -f $FF_PATH/configure < $SHELL_PATH/ffmpeg_modify_configure.patch 1>/dev/null
if [ $? -eq 0 ]; then
patch -p0 -f $FF_PATH/configure < $SHELL_PATH/ffmpeg_modify_configure.patch
fi
set +x

此脚本主要目的是为了执行FFmpeg代码修改的补丁,因r14之后NDK的代码及结构和之前的有部分调整,最新的NDK(大等于r15c)与FFmpeg代码存在冲突,所以需要修改FFmpeg部分代码,这不会影响任何功能。将上述内容写入build-ffmpeg-patch.sh,并修改文件权限:

sudo chmod 777 build-ffmpeg-android.sh


FFmpeg修改补丁(共4处)

ffmpeg_modify_aacoder.patch:

--- a/ffmpeg/libavcodec/aaccoder.c 
+++ b/ffmpeg/libavcodec/aaccoder.c 
@@ -58,12 +58,13 @@
 
 /* Parameter of f(x) = a*(100/lambda), defines how much PNS is allowed to
  * replace low energy non zero bands */
 #define NOISE_LAMBDA_REPLACE 1.948f
 
 #include "libavcodec/aaccoder_trellis.h"
+#undef B0
 
 /**
  * structure used in optimal codebook search
  */
 typedef struct BandCodingPath {
     int prev_idx; ///< pointer to the previous path point
ffmpeg_modify_configure.patch:
--- a/ffmpeg/configure 
+++ b/ffmpeg/configure 
@@ -3415,4 +3415,4 @@
-SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'
-LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
-SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'
-SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR) $(SLIBNAME)'
+SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
+LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'
+SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
+SLIB_INSTALL_LINKS='$(SLIBNAME)'

ffmpeg_modify_hevc_mvs.patch:

--- a/ffmpeg/libavcodec/hevc_mvs.c
+++ b/ffmpeg/libavcodec/hevc_mvs.c 
@@ -20,12 +20,13 @@
  * License along with FFmpeg; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include "hevc.h"
 #include "hevcdec.h"
+#undef B0
 
 static const uint8_t l0_l1_cand_idx[12][2] = {
     { 0, 1, },
     { 1, 0, },
     { 0, 2, },
     { 2, 0, },
ffmpeg_modify_opus_pvq.patch:
--- a/ffmpeg/libavcodec/opus_pvq.c
+++ b/ffmpeg/libavcodec/opus_pvq.c 
@@ -22,13 +22,14 @@
  * License along with FFmpeg; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include "opustab.h"
 #include "opus_pvq.h"
-
+#undef B0
+
 #define CELT_PVQ_U(n, k) (ff_celt_pvq_u_row[FFMIN(n, k)][FFMAX(n, k)])
 #define CELT_PVQ_V(n, k) (CELT_PVQ_U(n, k) + CELT_PVQ_U(n, (k) + 1))
 
 static inline int16_t celt_cos(int16_t x)
 {
     x = (MUL16(x, x) + 4096) >> 13;

以上4份代码分别新建:ffmpeg_modify_aacoder.patch、ffmpeg_modify_configure.patch、ffmpeg_modify_hevc_mvs.patch、ffmpeg_modify_opus_pvq.patch文本,将内容写入保存即可。


x264编译脚本

#!/bin/bash

X264_VERSION=""
SOURCE="x264"
SHELL_PATH=`pwd`
X264_PATH=$SHELL_PATH/$SOURCE
#输出路径
PREFIX=$SHELL_PATH/x264_android
LAST_VERSION=$1
ANDROID_API=$2
NDK=$3

#需要编译的Android API版本
if [ ! "$ANDROID_API" ]
then
ANDROID_API=21
fi
#需要编译的NDK路径,NDK版本需大等于r15c
if [ ! "$NDK" ]
then
NDK=/Users/lzj/Library/Android/sdk/ndk-bundle
fi
echo ANDROID_API=$ANDROID_API
echo NDK=$NDK

#需要编译的平台:arm arm64 x86 x86_64
ARCHS=(arm arm64 x86 x86_64)
TRIPLES=(arm-linux-androideabi aarch64-linux-android i686-linux-android x86_64-linux-android)
TRIPLES_PATH=(arm-linux-androideabi-4.9 aarch64-linux-android-4.9 x86-4.9 x86_64-4.9)

FF_CONFIGURE_FLAGS="--enable-static --enable-pic --disable-cli"

rm -rf "$SOURCE"
if [ ! -r $SOURCE ]
then
    echo "$SOURCE source not found, Trying to download..."
    if [ "$LAST_VERSION" ]
    then
        X264_TAR_NAME="last_x264.tar.bz2"
    else
        X264_TAR_NAME="x264-snapshot-20160114-2245.tar.bz2"
    fi
    curl -O http://download.videolan.org/pub/videolan/x264/snapshots/$X264_TAR_NAME
    mkdir $X264_PATH
    tar zxvf $SHELL_PATH/$X264_TAR_NAME --strip-components 1 -C $X264_PATH || exit 1
fi

cd $X264_PATH
for i in "${!ARCHS[@]}";
do
    ARCH=${ARCHS[$i]}
    TOOLCHAIN=$NDK/toolchains/${TRIPLES_PATH[$i]}/prebuilt/darwin-x86_64
    SYSROOT=$NDK/platforms/android-$ANDROID_API/arch-$ARCH/
    ISYSROOT=$NDK/sysroot
    ASM=$ISYSROOT/usr/include/${TRIPLES[$i]}
    CROSS_PREFIX=$TOOLCHAIN/bin/${TRIPLES[$i]}-
    PREFIX_ARCH=$PREFIX/$ARCH

    FF_CFLAGS="-I$ASM -isysroot $ISYSROOT -D__ANDROID_API__=$ANDROID_API -U_FILE_OFFSET_BITS -DANDROID"

    ./configure \
    --prefix=$PREFIX_ARCH \
    --sysroot=$SYSROOT \
    --host=${TRIPLES[$i]} \
    --cross-prefix=$CROSS_PREFIX \
    $FF_CONFIGURE_FLAGS \
    --extra-cflags="$FF_CFLAGS" \
    --extra-ldflags="" \
    $ADDITIONAL_CONFIGURE_FLAG || exit 1
    make -j3 install || exit 1
    make distclean
    rm -rf "$PREFIX_ARCH/lib/pkgconfig"
    if [[ $FF_CONFIGURE_FLAGS == *--enable-shared* ]]
    then
        mv $PREFIX_ARCH/lib/libx264.so.* $PREFIX_ARCH/lib/libx264.so
    fi
done

echo "Android x264 bulid success!"

将上述内容写入build-x264-android.sh,并修改文件权限:

sudo chmod 777 build-x264-android.sh


执行方式

1、若不需要x264,需屏蔽build-ffmpeg-android.sh脚本中下面这行代码:

x264=$SHELL_PATH/x264_android

2、项目中除NDK外,其他资源均自动下载,无须手动下载,不管是否包含x264,均只需运行build-ffmpeg-android.sh脚本即可(在脚本文件路径):

./build-ffmpeg-android.sh

3、此脚本仅包含arm(armv7-a)、arm64、x86、x86_64架构,同时可单独编译某一平台,比如arm64:

./build-ffmpeg-android.sh arm64

闲话

1、脚本文件参考了网上部分资料,本人在此表示感谢;

2、请注意查看前文中的”注意“事项,若需要修改其他版本,可自行修改脚本中对应的版本号;

3、因现在的FFmpeg对AAC已比较好的支持,脚本fdk-aac的编译连接,若需要可自行添加或联系我补上。

4、若有什么问题或建议,欢迎留言。


FFmpeg3.4.2版本已编译库传送门:动态库静态库;x264静态库:x264-snapshot-20180613-2245

猜你喜欢

转载自blog.csdn.net/lizhijian21/article/details/80676254