1 /* <lambda>null2 * Copyright 2020 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.hardware.camera2.CameraCaptureSession 20 import android.hardware.camera2.CaptureFailure 21 import android.hardware.camera2.CaptureRequest 22 import android.hardware.camera2.CaptureResult 23 import android.hardware.camera2.TotalCaptureResult 24 import android.os.Build 25 import android.view.Surface 26 import androidx.camera.camera2.pipe.CameraTimestamp 27 import androidx.camera.camera2.pipe.FrameInfo 28 import androidx.camera.camera2.pipe.FrameMetadata 29 import androidx.camera.camera2.pipe.FrameNumber 30 import androidx.camera.camera2.pipe.Request 31 import androidx.camera.camera2.pipe.RequestFailure 32 import androidx.camera.camera2.pipe.RequestMetadata 33 import androidx.camera.camera2.pipe.SensorTimestamp 34 import androidx.camera.camera2.pipe.StreamId 35 import androidx.camera.camera2.pipe.integration.adapter.CameraUseCaseAdapter 36 import androidx.camera.camera2.pipe.integration.adapter.CaptureResultAdapter 37 import androidx.camera.camera2.pipe.integration.compat.Api24Compat 38 import androidx.camera.camera2.pipe.integration.compat.Api34Compat 39 import androidx.camera.camera2.pipe.integration.config.CameraScope 40 import androidx.camera.core.impl.CameraCaptureCallback 41 import androidx.camera.core.impl.CameraCaptureFailure 42 import androidx.camera.core.impl.CaptureConfig 43 import androidx.camera.core.impl.TagBundle 44 import java.util.concurrent.Executor 45 import javax.inject.Inject 46 47 /** A map of [CameraCaptureCallback] that are invoked on each [Request]. */ 48 @CameraScope 49 public class CameraCallbackMap @Inject constructor() : Request.Listener { 50 private val callbackMap = mutableMapOf<CameraCaptureCallback, Executor>() 51 52 @Volatile private var callbacks: Map<CameraCaptureCallback, Executor> = mapOf() 53 54 public fun addCaptureCallback(callback: CameraCaptureCallback, executor: Executor) { 55 check(!callbacks.contains(callback)) { "$callback was already registered!" } 56 57 synchronized(callbackMap) { 58 callbackMap[callback] = executor 59 callbacks = callbackMap.toMap() 60 } 61 } 62 63 public fun removeCaptureCallback(callback: CameraCaptureCallback) { 64 synchronized(callbackMap) { 65 callbackMap.remove(callback) 66 callbacks = callbackMap.toMap() 67 } 68 } 69 70 override fun onBufferLost( 71 requestMetadata: RequestMetadata, 72 frameNumber: FrameNumber, 73 stream: StreamId 74 ) { 75 for ((callback, executor) in callbacks) { 76 if ( 77 Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && 78 callback is CameraUseCaseAdapter.CaptureCallbackContainer 79 ) { 80 val session: CameraCaptureSession? = 81 requestMetadata.unwrapAs(CameraCaptureSession::class) 82 val request: CaptureRequest? = requestMetadata.unwrapAs(CaptureRequest::class) 83 val surface: Surface? = requestMetadata.streams[stream] 84 if (session != null && request != null && surface != null) { 85 executor.execute { 86 Api24Compat.onCaptureBufferLost( 87 callback.captureCallback, 88 session, 89 request, 90 surface, 91 frameNumber.value 92 ) 93 } 94 } 95 } 96 } 97 } 98 99 override fun onComplete( 100 requestMetadata: RequestMetadata, 101 frameNumber: FrameNumber, 102 result: FrameInfo 103 ) { 104 for ((callback, executor) in callbacks) { 105 if (callback is CameraUseCaseAdapter.CaptureCallbackContainer) { 106 val session: CameraCaptureSession? = 107 requestMetadata.unwrapAs(CameraCaptureSession::class) 108 val request: CaptureRequest? = requestMetadata.unwrapAs(CaptureRequest::class) 109 val totalCaptureResult: TotalCaptureResult? = 110 result.unwrapAs(TotalCaptureResult::class) 111 if (session != null && request != null && totalCaptureResult != null) { 112 executor.execute { 113 callback.captureCallback.onCaptureCompleted( 114 session, 115 request, 116 totalCaptureResult 117 ) 118 } 119 } 120 } else { 121 val captureResult = CaptureResultAdapter(requestMetadata, frameNumber, result) 122 executor.execute { 123 callback.onCaptureCompleted(requestMetadata.getCaptureConfigId(), captureResult) 124 } 125 } 126 } 127 } 128 129 private fun RequestMetadata.getCaptureConfigId(): Int { 130 val tagBundle = this[CAMERAX_TAG_BUNDLE] 131 return tagBundle?.getTag(CaptureConfig.CAPTURE_CONFIG_ID_TAG_KEY) as? Int 132 ?: CaptureConfig.DEFAULT_ID 133 } 134 135 override fun onFailed( 136 requestMetadata: RequestMetadata, 137 frameNumber: FrameNumber, 138 requestFailure: RequestFailure 139 ) { 140 for ((callback, executor) in callbacks) { 141 if (callback is CameraUseCaseAdapter.CaptureCallbackContainer) { 142 val session: CameraCaptureSession? = 143 requestMetadata.unwrapAs(CameraCaptureSession::class) 144 val request: CaptureRequest? = requestMetadata.unwrapAs(CaptureRequest::class) 145 val captureFailure = requestFailure.unwrapAs(CaptureFailure::class) 146 if (session != null && request != null && captureFailure != null) { 147 executor.execute { 148 callback.captureCallback.onCaptureFailed(session, request, captureFailure) 149 } 150 } 151 } else { 152 val failure = CameraCaptureFailure(CameraCaptureFailure.Reason.ERROR) 153 executor.execute { 154 callback.onCaptureFailed(requestMetadata.getCaptureConfigId(), failure) 155 } 156 } 157 } 158 } 159 160 override fun onAborted(request: Request) { 161 for ((callback, executor) in callbacks) { 162 // TODO: get the correct requestId 163 val tagBundle = request.extras[CAMERAX_TAG_BUNDLE] as? TagBundle 164 val captureConfigId = 165 tagBundle?.getTag(CaptureConfig.CAPTURE_CONFIG_ID_TAG_KEY) as? Int 166 ?: CaptureConfig.DEFAULT_ID 167 executor.execute { callback.onCaptureCancelled(captureConfigId) } 168 } 169 } 170 171 override fun onPartialCaptureResult( 172 requestMetadata: RequestMetadata, 173 frameNumber: FrameNumber, 174 captureResult: FrameMetadata 175 ) { 176 for ((callback, executor) in callbacks) { 177 if (callback is CameraUseCaseAdapter.CaptureCallbackContainer) { 178 val session: CameraCaptureSession? = 179 requestMetadata.unwrapAs(CameraCaptureSession::class) 180 val request: CaptureRequest? = requestMetadata.unwrapAs(CaptureRequest::class) 181 val partialResult: CaptureResult? = captureResult.unwrapAs(CaptureResult::class) 182 if (session != null && request != null && partialResult != null) { 183 executor.execute { 184 callback.captureCallback.onCaptureProgressed( 185 session, 186 request, 187 partialResult 188 ) 189 } 190 } 191 } 192 } 193 } 194 195 override fun onRequestSequenceAborted(requestMetadata: RequestMetadata) { 196 for ((callback, executor) in callbacks) { 197 if (callback is CameraUseCaseAdapter.CaptureCallbackContainer) { 198 val session: CameraCaptureSession? = 199 requestMetadata.unwrapAs(CameraCaptureSession::class) 200 val request: CaptureRequest? = requestMetadata.unwrapAs(CaptureRequest::class) 201 if (session != null && request != null) { 202 executor.execute { 203 callback.captureCallback.onCaptureSequenceAborted( 204 session, 205 -1 /*sequenceId*/ 206 ) 207 } 208 } 209 } else { 210 executor.execute { 211 callback.onCaptureCancelled(requestMetadata.getCaptureConfigId()) 212 } 213 } 214 } 215 } 216 217 override fun onRequestSequenceCompleted( 218 requestMetadata: RequestMetadata, 219 frameNumber: FrameNumber 220 ) { 221 for ((callback, executor) in callbacks) { 222 if (callback is CameraUseCaseAdapter.CaptureCallbackContainer) { 223 val session: CameraCaptureSession? = 224 requestMetadata.unwrapAs(CameraCaptureSession::class) 225 val request: CaptureRequest? = requestMetadata.unwrapAs(CaptureRequest::class) 226 if (session != null && request != null) { 227 executor.execute { 228 callback.captureCallback.onCaptureSequenceCompleted( 229 session, 230 -1 /*sequenceId*/, 231 frameNumber.value 232 ) 233 } 234 } 235 } 236 } 237 } 238 239 override fun onStarted( 240 requestMetadata: RequestMetadata, 241 frameNumber: FrameNumber, 242 timestamp: CameraTimestamp 243 ) { 244 for ((callback, executor) in callbacks) { 245 if (callback is CameraUseCaseAdapter.CaptureCallbackContainer) { 246 val session: CameraCaptureSession? = 247 requestMetadata.unwrapAs(CameraCaptureSession::class) 248 val request: CaptureRequest? = requestMetadata.unwrapAs(CaptureRequest::class) 249 if (session != null && request != null) { 250 executor.execute { 251 callback.captureCallback.onCaptureStarted( 252 session, 253 request, 254 timestamp.value, 255 frameNumber.value 256 ) 257 } 258 } 259 } else { 260 executor.execute { callback.onCaptureStarted(requestMetadata.getCaptureConfigId()) } 261 } 262 } 263 } 264 265 override fun onReadoutStarted( 266 requestMetadata: RequestMetadata, 267 frameNumber: FrameNumber, 268 timestamp: SensorTimestamp 269 ) { 270 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { 271 return 272 } 273 for ((callback, executor) in callbacks) { 274 if (callback is CameraUseCaseAdapter.CaptureCallbackContainer) { 275 val session: CameraCaptureSession? = 276 requestMetadata.unwrapAs(CameraCaptureSession::class) 277 val request: CaptureRequest? = requestMetadata.unwrapAs(CaptureRequest::class) 278 if (session != null && request != null) { 279 executor.execute { 280 Api34Compat.onReadoutStarted( 281 callback.captureCallback, 282 session, 283 request, 284 timestamp.value, 285 frameNumber.value 286 ) 287 } 288 } 289 } 290 } 291 } 292 293 public companion object { 294 public fun createFor( 295 callbacks: Collection<CameraCaptureCallback>, 296 executor: Executor 297 ): CameraCallbackMap { 298 return CameraCallbackMap().apply { 299 callbacks.forEach { callback -> addCaptureCallback(callback, executor) } 300 } 301 } 302 } 303 } 304