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