【问题标题】:Preview callback in Camera2 is significantly slower than in Camera1Camera2 中的预览回调明显慢于 Camera1
【发布时间】:2017-11-22 17:28:03
【问题描述】:

现在是 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();

我已经检查过类似的答案,例如this one。然而他们的问题是他们使用JPEG 图像格式而不是YUV_420_888。

如何达到类似Camera1的性能?

【问题讨论】:

  • ImageReader 的大小决定了相机的输出。您也可以使用YV12 图像格式,并确保您拥有最新版本的Android API
  • @KingReload 与 YUV 不同,并非所有设备都支持 YV12。此外,我不希望所有客户都拥有最新版本的 Android。如果 Camera1 工作正常,为什么 Camera2 也不能正常工作?
  • 您可以减小 ImageReader 的图像大小,以便预览可以更流畅,如此答案所述:stackoverflow.com/a/40152147/2949966
  • @ahasbini 帧速率确实会增加。但是,我希望拥有与使用 Camera1 完全相同的预览帧分辨率。否则,Camera2 将是 Camera1 功能的降级,使用它毫无意义。
  • 你好,德米特里。我有同样的问题。你解决了吗?还是返回Camera1?您是否尝试使用setRepeatingBurst 而不是setRepeatingRequest?

标签: android android-camera2


【解决方案1】:

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

只有当手机完全支持硬件时,我才最终使用 Camera2 API。您可以使用 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL

进行检查

希望对你有帮助

【讨论】:

  • 澄清一下:你的意思是完全硬件支持的手机/设备在使用 Camera2 时的性能比没有完全硬件支持的手机更好吗?
  • 是的,你说的没错。但主要问题实际上是在没有完全硬件支持的手机上同时使用 Camera2 API 有 2 个目标(Surface 和 ImageReader)(可能它在某处对软件执行某种回退)。两个 API 中只有一个目标(如预览)就可以了
【解决方案2】:

这只是一个观察,但我还是会发布它。

您说您正在注册OnImageAvailableListener。此侦听器不提供图像,而是对您订阅的同一 ImageReader 的引用。然后您必须调用acquireLatestImage 或acquireNextImage 来获取实际图像。

the docs 中有一段可能有助于理解发生了什么:

图像数据被封装在Image对象中,可以同时访问多个这样的对象,最多可以访问maxImages构造函数参数指定的数量。通过其 Surface 发送到ImageReader 的新图像将排队等待通过acquireLatestImage() 或acquireNextImage() 调用访问。 由于内存限制,如果ImageReader 没有以等于生产速率的速率获取和释放图像,图像源最终会在尝试渲染到 Surface 时停止或丢弃图像。 p>

所以有些事情可能会有所帮助:

  • 在清单中请求大内存
  • 将足够大的maxImages 参数传递给ImageReader 构造函数(如果你用尽队列,你会得到IllegalStateException)。
  • 更喜欢acquireLatestImage 而不是acquireNextImage 进行实时处理。此方法会自动释放较旧的图像,而另一种则不会,因此错误地使用 acquireNextImage 会越来越慢地释放图像,直到内存不足。

【讨论】:

  • 感谢您的回答。不幸的是,我已经尝试了所有这些并且它不会对性能产生轻微影响(尽管我希望 maxImages 会有所改进,但实际上没有)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-07
  • 1970-01-01
  • 2017-09-09
  • 1970-01-01
  • 2018-02-17
相关资源
最近更新 更多