“Android 内置的 JNI 函数”有点自相矛盾。从技术上讲,许多 Android 框架 Java 类在某个地方使用 JNI 调用本地库是正确的。但是,关于这个说法有三个保留意见。
1. 这些都是“实现细节”,可能会在 Android 的下一个版本、任何分支(例如 Kindle)或甚至 OEM 版本中(不被视为
“分支”,例如由 Samsung 构建或针对 Quallcom SOC 构建)没有通知地进行更改。
2. 核心 Java 类中本地方法的实现方式与“传统”的 JNI 不同。这些方法被 JVM 预加载和缓存,因此不会遭受大部分 JNI 调用典型开销的影响。
3. 没有什么可以让你的 Java 或本地代码直接与其他类的 JNI 方法交互,特别是构成系统框架的类。
所有这些都说了,你可以自由地研究Android的源代码,找到支持特定类和方法(例如面部检测)的本机库,并在本机代码中使用这些库,或者构建自己的JNI层以从Java代码中使用这些库。
为了举个具体的例子,在Android中,
人脸检测是通过
android.media.FaceDetector类实现的,该类加载
libFFTEm.so
。您可以查看
本地代码并根据需要使用它。您不应假设设备上存在
libFFTEm.so
,或者设备上的库具有相同的API。
但在这种特定情况下,这不是问题,因为
neven
的所有工作完全基于软件。因此,您可以将此代码全部复制或仅复制相关部分,并将其作为本机库的一部分。请注意,对于许多设备,您可以简单地加载和使用
/system/lib/libFFTEm.so
,并且永远不会感到不适,直到您遇到一个会出现问题的系统。
通过阅读
本地代码,您可以得出一个值得注意的结论,即底层算法忽略颜色信息。因此,如果您要查找人脸坐标的图像来自YUV源,则可以避免很多开销,只需要调用。
btk_DCR_assignGrayByteImage(hdcr, bwbuffer, width, height);
int numberOfFaces = 0;
if (btk_FaceFinder_putDCR(hfd, hdcr) == btk_STATUS_OK) {
numberOfFaces = btk_FaceFinder_faces(hfd);
} else {
ALOGE("ERROR: Return 0 faces because error exists in btk_FaceFinder_putDCR.\n");
}
你可以直接使用YUV(或Y)字节数组,而不是在
android.media.FaceDetector.findFaces()中将其转换为RGB再转回YUV。如果你的YUV缓冲区来自Java,你可以构建自己的类
YuvFaceDetector
,它将是
android.media.FaceDetector的副本,唯一的区别是
YuvFaceDetector.findFaces()
只会使用Y(亮度)值,而不是位图,并避免RGB到Y的转换。
一些其他情况并不像这样简单。例如,视频编解码器与硬件平台紧密耦合,你不能仅仅从
libstagefright.so 复制代码到你的项目中。Jpeg 编解码器是一个特殊的存在。在现代系统中(我记得自 2.2 版本以来),你可以期望
/system/lib/libjpeg.so
存在。但是许多平台也有更高效的 Jpeg 编解码器的硬件实现,通过使用
libstagefright.so
或 OpenMAX,并且通常在
android.graphics.Bitmap.compress() 和
android.graphics.BitmapFactory.decode***() 方法中使用这些实现。
还有一种优化的 libjpeg-turbo,它比 /system/lib/libjpeg.so
有其独特的优势。