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 
CallbackProcessor(int width, int height, int format, Resources res, SurfaceView callbackView, int viewWidth, int viewHeight, RenderScript rs)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 
stop()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 
displayCallback(byte[] data)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
doInBackground(byte[]... datas)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
onPostExecute(Boolean result)153         protected void onPostExecute(Boolean result) {
154         }
155     }
156 
157 }
158