我一直在彻底搜索 Google 和 StackOverflow,但找不到这个。也许我错过了一些明显的东西。谢谢!
(这是因为预览回调的Java实现[即使有缓冲区]效率太低。)
最佳答案
我对主题进行了一些调查。这个presentation (从第277页开始,中文)帮助很大。
相机预览调用链
正如其他人提到的,您可以使用 Camera.setPreviewCallback
方法获取缓冲区。
以下是它的发生方式(详细版本):
- 用户调用
Camera.startPreview()
这是一个原生函数。 android_hardware_Camera_startPreview
调用C++Camera
类的startPreview
方法。Camera
调用ICamera
接口(interface)的startPreview
方法ICamera
对远程客户端进行IPC
调用。- 调用
CameraService
类的setCameraMode
方法。 CameraService
设置一个窗口显示预览并调用CameraHardwareInterface
类的startPreview
方法。- 后者尝试在特定
camera_device_t
设备上调用start_preview
方法。
我没有进一步查找,但它应该会调用驱动程序。 - 当图片到达时,调用
CameraService
的dataCallback
。 - 将数据传递给客户端的
handlePreviewData
方法。 - 客户端要么复制缓冲区,要么直接将其发送到
ICameraClient
。 ICameraClient
通过IPC
将其发送到Camera
。Camera
调用已注册的监听器并将缓冲区传递给JNI
。- 它调用 Java 类中的回调。如果用户使用
Camera.addCallbackBuffer
提供了一个缓冲区,则它首先复制到缓冲区。 - 最后,Java 类
Camera
处理消息并调用Camera.PreviewCallback
的onPreviewFrame
方法。
如您所见,调用了 2 个 IPC
调用,并且在步骤 10、11 中至少复制了两次缓冲区。camera_device_t
返回的原始缓冲区的第一个实例是托管在另一个进程中,由于 CameraService
中的安全检查,您无法访问它。
预览表面
但是,当您使用 Camera.setPreviewTexture
或 Camera.setPreviewDisplay
设置预览表面时,它会直接传递给相机设备并实时刷新,而无需上面的所有链条。正如它的文档所说:
Handle onto a raw buffer that is being managed by the screen compositor.
Java 类 Surface
有一个方法来检索它的内容:
public static native Bitmap screenshot(int width, int height, int minLayer, int maxLayer);
但是这个 API 是隐藏的。见即this question一种使用它的方法。
关于java - 如何使用 JNI 在 C 中获取原始 Android 相机缓冲区?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10670953/