• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.rs.livepreview;
17 
18 //import com.android.cts.verifier.PassFailButtons;
19 //import com.android.cts.verifier.R;
20 
21 import android.app.Activity;
22 import android.app.AlertDialog;
23 import android.graphics.Bitmap;
24 import android.graphics.Color;
25 import android.graphics.ColorMatrix;
26 import android.graphics.ColorMatrixColorFilter;
27 import android.graphics.ImageFormat;
28 import android.graphics.Matrix;
29 import android.graphics.SurfaceTexture;
30 import android.hardware.Camera;
31 import android.os.AsyncTask;
32 import android.os.Bundle;
33 import android.os.Handler;
34 import android.util.Log;
35 import android.util.SparseArray;
36 import android.view.View;
37 import android.view.TextureView;
38 import android.widget.AdapterView;
39 import android.widget.ArrayAdapter;
40 import android.widget.ImageView;
41 import android.widget.Spinner;
42 
43 import java.io.IOException;
44 import java.lang.InterruptedException;
45 import java.lang.Math;
46 import java.lang.Thread;
47 import java.util.ArrayList;
48 import java.util.Comparator;
49 import java.util.List;
50 import java.util.TreeSet;
51 
52 import android.renderscript.*;
53 
54 /**
55  * Tests for manual verification of the CDD-required camera output formats
56  * for preview callbacks
57  */
58 public class CameraPreviewActivity extends Activity
59         implements TextureView.SurfaceTextureListener, Camera.PreviewCallback {
60 
61     private static final String TAG = "CameraFormats";
62 
63     private TextureView mPreviewView;
64     private SurfaceTexture mPreviewTexture;
65     private int mPreviewTexWidth;
66     private int mPreviewTexHeight;
67 
68     //private TextureView mFormatView;
69 
70     private Spinner mCameraSpinner;
71     private Spinner mResolutionSpinner;
72 
73     private int mCurrentCameraId = -1;
74     private Camera mCamera;
75 
76     private List<Camera.Size> mPreviewSizes;
77     private Camera.Size mNextPreviewSize;
78     private Camera.Size mPreviewSize;
79 
80     private TextureView mOutputView;
81     //private Bitmap mCallbackBitmap;
82 
83     private static final int STATE_OFF = 0;
84     private static final int STATE_PREVIEW = 1;
85     private static final int STATE_NO_CALLBACKS = 2;
86     private int mState = STATE_OFF;
87     private boolean mProcessInProgress = false;
88     private boolean mProcessingFirstFrame = false;
89 
90 
91     private RenderScript mRS;
92     private RsYuv mFilterYuv;
93 
94     @Override
onCreate(Bundle savedInstanceState)95     public void onCreate(Bundle savedInstanceState) {
96         super.onCreate(savedInstanceState);
97 
98         setContentView(R.layout.cf_main);
99 
100         mPreviewView = (TextureView) findViewById(R.id.preview_view);
101         mOutputView = (TextureView) findViewById(R.id.format_view);
102 
103         mPreviewView.setSurfaceTextureListener(this);
104 
105         int numCameras = Camera.getNumberOfCameras();
106         String[] cameraNames = new String[numCameras];
107         for (int i = 0; i < numCameras; i++) {
108             cameraNames[i] = "Camera " + i;
109         }
110         mCameraSpinner = (Spinner) findViewById(R.id.cameras_selection);
111         mCameraSpinner.setAdapter(
112             new ArrayAdapter<String>(
113                 this, R.layout.cf_format_list_item, cameraNames));
114         mCameraSpinner.setOnItemSelectedListener(mCameraSpinnerListener);
115 
116         mResolutionSpinner = (Spinner) findViewById(R.id.resolution_selection);
117         mResolutionSpinner.setOnItemSelectedListener(mResolutionSelectedListener);
118 
119         mRS = RenderScript.create(this);
120         mFilterYuv = new RsYuv(mRS);
121         mOutputView.setSurfaceTextureListener(mFilterYuv);
122     }
123 
124     @Override
onResume()125     public void onResume() {
126         super.onResume();
127 
128         setUpCamera(mCameraSpinner.getSelectedItemPosition());
129     }
130 
131     @Override
onPause()132     public void onPause() {
133         super.onPause();
134 
135         shutdownCamera();
136     }
137 
onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)138     public void onSurfaceTextureAvailable(SurfaceTexture surface,
139             int width, int height) {
140         mPreviewTexture = surface;
141         mPreviewTexWidth = width;
142         mPreviewTexHeight = height;
143         if (mCamera != null) {
144             startPreview();
145         }
146     }
147 
onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height)148     public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
149         // Ignored, Camera does all the work for us
150     }
151 
onSurfaceTextureDestroyed(SurfaceTexture surface)152     public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
153         return true;
154     }
155 
onSurfaceTextureUpdated(SurfaceTexture surface)156     public void onSurfaceTextureUpdated(SurfaceTexture surface) {
157         // Invoked every time there's a new Camera preview frame
158     }
159 
160     private AdapterView.OnItemSelectedListener mCameraSpinnerListener =
161             new AdapterView.OnItemSelectedListener() {
162                 public void onItemSelected(AdapterView<?> parent,
163                         View view, int pos, long id) {
164                     if (mCurrentCameraId != pos) {
165                         setUpCamera(pos);
166                     }
167                 }
168 
169                 public void onNothingSelected(AdapterView parent) {
170 
171                 }
172 
173             };
174 
175     private AdapterView.OnItemSelectedListener mResolutionSelectedListener =
176             new AdapterView.OnItemSelectedListener() {
177                 public void onItemSelected(AdapterView<?> parent,
178                         View view, int position, long id) {
179                     if (mPreviewSizes.get(position) != mPreviewSize) {
180                         mNextPreviewSize = mPreviewSizes.get(position);
181                         startPreview();
182                     }
183                 }
184 
185                 public void onNothingSelected(AdapterView parent) {
186 
187                 }
188 
189             };
190 
191 
setUpCamera(int id)192     private void setUpCamera(int id) {
193         shutdownCamera();
194 
195         mCurrentCameraId = id;
196         mCamera = Camera.open(id);
197         Camera.Parameters p = mCamera.getParameters();
198 
199         // Get preview resolutions
200 
201         List<Camera.Size> unsortedSizes = p.getSupportedPreviewSizes();
202 
203         class SizeCompare implements Comparator<Camera.Size> {
204             public int compare(Camera.Size lhs, Camera.Size rhs) {
205                 if (lhs.width < rhs.width) return -1;
206                 if (lhs.width > rhs.width) return 1;
207                 if (lhs.height < rhs.height) return -1;
208                 if (lhs.height > rhs.height) return 1;
209                 return 0;
210             }
211         };
212 
213         SizeCompare s = new SizeCompare();
214         TreeSet<Camera.Size> sortedResolutions = new TreeSet<Camera.Size>(s);
215         sortedResolutions.addAll(unsortedSizes);
216 
217         mPreviewSizes = new ArrayList<Camera.Size>(sortedResolutions);
218 
219         String[] availableSizeNames = new String[mPreviewSizes.size()];
220         for (int i = 0; i < mPreviewSizes.size(); i++) {
221             availableSizeNames[i] =
222                     Integer.toString(mPreviewSizes.get(i).width) + " x " +
223                     Integer.toString(mPreviewSizes.get(i).height);
224         }
225         mResolutionSpinner.setAdapter(
226             new ArrayAdapter<String>(
227                 this, R.layout.cf_format_list_item, availableSizeNames));
228 
229 
230         // Set initial values
231 	//
232         int initialSize = mPreviewSizes.size() - 1;
233 
234 	mNextPreviewSize = mPreviewSizes.get(initialSize);
235         mResolutionSpinner.setSelection(initialSize);
236 
237 	if(mPreviewTexture != null)
238 	{
239             startPreview();
240         }
241     }
242 
shutdownCamera()243     private void shutdownCamera() {
244         if (mCamera != null) {
245             mCamera.setPreviewCallbackWithBuffer(null);
246             mCamera.stopPreview();
247             mCamera.release();
248             mCamera = null;
249             mState = STATE_OFF;
250         }
251     }
252 
startPreview()253     private void startPreview() {
254         if (mState != STATE_OFF) {
255             // Stop for a while to drain callbacks
256             mCamera.setPreviewCallbackWithBuffer(null);
257             mCamera.stopPreview();
258             mState = STATE_OFF;
259             Handler h = new Handler();
260             Runnable mDelayedPreview = new Runnable() {
261                 public void run() {
262                     startPreview();
263                 }
264             };
265             h.postDelayed(mDelayedPreview, 300);
266             return;
267         }
268         mState = STATE_PREVIEW;
269 
270         Matrix transform = new Matrix();
271         float widthRatio = mNextPreviewSize.width / (float)mPreviewTexWidth;
272         float heightRatio = mNextPreviewSize.height / (float)mPreviewTexHeight;
273 
274         transform.setScale(1, heightRatio/widthRatio);
275         transform.postTranslate(0,
276                 mPreviewTexHeight * (1 - heightRatio/widthRatio)/2);
277 
278         mPreviewView.setTransform(transform);
279         mOutputView.setTransform(transform);
280 
281         mPreviewSize   = mNextPreviewSize;
282 
283         Camera.Parameters p = mCamera.getParameters();
284         p.setPreviewFormat(ImageFormat.NV21);
285         p.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
286         mCamera.setParameters(p);
287 
288         mCamera.setPreviewCallbackWithBuffer(this);
289         int expectedBytes = mPreviewSize.width * mPreviewSize.height *
290                 ImageFormat.getBitsPerPixel(ImageFormat.NV21) / 8;
291         for (int i=0; i < 4; i++) {
292             mCamera.addCallbackBuffer(new byte[expectedBytes]);
293         }
294         //mFormatView.setColorFilter(mYuv2RgbFilter);
295 
296         mProcessingFirstFrame = true;
297         try {
298             mCamera.setPreviewTexture(mPreviewTexture);
299             mCamera.startPreview();
300         } catch (IOException ioe) {
301             // Something bad happened
302             Log.e(TAG, "Unable to start up preview");
303         }
304 
305     }
306 
307 
308     private class ProcessPreviewDataTask extends AsyncTask<byte[], Void, Boolean> {
doInBackground(byte[]... datas)309         protected Boolean doInBackground(byte[]... datas) {
310             byte[] data = datas[0];
311 
312             long t1 = java.lang.System.currentTimeMillis();
313 
314             mFilterYuv.execute(data);
315 
316             long t2 = java.lang.System.currentTimeMillis();
317             mTiming[mTimingSlot++] = t2 - t1;
318             if (mTimingSlot >= mTiming.length) {
319                 float total = 0;
320                 for (int i=0; i<mTiming.length; i++) {
321                     total += (float)mTiming[i];
322                 }
323                 total /= mTiming.length;
324                 Log.e(TAG, "time + " + total);
325                 mTimingSlot = 0;
326             }
327 
328             mCamera.addCallbackBuffer(data);
329             mProcessInProgress = false;
330             return true;
331         }
332 
onPostExecute(Boolean result)333         protected void onPostExecute(Boolean result) {
334             mOutputView.invalidate();
335         }
336 
337     }
338 
339     private long mTiming[] = new long[50];
340     private int mTimingSlot = 0;
341 
onPreviewFrame(byte[] data, Camera camera)342     public void onPreviewFrame(byte[] data, Camera camera) {
343         if (mProcessInProgress || mState != STATE_PREVIEW) {
344             mCamera.addCallbackBuffer(data);
345             return;
346         }
347         if (data == null) {
348             return;
349         }
350 
351         int expectedBytes = mPreviewSize.width * mPreviewSize.height *
352                 ImageFormat.getBitsPerPixel(ImageFormat.NV21) / 8;
353 
354         if (expectedBytes != data.length) {
355             Log.e(TAG, "Mismatched size of buffer! Expected ");
356 
357             mState = STATE_NO_CALLBACKS;
358             mCamera.setPreviewCallbackWithBuffer(null);
359             return;
360         }
361 
362         mProcessInProgress = true;
363 
364         if ((mFilterYuv == null) ||
365             (mPreviewSize.width != mFilterYuv.getWidth()) ||
366             (mPreviewSize.height != mFilterYuv.getHeight()) ) {
367 
368             mFilterYuv.reset(mPreviewSize.width, mPreviewSize.height);
369         }
370 
371         mProcessInProgress = true;
372         new ProcessPreviewDataTask().execute(data);
373     }
374 
375 
376 
377 }
378