| package com.android.testingcamera; |
| |
| import android.content.res.Resources; |
| import android.graphics.ImageFormat; |
| import android.graphics.PixelFormat; |
| import android.os.AsyncTask; |
| import android.os.SystemClock; |
| import android.renderscript.Allocation; |
| import android.renderscript.Element; |
| import android.renderscript.Matrix4f; |
| import android.renderscript.RenderScript; |
| import android.renderscript.Script; |
| import android.renderscript.ScriptGroup; |
| import android.renderscript.ScriptIntrinsicColorMatrix; |
| import android.renderscript.Type; |
| import android.util.Log; |
| import android.view.Surface; |
| import android.view.SurfaceView; |
| |
| /** |
| * Process preview callback data for display. |
| * This is done by constructing a two-step Renderscript group, |
| * the first of which converts from various YUV formats to 8bpp YUV, and |
| * the second of which converts from YUV to RGB. |
| * |
| * The processing is done in a background thread, and the result is produced |
| * into an Allocation that's backed by a SurfaceView |
| */ |
| class CallbackProcessor { |
| private SurfaceView mCallbackView; |
| private Surface mCallbackSurface; |
| |
| private Object mTaskLock = new Object(); |
| |
| private RenderScript mRS; |
| private Allocation mAllocationIn; |
| private Allocation mAllocationOut; |
| private ScriptGroup mConverter; |
| |
| private int mWidth; |
| private int mHeight; |
| private int mFormat; |
| |
| private boolean mDone = false; |
| private boolean mTaskInProgress = false; |
| |
| static final private int kStopTimeout = 2000; // ms |
| |
| private static final String TAG = "CallbackProcessor"; |
| |
| public CallbackProcessor(int width, int height, int format, |
| Resources res, SurfaceView callbackView, |
| int viewWidth, int viewHeight, |
| RenderScript rs) { |
| mWidth = width; |
| mHeight = height; |
| mFormat = format; |
| mRS = rs; |
| mCallbackView = callbackView; |
| |
| int inputSize = TestingCamera.getCallbackBufferSize(mWidth, mHeight, |
| mFormat); |
| mAllocationIn = Allocation.createSized(mRS, Element.U8(mRS), inputSize); |
| |
| Type.Builder tb = new Type.Builder(mRS, Element.RGBA_8888(mRS)); |
| tb.setX(viewWidth); |
| tb.setY(viewHeight); |
| Type outType = tb.create(); |
| |
| mAllocationOut = Allocation.createTyped(mRS, outType, |
| Allocation.USAGE_IO_OUTPUT | Allocation.USAGE_SCRIPT); |
| |
| ScriptC_callback swizzleScript = |
| new ScriptC_callback(mRS, res, R.raw.callback); |
| swizzleScript.bind_yuv_in(mAllocationIn); |
| swizzleScript.invoke_init_convert(mWidth, mHeight, |
| mFormat, viewWidth, viewHeight); |
| Script.KernelID swizzleId; |
| |
| switch (mFormat) { |
| case ImageFormat.NV21: |
| swizzleId = swizzleScript.getKernelID_convert_semiplanar(); |
| break; |
| case ImageFormat.YV12: |
| swizzleId = swizzleScript.getKernelID_convert_planar(); |
| break; |
| case ImageFormat.YUY2: |
| swizzleId = swizzleScript.getKernelID_convert_interleaved(); |
| break; |
| case ImageFormat.UNKNOWN: |
| default: |
| swizzleId = swizzleScript.getKernelID_convert_unknown(); |
| } |
| |
| ScriptGroup.Builder b = new ScriptGroup.Builder(rs); |
| b.addKernel(swizzleId); |
| mConverter = b.create(); |
| |
| mConverter.setOutput(swizzleId, mAllocationOut); |
| } |
| |
| public boolean stop() { |
| synchronized(mTaskLock) { |
| mDone = true; |
| long startTime = SystemClock.elapsedRealtime(); |
| while (mTaskInProgress) { |
| try { |
| mTaskLock.wait(kStopTimeout); |
| } catch (InterruptedException e) { |
| // ignored, keep waiting |
| } |
| long endTime = SystemClock.elapsedRealtime(); |
| if (endTime - startTime > kStopTimeout) { |
| return false; |
| } |
| } |
| } |
| mAllocationOut.setSurface(null); |
| return true; |
| } |
| |
| public void displayCallback(byte[] data) { |
| synchronized(mTaskLock) { |
| if (mTaskInProgress || mDone) return; |
| mTaskInProgress = true; |
| } |
| if (mCallbackSurface == null) { |
| mCallbackView.getHolder().setFormat(PixelFormat.RGBA_8888); |
| mCallbackSurface = mCallbackView.getHolder().getSurface(); |
| if (mCallbackSurface == null) return; |
| mAllocationOut.setSurface(mCallbackSurface); |
| } |
| new ProcessCallbackTask().execute(data); |
| } |
| |
| private class ProcessCallbackTask extends AsyncTask<byte[], Void, Boolean> { |
| |
| @Override |
| protected Boolean doInBackground(byte[]... datas) { |
| byte[] data = datas[0]; |
| |
| mAllocationIn.copyFrom(data); |
| mConverter.execute(); |
| mAllocationOut.ioSend(); |
| |
| synchronized(mTaskLock) { |
| mTaskInProgress = false; |
| mTaskLock.notify(); |
| } |
| return true; |
| } |
| |
| @Override |
| protected void onPostExecute(Boolean result) { |
| } |
| } |
| |
| } |