1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.media; 6 7 import android.content.Context; 8 import android.content.pm.PackageManager; 9 import android.hardware.Camera; 10 import android.util.Log; 11 12 import org.chromium.base.CalledByNative; 13 import org.chromium.base.JNINamespace; 14 // Needed for jni_generator.py to guess correctly the origin of 15 // VideoCapture.CaptureFormat. 16 import org.chromium.media.VideoCapture; 17 18 /** 19 * This class implements a factory of Android Video Capture objects for Chrome. 20 * The static createVideoCapture() returns either a "normal" VideoCaptureAndroid 21 * or a "special" VideoCaptureTango. Cameras are identified by |id|, where Tango 22 * cameras have |id| above the standard ones. Video Capture objects allocated 23 * via createVideoCapture() are explicitly owned by the caller. 24 * ChromiumCameraInfo is an internal class with some static methods needed from 25 * the native side to enumerate devices and collect their names and info. It 26 * takes into account the mentioned special devices. 27 **/ 28 @JNINamespace("media") 29 class VideoCaptureFactory { 30 31 static class CamParams { 32 final int mId; 33 final String mName; 34 final int mWidth; 35 final int mHeight; 36 CamParams(int id, String name, int width, int height)37 CamParams(int id, String name, int width, int height) { 38 mId = id; 39 mName = name; 40 mWidth = width; 41 mHeight = height; 42 } 43 } 44 45 static class ChromiumCameraInfo { 46 private final int mId; 47 private final Camera.CameraInfo mCameraInfo; 48 // Special devices have more cameras than usual. Those devices are 49 // identified by model & device. Currently only the Tango is supported. 50 // Note that these devices have no Camera.CameraInfo. 51 private static final String[][] s_SPECIAL_DEVICE_LIST = { 52 {"Peanut", "peanut"}, 53 }; 54 private static final String TAG = "ChromiumCameraInfo"; 55 56 private static int sNumberOfSystemCameras = -1; 57 isSpecialDevice()58 private static boolean isSpecialDevice() { 59 for (String[] device : s_SPECIAL_DEVICE_LIST) { 60 if (device[0].contentEquals(android.os.Build.MODEL) && 61 device[1].contentEquals(android.os.Build.DEVICE)) { 62 return true; 63 } 64 } 65 return false; 66 } 67 isSpecialCamera(int id)68 private static boolean isSpecialCamera(int id) { 69 return id >= sNumberOfSystemCameras; 70 } 71 toSpecialCameraId(int id)72 private static int toSpecialCameraId(int id) { 73 assert isSpecialCamera(id); 74 return id - sNumberOfSystemCameras; 75 } 76 ChromiumCameraInfo(int index)77 private ChromiumCameraInfo(int index) { 78 mId = index; 79 mCameraInfo = isSpecialCamera(index) ? null : getCameraInfo(mId); 80 } 81 82 @CalledByNative("ChromiumCameraInfo") getNumberOfCameras(Context appContext)83 private static int getNumberOfCameras(Context appContext) { 84 // Camera.getNumberOfCammeras() will not fail without permission, but the 85 // following operation on camera will do. Without permission isn't fatal 86 // error in WebView, specially for those application which has no purpose 87 // to use camera, but happens to load page required it. 88 // So, we output a warning log and pretend system have no camera at all. 89 if (sNumberOfSystemCameras == -1) { 90 if (PackageManager.PERMISSION_GRANTED == 91 appContext.getPackageManager().checkPermission( 92 "android.permission.CAMERA", appContext.getPackageName())) { 93 sNumberOfSystemCameras = Camera.getNumberOfCameras(); 94 } else { 95 sNumberOfSystemCameras = 0; 96 Log.w(TAG, "Missing android.permission.CAMERA permission, " 97 + "no system camera available."); 98 } 99 } 100 if (isSpecialDevice()) { 101 Log.d(TAG, "Special device: " + android.os.Build.MODEL); 102 return sNumberOfSystemCameras + 103 VideoCaptureTango.numberOfCameras(); 104 } else { 105 return sNumberOfSystemCameras; 106 } 107 } 108 109 @CalledByNative("ChromiumCameraInfo") getAt(int index)110 private static ChromiumCameraInfo getAt(int index) { 111 return new ChromiumCameraInfo(index); 112 } 113 114 @CalledByNative("ChromiumCameraInfo") getId()115 private int getId() { 116 return mId; 117 } 118 119 @CalledByNative("ChromiumCameraInfo") getDeviceName()120 private String getDeviceName() { 121 if (isSpecialCamera(mId)) { 122 return VideoCaptureTango.getCamParams(toSpecialCameraId(mId)).mName; 123 } else { 124 if (mCameraInfo == null) { 125 return ""; 126 } 127 Log.d(TAG, "Camera enumerated: " + (mCameraInfo.facing == 128 Camera.CameraInfo.CAMERA_FACING_FRONT ? "front" : 129 "back")); 130 return "camera " + mId + ", facing " + (mCameraInfo.facing == 131 Camera.CameraInfo.CAMERA_FACING_FRONT ? "front" : 132 "back"); 133 } 134 } 135 136 @CalledByNative("ChromiumCameraInfo") getOrientation()137 private int getOrientation() { 138 if (isSpecialCamera(mId)) { 139 return Camera.CameraInfo.CAMERA_FACING_BACK; 140 } else { 141 return (mCameraInfo == null ? 0 : mCameraInfo.orientation); 142 } 143 } 144 getCameraInfo(int id)145 private Camera.CameraInfo getCameraInfo(int id) { 146 Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); 147 try { 148 Camera.getCameraInfo(id, cameraInfo); 149 } catch (RuntimeException ex) { 150 Log.e(TAG, "getCameraInfo: Camera.getCameraInfo: " + ex); 151 return null; 152 } 153 return cameraInfo; 154 } 155 } 156 157 // Factory methods. 158 @CalledByNative createVideoCapture( Context context, int id, long nativeVideoCaptureDeviceAndroid)159 static VideoCapture createVideoCapture( 160 Context context, int id, long nativeVideoCaptureDeviceAndroid) { 161 if (ChromiumCameraInfo.isSpecialCamera(id)) { 162 return new VideoCaptureTango(context, ChromiumCameraInfo.toSpecialCameraId(id), 163 nativeVideoCaptureDeviceAndroid); 164 } else { 165 return new VideoCaptureAndroid(context, id, 166 nativeVideoCaptureDeviceAndroid); 167 } 168 } 169 170 @CalledByNative getDeviceSupportedFormats(int id)171 static VideoCapture.CaptureFormat[] getDeviceSupportedFormats(int id) { 172 return ChromiumCameraInfo.isSpecialCamera(id) ? 173 VideoCaptureTango.getDeviceSupportedFormats( 174 ChromiumCameraInfo.toSpecialCameraId(id)) : 175 VideoCaptureAndroid.getDeviceSupportedFormats(id); 176 } 177 178 @CalledByNative getCaptureFormatWidth(VideoCapture.CaptureFormat format)179 static int getCaptureFormatWidth(VideoCapture.CaptureFormat format) { 180 return format.getWidth(); 181 } 182 183 @CalledByNative getCaptureFormatHeight(VideoCapture.CaptureFormat format)184 static int getCaptureFormatHeight(VideoCapture.CaptureFormat format) { 185 return format.getHeight(); 186 } 187 188 @CalledByNative getCaptureFormatFramerate(VideoCapture.CaptureFormat format)189 static int getCaptureFormatFramerate(VideoCapture.CaptureFormat format) { 190 return format.getFramerate(); 191 } 192 193 @CalledByNative getCaptureFormatPixelFormat(VideoCapture.CaptureFormat format)194 static int getCaptureFormatPixelFormat(VideoCapture.CaptureFormat format) { 195 return format.getPixelFormat(); 196 } 197 } 198