25

我一直在详尽地搜索 Google 和 StackOverflow,但找不到这个。也许我错过了一些明显的东西。谢谢!

(这是因为预览回调的 Java 实现 [即使有缓冲区] 效率太低。)

4

3 回答 3

25

我对主题进行了一些调查。此演示文稿(来自第 277 页,中文)帮助很大。

相机预览调用链

正如其他人提到的,您可以使用Camera.setPreviewCallback方法获取缓冲区。
这是它在那里发生的方式(详细版本):

  1. 用户调用Camera.startPreview()是本机功能。
  2. android_hardware_Camera_startPreview调用startPreviewC++Camera类的方法。
  3. Camera调用接口的startPreview方法ICamera
  4. ICamera调用IPC远程客户端。
  5. 它调用类的setCameraMode方法CameraService
  6. CameraService设置一个窗口以显示预览并调用类的startPreview方法CameraHardwareInterface
  7. 后者尝试start_preview在特定camera_device_t设备上调用方法。
    我没有进一步抬头,但它应该会呼叫司机。
  8. 当 image 到达时,dataCallbackofCameraService被调用。
  9. 它将数据传递给handlePreviewData客户端的方法。
  10. 客户端要么复制缓冲区,要么直接将其发送到ICameraClient.
  11. ICameraClient将其发送IPCCamera.
  12. Camera调用已注册的侦听器并将缓冲区传递给JNI.
  13. 它调用 Java 类中的回调。如果用户提供了缓冲区,Camera.addCallbackBuffer则它首先复制到缓冲区。
  14. 最后,Java 类Camera处理消息并调用onPreviewFrame.Camera.PreviewCallback

如您所见IPC,在步骤 10、11 中调用了 2 个调用,并且缓冲区至少被复制了两次。由返回的原始缓冲区的第一个实例camera_device_t托管在另一个进程中,由于CameraService.

预览表面

但是,当您使用Camera.setPreviewTexture或设置预览表面时,Camera.setPreviewDisplay它会直接传递到相机设备并实时刷新,而无需上述所有链的参与。正如它的文档所说:

处理由屏幕合成器管理的原始缓冲区。

Java 类Surface有一个方法来检索它的内容:

public static native Bitmap screenshot(int width, int height, int minLayer, int maxLayer);

但是这个 API 是隐藏的。有关使用它的方法,请参阅此问题

于 2012-05-27T22:33:12.900 回答
5

没有公共 API 可以做你想做的事;唯一的官方(即保证工作)方法是通过调用Camera.setPreviewCallback()设置的 Java 级预览回调。在 Android > 3.0 中,您还可以使用Camera.setPreviewTexture()将预览数据路由到 GPU,并使用 GLES 处理它(或将其读回 CPU)。GPU 路径是 ICS AOSP 相机应用程序用于其视频效果的路径。

想必OpenCV等人已经看穿了Android框架的原生代码,绕过了Java Camera API,直接和下面的服务对话。

这是相当危险的,因为绝对不能保证这些接口不会在 Android 版本之间发生变化,因为它们不是公共 API 的一部分。现在使用它们可能没问题,然后当用户升级他们的设备时,您的应用程序将停止工作。

于 2012-05-27T18:23:51.260 回答
1

你看过OpenCV for Android吗?他们的高级教程展示了如何使用 JNI,并且他们的相机包中有一个 NativeProcessor 对象。

于 2012-05-22T19:48:45.777 回答