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