Android Camera2 预览输出大小

Posted

技术标签:

【中文标题】Android Camera2 预览输出大小【英文标题】:Android Camera2 preview output sizes 【发布时间】:2017-02-23 03:22:06 【问题描述】:

我正在尝试使用 Camera2 API 通过 ImageReader(YUV_420_888 格式)设置相机预览。首先我需要选择支持的预览尺寸:

StreamConfigurationMap scmap = camCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Size previewSizes[] = scmap.getOutputSizes(ImageReader.class);

我的 Nexus 5X 支持下一个尺寸:

[4032x3024,4000x3000,3840x2160,3288x2480,3200x2400,2592x1944,2688x1512,2048x1536,1920x1080,1600x1200,1440x1080,1280x960,1280x768,1280x720,1024x768,800x600,864x480,800x480,720x480,640x480,640x360,352x288,320x240,176x144,160x120]

准备一个 ImageReader 实例并使用重复捕获请求启动 CaptureSession:

mImageReader = ImageReader.newInstance(W,H, ImageFormat.YUV_420_888,1);

然后我尝试在 OnImageAvailableListener 中读取每个预览帧(以通过 GLES 进一步处理和显示)。还有我想知道的——我收到了多少 Y 通道字节:

public void onImageAvailable(ImageReader reader) 
        ByteBuffer yBuffer = mImageReader.acquireNextImage().getPlanes()[0].getBuffer();
        Log.d("Camera2Debug","Y-channel bytes received: " + yBuffer.remaining());
        ...
    

YUV_420_888 图像的 Y 通道应包含 WxH 字节,其中 W - 是宽度,H - 是高度考虑的图像。

问题: 对于某些支持的预览尺寸,yBuffer 的实际尺寸与预期值不匹配 (WxH)。

例如:

Preview Size  | Y-bytes received | Y-bytes expected  |   match
4032x3024     | 12 192 768       | 12 192 768        |    yes
1920x1080     |  2 073 600       |  2 073 600        |    yes
1440x1080     |  1 589 728       |  1 555 200        |    no
1280x960      |  1 228 800       |  1 228 800        |    yes
1280x768      |    983 040       |    983 040        |    yes
800x600       |    499 168       |    480 000        |    no
...
499168

因此,由于这个问题,即使设备支持,我也无法使用必要的预览大小。

我做错了什么?

【问题讨论】:

您可以通过记录返回图像的宽度和高度来进一步调试,但我的想法是您可能希望在最初获取尺寸时使用scmap.getOutputSizes(ImageFormat.YUV_420_888)。根据文档,getOutputSizes(Class<?>) 返回PRIVATE 格式的大小。见这里:developer.android.com/reference/android/hardware/camera2/params/… 感谢您的评论。我忘了提到acquireNextImage() 返回的图像大小是正确的(等于预览大小)。问题在于getPlanes()[0].getBuffer() 的大小。 已解决:link. 【参考方案1】:

您可能没有考虑https://developer.android.com/reference/android/media/Image.Plane.html#getRowStride(),它可能大于宽度(但至少等于它)。实际缓冲区大小为

size = rowStride * height - (rowStride - width)

减去 (rowStride - width) 因为最后一行不包括最后一个像素之后的任何填充。

【讨论】:

你说得对,我并不关心数据如何存储在数组中(就像我使用旧相机 api 中的 PreviewCallback 一样)。那么现在我需要手动从数组中提取“有用”的数据吗? 是的,如果您需要使用数据。相机硬件通常使用 stride,因为由于内存映射要求,每行的大小通常需要为 16 像素/字节的倍数。旧的 API 没有跨步,这通常会导致额外的副本以删除设备内部的跨步。这是您现在可以避免的额外开销,但您需要付出更多的工作。

以上是关于Android Camera2 预览输出大小的主要内容,如果未能解决你的问题,请参考以下文章

Camera2 API预览方面已损坏

Android Camera2 API:捕获视频而不预览

Android Camera2预览偶尔会旋转90度

如何在 Camera2 API Android 5.0 中获取单个预览帧?

Android Camera2最简单的预览框显示

在使用后台服务的情况下,android camera2预览表面