CallbackProcessor.java revision 59c639e1919e7f7b39758cfbafb1e12b78e7b2d4
1package com.android.testingcamera;
2
3import android.content.res.Resources;
4import android.graphics.ImageFormat;
5import android.graphics.PixelFormat;
6import android.os.AsyncTask;
7import android.os.SystemClock;
8import android.renderscript.Allocation;
9import android.renderscript.Element;
10import android.renderscript.Matrix4f;
11import android.renderscript.RenderScript;
12import android.renderscript.Script;
13import android.renderscript.ScriptGroup;
14import android.renderscript.ScriptIntrinsicColorMatrix;
15import android.renderscript.Type;
16import android.util.Log;
17import android.view.Surface;
18import 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 */
29class 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     /**
48      * JFIF standard YCbCr <-> RGB conversion matrix,
49      * column-major order.
50      */
51    static final private float[] kJpegYuv2Rgb = new float[] {
52            1.f,     1.f,      1.f,     0.f,
53            0.f,    -0.34414f, 1.772f,  0.f,
54            1.402f, -0.71414f, 0.f,     0.f,
55           -0.701f,  0.529f,  -0.886f, 1.0f
56    };
57
58    static final private int kStopTimeout = 2000; // ms
59
60    private static final String TAG = "CallbackProcessor";
61
62    public CallbackProcessor(int width, int height, int format,
63            Resources res, SurfaceView callbackView,
64            int viewWidth, int viewHeight,
65            RenderScript rs) {
66        mWidth = width;
67        mHeight = height;
68        mFormat = format;
69        mRS = rs;
70        mCallbackView = callbackView;
71
72        int inputSize = TestingCamera.getCallbackBufferSize(mWidth, mHeight,
73                mFormat);
74        mAllocationIn = Allocation.createSized(mRS, Element.U8(mRS), inputSize);
75
76        Type.Builder tb = new Type.Builder(mRS, Element.RGBA_8888(mRS));
77        tb.setX(viewWidth);
78        tb.setY(viewHeight);
79        Type outType = tb.create();
80
81        mAllocationOut = Allocation.createTyped(mRS, outType,
82                Allocation.USAGE_IO_OUTPUT | Allocation.USAGE_SCRIPT);
83
84        ScriptC_callback swizzleScript =
85                new ScriptC_callback(mRS, res, R.raw.callback);
86        swizzleScript.bind_yuv_in(mAllocationIn);
87        swizzleScript.invoke_init_convert(mWidth, mHeight,
88            mFormat, viewWidth, viewHeight);
89        Script.KernelID swizzleId;
90        switch (mFormat) {
91        case ImageFormat.NV21:
92            swizzleId = swizzleScript.getKernelID_convert_semiplanar();
93            break;
94        case ImageFormat.YV12:
95            swizzleId = swizzleScript.getKernelID_convert_planar();
96            break;
97        case ImageFormat.YUY2:
98            swizzleId = swizzleScript.getKernelID_convert_interleaved();
99            break;
100        case ImageFormat.UNKNOWN:
101        default:
102            swizzleId = swizzleScript.getKernelID_convert_unknown();
103        }
104
105        ScriptIntrinsicColorMatrix colorMatrix =
106                ScriptIntrinsicColorMatrix.create(rs, Element.U8_4(mRS));
107
108        Matrix4f yuv2rgb = new Matrix4f(kJpegYuv2Rgb);
109        colorMatrix.setColorMatrix(yuv2rgb);
110
111        ScriptGroup.Builder b = new ScriptGroup.Builder(rs);
112        b.addKernel(swizzleId);
113        b.addKernel(colorMatrix.getKernelID());
114        b.addConnection(outType, swizzleId,
115                colorMatrix.getKernelID());
116        mConverter = b.create();
117
118        mConverter.setOutput(colorMatrix.getKernelID(), mAllocationOut);
119    }
120
121    public boolean stop() {
122        synchronized(mTaskLock) {
123            mDone = true;
124            long startTime = SystemClock.elapsedRealtime();
125            while (mTaskInProgress) {
126                try {
127                    mTaskLock.wait(kStopTimeout);
128                } catch (InterruptedException e) {
129                    // ignored, keep waiting
130                }
131                long endTime = SystemClock.elapsedRealtime();
132                if (endTime - startTime > kStopTimeout) {
133                    return false;
134                }
135            }
136        }
137        mAllocationOut.setSurface(null);
138        return true;
139    }
140
141    public void displayCallback(byte[] data) {
142        synchronized(mTaskLock) {
143            if (mTaskInProgress || mDone) return;
144            mTaskInProgress = true;
145        }
146        if (mCallbackSurface == null) {
147            mCallbackView.getHolder().setFormat(PixelFormat.RGBA_8888);
148            mCallbackSurface = mCallbackView.getHolder().getSurface();
149            if (mCallbackSurface == null) return;
150            mAllocationOut.setSurface(mCallbackSurface);
151        }
152        new ProcessCallbackTask().execute(data);
153    }
154
155    private class ProcessCallbackTask extends AsyncTask<byte[], Void, Boolean> {
156
157        @Override
158        protected Boolean doInBackground(byte[]... datas) {
159            byte[] data = datas[0];
160
161            mAllocationIn.copyFrom(data);
162            mConverter.execute();
163            mAllocationOut.ioSend();
164
165            synchronized(mTaskLock) {
166                mTaskInProgress = false;
167                mTaskLock.notify();
168            }
169            return true;
170        }
171
172        @Override
173        protected void onPostExecute(Boolean result) {
174        }
175    }
176
177}
178