Bug fix and refactor video capture code on android

BUG=
TEST=test on android
Review URL: https://webrtc-codereview.appspot.com/541009

git-svn-id: http://webrtc.googlecode.com/svn/trunk@2173 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
leozwang@webrtc.org 2012-05-04 17:06:32 +00:00
parent b6f2417f37
commit e62fec2285
2 changed files with 104 additions and 104 deletions

View File

@ -19,6 +19,8 @@ import org.webrtc.videoengine.VideoCaptureDeviceInfoAndroid.AndroidVideoCaptureD
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.util.Log;
@ -33,7 +35,10 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
private int PIXEL_FORMAT = ImageFormat.NV21;
PixelFormat pixelFormat = new PixelFormat();
// True when the C++ layer has ordered the camera to be started.
private boolean isRunning=false;
private boolean isCaptureStarted = false;
private boolean isCaptureRunning = false;
private boolean isSurfaceReady = false;
private SurfaceHolder surfaceHolder = null;
private final int numCaptureBuffers = 3;
private int expectedFrameSize = 0;
@ -45,8 +50,9 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
// True if this class owns the preview video buffers.
private boolean ownsBuffers = false;
// Set this to 2 for VERBOSE logging. 1 for DEBUG
private static int LOGLEVEL = 0;
// Set this to 4 for DEBUG logging. 2 for DEBUG
private final static String TAG = "WEBRTC";
private static int LOGLEVEL = 2;
private static boolean VERBOSE = LOGLEVEL > 2;
private static boolean DEBUG = LOGLEVEL > 1;
@ -54,15 +60,14 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
public static
void DeleteVideoCaptureAndroid(VideoCaptureAndroid captureAndroid) {
if(DEBUG) Log.d("*WEBRTC*", "DeleteVideoCaptureAndroid");
if(DEBUG) Log.d(TAG, "DeleteVideoCaptureAndroid");
captureAndroid.StopCapture();
captureAndroid.camera.release();
captureAndroid.camera = null;
captureAndroid.context = 0;
if(DEBUG) Log.v("*WEBRTC*", "DeleteVideoCaptureAndroid ended");
if(DEBUG) Log.v(TAG, "DeleteVideoCaptureAndroid ended");
}
public VideoCaptureAndroid(int in_id,
@ -75,13 +80,13 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
currentDevice = in_device;
}
public int StartCapture(int width, int height, int frameRate) {
if(DEBUG) Log.d("*WEBRTC*", "StartCapture width" + width +
private int doStartCapture(int width, int height, int frameRate) {
if(DEBUG) Log.d(TAG, "doStartCapture " + width +
" height " + height +" frame rate " + frameRate);
try {
if (camera == null) {
Log.e("*WEBRTC*",
String.format(Locale.US,"Camera not initialized %d",id));
Log.e(TAG, "Camera not initialized %d" + id);
return -1;
}
currentCapability = new CaptureCapabilityAndroid();
@ -93,16 +98,10 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(currentCapability.width,
currentCapability.height);
parameters.setPreviewFormat(PIXEL_FORMAT );
parameters.setPreviewFormat(PIXEL_FORMAT);
parameters.setPreviewFrameRate(currentCapability.maxFPS);
camera.setParameters(parameters);
// Get the local preview SurfaceHolder from the static render class
localPreview = ViERenderer.GetLocalRenderer();
if(localPreview != null) {
localPreview.addCallback(this);
}
int bufSize = width * height * pixelFormat.bitsPerPixel / 8;
if(android.os.Build.VERSION.SDK_INT >= 7) {
// According to Doc addCallbackBuffer belongs to API level 8.
@ -124,21 +123,44 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
camera.startPreview();
previewBufferLock.lock();
expectedFrameSize = bufSize;
isRunning = true;
isCaptureRunning = true;
previewBufferLock.unlock();
}
catch (Exception ex) {
Log.e("*WEBRTC*", "Failed to start camera");
Log.e(TAG, "Failed to start camera");
return -1;
}
isCaptureRunning = true;
return 0;
}
public int StartCapture(int width, int height, int frameRate) {
if(DEBUG) Log.d(TAG, "StartCapture width " + width +
" height " + height +" frame rate " + frameRate);
isCaptureStarted = true;
// Get the local preview SurfaceHolder from the static render class
localPreview = ViERenderer.GetLocalRenderer();
if(localPreview != null) {
localPreview.addCallback(this);
}
if (camera == null) {
Log.e(TAG, "Camera not initialized %d" + id);
return -1;
}
if (!isSurfaceReady) return 0;
return doStartCapture(width, height, frameRate);
}
public int StopCapture() {
if(DEBUG) Log.d("*WEBRTC*", "StopCapture");
if(DEBUG) Log.d(TAG, "StopCapture");
try {
previewBufferLock.lock();
isRunning = false;
isCaptureRunning = false;
previewBufferLock.unlock();
camera.stopPreview();
@ -151,34 +173,28 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
}
}
catch (Exception ex) {
Log.e("*WEBRTC*", "Failed to stop camera");
Log.e(TAG, "Failed to stop camera");
return -1;
}
if(DEBUG) {
Log.d("*WEBRTC*", "StopCapture ended");
}
isCaptureStarted = false;
return 0;
}
native void ProvideCameraFrame(byte[] data,int length, long captureObject);
native void ProvideCameraFrame(byte[] data, int length, long captureObject);
public void onPreviewFrame(byte[] data, Camera camera) {
previewBufferLock.lock();
if(VERBOSE) {
Log.v("*WEBRTC*",
String.format(Locale.US, "preview frame length %d context %x",
data.length, context));
Log.v(TAG, "preview frame length " + data.length +
" context" + context);
}
if(isRunning) {
if(isCaptureRunning) {
// If StartCapture has been called but not StopCapture
// Call the C++ layer with the captured frame
if (data.length == expectedFrameSize) {
ProvideCameraFrame(data, expectedFrameSize, context);
if (VERBOSE) {
Log.v("*WEBRTC*", String.format(Locale.US, "frame delivered"));
}
if(ownsBuffers) {
// Give the video buffer to the camera service again.
camera.addCallbackBuffer(data);
@ -188,36 +204,21 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
previewBufferLock.unlock();
}
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
try {
if(camera != null) {
camera.setPreviewDisplay(localPreview);
}
} catch (IOException e) {
Log.e("*WEBRTC*",
String.format(Locale.US,
"Failed to set Local preview. " + e.getMessage()));
}
}
// Sets the rotation of the preview render window.
// Does not affect the captured video image.
public void SetPreviewRotation(int rotation) {
Log.v(TAG, "SetPreviewRotation:" + rotation);
if(camera != null) {
previewBufferLock.lock();
final boolean running = isRunning;
int width = 0;
int height = 0;
int framerate = 0;
if(running) {
if(isCaptureRunning) {
width = currentCapability.width;
height = currentCapability.height;
framerate = currentCapability.maxFPS;
StopCapture();
}
@ -245,18 +246,46 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
camera.setParameters(parameters);
}
if(running) {
if(isCaptureRunning) {
StartCapture(width, height, framerate);
}
previewBufferLock.unlock();
}
}
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
if (DEBUG) Log.d(TAG, "VideoCaptureAndroid::surfaceChanged");
isSurfaceReady = true;
surfaceHolder = holder;
if (!isCaptureStarted || isCaptureRunning)
return;
if (DEBUG) {
Log.d(TAG, "VideoCaptureAndroid::surfaceChanged StartCapture");
}
if(camera != null) {
try {
camera.setPreviewDisplay(surfaceHolder);
}
catch (IOException e) {
Log.e(TAG, "Failed to set Local preview. " + e.getMessage());
}
}
doStartCapture(currentCapability.width,
currentCapability.height,
currentCapability.maxFPS);
}
public void surfaceCreated(SurfaceHolder holder) {
if(DEBUG) Log.d(TAG, "VideoCaptureAndroid::surfaceCreated");
}
public void surfaceDestroyed(SurfaceHolder holder) {
if(DEBUG) Log.d(TAG, "VideoCaptureAndroid::surfaceDestroyed");
isSurfaceReady = false;
}
}

View File

@ -29,10 +29,9 @@ public class VideoCaptureDeviceInfoAndroid {
//Context
Context context;
// Set this to 2 for VERBOSE logging. 1 for DEBUG
private static int LOGLEVEL = 0;
private static boolean VERBOSE = LOGLEVEL > 2;
private static boolean DEBUG = LOGLEVEL > 1;
// Set VERBOSE as the default logging level because camera device info
// is very useful information and doesn't degrade performance normally
private final static String TAG = "WEBRTC";
// Private class with info about all available cameras and the capabilities
public class AndroidVideoCaptureDevice {
@ -65,10 +64,8 @@ public class VideoCaptureDeviceInfoAndroid {
public static VideoCaptureDeviceInfoAndroid
CreateVideoCaptureDeviceInfoAndroid(int in_id, Context in_context) {
if(DEBUG) {
Log.d("*WEBRTC*",
String.format(Locale.US, "VideoCaptureDeviceInfoAndroid"));
}
Log.d(TAG,
String.format(Locale.US, "VideoCaptureDeviceInfoAndroid"));
VideoCaptureDeviceInfoAndroid self =
new VideoCaptureDeviceInfoAndroid(in_id, in_context);
@ -76,9 +73,7 @@ public class VideoCaptureDeviceInfoAndroid {
return self;
}
else {
if(DEBUG) {
Log.d("*WEBRTC*", "Failed to create VideoCaptureDeviceInfoAndroid.");
}
Log.d(TAG, "Failed to create VideoCaptureDeviceInfoAndroid.");
}
return null;
}
@ -106,11 +101,14 @@ public class VideoCaptureDeviceInfoAndroid {
if(info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
newDevice.deviceUniqueName =
"Camera " + i +", Facing back, Orientation "+ info.orientation;
Log.d(TAG, "Camera " + i +", Facing back, Orientation "+ info.orientation);
}
else {
newDevice.deviceUniqueName =
"Camera " + i +", Facing front, Orientation "+ info.orientation;
newDevice.frontCameraType = FrontFacingCameraType.Android23;
Log.d(TAG, "Camera " + i +", Facing front, Orientation "+ info.orientation);
}
camera = Camera.open(i);
@ -121,33 +119,9 @@ public class VideoCaptureDeviceInfoAndroid {
deviceList.add(newDevice);
}
}
else {
// Prior to Android 2.3
AndroidVideoCaptureDevice newDevice;
Camera.Parameters parameters;
newDevice = new AndroidVideoCaptureDevice();
camera = Camera.open();
parameters = camera.getParameters();
newDevice.deviceUniqueName = "Camera 1, Facing back";
newDevice.orientation = 90;
AddDeviceInfo(newDevice, parameters);
deviceList.add(newDevice);
camera.release();
camera=null;
newDevice = new AndroidVideoCaptureDevice();
newDevice.deviceUniqueName = "Camera 2, Facing front";
parameters = SearchOldFrontFacingCameras(newDevice);
if(parameters != null) {
AddDeviceInfo(newDevice, parameters);
deviceList.add(newDevice);
}
}
}
catch (Exception ex) {
Log.e("*WEBRTC*", "Failed to init VideoCaptureDeviceInfo ex" +
Log.e(TAG, "Failed to init VideoCaptureDeviceInfo ex" +
ex.getLocalizedMessage());
return -1;
}
@ -161,12 +135,8 @@ public class VideoCaptureDeviceInfoAndroid {
List<Size> sizes = parameters.getSupportedPreviewSizes();
List<Integer> frameRates = parameters.getSupportedPreviewFrameRates();
int maxFPS=0;
int maxFPS = 0;
for(Integer frameRate:frameRates) {
if(VERBOSE) {
Log.v("*WEBRTC*",
"VideoCaptureDeviceInfoAndroid:frameRate " + frameRate);
}
if(frameRate > maxFPS) {
maxFPS = frameRate;
}
@ -179,6 +149,9 @@ public class VideoCaptureDeviceInfoAndroid {
newDevice.captureCapabilies[i].height = s.height;
newDevice.captureCapabilies[i].width = s.width;
newDevice.captureCapabilies[i].maxFPS = maxFPS;
Log.v(TAG,
"VideoCaptureDeviceInfo " + "maxFPS:" + maxFPS +
" width:" + s.width + " height:" + s.height);
}
}
@ -282,7 +255,7 @@ public class VideoCaptureDeviceInfoAndroid {
public VideoCaptureAndroid AllocateCamera(int id, long context,
String deviceUniqueId) {
try {
if(DEBUG) Log.d("*WEBRTC*", "AllocateCamera " + deviceUniqueId);
Log.d(TAG, "AllocateCamera " + deviceUniqueId);
Camera camera = null;
AndroidVideoCaptureDevice deviceToUse = null;
@ -310,14 +283,12 @@ public class VideoCaptureDeviceInfoAndroid {
if(camera == null) {
return null;
}
if(VERBOSE) {
Log.v("*WEBRTC*", "AllocateCamera - creating VideoCaptureAndroid");
}
Log.v(TAG, "AllocateCamera - creating VideoCaptureAndroid");
return new VideoCaptureAndroid(id,context,camera,deviceToUse);
return new VideoCaptureAndroid(id, context, camera, deviceToUse);
}catch (Exception ex) {
Log.e("*WEBRTC*", "AllocateCamera Failed to open camera- ex " +
Log.e(TAG, "AllocateCamera Failed to open camera- ex " +
ex.getLocalizedMessage());
}
return null;
@ -346,14 +317,14 @@ public class VideoCaptureDeviceInfoAndroid {
return parameters;
}
catch (Exception ex) {
//Nope - it did not work.
Log.e("*WEBRTC*", "Init Failed to open front camera camera - ex " +
// Nope - it did not work.
Log.e(TAG, "Init Failed to open front camera camera - ex " +
ex.getLocalizedMessage());
}
}
camera.release();
//Check for Evo front facing camera
// Check for Evo front facing camera
File file =
new File("/system/framework/com.htc.hardware.twinCamDevice.jar");
boolean exists = file.exists();
@ -399,9 +370,9 @@ public class VideoCaptureDeviceInfoAndroid {
dexOutputDir = context.getFilesDir().getAbsolutePath();
File mFilesDir = new File(dexOutputDir, "dexfiles");
if(!mFilesDir.exists()){
//Log.e("*WEBRTCN*", "Directory doesn't exists");
// Log.e("*WEBRTCN*", "Directory doesn't exists");
if(!mFilesDir.mkdirs()) {
//Log.e("*WEBRTCN*", "Unable to create files directory");
// Log.e("*WEBRTCN*", "Unable to create files directory");
}
}
}