Android(安卓)preview YUV转换 RenderScript 优化
PS:2018/0807
不可以使用生产者模式 去不断的textureView.getBitmap, 否则RenderThread线程会 非常奇怪的抛出异常(疑似当前Frame被释放,再get的native层空指针)。应该在TextureView.SurfaceTextureListener的onSurfaceTextureUpdated(SurfaceTexture surface) 回调内去textureView.getBitmap
PS:2018/05/07
最近又发现TextureView的getBitmap方法 更快,比RenderScript还快。具体就是讲Camera 的Preview set到TextureView上,然后调用TextureView的getBitmap方法。推荐用生产者模式去getBitmap,我试验的是整幅图也就10+ms
Context
YUV格式转换为Bitmap比较耗时,使用RenderScript从50ms降到3、4ms(和像素值、手机相关,但比例差不多)
RenderScript耗时的地方是内存Allocation的分配,RenderScript的初始化,所以要设置为属性 缓存起来,不要重复创建。只要预览的宽高不变是不用变Allocation的大小的。
RenderScript
简单讲就是 Android系统为 解决高计算作业问题 采用了基于 C语言风格的RenderScript。具体:系统利用GPU、CPU多核来处理并发调度,使程序员只专注于算法。系统自己提供了几个常用的RenderScript,高斯模糊、直方图、yuv格式转换。
具体怎么看官网,不累述了,直接上代码
参考博客: Camera使用RenderScript
代码
private void initRenderScript() { renderScript = RenderScript.create(this); yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(renderScript, Element.U8_4(renderScript)); script = new ScriptC_rotator(renderScript); }
public Bitmap YUV_toRGB(byte[] yuvByteArray, int width, int height) { Allocation in = getYuvAllocationIn(yuvByteArray); Allocation out = getAllocationOut(width, height); in.copyFrom(yuvByteArray); yuvToRgbIntrinsic.setInput(in); yuvToRgbIntrinsic.forEach(out); Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); out.copyTo(bmp); bmp = rotate(bmp); return bmp; }
private Allocation getYuvAllocationIn(byte[] yuvByteArray) { if (mInAllocation == null || yuvByteArray.length != preYuvInLength) { preYuvInLength = yuvByteArray.length; Type.Builder yuvType = new Type.Builder(renderScript, Element.U8(renderScript)).setX(yuvByteArray.length); mInAllocation = Allocation.createTyped(renderScript, yuvType.create(), Allocation.USAGE_SCRIPT); } return mInAllocation; }
private Allocation getAllocationOut(int W, int H) { if (preW != W || preH != H) { preW = W; preH = H; Type.Builder rgbaType = new Type.Builder(renderScript, Element.RGBA_8888(renderScript)).setX(W).setY(H); outAllocation = Allocation.createTyped(renderScript, rgbaType.create(), Allocation.USAGE_SCRIPT); } return outAllocation; }
public Bitmap rotate(Bitmap bitmap) { Bitmap.Config config = bitmap.getConfig(); int targetHeight = bitmap.getWidth(); int targetWidth = bitmap.getHeight(); script.set_inWidth(bitmap.getWidth()); script.set_inHeight(bitmap.getHeight()); Allocation sourceAllocation = getFromRotateAllocation(bitmap); sourceAllocation.copyFrom(bitmap); script.set_inImage(sourceAllocation); bitmap.recycle(); Bitmap target = Bitmap.createBitmap(targetWidth, targetHeight, config); final Allocation targetAllocation = getToRotateAllocation(target); script.forEach_rotate_270_clockwise(targetAllocation, targetAllocation); targetAllocation.copyTo(target); return target; }
private Allocation getFromRotateAllocation(Bitmap bitmap) { int targetHeight = bitmap.getWidth(); int targetWidth = bitmap.getHeight(); if (targetHeight != preRotateHeight || targetWidth != preRotateWidth) { preRotateHeight = targetHeight; preRotateWidth = targetWidth; fromRotateAllocation = Allocation.createFromBitmap(renderScript, bitmap, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT); } return fromRotateAllocation; } private Allocation getToRotateAllocation(Bitmap bitmap) { int targetHeight = bitmap.getWidth(); int targetWidth = bitmap.getHeight(); if (targetHeight != preRotateHeight || targetWidth != preRotateWidth) { toRotateAllocation = Allocation.createFromBitmap(renderScript, bitmap, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT); } return toRotateAllocation; }
Preview拿的是物理设备方向,所以用时需要旋转,旋转的RenderScript是自己写的。
main/rs/your.package.name(包名)/rotate.rs
#pragma version(1)#pragma rs java_package_name(your.package.name)rs_allocation inImage;int inWidth;int inHeight;uchar4 __attribute__ ((kernel)) rotate_90_clockwise (uchar4 in, uint32_t x, uint32_t y) { uint32_t inX = inWidth - 1 - y; uint32_t inY = x; const uchar4 *out = rsGetElementAt(inImage, inX, inY); return *out;}uchar4 __attribute__ ((kernel)) rotate_270_clockwise (uchar4 in, uint32_t x, uint32_t y) { uint32_t inX = y; uint32_t inY = inHeight - 1 - x; const uchar4 *out = rsGetElementAt(inImage, inX, inY); return *out;}
#pragma rs java_package_name(your.package.name) 这一行里的your.package.name需要替换你放置rotate.rs的地方
build后系统自动生成ScriptC_rotator 类,上文的script就是ScriptC_rotator的对象
更多相关文章
- 获取设备上所有系统app信息
- Android(安卓)学生信息管理系统
- unix like系统的android反编译工具
- springmvc+mybatis 构建cms内容发布系统 ios android
- android编译系统makefile(Android.mk)写法 (zz)
- Android(安卓)Interfaces and Architecture 安卓接口和架构
- ubuntu环境下载android系统源码代码
- android 如何隐藏4.0以上系统下面的3按个虚拟按键?
- Android之系统架构