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 */ 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 118 boolean supportedModesContains(int[] modes, int mode) { 119 for (int m : modes) { 120 if (m == mode) return true; 121 } 122 return false; 123 } 124 125 public int sensorOrientation() { 126 return mSensorOrientation; 127 } 128 129 public boolean isCamera2FullModeAvailable() { 130 return isHardwareLevelAtLeast(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL); 131 } 132 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 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 155 public float getDiopterLow() { 156 return 0f; // Infinity 157 } 158 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 */ 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 */ 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 222 public int bestFaceDetectionMode() { 223 return mBestFaceMode; 224 } 225 226 public int faceOffsetX() { 227 return (mActiveArea.width() - mLargestYuvSize.getWidth()) / 2; 228 } 229 230 public int faceOffsetY() { 231 return (mActiveArea.height() - mLargestYuvSize.getHeight()) / 2; 232 } 233 234 public int activeAreaWidth() { 235 return mActiveArea.width(); 236 } 237 238 public int activeAreaHeight() { 239 return mActiveArea.height(); 240 } 241 242 public Rect getActiveAreaRect() { 243 return mActiveArea; 244 } 245 246 public String getCameraId() { 247 return mCameraId; 248 } 249 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 263 public Size getJpegStreamSize() { 264 return mLargestJpegSize; 265 } 266 267 public Size getYuvStream1Size() { 268 return mLargestYuvSize; 269 } 270 271 public Size getYuvStream2Size() { 272 return new Size(320, 240); 273 } 274 275 public boolean rawAvailable() { 276 return mRawSize != null; 277 } 278 public boolean isYuvReprocessingAvailable() { 279 return isCapabilitySupported( 280 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING); 281 } 282 283 public Integer getRawFormat() { 284 return mRawFormat; 285 } 286 287 public Size getRawStreamSize() { 288 return mRawSize; 289 } 290 291 } 292