diff --git a/src/modules/video_capture/main/source/android/java/org/webrtc/videoengine/VideoCaptureAndroid.java b/src/modules/video_capture/main/source/android/java/org/webrtc/videoengine/VideoCaptureAndroid.java index 38fe75dd78..4a018481e8 100644 --- a/src/modules/video_capture/main/source/android/java/org/webrtc/videoengine/VideoCaptureAndroid.java +++ b/src/modules/video_capture/main/source/android/java/org/webrtc/videoengine/VideoCaptureAndroid.java @@ -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; } } diff --git a/src/modules/video_capture/main/source/android/java/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java b/src/modules/video_capture/main/source/android/java/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java index 2fc71b4f6b..b0e75cc438 100644 --- a/src/modules/video_capture/main/source/android/java/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java +++ b/src/modules/video_capture/main/source/android/java/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java @@ -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 sizes = parameters.getSupportedPreviewSizes(); List 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"); } } }