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.
5 package org.chromium.media;
7 import android.content.Context;
8 import android.content.pm.PackageManager;
9 import android.hardware.Camera;
10 import android.util.Log;
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;
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.
28 @JNINamespace("media")
29 class VideoCaptureFactory {
31 static class CamParams {
37 CamParams(int id, String name, int width, int height) {
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[][] SPECIAL_DEVICE_LIST = {
54 private static final String TAG = "ChromiumCameraInfo";
56 private static int sNumberOfSystemCameras = -1;
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)) {
68 private static boolean isSpecialCamera(int id) {
69 return id >= sNumberOfSystemCameras;
72 private static int toSpecialCameraId(int id) {
73 assert isSpecialCamera(id);
74 return id - sNumberOfSystemCameras;
77 private ChromiumCameraInfo(int index) {
79 mCameraInfo = isSpecialCamera(index) ? null : getCameraInfo(mId);
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 = Camera.getNumberOfCameras();
95 sNumberOfSystemCameras = 0;
96 Log.w(TAG, "Missing android.permission.CAMERA permission, "
97 + "no system camera available.");
100 if (isSpecialDevice()) {
101 Log.d(TAG, "Special device: " + android.os.Build.MODEL);
102 return sNumberOfSystemCameras +
103 VideoCaptureTango.numberOfCameras();
105 return sNumberOfSystemCameras;
109 @CalledByNative("ChromiumCameraInfo")
110 private static ChromiumCameraInfo getAt(int index) {
111 return new ChromiumCameraInfo(index);
114 @CalledByNative("ChromiumCameraInfo")
115 private int getId() {
119 @CalledByNative("ChromiumCameraInfo")
120 private String getDeviceName() {
121 if (isSpecialCamera(mId)) {
122 return VideoCaptureTango.getCamParams(toSpecialCameraId(mId)).mName;
124 if (mCameraInfo == null) {
127 Log.d(TAG, "Camera enumerated: " + (mCameraInfo.facing ==
128 Camera.CameraInfo.CAMERA_FACING_FRONT ? "front" :
130 return "camera " + mId + ", facing " + (mCameraInfo.facing ==
131 Camera.CameraInfo.CAMERA_FACING_FRONT ? "front" :
136 @CalledByNative("ChromiumCameraInfo")
137 private int getOrientation() {
138 if (isSpecialCamera(mId)) {
139 return Camera.CameraInfo.CAMERA_FACING_BACK;
141 return (mCameraInfo == null ? 0 : mCameraInfo.orientation);
145 private Camera.CameraInfo getCameraInfo(int id) {
146 Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
148 Camera.getCameraInfo(id, cameraInfo);
149 } catch (RuntimeException ex) {
150 Log.e(TAG, "getCameraInfo: Camera.getCameraInfo: " + ex);
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);
165 return new VideoCaptureAndroid(context, id,
166 nativeVideoCaptureDeviceAndroid);
171 static VideoCapture.CaptureFormat[] getDeviceSupportedFormats(int id) {
172 return ChromiumCameraInfo.isSpecialCamera(id) ?
173 VideoCaptureTango.getDeviceSupportedFormats(
174 ChromiumCameraInfo.toSpecialCameraId(id)) :
175 VideoCaptureAndroid.getDeviceSupportedFormats(id);
179 static int getCaptureFormatWidth(VideoCapture.CaptureFormat format) {
180 return format.getWidth();
184 static int getCaptureFormatHeight(VideoCapture.CaptureFormat format) {
185 return format.getHeight();
189 static int getCaptureFormatFramerate(VideoCapture.CaptureFormat format) {
190 return format.getFramerate();
194 static int getCaptureFormatPixelFormat(VideoCapture.CaptureFormat format) {
195 return format.getPixelFormat();