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.annotation.SuppressLint 19 import android.hardware.camera2.CameraCharacteristics 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.Recorder 31 import androidx.camera.video.VideoCapture 32 import com.google.jetpackcamera.settings.model.DynamicRange 33 import com.google.jetpackcamera.settings.model.ImageOutputFormat 34 import com.google.jetpackcamera.settings.model.LensFacing 35 36 val CameraInfo.appLensFacing: LensFacing 37 get() = when (this.lensFacing) { 38 CameraSelector.LENS_FACING_FRONT -> LensFacing.FRONT 39 CameraSelector.LENS_FACING_BACK -> LensFacing.BACK 40 else -> throw IllegalArgumentException( 41 "Unknown CameraSelector.LensFacing -> LensFacing mapping. " + 42 "[CameraSelector.LensFacing: ${this.lensFacing}]" 43 ) 44 } 45 toSupportedAppDynamicRangenull46fun CXDynamicRange.toSupportedAppDynamicRange(): DynamicRange? { 47 return when (this) { 48 CXDynamicRange.SDR -> DynamicRange.SDR 49 CXDynamicRange.HLG_10_BIT -> DynamicRange.HLG10 50 // All other dynamic ranges unsupported. Return null. 51 else -> null 52 } 53 } 54 toCXDynamicRangenull55fun DynamicRange.toCXDynamicRange(): CXDynamicRange { 56 return when (this) { 57 com.google.jetpackcamera.settings.model.DynamicRange.SDR -> CXDynamicRange.SDR 58 com.google.jetpackcamera.settings.model.DynamicRange.HLG10 -> CXDynamicRange.HLG_10_BIT 59 } 60 } 61 toCameraSelectornull62fun LensFacing.toCameraSelector(): CameraSelector = when (this) { 63 LensFacing.FRONT -> CameraSelector.DEFAULT_FRONT_CAMERA 64 LensFacing.BACK -> CameraSelector.DEFAULT_BACK_CAMERA 65 } 66 67 @SuppressLint("RestrictedApi") CameraSelectornull68fun CameraSelector.toAppLensFacing(): LensFacing = when (this.lensFacing) { 69 CameraSelector.LENS_FACING_FRONT -> LensFacing.FRONT 70 CameraSelector.LENS_FACING_BACK -> LensFacing.BACK 71 else -> throw IllegalArgumentException( 72 "Unknown CameraSelector -> LensFacing mapping. [CameraSelector: $this]" 73 ) 74 } 75 76 val CameraInfo.sensorLandscapeRatio: Float 77 @OptIn(ExperimentalCamera2Interop::class) 78 get() = Camera2CameraInfo.from(this) 79 .getCameraCharacteristic(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE) sensorRectnull80 ?.let { sensorRect -> 81 if (sensorRect.width() > sensorRect.height()) { 82 sensorRect.width().toFloat() / sensorRect.height() 83 } else { 84 sensorRect.height().toFloat() / sensorRect.width() 85 } 86 } ?: Float.NaN 87 toAppImageFormatnull88fun Int.toAppImageFormat(): ImageOutputFormat? { 89 return when (this) { 90 ImageCapture.OUTPUT_FORMAT_JPEG -> ImageOutputFormat.JPEG 91 ImageCapture.OUTPUT_FORMAT_JPEG_ULTRA_HDR -> ImageOutputFormat.JPEG_ULTRA_HDR 92 // All other output formats unsupported. Return null. 93 else -> null 94 } 95 } 96 97 /** 98 * Checks if preview stabilization is supported by the device. 99 * 100 */ 101 val CameraInfo.isPreviewStabilizationSupported: Boolean 102 get() = Preview.getPreviewCapabilities(this).isStabilizationSupported 103 104 /** 105 * Checks if video stabilization is supported by the device. 106 * 107 */ 108 val CameraInfo.isVideoStabilizationSupported: Boolean 109 get() = Recorder.getVideoCapabilities(this).isStabilizationSupported 110 CameraInfonull111fun CameraInfo.filterSupportedFixedFrameRates(desired: Set<Int>): Set<Int> { 112 return buildSet { 113 this@filterSupportedFixedFrameRates.supportedFrameRateRanges.forEach { e -> 114 if (e.upper == e.lower && desired.contains(e.upper)) { 115 add(e.upper) 116 } 117 } 118 } 119 } 120 121 val CameraInfo.supportedImageFormats: Set<ImageOutputFormat> 122 get() = ImageCapture.getImageCaptureCapabilities(this).supportedOutputFormats 123 .mapNotNull(Int::toAppImageFormat) 124 .toSet() 125 UseCaseGroupnull126fun UseCaseGroup.getVideoCapture() = getUseCaseOrNull<VideoCapture<Recorder>>() 127 fun UseCaseGroup.getImageCapture() = getUseCaseOrNull<ImageCapture>() 128 129 private inline fun <reified T : UseCase> UseCaseGroup.getUseCaseOrNull(): T? { 130 return useCases.filterIsInstance<T>().singleOrNull() 131 } 132