在Android NDK下编译FFMPEG,除了要编写Android.mk文件外,还需要编写Application.mk来指定编译选项
一. 指定编译目标cpu的类型,使用APP_ABI 选项
如: APP_ABI := armeabi
APP_ABI := armeabi armeabi-v7a
APP_ABI := x86
目前,在构建 NDK 库时,可以使用三种支持的应用二进制接口(ABI):
- ‘armeabi’ – 默认接口,可创建出指向基于 ARM* v5TE 设备的二进制代码。具有这种目标的浮点运算使用软件浮点运算。使用此 ABI 创建的二进制代码将可以在所有 ARM* 设备上运行。
- ‘armeabi-v7a’ – 可创建出支持 ARM* v7 设备的二进制代码,将使用硬件 FPU 指令。
- ‘x86’ – 生成的二进制代码可支持包含基于硬件的浮点运算的 IA-32 指令集。
所有这些 ABI 选项均支持浮点运算。除非使用的是特定于 ARM* 的汇编指令,否则在将代码移植到 x86 时不会发生问题。其优势在于,如果碰巧您的应用仅针对‘armeabi’进行编译,而现在需要支持 x86,则您在进行大多数浮点运算时均能感觉到性能提升。
有release和debug两种选择,release表示输出二进制文件被优化,debug表示没有被优化,可以调试
如:APP_OPTIM := debug
三. 指定c,c++编译选项,使用APP_CFLAGS 和 APP_CPPFLAGS 选项,还有APP_STL
一些常用的c,c++编译选项介绍
-mlong-calls
• -ffast-math
-ffast-math, -fno-fast-math
设定 -fno-math-errno, -funsafe-math-optimizations, -fno-trapping-math, -ffinite-math-only, -fno-rounding-math, 以及 -fno-signaling-nans 这几个选项,以及设定预先处理器的 __FAST_MATH__ 宏。这些技术虽然较快,但是违反 IEEE 或 ISO 的规则,并且很有可能让程序算出错误的数值。
浮点优化选项 -ffast-math:极大地提高浮点运算速度
C99 浮点环境支持科学和数学级别的应用,这些应用必须有相当高的精度,但是某些应用却不是如此,注重速度高于精度。对于这些以速度为重的应用, -ffast-math 选项定义了预处理器宏 __FAST_MATH__, 指示编译不必遵循 IEEE 和 ISO 的浮点运算标准。
具体的分析可以参考http://blog.csdn.net/zjujoe/article/details/2604157
• -fprefetch-loop-arrays
-fprefetch-loop-arrays, -fno-prefetch-loop-arrays
若目标机器支持,在存取大型数组循环执行之前预先将数组加载至内存。于 -Os 中关闭。
其实不太会有需要存取大型数组的循环 (多媒体、数据库、科学计算软件中才比较常见),所以您可以放心将此选项关闭。
• -fforce-mem -fforce-addr
-fforce-mem, -fno-force-mem -fforce-addr, -fno-force-addr
强制在运算前将内存中的数值 (mem) 或内存位置 (addr) 复制到缓存器中。启动这两个选项可以做出较好的程序代码。
这两个是好东西,启动它们!其中 -fforce-mem 已在 -O2, -O3, -Os 中启动,所以若您有用这三个选项的其中一个,只要 -fforce-addr 就够了。
• -fomit-frame-pointer
-fomit-frame-pointer, -fno-omit-frame-pointer
若非必要,不将函式的 frame pointer 放进缓存器中。这将避免您的程序储存、设定、以及还原 frame pointer;也在许多函式中省下一个缓存器。这个选项可能让某些平台上的除错工作变成不可能!。若平台支持不使用 frame pointer 除错,这个选项将在 -O, -O2, -O3, -Os 中启动。
很抱歉,x86 刚好是非这个不可才能除错的平台之一。但是... 您想对您的桌面进行除错吗?若答案为非,您可以放心启动这个选项。
• -finline-functions
-finline-functions, -fno-inline-functions
将所有简单的函式整合进呼叫他们的函式中。编译器会自动试探并决定那些函式值得被整合。于 -O3 时启动。
虽然这个选项会增加程序大小,但是他却是个增进效能的好东西。我建议您在这里启动它,然后使用下面一个指令指定 inline 条件。
• -finline-limit
-finline-limit=n
n 为决定函式是否能被 inline 的伪指令长度。预设的值为 600。
这个数值越小,程序启动的速度越快,但是运算的速度越慢。作为桌面使用,我建议 -finline-limit=400。
• -fmove-all-movables -freduce-all-givs
-fmove-all-movables, -fno-move-all-moveables
-freduce-all-givs, -fno-redduse-all-givs
这两个是循环最佳化技术,将无关循环内容的运算改在循环外执行。编译出的执行档可能更快也可能更慢,结果跟程序的写法有很大的关系。
虽然说效能跟程序写法有关,但是大部份的状况下这两个选项会做出比较小与比较快的程序代码,所以我建议您启动他们!
• -freorder-blocks -freorder-functions
-freorder-blocks, -fno-reorder-blocks
-freorder-functions, -fno-reorder-functions
藉由重新编排程序区块来增进效能以及减少执行档大小。
这两个也是好东西,所以我建议您启动它们。缺点是会让编译时间变长。
-freorder-blocks 于 -O2, -O3 时启动,于 -Os 中关闭。-freorder-functions 于 -O2, -O3, -Os 时启动。
• -fexpensive-optimizations
-fexpensive-optimizations, -fno-expensive-optimizations
执行几个会加长编译时间的非主要最佳化程序。于 -O2, -O3, -Os 中预设开启。
虽然会增加编译时间,但是能增加效能也能减少执行档大小,所以建议启用。
• -frename-registers
-frename-registers, -fno-rename-registers
在作过缓存器定位之后,使用剩下来的缓存器。这个最佳化在有很多缓存器的 CPU 上最明显 (如 ARM、PowerPC... 等。x86 不属于他们的一份子)。会增加除错的困难度。
虽然在 x86 上不明显,但是还是有用。而且 x86-64 提供更多的缓存器,所以建议您还是应该打开它。于 -O3 时启动。
C++的异常支持:
从NDK r5就开始NDK的工具链就开始支持了C++的异常控制,只不过为了通用性的原因,所有的C++原文件被编译的时候都是默认的是-fno-exceptions,即不不支持异常控制的。
使用-fexceptions标记可以开启异常控制。所以你只需要在你的每个模块的Android.mk中添加LOCAL_CPPFLAGS += -fexceptions就可以了。
更简单的是,在你的Application.mk文件中添加APP_CPPFLAGS += -fexceptions,这种配置会自动应用到你工程的所有模块当中。
注意:
已被废弃的"arm-eabi-4.4.0"工具链提供的向后兼容的NDK是不支持异常的。
参考资料:
http://stackoverflow.com/questions/4663291/android-ndk-r5-and-support-of-c-exception
http://bbs.sjtu.edu.cn/bbstcon?board=GNULinux&reid=1305092782
RTTI support:
从NDK r5开始,NDK工具链也开始支持C++ RTTI(Runtime Type Information)了。但是,为了通用性的,所有的C++源文件被构建的时候默认是不支持RRRI的(-fno-rtti)。需要开启的话,你需要在Android.mk中添加:LOCAL_CPPFLAGS += -frtti,或者更简单的做法是在Application.mk添加APP_CPPFLAGS += -frtti。
注意:
已被废弃的"arm-eabi-4.4.0"工具链提供的向后兼容的NDK是不支持RTTI的。
c++支持库用APP_STL := gnustl_static指令指定
另外在编译FFMPEG时,还要加上针对arm的优化指令
EXTRA_CFLAGS="-mtune=cortex-a8 -march=armv7-a -mfpu=neon -mfloat-abi=softfp(等价于-mhard-float) -mvectorize-with-neon-quad"