Android集成FFmpeg基础知识

在Android端集成FFmpeg需要掌握的基础知识:

  • JNI
  • CPU架构
  • 交叉编译
  • NDK
  • FFmpeg简介

JNI

JNI,即Java Native Interface,是Java提供用来与其他语言通信的api,“其他语言”意味不止局限于C或C++,也可以调用除C和C++之外的语言,只是大多数情况下调用C或C++;“通信”意味着Java和其他语言之间可以相互调用,不止局限于java调用其他语言,其他语言也可以主动调用Java。

Java虚拟机实现了跨平台特性,无法很好的实现与操作系统相关的本地操作,而C和C++可以,同时代表这C或C++不具备Java的跨平台能力,那么当我们再程序中使用JNI功能时,就必须关注程序的平台可移植性,JNI标准要求本地代码至少能工作在任何Java虚拟机环境。

简而言之,跨平台的Java调用了不跨平台的C/C++,使程序丧失了跨平台性,这就是调用JNI的副作用,所以可以不适用JNI时就尽量避免。而大多数不可避免的情况是:已存在C/C++写的程序/库或者Java语言不支持所要实现的特性,比如FFmpeg是由C编写的,则必须要通过JNI实现调用。

JNI 的实现步骤很简单,如下:

  • 编写带有 native 方法的 Java 类
  • 生成该类扩展名为 .h 的头文件
  • 创建该头文件的 C/C++ 文件,实现 native 方法
  • 将该 C/C++ 文件编译成动态链接库
  • 在Java 程序中加载该动态链接库

动态链接库是一组源代码的模块,其中包含可供应用程序调用的函数。比如Windows下的.dll文件就是一种动态链接库,也就是说Java程序在Windows中允许,所需要的动态链接库就是.dll文件;如果Java程序在Lniux中运行。所需的动态链接库就是.so文件,这样就使得,本来无视操作系统的Java,因为JNI,就要考虑运行环境是Windows还是Linux。除此之外,还有考虑CPU结构,这也是Android中使用JNI主要需要考虑的so库兼容型问题。

对于Java程序来说,需要的仅仅是编译后的动态链接库,不需要C/C++和.h头文件。Android亦如此,网上很多 Android NDK 教程会把需要编译的 C/C++ 源码放入 Android 工程中,形成类似这样的工程结构:

这里写图片描述

这对新手来说可能会产生误导,误以为 Android 工程需要 C/C++ 文件或 .h 头文件或者其他的文件,要清楚的是, Android 工程需要的仅仅是编译后的 .so 库,所以我们可以在工程之外编译完后,只将 .so 库移植到工程中。那为什么大多数教程会把源码先移植到 Android 工程中再去编译呢?目的只有一个:节省目录的切换以及 .so 库的复制时间,实际上这些时间微乎其微,我推荐新手将编译操作于工程外进行,更易理解。

CPU架构

CPU架构就是CPU的框架结构,设计方案,处理器厂商以某种结构为基础,生产自己的SPU,就好比总-分-总是文章的一种结构,多篇文章可以都基于总-分-总架构。
常见的CPU架构有x86,x86-64以及arm等,x86-64也是基于x86架构,只是在x86的基础上做了一些扩展,以支持64 位程序的应用,创建的Intel,AMD处理器都是基于x86架构的。
而x86架构主打的是pc段,对于移动端,arm架构处于霸主地位,由于其体积小,低功耗,低成本,高性能的优点,被广泛应用在嵌入式系统中,目前大多数安卓,苹果手机的CPU都基于arm架构,此处所说的arm架构值arm系统架构,其中包括ARMv5,ARMv7等等。
最后再看 Android 端 , Android 系统目前支持 ARMv5、ARMv7、ARMv8、 x86 、x86_64、MIPS 以及 MIPS64 共七种 CPU 架构,也就是说除此之外其他 CPU 架构的硬件并不能运行 Android 系统。

交叉编译

在某个平台上,编译该平台的可执行程序,叫做本地编译,比如在Windows平台上编译Windows自身的可执行程序,在x86平台上,编译x86平台自身可执行程序。
在某个平台上,编译另一种平台的可执行程序,就是交叉编译,比如在x86平台上,编译arm平台的可执行程序,这也是Android端使用最多的交叉编译类型。
在交叉编译时,由于主机与目标的体系架构,环境不同,所以交叉编译比本地编译负责很多,需要一些工具来解决主机与目标不同特性的问题,这些工具构成的工具集叫做交叉编译链。
既然交叉编译比本地复杂很多,那为什么不使用本地编译,比如在 arm 平台编译 arm 平台的可执行程序呢?这是因为目标平台存储空间和计算能力通常是有限的,而编译过程需要较大的存储空间和较快的计算能力,但目标平台无法提供

NDK

我们需要的是arm平台的动态库,而这一编译过程往往是在x86平台上进行,所以属于交叉编译,需要交叉编译链来实现,所以 NDK(Native Development Kit )中提供了交叉编译链,方便开发。

Android 中包括七种 CPU 架构,NDK 中自然就有与之对应的交叉编译链,以下是 Android 官网对此的表格描述:

架构 工具链名称
基于 ARM arm-linux-androideabi- < gcc-version >
基于 ARM64 aarch64-linux-android- < gcc-version >
基于 x86 x86- < gcc-version >
基于 X86-64 x86_64- < gcc-version >
基于 MIPS mipsel-linux-android- < gcc-version >
基于 MIPS64 mips64el-linux-android– < gcc-version >

除此之外,NDK 还提供了一些原生标头和共享库文件,包括 C/C++ 支持库、从 C/C++ 代码中可以向 Android 系统输出日志的 < android/log.h > 等等,可以点击这里https://developer.android.google.cn/ndk/guides/stable_apis#mnu,总之,NDK 是用来帮助我们实现交叉编译的工具。

在实际使用时,比较重要的是 Android.mk 语法,内容并不多,但你必须了解,不然只复制别人的配置很容易出错,关键是你无法真正的掌握这部分知识,而最好的学习方法就是仔细阅读几遍 Android.mk 官网教程 :https://developer.android.google.cn/ndk/guides/android_mk#over

另外还需要了解什么是 ABI ,ABI 即 application binary interface ,应用程序二进制接口,顾名思义,“二进制接口”说明这是程序与系统之间的底层接口,它定义了程序如何与系统交互。我们应该指定每个 CPU 架构所对应的 ABI,所以 Android 中就出现了 armeabi 、armeabi-v7a、arm64-v8a、x86、x86_64、mips 以及 mips64 目录来区分不同的 ABI ,我们将编译好的动态库放入对应 CPU 架构的 ABI 目录中就可以了。

掌握了以上知识点,才能知道 Android 集成 FFmpeg本质上是在做什么,为什么要这样做。不只是集成 FFmpeg,这些知识对于任何底层库的集成都是通用、必要的。

FFmpeg简介

FFmpeg是一套可以用来记录,转换数字音频,视频,并能将其转化为流的的开源计算机程序。

关于这个的环境配置,可以看:
https://blog.csdn.net/yhaolpz/article/details/76408829?locationNum=2&fps=1

猜你喜欢

转载自blog.csdn.net/qq_36391075/article/details/80558328