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.graphics.ImageFormat
20 import android.graphics.SurfaceTexture
21 import android.hardware.camera2.CameraCharacteristics
22 import android.hardware.camera2.CameraDevice
23 import android.os.Build
24 import android.util.Size
25 import android.view.Surface
26 import androidx.annotation.GuardedBy
27 import androidx.camera.camera2.pipe.core.Log.error
28 import androidx.camera.camera2.pipe.core.Log.warn
29 import androidx.camera.camera2.pipe.integration.adapter.CameraUseCaseAdapter
30 import androidx.camera.camera2.pipe.integration.compat.workaround.getSupportedRepeatingSurfaceSizes
31 import androidx.camera.core.UseCase
32 import androidx.camera.core.impl.CaptureConfig
33 import androidx.camera.core.impl.Config
34 import androidx.camera.core.impl.DeferrableSurface
35 import androidx.camera.core.impl.ImageFormatConstants
36 import androidx.camera.core.impl.ImageInputConfig
37 import androidx.camera.core.impl.ImmediateSurface
38 import androidx.camera.core.impl.MutableOptionsBundle
39 import androidx.camera.core.impl.SessionConfig
40 import androidx.camera.core.impl.SessionConfig.CloseableErrorListener
41 import androidx.camera.core.impl.StreamSpec
42 import androidx.camera.core.impl.UseCaseConfig
43 import androidx.camera.core.impl.UseCaseConfig.OPTION_CAPTURE_TYPE
44 import androidx.camera.core.impl.UseCaseConfig.OPTION_SESSION_CONFIG_UNPACKER
45 import androidx.camera.core.impl.UseCaseConfigFactory
46 import androidx.camera.core.impl.UseCaseConfigFactory.CaptureType
47 import androidx.camera.core.impl.utils.executor.CameraXExecutors
48 import androidx.camera.core.internal.TargetConfig.OPTION_TARGET_NAME
49 import kotlin.math.min
50 
51 private val DEFAULT_PREVIEW_SIZE = Size(0, 0)
52 
53 /**
54  * A [UseCase] used to issue repeating requests when only [androidx.camera.core.ImageCapture] is
55  * enabled, since taking a picture may require a repeating surface to perform pre-capture checks,
56  * mainly around 3A.
57  */
58 public class MeteringRepeating(
59     private val cameraProperties: CameraProperties,
60     config: MeteringRepeatingConfig,
61     private val displayInfoManager: DisplayInfoManager
62 ) : UseCase(config) {
63 
64     private val meteringSurfaceSize = getProperPreviewSize()
65 
66     private val deferrableSurfaceLock = Any()
67 
68     private var closeableErrorListener: CloseableErrorListener? = null
69 
70     @GuardedBy("deferrableSurfaceLock") private var deferrableSurface: DeferrableSurface? = null
71 
72     override fun getDefaultConfig(
73         applyDefaultConfig: Boolean,
74         factory: UseCaseConfigFactory
75     ): MeteringRepeatingConfig = Builder(cameraProperties, displayInfoManager).useCaseConfig
76 
77     override fun getUseCaseConfigBuilder(config: Config): Builder =
78         Builder(cameraProperties, displayInfoManager)
79 
80     override fun onSuggestedStreamSpecUpdated(
81         primaryStreamSpec: StreamSpec,
82         secondaryStreamSpec: StreamSpec?,
83     ): StreamSpec {
84         updateSessionConfig(listOf(createPipeline(meteringSurfaceSize).build()))
85         notifyActive()
86         return primaryStreamSpec.toBuilder().setResolution(meteringSurfaceSize).build()
87     }
88 
89     override fun onUnbind() {
90         synchronized(deferrableSurfaceLock) {
91             deferrableSurface?.close()
92             deferrableSurface = null
93         }
94     }
95 
96     /** Sets up the use case's session configuration, mainly its [DeferrableSurface]. */
97     public fun setupSession() {
98         // The suggested stream spec passed to `updateSuggestedStreamSpec` doesn't matter since
99         // this use case uses the min preview size.
100         updateSuggestedStreamSpec(StreamSpec.builder(DEFAULT_PREVIEW_SIZE).build(), null)
101     }
102 
103     private fun createPipeline(resolution: Size): SessionConfig.Builder {
104         synchronized(deferrableSurfaceLock) {
105             val surfaceTexture =
106                 SurfaceTexture(0).apply {
107                     setDefaultBufferSize(resolution.width, resolution.height)
108                 }
109             val surface = Surface(surfaceTexture)
110 
111             deferrableSurface?.close()
112             deferrableSurface = ImmediateSurface(surface, resolution, imageFormat)
113             deferrableSurface!!
114                 .terminationFuture
115                 .addListener(
116                     {
117                         surface.release()
118                         surfaceTexture.release()
119                     },
120                     CameraXExecutors.directExecutor()
121                 )
122         }
123 
124         // Closes the old error listener if there is
125         closeableErrorListener?.close()
126         val errorListener = CloseableErrorListener { _, _ ->
127             updateSessionConfig(listOf(createPipeline(resolution).build()))
128             notifyReset()
129         }
130         closeableErrorListener = errorListener
131 
132         return SessionConfig.Builder.createFrom(MeteringRepeatingConfig(), resolution).apply {
133             setTemplateType(CameraDevice.TEMPLATE_PREVIEW)
134             addSurface(deferrableSurface!!)
135             setErrorListener(errorListener)
136         }
137     }
138 
139     private fun CameraProperties.getOutputSizes(): Array<Size>? {
140         val map =
141             metadata[CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP]
142                 ?: run {
143                     error { "Can not retrieve SCALER_STREAM_CONFIGURATION_MAP." }
144                     return null
145                 }
146 
147         return if (Build.VERSION.SDK_INT < 23) {
148             // ImageFormat.PRIVATE is only public after Android level 23. Therefore, use
149             // SurfaceTexture.class to get the supported output sizes before Android level 23.
150             map.getOutputSizes(SurfaceTexture::class.java)
151         } else {
152             map.getOutputSizes(ImageFormat.PRIVATE)
153         }
154     }
155 
156     private fun getProperPreviewSize(): Size {
157         var outputSizes = cameraProperties.getOutputSizes()
158 
159         if (outputSizes == null) {
160             error { "Can not get output size list." }
161             return DEFAULT_PREVIEW_SIZE
162         }
163 
164         if (outputSizes.isEmpty()) {
165             error { "Output sizes empty" }
166             return DEFAULT_PREVIEW_SIZE
167         }
168 
169         val supportedOutputSizes = outputSizes.getSupportedRepeatingSurfaceSizes()
170 
171         if (supportedOutputSizes.isNotEmpty()) {
172             outputSizes = supportedOutputSizes
173         } else {
174             warn { "No supported output size list, fallback to current list" }
175         }
176 
177         outputSizes.sortBy { size -> size.width.toLong() * size.height.toLong() }
178 
179         // Find maximum supported resolution that is <= min(VGA, display resolution)
180         // Using minimum supported size could cause some issue on certain devices.
181         val previewSize = displayInfoManager.getPreviewSize()
182         val maxSizeProduct =
183             min(640L * 480L, previewSize.width.toLong() * previewSize.height.toLong())
184 
185         var previousSize: Size? = null
186         for (outputSize in outputSizes) {
187             val product = outputSize.width.toLong() * outputSize.height.toLong()
188             if (product == maxSizeProduct) {
189                 return outputSize
190             } else if (product > maxSizeProduct) {
191                 // Returns the maximum supported resolution that is <= min(VGA, display resolution)
192                 // if it is found
193                 return previousSize ?: break
194             }
195             previousSize = outputSize
196         }
197 
198         // If not found, return the minimum size.
199         return previousSize ?: outputSizes[0]
200     }
201 
202     public class MeteringRepeatingConfig : UseCaseConfig<MeteringRepeating>, ImageInputConfig {
203         private val config =
204             MutableOptionsBundle.create().apply {
205                 insertOption(
206                     OPTION_SESSION_CONFIG_UNPACKER,
207                     CameraUseCaseAdapter.DefaultSessionOptionsUnpacker
208                 )
209                 insertOption(OPTION_TARGET_NAME, "MeteringRepeating")
210                 insertOption(OPTION_CAPTURE_TYPE, CaptureType.METERING_REPEATING)
211             }
212 
213         override fun getCaptureType(): CaptureType =
214             UseCaseConfigFactory.CaptureType.METERING_REPEATING
215 
216         override fun getConfig(): MutableOptionsBundle = config
217 
218         override fun getInputFormat(): Int =
219             ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE
220     }
221 
222     public class Builder(
223         private val cameraProperties: CameraProperties,
224         private val displayInfoManager: DisplayInfoManager
225     ) : UseCaseConfig.Builder<MeteringRepeating, MeteringRepeatingConfig, Builder> {
226 
227         override fun getMutableConfig(): MutableOptionsBundle = MutableOptionsBundle.create()
228 
229         override fun getUseCaseConfig(): MeteringRepeatingConfig = MeteringRepeatingConfig()
230 
231         override fun setTargetClass(targetClass: Class<MeteringRepeating>): Builder = this
232 
233         override fun setTargetName(targetName: String): Builder = this
234 
235         override fun setDefaultSessionConfig(sessionConfig: SessionConfig): Builder = this
236 
237         override fun setDefaultCaptureConfig(captureConfig: CaptureConfig): Builder = this
238 
239         override fun setSessionOptionUnpacker(
240             optionUnpacker: SessionConfig.OptionUnpacker
241         ): Builder = this
242 
243         override fun setCaptureOptionUnpacker(
244             optionUnpacker: CaptureConfig.OptionUnpacker
245         ): Builder = this
246 
247         override fun setSurfaceOccupancyPriority(priority: Int): Builder = this
248 
249         override fun setZslDisabled(disabled: Boolean): Builder = this
250 
251         override fun setHighResolutionDisabled(disabled: Boolean): Builder = this
252 
253         override fun setCaptureType(captureType: UseCaseConfigFactory.CaptureType): Builder = this
254 
255         override fun build(): MeteringRepeating {
256             return MeteringRepeating(cameraProperties, useCaseConfig, displayInfoManager)
257         }
258     }
259 }
260