为什么新版本的ffmpeg搭配新版本的ndk编译很容易出错呢?
其实关键点主要还是新旧版本ndk中的交叉编译工具不一样导致的。
比如旧版本(r17及之前)的ndk中的编译器用的是gcc,而网上大部分的同类文章中用的也是gcc,
而新版本的ndk文件已经弃用gcc编译器改用clang了,所以照着网上的文章做当然编译不起来。
从谷歌官网,NDK 修订历史记录(https://developer.android.google.cn/ndk/downloads/revision_history)
ndk-build
命令在 r13 中默认为使用 Clang。我们将在后续版本中移除 GCC。
在 13b、14b、15c、16b 中均作出了如下说明:
GCC 不再受支持,虽然尚未从 NDK 中移除,但其已不再接收向后移植项。
在17c中:
明确说明GCC 在 r18 移除。
综上所述,ndk 编译至少有两种方案,根据不同的 ndk 版本,我这里列出了不同的解决方案。
根据 GCC 和 Clang 两种编译方式,可以分成 3 种类型
1,完全GCC(r12及其以下版本)(2016.10 以前)
2,GCC 和 Clang 共存(r13,r14,r15,r16,r17)(2016.10~2018.09)
3,完全 Clang(r18及其以上)(2018.09 以后)
方案一,低版本编译:(android-ndk-r12b + ffmpeg 2.x.x)
方案二,过渡版编译:(android-ndk-r14b + ffmpeg 3.xx)
方案三,高版本编译:(android-ndk-r19c + ffmpeg 4.x.x)
备注:r19 之前的版本,NDK 的默认工具链都是独立工具链,r18 是一个比较尴尬的版本,这里就不使用了。
三种方案中,除了编译的 shell 脚本不同外,其他的步骤是相通的。这里就简单的说明下编译步骤。
第一步:配置系统(编译的系统环境:Ubuntu 20.04 LTS )
为了方便操作,这里采用 XShell 进行远程操作。
系统安装过程和 xShell 安装过程省略。
XShell 连接方式:
1、先在Ubuntu系统中获取 ip地址
ifconfig
2、判断SSH服务是否打开
ps -e|grep ssh
3、打开ssh
sudo service sshd start
4、如果提示sshd不存在则安装ssh
sudo apt install openssh-server
5、在xShell 中新建连接,输入Ubuntu的 ip 。
第二步:配置 NDK 系统环境变量
1、先安装 lrzsz 工具,方便上传文件
sudo apt install lrzsz
2、我们先将本地下载好的文件通过 xShell 上传到 linux 。
a、将 NDK 文件上传到 /usr/ndk 目录
cd /usr
sudo mkdir ndk
cd ndk
sudo rz
然后选择要上传的 ndk 文件即可。
上传完毕后,将 ndk 解压当当前目录。
sudo unzip android-ndk.zip
b、配置环境变量
需要先安装 vim ,这个自行安装
cd ~
vim .bashrc
在 bashrc 文件末尾添加 ndk 路径,根据实际名字填写
export NDKROOT=/usr/ndk/android-ndk-r12b
export PATH=$NDKROOT:$PATH
保存退出(:wq)
c、刷新环境
source .bashrc
d、测试 ndk 环境是否安装成功
ndk-build
弹出类似信息:
Android NDK: Could not find application project directory !
Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.
/usr/ndk/android-ndk-r12b/build/core/build-local.mk:151: *** Android NDK: Aborting
第三步:上传 FFmpeg 并配置脚本
1、上传 ffmpeg 文件
将 ffmpeg 压缩文件上传到 /usr/ffmpeg-android
cd /usr/
sudo mkdir ffmpeg-android
cd ffmpeg-android/
sudo rz
选择下载好的 ffmpeg 压缩文件,上传完成后解压到当前目录。
sudo tar -xzvf ffmpeg-2.7.7.tar.gz
一般而言,以“.gz”结尾的是以gzip方式进行压缩的,以".bz2"结尾的是以bzip2方式压缩的。
tar命令有5个常用的选项:
1 “c”:表示创建,用来生成文件包;
2 “x”:表示提取,从文件包中提取文件;
3 “z”:使用 gzip 方式进行处理,它与“c”结合就表示压缩,与“x”结合就表示解压缩;
4 “j”:使用 bzip2 方式进行处理,它与“c”结合就表示压缩,与“x”结合就表示解压缩;
5、“v” : 即view,是可视化的意思,想看解压的文件进度就加上v。
6 “f”:表示文件,后面接着一个文件名。
所以,怎样使用tar命令去压缩,解压文件就一目了然了吧,理解了之后很容易记住,以后就不用再查了。
2、进入 解压后的文件目录,创建编译文件
sudo touch build_android.sh
vim build_android.sh
2.x 的编译脚本(配置文件换行如果前面自动加tab空格要删除)
#!/bin/bash
export NDK_HOME=/usr/ndk/android-ndk-r12b
export PLATFORM_VERSION=android-9
function build
{
echo "start build ffmpeg for $CPU"
./configure --target-os=linux \
--prefix=$PREFIX --arch=$ARCH \
--disable-doc \
--enable-shared \
--disable-static \
--disable-yasm \
--disable-asm \
--disable-symver \
--enable-gpl \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--cross-prefix=$CROSS_COMPILE \
--enable-cross-compile \
--sysroot=$SYSROOT \
--extra-cflags="-Os -fpic $ADDI_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
echo "build ffmpeg for $CPU finished"
}
#arm
ARCH=arm
CPU=arm
PREFIX=$(pwd)/android/$CPU
TOOLCHAIN=$NDK_HOME/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi-
ADDI_CFLAGS="-marm"
SYSROOT=$NDK_HOME/platforms/$PLATFORM_VERSION/arch-$ARCH/
build
#x86
ARCH=x86
CPU=x86
PREFIX=$(pwd)/android/$CPU
TOOLCHAIN=$NDK_HOME/toolchains/x86-4.9/prebuilt/linux-x86_64
CROSS_COMPILE=$TOOLCHAIN/bin/i686-linux-android-
ADDI_CFLAGS="-march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32"
SYSROOT=$NDK_HOME/platforms/$PLATFORM_VERSION/arch-$ARCH/
build
将NDK路径替换成自己实际的 ndk 路径,
保存 platforms 和 toolchains 的子目录是存在的,
如果不存在,选择已存在的目录
效果图:
退出请按 Esc ,然后输入 :wq! 强制保存
3.x 的编译脚本(android-ndk-r14b + ffmpeg-3.3.9)
#!/bin/bash
export NDK_HOME=/usr/ndk/android-ndk-r14b
export PLATFORM_VERSION=android-9
function build
{
echo "start build ffmpeg for $ARCH"
./configure --target-os=linux \
--prefix=$PREFIX --arch=$ARCH \
--disable-doc \
--enable-shared \
--disable-static \
--disable-yasm \
--disable-asm \
--disable-symver \
--enable-gpl \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--cross-prefix=$CROSS_COMPILE \
--enable-cross-compile \
--sysroot=$SYSROOT \
--enable-small \
--extra-cflags="-Os -fpic $ADDI_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
echo "build ffmpeg for $ARCH finished"
}
#arm
ARCH=arm
CPU=arm
PREFIX=$(pwd)/android/$ARCH
TOOLCHAIN=$NDK_HOME/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi-
ADDI_CFLAGS="-marm"
SYSROOT=$NDK_HOME/platforms/$PLATFORM_VERSION/arch-$ARCH/
build
#x86
ARCH=x86
CPU=x86
PREFIX=$(pwd)/android/$ARCH
TOOLCHAIN=$NDK_HOME/toolchains/x86-4.9/prebuilt/linux-x86_64
CROSS_COMPILE=$TOOLCHAIN/bin/i686-linux-android-
ADDI_CFLAGS="-march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32"
SYSROOT=$NDK_HOME/platforms/$PLATFORM_VERSION/arch-$ARCH/
build
效果图如下:
4.x 的编译脚本(android-ndk-r19c + ffmpeg-4.0.6)
r19 编译的最低版本,为了兼容,统一使用 21:
aarch64-linux-android21-clang
armv7a-linux-androideabi16-clang
i686-linux-android16-clang
x86_64-linux-android21-clang
#!/bin/bash
NDK=/usr/ndk/android-ndk-r19c
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64/
API=21
function build_android
{
echo "Compiling FFmpeg for $CPU"
./configure \
--prefix=$PREFIX \
--disable-neon \
--disable-hwaccels \
--disable-gpl \
--disable-postproc \
--enable-shared \
--enable-jni \
--disable-mediacodec \
--disable-decoder=h264_mediacodec \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-avdevice \
--disable-doc \
--disable-symver \
--cross-prefix=$CROSS_PREFIX \
--target-os=android \
--arch=$ARCH \
--cpu=$CPU \
--cc=$CC \
--cxx=$CXX \
--enable-cross-compile \
--sysroot=$SYSROOT \
--extra-cflags="-Os -fpic -mno-stackrealign $OPTIMIZE_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS" \
--disable-asm \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
echo "The Compilation of FFmpeg for $CPU is completed"
}
#armv8-a
ARCH=arm64
CPU=armv8-a
CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clang
CXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=$CPU"
build_android
#armv7-a
ARCH=arm
CPU=armv7-a
CC=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang
CXX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/arm-linux-androideabi-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfp -marm -march=$CPU "
build_android
#x86
ARCH=x86
CPU=x86
CC=$TOOLCHAIN/bin/i686-linux-android$API-clang
CXX=$TOOLCHAIN/bin/i686-linux-android$API-clang++
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/i686-linux-android-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32"
build_android
#x86_64
ARCH=x86_64
CPU=x86-64
CC=$TOOLCHAIN/bin/x86_64-linux-android$API-clang
CXX=$TOOLCHAIN/bin/x86_64-linux-android$API-clang++
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/x86_64-linux-android-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=$CPU -msse4.2 -mpopcnt -m64 -mtune=intel"
build_android
效果图如下:
问题1:4.x 版本没有生成x86 包
解决方案:
-mno-stackrealign
问题2:编译x86版本时,出现如下错误:
解决方案:安装 yasm
sudo apt install yasm
问题3:4.x的x86 在6.0及以上版本报(has text relocations)
解决方案:
--disable-asm \
https://blog.csdn.net/mike_modern/article/details/78762746
3、2.x 和 3.x 的 ffmpeg 还需要修改配置文件,保证生成的 *.so 文件是可用的
vim configure
将 vim 的行号显示出来,方便等下编辑
:set number 回车键确认
搜索要修改的位置
/# build
然后跳转到 刚才定位的位置 大概 2850 行
:2850 回车键确认
i 进入编辑模式
将需要替换的文字替换
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'
修改完成效果如下:
:wq! 保存退出
4、授予执行权限
为了方便,直接将整个目录,及其子文件授予最高权限
cd ..
chmod 777 -R ffmpeg-2.7.7
5、开始编译
cd ffmpeg-2.7.7/
sudo ./build_android.sh
6、将编译好的文件压缩下载到本地
编译完成后可以看到如下目录:
将 根目录下的 android 文件夹, 整个压缩 成 android.zip 然后下载到本地电脑。
在ffmpeg 根目录中
sudo zip -r android.zip android/
sudo sz android.zip
选择保存的目录即可
第四步:将编译好的so 集成到本地项目
省略...
NDK 下载地址:https://developer.android.google.cn/ndk/downloads/older_releases
FFMPEG 下载地址:http://www.ffmpeg.org/olddownload.html
XShell下载:https://www.netsarang.com/zh/xshell/
参考:
https://juejin.cn/post/6844903945496690696
https://blog.csdn.net/mvp_dawn/article/details/109125631
ffmpeg ./configure 的相关参数说明:
https://blog.csdn.net/fengsh998/article/details/79443503
编译好的资源下载: