如何使用JNI在C中获取原始Android相机缓冲区?

Nic*_*ick 25 c java java-native-interface camera android

我一直在搜索谷歌和StackOverflow,但无法找到它.也许我错过了一些明显的东西.谢谢!

(这是因为预览回调的Java实现[甚至使用缓冲区]效率太低.)

And*_*kov 25

我对话题进行了一些调查.这个演讲(来自p.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. 当图像到达时,dataCallbackCameraService被调用.
  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.setPreviewTextureCamera.setPreviewDisplay它被直接传递到相机设备和没有上述所有的链的参与实时刷新.正如它的文件说:

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

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

public static native Bitmap screenshot(int width, int height, int minLayer, int maxLayer);
Run Code Online (Sandbox Code Playgroud)

但是这个API是隐藏的.请参阅ie 这个问题以获得使用它的方法.


Edd*_*ala 5

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

据推测,OpenCV和其他人已经浏览了Android框架本机代码,并绕过了Java Camera API,直接与下面的服务交谈.

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