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 5package org.chromium.media; 6 7import android.content.Context; 8import android.content.pm.PackageManager; 9import android.util.Log; 10 11import org.chromium.base.CalledByNative; 12import org.chromium.base.JNINamespace; 13// Needed for jni_generator.py to guess correctly the origin of 14// VideoCapture.CaptureFormat. 15import org.chromium.media.VideoCapture; 16 17/** 18 * This class implements a factory of Android Video Capture objects for Chrome. 19 * The static createVideoCapture() returns either a "normal" VideoCaptureAndroid 20 * or a "special" VideoCaptureTango. Cameras are identified by |id|, where Tango 21 * cameras have |id| above the standard ones. Video Capture objects allocated 22 * via createVideoCapture() are explicitly owned by the caller. 23 * ChromiumCameraInfo is an internal class with some static methods needed from 24 * the native side to enumerate devices and collect their names and info. It 25 * takes into account the mentioned special devices. 26 **/ 27@JNINamespace("media") 28@SuppressWarnings("deprecation") 29class VideoCaptureFactory { 30 31 static class CamParams { 32 final int mId; 33 final String mName; 34 final int mWidth; 35 final int mHeight; 36 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 android.hardware.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[][] SPECIAL_DEVICE_LIST = { 52 {"Peanut", "peanut"}, 53 }; 54 private static final String TAG = "ChromiumCameraInfo"; 55 56 private static int sNumberOfSystemCameras = -1; 57 58 private static boolean isSpecialDevice() { 59 for (String[] device : 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 68 private static boolean isSpecialCamera(int id) { 69 return id >= sNumberOfSystemCameras; 70 } 71 72 private static int toSpecialCameraId(int id) { 73 assert isSpecialCamera(id); 74 return id - sNumberOfSystemCameras; 75 } 76 77 private ChromiumCameraInfo(int index) { 78 mId = index; 79 mCameraInfo = isSpecialCamera(index) ? null : getCameraInfo(mId); 80 } 81 82 @CalledByNative("ChromiumCameraInfo") 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 = android.hardware.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") 110 private static ChromiumCameraInfo getAt(int index) { 111 return new ChromiumCameraInfo(index); 112 } 113 114 @CalledByNative("ChromiumCameraInfo") 115 private int getId() { 116 return mId; 117 } 118 119 @CalledByNative("ChromiumCameraInfo") 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 android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT ? "front" : 129 "back")); 130 return "camera " + mId + ", facing " + (mCameraInfo.facing == 131 android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT ? "front" : 132 "back"); 133 } 134 } 135 136 @CalledByNative("ChromiumCameraInfo") 137 private int getOrientation() { 138 if (isSpecialCamera(mId)) { 139 return android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK; 140 } else { 141 return (mCameraInfo == null ? 0 : mCameraInfo.orientation); 142 } 143 } 144 145 private android.hardware.Camera.CameraInfo getCameraInfo(int id) { 146 android.hardware.Camera.CameraInfo cameraInfo = 147 new android.hardware.Camera.CameraInfo(); 148 try { 149 android.hardware.Camera.getCameraInfo(id, cameraInfo); 150 } catch (RuntimeException ex) { 151 Log.e(TAG, "getCameraInfo: android.hardware.Camera.getCameraInfo: " + ex); 152 return null; 153 } 154 return cameraInfo; 155 } 156 } 157 158 // Factory methods. 159 @CalledByNative 160 static VideoCapture createVideoCapture( 161 Context context, int id, long nativeVideoCaptureDeviceAndroid) { 162 if (ChromiumCameraInfo.isSpecialCamera(id)) { 163 return new VideoCaptureTango(context, ChromiumCameraInfo.toSpecialCameraId(id), 164 nativeVideoCaptureDeviceAndroid); 165 } else { 166 return new VideoCaptureAndroid(context, id, 167 nativeVideoCaptureDeviceAndroid); 168 } 169 } 170 171 @CalledByNative 172 static VideoCapture.CaptureFormat[] getDeviceSupportedFormats(int id) { 173 return ChromiumCameraInfo.isSpecialCamera(id) ? 174 VideoCaptureTango.getDeviceSupportedFormats( 175 ChromiumCameraInfo.toSpecialCameraId(id)) : 176 VideoCaptureAndroid.getDeviceSupportedFormats(id); 177 } 178 179 @CalledByNative 180 static int getCaptureFormatWidth(VideoCapture.CaptureFormat format) { 181 return format.getWidth(); 182 } 183 184 @CalledByNative 185 static int getCaptureFormatHeight(VideoCapture.CaptureFormat format) { 186 return format.getHeight(); 187 } 188 189 @CalledByNative 190 static int getCaptureFormatFramerate(VideoCapture.CaptureFormat format) { 191 return format.getFramerate(); 192 } 193 194 @CalledByNative 195 static int getCaptureFormatPixelFormat(VideoCapture.CaptureFormat format) { 196 return format.getPixelFormat(); 197 } 198} 199