fengfeilong0529 / Android-Notes

Ask myself one question at least every day!
0 stars 1 forks source link

Nv21转Bitmap(高效率转化) #44

Open fengfeilong0529 opened 5 years ago

fengfeilong0529 commented 5 years ago

前言

在调Camera的时候有个回调方法onPreviewFrame是返回摄像头每一帧的图像数据的,当我们需要对图像数据做处理时就需要Nv21转Bitmap,下面介绍两种方式第一种方式只需要几毫秒时间,第二种方式需要几十毫秒。

第一种方式(高效,推荐)


import android.content.Context;
import android.graphics.Bitmap;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicYuvToRGB;
import android.renderscript.Type;

public class NV21ToBitmap {

    private RenderScript rs;
    private ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic;
    private Type.Builder yuvType, rgbaType;
    private Allocation in, out;

    public NV21ToBitmap(Context context) {
        rs = RenderScript.create(context);
        yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
    }

    public Bitmap nv21ToBitmap(byte[] nv21, int width, int height){
        if (yuvType == null){
            yuvType = new Type.Builder(rs, Element.U8(rs)).setX(nv21.length);
            in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT);

            rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(width).setY(height);
            out = Allocation.createTyped(rs, 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;

    }

}

第二种方式(时间久了会内存泄漏)

private static Bitmap nv21ToBitmap(byte[] nv21, int width, int height) {
    Bitmap bitmap = null;
    try {
        YuvImage image = new YuvImage(nv21, ImageFormat.NV21, width, height, null);
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        image.compressToJpeg(new Rect(0, 0, width, height), 80, stream);
        bitmap = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
        stream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return bitmap;
}

参考: https://blog.csdn.net/bluegodisplay/article/details/53431798 https://blog.csdn.net/qq1137830424/article/details/81980673

fengfeilong0529 commented 5 years ago

Android 7.0下,使用renderscript会报错:RenderScript code cache directory uninitialized,解决方法:

参考:https://juejin.im/post/5a4353426fb9a0451d41c1a7


//在create之前调用:
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {
setRSCacheDir(context);
}
rs = RenderScript.create(context);
......

/**