Camera2中的预览回调比Camera1慢得多。

29

现在是2017年,我终于开始从Camera1切换到Camera2。在Camera1中,我非常依赖setPreviewCallbackWithBuffer()进行实时帧处理,但在Camera2中,这种方式要慢得多,甚至几乎无法使用。

举个例子,在Moto G3上,Camera1可以轻松产生30-40 FPS,而在Camera2上,最多只能获得10-15 FPS。

这是我创建ImageReader的方法:

imageReader = ImageReader
  .newInstance(
    previewSize.width,        // size is around 1280x720
    previewSize.height,
    ImageFormat.YUV_420_888,  // note, it is not JPEG
    2 // max number of images, does not really affect performance
  );

imageReader.setOnImageAvailableListener(
  callback,
  CameraThread.getInstance().createHandler()
);

回调本身只做最少可能的工作:

Image image = reader.acquireNextImage();
image.close();

我已经查看过类似的答案,比如这个。但是他们的问题在于他们使用的是JPEG图像格式而不是YUV_420_888

如何实现类似Camera1的性能?


ImageReader的大小决定了相机的输出。您还可以使用YV12图像格式,并确保您拥有最新版本的Android API - King Reload
@KingReload,与YUV不同,YV12并非所有设备都支持。此外,我不指望所有客户都拥有最新版本的Android。如果Camera1可以正常工作,为什么Camera2也不能正常工作呢? - Dmitry Zaytsev
您可以根据此答案 https://dev59.com/QFkS5IYBdhLWcg3wSk1G#40152147 的建议,缩小ImageReader的图像尺寸,以使预览更加流畅。 - ahasbini
@ahasbini 这是真的,帧率会增加。但是,我希望可以像使用Camera1时一样获得完全相同的预览帧分辨率。否则,Camera2将会是相对于Camera1能力的降级,这样使用它没有任何意义。 - Dmitry Zaytsev
你找到解决方案了吗? - nhoxbypass
显示剩余3条评论
2个回答

3

我曾经在支持Camera1和Camera2 API的应用程序上遇到了相同的性能问题。当Android版本高于Lollipop时,我切换到Camera2 API,结果性能非常差(同时有一个ImageReader和一个Surface的目标)。

最终我只在手机完全支持硬件时使用了Camera2 API。您可以使用CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL进行检查。

希望能对您有所帮助。


只是想澄清一下:您的意思是,具有完整硬件支持的手机/设备在使用Camera2时性能比没有完整硬件支持的手机更好吗? - WillC
1
是的,你说得对。但实际上主要问题在于在没有完全硬件支持的手机上(可能在某个地方执行了一些软件回退),使用Camera2 API同时具有两个目标(Surface和ImageReader)。只有一个目标,例如预览,在两个API中都很好。 - Josef Grunig

2
这只是一条观察记录,但我仍会发布它。 你说你正在注册一个 OnImageAvailableListener。这个监听器不会传递图像,而是传递对你订阅的同一个 ImageReader 的引用。然后你必须调用 acquireLatestImageacquireNextImage 来获取实际的图像。 文档 中有一段话可能有助于理解正在发生的事情。 图像数据封装在“Image”对象中,可以同时访问多个这样的对象,最多可访问由“maxImages”构造函数参数指定的数量。通过其表面将新图像发送到“ImageReader”,直到通过“acquireLatestImage()”或“acquireNextImage()”调用访问为止。由于内存限制,如果“ImageReader”未以等于生产速率的速率获取和释放图像,则图像源最终会停滞或丢弃图像,以尝试呈现到表面。一些可能有所帮助的事情:
  • 在清单文件中请求大内存
  • ImageReader构造函数传递足够大的maxImages参数(如果排队已满,您将获得IllegalStateException)。
  • 实时处理时优先使用acquireLatestImage而不是acquireNextImage。这个方法会自动释放旧图像,而另一个方法则不会,因此错误地使用acquireNextImage会越来越慢,直到内存耗尽。

3
谢谢你的回答。不幸的是,我已经尝试了所有这些方法,但它们对性能没有任何影响(尽管我本来期望从“maxImages”中得到一些改善,但实际上完全没有)。 - Dmitry Zaytsev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,