Home | History | Annotate | Download | only in videochatcameratest
      1 // Copyright 2010 Google Inc.
      2 // All Rights Reserved.
      3 
      4 package com.example.android.videochatcameratest;
      5 
      6 import android.app.Activity;
      7 import android.graphics.ImageFormat;
      8 import android.hardware.Camera;
      9 import android.hardware.Camera.Size;
     10 import android.os.AsyncTask;
     11 import android.os.Bundle;
     12 import android.util.Log;
     13 import android.view.Surface;
     14 import android.view.TextureView;
     15 import android.view.View;
     16 import android.view.View.OnClickListener;
     17 import android.view.Window;
     18 import android.view.WindowManager;
     19 import android.widget.Button;
     20 import android.widget.CheckBox;
     21 import android.widget.FrameLayout;
     22 import android.widget.TextView;
     23 
     24 import java.io.IOException;
     25 import java.lang.UnsupportedOperationException;
     26 import java.util.ArrayList;
     27 import java.util.List;
     28 
     29 public class VideoChatTestActivity extends Activity {
     30 
     31     static final private int NUM_CAMERA_PREVIEW_BUFFERS = 2;
     32     static final boolean sRunningOnHoneycomb;
     33     static final private String TAG = "VideoChatTest";
     34     TextView mTextStatusHistory;
     35     static {
     36         sRunningOnHoneycomb =
     37                 android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB;
     38     }
     39 
     40     public VideoChatTestActivity() {
     41     }
     42 
     43     /** Called with the activity is first created. */
     44     @Override
     45     public void onCreate(Bundle savedInstanceState) {
     46         super.onCreate(savedInstanceState);
     47 
     48         Window window = getWindow();
     49         window.setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
     50                 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
     51 
     52         // Inflate our UI from its XML layout description.
     53         setContentView(R.layout.videochatcameratest_activity);
     54 
     55         FrameLayout fl = (FrameLayout)findViewById(R.id.previewFrame);
     56 
     57         if (sRunningOnHoneycomb) {
     58             fl.addView(new SurfaceTextureView(this));
     59         } else {
     60             fl.addView(new CameraPreviewView(this));
     61         }
     62 
     63         ((Button) findViewById(R.id.gobutton)).setOnClickListener(mGoListener);
     64 
     65         ((TextView)findViewById(R.id.statushistory)).setVerticalScrollBarEnabled(true);
     66         mTextStatusHistory = (TextView) findViewById(R.id.statushistory);
     67 
     68         logMessage("Display Orientation " + getDisplayOrientation());
     69         for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
     70             dumpCameraCaps(i);
     71         }
     72     }
     73 
     74     private void logMessage(String message) {
     75         Log.v(TAG, message);
     76         mTextStatusHistory.append(message + "\r\n");
     77     }
     78 
     79     public int getCameraOrientation(int id) {
     80         Camera.CameraInfo info =
     81             new Camera.CameraInfo();
     82         Camera.getCameraInfo(id, info);
     83         return info.orientation;
     84     }
     85 
     86     private void dumpCameraCaps(int id) {
     87         Camera cam = Camera.open(id);
     88         Camera.Parameters params = cam.getParameters();
     89         List<Integer> formats = params.getSupportedPreviewFormats();
     90         List<int[]> frameRates = params.getSupportedPreviewFpsRange();
     91         List<Camera.Size> sizes = params.getSupportedPreviewSizes();
     92         logMessage("Camera " + id);
     93         logMessage("Orientation " + getCameraOrientation(id));
     94         logMessage("Sizes");
     95         for (Size size : sizes) {
     96             logMessage(size.width + "x" + size.height);
     97         }
     98         logMessage("frameRates");
     99         for (int[] rates : frameRates) {
    100             logMessage(rates[0] + "-" + rates[1]);
    101         }
    102         logMessage("formats");
    103         for (Integer format : formats) {
    104             logMessage(format.toString());
    105         }
    106         cam.release();
    107     }
    108     /**
    109      * Called when the activity is about to start interacting with the user.
    110      */
    111     @Override
    112     protected void onResume() {
    113         super.onResume();
    114     }
    115 
    116     private int getDisplayOrientation() {
    117         int rotation = getWindowManager().getDefaultDisplay().getRotation();
    118         int degrees = 0;
    119         switch (rotation) {
    120             case Surface.ROTATION_0:
    121                 degrees = 0;
    122                 break;
    123             case Surface.ROTATION_90:
    124                 degrees = 90;
    125                 break;
    126             case Surface.ROTATION_180:
    127                 degrees = 180;
    128                 break;
    129             case Surface.ROTATION_270:
    130                 degrees = 270;
    131                 break;
    132         }
    133         return degrees;
    134     }
    135 
    136     /**
    137      * A call-back for when the user presses the back button.
    138      */
    139     OnClickListener mGoListener = new OnClickListener() {
    140         @Override
    141         public void onClick(View v) {
    142             int degrees = getDisplayOrientation();
    143             new CameraTestRunner().execute(new Integer[] { degrees });
    144         }
    145     };
    146 
    147     private class CameraTestRunner extends AsyncTask<Integer, String, Void> {
    148 
    149         TextView mTextStatus;
    150         private int mDisplayOrientation;
    151         private volatile boolean mClearStatusOnNextUpdate;
    152 
    153         @Override
    154         protected Void doInBackground(Integer... params) {
    155             mDisplayOrientation = params[0];
    156             mTextStatus = (TextView) findViewById(R.id.status);
    157             boolean testFrontCamera =
    158                     ((CheckBox) findViewById(R.id.frontcameracheckbox)).isChecked();
    159             boolean testBackCamera = ((CheckBox) findViewById(R.id.backcameracheckbox)).isChecked();
    160             boolean testQVGA = ((CheckBox) findViewById(R.id.qvgacheckbox)).isChecked();
    161             boolean testVGA = ((CheckBox) findViewById(R.id.vgacheckbox)).isChecked();
    162             boolean test15fps = ((CheckBox) findViewById(R.id.fps15checkbox)).isChecked();
    163             boolean test30fps = ((CheckBox) findViewById(R.id.fps30checkbox)).isChecked();
    164             boolean testRotate0 = ((CheckBox) findViewById(R.id.rotate0checkbox)).isChecked();
    165             boolean testRotate90 = ((CheckBox) findViewById(R.id.rotate90checkbox)).isChecked();
    166             boolean testRotate180 = ((CheckBox) findViewById(R.id.rotate180checkbox)).isChecked();
    167             boolean testRotate270 = ((CheckBox) findViewById(R.id.rotate270checkbox)).isChecked();
    168             boolean testRotateAuto = ((CheckBox) findViewById(R.id.rotateautocheckbox)).isChecked();
    169 
    170             ArrayList<Integer> setDisplayOrentationAngles = new ArrayList<Integer>();
    171 
    172             if (testRotate0) {
    173                 setDisplayOrentationAngles.add(0);
    174             }
    175             if (testRotate90) {
    176                 setDisplayOrentationAngles.add(90);
    177             }
    178             if (testRotate180) {
    179                 setDisplayOrentationAngles.add(180);
    180             }
    181             if (testRotate270) {
    182                 setDisplayOrentationAngles.add(270);
    183             }
    184             if (testRotateAuto) {
    185                 setDisplayOrentationAngles.add(-1);
    186             }
    187 
    188             final int widths[] = new int[] {320, 640};
    189             final int heights[] = new int[] {240, 480};
    190 
    191             final int framerates[] = new int[] {15, 30};
    192 
    193             ArrayList<Integer> whichCameras = new ArrayList<Integer>();
    194             int numCameras = Camera.getNumberOfCameras();
    195             if (testFrontCamera) {
    196                 for (int i = 0; i < numCameras; i++) {
    197                     Camera.CameraInfo info = new Camera.CameraInfo();
    198                     Camera.getCameraInfo(i, info);
    199                     if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
    200                         whichCameras.add(i);
    201                         break;
    202                     }
    203                 }
    204             }
    205             if (testBackCamera) {
    206                 for (int i = 0; i < numCameras; i++) {
    207                     Camera.CameraInfo info = new Camera.CameraInfo();
    208                     Camera.getCameraInfo(i, info);
    209                     if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
    210                         whichCameras.add(i);
    211                         break;
    212                     }
    213                 }
    214             }
    215             do {
    216                 mClearStatusOnNextUpdate = true;
    217                 for (Integer whichCamera : whichCameras) {
    218                     for (int whichResolution = 0; whichResolution < 2; whichResolution++) {
    219                         if (whichResolution == 0 && !testQVGA) {
    220                             continue;
    221                         }
    222                         if (whichResolution == 1 && !testVGA) {
    223                             continue;
    224                         }
    225 
    226                         for (int whichFramerate = 0; whichFramerate < 2; whichFramerate++) {
    227                             if (whichFramerate == 0 && !test15fps) {
    228                                 continue;
    229                             }
    230                             if (whichFramerate == 1 && !test30fps) {
    231                                 continue;
    232                             }
    233 
    234                             TestCamera(whichCamera, widths[whichResolution],
    235                                     heights[whichResolution], framerates[whichFramerate],
    236                                     setDisplayOrentationAngles);
    237                         }
    238                     }
    239                 }
    240             } while (((CheckBox) findViewById(R.id.repeatcheckbox)).isChecked());
    241             // start tests
    242 
    243             return null;
    244         }
    245 
    246         @Override
    247         protected void onPostExecute(Void result) {
    248             final String allDoneString = "Test complete";
    249             Log.v(TAG, allDoneString);
    250             mTextStatus.setText(allDoneString);
    251             mTextStatusHistory.append(allDoneString + "\r\n");
    252         }
    253 
    254 
    255         private class FrameCatcher implements Camera.PreviewCallback {
    256             public int mFrames = 0;
    257             private final int mExpectedSize;
    258             public FrameCatcher(int width, int height) {
    259                 mExpectedSize = width * height * 3 / 2;
    260             }
    261 
    262             @Override
    263             public void onPreviewFrame(byte[] data, Camera camera) {
    264                 if (mExpectedSize != data.length) {
    265                     throw new UnsupportedOperationException("bad size, got " + data.length + " expected " + mExpectedSize);
    266                 }
    267                 mFrames++;
    268                 camera.addCallbackBuffer(data);
    269             }
    270 
    271         }
    272 
    273         private void setupCallback(Camera camera, FrameCatcher catcher, int bufferSize) {
    274             camera.setPreviewCallbackWithBuffer(null);
    275             camera.setPreviewCallbackWithBuffer(catcher);
    276             for (int i = 0; i < NUM_CAMERA_PREVIEW_BUFFERS; i++) {
    277                 byte [] cameraBuffer = new byte[bufferSize];
    278                 camera.addCallbackBuffer(cameraBuffer);
    279             }
    280         }
    281 
    282         private int getAutoDisplayOrientation(int displayOrientationDegrees,
    283                 int cameraId, android.hardware.Camera camera) {
    284             android.hardware.Camera.CameraInfo info =
    285                     new android.hardware.Camera.CameraInfo();
    286             android.hardware.Camera.getCameraInfo(cameraId, info);
    287 
    288             int result;
    289             if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
    290                 result = (info.orientation + displayOrientationDegrees) % 360;
    291                 result = (360 - result) % 360; // compensate the mirror
    292             } else { // back-facing
    293                 result = (info.orientation - displayOrientationDegrees + 360) % 360;
    294             }
    295             return result;
    296         }
    297 
    298         protected void TestCamera(int whichCamera,
    299                 int width, int height,
    300                 int frameRate,
    301                 List<Integer> setDisplayOrentationAngles) {
    302             String baseStatus = "Camera id " + whichCamera + " " +
    303                 width + "x" + height + " " +
    304                 frameRate + "fps";
    305             publishProgress("Initializing " + baseStatus);
    306             String status = "";
    307             boolean succeeded = true;
    308             Log.v(TAG, "Start test -- id " + whichCamera + " " + width + "x" + height +
    309                     " " + frameRate + "fps");
    310             Camera camera;
    311             FrameLayout previewBlock = (FrameLayout)findViewById(R.id.previewFrame);
    312             SurfaceTextureView surfaceTextureView = null;
    313             CameraPreviewView previewView = null;
    314             if (sRunningOnHoneycomb) {
    315                 surfaceTextureView = (SurfaceTextureView)previewBlock.getChildAt(0);
    316             } else {
    317                 previewView = (CameraPreviewView)previewBlock.getChildAt(0);
    318             }
    319 
    320             camera = Camera.open(whichCamera);
    321             publishProgress("Opened " + baseStatus);
    322             try {
    323                 try {
    324                     if (sRunningOnHoneycomb) {
    325                         camera.setPreviewTexture(surfaceTextureView.getSurfaceTexture());
    326                     } else {
    327                         camera.setPreviewDisplay(previewView.mHolder);
    328                     }
    329                 } catch (IOException exception) {
    330                     succeeded = false;
    331                     status = exception.toString();
    332                     return;
    333                 }
    334 
    335                 camera.setPreviewCallbackWithBuffer(null);
    336                 Camera.Parameters parameters = camera.getParameters();
    337 
    338                 publishProgress("Changing preview parameters " + width + "x" + height + baseStatus);
    339 
    340                 parameters.setPreviewSize(width, height);
    341                 parameters.setPreviewFormat(ImageFormat.NV21);
    342 
    343                 parameters.setPreviewFrameRate(frameRate);
    344                 camera.setParameters(parameters);
    345 
    346                 publishProgress("Validating preview parameters " + baseStatus);
    347 
    348                 parameters = camera.getParameters();
    349                 Size setSize = parameters.getPreviewSize();
    350                 if (setSize.width != width || setSize.height != height) {
    351                     status += "Bad reported size, wanted " + width + "x" + height + ", got " +
    352                     setSize.width + "x" + setSize.height;
    353                     succeeded = false;
    354                 }
    355 
    356                 if (parameters.getPreviewFrameRate() != frameRate) {
    357                     status += "Bad reported frame rate, wanted " + frameRate
    358                     + ", got " + parameters.getPreviewFrameRate();
    359                     succeeded = false;
    360                 }
    361 
    362                 publishProgress("Initializing callback buffers " + baseStatus);
    363                 int imageFormat = parameters.getPreviewFormat();
    364                 if (imageFormat != ImageFormat.NV21) {
    365                     status = "Bad reported image format, wanted NV21 (" + ImageFormat.NV21 +
    366                             ") got " + imageFormat;
    367                     succeeded = false;
    368                     throw new UnsupportedOperationException(status);
    369                 }
    370                 int bufferSize;
    371                 bufferSize = setSize.width * setSize.height
    372                                 * ImageFormat.getBitsPerPixel(imageFormat) / 8;
    373                 int sizeWeShouldHave = (width * height * 3 / 2);
    374                 if (bufferSize != sizeWeShouldHave) {
    375                     status = "Bad calculate size. Should have been " + (width * height * 3 / 2) +
    376                             " but got " + imageFormat;
    377                     succeeded = false;
    378                     throw new UnsupportedOperationException(status);
    379                 }
    380 
    381                 FrameCatcher catcher = new FrameCatcher(setSize.width, setSize.height);
    382 
    383                 if (succeeded) {
    384                     publishProgress("Starting " + baseStatus);
    385                 } else {
    386                     publishProgress("Starting " + baseStatus + " -- but " + status);
    387                 }
    388 
    389                 int numPasses;
    390                 boolean doSetDisplayOrientation;
    391                 if (setDisplayOrentationAngles == null || setDisplayOrentationAngles.size() == 0) {
    392                     numPasses = 1;
    393                     doSetDisplayOrientation = false;
    394                 } else {
    395                     numPasses = setDisplayOrentationAngles.size();
    396                     doSetDisplayOrientation = true;
    397                 }
    398 
    399                 for (int i = 0; i < numPasses; i++) {
    400                     if (doSetDisplayOrientation) {
    401                         int rotation = setDisplayOrentationAngles.get(i);
    402                         if (rotation == -1) {
    403                             rotation = getAutoDisplayOrientation(mDisplayOrientation,
    404                                     whichCamera, camera);
    405                         }
    406                         publishProgress("setDisplayOrientation to " + rotation);
    407                         try {
    408                             camera.setDisplayOrientation(rotation);
    409                         } catch (RuntimeException exception) {
    410                             succeeded = false;
    411                             status = exception.toString();
    412                             return;
    413                         }
    414                     }
    415                     if (sRunningOnHoneycomb) {
    416                         surfaceTextureView.resetFrameCounter();
    417                         surfaceTextureView.setCameraEnabled(true);
    418                     } else {
    419                         setupCallback(camera, catcher, bufferSize);
    420                     }
    421                     camera.startPreview();
    422                     try {
    423                         Thread.sleep(5000);
    424                     } catch (InterruptedException exception) {
    425                         succeeded = false;
    426                         status = exception.toString();
    427                         return;
    428                     }
    429                     if (sRunningOnHoneycomb) {
    430                         surfaceTextureView.setCameraEnabled(false);
    431                     } else {
    432                         camera.setPreviewCallbackWithBuffer(null);
    433                     }
    434                     camera.stopPreview();
    435                 }
    436 
    437                 int frames;
    438                 if (sRunningOnHoneycomb) {
    439                     frames = surfaceTextureView.getFrameCounter();
    440                 } else {
    441                     frames = catcher.mFrames;
    442                 }
    443                 if (frames == 0) {
    444                     succeeded = false;
    445                     publishProgress("Preview callback received no frames from " + baseStatus);
    446                 } else {
    447                     publishProgress("Preview callback got " + frames + " frames (~" +
    448                             Math.round(((double)frames)/(5.0 * numPasses)) + "fps) " +
    449                             baseStatus);
    450                 }
    451                 try {
    452                     camera.setPreviewDisplay(null);
    453                 } catch (IOException exception) {
    454                     succeeded = false;
    455                     status = exception.toString();
    456                     return;
    457                 }
    458             } finally {
    459                 Log.v(TAG, "Releasing camera");
    460 
    461                 if (succeeded) {
    462                     publishProgress("Success " + baseStatus);
    463                 } else {
    464                     publishProgress("Finished " + baseStatus + " -- but " + status);
    465                 }
    466 
    467                 camera.release();
    468             }
    469         }
    470 
    471         @Override
    472         protected void onProgressUpdate(String... message) {
    473             if (mClearStatusOnNextUpdate) {
    474                 mClearStatusOnNextUpdate = false;
    475                 mTextStatusHistory.setText("");
    476             }
    477             Log.v(TAG, message[0]);
    478             mTextStatus.setText(message[0]);
    479             mTextStatusHistory.append(message[0] + "\r\n");
    480         }
    481     }
    482 }
    483