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类似的性能?
答案 0 :(得分:3)
我在支持Camera1和Camera2 API的应用上遇到了相同的性能问题。当Android版本高于Lollipop时,我曾经切换到Camera2 API导致非常糟糕的表现(我有两个目标:ImageReader和Surface)。
我最终只在手机有完整的硬件支持时才使用Camera2 API。您可以使用 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL
进行检查希望有所帮助
答案 1 :(得分:2)
这只是一个观察,但无论如何我都会发布它。
您说您正在注册OnImageAvailableListener。此侦听器不提供图像,而是对您订阅的同一ImageReader
的引用。然后,您必须拨打acquireLatestImage
或acquireNextImage
来获取实际图片。
the docs中有一段可能有助于了解正在发生的事情:
图像数据封装在
Image
个对象中,可以同时访问多个此类对象,最多可达maxImages
构造函数参数指定的数量。通过其Surface发送到ImageReader
的新图像会排队,直到通过acquireLatestImage()
或acquireNextImage()
调用进行访问。 由于内存限制,如果ImageReader
无法以等于生产率的速率获取和释放图像,则图像源最终会在尝试渲染到Surface时停止或丢弃图像。
所以有些事情可能会有所帮助:
maxImages
参数传递给ImageReader
构造函数(如果你耗尽了队列,你会得到IllegalStateException
。)acquireLatestImage
超过acquireNextImage
进行实时处理。此方法会自动释放旧图像,而另一个则不会,因此错误地使用acquireNextImage
会减慢图像传输速度,直到内存不足为止。