1 /*
<lambda>null2  * Copyright 2021 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.CameraCaptureSession.CaptureCallback
21 import android.hardware.camera2.CameraDevice
22 import android.hardware.camera2.CaptureRequest
23 import androidx.annotation.RestrictTo
24 import androidx.camera.camera2.pipe.integration.interop.CaptureRequestOptions
25 import androidx.camera.camera2.pipe.integration.interop.CaptureRequestOptions.Builder.Companion.from
26 import androidx.camera.camera2.pipe.integration.interop.ExperimentalCamera2Interop
27 import androidx.camera.core.ExtendableBuilder
28 import androidx.camera.core.impl.Config
29 import androidx.camera.core.impl.MutableConfig
30 import androidx.camera.core.impl.MutableOptionsBundle
31 import androidx.camera.core.impl.OptionsBundle
32 
33 internal const val CAPTURE_REQUEST_ID_STEM = "camera2.captureRequest.option."
34 internal val TEMPLATE_TYPE_OPTION: Config.Option<Int> =
35     Config.Option.create("camera2.captureRequest.templateType", Int::class.javaPrimitiveType!!)
36 internal val DEVICE_STATE_CALLBACK_OPTION: Config.Option<CameraDevice.StateCallback> =
37     Config.Option.create(
38         "camera2.cameraDevice.stateCallback",
39         CameraDevice.StateCallback::class.java
40     )
41 internal val SESSION_STATE_CALLBACK_OPTION: Config.Option<CameraCaptureSession.StateCallback> =
42     Config.Option.create(
43         "camera2.cameraCaptureSession.stateCallback",
44         CameraCaptureSession.StateCallback::class.java
45     )
46 internal val SESSION_CAPTURE_CALLBACK_OPTION: Config.Option<CaptureCallback> =
47     Config.Option.create(
48         "camera2.cameraCaptureSession.captureCallback",
49         CaptureCallback::class.java
50     )
51 internal val STREAM_USE_CASE_OPTION: Config.Option<Long> =
52     Config.Option.create(
53         "camera2.cameraCaptureSession.streamUseCase",
54         Long::class.javaPrimitiveType!!
55     )
56 internal val STREAM_USE_HINT_OPTION: Config.Option<Long> =
57     Config.Option.create(
58         "camera2.cameraCaptureSession.streamUseHint",
59         Long::class.javaPrimitiveType!!
60     )
61 internal val CAPTURE_REQUEST_TAG_OPTION: Config.Option<Any> =
62     Config.Option.create("camera2.captureRequest.tag", Any::class.java)
63 internal val SESSION_PHYSICAL_CAMERA_ID_OPTION: Config.Option<String> =
64     Config.Option.create("camera2.cameraCaptureSession.physicalCameraId", String::class.java)
65 
66 /**
67  * Internal shared implementation details for camera 2 interop.
68  *
69  * @constructor Creates a Camera2ImplConfig for reading Camera2 options from the given config.
70  * @property config The config that potentially contains Camera2 options.
71  */
72 @OptIn(ExperimentalCamera2Interop::class)
73 public class Camera2ImplConfig(config: Config) : CaptureRequestOptions(config) {
74 
75     /** Returns all capture request options contained in this configuration. */
76     @get:RestrictTo(RestrictTo.Scope.LIBRARY)
77     public val captureRequestOptions: CaptureRequestOptions
78         get() = from(config).build()
79 
80     /**
81      * Returns the CameraDevice template from the given configuration.
82      *
83      * See [CameraDevice] for valid template types. For example, [CameraDevice.TEMPLATE_PREVIEW].
84      *
85      * @param valueIfMissing The value to return if this configuration option has not been set.
86      * @return The stored value or `valueIfMissing` if the value does not exist in this
87      *   configuration.
88      */
89     public fun getCaptureRequestTemplate(valueIfMissing: Int): Int {
90         return config.retrieveOption(TEMPLATE_TYPE_OPTION, valueIfMissing)!!
91     }
92 
93     /**
94      * Returns a CameraDevice template on the given configuration. Requires API 33 or above.
95      *
96      * @param valueIfMissing The value to return if this configuration option has not been set.
97      * @return The stored value or `valueIfMissing` if the value does not exist in this
98      *   configuration.
99      * @see [android.hardware.camera2.CameraMetadata] for valid stream use cases.
100      * @see [android.hardware.camera2.params.OutputConfiguration] to see how camera2 framework uses
101      *   this.
102      */
103     public fun getStreamUseCase(valueIfMissing: Long? = null): Long? {
104         return config.retrieveOption(STREAM_USE_CASE_OPTION, valueIfMissing)
105     }
106 
107     /**
108      * Returns a CameraDevice template on the given configuration.
109      *
110      * @param valueIfMissing The value to return if this configuration option has not been set.
111      * @return The stored value or `valueIfMissing` if the value does not exist in this
112      *   configuration.
113      * @see [android.hardware.camera2.CameraMetadata] for valid stream use cases.
114      * @see [android.hardware.camera2.params.OutputConfiguration] to see how camera2 framework uses
115      *   this.
116      */
117     public fun getStreamUseHint(valueIfMissing: Long? = null): Long? {
118         return config.retrieveOption(STREAM_USE_HINT_OPTION, valueIfMissing)
119     }
120 
121     /**
122      * Returns the stored [CameraDevice.StateCallback].
123      *
124      * @param valueIfMissing The value to return if this configuration option has not been set.
125      *   Defaults to `null`.
126      * @return The stored value or `valueIfMissing` if the value does not exist in this
127      *   configuration.
128      */
129     public fun getDeviceStateCallback(
130         valueIfMissing: CameraDevice.StateCallback? = null
131     ): CameraDevice.StateCallback? {
132         return config.retrieveOption(DEVICE_STATE_CALLBACK_OPTION, valueIfMissing)
133     }
134 
135     /**
136      * Returns the stored [CameraCaptureSession.StateCallback].
137      *
138      * @param valueIfMissing The value to return if this configuration option has not been set.
139      *   Defaults to `null`.
140      * @return The stored value or `valueIfMissing` if the value does not exist in this
141      *   configuration.
142      */
143     public fun getSessionStateCallback(
144         valueIfMissing: CameraCaptureSession.StateCallback? = null
145     ): CameraCaptureSession.StateCallback? {
146         return config.retrieveOption(SESSION_STATE_CALLBACK_OPTION, valueIfMissing)
147     }
148 
149     /**
150      * Returns the stored [CameraCaptureSession.CaptureCallback].
151      *
152      * @param valueIfMissing The value to return if this configuration option has not been set.
153      *   Defaults to `null`.
154      * @return The stored value or `valueIfMissing` if the value does not exist in this
155      *   configuration.
156      */
157     public fun getSessionCaptureCallback(
158         valueIfMissing: CaptureCallback? = null
159     ): CaptureCallback? {
160         return config.retrieveOption(SESSION_CAPTURE_CALLBACK_OPTION, valueIfMissing)
161     }
162 
163     /**
164      * Returns the capture request tag.
165      *
166      * @param valueIfMissing The value to return if this configuration option has not been set.
167      *   Defaults to `null`.
168      * @return The stored value or `valueIfMissing` if the value does not exist in this
169      *   configuration.
170      */
171     public fun getCaptureRequestTag(valueIfMissing: Any? = null): Any? {
172         return config.retrieveOption(CAPTURE_REQUEST_TAG_OPTION, valueIfMissing)
173     }
174 
175     /**
176      * Returns the physical camera ID.
177      *
178      * @param valueIfMissing The value to return if this configuration option has not been set.
179      *   Defaults to `null`.
180      * @return The stored value or `valueIfMissing` if the value does not exist in this
181      *   configuration.
182      */
183     public fun getPhysicalCameraId(valueIfMissing: String? = null): String? {
184         return config.retrieveOption(SESSION_PHYSICAL_CAMERA_ID_OPTION, valueIfMissing)
185     }
186 
187     /**
188      * Builder for creating [Camera2ImplConfig] instance.
189      *
190      * Use [Builder] for creating [Config] which contains camera2 options only. And use
191      * [androidx.camera.camera2.pipe.integration.interop.Camera2Interop.Extender] to add Camera2
192      * options on existing other [ExtendableBuilder].
193      */
194     public class Builder : ExtendableBuilder<Camera2ImplConfig?> {
195 
196         private val mutableOptionsBundle = MutableOptionsBundle.create()
197 
198         override fun getMutableConfig(): MutableConfig {
199             return mutableOptionsBundle
200         }
201 
202         /** Inserts new capture request option with specific [CaptureRequest.Key] setting. */
203         public fun <ValueT> setCaptureRequestOption(
204             key: CaptureRequest.Key<ValueT>,
205             value: ValueT
206         ): Builder {
207             val opt = key.createCaptureRequestOption()
208             mutableOptionsBundle.insertOption(opt, value)
209             return this
210         }
211 
212         /**
213          * Inserts new capture request option with specific [CaptureRequest.Key] setting and
214          * [Config.OptionPriority].
215          */
216         public fun <ValueT> setCaptureRequestOptionWithPriority(
217             key: CaptureRequest.Key<ValueT>,
218             value: ValueT,
219             priority: Config.OptionPriority
220         ): Builder {
221             val opt = key.createCaptureRequestOption()
222             mutableOptionsBundle.insertOption(opt, priority, value)
223             return this
224         }
225 
226         /**
227          * Inserts all capture request options in the map to the setting with
228          * [Config.OptionPriority].
229          */
230         public fun addAllCaptureRequestOptionsWithPriority(
231             values: Map<CaptureRequest.Key<*>, Any>,
232             priority: Config.OptionPriority
233         ): Builder {
234             values.forEach { (key, value) ->
235                 val opt = key.createCaptureRequestOption()
236                 mutableOptionsBundle.insertOption(opt, priority, value)
237             }
238             return this
239         }
240 
241         /** Inserts options from other [Config] objects. */
242         public fun insertAllOptions(config: Config): Builder {
243             for (option in config.listOptions()) {
244                 // Options/values and priority are being copied directly
245                 @Suppress("UNCHECKED_CAST") val objectOpt = option as Config.Option<Any>
246                 mutableOptionsBundle.insertOption(
247                     objectOpt,
248                     config.getOptionPriority(option),
249                     config.retrieveOption(objectOpt)
250                 )
251             }
252             return this
253         }
254 
255         /**
256          * Builds an immutable [Camera2ImplConfig] from the current state.
257          *
258          * @return A [Camera2ImplConfig] populated with the current state.
259          */
260         override fun build(): Camera2ImplConfig {
261             return Camera2ImplConfig(OptionsBundle.from(mutableOptionsBundle))
262         }
263     }
264 }
265 
createCaptureRequestOptionnull266 internal fun CaptureRequest.Key<*>.createCaptureRequestOption(): Config.Option<Any> {
267     /**
268      * Unfortunately, we can't get the Class<T> from the CaptureRequest.Key, so we're forced to
269      * erase the type. This shouldn't be a problem as long as we are only using these options within
270      * the Camera2ImplConfig and Camera2ImplConfig.Builder classes.
271      */
272     return Config.Option.create(CAPTURE_REQUEST_ID_STEM + name, Any::class.java, this)
273 }
274 
275 /** Convert the Config to the CaptureRequest key-value map. */
toParametersnull276 public fun Config.toParameters(): Map<CaptureRequest.Key<*>, Any> {
277     val parameters = mutableMapOf<CaptureRequest.Key<*>, Any>()
278     for (configOption in listOptions()) {
279         val requestKey = configOption.token as? CaptureRequest.Key<*> ?: continue
280         val value = retrieveOption(configOption) ?: continue
281         parameters[requestKey] = value
282     }
283 
284     return parameters
285 }
286