首页  编辑  

高性能转换NV21数据到Bitmap位图

Tags: /Android/   Date Created:
在安卓开发当中,如果操作相机预览视频,要处理数据,需要在onPreviewFrame中处理数据,一般给出来的是NV21格式的数据,需要转Bitmap的时候,可以用下面的方法,只要20ms就可以搞定了。
private RenderScript renderScript;
private final ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic;
private Type.Builder yuvType, rgbaType;
private Allocation in, out;
// 初始化对象
renderScript = RenderScript.create(context);
yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(renderScript, Element.U8_4(renderScript));
public Bitmap NV21ToBitmap(byte [] nv21, int width, int height) {
    if (yuvType == null){
        yuvType = new Type.Builder(renderScript, Element.U8(renderScript)).setX(nv21.length);
        in = Allocation.createTyped(renderScript, yuvType.create(), Allocation.USAGE_SCRIPT);

        rgbaType = new Type.Builder(renderScript, Element.RGBA_8888(renderScript)).setX(width).setY(height);
        out = Allocation.createTyped(renderScript, rgbaType.create(), Allocation.USAGE_SCRIPT);
    }

    in.copyFrom(nv21);

    yuvToRgbIntrinsic.setInput(in);
    yuvToRgbIntrinsic.forEach(out);

    Bitmap bmpout = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    out.copyTo(bmpout);

    return bmpout;
}

下面的方法,需要100多ms!相差5 倍。
YuvImage image = new YuvImage(bytes, ImageFormat.NV21, previewSize.width, previewSize.height, null);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, previewSize.width, previewSize.height), 100, stream);

// 从 JPG 转码位图
Bitmap bitmap;
if (rotate) {
    Bitmap raw = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size(), bitmapOption);
    Matrix matrix = new Matrix();
    matrix.postRotate(270);
    bitmap = Bitmap.createBitmap(raw, 0, 0, raw.getWidth(), raw.getHeight(), matrix, false);
    raw.recycle();
} else {
    bitmap = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size(), bitmapOption);
}

下面的链接,可以高性能旋转位图:
https://stackoverflow.com/questions/12044674/android-rotate-image-without-loading-it-to-memory
使用的是RenderScript旋转。
Bitmap target = Bitmap.createBitmap(height, width, Bitmap.Config.ARGB_8888);
final Allocation targetAllocation = Allocation.createFromBitmap(renderScript, target,
        Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);

ScriptC_rotator script = new ScriptC_rotator(renderScript);
script.set_inWidth(width);
script.set_inHeight(height);
Allocation sourceAllocation = Allocation.createFromBitmap(renderScript, bmpout,
        Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
script.set_inImage(sourceAllocation);
script.forEach_rotate_270_clockwise(targetAllocation, targetAllocation);
targetAllocation.copyTo(target);

return target;