如何使用 JNI 在 C 中获取原始 Android 相机缓冲区?
Posted
技术标签:
【中文标题】如何使用 JNI 在 C 中获取原始 Android 相机缓冲区?【英文标题】:How do I get the raw Android camera buffer in C using JNI? 【发布时间】:2012-05-20 05:14:45 【问题描述】:我一直在彻底搜索 Google 和 ***,但找不到这个。也许我错过了一些明显的东西。谢谢!
(这是因为预览回调的Java实现[即使有缓冲区]效率太低。)
【问题讨论】:
您只有普通权限还是任何额外(可能是 root)权限? 你有没有找到一种方法来做到这一点。因为我正在寻找同样的东西。 【参考方案1】:我对主题进行了一些调查。这个presentation(来自p.277,中文)帮助很大。
相机预览调用链
正如其他人提到的,您可以使用Camera.setPreviewCallback
方法获取缓冲区。
以下是它的发生方式(详细版本):
-
用户调用
Camera.startPreview()
,这是一个原生函数。
android_hardware_Camera_startPreview
调用 C++ 的 startPreview
方法 Camera
类。
Camera
调用ICamera
接口的startPreview
方法
ICamera
向远程客户端发出 IPC
调用。
它调用CameraService
类的setCameraMode
方法。
CameraService
设置一个窗口来显示预览并调用CameraHardwareInterface
类的startPreview
方法。
后者试图在特定的camera_device_t
设备上调用start_preview
方法。 我没有进一步查找,但它应该会调用驱动程序。
当图像到达时,dataCallback
的 CameraService
被调用。
它将数据传递给客户端的handlePreviewData
方法。
客户端要么复制缓冲区,要么直接将其发送到ICameraClient
。
ICameraClient
将其通过IPC
发送到Camera
。
Camera
调用已注册的侦听器并将缓冲区传递给 JNI
。
它调用 Java 类中的回调。如果用户提供了带有Camera.addCallbackBuffer
的缓冲区,则它首先复制到缓冲区。
最后,Java 类Camera
处理消息并调用Camera.PreviewCallback
的onPreviewFrame
方法。
如您所见,在步骤 10、11 中调用了 2 个 IPC
并至少复制了两次缓冲区。camera_device_t
返回的原始缓冲区的第一个实例托管在另一个进程中,由于您无法访问它到CameraService
进行安全检查。
预览表面
但是,当您使用Camera.setPreviewTexture
或Camera.setPreviewDisplay
设置预览表面时,它会直接传递到相机设备并实时刷新,而无需上述所有链的参与。正如它的文档所说:
处理一个由屏幕合成器管理的原始缓冲区。
Java 类Surface
有一个方法来检索它的内容:
public static native Bitmap screenshot(int width, int height, int minLayer, int maxLayer);
但是这个 API 是隐藏的。请参阅 this question 了解使用方法。
【讨论】:
这个出色的总结有两个方面。 1. 步骤 10-11可能涉及memcpy
,但很可能它们只通过缓冲区而不复制,通过使用进程间内存共享。 2. Surface 的screenshot
方法是复制像素,还涉及到IPC,可能还有颜色转换,所以为了更好的性能使用它是错误的. 2a. 这个screenshot
方法产生一个RGB 位图,而大多数视频编码需要YUV。【参考方案2】:
没有公共 API 可以做你想做的事;唯一的官方(即保证工作)方法是通过调用Camera.setPreviewCallback() 设置的Java 级预览回调。在 Android > 3.0 中,您还可以使用 Camera.setPreviewTexture() 将预览数据路由到 GPU,并使用 GLES 在那里处理它(或将其读回 CPU)。 GPU 路径是 ICS AOSP 相机应用程序用于其视频效果的路径。
想必OpenCV等人翻阅了Android框架原生代码,绕过了Java Camera API,直接与下面的服务对话。
这是相当危险的,因为绝对不能保证这些接口不会在 Android 版本之间发生变化,因为它们不是公共 API 的一部分。现在使用它们可能没问题,然后当用户升级他们的设备时,您的应用将停止工作。
【讨论】:
【参考方案3】:你看过OpenCV for Android。他们的advanced tutorials 展示了如何使用 JNI,并且他们的相机包中有一个 NativeProcessor 对象。
【讨论】:
以上是关于如何使用 JNI 在 C 中获取原始 Android 相机缓冲区?的主要内容,如果未能解决你的问题,请参考以下文章