我如何区分imageReader相机API 2中的NV21和YV12编码?

时间:2016-11-18 12:04:25

标签: android android-camera2 yuv

我正在开发自定义相机API 2应用程序,我注意到当我使用ImageReader回调时,某些设备上的捕获格式转换是不同的。

例如在Nexus 4中工作不正常并且在Nexus5X中看起来没问题,这是输出。

enter image description here

我以这种形式初始化ImageReader:

mImageReader = ImageReader.newInstance(320, 240, ImageFormat.YUV_420_888,2); 

我的回调是简单的回调ImageReader回调。

 mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() {

    @Override
    public void onImageAvailable( ImageReader reader) {

       try {
             mBackgroundHandler.post(
                 new ImageController(reader.acquireNextImage())
             );
        }
        catch(Exception e)
        {
          //exception
        }
        }

};

在Nexus 4的情况下:我有这个错误。

D/qdgralloc: gralloc_lock_ycbcr: Invalid format passed: 0x32315659

当我尝试在两个设备中编写原始文件时,我有这些不同的图像。所以我知道Nexus 5X图像具有NV21编码,而Nexus 4具有YV12编码。 enter image description here

我找到了image format的规范,我尝试在ImageReader中获取格式。 有YV12和NV21选项,但显然,当我尝试获取格式时,我得到了YUV_420_888格式。

 int test=mImageReader.getImageFormat();

那么有没有办法让相机输入格式(NV21或YV12)区分相机类中的编码类型? CameraCharacteristics可能吗?

提前致谢。

垂发。 PD:我使用OpenGL显示RGB图像,我使用Opencv将转换转换为YUV_420_888。

2 个答案:

答案 0 :(得分:1)

YUV_420_888是一个包装器,可以托管(其中包括)NV21和YV12图像。如果必须使用飞机和步幅来访问各种颜色:

ByteBuffer Y = image.getPlanes()[0];
ByteBuffer U = image.getPlanes()[1];
ByteBuffer V = image.getPlanes()[2];

如果基础像素采用NV21格式(如Nexus 4),则pixelStride将为2,

int getU(image, col, row) {
    return getPixel(image.getPlanes()[1], col/2, row/2);
}

int getPixel(plane, col, row) {
    return plane.getBuffer().get(col*plane.getPixelStride() + row*plane.getRowStride());
}

我们采用半列和半行,因为这是U和V(色度)平面存储在420图像中的方式。

此代码仅供参考,效率非常低,您可能希望使用get(byte[], int, int)或片段着色器或本机代码中的JNI函数GetDirectBufferAddress批量访问像素。你不能使用的是方法 plane.array() ,因为这些平面保证是直接的字节缓冲区。

答案 1 :(得分:0)

这是从 YV12 转换为 NV21 的有用方法。

public static byte[] fromYV12toNV21(@NonNull final byte[] yv12,
                                    final int width,
                                    final int height) {
    byte[] nv21 = new byte[yv12.length];
    final int size = width * height;
    final int quarter = size / 4;
    final int vPosition = size; // This is where V starts
    final int uPosition = size + quarter; // This is where U starts

    System.arraycopy(yv12, 0, nv21, 0, size); // Y is same

    for (int i = 0; i < quarter; i++) {
        nv21[size + i * 2] = yv12[vPosition + i]; // For NV21, V first
        nv21[size + i * 2 + 1] = yv12[uPosition + i]; // For Nv21, U second
    }
    return nv21;
}