ffmpeg4.4 for Android 编译 ndk(r21e)

最近也是准备学习音视频相关的内容,可在第一步--编译就卡住了很久,遇到很多莫名其妙的坑,可谓编译的血泪史,但是在查阅几十篇博客和逛烂StackOverFlow之后,终于算是成功的把ffmpeg给编译出来了,现在分享给大家一些我踩过的坑。

编译环境

本机系统:macOS Big Sur 11.2.1

ffmpeg: 4.4

ndk:r21e

一、准备工作

下载 FFmpeg

点击这个

image-20210421180825019.png

下载完成之后解压即可。

下载ndk(需要翻墙),如果是Android开发者可以直接自己的Sdk目录下找到ndk(无需重新下载)。打开Android Studio去这个目录下面找

image-20210421181344148.png

可以看到这个目录下有个ndk的目录

image-20210421181504187.png

二、编写编译脚本

1.先进入解压好的ffmpeg文件夹,找到configure文件

image-20210421182246442.png

用记事本或者VSCode之类的编辑器打开,找到以下代码并进行替换

# 注释掉默认configure 文件中的配置:
# 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)'
注意第二行的 LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
$$(RANLIB)和"$(LIBDIR)/$(LIBNAME)"之间有一个空格,好像空格打掉了编译会出问题

改好之后记得保存

2.新建构建脚本(重要)

在解压出来的ffmpeg目录下打开命令行工具,输入

touch build_android.sh

然后随便找个编辑器打开这个编译文件,vim、Sublime、VSCode都行。

复制粘贴以下编译代码,对编译代码不熟悉的,后面我会一步步的解析这个编译脚本

#!/bin/bash
# 以下路径需要修改成自己的NDK目录
TOOLCHAIN=/xxxxxx/toolchains/llvm/prebuilt/darwin-x86_64
# 最低支持的android sdk版本
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 \
 --enable-small \
 --enable-gpl \
 --disable-decoder=h264_mediacodec \
 --disable-static \
 --disable-doc \
 --disable-programs \
 --disable-ffmpeg \
 --disable-ffplay \
 --disable-ffprobe \
 --disable-avdevice \
 --disable-symver \
 --cross-prefix=$CROSS_PREFIX \
 --target-os=android \
 --arch=$ARCH \
 --cpu=$CPU \
 --cc=$CC \
 --cxx=$CXX \
 --enable-cross-compile \
 --sysroot=$SYSROOT \
 --extra-cflags="-mno-stackrealign -Os -fpic $OPTIMIZE_CFLAGS" \
 --extra-ldflags="$ADDI_LDFLAGS" \
 $ADDITIONAL_CONFIGURE_FLAG
make clean
make -j4
make install
echo "The Compilation of FFmpeg for $CPU is completed"
}

#armv8-a
ARCH=arm64
CPU=armv8-a
# r21版本的ndk中所有的编译器都在/toolchains/llvm/prebuilt/darwin-x86_64/目录下(clang)
CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clang
CXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++
# NDK头文件环境
SYSROOT=$TOOLCHAIN/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-
# so输出路径
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=$CPU"
build_android

# 交叉编译工具目录,对应关系如下
# armv8a -> arm64 -> aarch64-linux-android-
# armv7a -> arm -> arm-linux-androideabi-
# x86 -> x86 -> i686-linux-android-
# x86_64 -> x86_64 -> x86_64-linux-android-

# CPU架构
#armv7-a
ARCH=arm
CPU=armv7-a
CC=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang
CXX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++
SYSROOT=$TOOLCHAIN/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=$TOOLCHAIN/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=$TOOLCHAIN/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

选一个编译单元来解析

#armv8-a
ARCH=arm64
CPU=armv8-a
# r21版本的ndk中所有的编译器都在/toolchains/llvm/prebuilt/darwin-x86_64/目录下(clang)
CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clang
CXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++
# NDK头文件环境
SYSROOT=$TOOLCHAIN/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-
# so输出路径
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=$CPU"
build_android

ARCH、CPU、CC这些,相当于定义变量,后面可以通过 $+变量名 进行引用。这个我相信大家有一点编程基础的都不难理解。再变量定义过后最后一句build_android是执行定义的方法,也就是

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 \
 --enable-small \
 --enable-gpl \
 --disable-decoder=h264_mediacodec \
 --disable-static \
 --disable-doc \
 --disable-programs \
 --disable-ffmpeg \
 --disable-ffplay \
 --disable-ffprobe \
 --disable-avdevice \
 --disable-symver \
 --cross-prefix=$CROSS_PREFIX \
 --target-os=android \
 --arch=$ARCH \
 --cpu=$CPU \
 --cc=$CC \
 --cxx=$CXX \
 --enable-cross-compile \
 --sysroot=$SYSROOT \
 --extra-cflags="-mno-stackrealign -Os -fpic $OPTIMIZE_CFLAGS" \
 --extra-ldflags="$ADDI_LDFLAGS" \
 $ADDITIONAL_CONFIGURE_FLAG
make clean
make -j4
make install
echo "The Compilation of FFmpeg for $CPU is completed"
}

这一段。

需要注意的点是

编译脚本最前面的TOOLCHAIN变量,路径一定要写对,后面的变量如果有对TOOLCHAIN进行拼接,也一定要检查该目录下的文件路径是否正确,以及拼接之后的文件是否存在,因为不同版本ndk可能里面的内容或者位置不同,我不确定您看到这边文章的时候里面的文件是否是和我当前目录下的文件一致。如果发现我给出的编译脚本中的文件位置和您所使用的ndk文件位置有出入,以自己ndk版本的文件位置为准

接下来一起来解析一下build_android这个方法。

1.echo为打印输出语句,没什么可说的,相当于java中的print函数

2.make clean 每次编译之前清空上次编译的内容

3.make -j4 使用4核编译

4.make install 开始编译

重头戏在这条参数链上,也是我踩坑很久的地方

./configure 表示调用同级目录的configure文件,也就是我们最开始修改了4行代码的那个文件,后面的--xxxx-xxx 这些配置项具体的我就不细说,有兴趣的可以直接用Sublime、VSCode等编译器打开configure文件,找到Help options 里面每个参数都有解释,这里我截取一小段,虽然是英文,可能对英文不好的同学不太友好,但是这个年代不会还有人不会用翻译软件吧,不会吧,不会吧?

image-20210422110213088.png

坑1

你会看到网上的有些编译脚本是这样的

image-20210422110414829.png

炸一看,好像没有什么问题,但是你开始编译,你就会发现你定义好的$PREFIX找不到文件或者目录甚至--disable-neon: command not found。是电脑出问题了?还是环境出问题了?还是打开的姿势不对?问题的原因在于在整个参数配置链中不能有注释及不该有的空格。我们看到的

# 指定输出目录
# 各种配置项,想详细了解的可以打开configure文件找到Help options:查看

这类的注释都会影响编译。插入注释,在编译解析参数链的时候就会解析不到注释后的那一项参数配置,同理,乱加空格也会导致同样的错误。所以,无论在用网上谁的编译脚本进行编译的时候,都应该检查参数链中是否有注释或者是多余的空格。

坑2

你可能会看到有些编译脚本是这样

image-20210422111929128.png

炸是一看是不是还是没有什么问题?但是你会发现你$CXX路径找不到,此时你会去一个目录一个目录对这个文件路径是否正确。最后你会发现你指定的文件路径是完全正确的。那么问题出在哪里了呢?问题出在参数链如果要换行书写,每个参数指定完成之后必须以\结尾,因为默认参数链是需要一行书写完成的,但是为了书写的美观,我们选择了换行,所以每个参数指定完成后末尾记得加上\.

到此,编译脚本就已经解析完成

最后在shell中运行编译脚本,首先在macOS和linux下,需要给编译文件赋予权限,不然在编译过程中,会遇到一些权限问题,这里我们直接最高权限拉满

chmod -R 777 build_android.sh

然后为了方便查看日志,我们把编译日志输出到一个build_log下

./build_anroid.sh > build_log

编译成功之后,会在ffmpeg目录下出现一个android目录,里面有我们编译的.so文件。

至此,ffmpeg编译已经完成,音视频的学习算是踏出了第一步,对于ffmpeg的编译有什么问题,也欢迎各位在评论区留言讨论。

另外转载请注明出处,peace !

参考文献

https://www.jianshu.com/p/117fe2ee048a

https://stackoverflow.com/questions/36664451/ffmpeg-android-build

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容