blob: 478922df51865c65979814aac76816ad2a6a29c9 [file] [log] [blame]
Igor Murashkin9c595172014-05-12 13:56:20 -07001/*
2 * Copyright (C) 2014 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
17package android.hardware.camera2.params;
18
Aurimas Liutikasdc309f22018-06-04 15:35:31 -070019import static com.android.internal.util.Preconditions.checkArrayElementsNotNull;
Aurimas Liutikasdc309f22018-06-04 15:35:31 -070020
Igor Murashkin9c595172014-05-12 13:56:20 -070021import android.graphics.ImageFormat;
22import android.graphics.PixelFormat;
23import android.hardware.camera2.CameraCharacteristics;
24import android.hardware.camera2.CameraDevice;
Zhijun He3c1ff682015-06-23 09:21:43 -070025import android.hardware.camera2.CameraMetadata;
Igor Murashkin9c595172014-05-12 13:56:20 -070026import android.hardware.camera2.CaptureRequest;
Aurimas Liutikasdc309f22018-06-04 15:35:31 -070027import android.hardware.camera2.legacy.LegacyCameraDevice;
Igor Murashkin9c595172014-05-12 13:56:20 -070028import android.hardware.camera2.utils.HashCodeHelpers;
Eino-Ville Talvalae3651202015-06-19 17:29:14 -070029import android.hardware.camera2.utils.SurfaceUtils;
Yin-Chia Yeh12da1402014-07-15 10:37:31 -070030import android.util.Range;
Igor Murashkin9c595172014-05-12 13:56:20 -070031import android.util.Size;
Eino-Ville Talvala0819c752015-06-17 11:34:41 -070032import android.util.SparseIntArray;
Aurimas Liutikasdc309f22018-06-04 15:35:31 -070033import android.view.Surface;
Igor Murashkin9c595172014-05-12 13:56:20 -070034
35import java.util.Arrays;
36import java.util.HashMap;
37import java.util.Objects;
Yin-Chia Yehb0056642014-07-28 13:17:05 -070038import java.util.Set;
Igor Murashkin9c595172014-05-12 13:56:20 -070039
Igor Murashkin9c595172014-05-12 13:56:20 -070040/**
41 * Immutable class to store the available stream
Eino-Ville Talvalab67a3b32014-06-06 13:07:20 -070042 * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP configurations} to set up
43 * {@link android.view.Surface Surfaces} for creating a
44 * {@link android.hardware.camera2.CameraCaptureSession capture session} with
45 * {@link android.hardware.camera2.CameraDevice#createCaptureSession}.
Igor Murashkin9c595172014-05-12 13:56:20 -070046 * <!-- TODO: link to input stream configuration -->
47 *
48 * <p>This is the authoritative list for all <!-- input/ -->output formats (and sizes respectively
49 * for that format) that are supported by a camera device.</p>
50 *
51 * <p>This also contains the minimum frame durations and stall durations for each format/size
52 * combination that can be used to calculate effective frame rate when submitting multiple captures.
53 * </p>
54 *
55 * <p>An instance of this object is available from {@link CameraCharacteristics} using
56 * the {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP} key and the
57 * {@link CameraCharacteristics#get} method.</p>
58 *
59 * <pre><code>{@code
60 * CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
61 * StreamConfigurationMap configs = characteristics.get(
62 * CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
63 * }</code></pre>
64 *
65 * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
Eino-Ville Talvalab67a3b32014-06-06 13:07:20 -070066 * @see CameraDevice#createCaptureSession
Igor Murashkin9c595172014-05-12 13:56:20 -070067 */
68public final class StreamConfigurationMap {
69
70 private static final String TAG = "StreamConfigurationMap";
Ruben Brunk3e4fed22014-06-18 17:08:42 -070071
72 /**
Igor Murashkin9c595172014-05-12 13:56:20 -070073 * Create a new {@link StreamConfigurationMap}.
74 *
75 * <p>The array parameters ownership is passed to this object after creation; do not
76 * write to them after this constructor is invoked.</p>
77 *
78 * @param configurations a non-{@code null} array of {@link StreamConfiguration}
79 * @param minFrameDurations a non-{@code null} array of {@link StreamConfigurationDuration}
80 * @param stallDurations a non-{@code null} array of {@link StreamConfigurationDuration}
Shuzhen Wangf655b1c2018-12-28 15:40:36 -080081 * @param depthConfigurations a non-{@code null} array of depth {@link StreamConfiguration}
82 * @param depthMinFrameDurations a non-{@code null} array of depth
83 * {@link StreamConfigurationDuration}
84 * @param depthStallDurations a non-{@code null} array of depth
85 * {@link StreamConfigurationDuration}
86 * @param dynamicDepthConfigurations a non-{@code null} array of dynamic depth
87 * {@link StreamConfiguration}
88 * @param dynamicDepthMinFrameDurations a non-{@code null} array of dynamic depth
89 * {@link StreamConfigurationDuration}
90 * @param dynamicDepthStallDurations a non-{@code null} array of dynamic depth
91 * {@link StreamConfigurationDuration}
92 * @param heicConfigurations a non-{@code null} array of heic {@link StreamConfiguration}
93 * @param heicMinFrameDurations a non-{@code null} array of heic
94 * {@link StreamConfigurationDuration}
95 * @param heicStallDurations a non-{@code null} array of heic
96 * {@link StreamConfigurationDuration}
Yin-Chia Yeh12da1402014-07-15 10:37:31 -070097 * @param highSpeedVideoConfigurations an array of {@link HighSpeedVideoConfiguration}, null if
98 * camera device does not support high speed video recording
Eino-Ville Talvala0819c752015-06-17 11:34:41 -070099 * @param listHighResolution a flag indicating whether the device supports BURST_CAPTURE
100 * and thus needs a separate list of slow high-resolution output sizes
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700101 * @throws NullPointerException if any of the arguments except highSpeedVideoConfigurations
102 * were {@code null} or any subelements were {@code null}
Igor Murashkin9c595172014-05-12 13:56:20 -0700103 *
104 * @hide
105 */
106 public StreamConfigurationMap(
107 StreamConfiguration[] configurations,
108 StreamConfigurationDuration[] minFrameDurations,
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700109 StreamConfigurationDuration[] stallDurations,
Eino-Ville Talvala456432e2015-03-05 15:42:49 -0800110 StreamConfiguration[] depthConfigurations,
111 StreamConfigurationDuration[] depthMinFrameDurations,
112 StreamConfigurationDuration[] depthStallDurations,
Emilian Peev934ffa62019-01-04 17:48:31 +0000113 StreamConfiguration[] dynamicDepthConfigurations,
114 StreamConfigurationDuration[] dynamicDepthMinFrameDurations,
115 StreamConfigurationDuration[] dynamicDepthStallDurations,
Shuzhen Wangf655b1c2018-12-28 15:40:36 -0800116 StreamConfiguration[] heicConfigurations,
117 StreamConfigurationDuration[] heicMinFrameDurations,
118 StreamConfigurationDuration[] heicStallDurations,
Chien-Yu Chen0a551f12015-04-03 17:57:35 -0700119 HighSpeedVideoConfiguration[] highSpeedVideoConfigurations,
Eino-Ville Talvala0819c752015-06-17 11:34:41 -0700120 ReprocessFormatsMap inputOutputFormatsMap,
121 boolean listHighResolution) {
Emilian Peev2776ca32018-09-18 14:00:39 +0100122 this(configurations, minFrameDurations, stallDurations,
123 depthConfigurations, depthMinFrameDurations, depthStallDurations,
Emilian Peev934ffa62019-01-04 17:48:31 +0000124 dynamicDepthConfigurations, dynamicDepthMinFrameDurations,
Shuzhen Wangf655b1c2018-12-28 15:40:36 -0800125 dynamicDepthStallDurations,
126 heicConfigurations, heicMinFrameDurations, heicStallDurations,
127 highSpeedVideoConfigurations, inputOutputFormatsMap, listHighResolution,
128 /*enforceImplementationDefined*/ true);
Emilian Peev2776ca32018-09-18 14:00:39 +0100129 }
130
131 /**
132 * Create a new {@link StreamConfigurationMap}.
133 *
134 * <p>The array parameters ownership is passed to this object after creation; do not
135 * write to them after this constructor is invoked.</p>
136 *
137 * @param configurations a non-{@code null} array of {@link StreamConfiguration}
138 * @param minFrameDurations a non-{@code null} array of {@link StreamConfigurationDuration}
139 * @param stallDurations a non-{@code null} array of {@link StreamConfigurationDuration}
Shuzhen Wangf655b1c2018-12-28 15:40:36 -0800140 * @param depthConfigurations a non-{@code null} array of depth {@link StreamConfiguration}
141 * @param depthMinFrameDurations a non-{@code null} array of depth
142 * {@link StreamConfigurationDuration}
143 * @param depthStallDurations a non-{@code null} array of depth
144 * {@link StreamConfigurationDuration}
145 * @param dynamicDepthConfigurations a non-{@code null} array of dynamic depth
146 * {@link StreamConfiguration}
147 * @param dynamicDepthMinFrameDurations a non-{@code null} array of dynamic depth
148 * {@link StreamConfigurationDuration}
149 * @param dynamicDepthStallDurations a non-{@code null} array of dynamic depth
150 * {@link StreamConfigurationDuration}
151 * @param heicConfigurations a non-{@code null} array of heic {@link StreamConfiguration}
152 * @param heicMinFrameDurations a non-{@code null} array of heic
153 * {@link StreamConfigurationDuration}
154 * @param heicStallDurations a non-{@code null} array of heic
155 * {@link StreamConfigurationDuration}
Emilian Peev2776ca32018-09-18 14:00:39 +0100156 * @param highSpeedVideoConfigurations an array of {@link HighSpeedVideoConfiguration}, null if
157 * camera device does not support high speed video recording
158 * @param listHighResolution a flag indicating whether the device supports BURST_CAPTURE
159 * and thus needs a separate list of slow high-resolution output sizes
160 * @param enforceImplementationDefined a flag indicating whether
161 * IMPLEMENTATION_DEFINED format configuration must be present
162 * @throws NullPointerException if any of the arguments except highSpeedVideoConfigurations
163 * were {@code null} or any subelements were {@code null}
164 *
165 * @hide
166 */
167 public StreamConfigurationMap(
168 StreamConfiguration[] configurations,
169 StreamConfigurationDuration[] minFrameDurations,
170 StreamConfigurationDuration[] stallDurations,
171 StreamConfiguration[] depthConfigurations,
172 StreamConfigurationDuration[] depthMinFrameDurations,
173 StreamConfigurationDuration[] depthStallDurations,
Emilian Peev934ffa62019-01-04 17:48:31 +0000174 StreamConfiguration[] dynamicDepthConfigurations,
175 StreamConfigurationDuration[] dynamicDepthMinFrameDurations,
176 StreamConfigurationDuration[] dynamicDepthStallDurations,
Shuzhen Wangf655b1c2018-12-28 15:40:36 -0800177 StreamConfiguration[] heicConfigurations,
178 StreamConfigurationDuration[] heicMinFrameDurations,
179 StreamConfigurationDuration[] heicStallDurations,
Emilian Peev2776ca32018-09-18 14:00:39 +0100180 HighSpeedVideoConfiguration[] highSpeedVideoConfigurations,
181 ReprocessFormatsMap inputOutputFormatsMap,
182 boolean listHighResolution,
183 boolean enforceImplementationDefined) {
Eino-Ville Talvala72064af2015-08-11 13:33:37 -0700184
Shuzhen Wangf655b1c2018-12-28 15:40:36 -0800185 if (configurations == null &&
186 depthConfigurations == null &&
187 heicConfigurations == null) {
188 throw new NullPointerException("At least one of color/depth/heic configurations " +
189 "must not be null");
190 }
191
Eino-Ville Talvala72064af2015-08-11 13:33:37 -0700192 if (configurations == null) {
193 // If no color configurations exist, ensure depth ones do
Eino-Ville Talvala72064af2015-08-11 13:33:37 -0700194 mConfigurations = new StreamConfiguration[0];
195 mMinFrameDurations = new StreamConfigurationDuration[0];
196 mStallDurations = new StreamConfigurationDuration[0];
197 } else {
198 mConfigurations = checkArrayElementsNotNull(configurations, "configurations");
199 mMinFrameDurations = checkArrayElementsNotNull(minFrameDurations, "minFrameDurations");
200 mStallDurations = checkArrayElementsNotNull(stallDurations, "stallDurations");
201 }
202
Eino-Ville Talvala0819c752015-06-17 11:34:41 -0700203 mListHighResolution = listHighResolution;
Eino-Ville Talvala456432e2015-03-05 15:42:49 -0800204
205 if (depthConfigurations == null) {
206 mDepthConfigurations = new StreamConfiguration[0];
207 mDepthMinFrameDurations = new StreamConfigurationDuration[0];
208 mDepthStallDurations = new StreamConfigurationDuration[0];
209 } else {
210 mDepthConfigurations = checkArrayElementsNotNull(depthConfigurations,
211 "depthConfigurations");
212 mDepthMinFrameDurations = checkArrayElementsNotNull(depthMinFrameDurations,
213 "depthMinFrameDurations");
214 mDepthStallDurations = checkArrayElementsNotNull(depthStallDurations,
215 "depthStallDurations");
216 }
217
Emilian Peev934ffa62019-01-04 17:48:31 +0000218 if (dynamicDepthConfigurations == null) {
219 mDynamicDepthConfigurations = new StreamConfiguration[0];
220 mDynamicDepthMinFrameDurations = new StreamConfigurationDuration[0];
221 mDynamicDepthStallDurations = new StreamConfigurationDuration[0];
222 } else {
223 mDynamicDepthConfigurations = checkArrayElementsNotNull(dynamicDepthConfigurations,
224 "dynamicDepthConfigurations");
225 mDynamicDepthMinFrameDurations = checkArrayElementsNotNull(
226 dynamicDepthMinFrameDurations, "dynamicDepthMinFrameDurations");
227 mDynamicDepthStallDurations = checkArrayElementsNotNull(dynamicDepthStallDurations,
228 "dynamicDepthStallDurations");
229 }
230
Shuzhen Wangf655b1c2018-12-28 15:40:36 -0800231 if (heicConfigurations == null) {
232 mHeicConfigurations = new StreamConfiguration[0];
233 mHeicMinFrameDurations = new StreamConfigurationDuration[0];
234 mHeicStallDurations = new StreamConfigurationDuration[0];
235 } else {
236 mHeicConfigurations = checkArrayElementsNotNull(heicConfigurations,
237 "heicConfigurations");
238 mHeicMinFrameDurations = checkArrayElementsNotNull(heicMinFrameDurations,
239 "heicMinFrameDurations");
240 mHeicStallDurations = checkArrayElementsNotNull(heicStallDurations,
241 "heicStallDurations");
242 }
243
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700244 if (highSpeedVideoConfigurations == null) {
245 mHighSpeedVideoConfigurations = new HighSpeedVideoConfiguration[0];
246 } else {
247 mHighSpeedVideoConfigurations = checkArrayElementsNotNull(
248 highSpeedVideoConfigurations, "highSpeedVideoConfigurations");
249 }
Igor Murashkin9c595172014-05-12 13:56:20 -0700250
251 // For each format, track how many sizes there are available to configure
Eino-Ville Talvala72064af2015-08-11 13:33:37 -0700252 for (StreamConfiguration config : mConfigurations) {
Eino-Ville Talvala0819c752015-06-17 11:34:41 -0700253 int fmt = config.getFormat();
254 SparseIntArray map = null;
255 if (config.isOutput()) {
256 mAllOutputFormats.put(fmt, mAllOutputFormats.get(fmt) + 1);
257 long duration = 0;
258 if (mListHighResolution) {
259 for (StreamConfigurationDuration configurationDuration : mMinFrameDurations) {
260 if (configurationDuration.getFormat() == fmt &&
261 configurationDuration.getWidth() == config.getSize().getWidth() &&
262 configurationDuration.getHeight() == config.getSize().getHeight()) {
263 duration = configurationDuration.getDuration();
264 break;
265 }
266 }
267 }
268 map = duration <= DURATION_20FPS_NS ?
269 mOutputFormats : mHighResOutputFormats;
270 } else {
271 map = mInputFormats;
Igor Murashkin9c595172014-05-12 13:56:20 -0700272 }
Eino-Ville Talvala0819c752015-06-17 11:34:41 -0700273 map.put(fmt, map.get(fmt) + 1);
Eino-Ville Talvala456432e2015-03-05 15:42:49 -0800274 }
275
276 // For each depth format, track how many sizes there are available to configure
277 for (StreamConfiguration config : mDepthConfigurations) {
278 if (!config.isOutput()) {
279 // Ignoring input depth configs
280 continue;
281 }
282
Eino-Ville Talvala0819c752015-06-17 11:34:41 -0700283 mDepthOutputFormats.put(config.getFormat(),
284 mDepthOutputFormats.get(config.getFormat()) + 1);
Igor Murashkin9c595172014-05-12 13:56:20 -0700285 }
Emilian Peev934ffa62019-01-04 17:48:31 +0000286 for (StreamConfiguration config : mDynamicDepthConfigurations) {
287 if (!config.isOutput()) {
288 // Ignoring input configs
289 continue;
290 }
291
292 mDynamicDepthOutputFormats.put(config.getFormat(),
293 mDynamicDepthOutputFormats.get(config.getFormat()) + 1);
294 }
Igor Murashkin9c595172014-05-12 13:56:20 -0700295
Shuzhen Wangf655b1c2018-12-28 15:40:36 -0800296 // For each heic format, track how many sizes there are available to configure
297 for (StreamConfiguration config : mHeicConfigurations) {
298 if (!config.isOutput()) {
299 // Ignoring input depth configs
300 continue;
301 }
302
303 mHeicOutputFormats.put(config.getFormat(),
304 mHeicOutputFormats.get(config.getFormat()) + 1);
305 }
306
Emilian Peev2776ca32018-09-18 14:00:39 +0100307 if (configurations != null && enforceImplementationDefined &&
Eino-Ville Talvala72064af2015-08-11 13:33:37 -0700308 mOutputFormats.indexOfKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) < 0) {
Igor Murashkin9c595172014-05-12 13:56:20 -0700309 throw new AssertionError(
310 "At least one stream configuration for IMPLEMENTATION_DEFINED must exist");
311 }
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700312
313 // For each Size/FPS range, track how many FPS range/Size there are available
314 for (HighSpeedVideoConfiguration config : mHighSpeedVideoConfigurations) {
315 Size size = config.getSize();
316 Range<Integer> fpsRange = config.getFpsRange();
317 Integer fpsRangeCount = mHighSpeedVideoSizeMap.get(size);
318 if (fpsRangeCount == null) {
319 fpsRangeCount = 0;
320 }
321 mHighSpeedVideoSizeMap.put(size, fpsRangeCount + 1);
322 Integer sizeCount = mHighSpeedVideoFpsRangeMap.get(fpsRange);
323 if (sizeCount == null) {
324 sizeCount = 0;
325 }
326 mHighSpeedVideoFpsRangeMap.put(fpsRange, sizeCount + 1);
327 }
Chien-Yu Chen0a551f12015-04-03 17:57:35 -0700328
329 mInputOutputFormatsMap = inputOutputFormatsMap;
Igor Murashkin9c595172014-05-12 13:56:20 -0700330 }
331
332 /**
333 * Get the image {@code format} output formats in this stream configuration.
334 *
335 * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
336 * or in {@link PixelFormat} (and there is no possibility of collision).</p>
337 *
338 * <p>Formats listed in this array are guaranteed to return true if queried with
Eino-Ville Talvalaf3621f32014-08-26 14:53:39 -0700339 * {@link #isOutputSupportedFor(int)}.</p>
Igor Murashkin9c595172014-05-12 13:56:20 -0700340 *
341 * @return an array of integer format
342 *
343 * @see ImageFormat
344 * @see PixelFormat
345 */
Emilian Peev2776ca32018-09-18 14:00:39 +0100346 public int[] getOutputFormats() {
Igor Murashkin9c595172014-05-12 13:56:20 -0700347 return getPublicFormats(/*output*/true);
348 }
349
350 /**
Chien-Yu Chen0a551f12015-04-03 17:57:35 -0700351 * Get the image {@code format} output formats for a reprocessing input format.
352 *
353 * <p>When submitting a {@link CaptureRequest} with an input Surface of a given format,
354 * the only allowed target outputs of the {@link CaptureRequest} are the ones with a format
355 * listed in the return value of this method. Including any other output Surface as a target
356 * will throw an IllegalArgumentException. If no output format is supported given the input
357 * format, an empty int[] will be returned.</p>
358 *
359 * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
360 * or in {@link PixelFormat} (and there is no possibility of collision).</p>
361 *
362 * <p>Formats listed in this array are guaranteed to return true if queried with
363 * {@link #isOutputSupportedFor(int)}.</p>
364 *
365 * @return an array of integer format
366 *
367 * @see ImageFormat
368 * @see PixelFormat
369 */
Emilian Peev2776ca32018-09-18 14:00:39 +0100370 public int[] getValidOutputFormatsForInput(int inputFormat) {
Chien-Yu Chen0a551f12015-04-03 17:57:35 -0700371 if (mInputOutputFormatsMap == null) {
372 return new int[0];
373 }
Shuzhen Wangf655b1c2018-12-28 15:40:36 -0800374
375 int[] outputs = mInputOutputFormatsMap.getOutputs(inputFormat);
376 if (mHeicOutputFormats.size() > 0) {
377 // All reprocessing formats map contain JPEG.
378 int[] outputsWithHeic = Arrays.copyOf(outputs, outputs.length+1);
379 outputsWithHeic[outputs.length] = ImageFormat.HEIC;
380 return outputsWithHeic;
381 } else {
382 return outputs;
383 }
Chien-Yu Chen0a551f12015-04-03 17:57:35 -0700384 }
385
386 /**
Igor Murashkin9c595172014-05-12 13:56:20 -0700387 * Get the image {@code format} input formats in this stream configuration.
388 *
389 * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
390 * or in {@link PixelFormat} (and there is no possibility of collision).</p>
391 *
392 * @return an array of integer format
393 *
394 * @see ImageFormat
395 * @see PixelFormat
Igor Murashkin9c595172014-05-12 13:56:20 -0700396 */
Emilian Peev2776ca32018-09-18 14:00:39 +0100397 public int[] getInputFormats() {
Igor Murashkin9c595172014-05-12 13:56:20 -0700398 return getPublicFormats(/*output*/false);
399 }
400
401 /**
402 * Get the supported input sizes for this input format.
403 *
404 * <p>The format must have come from {@link #getInputFormats}; otherwise
405 * {@code null} is returned.</p>
406 *
407 * @param format a format from {@link #getInputFormats}
408 * @return a non-empty array of sizes, or {@code null} if the format was not available.
Igor Murashkin9c595172014-05-12 13:56:20 -0700409 */
410 public Size[] getInputSizes(final int format) {
Eino-Ville Talvala0819c752015-06-17 11:34:41 -0700411 return getPublicFormatSizes(format, /*output*/false, /*highRes*/false);
Igor Murashkin9c595172014-05-12 13:56:20 -0700412 }
413
414 /**
Eino-Ville Talvalab67a3b32014-06-06 13:07:20 -0700415 * Determine whether or not output surfaces with a particular user-defined format can be passed
416 * {@link CameraDevice#createCaptureSession createCaptureSession}.
Igor Murashkin9c595172014-05-12 13:56:20 -0700417 *
418 * <p>This method determines that the output {@code format} is supported by the camera device;
419 * each output {@code surface} target may or may not itself support that {@code format}.
420 * Refer to the class which provides the surface for additional documentation.</p>
421 *
422 * <p>Formats for which this returns {@code true} are guaranteed to exist in the result
423 * returned by {@link #getOutputSizes}.</p>
424 *
425 * @param format an image format from either {@link ImageFormat} or {@link PixelFormat}
426 * @return
427 * {@code true} iff using a {@code surface} with this {@code format} will be
Eino-Ville Talvalab67a3b32014-06-06 13:07:20 -0700428 * supported with {@link CameraDevice#createCaptureSession}
Igor Murashkin9c595172014-05-12 13:56:20 -0700429 *
430 * @throws IllegalArgumentException
431 * if the image format was not a defined named constant
432 * from either {@link ImageFormat} or {@link PixelFormat}
433 *
434 * @see ImageFormat
435 * @see PixelFormat
Eino-Ville Talvalab67a3b32014-06-06 13:07:20 -0700436 * @see CameraDevice#createCaptureSession
Igor Murashkin9c595172014-05-12 13:56:20 -0700437 */
438 public boolean isOutputSupportedFor(int format) {
439 checkArgumentFormat(format);
440
Eino-Ville Talvala456432e2015-03-05 15:42:49 -0800441 int internalFormat = imageFormatToInternal(format);
442 int dataspace = imageFormatToDataspace(format);
443 if (dataspace == HAL_DATASPACE_DEPTH) {
Eino-Ville Talvala0819c752015-06-17 11:34:41 -0700444 return mDepthOutputFormats.indexOfKey(internalFormat) >= 0;
Emilian Peev934ffa62019-01-04 17:48:31 +0000445 } else if (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) {
446 return mDynamicDepthOutputFormats.indexOfKey(internalFormat) >= 0;
Shuzhen Wangf655b1c2018-12-28 15:40:36 -0800447 } else if (dataspace == HAL_DATASPACE_HEIF) {
448 return mHeicOutputFormats.indexOfKey(internalFormat) >= 0;
Eino-Ville Talvala456432e2015-03-05 15:42:49 -0800449 } else {
Eino-Ville Talvala0819c752015-06-17 11:34:41 -0700450 return getFormatsMap(/*output*/true).indexOfKey(internalFormat) >= 0;
Eino-Ville Talvala456432e2015-03-05 15:42:49 -0800451 }
Igor Murashkin9c595172014-05-12 13:56:20 -0700452 }
453
454 /**
455 * Determine whether or not output streams can be configured with a particular class
456 * as a consumer.
457 *
458 * <p>The following list is generally usable for outputs:
459 * <ul>
460 * <li>{@link android.media.ImageReader} -
461 * Recommended for image processing or streaming to external resources (such as a file or
462 * network)
463 * <li>{@link android.media.MediaRecorder} -
464 * Recommended for recording video (simple to use)
465 * <li>{@link android.media.MediaCodec} -
466 * Recommended for recording video (more complicated to use, with more flexibility)
467 * <li>{@link android.renderscript.Allocation} -
468 * Recommended for image processing with {@link android.renderscript RenderScript}
469 * <li>{@link android.view.SurfaceHolder} -
470 * Recommended for low-power camera preview with {@link android.view.SurfaceView}
471 * <li>{@link android.graphics.SurfaceTexture} -
472 * Recommended for OpenGL-accelerated preview processing or compositing with
473 * {@link android.view.TextureView}
474 * </ul>
475 * </p>
476 *
477 * <p>Generally speaking this means that creating a {@link Surface} from that class <i>may</i>
478 * provide a producer endpoint that is suitable to be used with
Eino-Ville Talvalab67a3b32014-06-06 13:07:20 -0700479 * {@link CameraDevice#createCaptureSession}.</p>
Igor Murashkin9c595172014-05-12 13:56:20 -0700480 *
481 * <p>Since not all of the above classes support output of all format and size combinations,
482 * the particular combination should be queried with {@link #isOutputSupportedFor(Surface)}.</p>
483 *
484 * @param klass a non-{@code null} {@link Class} object reference
485 * @return {@code true} if this class is supported as an output, {@code false} otherwise
486 *
487 * @throws NullPointerException if {@code klass} was {@code null}
488 *
Eino-Ville Talvalab67a3b32014-06-06 13:07:20 -0700489 * @see CameraDevice#createCaptureSession
Igor Murashkin9c595172014-05-12 13:56:20 -0700490 * @see #isOutputSupportedFor(Surface)
491 */
492 public static <T> boolean isOutputSupportedFor(Class<T> klass) {
Daulet Zhanguzin0eb0a772019-12-30 17:13:24 +0000493 Objects.requireNonNull(klass, "klass must not be null");
Igor Murashkin9c595172014-05-12 13:56:20 -0700494
495 if (klass == android.media.ImageReader.class) {
496 return true;
497 } else if (klass == android.media.MediaRecorder.class) {
498 return true;
499 } else if (klass == android.media.MediaCodec.class) {
500 return true;
501 } else if (klass == android.renderscript.Allocation.class) {
502 return true;
503 } else if (klass == android.view.SurfaceHolder.class) {
504 return true;
505 } else if (klass == android.graphics.SurfaceTexture.class) {
506 return true;
507 }
508
509 return false;
510 }
511
512 /**
Eino-Ville Talvalab67a3b32014-06-06 13:07:20 -0700513 * Determine whether or not the {@code surface} in its current state is suitable to be included
514 * in a {@link CameraDevice#createCaptureSession capture session} as an output.
Igor Murashkin9c595172014-05-12 13:56:20 -0700515 *
516 * <p>Not all surfaces are usable with the {@link CameraDevice}, and not all configurations
517 * of that {@code surface} are compatible. Some classes that provide the {@code surface} are
518 * compatible with the {@link CameraDevice} in general
519 * (see {@link #isOutputSupportedFor(Class)}, but it is the caller's responsibility to put the
520 * {@code surface} into a state that will be compatible with the {@link CameraDevice}.</p>
521 *
522 * <p>Reasons for a {@code surface} being specifically incompatible might be:
523 * <ul>
524 * <li>Using a format that's not listed by {@link #getOutputFormats}
525 * <li>Using a format/size combination that's not listed by {@link #getOutputSizes}
526 * <li>The {@code surface} itself is not in a state where it can service a new producer.</p>
527 * </li>
528 * </ul>
529 *
Eino-Ville Talvalafa0b9a02015-01-20 12:30:59 -0800530 * <p>Surfaces from flexible sources will return true even if the exact size of the Surface does
531 * not match a camera-supported size, as long as the format (or class) is supported and the
532 * camera device supports a size that is equal to or less than 1080p in that format. If such as
533 * Surface is used to create a capture session, it will have its size rounded to the nearest
534 * supported size, below or equal to 1080p. Flexible sources include SurfaceView, SurfaceTexture,
535 * and ImageReader.</p>
536 *
537 * <p>This is not an exhaustive list; see the particular class's documentation for further
Igor Murashkin9c595172014-05-12 13:56:20 -0700538 * possible reasons of incompatibility.</p>
539 *
540 * @param surface a non-{@code null} {@link Surface} object reference
541 * @return {@code true} if this is supported, {@code false} otherwise
542 *
543 * @throws NullPointerException if {@code surface} was {@code null}
Eino-Ville Talvalafa0b9a02015-01-20 12:30:59 -0800544 * @throws IllegalArgumentException if the Surface endpoint is no longer valid
Igor Murashkin9c595172014-05-12 13:56:20 -0700545 *
Eino-Ville Talvalab67a3b32014-06-06 13:07:20 -0700546 * @see CameraDevice#createCaptureSession
Igor Murashkin9c595172014-05-12 13:56:20 -0700547 * @see #isOutputSupportedFor(Class)
548 */
549 public boolean isOutputSupportedFor(Surface surface) {
Daulet Zhanguzin0eb0a772019-12-30 17:13:24 +0000550 Objects.requireNonNull(surface, "surface must not be null");
Igor Murashkin9c595172014-05-12 13:56:20 -0700551
Eino-Ville Talvalae3651202015-06-19 17:29:14 -0700552 Size surfaceSize = SurfaceUtils.getSurfaceSize(surface);
553 int surfaceFormat = SurfaceUtils.getSurfaceFormat(surface);
554 int surfaceDataspace = SurfaceUtils.getSurfaceDataspace(surface);
Igor Murashkin9c595172014-05-12 13:56:20 -0700555
Eino-Ville Talvalafa0b9a02015-01-20 12:30:59 -0800556 // See if consumer is flexible.
Eino-Ville Talvalae3651202015-06-19 17:29:14 -0700557 boolean isFlexible = SurfaceUtils.isFlexibleConsumer(surface);
Eino-Ville Talvalafa0b9a02015-01-20 12:30:59 -0800558
Eino-Ville Talvalae3651202015-06-19 17:29:14 -0700559 StreamConfiguration[] configs =
Emilian Peev934ffa62019-01-04 17:48:31 +0000560 surfaceDataspace == HAL_DATASPACE_DEPTH ? mDepthConfigurations :
561 surfaceDataspace == HAL_DATASPACE_DYNAMIC_DEPTH ? mDynamicDepthConfigurations :
Shuzhen Wangf655b1c2018-12-28 15:40:36 -0800562 surfaceDataspace == HAL_DATASPACE_HEIF ? mHeicConfigurations :
Emilian Peev934ffa62019-01-04 17:48:31 +0000563 mConfigurations;
Eino-Ville Talvalae3651202015-06-19 17:29:14 -0700564 for (StreamConfiguration config : configs) {
Eino-Ville Talvalafa0b9a02015-01-20 12:30:59 -0800565 if (config.getFormat() == surfaceFormat && config.isOutput()) {
Eino-Ville Talvalae3651202015-06-19 17:29:14 -0700566 // Matching format, either need exact size match, or a flexible consumer
Eino-Ville Talvalafa0b9a02015-01-20 12:30:59 -0800567 // and a size no bigger than MAX_DIMEN_FOR_ROUNDING
568 if (config.getSize().equals(surfaceSize)) {
569 return true;
570 } else if (isFlexible &&
571 (config.getSize().getWidth() <= LegacyCameraDevice.MAX_DIMEN_FOR_ROUNDING)) {
572 return true;
573 }
574 }
575 }
576 return false;
Igor Murashkin9c595172014-05-12 13:56:20 -0700577 }
578
579 /**
Emilian Peev2776ca32018-09-18 14:00:39 +0100580 * Determine whether or not the particular stream configuration is suitable to be included
581 * in a {@link CameraDevice#createCaptureSession capture session} as an output.
582 *
583 * @param size stream configuration size
584 * @param format stream configuration format
585 * @return {@code true} if this is supported, {@code false} otherwise
586 *
587 * @see CameraDevice#createCaptureSession
588 * @see #isOutputSupportedFor(Class)
589 * @hide
590 */
591 public boolean isOutputSupportedFor(Size size, int format) {
592 int internalFormat = imageFormatToInternal(format);
593 int dataspace = imageFormatToDataspace(format);
594
595 StreamConfiguration[] configs =
Shuzhen Wangf655b1c2018-12-28 15:40:36 -0800596 dataspace == HAL_DATASPACE_DEPTH ? mDepthConfigurations :
597 dataspace == HAL_DATASPACE_DYNAMIC_DEPTH ? mDynamicDepthConfigurations :
598 dataspace == HAL_DATASPACE_HEIF ? mHeicConfigurations :
599 mConfigurations;
Emilian Peev2776ca32018-09-18 14:00:39 +0100600 for (StreamConfiguration config : configs) {
601 if ((config.getFormat() == internalFormat) && config.isOutput() &&
602 config.getSize().equals(size)) {
603 return true;
604 }
605 }
606
607 return false;
608 }
609
610 /**
Igor Murashkin9c595172014-05-12 13:56:20 -0700611 * Get a list of sizes compatible with {@code klass} to use as an output.
612 *
Eino-Ville Talvala0819c752015-06-17 11:34:41 -0700613 * <p>Some of the supported classes may support additional formats beyond
Chien-Yu Chen0a551f12015-04-03 17:57:35 -0700614 * {@link ImageFormat#PRIVATE}; this function only returns
615 * sizes for {@link ImageFormat#PRIVATE}. For example, {@link android.media.ImageReader}
616 * supports {@link ImageFormat#YUV_420_888} and {@link ImageFormat#PRIVATE}, this method will
617 * only return the sizes for {@link ImageFormat#PRIVATE} for {@link android.media.ImageReader}
Eino-Ville Talvala0819c752015-06-17 11:34:41 -0700618 * class.</p>
Igor Murashkin9c595172014-05-12 13:56:20 -0700619 *
620 * <p>If a well-defined format such as {@code NV21} is required, use
621 * {@link #getOutputSizes(int)} instead.</p>
622 *
623 * <p>The {@code klass} should be a supported output, that querying
624 * {@code #isOutputSupportedFor(Class)} should return {@code true}.</p>
625 *
626 * @param klass
627 * a non-{@code null} {@link Class} object reference
628 * @return
Chien-Yu Chen0a551f12015-04-03 17:57:35 -0700629 * an array of supported sizes for {@link ImageFormat#PRIVATE} format,
630 * or {@code null} iff the {@code klass} is not a supported output.
631 *
Igor Murashkin9c595172014-05-12 13:56:20 -0700632 *
633 * @throws NullPointerException if {@code klass} was {@code null}
634 *
635 * @see #isOutputSupportedFor(Class)
636 */
637 public <T> Size[] getOutputSizes(Class<T> klass) {
638 if (isOutputSupportedFor(klass) == false) {
639 return null;
640 }
641
Eino-Ville Talvala456432e2015-03-05 15:42:49 -0800642 return getInternalFormatSizes(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
Eino-Ville Talvala0819c752015-06-17 11:34:41 -0700643 HAL_DATASPACE_UNKNOWN,/*output*/true, /*highRes*/false);
Igor Murashkin9c595172014-05-12 13:56:20 -0700644 }
645
646 /**
647 * Get a list of sizes compatible with the requested image {@code format}.
648 *
649 * <p>The {@code format} should be a supported format (one of the formats returned by
650 * {@link #getOutputFormats}).</p>
651 *
Eino-Ville Talvala0819c752015-06-17 11:34:41 -0700652 * As of API level 23, the {@link #getHighResolutionOutputSizes} method can be used on devices
653 * that support the
654 * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE BURST_CAPTURE}
655 * capability to get a list of high-resolution output sizes that cannot operate at the preferred
656 * 20fps rate. This means that for some supported formats, this method will return an empty
657 * list, if all the supported resolutions operate at below 20fps. For devices that do not
658 * support the BURST_CAPTURE capability, all output resolutions are listed through this method.
659 *
Igor Murashkin9c595172014-05-12 13:56:20 -0700660 * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
661 * @return
662 * an array of supported sizes,
663 * or {@code null} if the {@code format} is not a supported output
664 *
665 * @see ImageFormat
666 * @see PixelFormat
667 * @see #getOutputFormats
668 */
669 public Size[] getOutputSizes(int format) {
Eino-Ville Talvala0819c752015-06-17 11:34:41 -0700670 return getPublicFormatSizes(format, /*output*/true, /*highRes*/ false);
Igor Murashkin9c595172014-05-12 13:56:20 -0700671 }
672
673 /**
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700674 * Get a list of supported high speed video recording sizes.
Zhijun He3c1ff682015-06-23 09:21:43 -0700675 * <p>
676 * When {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO} is
677 * supported in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES}, this method will
678 * list the supported high speed video size configurations. All the sizes listed will be a
679 * subset of the sizes reported by {@link #getOutputSizes} for processed non-stalling formats
680 * (typically {@link ImageFormat#PRIVATE} {@link ImageFormat#YUV_420_888}, etc.)
681 * </p>
682 * <p>
683 * To enable high speed video recording, application must create a constrained create high speed
684 * capture session via {@link CameraDevice#createConstrainedHighSpeedCaptureSession}, and submit
Eino-Ville Talvala639fffe2015-06-30 10:34:48 -0700685 * a CaptureRequest list created by
686 * {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList}
Zhijun He3c1ff682015-06-23 09:21:43 -0700687 * to this session. The application must select the video size from this method and
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700688 * {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE FPS range} from
Zhijun He3c1ff682015-06-23 09:21:43 -0700689 * {@link #getHighSpeedVideoFpsRangesFor} to configure the constrained high speed session and
690 * generate the high speed request list. For example, if the application intends to do high
691 * speed recording, it can select the maximum size reported by this method to create high speed
692 * capture session. Note that for the use case of multiple output streams, application must
693 * select one unique size from this method to use (e.g., preview and recording streams must have
694 * the same size). Otherwise, the high speed session creation will fail. Once the size is
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700695 * selected, application can get the supported FPS ranges by
696 * {@link #getHighSpeedVideoFpsRangesFor}, and use these FPS ranges to setup the recording
Eino-Ville Talvala639fffe2015-06-30 10:34:48 -0700697 * request lists via
698 * {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList}.
Zhijun He3c1ff682015-06-23 09:21:43 -0700699 * </p>
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700700 *
Zhijun He3c1ff682015-06-23 09:21:43 -0700701 * @return an array of supported high speed video recording sizes
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700702 * @see #getHighSpeedVideoFpsRangesFor(Size)
Zhijun He3c1ff682015-06-23 09:21:43 -0700703 * @see CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO
704 * @see CameraDevice#createConstrainedHighSpeedCaptureSession
Eino-Ville Talvala639fffe2015-06-30 10:34:48 -0700705 * @see android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700706 */
707 public Size[] getHighSpeedVideoSizes() {
Yin-Chia Yehb0056642014-07-28 13:17:05 -0700708 Set<Size> keySet = mHighSpeedVideoSizeMap.keySet();
709 return keySet.toArray(new Size[keySet.size()]);
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700710 }
711
712 /**
713 * Get the frame per second ranges (fpsMin, fpsMax) for input high speed video size.
Zhijun He3c1ff682015-06-23 09:21:43 -0700714 * <p>
715 * See {@link #getHighSpeedVideoFpsRanges} for how to enable high speed recording.
716 * </p>
717 * <p>
718 * The {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE FPS ranges} reported in this method
719 * must not be used to setup capture requests that are submitted to unconstrained capture
720 * sessions, or it will result in {@link IllegalArgumentException IllegalArgumentExceptions}.
721 * </p>
722 * <p>
723 * See {@link #getHighSpeedVideoFpsRanges} for the characteristics of the returned FPS ranges.
724 * </p>
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700725 *
726 * @param size one of the sizes returned by {@link #getHighSpeedVideoSizes()}
Zhijun He3c1ff682015-06-23 09:21:43 -0700727 * @return an array of supported high speed video recording FPS ranges The upper bound of
728 * returned ranges is guaranteed to be greater than or equal to 120.
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700729 * @throws IllegalArgumentException if input size does not exist in the return value of
Zhijun He3c1ff682015-06-23 09:21:43 -0700730 * getHighSpeedVideoSizes
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700731 * @see #getHighSpeedVideoSizes()
Zhijun He3c1ff682015-06-23 09:21:43 -0700732 * @see #getHighSpeedVideoFpsRanges()
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700733 */
734 public Range<Integer>[] getHighSpeedVideoFpsRangesFor(Size size) {
735 Integer fpsRangeCount = mHighSpeedVideoSizeMap.get(size);
736 if (fpsRangeCount == null || fpsRangeCount == 0) {
737 throw new IllegalArgumentException(String.format(
738 "Size %s does not support high speed video recording", size));
739 }
740
741 @SuppressWarnings("unchecked")
742 Range<Integer>[] fpsRanges = new Range[fpsRangeCount];
743 int i = 0;
744 for (HighSpeedVideoConfiguration config : mHighSpeedVideoConfigurations) {
745 if (size.equals(config.getSize())) {
746 fpsRanges[i++] = config.getFpsRange();
747 }
748 }
749 return fpsRanges;
750 }
751
752 /**
753 * Get a list of supported high speed video recording FPS ranges.
Zhijun He3c1ff682015-06-23 09:21:43 -0700754 * <p>
755 * When {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO} is
756 * supported in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES}, this method will
757 * list the supported high speed video FPS range configurations. Application can then use
758 * {@link #getHighSpeedVideoSizesFor} to query available sizes for one of returned FPS range.
759 * </p>
760 * <p>
761 * To enable high speed video recording, application must create a constrained create high speed
762 * capture session via {@link CameraDevice#createConstrainedHighSpeedCaptureSession}, and submit
Eino-Ville Talvala639fffe2015-06-30 10:34:48 -0700763 * a CaptureRequest list created by
764 * {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList}
Zhijun He3c1ff682015-06-23 09:21:43 -0700765 * to this session. The application must select the video size from this method and
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700766 * {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE FPS range} from
Zhijun He3c1ff682015-06-23 09:21:43 -0700767 * {@link #getHighSpeedVideoFpsRangesFor} to configure the constrained high speed session and
768 * generate the high speed request list. For example, if the application intends to do high
769 * speed recording, it can select one FPS range reported by this method, query the video sizes
770 * corresponding to this FPS range by {@link #getHighSpeedVideoSizesFor} and use one of reported
771 * sizes to create a high speed capture session. Note that for the use case of multiple output
772 * streams, application must select one unique size from this method to use (e.g., preview and
773 * recording streams must have the same size). Otherwise, the high speed session creation will
774 * fail. Once the high speed capture session is created, the application can set the FPS range
775 * in the recording request lists via
Eino-Ville Talvala639fffe2015-06-30 10:34:48 -0700776 * {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList}.
Zhijun He3c1ff682015-06-23 09:21:43 -0700777 * </p>
778 * <p>
779 * The FPS ranges reported by this method will have below characteristics:
780 * <li>The fpsMin and fpsMax will be a multiple 30fps.</li>
781 * <li>The fpsMin will be no less than 30fps, the fpsMax will be no less than 120fps.</li>
782 * <li>At least one range will be a fixed FPS range where fpsMin == fpsMax.</li>
783 * <li>For each fixed FPS range, there will be one corresponding variable FPS range [30,
784 * fps_max]. These kinds of FPS ranges are suitable for preview-only use cases where the
785 * application doesn't want the camera device always produce higher frame rate than the display
786 * refresh rate.</li>
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700787 * </p>
788 *
Zhijun He3c1ff682015-06-23 09:21:43 -0700789 * @return an array of supported high speed video recording FPS ranges The upper bound of
790 * returned ranges is guaranteed to be larger or equal to 120.
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700791 * @see #getHighSpeedVideoSizesFor
Zhijun He3c1ff682015-06-23 09:21:43 -0700792 * @see CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO
793 * @see CameraDevice#createConstrainedHighSpeedCaptureSession
Aurimas Liutikasdc309f22018-06-04 15:35:31 -0700794 * @see android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700795 */
796 @SuppressWarnings("unchecked")
797 public Range<Integer>[] getHighSpeedVideoFpsRanges() {
Yin-Chia Yehb0056642014-07-28 13:17:05 -0700798 Set<Range<Integer>> keySet = mHighSpeedVideoFpsRangeMap.keySet();
799 return keySet.toArray(new Range[keySet.size()]);
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700800 }
801
802 /**
Zhijun He3c1ff682015-06-23 09:21:43 -0700803 * Get the supported video sizes for an input high speed FPS range.
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700804 *
Zhijun He3c1ff682015-06-23 09:21:43 -0700805 * <p> See {@link #getHighSpeedVideoSizes} for how to enable high speed recording.</p>
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700806 *
807 * @param fpsRange one of the FPS range returned by {@link #getHighSpeedVideoFpsRanges()}
Zhijun He3c1ff682015-06-23 09:21:43 -0700808 * @return An array of video sizes to create high speed capture sessions for high speed streaming
809 * use cases.
Yin-Chia Yeh12da1402014-07-15 10:37:31 -0700810 *
811 * @throws IllegalArgumentException if input FPS range does not exist in the return value of
812 * getHighSpeedVideoFpsRanges
813 * @see #getHighSpeedVideoFpsRanges()
814 */
815 public Size[] getHighSpeedVideoSizesFor(Range<Integer> fpsRange) {
816 Integer sizeCount = mHighSpeedVideoFpsRangeMap.get(fpsRange);
817 if (sizeCount == null || sizeCount == 0) {
818 throw new IllegalArgumentException(String.format(
819 "FpsRange %s does not support high speed video recording", fpsRange));
820 }
821
822 Size[] sizes = new Size[sizeCount];
823 int i = 0;
824 for (HighSpeedVideoConfiguration config : mHighSpeedVideoConfigurations) {
825 if (fpsRange.equals(config.getFpsRange())) {
826 sizes[i++] = config.getSize();
827 }
828 }
829 return sizes;
830 }
831
832 /**
Eino-Ville Talvala0819c752015-06-17 11:34:41 -0700833 * Get a list of supported high resolution sizes, which cannot operate at full BURST_CAPTURE
834 * rate.
835 *
836 * <p>This includes all output sizes that cannot meet the 20 fps frame rate requirements for the
837 * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE BURST_CAPTURE}
838 * capability. This does not include the stall duration, so for example, a JPEG or RAW16 output
839 * resolution with a large stall duration but a minimum frame duration that's above 20 fps will
Shuzhen Wang062c22b2019-04-09 23:05:23 -0700840 * still be listed in the regular {@link #getOutputSizes} list. All the sizes on this list that
841 * are less than 24 megapixels are still guaranteed to operate at a rate of at least 10 fps,
842 * not including stall duration. Sizes on this list that are at least 24 megapixels are allowed
843 * to operate at less than 10 fps.</p>
Eino-Ville Talvala0819c752015-06-17 11:34:41 -0700844 *
845 * <p>For a device that does not support the BURST_CAPTURE capability, this list will be
846 * {@code null}, since resolutions in the {@link #getOutputSizes} list are already not
847 * guaranteed to meet &gt;= 20 fps rate requirements. For a device that does support the
848 * BURST_CAPTURE capability, this list may be empty, if all supported resolutions meet the 20
849 * fps requirement.</p>
850 *
851 * @return an array of supported slower high-resolution sizes, or {@code null} if the
852 * BURST_CAPTURE capability is not supported
853 */
854 public Size[] getHighResolutionOutputSizes(int format) {
855 if (!mListHighResolution) return null;
856
857 return getPublicFormatSizes(format, /*output*/true, /*highRes*/ true);
858 }
859
860 /**
Igor Murashkin9c595172014-05-12 13:56:20 -0700861 * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
862 * for the format/size combination (in nanoseconds).
863 *
864 * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p>
865 * <p>{@code size} should be one of the ones returned by
866 * {@link #getOutputSizes(int)}.</p>
867 *
868 * <p>This should correspond to the frame duration when only that stream is active, with all
869 * processing (typically in {@code android.*.mode}) set to either {@code OFF} or {@code FAST}.
870 * </p>
871 *
872 * <p>When multiple streams are used in a request, the minimum frame duration will be
873 * {@code max(individual stream min durations)}.</p>
874 *
Eino-Ville Talvala08bc3b02014-07-09 10:07:36 -0700875 * <p>For devices that do not support manual sensor control
876 * ({@link android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR}),
Eino-Ville Talvalaabd9d3c2014-07-28 13:01:52 -0700877 * this function may return 0.</p>
Eino-Ville Talvala08bc3b02014-07-09 10:07:36 -0700878 *
Igor Murashkin9c595172014-05-12 13:56:20 -0700879 * <!--
880 * TODO: uncomment after adding input stream support
881 * <p>The minimum frame duration of a stream (of a particular format, size) is the same
882 * regardless of whether the stream is input or output.</p>
883 * -->
884 *
885 * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
886 * @param size an output-compatible size
Ruben Brunk3e4fed22014-06-18 17:08:42 -0700887 * @return a minimum frame duration {@code >} 0 in nanoseconds, or
Eino-Ville Talvalaabd9d3c2014-07-28 13:01:52 -0700888 * 0 if the minimum frame duration is not available.
Igor Murashkin9c595172014-05-12 13:56:20 -0700889 *
890 * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
891 * @throws NullPointerException if {@code size} was {@code null}
892 *
893 * @see CaptureRequest#SENSOR_FRAME_DURATION
894 * @see #getOutputStallDuration(int, Size)
895 * @see ImageFormat
896 * @see PixelFormat
897 */
898 public long getOutputMinFrameDuration(int format, Size size) {
Daulet Zhanguzin0eb0a772019-12-30 17:13:24 +0000899 Objects.requireNonNull(size, "size must not be null");
Igor Murashkin9c595172014-05-12 13:56:20 -0700900 checkArgumentFormatSupported(format, /*output*/true);
901
Eino-Ville Talvala456432e2015-03-05 15:42:49 -0800902 return getInternalFormatDuration(imageFormatToInternal(format),
903 imageFormatToDataspace(format),
904 size,
905 DURATION_MIN_FRAME);
Igor Murashkin9c595172014-05-12 13:56:20 -0700906 }
907
908 /**
909 * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
910 * for the class/size combination (in nanoseconds).
911 *
Yuriy Romanenkoeeb19d22018-06-19 19:11:22 -0700912 * <p>This assumes that the {@code klass} is set up to use {@link ImageFormat#PRIVATE}.
Igor Murashkin9c595172014-05-12 13:56:20 -0700913 * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p>
914 *
915 * <p>{@code klass} should be one of the ones which is supported by
916 * {@link #isOutputSupportedFor(Class)}.</p>
917 *
918 * <p>{@code size} should be one of the ones returned by
919 * {@link #getOutputSizes(int)}.</p>
920 *
921 * <p>This should correspond to the frame duration when only that stream is active, with all
922 * processing (typically in {@code android.*.mode}) set to either {@code OFF} or {@code FAST}.
923 * </p>
924 *
925 * <p>When multiple streams are used in a request, the minimum frame duration will be
926 * {@code max(individual stream min durations)}.</p>
927 *
Eino-Ville Talvala08bc3b02014-07-09 10:07:36 -0700928 * <p>For devices that do not support manual sensor control
929 * ({@link android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR}),
Eino-Ville Talvalaabd9d3c2014-07-28 13:01:52 -0700930 * this function may return 0.</p>
Eino-Ville Talvala08bc3b02014-07-09 10:07:36 -0700931 *
Igor Murashkin9c595172014-05-12 13:56:20 -0700932 * <!--
933 * TODO: uncomment after adding input stream support
934 * <p>The minimum frame duration of a stream (of a particular format, size) is the same
935 * regardless of whether the stream is input or output.</p>
936 * -->
937 *
938 * @param klass
939 * a class which is supported by {@link #isOutputSupportedFor(Class)} and has a
940 * non-empty array returned by {@link #getOutputSizes(Class)}
941 * @param size an output-compatible size
Ruben Brunk3e4fed22014-06-18 17:08:42 -0700942 * @return a minimum frame duration {@code >} 0 in nanoseconds, or
Eino-Ville Talvalaabd9d3c2014-07-28 13:01:52 -0700943 * 0 if the minimum frame duration is not available.
Igor Murashkin9c595172014-05-12 13:56:20 -0700944 *
945 * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
946 * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
947 *
948 * @see CaptureRequest#SENSOR_FRAME_DURATION
949 * @see ImageFormat
950 * @see PixelFormat
951 */
952 public <T> long getOutputMinFrameDuration(final Class<T> klass, final Size size) {
953 if (!isOutputSupportedFor(klass)) {
954 throw new IllegalArgumentException("klass was not supported");
955 }
956
957 return getInternalFormatDuration(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
Eino-Ville Talvala456432e2015-03-05 15:42:49 -0800958 HAL_DATASPACE_UNKNOWN,
Igor Murashkin9c595172014-05-12 13:56:20 -0700959 size, DURATION_MIN_FRAME);
960 }
961
962 /**
963 * Get the stall duration for the format/size combination (in nanoseconds).
964 *
965 * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p>
966 * <p>{@code size} should be one of the ones returned by
967 * {@link #getOutputSizes(int)}.</p>
968 *
969 * <p>
970 * A stall duration is how much extra time would get added to the normal minimum frame duration
971 * for a repeating request that has streams with non-zero stall.
972 *
973 * <p>For example, consider JPEG captures which have the following characteristics:
974 *
975 * <ul>
976 * <li>JPEG streams act like processed YUV streams in requests for which they are not included;
977 * in requests in which they are directly referenced, they act as JPEG streams.
978 * This is because supporting a JPEG stream requires the underlying YUV data to always be ready
979 * for use by a JPEG encoder, but the encoder will only be used (and impact frame duration) on
980 * requests that actually reference a JPEG stream.
981 * <li>The JPEG processor can run concurrently to the rest of the camera pipeline, but cannot
982 * process more than 1 capture at a time.
983 * </ul>
984 *
985 * <p>In other words, using a repeating YUV request would result in a steady frame rate
986 * (let's say it's 30 FPS). If a single JPEG request is submitted periodically,
987 * the frame rate will stay at 30 FPS (as long as we wait for the previous JPEG to return each
988 * time). If we try to submit a repeating YUV + JPEG request, then the frame rate will drop from
989 * 30 FPS.</p>
990 *
991 * <p>In general, submitting a new request with a non-0 stall time stream will <em>not</em> cause a
992 * frame rate drop unless there are still outstanding buffers for that stream from previous
993 * requests.</p>
994 *
995 * <p>Submitting a repeating request with streams (call this {@code S}) is the same as setting
996 * the minimum frame duration from the normal minimum frame duration corresponding to {@code S},
997 * added with the maximum stall duration for {@code S}.</p>
998 *
999 * <p>If interleaving requests with and without a stall duration, a request will stall by the
1000 * maximum of the remaining times for each can-stall stream with outstanding buffers.</p>
1001 *
1002 * <p>This means that a stalling request will not have an exposure start until the stall has
1003 * completed.</p>
1004 *
1005 * <p>This should correspond to the stall duration when only that stream is active, with all
1006 * processing (typically in {@code android.*.mode}) set to {@code FAST} or {@code OFF}.
1007 * Setting any of the processing modes to {@code HIGH_QUALITY} effectively results in an
1008 * indeterminate stall duration for all streams in a request (the regular stall calculation
1009 * rules are ignored).</p>
1010 *
1011 * <p>The following formats may always have a stall duration:
1012 * <ul>
1013 * <li>{@link ImageFormat#JPEG JPEG}
1014 * <li>{@link ImageFormat#RAW_SENSOR RAW16}
Yin-Chia Yeh44581ff2015-12-07 17:15:24 -08001015 * <li>{@link ImageFormat#RAW_PRIVATE RAW_PRIVATE}
Igor Murashkin9c595172014-05-12 13:56:20 -07001016 * </ul>
1017 * </p>
1018 *
1019 * <p>The following formats will never have a stall duration:
1020 * <ul>
1021 * <li>{@link ImageFormat#YUV_420_888 YUV_420_888}
1022 * <li>{@link #isOutputSupportedFor(Class) Implementation-Defined}
1023 * </ul></p>
1024 *
1025 * <p>
1026 * All other formats may or may not have an allowed stall duration on a per-capability basis;
1027 * refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
1028 * android.request.availableCapabilities} for more details.</p>
1029 * </p>
1030 *
1031 * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration}
1032 * for more information about calculating the max frame rate (absent stalls).</p>
1033 *
1034 * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
1035 * @param size an output-compatible size
1036 * @return a stall duration {@code >=} 0 in nanoseconds
1037 *
1038 * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
1039 * @throws NullPointerException if {@code size} was {@code null}
1040 *
1041 * @see CaptureRequest#SENSOR_FRAME_DURATION
1042 * @see ImageFormat
1043 * @see PixelFormat
1044 */
1045 public long getOutputStallDuration(int format, Size size) {
1046 checkArgumentFormatSupported(format, /*output*/true);
1047
1048 return getInternalFormatDuration(imageFormatToInternal(format),
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001049 imageFormatToDataspace(format),
1050 size,
1051 DURATION_STALL);
Igor Murashkin9c595172014-05-12 13:56:20 -07001052 }
1053
1054 /**
1055 * Get the stall duration for the class/size combination (in nanoseconds).
1056 *
Yuriy Romanenkoeeb19d22018-06-19 19:11:22 -07001057 * <p>This assumes that the {@code klass} is set up to use {@link ImageFormat#PRIVATE}.
Igor Murashkin9c595172014-05-12 13:56:20 -07001058 * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p>
1059 *
1060 * <p>{@code klass} should be one of the ones with a non-empty array returned by
1061 * {@link #getOutputSizes(Class)}.</p>
1062 *
1063 * <p>{@code size} should be one of the ones returned by
1064 * {@link #getOutputSizes(Class)}.</p>
1065 *
1066 * <p>See {@link #getOutputStallDuration(int, Size)} for a definition of a
1067 * <em>stall duration</em>.</p>
1068 *
1069 * @param klass
1070 * a class which is supported by {@link #isOutputSupportedFor(Class)} and has a
1071 * non-empty array returned by {@link #getOutputSizes(Class)}
1072 * @param size an output-compatible size
1073 * @return a minimum frame duration {@code >=} 0 in nanoseconds
1074 *
1075 * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
1076 * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
1077 *
1078 * @see CaptureRequest#SENSOR_FRAME_DURATION
1079 * @see ImageFormat
1080 * @see PixelFormat
1081 */
1082 public <T> long getOutputStallDuration(final Class<T> klass, final Size size) {
1083 if (!isOutputSupportedFor(klass)) {
1084 throw new IllegalArgumentException("klass was not supported");
1085 }
1086
1087 return getInternalFormatDuration(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001088 HAL_DATASPACE_UNKNOWN, size, DURATION_STALL);
Igor Murashkin9c595172014-05-12 13:56:20 -07001089 }
1090
1091 /**
1092 * Check if this {@link StreamConfigurationMap} is equal to another
1093 * {@link StreamConfigurationMap}.
1094 *
1095 * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
1096 *
1097 * @return {@code true} if the objects were equal, {@code false} otherwise
1098 */
1099 @Override
1100 public boolean equals(final Object obj) {
1101 if (obj == null) {
1102 return false;
1103 }
1104 if (this == obj) {
1105 return true;
1106 }
1107 if (obj instanceof StreamConfigurationMap) {
1108 final StreamConfigurationMap other = (StreamConfigurationMap) obj;
1109 // XX: do we care about order?
1110 return Arrays.equals(mConfigurations, other.mConfigurations) &&
1111 Arrays.equals(mMinFrameDurations, other.mMinFrameDurations) &&
Yin-Chia Yeh12da1402014-07-15 10:37:31 -07001112 Arrays.equals(mStallDurations, other.mStallDurations) &&
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001113 Arrays.equals(mDepthConfigurations, other.mDepthConfigurations) &&
Emilian Peev934ffa62019-01-04 17:48:31 +00001114 Arrays.equals(mDepthMinFrameDurations, other.mDepthMinFrameDurations) &&
1115 Arrays.equals(mDepthStallDurations, other.mDepthStallDurations) &&
1116 Arrays.equals(mDynamicDepthConfigurations, other.mDynamicDepthConfigurations) &&
1117 Arrays.equals(mDynamicDepthMinFrameDurations,
1118 other.mDynamicDepthMinFrameDurations) &&
1119 Arrays.equals(mDynamicDepthStallDurations, other.mDynamicDepthStallDurations) &&
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001120 Arrays.equals(mHeicConfigurations, other.mHeicConfigurations) &&
1121 Arrays.equals(mHeicMinFrameDurations, other.mHeicMinFrameDurations) &&
1122 Arrays.equals(mHeicStallDurations, other.mHeicStallDurations) &&
Yin-Chia Yeh12da1402014-07-15 10:37:31 -07001123 Arrays.equals(mHighSpeedVideoConfigurations,
1124 other.mHighSpeedVideoConfigurations);
Igor Murashkin9c595172014-05-12 13:56:20 -07001125 }
1126 return false;
1127 }
1128
1129 /**
1130 * {@inheritDoc}
1131 */
1132 @Override
1133 public int hashCode() {
1134 // XX: do we care about order?
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001135 return HashCodeHelpers.hashCodeGeneric(
Emilian Peev934ffa62019-01-04 17:48:31 +00001136 mConfigurations, mMinFrameDurations, mStallDurations,
1137 mDepthConfigurations, mDepthMinFrameDurations, mDepthStallDurations,
1138 mDynamicDepthConfigurations, mDynamicDepthMinFrameDurations,
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001139 mDynamicDepthStallDurations, mHeicConfigurations,
1140 mHeicMinFrameDurations, mHeicStallDurations,
1141 mHighSpeedVideoConfigurations);
Igor Murashkin9c595172014-05-12 13:56:20 -07001142 }
1143
1144 // Check that the argument is supported by #getOutputFormats or #getInputFormats
1145 private int checkArgumentFormatSupported(int format, boolean output) {
1146 checkArgumentFormat(format);
1147
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001148 int internalFormat = imageFormatToInternal(format);
1149 int internalDataspace = imageFormatToDataspace(format);
1150
1151 if (output) {
1152 if (internalDataspace == HAL_DATASPACE_DEPTH) {
1153 if (mDepthOutputFormats.indexOfKey(internalFormat) >= 0) {
1154 return format;
1155 }
Emilian Peev934ffa62019-01-04 17:48:31 +00001156 } else if (internalDataspace == HAL_DATASPACE_DYNAMIC_DEPTH) {
1157 if (mDynamicDepthOutputFormats.indexOfKey(internalFormat) >= 0) {
1158 return format;
1159 }
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001160 } else if (internalDataspace == HAL_DATASPACE_HEIF) {
1161 if (mHeicOutputFormats.indexOfKey(internalFormat) >= 0) {
1162 return format;
1163 }
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001164 } else {
1165 if (mAllOutputFormats.indexOfKey(internalFormat) >= 0) {
1166 return format;
1167 }
1168 }
1169 } else {
1170 if (mInputFormats.indexOfKey(internalFormat) >= 0) {
Igor Murashkin9c595172014-05-12 13:56:20 -07001171 return format;
1172 }
1173 }
1174
1175 throw new IllegalArgumentException(String.format(
1176 "format %x is not supported by this stream configuration map", format));
1177 }
1178
1179 /**
1180 * Ensures that the format is either user-defined or implementation defined.
1181 *
1182 * <p>If a format has a different internal representation than the public representation,
1183 * passing in the public representation here will fail.</p>
1184 *
1185 * <p>For example if trying to use {@link ImageFormat#JPEG}:
1186 * it has a different public representation than the internal representation
1187 * {@code HAL_PIXEL_FORMAT_BLOB}, this check will fail.</p>
1188 *
1189 * <p>Any invalid/undefined formats will raise an exception.</p>
1190 *
1191 * @param format image format
1192 * @return the format
1193 *
1194 * @throws IllegalArgumentException if the format was invalid
1195 */
1196 static int checkArgumentFormatInternal(int format) {
1197 switch (format) {
1198 case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
1199 case HAL_PIXEL_FORMAT_BLOB:
Eino-Ville Talvalad3b85f62014-08-05 15:02:31 -07001200 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001201 case HAL_PIXEL_FORMAT_Y16:
Igor Murashkin9c595172014-05-12 13:56:20 -07001202 return format;
1203 case ImageFormat.JPEG:
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001204 case ImageFormat.HEIC:
Igor Murashkin9c595172014-05-12 13:56:20 -07001205 throw new IllegalArgumentException(
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001206 "An unknown internal format: " + format);
Igor Murashkin9c595172014-05-12 13:56:20 -07001207 default:
1208 return checkArgumentFormat(format);
1209 }
1210 }
1211
1212 /**
1213 * Ensures that the format is publicly user-defined in either ImageFormat or PixelFormat.
1214 *
1215 * <p>If a format has a different public representation than the internal representation,
1216 * passing in the internal representation here will fail.</p>
1217 *
1218 * <p>For example if trying to use {@code HAL_PIXEL_FORMAT_BLOB}:
1219 * it has a different internal representation than the public representation
1220 * {@link ImageFormat#JPEG}, this check will fail.</p>
1221 *
1222 * <p>Any invalid/undefined formats will raise an exception, including implementation-defined.
1223 * </p>
1224 *
1225 * <p>Note that {@code @hide} and deprecated formats will not pass this check.</p>
1226 *
1227 * @param format image format
1228 * @return the format
1229 *
1230 * @throws IllegalArgumentException if the format was not user-defined
1231 */
1232 static int checkArgumentFormat(int format) {
Igor Murashkin9c595172014-05-12 13:56:20 -07001233 if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
1234 throw new IllegalArgumentException(String.format(
1235 "format 0x%x was not defined in either ImageFormat or PixelFormat", format));
1236 }
1237
1238 return format;
1239 }
1240
1241 /**
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001242 * Convert an internal format compatible with {@code graphics.h} into public-visible
1243 * {@code ImageFormat}. This assumes the dataspace of the format is not HAL_DATASPACE_DEPTH.
Igor Murashkin9c595172014-05-12 13:56:20 -07001244 *
1245 * <p>In particular these formats are converted:
1246 * <ul>
Chien-Yu Chen0a551f12015-04-03 17:57:35 -07001247 * <li>HAL_PIXEL_FORMAT_BLOB => ImageFormat.JPEG</li>
Igor Murashkin9c595172014-05-12 13:56:20 -07001248 * </ul>
1249 * </p>
1250 *
Chien-Yu Chen0a551f12015-04-03 17:57:35 -07001251 * <p>Passing in a format which has no public equivalent will fail;
Igor Murashkin9c595172014-05-12 13:56:20 -07001252 * as will passing in a public format which has a different internal format equivalent.
1253 * See {@link #checkArgumentFormat} for more details about a legal public format.</p>
1254 *
1255 * <p>All other formats are returned as-is, no further invalid check is performed.</p>
1256 *
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001257 * <p>This function is the dual of {@link #imageFormatToInternal} for dataspaces other than
1258 * HAL_DATASPACE_DEPTH.</p>
Igor Murashkin9c595172014-05-12 13:56:20 -07001259 *
1260 * @param format image format from {@link ImageFormat} or {@link PixelFormat}
1261 * @return the converted image formats
1262 *
1263 * @throws IllegalArgumentException
1264 * if {@code format} is {@code HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED} or
1265 * {@link ImageFormat#JPEG}
1266 *
1267 * @see ImageFormat
1268 * @see PixelFormat
1269 * @see #checkArgumentFormat
Emilian Peev2776ca32018-09-18 14:00:39 +01001270 * @hide
Igor Murashkin9c595172014-05-12 13:56:20 -07001271 */
Emilian Peev2776ca32018-09-18 14:00:39 +01001272 public static int imageFormatToPublic(int format) {
Igor Murashkin9c595172014-05-12 13:56:20 -07001273 switch (format) {
1274 case HAL_PIXEL_FORMAT_BLOB:
1275 return ImageFormat.JPEG;
1276 case ImageFormat.JPEG:
1277 throw new IllegalArgumentException(
1278 "ImageFormat.JPEG is an unknown internal format");
Igor Murashkin9c595172014-05-12 13:56:20 -07001279 default:
1280 return format;
1281 }
1282 }
1283
1284 /**
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001285 * Convert an internal format compatible with {@code graphics.h} into public-visible
1286 * {@code ImageFormat}. This assumes the dataspace of the format is HAL_DATASPACE_DEPTH.
1287 *
1288 * <p>In particular these formats are converted:
1289 * <ul>
1290 * <li>HAL_PIXEL_FORMAT_BLOB => ImageFormat.DEPTH_POINT_CLOUD
1291 * <li>HAL_PIXEL_FORMAT_Y16 => ImageFormat.DEPTH16
1292 * </ul>
1293 * </p>
1294 *
1295 * <p>Passing in an implementation-defined format which has no public equivalent will fail;
1296 * as will passing in a public format which has a different internal format equivalent.
1297 * See {@link #checkArgumentFormat} for more details about a legal public format.</p>
1298 *
1299 * <p>All other formats are returned as-is, no further invalid check is performed.</p>
1300 *
1301 * <p>This function is the dual of {@link #imageFormatToInternal} for formats associated with
1302 * HAL_DATASPACE_DEPTH.</p>
1303 *
1304 * @param format image format from {@link ImageFormat} or {@link PixelFormat}
1305 * @return the converted image formats
1306 *
1307 * @throws IllegalArgumentException
1308 * if {@code format} is {@code HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED} or
1309 * {@link ImageFormat#JPEG}
1310 *
1311 * @see ImageFormat
1312 * @see PixelFormat
1313 * @see #checkArgumentFormat
Emilian Peev2776ca32018-09-18 14:00:39 +01001314 * @hide
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001315 */
Emilian Peev2776ca32018-09-18 14:00:39 +01001316 public static int depthFormatToPublic(int format) {
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001317 switch (format) {
1318 case HAL_PIXEL_FORMAT_BLOB:
1319 return ImageFormat.DEPTH_POINT_CLOUD;
1320 case HAL_PIXEL_FORMAT_Y16:
1321 return ImageFormat.DEPTH16;
Emilian Peevf7fec732017-03-17 19:54:30 +00001322 case HAL_PIXEL_FORMAT_RAW16:
1323 return ImageFormat.RAW_DEPTH;
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001324 case ImageFormat.JPEG:
1325 throw new IllegalArgumentException(
1326 "ImageFormat.JPEG is an unknown internal format");
1327 case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
1328 throw new IllegalArgumentException(
1329 "IMPLEMENTATION_DEFINED must not leak to public API");
1330 default:
1331 throw new IllegalArgumentException(
1332 "Unknown DATASPACE_DEPTH format " + format);
1333 }
1334 }
1335
1336 /**
Igor Murashkin9c595172014-05-12 13:56:20 -07001337 * Convert image formats from internal to public formats (in-place).
1338 *
1339 * @param formats an array of image formats
1340 * @return {@code formats}
1341 *
1342 * @see #imageFormatToPublic
1343 */
1344 static int[] imageFormatToPublic(int[] formats) {
1345 if (formats == null) {
1346 return null;
1347 }
1348
1349 for (int i = 0; i < formats.length; ++i) {
1350 formats[i] = imageFormatToPublic(formats[i]);
1351 }
1352
1353 return formats;
1354 }
1355
1356 /**
1357 * Convert a public format compatible with {@code ImageFormat} to an internal format
1358 * from {@code graphics.h}.
1359 *
1360 * <p>In particular these formats are converted:
1361 * <ul>
1362 * <li>ImageFormat.JPEG => HAL_PIXEL_FORMAT_BLOB
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001363 * <li>ImageFormat.DEPTH_POINT_CLOUD => HAL_PIXEL_FORMAT_BLOB
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001364 * <li>ImageFormat.DEPTH_JPEG => HAL_PIXEL_FORMAT_BLOB
1365 * <li>ImageFormat.HEIC => HAL_PIXEL_FORMAT_BLOB
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001366 * <li>ImageFormat.DEPTH16 => HAL_PIXEL_FORMAT_Y16
Igor Murashkin9c595172014-05-12 13:56:20 -07001367 * </ul>
1368 * </p>
1369 *
Chien-Yu Chen0a551f12015-04-03 17:57:35 -07001370 * <p>Passing in an internal format which has a different public format equivalent will fail.
Igor Murashkin9c595172014-05-12 13:56:20 -07001371 * See {@link #checkArgumentFormat} for more details about a legal public format.</p>
1372 *
1373 * <p>All other formats are returned as-is, no invalid check is performed.</p>
1374 *
1375 * <p>This function is the dual of {@link #imageFormatToPublic}.</p>
1376 *
1377 * @param format public image format from {@link ImageFormat} or {@link PixelFormat}
1378 * @return the converted image formats
1379 *
1380 * @see ImageFormat
1381 * @see PixelFormat
1382 *
1383 * @throws IllegalArgumentException
1384 * if {@code format} was {@code HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED}
1385 */
1386 static int imageFormatToInternal(int format) {
1387 switch (format) {
1388 case ImageFormat.JPEG:
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001389 case ImageFormat.DEPTH_POINT_CLOUD:
Emilian Peev934ffa62019-01-04 17:48:31 +00001390 case ImageFormat.DEPTH_JPEG:
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001391 case ImageFormat.HEIC:
Igor Murashkin9c595172014-05-12 13:56:20 -07001392 return HAL_PIXEL_FORMAT_BLOB;
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001393 case ImageFormat.DEPTH16:
1394 return HAL_PIXEL_FORMAT_Y16;
Emilian Peevf7fec732017-03-17 19:54:30 +00001395 case ImageFormat.RAW_DEPTH:
1396 return HAL_PIXEL_FORMAT_RAW16;
Igor Murashkin9c595172014-05-12 13:56:20 -07001397 default:
1398 return format;
1399 }
1400 }
1401
1402 /**
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001403 * Convert a public format compatible with {@code ImageFormat} to an internal dataspace
1404 * from {@code graphics.h}.
1405 *
1406 * <p>In particular these formats are converted:
1407 * <ul>
Eino-Ville Talvala7966d442016-03-14 13:21:03 -07001408 * <li>ImageFormat.JPEG => HAL_DATASPACE_V0_JFIF
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001409 * <li>ImageFormat.DEPTH_POINT_CLOUD => HAL_DATASPACE_DEPTH
1410 * <li>ImageFormat.DEPTH16 => HAL_DATASPACE_DEPTH
Emilian Peev934ffa62019-01-04 17:48:31 +00001411 * <li>ImageFormat.DEPTH_JPEG => HAL_DATASPACE_DYNAMIC_DEPTH
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001412 * <li>ImageFormat.HEIC => HAL_DATASPACE_HEIF
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001413 * <li>others => HAL_DATASPACE_UNKNOWN
1414 * </ul>
1415 * </p>
1416 *
1417 * <p>Passing in an implementation-defined format here will fail (it's not a public format);
1418 * as will passing in an internal format which has a different public format equivalent.
1419 * See {@link #checkArgumentFormat} for more details about a legal public format.</p>
1420 *
1421 * <p>All other formats are returned as-is, no invalid check is performed.</p>
1422 *
1423 * <p>This function is the dual of {@link #imageFormatToPublic}.</p>
1424 *
1425 * @param format public image format from {@link ImageFormat} or {@link PixelFormat}
1426 * @return the converted image formats
1427 *
1428 * @see ImageFormat
1429 * @see PixelFormat
1430 *
1431 * @throws IllegalArgumentException
1432 * if {@code format} was {@code HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED}
1433 */
1434 static int imageFormatToDataspace(int format) {
1435 switch (format) {
1436 case ImageFormat.JPEG:
Eino-Ville Talvala7966d442016-03-14 13:21:03 -07001437 return HAL_DATASPACE_V0_JFIF;
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001438 case ImageFormat.DEPTH_POINT_CLOUD:
1439 case ImageFormat.DEPTH16:
Emilian Peevf7fec732017-03-17 19:54:30 +00001440 case ImageFormat.RAW_DEPTH:
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001441 return HAL_DATASPACE_DEPTH;
Emilian Peev934ffa62019-01-04 17:48:31 +00001442 case ImageFormat.DEPTH_JPEG:
1443 return HAL_DATASPACE_DYNAMIC_DEPTH;
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001444 case ImageFormat.HEIC:
1445 return HAL_DATASPACE_HEIF;
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001446 default:
1447 return HAL_DATASPACE_UNKNOWN;
1448 }
1449 }
1450
1451 /**
Igor Murashkin9c595172014-05-12 13:56:20 -07001452 * Convert image formats from public to internal formats (in-place).
1453 *
1454 * @param formats an array of image formats
1455 * @return {@code formats}
1456 *
1457 * @see #imageFormatToInternal
1458 *
1459 * @hide
1460 */
1461 public static int[] imageFormatToInternal(int[] formats) {
1462 if (formats == null) {
1463 return null;
1464 }
1465
1466 for (int i = 0; i < formats.length; ++i) {
1467 formats[i] = imageFormatToInternal(formats[i]);
1468 }
1469
1470 return formats;
1471 }
1472
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001473 private Size[] getPublicFormatSizes(int format, boolean output, boolean highRes) {
Igor Murashkin9c595172014-05-12 13:56:20 -07001474 try {
1475 checkArgumentFormatSupported(format, output);
1476 } catch (IllegalArgumentException e) {
1477 return null;
1478 }
1479
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001480 int internalFormat = imageFormatToInternal(format);
1481 int dataspace = imageFormatToDataspace(format);
Igor Murashkin9c595172014-05-12 13:56:20 -07001482
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001483 return getInternalFormatSizes(internalFormat, dataspace, output, highRes);
Igor Murashkin9c595172014-05-12 13:56:20 -07001484 }
1485
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001486 private Size[] getInternalFormatSizes(int format, int dataspace,
1487 boolean output, boolean highRes) {
Chien-Yu Chen4a677242016-02-16 14:28:50 -08001488 // All depth formats are non-high-res.
1489 if (dataspace == HAL_DATASPACE_DEPTH && highRes) {
1490 return new Size[0];
1491 }
1492
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001493 SparseIntArray formatsMap =
1494 !output ? mInputFormats :
1495 dataspace == HAL_DATASPACE_DEPTH ? mDepthOutputFormats :
Emilian Peev934ffa62019-01-04 17:48:31 +00001496 dataspace == HAL_DATASPACE_DYNAMIC_DEPTH ? mDynamicDepthOutputFormats :
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001497 dataspace == HAL_DATASPACE_HEIF ? mHeicOutputFormats :
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001498 highRes ? mHighResOutputFormats :
1499 mOutputFormats;
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001500
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001501 int sizesCount = formatsMap.get(format);
Emilian Peev934ffa62019-01-04 17:48:31 +00001502 if ( ((!output || (dataspace == HAL_DATASPACE_DEPTH ||
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001503 dataspace == HAL_DATASPACE_DYNAMIC_DEPTH ||
1504 dataspace == HAL_DATASPACE_HEIF)) && sizesCount == 0) ||
Emilian Peev934ffa62019-01-04 17:48:31 +00001505 (output && (dataspace != HAL_DATASPACE_DEPTH &&
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001506 dataspace != HAL_DATASPACE_DYNAMIC_DEPTH &&
1507 dataspace != HAL_DATASPACE_HEIF) &&
Emilian Peev934ffa62019-01-04 17:48:31 +00001508 mAllOutputFormats.get(format) == 0)) {
Emilian Peev0fde6be2019-05-15 11:12:19 -07001509 return null;
Igor Murashkin9c595172014-05-12 13:56:20 -07001510 }
1511
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001512 Size[] sizes = new Size[sizesCount];
Igor Murashkin9c595172014-05-12 13:56:20 -07001513 int sizeIndex = 0;
1514
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001515 StreamConfiguration[] configurations =
Emilian Peev934ffa62019-01-04 17:48:31 +00001516 (dataspace == HAL_DATASPACE_DEPTH) ? mDepthConfigurations :
1517 (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthConfigurations :
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001518 (dataspace == HAL_DATASPACE_HEIF) ? mHeicConfigurations :
Emilian Peev934ffa62019-01-04 17:48:31 +00001519 mConfigurations;
Chien-Yu Chen4a677242016-02-16 14:28:50 -08001520 StreamConfigurationDuration[] minFrameDurations =
Emilian Peev934ffa62019-01-04 17:48:31 +00001521 (dataspace == HAL_DATASPACE_DEPTH) ? mDepthMinFrameDurations :
1522 (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthMinFrameDurations :
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001523 (dataspace == HAL_DATASPACE_HEIF) ? mHeicMinFrameDurations :
Emilian Peev934ffa62019-01-04 17:48:31 +00001524 mMinFrameDurations;
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001525
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001526 for (StreamConfiguration config : configurations) {
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001527 int fmt = config.getFormat();
1528 if (fmt == format && config.isOutput() == output) {
Eino-Ville Talvalae3f54832015-08-24 14:06:12 -07001529 if (output && mListHighResolution) {
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001530 // Filter slow high-res output formats; include for
1531 // highRes, remove for !highRes
1532 long duration = 0;
Chien-Yu Chen4a677242016-02-16 14:28:50 -08001533 for (int i = 0; i < minFrameDurations.length; i++) {
1534 StreamConfigurationDuration d = minFrameDurations[i];
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001535 if (d.getFormat() == fmt &&
1536 d.getWidth() == config.getSize().getWidth() &&
1537 d.getHeight() == config.getSize().getHeight()) {
1538 duration = d.getDuration();
1539 break;
1540 }
1541 }
Chien-Yu Chen4a677242016-02-16 14:28:50 -08001542 if (dataspace != HAL_DATASPACE_DEPTH &&
1543 highRes != (duration > DURATION_20FPS_NS)) {
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001544 continue;
1545 }
1546 }
Igor Murashkin9c595172014-05-12 13:56:20 -07001547 sizes[sizeIndex++] = config.getSize();
1548 }
1549 }
1550
Emilian Peev934ffa62019-01-04 17:48:31 +00001551 // Dynamic depth streams can have both fast and also high res modes.
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001552 if ((sizeIndex != sizesCount) && (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH ||
1553 dataspace == HAL_DATASPACE_HEIF)) {
Emilian Peev934ffa62019-01-04 17:48:31 +00001554
1555 if (sizeIndex > sizesCount) {
1556 throw new AssertionError(
1557 "Too many dynamic depth sizes (expected " + sizesCount + ", actual " +
1558 sizeIndex + ")");
1559 }
1560
1561 if (sizeIndex <= 0) {
1562 sizes = new Size[0];
1563 } else {
1564 sizes = Arrays.copyOf(sizes, sizeIndex);
1565 }
1566 } else if (sizeIndex != sizesCount) {
Igor Murashkin9c595172014-05-12 13:56:20 -07001567 throw new AssertionError(
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001568 "Too few sizes (expected " + sizesCount + ", actual " + sizeIndex + ")");
Igor Murashkin9c595172014-05-12 13:56:20 -07001569 }
1570
1571 return sizes;
1572 }
1573
1574 /** Get the list of publically visible output formats; does not include IMPL_DEFINED */
1575 private int[] getPublicFormats(boolean output) {
1576 int[] formats = new int[getPublicFormatCount(output)];
1577
1578 int i = 0;
1579
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001580 SparseIntArray map = getFormatsMap(output);
1581 for (int j = 0; j < map.size(); j++) {
1582 int format = map.keyAt(j);
Yin-Chia Yeh44581ff2015-12-07 17:15:24 -08001583 formats[i++] = imageFormatToPublic(format);
Igor Murashkin9c595172014-05-12 13:56:20 -07001584 }
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001585 if (output) {
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001586 for (int j = 0; j < mDepthOutputFormats.size(); j++) {
1587 formats[i++] = depthFormatToPublic(mDepthOutputFormats.keyAt(j));
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001588 }
Emilian Peev934ffa62019-01-04 17:48:31 +00001589 if (mDynamicDepthOutputFormats.size() > 0) {
1590 // Only one publicly dynamic depth format is available.
1591 formats[i++] = ImageFormat.DEPTH_JPEG;
1592 }
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001593 if (mHeicOutputFormats.size() > 0) {
1594 formats[i++] = ImageFormat.HEIC;
1595 }
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001596 }
Igor Murashkin9c595172014-05-12 13:56:20 -07001597 if (formats.length != i) {
1598 throw new AssertionError("Too few formats " + i + ", expected " + formats.length);
1599 }
1600
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001601 return formats;
Igor Murashkin9c595172014-05-12 13:56:20 -07001602 }
1603
1604 /** Get the format -> size count map for either output or input formats */
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001605 private SparseIntArray getFormatsMap(boolean output) {
1606 return output ? mAllOutputFormats : mInputFormats;
Igor Murashkin9c595172014-05-12 13:56:20 -07001607 }
1608
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001609 private long getInternalFormatDuration(int format, int dataspace, Size size, int duration) {
Igor Murashkin9c595172014-05-12 13:56:20 -07001610 // assume format is already checked, since its internal
1611
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001612 if (!isSupportedInternalConfiguration(format, dataspace, size)) {
Igor Murashkin9c595172014-05-12 13:56:20 -07001613 throw new IllegalArgumentException("size was not supported");
1614 }
1615
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001616 StreamConfigurationDuration[] durations = getDurations(duration, dataspace);
Igor Murashkin9c595172014-05-12 13:56:20 -07001617
1618 for (StreamConfigurationDuration configurationDuration : durations) {
1619 if (configurationDuration.getFormat() == format &&
1620 configurationDuration.getWidth() == size.getWidth() &&
1621 configurationDuration.getHeight() == size.getHeight()) {
1622 return configurationDuration.getDuration();
1623 }
1624 }
Eino-Ville Talvalaabd9d3c2014-07-28 13:01:52 -07001625 // Default duration is '0' (unsupported/no extra stall)
1626 return 0;
Igor Murashkin9c595172014-05-12 13:56:20 -07001627 }
1628
1629 /**
1630 * Get the durations array for the kind of duration
1631 *
1632 * @see #DURATION_MIN_FRAME
1633 * @see #DURATION_STALL
1634 * */
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001635 private StreamConfigurationDuration[] getDurations(int duration, int dataspace) {
Igor Murashkin9c595172014-05-12 13:56:20 -07001636 switch (duration) {
1637 case DURATION_MIN_FRAME:
Emilian Peev934ffa62019-01-04 17:48:31 +00001638 return (dataspace == HAL_DATASPACE_DEPTH) ? mDepthMinFrameDurations :
1639 (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ?
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001640 mDynamicDepthMinFrameDurations :
1641 (dataspace == HAL_DATASPACE_HEIF) ? mHeicMinFrameDurations :
1642 mMinFrameDurations;
1643
Igor Murashkin9c595172014-05-12 13:56:20 -07001644 case DURATION_STALL:
Emilian Peev934ffa62019-01-04 17:48:31 +00001645 return (dataspace == HAL_DATASPACE_DEPTH) ? mDepthStallDurations :
1646 (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthStallDurations :
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001647 (dataspace == HAL_DATASPACE_HEIF) ? mHeicStallDurations :
Emilian Peev934ffa62019-01-04 17:48:31 +00001648 mStallDurations;
Igor Murashkin9c595172014-05-12 13:56:20 -07001649 default:
1650 throw new IllegalArgumentException("duration was invalid");
1651 }
1652 }
1653
Igor Murashkin9c595172014-05-12 13:56:20 -07001654 /** Count the number of publicly-visible output formats */
1655 private int getPublicFormatCount(boolean output) {
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001656 SparseIntArray formatsMap = getFormatsMap(output);
Igor Murashkin9c595172014-05-12 13:56:20 -07001657 int size = formatsMap.size();
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001658 if (output) {
1659 size += mDepthOutputFormats.size();
Emilian Peev934ffa62019-01-04 17:48:31 +00001660 size += mDynamicDepthOutputFormats.size();
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001661 size += mHeicOutputFormats.size();
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001662 }
Eino-Ville Talvalafa0b9a02015-01-20 12:30:59 -08001663
Igor Murashkin9c595172014-05-12 13:56:20 -07001664 return size;
1665 }
1666
1667 private static <T> boolean arrayContains(T[] array, T element) {
1668 if (array == null) {
1669 return false;
1670 }
1671
1672 for (T el : array) {
1673 if (Objects.equals(el, element)) {
1674 return true;
1675 }
1676 }
1677
1678 return false;
1679 }
1680
Emilian Peev934ffa62019-01-04 17:48:31 +00001681 private boolean isSupportedInternalConfiguration(int format, int dataspace, Size size) {
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001682 StreamConfiguration[] configurations =
Emilian Peev934ffa62019-01-04 17:48:31 +00001683 (dataspace == HAL_DATASPACE_DEPTH) ? mDepthConfigurations :
1684 (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthConfigurations :
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001685 (dataspace == HAL_DATASPACE_HEIF) ? mHeicConfigurations :
Emilian Peev934ffa62019-01-04 17:48:31 +00001686 mConfigurations;
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001687
1688 for (int i = 0; i < configurations.length; i++) {
1689 if (configurations[i].getFormat() == format &&
1690 configurations[i].getSize().equals(size)) {
1691 return true;
1692 }
1693 }
1694
1695 return false;
1696 }
1697
Chien-Yu Chen310f3812015-05-20 10:16:59 -07001698 /**
1699 * Return this {@link StreamConfigurationMap} as a string representation.
1700 *
1701 * <p>{@code "StreamConfigurationMap(Outputs([w:%d, h:%d, format:%s(%d), min_duration:%d,
1702 * stall:%d], ... [w:%d, h:%d, format:%s(%d), min_duration:%d, stall:%d]), Inputs([w:%d, h:%d,
1703 * format:%s(%d)], ... [w:%d, h:%d, format:%s(%d)]), ValidOutputFormatsForInput(
1704 * [in:%d, out:%d, ... %d], ... [in:%d, out:%d, ... %d]), HighSpeedVideoConfigurations(
1705 * [w:%d, h:%d, min_fps:%d, max_fps:%d], ... [w:%d, h:%d, min_fps:%d, max_fps:%d]))"}.</p>
1706 *
1707 * <p>{@code Outputs([w:%d, h:%d, format:%s(%d), min_duration:%d, stall:%d], ...
1708 * [w:%d, h:%d, format:%s(%d), min_duration:%d, stall:%d])}, where
1709 * {@code [w:%d, h:%d, format:%s(%d), min_duration:%d, stall:%d]} represents an output
1710 * configuration's width, height, format, minimal frame duration in nanoseconds, and stall
1711 * duration in nanoseconds.</p>
1712 *
1713 * <p>{@code Inputs([w:%d, h:%d, format:%s(%d)], ... [w:%d, h:%d, format:%s(%d)])}, where
1714 * {@code [w:%d, h:%d, format:%s(%d)]} represents an input configuration's width, height, and
1715 * format.</p>
1716 *
1717 * <p>{@code ValidOutputFormatsForInput([in:%s(%d), out:%s(%d), ... %s(%d)],
1718 * ... [in:%s(%d), out:%s(%d), ... %s(%d)])}, where {@code [in:%s(%d), out:%s(%d), ... %s(%d)]}
1719 * represents an input fomat and its valid output formats.</p>
1720 *
1721 * <p>{@code HighSpeedVideoConfigurations([w:%d, h:%d, min_fps:%d, max_fps:%d],
1722 * ... [w:%d, h:%d, min_fps:%d, max_fps:%d])}, where
1723 * {@code [w:%d, h:%d, min_fps:%d, max_fps:%d]} represents a high speed video output
1724 * configuration's width, height, minimal frame rate, and maximal frame rate.</p>
1725 *
1726 * @return string representation of {@link StreamConfigurationMap}
1727 */
1728 @Override
1729 public String toString() {
1730 StringBuilder sb = new StringBuilder("StreamConfiguration(");
1731 appendOutputsString(sb);
1732 sb.append(", ");
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001733 appendHighResOutputsString(sb);
1734 sb.append(", ");
Chien-Yu Chen310f3812015-05-20 10:16:59 -07001735 appendInputsString(sb);
1736 sb.append(", ");
1737 appendValidOutputFormatsForInputString(sb);
1738 sb.append(", ");
1739 appendHighSpeedVideoConfigurationsString(sb);
1740 sb.append(")");
1741
1742 return sb.toString();
1743 }
1744
1745 private void appendOutputsString(StringBuilder sb) {
1746 sb.append("Outputs(");
1747 int[] formats = getOutputFormats();
1748 for (int format : formats) {
1749 Size[] sizes = getOutputSizes(format);
1750 for (Size size : sizes) {
1751 long minFrameDuration = getOutputMinFrameDuration(format, size);
1752 long stallDuration = getOutputStallDuration(format, size);
1753 sb.append(String.format("[w:%d, h:%d, format:%s(%d), min_duration:%d, " +
1754 "stall:%d], ", size.getWidth(), size.getHeight(), formatToString(format),
1755 format, minFrameDuration, stallDuration));
1756 }
1757 }
1758 // Remove the pending ", "
1759 if (sb.charAt(sb.length() - 1) == ' ') {
1760 sb.delete(sb.length() - 2, sb.length());
1761 }
1762 sb.append(")");
1763 }
1764
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001765 private void appendHighResOutputsString(StringBuilder sb) {
1766 sb.append("HighResolutionOutputs(");
1767 int[] formats = getOutputFormats();
1768 for (int format : formats) {
1769 Size[] sizes = getHighResolutionOutputSizes(format);
1770 if (sizes == null) continue;
1771 for (Size size : sizes) {
1772 long minFrameDuration = getOutputMinFrameDuration(format, size);
1773 long stallDuration = getOutputStallDuration(format, size);
1774 sb.append(String.format("[w:%d, h:%d, format:%s(%d), min_duration:%d, " +
1775 "stall:%d], ", size.getWidth(), size.getHeight(), formatToString(format),
1776 format, minFrameDuration, stallDuration));
1777 }
1778 }
1779 // Remove the pending ", "
1780 if (sb.charAt(sb.length() - 1) == ' ') {
1781 sb.delete(sb.length() - 2, sb.length());
1782 }
1783 sb.append(")");
1784 }
1785
Chien-Yu Chen310f3812015-05-20 10:16:59 -07001786 private void appendInputsString(StringBuilder sb) {
1787 sb.append("Inputs(");
1788 int[] formats = getInputFormats();
1789 for (int format : formats) {
1790 Size[] sizes = getInputSizes(format);
1791 for (Size size : sizes) {
1792 sb.append(String.format("[w:%d, h:%d, format:%s(%d)], ", size.getWidth(),
1793 size.getHeight(), formatToString(format), format));
1794 }
1795 }
1796 // Remove the pending ", "
1797 if (sb.charAt(sb.length() - 1) == ' ') {
1798 sb.delete(sb.length() - 2, sb.length());
1799 }
1800 sb.append(")");
1801 }
1802
1803 private void appendValidOutputFormatsForInputString(StringBuilder sb) {
1804 sb.append("ValidOutputFormatsForInput(");
1805 int[] inputFormats = getInputFormats();
1806 for (int inputFormat : inputFormats) {
1807 sb.append(String.format("[in:%s(%d), out:", formatToString(inputFormat), inputFormat));
1808 int[] outputFormats = getValidOutputFormatsForInput(inputFormat);
1809 for (int i = 0; i < outputFormats.length; i++) {
1810 sb.append(String.format("%s(%d)", formatToString(outputFormats[i]),
1811 outputFormats[i]));
1812 if (i < outputFormats.length - 1) {
1813 sb.append(", ");
1814 }
1815 }
1816 sb.append("], ");
1817 }
1818 // Remove the pending ", "
1819 if (sb.charAt(sb.length() - 1) == ' ') {
1820 sb.delete(sb.length() - 2, sb.length());
1821 }
1822 sb.append(")");
1823 }
1824
1825 private void appendHighSpeedVideoConfigurationsString(StringBuilder sb) {
1826 sb.append("HighSpeedVideoConfigurations(");
1827 Size[] sizes = getHighSpeedVideoSizes();
1828 for (Size size : sizes) {
1829 Range<Integer>[] ranges = getHighSpeedVideoFpsRangesFor(size);
1830 for (Range<Integer> range : ranges) {
1831 sb.append(String.format("[w:%d, h:%d, min_fps:%d, max_fps:%d], ", size.getWidth(),
1832 size.getHeight(), range.getLower(), range.getUpper()));
1833 }
1834 }
1835 // Remove the pending ", "
1836 if (sb.charAt(sb.length() - 1) == ' ') {
1837 sb.delete(sb.length() - 2, sb.length());
1838 }
1839 sb.append(")");
1840 }
1841
1842 private String formatToString(int format) {
1843 switch (format) {
1844 case ImageFormat.YV12:
1845 return "YV12";
1846 case ImageFormat.YUV_420_888:
1847 return "YUV_420_888";
1848 case ImageFormat.NV21:
1849 return "NV21";
1850 case ImageFormat.NV16:
1851 return "NV16";
1852 case PixelFormat.RGB_565:
1853 return "RGB_565";
1854 case PixelFormat.RGBA_8888:
1855 return "RGBA_8888";
1856 case PixelFormat.RGBX_8888:
1857 return "RGBX_8888";
1858 case PixelFormat.RGB_888:
1859 return "RGB_888";
1860 case ImageFormat.JPEG:
1861 return "JPEG";
1862 case ImageFormat.YUY2:
1863 return "YUY2";
1864 case ImageFormat.Y8:
1865 return "Y8";
1866 case ImageFormat.Y16:
1867 return "Y16";
1868 case ImageFormat.RAW_SENSOR:
1869 return "RAW_SENSOR";
Yin-Chia Yeh44581ff2015-12-07 17:15:24 -08001870 case ImageFormat.RAW_PRIVATE:
1871 return "RAW_PRIVATE";
Chien-Yu Chen310f3812015-05-20 10:16:59 -07001872 case ImageFormat.RAW10:
1873 return "RAW10";
1874 case ImageFormat.DEPTH16:
1875 return "DEPTH16";
1876 case ImageFormat.DEPTH_POINT_CLOUD:
1877 return "DEPTH_POINT_CLOUD";
Emilian Peev934ffa62019-01-04 17:48:31 +00001878 case ImageFormat.DEPTH_JPEG:
1879 return "DEPTH_JPEG";
Emilian Peevf7fec732017-03-17 19:54:30 +00001880 case ImageFormat.RAW_DEPTH:
1881 return "RAW_DEPTH";
Chien-Yu Chen310f3812015-05-20 10:16:59 -07001882 case ImageFormat.PRIVATE:
1883 return "PRIVATE";
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001884 case ImageFormat.HEIC:
1885 return "HEIC";
Chien-Yu Chen310f3812015-05-20 10:16:59 -07001886 default:
1887 return "UNKNOWN";
1888 }
1889 }
1890
Igor Murashkin9c595172014-05-12 13:56:20 -07001891 // from system/core/include/system/graphics.h
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001892 private static final int HAL_PIXEL_FORMAT_RAW16 = 0x20;
Igor Murashkin9c595172014-05-12 13:56:20 -07001893 private static final int HAL_PIXEL_FORMAT_BLOB = 0x21;
1894 private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22;
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001895 private static final int HAL_PIXEL_FORMAT_YCbCr_420_888 = 0x23;
Igor Murashkin9c595172014-05-12 13:56:20 -07001896 private static final int HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24;
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001897 private static final int HAL_PIXEL_FORMAT_RAW10 = 0x25;
1898 private static final int HAL_PIXEL_FORMAT_RAW12 = 0x26;
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001899 private static final int HAL_PIXEL_FORMAT_Y16 = 0x20363159;
1900
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001901
Eino-Ville Talvala7966d442016-03-14 13:21:03 -07001902 private static final int HAL_DATASPACE_STANDARD_SHIFT = 16;
1903 private static final int HAL_DATASPACE_TRANSFER_SHIFT = 22;
1904 private static final int HAL_DATASPACE_RANGE_SHIFT = 27;
1905
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001906 private static final int HAL_DATASPACE_UNKNOWN = 0x0;
Eino-Ville Talvala7966d442016-03-14 13:21:03 -07001907 private static final int HAL_DATASPACE_V0_JFIF =
1908 (2 << HAL_DATASPACE_STANDARD_SHIFT) |
1909 (3 << HAL_DATASPACE_TRANSFER_SHIFT) |
1910 (1 << HAL_DATASPACE_RANGE_SHIFT);
1911
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001912 private static final int HAL_DATASPACE_DEPTH = 0x1000;
Emilian Peev934ffa62019-01-04 17:48:31 +00001913 private static final int HAL_DATASPACE_DYNAMIC_DEPTH = 0x1002;
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001914 private static final int HAL_DATASPACE_HEIF = 0x1003;
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001915 private static final long DURATION_20FPS_NS = 50000000L;
Igor Murashkin9c595172014-05-12 13:56:20 -07001916 /**
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001917 * @see #getDurations(int, int)
Igor Murashkin9c595172014-05-12 13:56:20 -07001918 */
1919 private static final int DURATION_MIN_FRAME = 0;
1920 private static final int DURATION_STALL = 1;
1921
1922 private final StreamConfiguration[] mConfigurations;
1923 private final StreamConfigurationDuration[] mMinFrameDurations;
1924 private final StreamConfigurationDuration[] mStallDurations;
Eino-Ville Talvala456432e2015-03-05 15:42:49 -08001925
1926 private final StreamConfiguration[] mDepthConfigurations;
1927 private final StreamConfigurationDuration[] mDepthMinFrameDurations;
1928 private final StreamConfigurationDuration[] mDepthStallDurations;
1929
Emilian Peev934ffa62019-01-04 17:48:31 +00001930 private final StreamConfiguration[] mDynamicDepthConfigurations;
1931 private final StreamConfigurationDuration[] mDynamicDepthMinFrameDurations;
1932 private final StreamConfigurationDuration[] mDynamicDepthStallDurations;
1933
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001934 private final StreamConfiguration[] mHeicConfigurations;
1935 private final StreamConfigurationDuration[] mHeicMinFrameDurations;
1936 private final StreamConfigurationDuration[] mHeicStallDurations;
1937
Yin-Chia Yeh12da1402014-07-15 10:37:31 -07001938 private final HighSpeedVideoConfiguration[] mHighSpeedVideoConfigurations;
Chien-Yu Chen0a551f12015-04-03 17:57:35 -07001939 private final ReprocessFormatsMap mInputOutputFormatsMap;
Igor Murashkin9c595172014-05-12 13:56:20 -07001940
Eino-Ville Talvala0819c752015-06-17 11:34:41 -07001941 private final boolean mListHighResolution;
1942
1943 /** internal format -> num output sizes mapping, not including slow high-res sizes, for
1944 * non-depth dataspaces */
1945 private final SparseIntArray mOutputFormats = new SparseIntArray();
1946 /** internal format -> num output sizes mapping for slow high-res sizes, for non-depth
1947 * dataspaces */
1948 private final SparseIntArray mHighResOutputFormats = new SparseIntArray();
1949 /** internal format -> num output sizes mapping for all non-depth dataspaces */
1950 private final SparseIntArray mAllOutputFormats = new SparseIntArray();
1951 /** internal format -> num input sizes mapping, for input reprocessing formats */
1952 private final SparseIntArray mInputFormats = new SparseIntArray();
1953 /** internal format -> num depth output sizes mapping, for HAL_DATASPACE_DEPTH */
1954 private final SparseIntArray mDepthOutputFormats = new SparseIntArray();
Emilian Peev934ffa62019-01-04 17:48:31 +00001955 /** internal format -> num dynamic depth output sizes mapping, for HAL_DATASPACE_DYNAMIC_DEPTH */
1956 private final SparseIntArray mDynamicDepthOutputFormats = new SparseIntArray();
Shuzhen Wangf655b1c2018-12-28 15:40:36 -08001957 /** internal format -> num heic output sizes mapping, for HAL_DATASPACE_HEIF */
1958 private final SparseIntArray mHeicOutputFormats = new SparseIntArray();
1959
Yin-Chia Yeh12da1402014-07-15 10:37:31 -07001960 /** High speed video Size -> FPS range count mapping*/
1961 private final HashMap</*HighSpeedVideoSize*/Size, /*Count*/Integer> mHighSpeedVideoSizeMap =
1962 new HashMap<Size, Integer>();
1963 /** High speed video FPS range -> Size count mapping*/
1964 private final HashMap</*HighSpeedVideoFpsRange*/Range<Integer>, /*Count*/Integer>
1965 mHighSpeedVideoFpsRangeMap = new HashMap<Range<Integer>, Integer>();
Igor Murashkin9c595172014-05-12 13:56:20 -07001966
1967}