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