1 /* <lambda>null2 * Copyright (C) 2024 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.google.jetpackcamera.core.camera 17 18 import android.hardware.camera2.CameraCharacteristics 19 import android.hardware.camera2.CameraMetadata 20 import androidx.annotation.OptIn 21 import androidx.camera.camera2.interop.Camera2CameraInfo 22 import androidx.camera.camera2.interop.ExperimentalCamera2Interop 23 import androidx.camera.core.CameraInfo 24 import androidx.camera.core.CameraSelector 25 import androidx.camera.core.DynamicRange as CXDynamicRange 26 import androidx.camera.core.ImageCapture 27 import androidx.camera.core.Preview 28 import androidx.camera.core.UseCase 29 import androidx.camera.core.UseCaseGroup 30 import androidx.camera.video.Quality 31 import androidx.camera.video.Recorder 32 import androidx.camera.video.VideoCapture 33 import com.google.jetpackcamera.settings.model.DynamicRange 34 import com.google.jetpackcamera.settings.model.ImageOutputFormat 35 import com.google.jetpackcamera.settings.model.LensFacing 36 import com.google.jetpackcamera.settings.model.VideoQuality 37 import com.google.jetpackcamera.settings.model.VideoQuality.FHD 38 import com.google.jetpackcamera.settings.model.VideoQuality.HD 39 import com.google.jetpackcamera.settings.model.VideoQuality.SD 40 import com.google.jetpackcamera.settings.model.VideoQuality.UHD 41 import com.google.jetpackcamera.settings.model.VideoQuality.UNSPECIFIED 42 43 val CameraInfo.appLensFacing: LensFacing 44 get() = when (this.lensFacing) { 45 CameraSelector.LENS_FACING_FRONT -> LensFacing.FRONT 46 CameraSelector.LENS_FACING_BACK -> LensFacing.BACK 47 else -> throw IllegalArgumentException( 48 "Unknown CameraSelector.LensFacing -> LensFacing mapping. " + 49 "[CameraSelector.LensFacing: ${this.lensFacing}]" 50 ) 51 } 52 toSupportedAppDynamicRangenull53fun CXDynamicRange.toSupportedAppDynamicRange(): DynamicRange? { 54 return when (this) { 55 CXDynamicRange.SDR -> DynamicRange.SDR 56 CXDynamicRange.HLG_10_BIT -> DynamicRange.HLG10 57 // All other dynamic ranges unsupported. Return null. 58 else -> null 59 } 60 } 61 toCXDynamicRangenull62fun DynamicRange.toCXDynamicRange(): CXDynamicRange { 63 return when (this) { 64 com.google.jetpackcamera.settings.model.DynamicRange.SDR -> CXDynamicRange.SDR 65 com.google.jetpackcamera.settings.model.DynamicRange.HLG10 -> CXDynamicRange.HLG_10_BIT 66 } 67 } 68 toCameraSelectornull69fun LensFacing.toCameraSelector(): CameraSelector = when (this) { 70 LensFacing.FRONT -> CameraSelector.DEFAULT_FRONT_CAMERA 71 LensFacing.BACK -> CameraSelector.DEFAULT_BACK_CAMERA 72 } 73 74 val CameraInfo.sensorLandscapeRatio: Float 75 @OptIn(ExperimentalCamera2Interop::class) 76 get() = Camera2CameraInfo.from(this) 77 .getCameraCharacteristic(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE) sensorRectnull78 ?.let { sensorRect -> 79 if (sensorRect.width() > sensorRect.height()) { 80 sensorRect.width().toFloat() / sensorRect.height() 81 } else { 82 sensorRect.height().toFloat() / sensorRect.width() 83 } 84 } ?: Float.NaN 85 toAppImageFormatnull86fun Int.toAppImageFormat(): ImageOutputFormat? { 87 return when (this) { 88 ImageCapture.OUTPUT_FORMAT_JPEG -> ImageOutputFormat.JPEG 89 ImageCapture.OUTPUT_FORMAT_JPEG_ULTRA_HDR -> ImageOutputFormat.JPEG_ULTRA_HDR 90 // All other output formats unsupported. Return null. 91 else -> null 92 } 93 } 94 VideoQualitynull95fun VideoQuality.toQuality(): Quality? { 96 return when (this) { 97 SD -> Quality.SD 98 HD -> Quality.HD 99 FHD -> Quality.FHD 100 UHD -> Quality.UHD 101 UNSPECIFIED -> null 102 } 103 } 104 Qualitynull105fun Quality.toVideoQuality(): VideoQuality { 106 return when (this) { 107 Quality.SD -> SD 108 Quality.HD -> HD 109 Quality.FHD -> FHD 110 Quality.UHD -> UHD 111 else -> UNSPECIFIED 112 } 113 } 114 115 /** 116 * Checks if preview stabilization is supported by the device. 117 * 118 */ 119 val CameraInfo.isPreviewStabilizationSupported: Boolean 120 get() = Preview.getPreviewCapabilities(this).isStabilizationSupported 121 122 /** 123 * Checks if video stabilization is supported by the device. 124 * 125 */ 126 val CameraInfo.isVideoStabilizationSupported: Boolean 127 get() = Recorder.getVideoCapabilities(this).isStabilizationSupported 128 129 /** Checks if optical image stabilization (OIS) is supported by the device. */ 130 val CameraInfo.isOpticalStabilizationSupported: Boolean 131 @OptIn(ExperimentalCamera2Interop::class) 132 get() = Camera2CameraInfo.from(this) 133 .getCameraCharacteristic(CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION) 134 ?.contains( 135 CameraMetadata.LENS_OPTICAL_STABILIZATION_MODE_ON 136 ) ?: false 137 138 val CameraInfo.isLowLightBoostSupported: Boolean 139 @OptIn(ExperimentalCamera2Interop::class) 140 get() = Camera2CameraInfo.from(this) 141 .getCameraCharacteristic(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES) 142 ?.contains( 143 CameraMetadata.CONTROL_AE_MODE_ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY 144 ) ?: false 145 CameraInfonull146fun CameraInfo.filterSupportedFixedFrameRates(desired: Set<Int>): Set<Int> { 147 return buildSet { 148 this@filterSupportedFixedFrameRates.supportedFrameRateRanges.forEach { e -> 149 if (e.upper == e.lower && desired.contains(e.upper)) { 150 add(e.upper) 151 } 152 } 153 } 154 } 155 156 val CameraInfo.supportedImageFormats: Set<ImageOutputFormat> 157 get() = ImageCapture.getImageCaptureCapabilities(this).supportedOutputFormats 158 .mapNotNull(Int::toAppImageFormat) 159 .toSet() 160 UseCaseGroupnull161fun UseCaseGroup.getVideoCapture() = getUseCaseOrNull<VideoCapture<Recorder>>() 162 fun UseCaseGroup.getImageCapture() = getUseCaseOrNull<ImageCapture>() 163 164 private inline fun <reified T : UseCase> UseCaseGroup.getUseCaseOrNull(): T? { 165 return useCases.filterIsInstance<T>().singleOrNull() 166 } 167