Home | History | Annotate | Download | only in devcamera
      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