Home | History | Annotate | Download | only in testingcamera
      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      /**
     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