Android Camera2 预览输出尺寸

3

我正在尝试使用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”格式的尺寸。请参见此处:https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputSizes(java.lang.Class<T>) - clstrfsck
感谢您的评论。我忘记提到acquireNextImage()返回的图像大小是正确的(等于预览大小)。问题在于getPlanes()[0].getBuffer()的大小。 - frumle
已解决:链接 - frumle
1个回答

4

你说得对,我没有关注数据在数组中的存储方式(就像我使用旧相机API的PreviewCallback一样)。所以现在我需要手动从数组中提取“有用”的数据? - frumle
1
如果需要使用数据,是的。相机硬件通常使用步幅,因为每行的大小通常需要是16个像素/字节的倍数,这是由于内存映射要求所致。旧的API没有步幅,这经常导致在设备的内部需要进行额外的复制以去除步幅。现在您可以避免这种额外开销,但需要付出更多的工作成本。 - Eddy Talvala

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