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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章