| /* |
| * 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.File; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Locale; |
| |
| import dalvik.system.DexClassLoader; |
| |
| import android.content.Context; |
| import android.hardware.Camera; |
| import android.hardware.Camera.Size; |
| import android.util.Log; |
| |
| 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; |
| |
| // Private class with info about all available cameras and the capabilities |
| public class AndroidVideoCaptureDevice { |
| AndroidVideoCaptureDevice() { |
| frontCameraType = FrontFacingCameraType.None; |
| index = 0; |
| } |
| |
| public String deviceUniqueName; |
| public CaptureCapabilityAndroid captureCapabilies[]; |
| public FrontFacingCameraType frontCameraType; |
| |
| // Orientation of camera as described in |
| // android.hardware.Camera.CameraInfo.Orientation |
| public int orientation; |
| // Camera index used in Camera.Open on Android 2.3 and onwards |
| public int index; |
| } |
| |
| public enum FrontFacingCameraType { |
| None, // This is not a front facing camera |
| GalaxyS, // Galaxy S front facing camera. |
| HTCEvo, // HTC Evo front facing camera |
| Android23, // Android 2.3 front facing camera. |
| } |
| |
| String currentDeviceUniqueId; |
| int id; |
| List<AndroidVideoCaptureDevice> deviceList; |
| |
| public static VideoCaptureDeviceInfoAndroid |
| CreateVideoCaptureDeviceInfoAndroid(int in_id, Context in_context) { |
| if(DEBUG) { |
| Log.d("*WEBRTC*", |
| String.format(Locale.US, "VideoCaptureDeviceInfoAndroid")); |
| } |
| |
| VideoCaptureDeviceInfoAndroid self = |
| new VideoCaptureDeviceInfoAndroid(in_id, in_context); |
| if(self != null && self.Init() == 0) { |
| return self; |
| } |
| else { |
| if(DEBUG) { |
| Log.d("*WEBRTC*", "Failed to create VideoCaptureDeviceInfoAndroid."); |
| } |
| } |
| return null; |
| } |
| |
| private VideoCaptureDeviceInfoAndroid(int in_id, |
| Context in_context) { |
| id = in_id; |
| context = in_context; |
| deviceList = new ArrayList<AndroidVideoCaptureDevice>(); |
| } |
| |
| private int Init() { |
| // Populate the deviceList with available cameras and their capabilities. |
| Camera camera = null; |
| try{ |
| if(android.os.Build.VERSION.SDK_INT > 8) { |
| // From Android 2.3 and onwards |
| for(int i = 0; i < Camera.getNumberOfCameras(); ++i) { |
| AndroidVideoCaptureDevice newDevice = new AndroidVideoCaptureDevice(); |
| |
| Camera.CameraInfo info = new Camera.CameraInfo(); |
| Camera.getCameraInfo(i, info); |
| newDevice.index = i; |
| newDevice.orientation=info.orientation; |
| if(info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { |
| newDevice.deviceUniqueName = |
| "Camera " + i +", Facing back, Orientation "+ info.orientation; |
| } |
| else { |
| newDevice.deviceUniqueName = |
| "Camera " + i +", Facing front, Orientation "+ info.orientation; |
| newDevice.frontCameraType = FrontFacingCameraType.Android23; |
| } |
| |
| camera = Camera.open(i); |
| Camera.Parameters parameters = camera.getParameters(); |
| AddDeviceInfo(newDevice, parameters); |
| camera.release(); |
| camera = null; |
| 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" + |
| ex.getLocalizedMessage()); |
| return -1; |
| } |
| VerifyCapabilities(); |
| return 0; |
| } |
| |
| // Adds the capture capabilities of the currently opened device |
| private void AddDeviceInfo(AndroidVideoCaptureDevice newDevice, |
| Camera.Parameters parameters) { |
| |
| List<Size> sizes = parameters.getSupportedPreviewSizes(); |
| List<Integer> frameRates = parameters.getSupportedPreviewFrameRates(); |
| int maxFPS=0; |
| for(Integer frameRate:frameRates) { |
| if(VERBOSE) { |
| Log.v("*WEBRTC*", |
| "VideoCaptureDeviceInfoAndroid:frameRate " + frameRate); |
| } |
| if(frameRate > maxFPS) { |
| maxFPS = frameRate; |
| } |
| } |
| |
| newDevice.captureCapabilies = new CaptureCapabilityAndroid[sizes.size()]; |
| for(int i = 0; i < sizes.size(); ++i) { |
| Size s = sizes.get(i); |
| newDevice.captureCapabilies[i] = new CaptureCapabilityAndroid(); |
| newDevice.captureCapabilies[i].height = s.height; |
| newDevice.captureCapabilies[i].width = s.width; |
| newDevice.captureCapabilies[i].maxFPS = maxFPS; |
| } |
| } |
| |
| // Function that make sure device specific capabilities are |
| // in the capability list. |
| // Ie Galaxy S supports CIF but does not list CIF as a supported capability. |
| // Motorola Droid Camera does not work with frame rate above 15fps. |
| // http://code.google.com/p/android/issues/detail?id=5514#c0 |
| private void VerifyCapabilities() { |
| // Nexus S or Galaxy S |
| if(android.os.Build.DEVICE.equals("GT-I9000") || |
| android.os.Build.DEVICE.equals("crespo")) { |
| CaptureCapabilityAndroid specificCapability = |
| new CaptureCapabilityAndroid(); |
| specificCapability.width = 352; |
| specificCapability.height = 288; |
| specificCapability.maxFPS = 15; |
| AddDeviceSpecificCapability(specificCapability); |
| |
| specificCapability = new CaptureCapabilityAndroid(); |
| specificCapability.width = 176; |
| specificCapability.height = 144; |
| specificCapability.maxFPS = 15; |
| AddDeviceSpecificCapability(specificCapability); |
| |
| specificCapability = new CaptureCapabilityAndroid(); |
| specificCapability.width = 320; |
| specificCapability.height = 240; |
| specificCapability.maxFPS = 15; |
| AddDeviceSpecificCapability(specificCapability); |
| } |
| // Motorola Milestone Camera server does not work at 30fps |
| // even though it reports that it can |
| if(android.os.Build.MANUFACTURER.equals("motorola") && |
| android.os.Build.DEVICE.equals("umts_sholes")) { |
| for(AndroidVideoCaptureDevice device:deviceList) { |
| for(CaptureCapabilityAndroid capability:device.captureCapabilies) { |
| capability.maxFPS=15; |
| } |
| } |
| } |
| } |
| |
| private void AddDeviceSpecificCapability( |
| CaptureCapabilityAndroid specificCapability) { |
| for(AndroidVideoCaptureDevice device:deviceList) { |
| boolean foundCapability = false; |
| for(CaptureCapabilityAndroid capability:device.captureCapabilies) { |
| if(capability.width == specificCapability.width && |
| capability.height == specificCapability.height) { |
| foundCapability = true; |
| break; |
| } |
| } |
| if(foundCapability==false) { |
| CaptureCapabilityAndroid newCaptureCapabilies[]= |
| new CaptureCapabilityAndroid[device.captureCapabilies.length+1]; |
| for(int i = 0; i < device.captureCapabilies.length; ++i) { |
| newCaptureCapabilies[i+1] = device.captureCapabilies[i]; |
| } |
| newCaptureCapabilies[0] = specificCapability; |
| device.captureCapabilies = newCaptureCapabilies; |
| } |
| } |
| } |
| |
| // Returns the number of Capture devices that is supported |
| public int NumberOfDevices() { |
| return deviceList.size(); |
| } |
| |
| public String GetDeviceUniqueName(int deviceNumber) { |
| if(deviceNumber < 0 || deviceNumber >= deviceList.size()) { |
| return null; |
| } |
| return deviceList.get(deviceNumber).deviceUniqueName; |
| } |
| |
| public CaptureCapabilityAndroid[] GetCapabilityArray (String deviceUniqueId) |
| { |
| for (AndroidVideoCaptureDevice device: deviceList) { |
| if(device.deviceUniqueName.equals(deviceUniqueId)) { |
| return (CaptureCapabilityAndroid[]) device.captureCapabilies; |
| } |
| } |
| return null; |
| } |
| |
| // Returns the camera orientation as described by |
| // android.hardware.Camera.CameraInfo.orientation |
| public int GetOrientation(String deviceUniqueId) { |
| for (AndroidVideoCaptureDevice device: deviceList) { |
| if(device.deviceUniqueName.equals(deviceUniqueId)) { |
| return device.orientation; |
| } |
| } |
| return -1; |
| } |
| |
| // Returns an instance of VideoCaptureAndroid. |
| public VideoCaptureAndroid AllocateCamera(int id, long context, |
| String deviceUniqueId) { |
| try { |
| if(DEBUG) Log.d("*WEBRTC*", "AllocateCamera " + deviceUniqueId); |
| |
| Camera camera = null; |
| AndroidVideoCaptureDevice deviceToUse = null; |
| for (AndroidVideoCaptureDevice device: deviceList) { |
| if(device.deviceUniqueName.equals(deviceUniqueId)) { |
| // Found the wanted camera |
| deviceToUse = device; |
| switch(device.frontCameraType) { |
| case GalaxyS: |
| camera = AllocateGalaxySFrontCamera(); |
| break; |
| case HTCEvo: |
| camera = AllocateEVOFrontFacingCamera(); |
| break; |
| default: |
| // From Android 2.3 and onwards) |
| if(android.os.Build.VERSION.SDK_INT>8) |
| camera=Camera.open(device.index); |
| else |
| camera=Camera.open(); // Default camera |
| } |
| } |
| } |
| |
| if(camera == null) { |
| return null; |
| } |
| if(VERBOSE) { |
| Log.v("*WEBRTC*", "AllocateCamera - creating VideoCaptureAndroid"); |
| } |
| |
| return new VideoCaptureAndroid(id,context,camera,deviceToUse); |
| |
| }catch (Exception ex) { |
| Log.e("*WEBRTC*", "AllocateCamera Failed to open camera- ex " + |
| ex.getLocalizedMessage()); |
| } |
| return null; |
| } |
| |
| // Searches for a front facing camera device. This is device specific code. |
| private Camera.Parameters |
| SearchOldFrontFacingCameras(AndroidVideoCaptureDevice newDevice) |
| throws SecurityException, IllegalArgumentException, |
| NoSuchMethodException, ClassNotFoundException, |
| IllegalAccessException, InvocationTargetException { |
| // Check the id of the opened camera device |
| // Returns null on X10 and 1 on Samsung Galaxy S. |
| Camera camera = Camera.open(); |
| Camera.Parameters parameters = camera.getParameters(); |
| String cameraId = parameters.get("camera-id"); |
| if(cameraId != null && cameraId.equals("1")) { |
| // This might be a Samsung Galaxy S with a front facing camera. |
| try { |
| parameters.set("camera-id", 2); |
| camera.setParameters(parameters); |
| parameters = camera.getParameters(); |
| newDevice.frontCameraType = FrontFacingCameraType.GalaxyS; |
| newDevice.orientation = 0; |
| camera.release(); |
| return parameters; |
| } |
| catch (Exception ex) { |
| //Nope - it did not work. |
| Log.e("*WEBRTC*", "Init Failed to open front camera camera - ex " + |
| ex.getLocalizedMessage()); |
| } |
| } |
| camera.release(); |
| |
| //Check for Evo front facing camera |
| File file = |
| new File("/system/framework/com.htc.hardware.twinCamDevice.jar"); |
| boolean exists = file.exists(); |
| if (!exists){ |
| file = |
| new File("/system/framework/com.sprint.hardware.twinCamDevice.jar"); |
| exists = file.exists(); |
| } |
| if(exists) { |
| newDevice.frontCameraType = FrontFacingCameraType.HTCEvo; |
| newDevice.orientation = 0; |
| Camera evCamera = AllocateEVOFrontFacingCamera(); |
| parameters = evCamera.getParameters(); |
| evCamera.release(); |
| return parameters; |
| } |
| return null; |
| } |
| |
| // Returns a handle to HTC front facing camera. |
| // The caller is responsible to release it on completion. |
| private Camera AllocateEVOFrontFacingCamera() |
| throws SecurityException, NoSuchMethodException, |
| ClassNotFoundException, IllegalArgumentException, |
| IllegalAccessException, InvocationTargetException { |
| String classPath = null; |
| File file = |
| new File("/system/framework/com.htc.hardware.twinCamDevice.jar"); |
| classPath = "com.htc.hardware.twinCamDevice.FrontFacingCamera"; |
| boolean exists = file.exists(); |
| if (!exists){ |
| file = |
| new File("/system/framework/com.sprint.hardware.twinCamDevice.jar"); |
| classPath = "com.sprint.hardware.twinCamDevice.FrontFacingCamera"; |
| exists = file.exists(); |
| } |
| if(!exists) { |
| return null; |
| } |
| |
| String dexOutputDir = ""; |
| if(context != null) { |
| dexOutputDir = context.getFilesDir().getAbsolutePath(); |
| File mFilesDir = new File(dexOutputDir, "dexfiles"); |
| if(!mFilesDir.exists()){ |
| //Log.e("*WEBRTCN*", "Directory doesn't exists"); |
| if(!mFilesDir.mkdirs()) { |
| //Log.e("*WEBRTCN*", "Unable to create files directory"); |
| } |
| } |
| } |
| |
| dexOutputDir += "/dexfiles"; |
| |
| DexClassLoader loader = |
| new DexClassLoader(file.getAbsolutePath(), dexOutputDir, |
| null, ClassLoader.getSystemClassLoader()); |
| |
| Method method = loader.loadClass(classPath).getDeclaredMethod( |
| "getFrontFacingCamera", (Class[]) null); |
| Camera camera = (Camera) method.invoke((Object[])null,(Object[]) null); |
| return camera; |
| } |
| |
| // Returns a handle to Galaxy S front camera. |
| // The caller is responsible to release it on completion. |
| private Camera AllocateGalaxySFrontCamera() |
| { |
| Camera camera = Camera.open(); |
| Camera.Parameters parameters = camera.getParameters(); |
| parameters.set("camera-id",2); |
| camera.setParameters(parameters); |
| return camera; |
| } |
| |
| } |