1 /* <lambda>null2 * Copyright 2023 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 androidx.camera.camera2.pipe.CameraTimestamp 20 import androidx.camera.camera2.pipe.FrameInfo 21 import androidx.camera.camera2.pipe.FrameMetadata 22 import androidx.camera.camera2.pipe.FrameNumber 23 import androidx.camera.camera2.pipe.Request 24 import androidx.camera.camera2.pipe.RequestFailure 25 import androidx.camera.camera2.pipe.RequestMetadata 26 import androidx.camera.camera2.pipe.RequestTemplate 27 import androidx.camera.camera2.pipe.StreamId 28 import androidx.camera.camera2.pipe.core.CoroutineMutex 29 import androidx.camera.camera2.pipe.core.Log 30 import androidx.camera.camera2.pipe.core.withLockLaunch 31 import androidx.camera.camera2.pipe.integration.config.UseCaseGraphConfig 32 import androidx.camera.camera2.pipe.integration.impl.CAMERAX_TAG_BUNDLE 33 import androidx.camera.camera2.pipe.integration.impl.Camera2ImplConfig 34 import androidx.camera.camera2.pipe.integration.impl.CameraCallbackMap 35 import androidx.camera.camera2.pipe.integration.impl.UseCaseThreads 36 import androidx.camera.camera2.pipe.integration.impl.toParameters 37 import androidx.camera.core.impl.DeferrableSurface 38 import androidx.camera.core.impl.RequestProcessor 39 import androidx.camera.core.impl.SessionConfig 40 import androidx.camera.core.impl.SessionProcessorSurface 41 import kotlinx.atomicfu.atomic 42 43 public class RequestProcessorAdapter( 44 private val useCaseGraphConfig: UseCaseGraphConfig, 45 private val processorSurfaces: List<SessionProcessorSurface>, 46 private val threads: UseCaseThreads 47 ) : RequestProcessor { 48 private val coroutineMutex = CoroutineMutex() 49 private val sequenceIds = atomic(0) 50 internal var sessionConfig: SessionConfig? = null 51 52 private class RequestProcessorCallbackAdapter( 53 private val callback: RequestProcessor.Callback, 54 private val sequenceId: Int, 55 private val shouldInvokeSequenceCallback: Boolean, 56 private val request: RequestProcessor.Request, 57 private val requestProcessorAdapter: RequestProcessorAdapter, 58 ) : Request.Listener { 59 override fun onStarted( 60 requestMetadata: RequestMetadata, 61 frameNumber: FrameNumber, 62 timestamp: CameraTimestamp 63 ) { 64 callback.onCaptureStarted(request, frameNumber.value, timestamp.value) 65 } 66 67 override fun onPartialCaptureResult( 68 requestMetadata: RequestMetadata, 69 frameNumber: FrameNumber, 70 captureResult: FrameMetadata 71 ) { 72 callback.onCaptureProgressed( 73 request, 74 PartialCaptureResultAdapter(requestMetadata, frameNumber, captureResult) 75 ) 76 } 77 78 override fun onComplete( 79 requestMetadata: RequestMetadata, 80 frameNumber: FrameNumber, 81 result: FrameInfo 82 ) { 83 callback.onCaptureCompleted( 84 request, 85 CaptureResultAdapter(requestMetadata, frameNumber, result) 86 ) 87 } 88 89 override fun onFailed( 90 requestMetadata: RequestMetadata, 91 frameNumber: FrameNumber, 92 requestFailure: RequestFailure 93 ) { 94 callback.onCaptureFailed(request, CaptureFailureAdapter(requestFailure)) 95 } 96 97 override fun onBufferLost( 98 requestMetadata: RequestMetadata, 99 frameNumber: FrameNumber, 100 stream: StreamId 101 ) { 102 val surface = requestProcessorAdapter.getDeferrableSurface(stream) 103 if (surface != null && surface is SessionProcessorSurface) { 104 callback.onCaptureBufferLost(request, frameNumber.value, surface.outputConfigId) 105 } 106 } 107 108 override fun onRequestSequenceCompleted( 109 requestMetadata: RequestMetadata, 110 frameNumber: FrameNumber 111 ) { 112 if (!shouldInvokeSequenceCallback) { 113 return 114 } 115 callback.onCaptureSequenceCompleted(sequenceId, frameNumber.value) 116 } 117 118 override fun onRequestSequenceAborted(requestMetadata: RequestMetadata) { 119 if (!shouldInvokeSequenceCallback) { 120 return 121 } 122 callback.onCaptureSequenceAborted(sequenceId) 123 } 124 } 125 126 override fun submit( 127 request: RequestProcessor.Request, 128 callback: RequestProcessor.Callback 129 ): Int { 130 return submit(mutableListOf(request), callback) 131 } 132 133 override fun submit( 134 requests: MutableList<RequestProcessor.Request>, 135 callback: RequestProcessor.Callback 136 ): Int { 137 Log.debug { "$this#submit" } 138 val sequenceId = sequenceIds.incrementAndGet() 139 val requestsToSubmit = 140 requests.mapIndexed { index, request -> 141 val parameters = 142 sessionConfig?.let { sessionConfig -> 143 val builder = 144 Camera2ImplConfig.Builder().apply { 145 insertAllOptions( 146 sessionConfig.repeatingCaptureConfig.implementationOptions 147 ) 148 insertAllOptions(request.parameters) 149 } 150 builder.build().toParameters() 151 } 152 ?: Camera2ImplConfig.Builder() 153 .insertAllOptions(request.parameters) 154 .build() 155 .toParameters() 156 157 Request( 158 template = RequestTemplate(request.templateId), 159 parameters = parameters, 160 streams = 161 request.targetOutputConfigIds 162 .mapNotNull { findSurface(it) } 163 .mapNotNull { useCaseGraphConfig.surfaceToStreamMap[it] }, 164 listeners = 165 listOf( 166 RequestProcessorCallbackAdapter( 167 callback, 168 sequenceId, 169 shouldInvokeSequenceCallback = index == 0, 170 request, 171 this, 172 ) 173 ) 174 ) 175 } 176 177 coroutineMutex.withLockLaunch(threads.scope) { 178 useCaseGraphConfig.graph.acquireSession().use { it.submit(requestsToSubmit) } 179 } 180 return sequenceId 181 } 182 183 override fun setRepeating( 184 request: RequestProcessor.Request, 185 callback: RequestProcessor.Callback 186 ): Int { 187 Log.debug { "$this#setRepeating" } 188 val sequenceId = sequenceIds.incrementAndGet() 189 val requestsToSubmit = 190 Request( 191 template = RequestTemplate(request.templateId), 192 parameters = 193 Camera2ImplConfig.Builder() 194 .insertAllOptions(request.parameters) 195 .build() 196 .toParameters(), 197 extras = 198 mapOf(CAMERAX_TAG_BUNDLE to sessionConfig!!.repeatingCaptureConfig.tagBundle), 199 streams = 200 request.targetOutputConfigIds 201 .mapNotNull { findSurface(it) } 202 .mapNotNull { useCaseGraphConfig.surfaceToStreamMap[it] }, 203 listeners = 204 listOf( 205 RequestProcessorCallbackAdapter( 206 callback, 207 sequenceId, 208 shouldInvokeSequenceCallback = true, 209 request, 210 this 211 ), 212 CameraCallbackMap.createFor( 213 sessionConfig!!.repeatingCameraCaptureCallbacks, 214 threads.backgroundExecutor 215 ) 216 ) 217 ) 218 coroutineMutex.withLockLaunch(threads.scope) { 219 useCaseGraphConfig.graph.acquireSession().use { it.startRepeating(requestsToSubmit) } 220 } 221 return sequenceId 222 } 223 224 override fun abortCaptures() { 225 Log.debug { "$this#abortCaptures" } 226 coroutineMutex.withLockLaunch(threads.scope) { 227 useCaseGraphConfig.graph.acquireSession().use { it.abort() } 228 } 229 } 230 231 override fun stopRepeating() { 232 Log.debug { "$this#stopRepeating" } 233 coroutineMutex.withLockLaunch(threads.scope) { 234 useCaseGraphConfig.graph.acquireSession().use { it.stopRepeating() } 235 } 236 } 237 238 private fun findSurface(outputConfigId: Int): DeferrableSurface? = 239 processorSurfaces.find { it.outputConfigId == outputConfigId } 240 241 private fun getDeferrableSurface(stream: StreamId): DeferrableSurface? { 242 for (entry in useCaseGraphConfig.surfaceToStreamMap.entries.iterator()) { 243 if (entry.value == stream) { 244 return entry.key 245 } 246 } 247 return null 248 } 249 } 250