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:
parent
b6f2417f37
commit
e62fec2285
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user