1 /*
2  * Copyright 2025 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.extensions.internal.sessionprocessor
18 
19 import android.hardware.camera2.CameraCharacteristics
20 import android.hardware.camera2.CaptureRequest
21 import android.hardware.camera2.CaptureResult
22 import android.os.Build
23 import android.util.Pair
24 import android.util.Size
25 import androidx.annotation.GuardedBy
26 import androidx.annotation.RequiresApi
27 import androidx.camera.core.CameraInfo
28 import androidx.camera.core.impl.AdapterCameraInfo
29 import androidx.camera.core.impl.CameraCaptureCallback
30 import androidx.camera.core.impl.CameraCaptureResult
31 import androidx.camera.core.impl.CameraInfoInternal
32 import androidx.camera.core.impl.Config
33 import androidx.camera.core.impl.OutputSurfaceConfiguration
34 import androidx.camera.core.impl.RequestProcessor
35 import androidx.camera.core.impl.SessionConfig
36 import androidx.camera.core.impl.SessionProcessor
37 import androidx.camera.core.impl.SessionProcessor.CaptureSessionRequestProcessor
38 import androidx.camera.core.impl.TagBundle
39 import androidx.camera.core.impl.utils.executor.CameraXExecutors
40 import androidx.camera.extensions.CameraExtensionsControl
41 import androidx.camera.extensions.CameraExtensionsInfo
42 import androidx.camera.extensions.ExtensionMode
43 import androidx.camera.extensions.internal.Camera2ExtensionsUtil.convertCamera2ModeToCameraXMode
44 import androidx.camera.extensions.internal.Camera2ExtensionsUtil.convertCameraXModeToCamera2Mode
45 import androidx.camera.extensions.internal.ExtensionsUtils
46 import androidx.camera.extensions.internal.VendorExtender
47 import androidx.lifecycle.LiveData
48 import androidx.lifecycle.MutableLiveData
49 import java.util.concurrent.atomic.AtomicInteger
50 
51 @RequiresApi(31)
52 public class Camera2ExtensionsSessionProcessor(
53     private val availableCaptureRequestKeys: List<CaptureRequest.Key<*>>,
54     @ExtensionMode.Mode private val mode: Int,
55     private val vendorExtender: VendorExtender
56 ) : SessionProcessor, CameraExtensionsInfo, CameraExtensionsControl {
57 
58     private val camera2ExtensionMode = convertCameraXModeToCamera2Mode(mode)
59 
60     private var extensionStrengthLiveData: MutableLiveData<Int>? = null
61     private var currentExtensionTypeLiveData: MutableLiveData<Int>? = null
62     private val extensionStrength: AtomicInteger = AtomicInteger(100)
63     private val currentExtensionType: AtomicInteger = AtomicInteger(mode)
64 
65     @AdapterCameraInfo.CameraOperation
66     private val supportedCameraOperations: Set<Int> =
67         ExtensionsUtils.getSupportedCameraOperations(availableCaptureRequestKeys)
68 
69     private var cameraInfoInternal: CameraInfoInternal? = null
70     private var cameraCaptureCallback: CameraCaptureCallback? = null
71 
72     private val lock = Any()
73 
74     @GuardedBy("lock")
75     private var captureSessionRequestProcessor: CaptureSessionRequestProcessor? = null
76 
77     init {
78         if (isCurrentExtensionModeAvailable()) {
79             currentExtensionTypeLiveData = MutableLiveData<Int>(mode)
80         }
81         if (isExtensionStrengthAvailable()) {
82             extensionStrengthLiveData = MutableLiveData<Int>(100)
83         }
84     }
85 
initSessionnull86     override fun initSession(
87         cameraInfo: CameraInfo,
88         outputSurfaceConfig: OutputSurfaceConfiguration?
89     ): SessionConfig? {
90         cameraInfoInternal = cameraInfo as CameraInfoInternal
91         // Sets up the CameraCaptureCallback to receive the extensions related info
92         cameraCaptureCallback =
93             object : CameraCaptureCallback() {
94                 override fun onCaptureCompleted(
95                     captureConfigId: Int,
96                     cameraCaptureResult: CameraCaptureResult
97                 ) {
98                     if (
99                         Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE &&
100                             isCurrentExtensionModeAvailable()
101                     ) {
102                         cameraCaptureResult.captureResult
103                             ?.get(CaptureResult.EXTENSION_CURRENT_TYPE)
104                             ?.let {
105                                 val cameraXMode = convertCamera2ModeToCameraXMode(it)
106                                 if (currentExtensionType.getAndSet(cameraXMode) != cameraXMode) {
107                                     extensionStrengthLiveData?.postValue(it)
108                                 }
109                             }
110                     }
111 
112                     if (
113                         Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE &&
114                             isExtensionStrengthAvailable()
115                     ) {
116                         cameraCaptureResult.captureResult
117                             ?.get(CaptureResult.EXTENSION_STRENGTH)
118                             ?.let {
119                                 if (extensionStrength.getAndSet(it) != it) {
120                                     extensionStrengthLiveData?.postValue(it)
121                                 }
122                             }
123                     }
124                 }
125             }
126 
127         cameraInfoInternal!!.addSessionCaptureCallback(
128             CameraXExecutors.directExecutor(),
129             cameraCaptureCallback!!
130         )
131 
132         return null
133     }
134 
deInitSessionnull135     override fun deInitSession() {
136         cameraInfoInternal?.apply {
137             cameraCaptureCallback?.let { removeSessionCaptureCallback(it) }
138         }
139     }
140 
getSupportedPostviewSizenull141     override fun getSupportedPostviewSize(captureSize: Size): Map<Int, List<Size>> {
142         return vendorExtender.getSupportedPostviewResolutions(captureSize)
143     }
144 
getSupportedCameraOperationsnull145     override fun getSupportedCameraOperations(): Set<Int> {
146         return supportedCameraOperations
147     }
148 
getAvailableCharacteristicsKeyValuesnull149     override fun getAvailableCharacteristicsKeyValues():
150         List<Pair<CameraCharacteristics.Key<*>, in Any>> {
151         return vendorExtender.availableCharacteristicsKeyValues
152     }
153 
getExtensionAvailableStabilizationModesnull154     override fun getExtensionAvailableStabilizationModes(): IntArray? {
155         return super.getExtensionAvailableStabilizationModes()
156     }
157 
getImplementationTypenull158     override fun getImplementationType(): Pair<Int, Int> {
159         return Pair.create(SessionProcessor.TYPE_CAMERA2_EXTENSION, camera2ExtensionMode)
160     }
161 
setParametersnull162     override fun setParameters(config: Config) {
163         throw UnsupportedOperationException(
164             "Camera2ExtensionsSessionProcessor#setParameters should not be invoked!"
165         )
166     }
167 
onCaptureSessionStartnull168     override fun onCaptureSessionStart(requestProcessor: RequestProcessor) {
169         throw UnsupportedOperationException(
170             "Camera2ExtensionsSessionProcessor#onCaptureSessionStart should not be invoked!"
171         )
172     }
173 
onCaptureSessionEndnull174     override fun onCaptureSessionEnd() {
175         throw UnsupportedOperationException(
176             "Camera2ExtensionsSessionProcessor#onCaptureSessionEnd should not be invoked!"
177         )
178     }
179 
startRepeatingnull180     override fun startRepeating(
181         tagBundle: TagBundle,
182         callback: SessionProcessor.CaptureCallback
183     ): Int {
184         throw UnsupportedOperationException(
185             "Camera2ExtensionsSessionProcessor#startRepeating should not be invoked!"
186         )
187     }
188 
stopRepeatingnull189     override fun stopRepeating() {
190         throw UnsupportedOperationException(
191             "Camera2ExtensionsSessionProcessor#stopRepeating should not be invoked!"
192         )
193     }
194 
startCapturenull195     override fun startCapture(
196         postviewEnabled: Boolean,
197         tagBundle: TagBundle,
198         callback: SessionProcessor.CaptureCallback
199     ): Int {
200         throw UnsupportedOperationException(
201             "Camera2ExtensionsSessionProcessor#startCapture should not be invoked!"
202         )
203     }
204 
abortCapturenull205     override fun abortCapture(captureSequenceId: Int) {
206         throw UnsupportedOperationException(
207             "Camera2ExtensionsSessionProcessor#abortCapture should not be invoked!"
208         )
209     }
210 
isExtensionStrengthAvailablenull211     override fun isExtensionStrengthAvailable(): Boolean =
212         vendorExtender.isExtensionStrengthAvailable
213 
214     override fun getExtensionStrength(): LiveData<Int>? = extensionStrengthLiveData
215 
216     override fun isCurrentExtensionModeAvailable(): Boolean =
217         vendorExtender.isCurrentExtensionModeAvailable
218 
219     override fun getCurrentExtensionMode(): LiveData<Int>? = currentExtensionTypeLiveData
220 
221     override fun getRealtimeCaptureLatency(): Pair<Long, Long>? {
222         synchronized(lock) {
223             return captureSessionRequestProcessor?.realtimeStillCaptureLatency
224         }
225     }
226 
setExtensionStrengthnull227     override fun setExtensionStrength(strength: Int) {
228         synchronized(lock) { captureSessionRequestProcessor?.setExtensionStrength(strength) }
229     }
230 
setCaptureSessionRequestProcessornull231     override fun setCaptureSessionRequestProcessor(processor: CaptureSessionRequestProcessor?) {
232         synchronized(lock) { captureSessionRequestProcessor = processor }
233     }
234 }
235