1 package com.android.testingcamera; 2 3 import android.content.res.Resources; 4 import android.graphics.ImageFormat; 5 import android.graphics.PixelFormat; 6 import android.os.AsyncTask; 7 import android.os.SystemClock; 8 import android.renderscript.Allocation; 9 import android.renderscript.Element; 10 import android.renderscript.Matrix4f; 11 import android.renderscript.RenderScript; 12 import android.renderscript.Script; 13 import android.renderscript.ScriptGroup; 14 import android.renderscript.ScriptIntrinsicColorMatrix; 15 import android.renderscript.Type; 16 import android.util.Log; 17 import android.view.Surface; 18 import android.view.SurfaceView; 19 20 /** 21 * Process preview callback data for display. 22 * This is done by constructing a two-step Renderscript group, 23 * the first of which converts from various YUV formats to 8bpp YUV, and 24 * the second of which converts from YUV to RGB. 25 * 26 * The processing is done in a background thread, and the result is produced 27 * into an Allocation that's backed by a SurfaceView 28 */ 29 class CallbackProcessor { 30 private SurfaceView mCallbackView; 31 private Surface mCallbackSurface; 32 33 private Object mTaskLock = new Object(); 34 35 private RenderScript mRS; 36 private Allocation mAllocationIn; 37 private Allocation mAllocationOut; 38 private ScriptGroup mConverter; 39 40 private int mWidth; 41 private int mHeight; 42 private int mFormat; 43 44 private boolean mDone = false; 45 private boolean mTaskInProgress = false; 46 47 static final private int kStopTimeout = 2000; // ms 48 49 private static final String TAG = "CallbackProcessor"; 50 51 public CallbackProcessor(int width, int height, int format, 52 Resources res, SurfaceView callbackView, 53 int viewWidth, int viewHeight, 54 RenderScript rs) { 55 mWidth = width; 56 mHeight = height; 57 mFormat = format; 58 mRS = rs; 59 mCallbackView = callbackView; 60 61 int inputSize = TestingCamera.getCallbackBufferSize(mWidth, mHeight, 62 mFormat); 63 mAllocationIn = Allocation.createSized(mRS, Element.U8(mRS), inputSize); 64 65 Type.Builder tb = new Type.Builder(mRS, Element.RGBA_8888(mRS)); 66 tb.setX(viewWidth); 67 tb.setY(viewHeight); 68 Type outType = tb.create(); 69 70 mAllocationOut = Allocation.createTyped(mRS, outType, 71 Allocation.USAGE_IO_OUTPUT | Allocation.USAGE_SCRIPT); 72 73 ScriptC_callback swizzleScript = new ScriptC_callback(mRS); 74 swizzleScript.bind_yuv_in(mAllocationIn); 75 swizzleScript.invoke_init_convert(mWidth, mHeight, 76 mFormat, viewWidth, viewHeight); 77 Script.KernelID swizzleId; 78 79 switch (mFormat) { 80 case ImageFormat.NV21: 81 swizzleId = swizzleScript.getKernelID_convert_semiplanar(); 82 break; 83 case ImageFormat.YV12: 84 swizzleId = swizzleScript.getKernelID_convert_planar(); 85 break; 86 case ImageFormat.YUY2: 87 swizzleId = swizzleScript.getKernelID_convert_interleaved(); 88 break; 89 case ImageFormat.UNKNOWN: 90 default: 91 swizzleId = swizzleScript.getKernelID_convert_unknown(); 92 } 93 94 ScriptGroup.Builder b = new ScriptGroup.Builder(rs); 95 b.addKernel(swizzleId); 96 mConverter = b.create(); 97 98 mConverter.setOutput(swizzleId, mAllocationOut); 99 } 100 101 public boolean stop() { 102 synchronized(mTaskLock) { 103 mDone = true; 104 long startTime = SystemClock.elapsedRealtime(); 105 while (mTaskInProgress) { 106 try { 107 mTaskLock.wait(kStopTimeout); 108 } catch (InterruptedException e) { 109 // ignored, keep waiting 110 } 111 long endTime = SystemClock.elapsedRealtime(); 112 if (endTime - startTime > kStopTimeout) { 113 return false; 114 } 115 } 116 } 117 mAllocationOut.setSurface(null); 118 return true; 119 } 120 121 public void displayCallback(byte[] data) { 122 synchronized(mTaskLock) { 123 if (mTaskInProgress || mDone) return; 124 mTaskInProgress = true; 125 } 126 if (mCallbackSurface == null) { 127 mCallbackView.getHolder().setFormat(PixelFormat.RGBA_8888); 128 mCallbackSurface = mCallbackView.getHolder().getSurface(); 129 if (mCallbackSurface == null) return; 130 mAllocationOut.setSurface(mCallbackSurface); 131 } 132 new ProcessCallbackTask().execute(data); 133 } 134 135 private class ProcessCallbackTask extends AsyncTask<byte[], Void, Boolean> { 136 137 @Override 138 protected Boolean doInBackground(byte[]... datas) { 139 byte[] data = datas[0]; 140 141 mAllocationIn.copyFrom(data); 142 mConverter.execute(); 143 mAllocationOut.ioSend(); 144 145 synchronized(mTaskLock) { 146 mTaskInProgress = false; 147 mTaskLock.notify(); 148 } 149 return true; 150 } 151 152 @Override 153 protected void onPostExecute(Boolean result) { 154 } 155 } 156 157 } 158