YUV_420_888数据裁剪

YUV_420_888是YUV_420的一个大类,android camera2的ImageReader中设置了YUV_420_888后具体返回数据U和V是单独处于不同平面还是相同平面交叉排列要看具体的设备了,一般来说pixelStride=1表示独占一个平面(一般Y平面就只有Y数据),pixelStride=2则表示U和V是交叉排列。

最近工作中发现ImageReader设置了特定尺寸后,实际返回的数据并不是之前设定的尺寸,所得非所设,玩我把。

比如我设置的分辨率是640*480

mImageReader2 = ImageReader.newInstance(640, 480,
        ImageFormat.YUV_420_888, /*maxImages*/2);
mImageReader2.setOnImageAvailableListener(
        mOnImageAvailableListener2, mBackgroundHandler);

但是返回的数据尺寸可能是1024*480,此时rowStride=1024,需要对数据进行裁剪才可以显示真实数据

public static byte[] getBytesFromImageAsType(Image image, int type) {
    try {
        //获取源数据,如果是YUV格式的数据planes.length = 3
        //plane[i]里面的实际数据可能存在byte[].length <= capacity (缓冲区总大小)
        final Image.Plane[] planes = image.getPlanes();

        LogUtil.d("getBytesFromImageAsType,type="+type+",,top="+image.getCropRect().top+",left="+image.getCropRect().left+",bottom="+image.getCropRect().bottom+",right="+image.getCropRect().right);
        //数据有效宽度,一般的,图片width <= rowStride,这也是导致byte[].length <= capacity的原因
        // 所以我们只取width部分
        int width = image.getWidth();
        int height = image.getHeight();

        //此处用来装填最终的YUV数据,需要1.5倍的图片大小,因为Y U V 比例为 4:1:1
        byte[] yuvBytes = new byte[width * height * ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8];
        //目标数组的装填到的位置
        int dstIndex = 0;

        //临时存储uv数据的
        byte uBytes[] = new byte[width * height / 4];
        byte vBytes[] = new byte[width * height / 4];
        int uIndex = 0;
        int vIndex = 0;

        int pixelsStride, rowStride;
        for (int i = 0; i < planes.length; i++) {
            pixelsStride = planes[i].getPixelStride();
            rowStride = planes[i].getRowStride();

            ByteBuffer buffer = planes[i].getBuffer();

            //如果pixelsStride==2,一般的Y的buffer长度=640*480,UV的长度=640*480/2-1
            //源数据的索引,y的数据是byte中连续的,u的数据是v向左移以为生成的,两者都是偶数位为有效数据
            byte[] bytes = new byte[buffer.capacity()];
            buffer.get(bytes);
            LogUtil.e("i="+i+",bytes.length="+bytes.length+",rowStride="+rowStride);
            int srcIndex = 0;
            if (i == 0) {
                //直接取出来所有Y的有效区域,也可以存储成一个临时的bytes,到下一步再copy
                for (int j = 0; j < height; j++) {
                    System.arraycopy(bytes, srcIndex, yuvBytes, dstIndex, width);
                    srcIndex += rowStride;
                    dstIndex += width;
                }
                LogUtil.e("i == 0,srcIndex="+srcIndex+",dstIndex="+dstIndex+",row="+rowStride);
                //ScreenCaptureUtil.dumpFile(new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),"y.yuv").getAbsolutePath(),bytes);
            } else if (i == 1) {
                //根据pixelsStride取相应的数据

                for (int j = 0; j < height / 2; j++) {
                    for (int k = 0; k < width / 2; k++) {
                        uBytes[uIndex++] = bytes[srcIndex];
                        srcIndex += pixelsStride;
                    }
                    if (pixelsStride == 2) {
                        srcIndex += rowStride - width;
                    } else if (pixelsStride == 1) {
                        srcIndex += rowStride - width / 2;
                    }
                }
                LogUtil.d("srcIndex="+srcIndex+",uIndex="+uIndex);
            } else if (i == 2) {
                //根据pixelsStride取相应的数据
                for (int j = 0; j < height / 2; j++) {
                    for (int k = 0; k < width / 2; k++) {
                        vBytes[vIndex++] = bytes[srcIndex];
                        srcIndex += pixelsStride;
                    }
                    if (pixelsStride == 2) {
                        srcIndex += rowStride - width;
                    } else if (pixelsStride == 1) {
                        srcIndex += rowStride - width / 2;
                    }
                }
                LogUtil.d("srcIndex="+srcIndex+",bytes.length="+bytes.length+",vIndex="+vIndex);
            }
        }

        image.close();

        //根据要求的结果类型进行填充
        switch (type) {
            case YUV420P:
              //  System.arraycopy(uBytes, 0, yuvBytes, dstIndex, uBytes.length);
                System.arraycopy(vBytes, 0, yuvBytes, dstIndex , vBytes.length);

                break;
            case YUV420SP:
                for (int i = 0; i < vBytes.length; i++) {
                    yuvBytes[dstIndex++] = uBytes[i];
                    yuvBytes[dstIndex++] = vBytes[i];
                }
                break;
            case NV21:
                for (int i = 0; i < vBytes.length; i++) {
                    yuvBytes[dstIndex++] = vBytes[i];
                    yuvBytes[dstIndex++] = uBytes[i];
                }
                break;
        }
        return yuvBytes;
    } catch (final Exception e) {
        if (image != null) {
            image.close();
        }
        LogUtil.d( e.toString());
    }
    return null;
}

demo

猜你喜欢

转载自blog.csdn.net/u013795543/article/details/106682235