1 /*
2  *  Copyright 2015 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 package org.webrtc;
12 
13 import android.os.SystemClock;
14 import android.support.annotation.Nullable;
15 import java.util.ArrayList;
16 import java.util.List;
17 import org.webrtc.CameraEnumerationAndroid.CaptureFormat;
18 
19 @SuppressWarnings("deprecation")
20 public class Camera1Enumerator implements CameraEnumerator {
21   private final static String TAG = "Camera1Enumerator";
22   // Each entry contains the supported formats for corresponding camera index. The formats for all
23   // cameras are enumerated on the first call to getSupportedFormats(), and cached for future
24   // reference.
25   private static List<List<CaptureFormat>> cachedSupportedFormats;
26 
27   private final boolean captureToTexture;
28 
Camera1Enumerator()29   public Camera1Enumerator() {
30     this(true /* captureToTexture */);
31   }
32 
Camera1Enumerator(boolean captureToTexture)33   public Camera1Enumerator(boolean captureToTexture) {
34     this.captureToTexture = captureToTexture;
35   }
36 
37   // Returns device names that can be used to create a new VideoCapturerAndroid.
38   @Override
getDeviceNames()39   public String[] getDeviceNames() {
40     ArrayList<String> namesList = new ArrayList<>();
41     for (int i = 0; i < android.hardware.Camera.getNumberOfCameras(); ++i) {
42       String name = getDeviceName(i);
43       if (name != null) {
44         namesList.add(name);
45         Logging.d(TAG, "Index: " + i + ". " + name);
46       } else {
47         Logging.e(TAG, "Index: " + i + ". Failed to query camera name.");
48       }
49     }
50     String[] namesArray = new String[namesList.size()];
51     return namesList.toArray(namesArray);
52   }
53 
54   @Override
isFrontFacing(String deviceName)55   public boolean isFrontFacing(String deviceName) {
56     android.hardware.Camera.CameraInfo info = getCameraInfo(getCameraIndex(deviceName));
57     return info != null && info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT;
58   }
59 
60   @Override
isBackFacing(String deviceName)61   public boolean isBackFacing(String deviceName) {
62     android.hardware.Camera.CameraInfo info = getCameraInfo(getCameraIndex(deviceName));
63     return info != null && info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK;
64   }
65 
66   @Override
getSupportedFormats(String deviceName)67   public List<CaptureFormat> getSupportedFormats(String deviceName) {
68     return getSupportedFormats(getCameraIndex(deviceName));
69   }
70 
71   @Override
createCapturer( String deviceName, CameraVideoCapturer.CameraEventsHandler eventsHandler)72   public CameraVideoCapturer createCapturer(
73       String deviceName, CameraVideoCapturer.CameraEventsHandler eventsHandler) {
74     return new Camera1Capturer(deviceName, eventsHandler, captureToTexture);
75   }
76 
getCameraInfo(int index)77   private static @Nullable android.hardware.Camera.CameraInfo getCameraInfo(int index) {
78     android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
79     try {
80       android.hardware.Camera.getCameraInfo(index, info);
81     } catch (Exception e) {
82       Logging.e(TAG, "getCameraInfo failed on index " + index, e);
83       return null;
84     }
85     return info;
86   }
87 
getSupportedFormats(int cameraId)88   static synchronized List<CaptureFormat> getSupportedFormats(int cameraId) {
89     if (cachedSupportedFormats == null) {
90       cachedSupportedFormats = new ArrayList<List<CaptureFormat>>();
91       for (int i = 0; i < android.hardware.Camera.getNumberOfCameras(); ++i) {
92         cachedSupportedFormats.add(enumerateFormats(i));
93       }
94     }
95     return cachedSupportedFormats.get(cameraId);
96   }
97 
enumerateFormats(int cameraId)98   private static List<CaptureFormat> enumerateFormats(int cameraId) {
99     Logging.d(TAG, "Get supported formats for camera index " + cameraId + ".");
100     final long startTimeMs = SystemClock.elapsedRealtime();
101     final android.hardware.Camera.Parameters parameters;
102     android.hardware.Camera camera = null;
103     try {
104       Logging.d(TAG, "Opening camera with index " + cameraId);
105       camera = android.hardware.Camera.open(cameraId);
106       parameters = camera.getParameters();
107     } catch (RuntimeException e) {
108       Logging.e(TAG, "Open camera failed on camera index " + cameraId, e);
109       return new ArrayList<CaptureFormat>();
110     } finally {
111       if (camera != null) {
112         camera.release();
113       }
114     }
115 
116     final List<CaptureFormat> formatList = new ArrayList<CaptureFormat>();
117     try {
118       int minFps = 0;
119       int maxFps = 0;
120       final List<int[]> listFpsRange = parameters.getSupportedPreviewFpsRange();
121       if (listFpsRange != null) {
122         // getSupportedPreviewFpsRange() returns a sorted list. Take the fps range
123         // corresponding to the highest fps.
124         final int[] range = listFpsRange.get(listFpsRange.size() - 1);
125         minFps = range[android.hardware.Camera.Parameters.PREVIEW_FPS_MIN_INDEX];
126         maxFps = range[android.hardware.Camera.Parameters.PREVIEW_FPS_MAX_INDEX];
127       }
128       for (android.hardware.Camera.Size size : parameters.getSupportedPreviewSizes()) {
129         formatList.add(new CaptureFormat(size.width, size.height, minFps, maxFps));
130       }
131     } catch (Exception e) {
132       Logging.e(TAG, "getSupportedFormats() failed on camera index " + cameraId, e);
133     }
134 
135     final long endTimeMs = SystemClock.elapsedRealtime();
136     Logging.d(TAG, "Get supported formats for camera index " + cameraId + " done."
137             + " Time spent: " + (endTimeMs - startTimeMs) + " ms.");
138     return formatList;
139   }
140 
141   // Convert from android.hardware.Camera.Size to Size.
convertSizes(List<android.hardware.Camera.Size> cameraSizes)142   static List<Size> convertSizes(List<android.hardware.Camera.Size> cameraSizes) {
143     final List<Size> sizes = new ArrayList<Size>();
144     for (android.hardware.Camera.Size size : cameraSizes) {
145       sizes.add(new Size(size.width, size.height));
146     }
147     return sizes;
148   }
149 
150   // Convert from int[2] to CaptureFormat.FramerateRange.
convertFramerates(List<int[]> arrayRanges)151   static List<CaptureFormat.FramerateRange> convertFramerates(List<int[]> arrayRanges) {
152     final List<CaptureFormat.FramerateRange> ranges = new ArrayList<CaptureFormat.FramerateRange>();
153     for (int[] range : arrayRanges) {
154       ranges.add(new CaptureFormat.FramerateRange(
155           range[android.hardware.Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
156           range[android.hardware.Camera.Parameters.PREVIEW_FPS_MAX_INDEX]));
157     }
158     return ranges;
159   }
160 
161   // Returns the camera index for camera with name |deviceName|, or throws IllegalArgumentException
162   // if no such camera can be found.
getCameraIndex(String deviceName)163   static int getCameraIndex(String deviceName) {
164     Logging.d(TAG, "getCameraIndex: " + deviceName);
165     for (int i = 0; i < android.hardware.Camera.getNumberOfCameras(); ++i) {
166       if (deviceName.equals(getDeviceName(i))) {
167         return i;
168       }
169     }
170     throw new IllegalArgumentException("No such camera: " + deviceName);
171   }
172 
173   // Returns the name of the camera with camera index. Returns null if the
174   // camera can not be used.
getDeviceName(int index)175   static @Nullable String getDeviceName(int index) {
176     android.hardware.Camera.CameraInfo info = getCameraInfo(index);
177     if (info == null) {
178       return null;
179     }
180 
181     String facing =
182         (info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT) ? "front" : "back";
183     return "Camera " + index + ", Facing " + facing + ", Orientation " + info.orientation;
184   }
185 }
186