blob: 92e2fc3585fb6f42376100a50cf66a13ef25f3a1 [file] [log] [blame]
// Copyright 2010 Google Inc.
// All Rights Reserved.
package com.example.android.videochatcameratest;
import android.app.Activity;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.hardware.Camera.Size;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.FrameLayout;
import android.widget.TextView;
import java.io.IOException;
import java.lang.UnsupportedOperationException;
import java.util.ArrayList;
import java.util.List;
public class VideoChatTestActivity extends Activity {
static final private int NUM_CAMERA_PREVIEW_BUFFERS = 2;
static final boolean sRunningOnHoneycomb;
static final private String TAG = "VideoChatTest";
TextView mTextStatusHistory;
static {
sRunningOnHoneycomb =
android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB;
}
public VideoChatTestActivity() {
}
/** Called with the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Window window = getWindow();
window.setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// Inflate our UI from its XML layout description.
setContentView(R.layout.videochatcameratest_activity);
FrameLayout fl = (FrameLayout)findViewById(R.id.previewFrame);
if (sRunningOnHoneycomb) {
fl.addView(new SurfaceTextureView(this));
} else {
fl.addView(new CameraPreviewView(this));
}
((Button) findViewById(R.id.gobutton)).setOnClickListener(mGoListener);
((TextView)findViewById(R.id.statushistory)).setVerticalScrollBarEnabled(true);
mTextStatusHistory = (TextView) findViewById(R.id.statushistory);
logMessage("Display Orientation " + getDisplayOrientation());
for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
dumpCameraCaps(i);
}
}
private void logMessage(String message) {
Log.v(TAG, message);
mTextStatusHistory.append(message + "\r\n");
}
public int getCameraOrientation(int id) {
Camera.CameraInfo info =
new Camera.CameraInfo();
Camera.getCameraInfo(id, info);
return info.orientation;
}
private void dumpCameraCaps(int id) {
Camera cam = Camera.open(id);
Camera.Parameters params = cam.getParameters();
List<Integer> formats = params.getSupportedPreviewFormats();
List<int[]> frameRates = params.getSupportedPreviewFpsRange();
List<Camera.Size> sizes = params.getSupportedPreviewSizes();
logMessage("Camera " + id);
logMessage("Orientation " + getCameraOrientation(id));
logMessage("Sizes");
for (Size size : sizes) {
logMessage(size.width + "x" + size.height);
}
logMessage("frameRates");
for (int[] rates : frameRates) {
logMessage(rates[0] + "-" + rates[1]);
}
logMessage("formats");
for (Integer format : formats) {
logMessage(format.toString());
}
cam.release();
}
/**
* Called when the activity is about to start interacting with the user.
*/
@Override
protected void onResume() {
super.onResume();
}
private int getDisplayOrientation() {
int rotation = getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
return degrees;
}
/**
* A call-back for when the user presses the back button.
*/
OnClickListener mGoListener = new OnClickListener() {
@Override
public void onClick(View v) {
int degrees = getDisplayOrientation();
new CameraTestRunner().execute(new Integer[] { degrees });
}
};
private class CameraTestRunner extends AsyncTask<Integer, String, Void> {
TextView mTextStatus;
private int mDisplayOrientation;
private volatile boolean mClearStatusOnNextUpdate;
@Override
protected Void doInBackground(Integer... params) {
mDisplayOrientation = params[0];
mTextStatus = (TextView) findViewById(R.id.status);
boolean testFrontCamera =
((CheckBox) findViewById(R.id.frontcameracheckbox)).isChecked();
boolean testBackCamera = ((CheckBox) findViewById(R.id.backcameracheckbox)).isChecked();
boolean testQVGA = ((CheckBox) findViewById(R.id.qvgacheckbox)).isChecked();
boolean testVGA = ((CheckBox) findViewById(R.id.vgacheckbox)).isChecked();
boolean test15fps = ((CheckBox) findViewById(R.id.fps15checkbox)).isChecked();
boolean test30fps = ((CheckBox) findViewById(R.id.fps30checkbox)).isChecked();
boolean testRotate0 = ((CheckBox) findViewById(R.id.rotate0checkbox)).isChecked();
boolean testRotate90 = ((CheckBox) findViewById(R.id.rotate90checkbox)).isChecked();
boolean testRotate180 = ((CheckBox) findViewById(R.id.rotate180checkbox)).isChecked();
boolean testRotate270 = ((CheckBox) findViewById(R.id.rotate270checkbox)).isChecked();
boolean testRotateAuto = ((CheckBox) findViewById(R.id.rotateautocheckbox)).isChecked();
ArrayList<Integer> setDisplayOrentationAngles = new ArrayList<Integer>();
if (testRotate0) {
setDisplayOrentationAngles.add(0);
}
if (testRotate90) {
setDisplayOrentationAngles.add(90);
}
if (testRotate180) {
setDisplayOrentationAngles.add(180);
}
if (testRotate270) {
setDisplayOrentationAngles.add(270);
}
if (testRotateAuto) {
setDisplayOrentationAngles.add(-1);
}
final int widths[] = new int[] {320, 640};
final int heights[] = new int[] {240, 480};
final int framerates[] = new int[] {15, 30};
ArrayList<Integer> whichCameras = new ArrayList<Integer>();
int numCameras = Camera.getNumberOfCameras();
if (testFrontCamera) {
for (int i = 0; i < numCameras; i++) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(i, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
whichCameras.add(i);
break;
}
}
}
if (testBackCamera) {
for (int i = 0; i < numCameras; i++) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(i, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
whichCameras.add(i);
break;
}
}
}
do {
mClearStatusOnNextUpdate = true;
for (Integer whichCamera : whichCameras) {
for (int whichResolution = 0; whichResolution < 2; whichResolution++) {
if (whichResolution == 0 && !testQVGA) {
continue;
}
if (whichResolution == 1 && !testVGA) {
continue;
}
for (int whichFramerate = 0; whichFramerate < 2; whichFramerate++) {
if (whichFramerate == 0 && !test15fps) {
continue;
}
if (whichFramerate == 1 && !test30fps) {
continue;
}
TestCamera(whichCamera, widths[whichResolution],
heights[whichResolution], framerates[whichFramerate],
setDisplayOrentationAngles);
}
}
}
} while (((CheckBox) findViewById(R.id.repeatcheckbox)).isChecked());
// start tests
return null;
}
@Override
protected void onPostExecute(Void result) {
final String allDoneString = "Test complete";
Log.v(TAG, allDoneString);
mTextStatus.setText(allDoneString);
mTextStatusHistory.append(allDoneString + "\r\n");
}
private class FrameCatcher implements Camera.PreviewCallback {
public int mFrames = 0;
private final int mExpectedSize;
public FrameCatcher(int width, int height) {
mExpectedSize = width * height * 3 / 2;
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
if (mExpectedSize != data.length) {
throw new UnsupportedOperationException("bad size, got " + data.length + " expected " + mExpectedSize);
}
mFrames++;
camera.addCallbackBuffer(data);
}
}
private void setupCallback(Camera camera, FrameCatcher catcher, int bufferSize) {
camera.setPreviewCallbackWithBuffer(null);
camera.setPreviewCallbackWithBuffer(catcher);
for (int i = 0; i < NUM_CAMERA_PREVIEW_BUFFERS; i++) {
byte [] cameraBuffer = new byte[bufferSize];
camera.addCallbackBuffer(cameraBuffer);
}
}
private int getAutoDisplayOrientation(int displayOrientationDegrees,
int cameraId, android.hardware.Camera camera) {
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + displayOrientationDegrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - displayOrientationDegrees + 360) % 360;
}
return result;
}
protected void TestCamera(int whichCamera,
int width, int height,
int frameRate,
List<Integer> setDisplayOrentationAngles) {
String baseStatus = "Camera id " + whichCamera + " " +
width + "x" + height + " " +
frameRate + "fps";
publishProgress("Initializing " + baseStatus);
String status = "";
boolean succeeded = true;
Log.v(TAG, "Start test -- id " + whichCamera + " " + width + "x" + height +
" " + frameRate + "fps");
Camera camera;
FrameLayout previewBlock = (FrameLayout)findViewById(R.id.previewFrame);
SurfaceTextureView surfaceTextureView = null;
CameraPreviewView previewView = null;
if (sRunningOnHoneycomb) {
surfaceTextureView = (SurfaceTextureView)previewBlock.getChildAt(0);
} else {
previewView = (CameraPreviewView)previewBlock.getChildAt(0);
}
camera = Camera.open(whichCamera);
publishProgress("Opened " + baseStatus);
try {
try {
if (sRunningOnHoneycomb) {
camera.setPreviewTexture(surfaceTextureView.getSurfaceTexture());
} else {
camera.setPreviewDisplay(previewView.mHolder);
}
} catch (IOException exception) {
succeeded = false;
status = exception.toString();
return;
}
camera.setPreviewCallbackWithBuffer(null);
Camera.Parameters parameters = camera.getParameters();
publishProgress("Changing preview parameters " + width + "x" + height + baseStatus);
parameters.setPreviewSize(width, height);
parameters.setPreviewFormat(ImageFormat.NV21);
parameters.setPreviewFrameRate(frameRate);
camera.setParameters(parameters);
publishProgress("Validating preview parameters " + baseStatus);
parameters = camera.getParameters();
Size setSize = parameters.getPreviewSize();
if (setSize.width != width || setSize.height != height) {
status += "Bad reported size, wanted " + width + "x" + height + ", got " +
setSize.width + "x" + setSize.height;
succeeded = false;
}
if (parameters.getPreviewFrameRate() != frameRate) {
status += "Bad reported frame rate, wanted " + frameRate
+ ", got " + parameters.getPreviewFrameRate();
succeeded = false;
}
publishProgress("Initializing callback buffers " + baseStatus);
int imageFormat = parameters.getPreviewFormat();
if (imageFormat != ImageFormat.NV21) {
status = "Bad reported image format, wanted NV21 (" + ImageFormat.NV21 +
") got " + imageFormat;
succeeded = false;
throw new UnsupportedOperationException(status);
}
int bufferSize;
bufferSize = setSize.width * setSize.height
* ImageFormat.getBitsPerPixel(imageFormat) / 8;
int sizeWeShouldHave = (width * height * 3 / 2);
if (bufferSize != sizeWeShouldHave) {
status = "Bad calculate size. Should have been " + (width * height * 3 / 2) +
" but got " + imageFormat;
succeeded = false;
throw new UnsupportedOperationException(status);
}
FrameCatcher catcher = new FrameCatcher(setSize.width, setSize.height);
if (succeeded) {
publishProgress("Starting " + baseStatus);
} else {
publishProgress("Starting " + baseStatus + " -- but " + status);
}
int numPasses;
boolean doSetDisplayOrientation;
if (setDisplayOrentationAngles == null || setDisplayOrentationAngles.size() == 0) {
numPasses = 1;
doSetDisplayOrientation = false;
} else {
numPasses = setDisplayOrentationAngles.size();
doSetDisplayOrientation = true;
}
for (int i = 0; i < numPasses; i++) {
if (doSetDisplayOrientation) {
int rotation = setDisplayOrentationAngles.get(i);
if (rotation == -1) {
rotation = getAutoDisplayOrientation(mDisplayOrientation,
whichCamera, camera);
}
publishProgress("setDisplayOrientation to " + rotation);
try {
camera.setDisplayOrientation(rotation);
} catch (RuntimeException exception) {
succeeded = false;
status = exception.toString();
return;
}
}
if (sRunningOnHoneycomb) {
surfaceTextureView.resetFrameCounter();
surfaceTextureView.setCameraEnabled(true);
} else {
setupCallback(camera, catcher, bufferSize);
}
camera.startPreview();
try {
Thread.sleep(5000);
} catch (InterruptedException exception) {
succeeded = false;
status = exception.toString();
return;
}
if (sRunningOnHoneycomb) {
surfaceTextureView.setCameraEnabled(false);
} else {
camera.setPreviewCallbackWithBuffer(null);
}
camera.stopPreview();
}
int frames;
if (sRunningOnHoneycomb) {
frames = surfaceTextureView.getFrameCounter();
} else {
frames = catcher.mFrames;
}
if (frames == 0) {
succeeded = false;
publishProgress("Preview callback received no frames from " + baseStatus);
} else {
publishProgress("Preview callback got " + frames + " frames (~" +
Math.round(((double)frames)/(5.0 * numPasses)) + "fps) " +
baseStatus);
}
try {
camera.setPreviewDisplay(null);
} catch (IOException exception) {
succeeded = false;
status = exception.toString();
return;
}
} finally {
Log.v(TAG, "Releasing camera");
if (succeeded) {
publishProgress("Success " + baseStatus);
} else {
publishProgress("Finished " + baseStatus + " -- but " + status);
}
camera.release();
}
}
@Override
protected void onProgressUpdate(String... message) {
if (mClearStatusOnNextUpdate) {
mClearStatusOnNextUpdate = false;
mTextStatusHistory.setText("");
}
Log.v(TAG, message[0]);
mTextStatus.setText(message[0]);
mTextStatusHistory.append(message[0] + "\r\n");
}
}
}