安卓 FFmpeg系列
第一章 Ubuntu生成ffmpeg安卓全平台so
第二章 Windows生成ffmpeg安卓全平台so
第三章 生成支持x264的ffmpeg安卓全平台so(本章)
文章目录
- [安卓 FFmpeg系列](#安卓 FFmpeg系列)
- 前言
- 一、实现步骤
- 二、完整代码
- 三、生成好的包
- 四、使用示例
-
- 1、基本用法
- 2、ubuntu中使用
- [3、windows msys2中使用](#3、windows msys2中使用)
- 总结
前言
前两张实现了ffmpeg全平台so的生成,但是ffmpeg依赖的第三方库是需要另外编译的,所以本章将提供编译x264库并加入ffmpeg的方法。本章提供的脚本在ubuntu以及windows的wsl、msys2都适用。
一、实现步骤
定义交叉编译相关变量
bash
#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源码
bash
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架构
bash
./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
bash
make -j$(nproc)
bash
make install
3、加入x264配置
bash
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
bash
./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
bash
make -j$(nproc)
bash
make install
二、完整代码
下列代码可以在ubuntu、wsl ubuntu、msys2中执行。无需任何额外操作,只需调用脚本即可生成so。可以指定cpu、安卓api、以及ffmpeg版本号。如果没有指定ANDROID_NDK_HOME会自动下载ndk,x264源码也会自动下载以及ffmpeg源码也会自动下载,然后自动生成so。同时还会生成ffmpeg.so,是ffmpeg可执行程序,笔者将其生成了so,其内包含的main符号可以直接调用,以输入命令行 。
注:合并所有库到libffmpeg.so的方式本文暂不提供。
下列代码可复制保存为build.sh直接执行。
bash
set -e
show_usage() {
echo "usage:
-p is cpu (armv7-a、armv8-a、i686、x86-64)
-a is android api number
-f is ffmpeg version
-h is help
"
}
#ffmpeg版本 -可配置
FFMPEG_VERSION=4.3.6
#ndk api版本 -可配置
API=24
#cpu 架构 -可配置 :armv7-a、armv8-a、i686、x86-64
CPU=x86-64
while getopts "p:a:f:h" arg; do
case $arg in
p)
CPU=$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 "Target cpu :$CPU"
echo "Android api :$API"
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
exit 1
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 $CPU in
armv7-a)
ARCH=arm
CROSS_PREFIX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-
USR_LIB=$SYSROOT/usr/lib/armv7a-linux-androideabi/$API
;;
armv8-a)
ARCH=arm64
CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android$API-
USR_LIB=$SYSROOT/usr/lib/aarch64-linux-android/$API
;;
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)
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}/${CPU}
PACKAGE_PREFIX=$PACKAGE_SOURCE_DIR/.output/${API}/${CPU}
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
tar -xf $PACKET_X264.tar.bz2
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-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 'ffmpeg.so' -type f -print) \
-o $PREFIX/lib/ffmpeg.so
popd
popd
echo "Generated files in: $PREFIX"
#ffmpeg -end
三、生成好的包
已加入第二章生成好的包里。
四、使用示例
1、基本用法
创建一个ffmpeg-android目录,将完整代码复制保存为build.sh
(1)查看用法
bash
./build.sh -h
(2)确认ffmpeg版本
ffmpeg版本参考:https://git.ffmpeg.org/ffmpeg.git 去掉前缀n
(3)生成so
生成全平台、api24、ffmpeg6.1.1的so
arm
bash
./build.sh -p armv7-a -a 24 -f 6.1.1
arm64
bash
./build.sh -p armv8-a -a 24 -f 6.1.1
x86
bash
./build.sh -p i686 -a 24 -f 6.1.1
x64
bash
./build.sh -p x86-64 -a 24 -f 6.1.1
生成好的so在build.sh脚本所在目录的output文件夹下
2、ubuntu中使用
wsl、虚拟机都可以。参考第一章安装必要的工具。
bash
sudo apt install git unzip
bash
./build.sh -p armv7-a -a 24 -f 6.1.1
3、windows msys2中使用
在msys2生成需要参考第二章配置环境,以及安装必要的工具。
bash
pacman -S unzip git
bash
./build.sh -p armv7-a -a 24 -f 6.1.1
总结
以上就是今天讲述的内容,生成ffmpeg安卓so其实并不难,如果熟悉交叉编译以及shell,编译起来还是比较简单的,尤其是想生成最小或者完整依赖的包,最好还是自己生成。