• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.devcamera;
17 
18 import android.graphics.ImageFormat;
19 import android.graphics.Rect;
20 import android.hardware.camera2.CameraCharacteristics;
21 import android.hardware.camera2.CameraManager;
22 import android.hardware.camera2.CameraMetadata;
23 import android.hardware.camera2.params.StreamConfigurationMap;
24 import android.os.Build;
25 import android.util.Log;
26 import android.util.Size;
27 import android.util.SizeF;
28 
29 /**
30  * Caches (static) information about the first/main camera.
31  * Convenience functions represent data from CameraCharacteristics.
32  */
33 
34 public class CameraInfoCache {
35     private static final String TAG = "DevCamera_CAMINFO";
36 
37     public static final boolean IS_NEXUS_6 = "shamu".equalsIgnoreCase(Build.DEVICE);
38 
39     public int[] noiseModes;
40     public int[] edgeModes;
41 
42     private CameraCharacteristics mCameraCharacteristics;
43     private String mCameraId;
44     private Size mLargestYuvSize;
45     private Size mLargestJpegSize;
46     private Size mRawSize;
47     private Rect mActiveArea;
48     private Integer mSensorOrientation;
49     private Integer mRawFormat;
50     private int mBestFaceMode;
51     private int mHardwareLevel;
52 
53     /**
54      * Constructor.
55      */
CameraInfoCache(CameraManager cameraMgr, boolean useFrontCamera)56     public CameraInfoCache(CameraManager cameraMgr, boolean useFrontCamera) {
57         String[] cameralist;
58         try {
59             cameralist = cameraMgr.getCameraIdList();
60             for (String id : cameralist) {
61                 mCameraCharacteristics = cameraMgr.getCameraCharacteristics(id);
62                 Integer facing = mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
63                 if (facing == (useFrontCamera ? CameraMetadata.LENS_FACING_FRONT : CameraMetadata.LENS_FACING_BACK)) {
64                     mCameraId = id;
65                     break;
66                 }
67             }
68         } catch (Exception e) {
69             Log.e(TAG, "ERROR: Could not get camera ID list / no camera information is available: " + e);
70             return;
71         }
72         // Should have mCameraId as this point.
73         if (mCameraId == null) {
74             Log.e(TAG, "ERROR: Could not find a suitable rear or front camera.");
75             return;
76         }
77 
78         // Store YUV_420_888, JPEG, Raw info
79         StreamConfigurationMap map = mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
80         int[] formats = map.getOutputFormats();
81         long lowestStall = Long.MAX_VALUE;
82         for (int i = 0; i < formats.length; i++) {
83             if (formats[i] == ImageFormat.YUV_420_888) {
84                 mLargestYuvSize = returnLargestSize(map.getOutputSizes(formats[i]));
85             }
86             if (formats[i] == ImageFormat.JPEG) {
87                 mLargestJpegSize = returnLargestSize(map.getOutputSizes(formats[i]));
88             }
89             if (formats[i] == ImageFormat.RAW10 || formats[i] == ImageFormat.RAW_SENSOR) { // TODO: Add RAW12
90                 Size size = returnLargestSize(map.getOutputSizes(formats[i]));
91                 long stall = map.getOutputStallDuration(formats[i], size);
92                 if (stall < lowestStall) {
93                     mRawFormat = formats[i];
94                     mRawSize = size;
95                     lowestStall = stall;
96                 }
97             }
98         }
99 
100         mActiveArea = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
101 
102         // Compute best face mode.
103         int[] faceModes = mCameraCharacteristics.get(CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES);
104         for (int i=0; i<faceModes.length; i++) {
105             if (faceModes[i] > mBestFaceMode) {
106                 mBestFaceMode = faceModes[i];
107             }
108         }
109         edgeModes = mCameraCharacteristics.get(CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES);
110         noiseModes = mCameraCharacteristics.get(CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES);
111 
112         // Misc stuff.
113         mHardwareLevel = mCameraCharacteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
114 
115         mSensorOrientation = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
116     }
117 
supportedModesContains(int[] modes, int mode)118     boolean supportedModesContains(int[] modes, int mode) {
119         for (int m : modes) {
120             if (m == mode) return true;
121         }
122         return false;
123     }
124 
sensorOrientation()125     public int sensorOrientation() {
126         return mSensorOrientation;
127     }
128 
isCamera2FullModeAvailable()129     public boolean isCamera2FullModeAvailable() {
130         return isHardwareLevelAtLeast(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL);
131     }
132 
isHardwareLevelAtLeast(int level)133     public boolean isHardwareLevelAtLeast(int level) {
134         // Special-case LEGACY since it has numerical value 2
135         if (level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
136             // All devices are at least LEGACY
137             return true;
138         }
139         if (mHardwareLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
140             // Since level isn't LEGACY
141             return false;
142         }
143         // All other levels can be compared numerically
144         return mHardwareLevel >= level;
145     }
146 
isCapabilitySupported(int capability)147     public boolean isCapabilitySupported(int capability) {
148         int[] caps = mCameraCharacteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
149         for (int c: caps) {
150             if (c == capability) return true;
151         }
152         return false;
153     }
154 
getDiopterLow()155     public float getDiopterLow() {
156         return 0f; // Infinity
157     }
158 
getDiopterHi()159     public float getDiopterHi() {
160         Float minFocusDistance =
161                 mCameraCharacteristics.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);
162         // LEGACY devices don't report this, but they won't report focus distance anyway, so just
163         // default to zero
164         return (minFocusDistance == null) ? 0.0f : minFocusDistance;
165     }
166 
167     /**
168      * Calculate camera device horizontal and vertical fields of view.
169      *
170      * @return horizontal and vertical field of view, in degrees.
171      */
getFieldOfView()172     public float[] getFieldOfView() {
173         float[] availableFocalLengths =
174                 mCameraCharacteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS);
175         float focalLength = 4.5f; // mm, default from Nexus 6P
176         if (availableFocalLengths == null || availableFocalLengths.length == 0) {
177             Log.e(TAG, "No focal length reported by camera device, assuming default " +
178                     focalLength);
179         } else {
180             focalLength = availableFocalLengths[0];
181         }
182         SizeF physicalSize =
183                 mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE);
184         if (physicalSize == null) {
185             physicalSize = new SizeF(6.32f, 4.69f); // mm, default from Nexus 6P
186             Log.e(TAG, "No physical sensor dimensions reported by camera device, assuming default "
187                     + physicalSize);
188         }
189 
190         // Only active array is actually visible, so calculate fraction of physicalSize that it takes up
191         Size pixelArraySize = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE);
192         Rect activeArraySize = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
193 
194         float activeWidthFraction = activeArraySize.width() / (float) pixelArraySize.getWidth();
195         float activeHeightFraction = activeArraySize.height() / (float) pixelArraySize.getHeight();
196 
197         // Simple rectilinear lens field of view formula:
198         //   angle of view = 2 * arctan ( active size / (2 * focal length) )
199         float[] fieldOfView = new float[2];
200         fieldOfView[0] = (float) Math.toDegrees(
201                 2 * Math.atan(physicalSize.getWidth() * activeWidthFraction / 2 / focalLength));
202         fieldOfView[1] = (float) Math.toDegrees(
203                 2 * Math.atan(physicalSize.getHeight() * activeHeightFraction / 2 / focalLength));
204 
205         return fieldOfView;
206     }
207     /**
208      * Private utility function.
209      */
returnLargestSize(Size[] sizes)210     private Size returnLargestSize(Size[] sizes) {
211         Size largestSize = null;
212         int area = 0;
213         for (int j = 0; j < sizes.length; j++) {
214             if (sizes[j].getHeight() * sizes[j].getWidth() > area) {
215                 area = sizes[j].getHeight() * sizes[j].getWidth();
216                 largestSize = sizes[j];
217             }
218         }
219         return largestSize;
220     }
221 
bestFaceDetectionMode()222     public int bestFaceDetectionMode() {
223         return mBestFaceMode;
224     }
225 
faceOffsetX()226     public int faceOffsetX() {
227         return (mActiveArea.width() - mLargestYuvSize.getWidth()) / 2;
228     }
229 
faceOffsetY()230     public int faceOffsetY() {
231         return (mActiveArea.height() - mLargestYuvSize.getHeight()) / 2;
232     }
233 
activeAreaWidth()234     public int activeAreaWidth() {
235         return mActiveArea.width();
236     }
237 
activeAreaHeight()238     public int activeAreaHeight() {
239         return mActiveArea.height();
240     }
241 
getActiveAreaRect()242     public Rect getActiveAreaRect() {
243         return mActiveArea;
244     }
245 
getCameraId()246     public String getCameraId() {
247         return mCameraId;
248     }
249 
getPreviewSize()250     public Size getPreviewSize() {
251         float aspect = mLargestYuvSize.getWidth() / mLargestYuvSize.getHeight();
252         aspect = aspect > 1f ? aspect : 1f / aspect;
253         if (aspect > 1.6) {
254             return new Size(1920, 1080); // TODO: Check available resolutions.
255         }
256         if (isHardwareLevelAtLeast(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3)) {
257             // Bigger preview size for more advanced devices
258             return new Size(1440, 1080);
259         }
260         return new Size(1280, 960); // TODO: Check available resolutions.
261     }
262 
getJpegStreamSize()263     public Size getJpegStreamSize() {
264         return mLargestJpegSize;
265     }
266 
getYuvStream1Size()267     public Size getYuvStream1Size() {
268         return mLargestYuvSize;
269     }
270 
getYuvStream2Size()271     public Size getYuvStream2Size() {
272         return new Size(320, 240);
273     }
274 
rawAvailable()275     public boolean rawAvailable() {
276         return mRawSize != null;
277     }
isYuvReprocessingAvailable()278     public boolean isYuvReprocessingAvailable() {
279         return isCapabilitySupported(
280                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING);
281     }
282 
getRawFormat()283     public Integer getRawFormat() {
284         return mRawFormat;
285     }
286 
getRawStreamSize()287     public Size getRawStreamSize() {
288         return mRawSize;
289     }
290 
291 }
292