Cómo utilizar ScriptIntrinsicYuvToRGB (conversión de byte yuv a byte rgba)

Tengo byte[] yuvByteArray (imagen de 540×360 capturada del método Camera.PreviewCallback.onPreviewFrame y assets/yuv.bin archivo assets/yuv.bin ). Quiero convertir byte[] yuv en byte[] rgba array, usando el siguiente código (basado en el ejemplo de Android de LivePreview).

Pero recibo outBytes rgba array lleno de ceros para forEach y copiando out asignación a outBytes. ¿Qué pasa con mi código?


 package hellorender; import android.app.Activity; import android.content.res.AssetManager; import android.graphics.Bitmap; import android.os.Bundle; import android.support.v8.renderscript.Allocation; import android.support.v8.renderscript.Element; import android.support.v8.renderscript.RenderScript; import android.support.v8.renderscript.ScriptIntrinsicYuvToRGB; import android.support.v8.renderscript.Type; import android.widget.ImageView; import hellorender.R; import java.io.IOException; import java.io.InputStream; public class HelloRenderActivity extends Activity { public static final int W = 540; public static final int H = 360; private RenderScript rs; private ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); AssetManager assets = getAssets(); byte[] yuvByteArray = new byte[291600]; byte[] outBytes = new byte[W * H * 4]; InputStream is = null; try { is = assets.open("yuv.bin"); System.out.println("read: " + is.read(yuvByteArray)); } catch (IOException e) { e.printStackTrace(); } finally { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } ImageView iv = (ImageView) findViewById(R.id.image); rs = RenderScript.create(this); yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.RGBA_8888(rs)); Type.Builder yuvType = new Type.Builder(rs, Element.U8(rs)) .setX(W).setY(H) .setYuvFormat(android.graphics.ImageFormat.NV21); Allocation in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT); Type.Builder rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)) .setX(W).setY(H); Allocation out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT); in.copyFrom(yuvByteArray); yuvToRgbIntrinsic.setInput(in); yuvToRgbIntrinsic.forEach(out); out.copyTo(outBytes); Bitmap bmpout = Bitmap.createBitmap(W, H, Bitmap.Config.ARGB_8888); out.copyTo(bmpout); iv.setImageBitmap(bmpout); } } 

El archivo yuv.bin está definitivamente en formato NV21, ya que captura aquí http://developer.android.com/reference/android/hardware/Camera.PreviewCallback.html#onPreviewFrame

El método setYuvFormat es del nivel API 18, lo eliminé

Entonces este código funciona bien:

  rs = RenderScript.create(this); yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs)); Type.Builder yuvType = new Type.Builder(rs, Element.U8(rs)).setX(yuvByteArray.length); Allocation in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT); Type.Builder rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(W).setY(H); Allocation out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT); in.copyFrom(yuvByteArray); yuvToRgbIntrinsic.setInput(in); yuvToRgbIntrinsic.forEach(out); 

Usando API18 + la respuesta de wilddev puede mejorarse ligeramente ya que no necesitas objetos Type.Builder. Haz todo esto en el método onCreate ():

 aIn = Allocation.createSized(rs, Element.U8(rs), H*W*3/2); // what the f**k ? This is 12 bit per pixel, giving the length of the camera data byte array ! bmpout = Bitmap.createBitmap(W, H, Bitmap.Config.ARGB_8888); // you will need this bitmap for output anyway aOut = Allocation.createFromBitmap(rs, bmpout); // tada ! // and set the script´s input yuvToRgbIntrinsic.setInput(aIn); // as pixel data are stored as int (one byte for red, green, blue, alpha), you first need an int[] array int rgba[] = new int[w*h]; // the rgba[] array 

Ahora puede continuar con estas líneas o ponerlas en el método onPreviewFrame ():

 aIn.copyFrom(data); // or aIn.copyFromUnchecked(data); // which is faster and safe for camera data yuvToRgbIntrinsic.forEach(aOut); // execute the script aOut.copyTo(bmpout); // copy result from aOut to bmpout // if you need the rgba-values, do bmpout.getPixels(rgba, 0, W, 0, 0, W, H); // now you may loop through the rgba[] array and extraxt the r,g,b,a values // and put them into a byte[] array(s), BUT this will surely have impact on the performance when doing in Java 

Nuestra aplicación de prueba interna usa la siguiente secuencia para crear la asignación YUV.

  tb = new Type.Builder(mRS, Element.createPixel(mRS, Element.DataType.UNSIGNED_8, Element.DataKind.PIXEL_YUV)); tb.setX(mWidth); tb.setY(mHeight); tb.setYuvFormat(android.graphics.ImageFormat.NV21); mAllocationIn = Allocation.createTyped(mRS, tb.create(), Allocation.USAGE_SCRIPT); 

Luego, dentro de la callback que los nuevos datos de YUV están disponibles, haga

  mAllocationIn.copyFrom(theYuvByteArray); 

Cambie su tipo de salida pasado al constructor de ScriptIntrinsicYubToRGB para que sea Element.U8_4 lugar de Element.RGBA_8888 . Necesitarás lo mismo para el Type.Builder usado para crear la Allocation salida.