VideoChatTestActivity.java revision 202e88cbb3a52a78d6c4ccf55fa9ed9248f43ecd
1/* 2 * Copyright (C) 2010 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 17package com.example.android.videochatcameratest; 18 19import android.app.Activity; 20import android.graphics.ImageFormat; 21import android.hardware.Camera; 22import android.hardware.Camera.Size; 23import android.os.AsyncTask; 24import android.os.Bundle; 25import android.util.Log; 26import android.view.View; 27import android.view.View.OnClickListener; 28import android.widget.Button; 29import android.widget.CheckBox; 30import android.widget.TextView; 31 32import java.io.IOException; 33import java.lang.UnsupportedOperationException; 34import java.util.ArrayList; 35import java.util.List; 36 37/** 38 * This class provides a basic demonstration of how to write an Android 39 * activity. Inside of its window, it places a single view: an EditText that 40 * displays and edits some internal text. 41 */ 42public class VideoChatTestActivity extends Activity { 43 44 static final private int NUM_CAMERA_PREVIEW_BUFFERS = 2; 45 46 static final private String TAG = "VideoChatTest"; 47 TextView mTextStatusHistory; 48 public VideoChatTestActivity() { 49 } 50 51 /** Called with the activity is first created. */ 52 @Override 53 public void onCreate(Bundle savedInstanceState) { 54 super.onCreate(savedInstanceState); 55 56 // Inflate our UI from its XML layout description. 57 setContentView(R.layout.videochatcameratest_activity); 58 59 ((Button) findViewById(R.id.gobutton)).setOnClickListener(mGoListener); 60 61 ((TextView)findViewById(R.id.statushistory)).setVerticalScrollBarEnabled(true); 62 mTextStatusHistory = (TextView) findViewById(R.id.statushistory); 63 64 for (int i = 0; i < Camera.getNumberOfCameras(); i++) { 65 dumpCameraCaps(i); 66 } 67 } 68 69 private void logMessage(String message) { 70 Log.v(TAG, message); 71 mTextStatusHistory.append(message + "\r\n"); 72 } 73 74 public int getCameraOrientation(int id) { 75 Camera.CameraInfo info = 76 new Camera.CameraInfo(); 77 Camera.getCameraInfo(id, info); 78 return info.orientation; 79 } 80 81 private void dumpCameraCaps(int id) { 82 Camera cam = Camera.open(id); 83 Camera.Parameters params = cam.getParameters(); 84 List<Integer> formats = params.getSupportedPreviewFormats(); 85 List<int[]> frameRates = params.getSupportedPreviewFpsRange(); 86 List<Camera.Size> sizes = params.getSupportedPreviewSizes(); 87 logMessage("Camera " + id); 88 logMessage("Orientation " + getCameraOrientation(id)); 89 logMessage("Sizes"); 90 for (Size size : sizes) { 91 logMessage(size.width + "x" + size.height); 92 } 93 logMessage("frameRates"); 94 for (int[] rates : frameRates) { 95 logMessage(rates[0] + "-" + rates[1]); 96 } 97 logMessage("formats"); 98 for (Integer format : formats) { 99 logMessage(format.toString()); 100 } 101 cam.release(); 102 } 103 /** 104 * Called when the activity is about to start interacting with the user. 105 */ 106 @Override 107 protected void onResume() { 108 super.onResume(); 109 } 110 111 /** 112 * A call-back for when the user presses the back button. 113 */ 114 OnClickListener mGoListener = new OnClickListener() { 115 116 public void onClick(View v) { 117 new CameraTestRunner().execute(); 118 } 119 }; 120 121 private class CameraTestRunner extends AsyncTask<Void, String, Void> { 122 123 TextView mTextStatus; 124 TextView mTextStatusHistory; 125 126 @Override 127 protected Void doInBackground(Void... params) { 128 mTextStatus = (TextView) findViewById(R.id.status); 129 mTextStatusHistory = (TextView) findViewById(R.id.statushistory); 130 boolean testFrontCamera = 131 ((CheckBox) findViewById(R.id.frontcameracheckbox)).isChecked(); 132 boolean testBackCamera = ((CheckBox) findViewById(R.id.backcameracheckbox)).isChecked(); 133 boolean testQVGA = ((CheckBox) findViewById(R.id.qvgacheckbox)).isChecked(); 134 boolean testVGA = ((CheckBox) findViewById(R.id.vgacheckbox)).isChecked(); 135 boolean test15fps = ((CheckBox) findViewById(R.id.fps15checkbox)).isChecked(); 136 boolean test30fps = ((CheckBox) findViewById(R.id.fps30checkbox)).isChecked(); 137 boolean testRotate0 = ((CheckBox) findViewById(R.id.rotate0checkbox)).isChecked(); 138 boolean testRotate90 = ((CheckBox) findViewById(R.id.rotate90checkbox)).isChecked(); 139 boolean testRotate180 = ((CheckBox) findViewById(R.id.rotate180checkbox)).isChecked(); 140 boolean testRotate270 = ((CheckBox) findViewById(R.id.rotate270checkbox)).isChecked(); 141 142 ArrayList<Integer> setDisplayOrentationAngles = new ArrayList<Integer>(); 143 144 if (testRotate0) { 145 setDisplayOrentationAngles.add(0); 146 } 147 if (testRotate90) { 148 setDisplayOrentationAngles.add(90); 149 } 150 if (testRotate180) { 151 setDisplayOrentationAngles.add(180); 152 } 153 if (testRotate270) { 154 setDisplayOrentationAngles.add(270); 155 } 156 157 final int widths[] = new int[] {320, 640}; 158 final int heights[] = new int[] {240, 480}; 159 160 final int framerates[] = new int[] {15, 30}; 161 162 do { 163 for (int whichCamera = 0; whichCamera < 2; whichCamera++) { 164 if (whichCamera == 0 && !testBackCamera) { 165 continue; 166 } 167 168 169 if (whichCamera == 1 && !testFrontCamera) { 170 continue; 171 } 172 173 for (int whichResolution = 0; whichResolution < 2; whichResolution++) { 174 if (whichResolution == 0 && !testQVGA) { 175 continue; 176 } 177 if (whichResolution == 1 && !testVGA) { 178 continue; 179 } 180 181 for (int whichFramerate = 0; whichFramerate < 2; whichFramerate++) { 182 if (whichFramerate == 0 && !test15fps) { 183 continue; 184 } 185 if (whichFramerate == 1 && !test30fps) { 186 continue; 187 } 188 189 TestCamera(whichCamera, widths[whichResolution], 190 heights[whichResolution], framerates[whichFramerate], 191 setDisplayOrentationAngles); 192 } 193 } 194 } 195 } while (((CheckBox) findViewById(R.id.repeatcheckbox)).isChecked()); 196 // start tests 197 198 return null; 199 } 200 201 @Override 202 protected void onPostExecute(Void result) { 203 final String allDoneString = "Test complete"; 204 Log.v(TAG, allDoneString); 205 mTextStatus.setText(allDoneString); 206 mTextStatusHistory.append(allDoneString + "\r\n"); 207 } 208 209 210 private class FrameCatcher implements Camera.PreviewCallback { 211 public int mFrames = 0; 212 private final int mExpectedSize; 213 public FrameCatcher(int width, int height) { 214 mExpectedSize = width * height * 3 / 2; 215 } 216 217 @Override 218 public void onPreviewFrame(byte[] data, Camera camera) { 219 if (mExpectedSize != data.length) { 220 throw new UnsupportedOperationException("bad size, got " + data.length + " expected " + mExpectedSize); 221 } 222 mFrames++; 223 camera.addCallbackBuffer(data); 224 } 225 226 } 227 228 private void setupCallback(Camera camera, FrameCatcher catcher, int bufferSize) { 229 camera.setPreviewCallbackWithBuffer(null); 230 camera.setPreviewCallbackWithBuffer(catcher); 231 for (int i = 0; i < NUM_CAMERA_PREVIEW_BUFFERS; i++) { 232 byte [] cameraBuffer = new byte[bufferSize]; 233 camera.addCallbackBuffer(cameraBuffer); 234 } 235 } 236 protected void TestCamera(int whichCamera, 237 int width, int height, 238 int frameRate, 239 List<Integer> setDisplayOrentationAngles) { 240 String baseStatus = "Camera id " + whichCamera + " " + 241 width + "x" + height + " " + 242 frameRate + "fps"; 243 publishProgress("Initializing " + baseStatus); 244 String status = ""; 245 boolean succeeded = true; 246 Log.v(TAG, "Start test -- id " + whichCamera + " " + width + "x" + height + 247 " " + frameRate + "fps"); 248 Camera camera; 249 CameraPreviewView previewView = (CameraPreviewView)findViewById(R.id.previewrender); 250 251 camera = Camera.open(whichCamera); 252 publishProgress("Opened " + baseStatus); 253 try { 254 try { 255 camera.setPreviewDisplay(previewView.mHolder); 256 } catch (IOException exception) { 257 succeeded = false; 258 status = exception.toString(); 259 return; 260 } 261 camera.startPreview(); 262 263 camera.setPreviewCallbackWithBuffer(null); 264 Camera.Parameters parameters = camera.getParameters(); 265 266 publishProgress("Changing preview parameters " + width + "x" + height + baseStatus); 267 268 parameters.setPreviewSize(width, height); 269 parameters.setPreviewFormat(ImageFormat.NV21); 270 271 parameters.setPreviewFrameRate(frameRate); 272 camera.stopPreview(); 273 camera.setParameters(parameters); 274 camera.startPreview(); 275 276 publishProgress("Validating preview parameters " + baseStatus); 277 278 parameters = camera.getParameters(); 279 Size setSize = parameters.getPreviewSize(); 280 if (setSize.width != width || setSize.height != height) { 281 status += "Bad reported size, wanted " + width + "x" + height + ", got " + 282 setSize.width + "x" + setSize.height; 283 succeeded = false; 284 } 285 286 if (parameters.getPreviewFrameRate() != frameRate) { 287 status += "Bad reported frame rate, wanted " + frameRate 288 + ", got " + parameters.getPreviewFrameRate(); 289 succeeded = false; 290 } 291 292 publishProgress("Initializing callback buffers " + baseStatus); 293 int imageFormat = parameters.getPreviewFormat(); 294 if (imageFormat != ImageFormat.NV21) { 295 status = "Bad reported image format, wanted NV21 (" + ImageFormat.NV21 + 296 ") got " + imageFormat; 297 succeeded = false; 298 throw new UnsupportedOperationException(status); 299 } 300 int bufferSize; 301 bufferSize = setSize.width * setSize.height 302 * ImageFormat.getBitsPerPixel(imageFormat) / 8; 303 int sizeWeShouldHave = (width * height * 3 / 2); 304 if (bufferSize != sizeWeShouldHave) { 305 status = "Bad calculate size. Should have been " + (width * height * 3 / 2) + 306 " but got " + imageFormat; 307 succeeded = false; 308 throw new UnsupportedOperationException(status); 309 } 310 camera.stopPreview(); 311 312 FrameCatcher catcher = new FrameCatcher(setSize.width, setSize.height); 313 314 if (succeeded) { 315 publishProgress("Starting " + baseStatus); 316 } else { 317 publishProgress("Starting " + baseStatus + " -- but " + status); 318 } 319 320 int numPasses; 321 boolean doSetDisplayOrientation; 322 if (setDisplayOrentationAngles == null || setDisplayOrentationAngles.size() == 0) { 323 numPasses = 1; 324 doSetDisplayOrientation = false; 325 } else { 326 numPasses = setDisplayOrentationAngles.size(); 327 doSetDisplayOrientation = true; 328 } 329 330 for (int i = 0; i < numPasses; i++) { 331 if (doSetDisplayOrientation) { 332 int rotation = setDisplayOrentationAngles.get(i); 333 publishProgress("setDisplayOrientation to " + rotation); 334 try { 335 camera.setDisplayOrientation(rotation); 336 } catch (RuntimeException exception) { 337 succeeded = false; 338 status = exception.toString(); 339 return; 340 } 341 } 342 setupCallback(camera, catcher, bufferSize); 343 camera.startPreview(); 344 try { 345 Thread.sleep(5000); 346 } catch (InterruptedException exception) { 347 succeeded = false; 348 status = exception.toString(); 349 return; 350 } 351 camera.setPreviewCallbackWithBuffer(null); 352 camera.stopPreview(); 353 } 354 355 if (catcher.mFrames == 0) { 356 succeeded = false; 357 publishProgress("Preview callback received no frames from " + baseStatus); 358 } else { 359 publishProgress("Preview callback got " + catcher.mFrames + " frames (~" + 360 Math.round(((double)catcher.mFrames)/(5.0 * numPasses)) + "fps) " + 361 baseStatus); 362 } 363 try { 364 camera.setPreviewDisplay(null); 365 } catch (IOException exception) { 366 succeeded = false; 367 status = exception.toString(); 368 return; 369 } 370 } finally { 371 Log.v(TAG, "Releasing camera"); 372 373 if (succeeded) { 374 publishProgress("Success " + baseStatus); 375 } else { 376 publishProgress("Finished " + baseStatus + " -- but " + status); 377 } 378 379 camera.release(); 380 } 381 } 382 383 @Override 384 protected void onProgressUpdate(String... message) { 385 Log.v(TAG, message[0]); 386 mTextStatus.setText(message[0]); 387 mTextStatusHistory.append(message[0] + "\r\n"); 388 } 389 } 390} 391