1 /* <lambda>null2 * Copyright 2022 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.graph 18 19 import android.view.Surface 20 import androidx.annotation.GuardedBy 21 import androidx.camera.camera2.pipe.CameraController 22 import androidx.camera.camera2.pipe.CameraGraph 23 import androidx.camera.camera2.pipe.CameraSurfaceManager 24 import androidx.camera.camera2.pipe.StreamId 25 import androidx.camera.camera2.pipe.SurfaceTracker 26 import androidx.camera.camera2.pipe.core.Log 27 import androidx.camera.camera2.pipe.media.ImageSource 28 import javax.inject.Provider 29 30 /** 31 * A SurfaceGraph tracks the current stream-to-surface mapping state for a [CameraGraph] instance. 32 * 33 * It's primary responsibility is aggregating the current stream-to-surface mapping and passing the 34 * most up to date version to the [CameraController] instance. 35 */ 36 internal class SurfaceGraph( 37 private val streamGraphImpl: StreamGraphImpl, 38 private val cameraController: Provider<CameraController>, 39 private val surfaceManager: CameraSurfaceManager, 40 private val imageSources: Map<StreamId, ImageSource> 41 ) : SurfaceTracker, AutoCloseable { 42 private val lock = Any() 43 44 /** 45 * A map of [StreamId]s to [Surface]s that stores the mapping of [Surface]s set on the streams 46 * on a [CameraGraph]. 47 */ 48 @GuardedBy("lock") 49 private val surfaceMap = imageSources.mapValuesTo(mutableMapOf()) { it.value.surface } 50 51 /** 52 * A map of [Surface]s to closeables from [CameraSurfaceManager]. This keeps track of the token 53 * each [Surface] is associated with, as well as the current tokens that remain active. 54 */ 55 @GuardedBy("lock") 56 private val surfaceUsageMap: MutableMap<Surface, AutoCloseable> = mutableMapOf() 57 58 @GuardedBy("lock") private var shouldRegisterSurfaces = true 59 60 @GuardedBy("lock") private var closed: Boolean = false 61 62 operator fun set(streamId: StreamId, surface: Surface?) { 63 check(!imageSources.keys.contains(streamId)) { 64 "Cannot configure surface for $streamId, it is permanently assigned to " + 65 "${imageSources[streamId]}" 66 } 67 val closeable = 68 synchronized(lock) { 69 if (closed) { 70 if (surface != null) { 71 Log.warn { "Refusing to configure $streamId with $surface after close!" } 72 } 73 return 74 } 75 76 Log.info { 77 if (surface != null) { 78 "Configured $streamId with $surface" 79 } else { 80 "Removed surface for $streamId" 81 } 82 } 83 var oldSurfaceToken: AutoCloseable? = null 84 85 if (surface == null) { 86 // TODO: Tell the graph processor that it should resubmit the repeating request 87 // or reconfigure the camera2 captureSession 88 val oldSurface = surfaceMap.remove(streamId) 89 if (shouldRegisterSurfaces && oldSurface != null) { 90 oldSurfaceToken = surfaceUsageMap.remove(oldSurface) 91 } 92 } else { 93 val oldSurface = surfaceMap[streamId] 94 surfaceMap[streamId] = surface 95 96 if (shouldRegisterSurfaces && oldSurface != surface) { 97 check(!surfaceUsageMap.containsKey(surface)) { 98 "Surface ($surface) is already in use!" 99 } 100 oldSurfaceToken = surfaceUsageMap.remove(oldSurface) 101 val newToken = surfaceManager.registerSurface(surface) 102 surfaceUsageMap[surface] = newToken 103 } 104 } 105 106 return@synchronized oldSurfaceToken 107 } 108 maybeUpdateSurfaces() 109 closeable?.close() 110 } 111 112 override fun unregisterAllSurfaces() { 113 val closeables = 114 synchronized(lock) { 115 shouldRegisterSurfaces = false 116 surfaceUsageMap.values.toList().also { surfaceUsageMap.clear() } 117 } 118 for (closeable in closeables) { 119 closeable.close() 120 } 121 } 122 123 override fun registerAllSurfaces() { 124 synchronized(lock) { 125 check(!closed) 126 for (surface in surfaceMap.values) { 127 surfaceManager.registerSurface(surface).also { token -> 128 surfaceUsageMap[surface] = token 129 } 130 } 131 shouldRegisterSurfaces = true 132 } 133 } 134 135 override fun close() { 136 val closeables = 137 synchronized(lock) { 138 if (closed) { 139 return 140 } 141 closed = true 142 surfaceMap.clear() 143 val tokensToClose = surfaceUsageMap.values.toList() 144 surfaceUsageMap.clear() 145 tokensToClose 146 } 147 148 for (closeable in closeables) { 149 closeable.close() 150 } 151 } 152 153 private fun maybeUpdateSurfaces() { 154 // Rules: 155 // 1. There must be at least one non-null surface. 156 // 2. All non-deferrable streams must have a non-null surface. 157 158 val surfaces = buildSurfaceMap() 159 if (surfaces.isEmpty()) { 160 return 161 } 162 cameraController.get().updateSurfaceMap(surfaces) 163 } 164 165 private fun buildSurfaceMap(): Map<StreamId, Surface> = 166 synchronized(lock) { 167 val surfaces = mutableMapOf<StreamId, Surface>() 168 for (outputConfig in streamGraphImpl.outputConfigs) { 169 for (stream in outputConfig.streamBuilder) { 170 val surface = surfaceMap[stream.id] 171 if (surface == null) { 172 if (!outputConfig.deferrable) { 173 // If output is non-deferrable, a surface must be available or the 174 // config is not yet valid. Exit now with an empty map. 175 return emptyMap() 176 } 177 } else { 178 surfaces[stream.id] = surface 179 } 180 } 181 } 182 return surfaces 183 } 184 } 185