1 /* <lambda>null2 * Copyright 2021 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 17 package androidx.camera.camera2.pipe.integration.impl 18 19 import android.graphics.ImageFormat 20 import android.graphics.SurfaceTexture 21 import android.hardware.camera2.CameraCharacteristics 22 import android.hardware.camera2.CameraDevice 23 import android.os.Build 24 import android.util.Size 25 import android.view.Surface 26 import androidx.annotation.GuardedBy 27 import androidx.camera.camera2.pipe.core.Log.error 28 import androidx.camera.camera2.pipe.core.Log.warn 29 import androidx.camera.camera2.pipe.integration.adapter.CameraUseCaseAdapter 30 import androidx.camera.camera2.pipe.integration.compat.workaround.getSupportedRepeatingSurfaceSizes 31 import androidx.camera.core.UseCase 32 import androidx.camera.core.impl.CaptureConfig 33 import androidx.camera.core.impl.Config 34 import androidx.camera.core.impl.DeferrableSurface 35 import androidx.camera.core.impl.ImageFormatConstants 36 import androidx.camera.core.impl.ImageInputConfig 37 import androidx.camera.core.impl.ImmediateSurface 38 import androidx.camera.core.impl.MutableOptionsBundle 39 import androidx.camera.core.impl.SessionConfig 40 import androidx.camera.core.impl.SessionConfig.CloseableErrorListener 41 import androidx.camera.core.impl.StreamSpec 42 import androidx.camera.core.impl.UseCaseConfig 43 import androidx.camera.core.impl.UseCaseConfig.OPTION_CAPTURE_TYPE 44 import androidx.camera.core.impl.UseCaseConfig.OPTION_SESSION_CONFIG_UNPACKER 45 import androidx.camera.core.impl.UseCaseConfigFactory 46 import androidx.camera.core.impl.UseCaseConfigFactory.CaptureType 47 import androidx.camera.core.impl.utils.executor.CameraXExecutors 48 import androidx.camera.core.internal.TargetConfig.OPTION_TARGET_NAME 49 import kotlin.math.min 50 51 private val DEFAULT_PREVIEW_SIZE = Size(0, 0) 52 53 /** 54 * A [UseCase] used to issue repeating requests when only [androidx.camera.core.ImageCapture] is 55 * enabled, since taking a picture may require a repeating surface to perform pre-capture checks, 56 * mainly around 3A. 57 */ 58 public class MeteringRepeating( 59 private val cameraProperties: CameraProperties, 60 config: MeteringRepeatingConfig, 61 private val displayInfoManager: DisplayInfoManager 62 ) : UseCase(config) { 63 64 private val meteringSurfaceSize = getProperPreviewSize() 65 66 private val deferrableSurfaceLock = Any() 67 68 private var closeableErrorListener: CloseableErrorListener? = null 69 70 @GuardedBy("deferrableSurfaceLock") private var deferrableSurface: DeferrableSurface? = null 71 72 override fun getDefaultConfig( 73 applyDefaultConfig: Boolean, 74 factory: UseCaseConfigFactory 75 ): MeteringRepeatingConfig = Builder(cameraProperties, displayInfoManager).useCaseConfig 76 77 override fun getUseCaseConfigBuilder(config: Config): Builder = 78 Builder(cameraProperties, displayInfoManager) 79 80 override fun onSuggestedStreamSpecUpdated( 81 primaryStreamSpec: StreamSpec, 82 secondaryStreamSpec: StreamSpec?, 83 ): StreamSpec { 84 updateSessionConfig(listOf(createPipeline(meteringSurfaceSize).build())) 85 notifyActive() 86 return primaryStreamSpec.toBuilder().setResolution(meteringSurfaceSize).build() 87 } 88 89 override fun onUnbind() { 90 synchronized(deferrableSurfaceLock) { 91 deferrableSurface?.close() 92 deferrableSurface = null 93 } 94 } 95 96 /** Sets up the use case's session configuration, mainly its [DeferrableSurface]. */ 97 public fun setupSession() { 98 // The suggested stream spec passed to `updateSuggestedStreamSpec` doesn't matter since 99 // this use case uses the min preview size. 100 updateSuggestedStreamSpec(StreamSpec.builder(DEFAULT_PREVIEW_SIZE).build(), null) 101 } 102 103 private fun createPipeline(resolution: Size): SessionConfig.Builder { 104 synchronized(deferrableSurfaceLock) { 105 val surfaceTexture = 106 SurfaceTexture(0).apply { 107 setDefaultBufferSize(resolution.width, resolution.height) 108 } 109 val surface = Surface(surfaceTexture) 110 111 deferrableSurface?.close() 112 deferrableSurface = ImmediateSurface(surface, resolution, imageFormat) 113 deferrableSurface!! 114 .terminationFuture 115 .addListener( 116 { 117 surface.release() 118 surfaceTexture.release() 119 }, 120 CameraXExecutors.directExecutor() 121 ) 122 } 123 124 // Closes the old error listener if there is 125 closeableErrorListener?.close() 126 val errorListener = CloseableErrorListener { _, _ -> 127 updateSessionConfig(listOf(createPipeline(resolution).build())) 128 notifyReset() 129 } 130 closeableErrorListener = errorListener 131 132 return SessionConfig.Builder.createFrom(MeteringRepeatingConfig(), resolution).apply { 133 setTemplateType(CameraDevice.TEMPLATE_PREVIEW) 134 addSurface(deferrableSurface!!) 135 setErrorListener(errorListener) 136 } 137 } 138 139 private fun CameraProperties.getOutputSizes(): Array<Size>? { 140 val map = 141 metadata[CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP] 142 ?: run { 143 error { "Can not retrieve SCALER_STREAM_CONFIGURATION_MAP." } 144 return null 145 } 146 147 return if (Build.VERSION.SDK_INT < 23) { 148 // ImageFormat.PRIVATE is only public after Android level 23. Therefore, use 149 // SurfaceTexture.class to get the supported output sizes before Android level 23. 150 map.getOutputSizes(SurfaceTexture::class.java) 151 } else { 152 map.getOutputSizes(ImageFormat.PRIVATE) 153 } 154 } 155 156 private fun getProperPreviewSize(): Size { 157 var outputSizes = cameraProperties.getOutputSizes() 158 159 if (outputSizes == null) { 160 error { "Can not get output size list." } 161 return DEFAULT_PREVIEW_SIZE 162 } 163 164 if (outputSizes.isEmpty()) { 165 error { "Output sizes empty" } 166 return DEFAULT_PREVIEW_SIZE 167 } 168 169 val supportedOutputSizes = outputSizes.getSupportedRepeatingSurfaceSizes() 170 171 if (supportedOutputSizes.isNotEmpty()) { 172 outputSizes = supportedOutputSizes 173 } else { 174 warn { "No supported output size list, fallback to current list" } 175 } 176 177 outputSizes.sortBy { size -> size.width.toLong() * size.height.toLong() } 178 179 // Find maximum supported resolution that is <= min(VGA, display resolution) 180 // Using minimum supported size could cause some issue on certain devices. 181 val previewSize = displayInfoManager.getPreviewSize() 182 val maxSizeProduct = 183 min(640L * 480L, previewSize.width.toLong() * previewSize.height.toLong()) 184 185 var previousSize: Size? = null 186 for (outputSize in outputSizes) { 187 val product = outputSize.width.toLong() * outputSize.height.toLong() 188 if (product == maxSizeProduct) { 189 return outputSize 190 } else if (product > maxSizeProduct) { 191 // Returns the maximum supported resolution that is <= min(VGA, display resolution) 192 // if it is found 193 return previousSize ?: break 194 } 195 previousSize = outputSize 196 } 197 198 // If not found, return the minimum size. 199 return previousSize ?: outputSizes[0] 200 } 201 202 public class MeteringRepeatingConfig : UseCaseConfig<MeteringRepeating>, ImageInputConfig { 203 private val config = 204 MutableOptionsBundle.create().apply { 205 insertOption( 206 OPTION_SESSION_CONFIG_UNPACKER, 207 CameraUseCaseAdapter.DefaultSessionOptionsUnpacker 208 ) 209 insertOption(OPTION_TARGET_NAME, "MeteringRepeating") 210 insertOption(OPTION_CAPTURE_TYPE, CaptureType.METERING_REPEATING) 211 } 212 213 override fun getCaptureType(): CaptureType = 214 UseCaseConfigFactory.CaptureType.METERING_REPEATING 215 216 override fun getConfig(): MutableOptionsBundle = config 217 218 override fun getInputFormat(): Int = 219 ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE 220 } 221 222 public class Builder( 223 private val cameraProperties: CameraProperties, 224 private val displayInfoManager: DisplayInfoManager 225 ) : UseCaseConfig.Builder<MeteringRepeating, MeteringRepeatingConfig, Builder> { 226 227 override fun getMutableConfig(): MutableOptionsBundle = MutableOptionsBundle.create() 228 229 override fun getUseCaseConfig(): MeteringRepeatingConfig = MeteringRepeatingConfig() 230 231 override fun setTargetClass(targetClass: Class<MeteringRepeating>): Builder = this 232 233 override fun setTargetName(targetName: String): Builder = this 234 235 override fun setDefaultSessionConfig(sessionConfig: SessionConfig): Builder = this 236 237 override fun setDefaultCaptureConfig(captureConfig: CaptureConfig): Builder = this 238 239 override fun setSessionOptionUnpacker( 240 optionUnpacker: SessionConfig.OptionUnpacker 241 ): Builder = this 242 243 override fun setCaptureOptionUnpacker( 244 optionUnpacker: CaptureConfig.OptionUnpacker 245 ): Builder = this 246 247 override fun setSurfaceOccupancyPriority(priority: Int): Builder = this 248 249 override fun setZslDisabled(disabled: Boolean): Builder = this 250 251 override fun setHighResolutionDisabled(disabled: Boolean): Builder = this 252 253 override fun setCaptureType(captureType: UseCaseConfigFactory.CaptureType): Builder = this 254 255 override fun build(): MeteringRepeating { 256 return MeteringRepeating(cameraProperties, useCaseConfig, displayInfoManager) 257 } 258 } 259 } 260