Home | History | Annotate | Download | only in media
      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.util.Log;
     10 
     11 import org.chromium.base.CalledByNative;
     12 import org.chromium.base.JNINamespace;
     13 // Needed for jni_generator.py to guess correctly the origin of
     14 // VideoCapture.CaptureFormat.
     15 import 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")
     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 
     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