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.adapter 18 19 import android.hardware.camera2.CameraDevice 20 import android.media.MediaCodec 21 import android.util.Range 22 import androidx.annotation.VisibleForTesting 23 import androidx.camera.camera2.pipe.OutputStream 24 import androidx.camera.camera2.pipe.core.Log 25 import androidx.camera.camera2.pipe.core.Log.debug 26 import androidx.camera.camera2.pipe.integration.impl.Camera2ImplConfig 27 import androidx.camera.camera2.pipe.integration.impl.STREAM_USE_HINT_OPTION 28 import androidx.camera.camera2.pipe.integration.internal.StreamUseCaseUtil 29 import androidx.camera.core.ImageAnalysis 30 import androidx.camera.core.ImageCapture 31 import androidx.camera.core.Preview 32 import androidx.camera.core.UseCase 33 import androidx.camera.core.impl.DeferrableSurface 34 import androidx.camera.core.impl.SessionConfig 35 import androidx.camera.core.impl.StreamSpec 36 import androidx.camera.core.impl.UseCaseConfig 37 import androidx.camera.core.streamsharing.StreamSharing 38 import java.util.Collections 39 import kotlinx.coroutines.CoroutineScope 40 import kotlinx.coroutines.Dispatchers 41 import kotlinx.coroutines.launch 42 43 /** 44 * Aggregate the SessionConfig from a List of [UseCase]s, and provide a validated SessionConfig for 45 * operation. 46 */ 47 public class SessionConfigAdapter( 48 private val useCases: Collection<UseCase>, 49 private val sessionProcessorConfig: SessionConfig? = null, 50 private val isPrimary: Boolean = true, 51 ) { 52 public val isSessionProcessorEnabled: Boolean = sessionProcessorConfig != null 53 public val surfaceToStreamUseCaseMap: Map<DeferrableSurface, Long> by lazy { 54 val sessionConfigs = mutableListOf<SessionConfig>() 55 val useCaseConfigs = mutableListOf<UseCaseConfig<*>>() 56 for (useCase in useCases) { 57 sessionConfigs.add(useCase.getSessionConfig(isPrimary)) 58 useCaseConfigs.add(useCase.currentConfig) 59 } 60 getSurfaceToStreamUseCaseMapping(sessionConfigs, useCaseConfigs) 61 } 62 public val surfaceToStreamUseHintMap: Map<DeferrableSurface, Long> by lazy { 63 val sessionConfigs = useCases.map { it.getSessionConfig(isPrimary) } 64 getSurfaceToStreamUseHintMapping(sessionConfigs) 65 } 66 private val validatingBuilder: SessionConfig.ValidatingBuilder by lazy { 67 val validatingBuilder = SessionConfig.ValidatingBuilder() 68 69 for (useCase in useCases) { 70 validatingBuilder.add(useCase.getSessionConfig(isPrimary)) 71 } 72 73 if (sessionProcessorConfig != null) { 74 validatingBuilder.clearSurfaces() 75 validatingBuilder.add(sessionProcessorConfig) 76 } 77 78 validatingBuilder 79 } 80 81 private val sessionConfig: SessionConfig by lazy { 82 check(validatingBuilder.isValid) 83 84 validatingBuilder.build() 85 } 86 87 public val deferrableSurfaces: List<DeferrableSurface> by lazy { 88 check(validatingBuilder.isValid) 89 90 sessionConfig.postviewOutputConfig?.let { 91 Collections.unmodifiableList( 92 mutableListOf<DeferrableSurface>().apply { 93 addAll(sessionConfig.surfaces) 94 add(it.surface) 95 } 96 ) 97 } ?: sessionConfig.surfaces 98 } 99 100 public fun getValidSessionConfigOrNull(): SessionConfig? { 101 return if (isSessionConfigValid()) sessionConfig else null 102 } 103 104 public fun isSessionConfigValid(): Boolean { 105 return validatingBuilder.isValid 106 } 107 108 public fun reportSurfaceInvalid(deferrableSurface: DeferrableSurface) { 109 debug { "Unavailable $deferrableSurface, notify SessionConfig invalid" } 110 111 // Only report error to one SessionConfig, CameraInternal#onUseCaseReset() 112 // will handle the other failed Surfaces if there are any. 113 val sessionConfig = 114 useCases 115 .firstOrNull { useCase -> 116 val sessionConfig = useCase.getSessionConfig(isPrimary) 117 sessionConfig.surfaces.contains(deferrableSurface) 118 } 119 ?.sessionConfig 120 121 CoroutineScope(Dispatchers.Main.immediate).launch { 122 // The error listener is used to notify the UseCase to recreate the pipeline, 123 // and the create pipeline task would be executed on the main thread. 124 sessionConfig?.errorListener?.apply { 125 onError(sessionConfig, SessionConfig.SessionError.SESSION_ERROR_SURFACE_NEEDS_RESET) 126 } 127 } 128 } 129 130 public fun getExpectedFrameRateRange(): Range<Int>? { 131 return if ( 132 isSessionConfigValid() && 133 sessionConfig.expectedFrameRateRange != StreamSpec.FRAME_RATE_RANGE_UNSPECIFIED 134 ) 135 sessionConfig.expectedFrameRateRange 136 else null 137 } 138 139 /** 140 * Populates the mapping between surfaces of a capture session and the Stream Use Case of their 141 * associated stream. 142 * 143 * @param sessionConfigs collection of all session configs for this capture session 144 * @return the mapping between surfaces and Stream Use Case flag 145 */ 146 @VisibleForTesting 147 public fun getSurfaceToStreamUseCaseMapping( 148 sessionConfigs: Collection<SessionConfig>, 149 useCaseConfigs: Collection<UseCaseConfig<*>>, 150 ): Map<DeferrableSurface, Long> { 151 if (sessionConfigs.any { it.templateType == CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG }) { 152 // If is ZSL, do not populate anything. 153 Log.error { "ZSL in populateSurfaceToStreamUseCaseMapping()" } 154 return emptyMap() 155 } 156 157 val mapping = mutableMapOf<DeferrableSurface, Long>() 158 StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping( 159 sessionConfigs, 160 useCaseConfigs, 161 mapping 162 ) 163 164 return mapping 165 } 166 167 /** 168 * Populates the mapping between surfaces of a capture session and the Stream Use Hint of their 169 * associated stream. 170 * 171 * @param sessionConfigs collection of all session configs for this capture session 172 * @return the mapping between surfaces and Stream Use Hint flag 173 */ 174 @VisibleForTesting 175 public fun getSurfaceToStreamUseHintMapping( 176 sessionConfigs: Collection<SessionConfig> 177 ): Map<DeferrableSurface, Long> { 178 val mapping = mutableMapOf<DeferrableSurface, Long>() 179 for (sessionConfig in sessionConfigs) { 180 for (surface in sessionConfig.surfaces) { 181 if ( 182 sessionConfig.implementationOptions.containsOption(STREAM_USE_HINT_OPTION) && 183 sessionConfig.implementationOptions.retrieveOption( 184 STREAM_USE_HINT_OPTION 185 ) != null 186 ) { 187 mapping[surface] = 188 sessionConfig.implementationOptions.retrieveOption(STREAM_USE_HINT_OPTION)!! 189 continue 190 } 191 } 192 } 193 return mapping 194 } 195 196 private fun getStreamUseCaseForContainerClass(kClass: Class<*>?): Long { 197 return when (kClass) { 198 ImageAnalysis::class.java -> OutputStream.StreamUseCase.PREVIEW.value 199 Preview::class.java -> OutputStream.StreamUseCase.PREVIEW.value 200 ImageCapture::class.java -> OutputStream.StreamUseCase.STILL_CAPTURE.value 201 MediaCodec::class.java -> OutputStream.StreamUseCase.VIDEO_RECORD.value 202 StreamSharing::class.java -> OutputStream.StreamUseCase.VIDEO_RECORD.value 203 else -> OutputStream.StreamUseCase.DEFAULT.value 204 } 205 } 206 207 private fun getStreamUseHintForContainerClass(kClass: Class<*>?): Long { 208 return when (kClass) { 209 MediaCodec::class.java -> OutputStream.StreamUseHint.VIDEO_RECORD.value 210 StreamSharing::class.java -> OutputStream.StreamUseHint.VIDEO_RECORD.value 211 else -> OutputStream.StreamUseHint.DEFAULT.value 212 } 213 } 214 215 public companion object { 216 public fun SessionConfig.toCamera2ImplConfig(): Camera2ImplConfig { 217 return Camera2ImplConfig(implementationOptions) 218 } 219 220 public fun UseCase.getSessionConfig(isPrimary: Boolean): SessionConfig { 221 return if (isPrimary) sessionConfig else secondarySessionConfig 222 } 223 } 224 } 225