RGB转NV21格式

RGB转NV21格式

  • 读取本地图片生成Bitmap
  • RGB转NV21
  • 保存NV21格式的byte[]为图片
  • 参考

NV21 格式属于 YUV420SP 类型,是安卓中有的模式,它的存储顺序是先存 Y 分量,再 VU 交替存储。存储大小=height * width * 3 / 2。
注意, 对于图片宽、高为奇数时,需要进行处理,否则会在byte[] yuv时发生越界。如果将byte[] yuv的初始化采用byte [] yuv = new byte[height * width + 2 * (int) Math.ceil(height / 2.0) * (int) Math.ceil(width / 2.0)],保存出的YUV格式图片不正确。 因此,采用了将奇数的宽、高,进行减一变成偶数

读取本地图片生成Bitmap

FileInputStream fis = new FileInputStream("/sdcard/test/test.jpg");
Bitmap bitmap = BitmapFactory.decodeStream(fis);

RGB转NV21

int width = bitmap.getWidth();
int height = bitmap.getHeight();

if(width % 2 != 0){
	width -= 1;
}
if(height % 2 != 0){
	height -= 1;
}
byte[] imgData = getNV21(width, height, bitmap);

public static byte[] getNV21(int inputWidth, int inputHeight, Bitmap srcBitmap) {
        int[] argb = new int[inputWidth * inputHeight];
        if (null != srcBitmap) {
            try {
                srcBitmap.getPixels(argb, 0, inputWidth, 0, 0, inputWidth, inputHeight);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
            
            if (null != srcBitmap && !srcBitmap.isRecycled()) {
                srcBitmap.recycle();
                srcBitmap = null;
            }
            return colorconvertRGB_YUV_NV21(argb, inputWidth, inputHeight);
        } else return null;
    }

public static byte[] colorconvertRGB_YUV_NV21(int[] aRGB, int width, int height) {
        final int frameSize = width * height;
        int yIndex = 0;
        int uvIndex = frameSize;
        byte[] yuv = new byte[width * height * 3 / 2];

        int a, R, G, B, Y, U, V;
        int index = 0;
        for (int j = 0; j < height; j++) {
            for (int i = 0; i < width; i++) {
                //a = (aRGB[index] & 0xff000000) >> 24; //not using it right now
                R = (aRGB[index] & 0xff0000) >> 16;
                G = (aRGB[index] & 0xff00) >> 8;
                B = (aRGB[index] & 0xff) >> 0;

                Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
                U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
                V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;

                yuv[yIndex++] = (byte) ((Y < 0) ? 0 : ((Y > 255) ? 255 : Y));

                if (j % 2 == 0 && index % 2 == 0) {
                    yuv[uvIndex++] = (byte) ((V < 0) ? 0 : ((V > 255) ? 255 : V));
                    yuv[uvIndex++] = (byte) ((U < 0) ? 0 : ((U > 255) ? 255 : U));
                }
                index++;
            }
        }
        return yuv;
    }

保存NV21格式的byte[]为图片

File pictureFile = new File("/sdcard/test/result/yuv_test.jpg");

FileOutputStream filecon = new FileOutputStream(pictureFile);

YuvImage image = new YuvImage(imgData, ImageFormat.NV21, width, height, null);   //将NV21 imgData保存成YuvImage
//图像压缩
image.compressToJpeg(new Rect(0, 0, image.getWidth(), image.getHeight()),
                    100, filecon);   // 将NV21格式图片,以质量70压缩成Jpeg,并得到JPEG数据流

参考

https://glumes.com/post/ffmpeg/understand-yuv-format/
https://stackoverflow.com/questions/5960247/convert-bitmap-array-to-yuv-ycbcr-nv21
https://blog.csdn.net/liyuanbhu/article/details/68951683

你可能感兴趣的:(android)