| /* |
| * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| package org.webrtc.videoengine; |
| |
| import java.io.IOException; |
| import java.util.Locale; |
| import java.util.concurrent.locks.ReentrantLock; |
| |
| import org.webrtc.videoengine.CaptureCapabilityAndroid; |
| import org.webrtc.videoengine.VideoCaptureDeviceInfoAndroid.AndroidVideoCaptureDevice; |
| |
| import android.graphics.ImageFormat; |
| import android.graphics.PixelFormat; |
| import android.hardware.Camera; |
| import android.hardware.Camera.PreviewCallback; |
| import android.util.Log; |
| import android.view.SurfaceHolder; |
| import android.view.SurfaceHolder.Callback; |
| |
| public class VideoCaptureAndroid implements PreviewCallback, Callback { |
| |
| private Camera camera; |
| private AndroidVideoCaptureDevice currentDevice = null; |
| public ReentrantLock previewBufferLock = new ReentrantLock(); |
| 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 final int numCaptureBuffers = 3; |
| private int expectedFrameSize = 0; |
| private int orientation = 0; |
| private int id = 0; |
| // C++ callback context variable. |
| private long context = 0; |
| private SurfaceHolder localPreview = null; |
| // 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; |
| private static boolean VERBOSE = LOGLEVEL > 2; |
| private static boolean DEBUG = LOGLEVEL > 1; |
| |
| CaptureCapabilityAndroid currentCapability = null; |
| |
| public static |
| void DeleteVideoCaptureAndroid(VideoCaptureAndroid captureAndroid) { |
| if(DEBUG) Log.d("*WEBRTC*", "DeleteVideoCaptureAndroid"); |
| |
| captureAndroid.StopCapture(); |
| captureAndroid.camera.release(); |
| captureAndroid.camera = null; |
| captureAndroid.context = 0; |
| |
| if(DEBUG) Log.v("*WEBRTC*", "DeleteVideoCaptureAndroid ended"); |
| |
| } |
| |
| public VideoCaptureAndroid(int in_id, |
| long in_context, |
| Camera in_camera, |
| AndroidVideoCaptureDevice in_device) { |
| id = in_id; |
| context = in_context; |
| camera = in_camera; |
| currentDevice = in_device; |
| } |
| |
| public int StartCapture(int width, int height, int frameRate) { |
| if(DEBUG) Log.d("*WEBRTC*", "StartCapture width" + width + |
| " height " + height +" frame rate " + frameRate); |
| try { |
| if (camera == null) { |
| Log.e("*WEBRTC*", |
| String.format(Locale.US,"Camera not initialized %d",id)); |
| return -1; |
| } |
| currentCapability = new CaptureCapabilityAndroid(); |
| currentCapability.width = width; |
| currentCapability.height = height; |
| currentCapability.maxFPS = frameRate; |
| PixelFormat.getPixelFormatInfo(PIXEL_FORMAT, pixelFormat); |
| |
| Camera.Parameters parameters = camera.getParameters(); |
| parameters.setPreviewSize(currentCapability.width, |
| currentCapability.height); |
| 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. |
| // But it seems like it works on Android 2.1 as well. |
| // At least SE X10 and Milestone |
| byte[] buffer = null; |
| for (int i = 0; i < numCaptureBuffers; i++) { |
| buffer = new byte[bufSize]; |
| camera.addCallbackBuffer(buffer); |
| } |
| |
| camera.setPreviewCallbackWithBuffer(this); |
| ownsBuffers = true; |
| } |
| else { |
| camera.setPreviewCallback(this); |
| } |
| |
| camera.startPreview(); |
| previewBufferLock.lock(); |
| expectedFrameSize = bufSize; |
| isRunning = true; |
| previewBufferLock.unlock(); |
| } |
| catch (Exception ex) { |
| Log.e("*WEBRTC*", "Failed to start camera"); |
| return -1; |
| } |
| return 0; |
| } |
| |
| public int StopCapture() { |
| if(DEBUG) Log.d("*WEBRTC*", "StopCapture"); |
| try { |
| previewBufferLock.lock(); |
| isRunning = false; |
| previewBufferLock.unlock(); |
| |
| camera.stopPreview(); |
| |
| if(android.os.Build.VERSION.SDK_INT > 7) { |
| camera.setPreviewCallbackWithBuffer(null); |
| } |
| else { |
| camera.setPreviewCallback(null); |
| } |
| } |
| catch (Exception ex) { |
| Log.e("*WEBRTC*", "Failed to stop camera"); |
| return -1; |
| } |
| |
| if(DEBUG) { |
| Log.d("*WEBRTC*", "StopCapture ended"); |
| } |
| return 0; |
| } |
| |
| 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)); |
| } |
| if(isRunning) { |
| // 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); |
| } |
| } |
| } |
| 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) { |
| if(camera != null) { |
| previewBufferLock.lock(); |
| final boolean running = isRunning; |
| int width = 0; |
| int height = 0; |
| int framerate = 0; |
| |
| if(running) { |
| width = currentCapability.width; |
| height = currentCapability.height; |
| framerate = currentCapability.maxFPS; |
| |
| StopCapture(); |
| } |
| |
| int resultRotation = 0; |
| if(currentDevice.frontCameraType == |
| VideoCaptureDeviceInfoAndroid.FrontFacingCameraType.Android23) { |
| // this is a 2.3 or later front facing camera. |
| // SetDisplayOrientation will flip the image horizontally |
| // before doing the rotation. |
| resultRotation=(360-rotation) % 360; // compensate the mirror |
| } |
| else { |
| // Back facing or 2.2 or previous front camera |
| resultRotation=rotation; |
| } |
| if(android.os.Build.VERSION.SDK_INT>7) { |
| camera.setDisplayOrientation(resultRotation); |
| } |
| else { |
| // Android 2.1 and previous |
| // This rotation unfortunately does not seems to work. |
| // http://code.google.com/p/android/issues/detail?id=1193 |
| Camera.Parameters parameters = camera.getParameters(); |
| parameters.setRotation(resultRotation); |
| camera.setParameters(parameters); |
| } |
| |
| if(running) { |
| StartCapture(width, height, framerate); |
| } |
| previewBufferLock.unlock(); |
| } |
| } |
| |
| public void surfaceCreated(SurfaceHolder holder) { |
| } |
| |
| |
| public void surfaceDestroyed(SurfaceHolder holder) { |
| } |
| |
| } |