StreamConfigurationMap.java revision 08bc3b0f0299a02d00004f4b2886469c1ed75569
1/* 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 19import android.graphics.ImageFormat; 20import android.graphics.PixelFormat; 21import android.hardware.camera2.CameraCharacteristics; 22import android.hardware.camera2.CameraDevice; 23import android.hardware.camera2.CaptureRequest; 24import android.hardware.camera2.utils.HashCodeHelpers; 25import android.view.Surface; 26import android.util.Log; 27import android.util.Size; 28 29import java.util.Arrays; 30import java.util.HashMap; 31import java.util.Objects; 32 33import static com.android.internal.util.Preconditions.*; 34 35/** 36 * Immutable class to store the available stream 37 * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP configurations} to set up 38 * {@link android.view.Surface Surfaces} for creating a 39 * {@link android.hardware.camera2.CameraCaptureSession capture session} with 40 * {@link android.hardware.camera2.CameraDevice#createCaptureSession}. 41 * <!-- TODO: link to input stream configuration --> 42 * 43 * <p>This is the authoritative list for all <!-- input/ -->output formats (and sizes respectively 44 * for that format) that are supported by a camera device.</p> 45 * 46 * <p>This also contains the minimum frame durations and stall durations for each format/size 47 * combination that can be used to calculate effective frame rate when submitting multiple captures. 48 * </p> 49 * 50 * <p>An instance of this object is available from {@link CameraCharacteristics} using 51 * the {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP} key and the 52 * {@link CameraCharacteristics#get} method.</p> 53 * 54 * <pre><code>{@code 55 * CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); 56 * StreamConfigurationMap configs = characteristics.get( 57 * CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 58 * }</code></pre> 59 * 60 * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP 61 * @see CameraDevice#createCaptureSession 62 */ 63public final class StreamConfigurationMap { 64 65 private static final String TAG = "StreamConfigurationMap"; 66 67 /** 68 * Indicates that a minimum frame duration is not available for a particular configuration. 69 */ 70 public static final long NO_MIN_FRAME_DURATION = 0; 71 72 /** 73 * 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} 81 * 82 * @throws NullPointerException if any of the arguments or subelements were {@code null} 83 * 84 * @hide 85 */ 86 public StreamConfigurationMap( 87 StreamConfiguration[] configurations, 88 StreamConfigurationDuration[] minFrameDurations, 89 StreamConfigurationDuration[] stallDurations) { 90 91 mConfigurations = checkArrayElementsNotNull(configurations, "configurations"); 92 mMinFrameDurations = checkArrayElementsNotNull(minFrameDurations, "minFrameDurations"); 93 mStallDurations = checkArrayElementsNotNull(stallDurations, "stallDurations"); 94 95 // For each format, track how many sizes there are available to configure 96 for (StreamConfiguration config : configurations) { 97 HashMap<Integer, Integer> map = config.isOutput() ? mOutputFormats : mInputFormats; 98 99 Integer count = map.get(config.getFormat()); 100 101 if (count == null) { 102 count = 0; 103 } 104 count = count + 1; 105 106 map.put(config.getFormat(), count); 107 } 108 109 if (!mOutputFormats.containsKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)) { 110 throw new AssertionError( 111 "At least one stream configuration for IMPLEMENTATION_DEFINED must exist"); 112 } 113 } 114 115 /** 116 * Get the image {@code format} output formats in this stream configuration. 117 * 118 * <p>All image formats returned by this function will be defined in either {@link ImageFormat} 119 * or in {@link PixelFormat} (and there is no possibility of collision).</p> 120 * 121 * <p>Formats listed in this array are guaranteed to return true if queried with 122 * {@link #isOutputSupportedFor(int).</p> 123 * 124 * @return an array of integer format 125 * 126 * @see ImageFormat 127 * @see PixelFormat 128 */ 129 public final int[] getOutputFormats() { 130 return getPublicFormats(/*output*/true); 131 } 132 133 /** 134 * Get the image {@code format} input formats in this stream configuration. 135 * 136 * <p>All image formats returned by this function will be defined in either {@link ImageFormat} 137 * or in {@link PixelFormat} (and there is no possibility of collision).</p> 138 * 139 * @return an array of integer format 140 * 141 * @see ImageFormat 142 * @see PixelFormat 143 * 144 * @hide 145 */ 146 public final int[] getInputFormats() { 147 return getPublicFormats(/*output*/false); 148 } 149 150 /** 151 * Get the supported input sizes for this input format. 152 * 153 * <p>The format must have come from {@link #getInputFormats}; otherwise 154 * {@code null} is returned.</p> 155 * 156 * @param format a format from {@link #getInputFormats} 157 * @return a non-empty array of sizes, or {@code null} if the format was not available. 158 * 159 * @hide 160 */ 161 public Size[] getInputSizes(final int format) { 162 return getPublicFormatSizes(format, /*output*/false); 163 } 164 165 /** 166 * Determine whether or not output surfaces with a particular user-defined format can be passed 167 * {@link CameraDevice#createCaptureSession createCaptureSession}. 168 * 169 * <p>This method determines that the output {@code format} is supported by the camera device; 170 * each output {@code surface} target may or may not itself support that {@code format}. 171 * Refer to the class which provides the surface for additional documentation.</p> 172 * 173 * <p>Formats for which this returns {@code true} are guaranteed to exist in the result 174 * returned by {@link #getOutputSizes}.</p> 175 * 176 * @param format an image format from either {@link ImageFormat} or {@link PixelFormat} 177 * @return 178 * {@code true} iff using a {@code surface} with this {@code format} will be 179 * supported with {@link CameraDevice#createCaptureSession} 180 * 181 * @throws IllegalArgumentException 182 * if the image format was not a defined named constant 183 * from either {@link ImageFormat} or {@link PixelFormat} 184 * 185 * @see ImageFormat 186 * @see PixelFormat 187 * @see CameraDevice#createCaptureSession 188 */ 189 public boolean isOutputSupportedFor(int format) { 190 checkArgumentFormat(format); 191 192 format = imageFormatToInternal(format); 193 return getFormatsMap(/*output*/true).containsKey(format); 194 } 195 196 /** 197 * Determine whether or not output streams can be configured with a particular class 198 * as a consumer. 199 * 200 * <p>The following list is generally usable for outputs: 201 * <ul> 202 * <li>{@link android.media.ImageReader} - 203 * Recommended for image processing or streaming to external resources (such as a file or 204 * network) 205 * <li>{@link android.media.MediaRecorder} - 206 * Recommended for recording video (simple to use) 207 * <li>{@link android.media.MediaCodec} - 208 * Recommended for recording video (more complicated to use, with more flexibility) 209 * <li>{@link android.renderscript.Allocation} - 210 * Recommended for image processing with {@link android.renderscript RenderScript} 211 * <li>{@link android.view.SurfaceHolder} - 212 * Recommended for low-power camera preview with {@link android.view.SurfaceView} 213 * <li>{@link android.graphics.SurfaceTexture} - 214 * Recommended for OpenGL-accelerated preview processing or compositing with 215 * {@link android.view.TextureView} 216 * </ul> 217 * </p> 218 * 219 * <p>Generally speaking this means that creating a {@link Surface} from that class <i>may</i> 220 * provide a producer endpoint that is suitable to be used with 221 * {@link CameraDevice#createCaptureSession}.</p> 222 * 223 * <p>Since not all of the above classes support output of all format and size combinations, 224 * the particular combination should be queried with {@link #isOutputSupportedFor(Surface)}.</p> 225 * 226 * @param klass a non-{@code null} {@link Class} object reference 227 * @return {@code true} if this class is supported as an output, {@code false} otherwise 228 * 229 * @throws NullPointerException if {@code klass} was {@code null} 230 * 231 * @see CameraDevice#createCaptureSession 232 * @see #isOutputSupportedFor(Surface) 233 */ 234 public static <T> boolean isOutputSupportedFor(Class<T> klass) { 235 checkNotNull(klass, "klass must not be null"); 236 237 if (klass == android.media.ImageReader.class) { 238 return true; 239 } else if (klass == android.media.MediaRecorder.class) { 240 return true; 241 } else if (klass == android.media.MediaCodec.class) { 242 return true; 243 } else if (klass == android.renderscript.Allocation.class) { 244 return true; 245 } else if (klass == android.view.SurfaceHolder.class) { 246 return true; 247 } else if (klass == android.graphics.SurfaceTexture.class) { 248 return true; 249 } 250 251 return false; 252 } 253 254 /** 255 * Determine whether or not the {@code surface} in its current state is suitable to be included 256 * in a {@link CameraDevice#createCaptureSession capture session} as an output. 257 * 258 * <p>Not all surfaces are usable with the {@link CameraDevice}, and not all configurations 259 * of that {@code surface} are compatible. Some classes that provide the {@code surface} are 260 * compatible with the {@link CameraDevice} in general 261 * (see {@link #isOutputSupportedFor(Class)}, but it is the caller's responsibility to put the 262 * {@code surface} into a state that will be compatible with the {@link CameraDevice}.</p> 263 * 264 * <p>Reasons for a {@code surface} being specifically incompatible might be: 265 * <ul> 266 * <li>Using a format that's not listed by {@link #getOutputFormats} 267 * <li>Using a format/size combination that's not listed by {@link #getOutputSizes} 268 * <li>The {@code surface} itself is not in a state where it can service a new producer.</p> 269 * </li> 270 * </ul> 271 * 272 * This is not an exhaustive list; see the particular class's documentation for further 273 * possible reasons of incompatibility.</p> 274 * 275 * @param surface a non-{@code null} {@link Surface} object reference 276 * @return {@code true} if this is supported, {@code false} otherwise 277 * 278 * @throws NullPointerException if {@code surface} was {@code null} 279 * 280 * @see CameraDevice#createCaptureSession 281 * @see #isOutputSupportedFor(Class) 282 */ 283 public boolean isOutputSupportedFor(Surface surface) { 284 checkNotNull(surface, "surface must not be null"); 285 286 throw new UnsupportedOperationException("Not implemented yet"); 287 288 // TODO: JNI function that checks the Surface's IGraphicBufferProducer state 289 } 290 291 /** 292 * Get a list of sizes compatible with {@code klass} to use as an output. 293 * 294 * <p>Since some of the supported classes may support additional formats beyond 295 * an opaque/implementation-defined (under-the-hood) format; this function only returns 296 * sizes for the implementation-defined format.</p> 297 * 298 * <p>Some classes such as {@link android.media.ImageReader} may only support user-defined 299 * formats; in particular {@link #isOutputSupportedFor(Class)} will return {@code true} for 300 * that class and this method will return an empty array (but not {@code null}).</p> 301 * 302 * <p>If a well-defined format such as {@code NV21} is required, use 303 * {@link #getOutputSizes(int)} instead.</p> 304 * 305 * <p>The {@code klass} should be a supported output, that querying 306 * {@code #isOutputSupportedFor(Class)} should return {@code true}.</p> 307 * 308 * @param klass 309 * a non-{@code null} {@link Class} object reference 310 * @return 311 * an array of supported sizes for implementation-defined formats, 312 * or {@code null} iff the {@code klass} is not a supported output 313 * 314 * @throws NullPointerException if {@code klass} was {@code null} 315 * 316 * @see #isOutputSupportedFor(Class) 317 */ 318 public <T> Size[] getOutputSizes(Class<T> klass) { 319 if (isOutputSupportedFor(klass) == false) { 320 return null; 321 } 322 323 return getInternalFormatSizes(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, /*output*/true); 324 } 325 326 /** 327 * Get a list of sizes compatible with the requested image {@code format}. 328 * 329 * <p>The {@code format} should be a supported format (one of the formats returned by 330 * {@link #getOutputFormats}).</p> 331 * 332 * @param format an image format from {@link ImageFormat} or {@link PixelFormat} 333 * @return 334 * an array of supported sizes, 335 * or {@code null} if the {@code format} is not a supported output 336 * 337 * @see ImageFormat 338 * @see PixelFormat 339 * @see #getOutputFormats 340 */ 341 public Size[] getOutputSizes(int format) { 342 return getPublicFormatSizes(format, /*output*/true); 343 } 344 345 /** 346 * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration} 347 * for the format/size combination (in nanoseconds). 348 * 349 * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p> 350 * <p>{@code size} should be one of the ones returned by 351 * {@link #getOutputSizes(int)}.</p> 352 * 353 * <p>This should correspond to the frame duration when only that stream is active, with all 354 * processing (typically in {@code android.*.mode}) set to either {@code OFF} or {@code FAST}. 355 * </p> 356 * 357 * <p>When multiple streams are used in a request, the minimum frame duration will be 358 * {@code max(individual stream min durations)}.</p> 359 * 360 * <p>For devices that do not support manual sensor control 361 * ({@link android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR}), 362 * this function may return {@link #NO_MIN_FRAME_DURATION}.</p> 363 * 364 * <!-- 365 * TODO: uncomment after adding input stream support 366 * <p>The minimum frame duration of a stream (of a particular format, size) is the same 367 * regardless of whether the stream is input or output.</p> 368 * --> 369 * 370 * @param format an image format from {@link ImageFormat} or {@link PixelFormat} 371 * @param size an output-compatible size 372 * @return a minimum frame duration {@code >} 0 in nanoseconds, or 373 * {@link #NO_MIN_FRAME_DURATION} if the minimum frame duration is not available. 374 * 375 * @throws IllegalArgumentException if {@code format} or {@code size} was not supported 376 * @throws NullPointerException if {@code size} was {@code null} 377 * 378 * @see CaptureRequest#SENSOR_FRAME_DURATION 379 * @see #getOutputStallDuration(int, Size) 380 * @see ImageFormat 381 * @see PixelFormat 382 */ 383 public long getOutputMinFrameDuration(int format, Size size) { 384 checkNotNull(size, "size must not be null"); 385 checkArgumentFormatSupported(format, /*output*/true); 386 387 return getInternalFormatDuration(imageFormatToInternal(format), size, DURATION_MIN_FRAME); 388 } 389 390 /** 391 * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration} 392 * for the class/size combination (in nanoseconds). 393 * 394 * <p>This assumes a the {@code klass} is set up to use an implementation-defined format. 395 * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p> 396 * 397 * <p>{@code klass} should be one of the ones which is supported by 398 * {@link #isOutputSupportedFor(Class)}.</p> 399 * 400 * <p>{@code size} should be one of the ones returned by 401 * {@link #getOutputSizes(int)}.</p> 402 * 403 * <p>This should correspond to the frame duration when only that stream is active, with all 404 * processing (typically in {@code android.*.mode}) set to either {@code OFF} or {@code FAST}. 405 * </p> 406 * 407 * <p>When multiple streams are used in a request, the minimum frame duration will be 408 * {@code max(individual stream min durations)}.</p> 409 * 410 * <p>For devices that do not support manual sensor control 411 * ({@link android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR}), 412 * this function may return {@link #NO_MIN_FRAME_DURATION}.</p> 413 * 414 * <!-- 415 * TODO: uncomment after adding input stream support 416 * <p>The minimum frame duration of a stream (of a particular format, size) is the same 417 * regardless of whether the stream is input or output.</p> 418 * --> 419 * 420 * @param klass 421 * a class which is supported by {@link #isOutputSupportedFor(Class)} and has a 422 * non-empty array returned by {@link #getOutputSizes(Class)} 423 * @param size an output-compatible size 424 * @return a minimum frame duration {@code >} 0 in nanoseconds, or 425 * {@link #NO_MIN_FRAME_DURATION} if the minimum frame duration is not available. 426 * 427 * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported 428 * @throws NullPointerException if {@code size} or {@code klass} was {@code null} 429 * 430 * @see CaptureRequest#SENSOR_FRAME_DURATION 431 * @see ImageFormat 432 * @see PixelFormat 433 */ 434 public <T> long getOutputMinFrameDuration(final Class<T> klass, final Size size) { 435 if (!isOutputSupportedFor(klass)) { 436 throw new IllegalArgumentException("klass was not supported"); 437 } 438 439 return getInternalFormatDuration(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 440 size, DURATION_MIN_FRAME); 441 } 442 443 /** 444 * Get the stall duration for the format/size combination (in nanoseconds). 445 * 446 * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p> 447 * <p>{@code size} should be one of the ones returned by 448 * {@link #getOutputSizes(int)}.</p> 449 * 450 * <p> 451 * A stall duration is how much extra time would get added to the normal minimum frame duration 452 * for a repeating request that has streams with non-zero stall. 453 * 454 * <p>For example, consider JPEG captures which have the following characteristics: 455 * 456 * <ul> 457 * <li>JPEG streams act like processed YUV streams in requests for which they are not included; 458 * in requests in which they are directly referenced, they act as JPEG streams. 459 * This is because supporting a JPEG stream requires the underlying YUV data to always be ready 460 * for use by a JPEG encoder, but the encoder will only be used (and impact frame duration) on 461 * requests that actually reference a JPEG stream. 462 * <li>The JPEG processor can run concurrently to the rest of the camera pipeline, but cannot 463 * process more than 1 capture at a time. 464 * </ul> 465 * 466 * <p>In other words, using a repeating YUV request would result in a steady frame rate 467 * (let's say it's 30 FPS). If a single JPEG request is submitted periodically, 468 * the frame rate will stay at 30 FPS (as long as we wait for the previous JPEG to return each 469 * time). If we try to submit a repeating YUV + JPEG request, then the frame rate will drop from 470 * 30 FPS.</p> 471 * 472 * <p>In general, submitting a new request with a non-0 stall time stream will <em>not</em> cause a 473 * frame rate drop unless there are still outstanding buffers for that stream from previous 474 * requests.</p> 475 * 476 * <p>Submitting a repeating request with streams (call this {@code S}) is the same as setting 477 * the minimum frame duration from the normal minimum frame duration corresponding to {@code S}, 478 * added with the maximum stall duration for {@code S}.</p> 479 * 480 * <p>If interleaving requests with and without a stall duration, a request will stall by the 481 * maximum of the remaining times for each can-stall stream with outstanding buffers.</p> 482 * 483 * <p>This means that a stalling request will not have an exposure start until the stall has 484 * completed.</p> 485 * 486 * <p>This should correspond to the stall duration when only that stream is active, with all 487 * processing (typically in {@code android.*.mode}) set to {@code FAST} or {@code OFF}. 488 * Setting any of the processing modes to {@code HIGH_QUALITY} effectively results in an 489 * indeterminate stall duration for all streams in a request (the regular stall calculation 490 * rules are ignored).</p> 491 * 492 * <p>The following formats may always have a stall duration: 493 * <ul> 494 * <li>{@link ImageFormat#JPEG JPEG} 495 * <li>{@link ImageFormat#RAW_SENSOR RAW16} 496 * </ul> 497 * </p> 498 * 499 * <p>The following formats will never have a stall duration: 500 * <ul> 501 * <li>{@link ImageFormat#YUV_420_888 YUV_420_888} 502 * <li>{@link #isOutputSupportedFor(Class) Implementation-Defined} 503 * </ul></p> 504 * 505 * <p> 506 * All other formats may or may not have an allowed stall duration on a per-capability basis; 507 * refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES 508 * android.request.availableCapabilities} for more details.</p> 509 * </p> 510 * 511 * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} 512 * for more information about calculating the max frame rate (absent stalls).</p> 513 * 514 * @param format an image format from {@link ImageFormat} or {@link PixelFormat} 515 * @param size an output-compatible size 516 * @return a stall duration {@code >=} 0 in nanoseconds 517 * 518 * @throws IllegalArgumentException if {@code format} or {@code size} was not supported 519 * @throws NullPointerException if {@code size} was {@code null} 520 * 521 * @see CaptureRequest#SENSOR_FRAME_DURATION 522 * @see ImageFormat 523 * @see PixelFormat 524 */ 525 public long getOutputStallDuration(int format, Size size) { 526 checkArgumentFormatSupported(format, /*output*/true); 527 528 return getInternalFormatDuration(imageFormatToInternal(format), 529 size, DURATION_STALL); 530 } 531 532 /** 533 * Get the stall duration for the class/size combination (in nanoseconds). 534 * 535 * <p>This assumes a the {@code klass} is set up to use an implementation-defined format. 536 * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p> 537 * 538 * <p>{@code klass} should be one of the ones with a non-empty array returned by 539 * {@link #getOutputSizes(Class)}.</p> 540 * 541 * <p>{@code size} should be one of the ones returned by 542 * {@link #getOutputSizes(Class)}.</p> 543 * 544 * <p>See {@link #getOutputStallDuration(int, Size)} for a definition of a 545 * <em>stall duration</em>.</p> 546 * 547 * @param klass 548 * a class which is supported by {@link #isOutputSupportedFor(Class)} and has a 549 * non-empty array returned by {@link #getOutputSizes(Class)} 550 * @param size an output-compatible size 551 * @return a minimum frame duration {@code >=} 0 in nanoseconds 552 * 553 * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported 554 * @throws NullPointerException if {@code size} or {@code klass} was {@code null} 555 * 556 * @see CaptureRequest#SENSOR_FRAME_DURATION 557 * @see ImageFormat 558 * @see PixelFormat 559 */ 560 public <T> long getOutputStallDuration(final Class<T> klass, final Size size) { 561 if (!isOutputSupportedFor(klass)) { 562 throw new IllegalArgumentException("klass was not supported"); 563 } 564 565 return getInternalFormatDuration(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 566 size, DURATION_STALL); 567 } 568 569 /** 570 * Check if this {@link StreamConfigurationMap} is equal to another 571 * {@link StreamConfigurationMap}. 572 * 573 * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p> 574 * 575 * @return {@code true} if the objects were equal, {@code false} otherwise 576 */ 577 @Override 578 public boolean equals(final Object obj) { 579 if (obj == null) { 580 return false; 581 } 582 if (this == obj) { 583 return true; 584 } 585 if (obj instanceof StreamConfigurationMap) { 586 final StreamConfigurationMap other = (StreamConfigurationMap) obj; 587 // XX: do we care about order? 588 return Arrays.equals(mConfigurations, other.mConfigurations) && 589 Arrays.equals(mMinFrameDurations, other.mMinFrameDurations) && 590 Arrays.equals(mStallDurations, other.mStallDurations); 591 } 592 return false; 593 } 594 595 /** 596 * {@inheritDoc} 597 */ 598 @Override 599 public int hashCode() { 600 // XX: do we care about order? 601 return HashCodeHelpers.hashCode(mConfigurations, mMinFrameDurations, mStallDurations); 602 } 603 604 // Check that the argument is supported by #getOutputFormats or #getInputFormats 605 private int checkArgumentFormatSupported(int format, boolean output) { 606 checkArgumentFormat(format); 607 608 int[] formats = output ? getOutputFormats() : getInputFormats(); 609 for (int i = 0; i < formats.length; ++i) { 610 if (format == formats[i]) { 611 return format; 612 } 613 } 614 615 throw new IllegalArgumentException(String.format( 616 "format %x is not supported by this stream configuration map", format)); 617 } 618 619 /** 620 * Ensures that the format is either user-defined or implementation defined. 621 * 622 * <p>If a format has a different internal representation than the public representation, 623 * passing in the public representation here will fail.</p> 624 * 625 * <p>For example if trying to use {@link ImageFormat#JPEG}: 626 * it has a different public representation than the internal representation 627 * {@code HAL_PIXEL_FORMAT_BLOB}, this check will fail.</p> 628 * 629 * <p>Any invalid/undefined formats will raise an exception.</p> 630 * 631 * @param format image format 632 * @return the format 633 * 634 * @throws IllegalArgumentException if the format was invalid 635 */ 636 static int checkArgumentFormatInternal(int format) { 637 switch (format) { 638 case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: 639 case HAL_PIXEL_FORMAT_BLOB: 640 return format; 641 case ImageFormat.JPEG: 642 throw new IllegalArgumentException( 643 "ImageFormat.JPEG is an unknown internal format"); 644 default: 645 return checkArgumentFormat(format); 646 } 647 } 648 649 /** 650 * Ensures that the format is publicly user-defined in either ImageFormat or PixelFormat. 651 * 652 * <p>If a format has a different public representation than the internal representation, 653 * passing in the internal representation here will fail.</p> 654 * 655 * <p>For example if trying to use {@code HAL_PIXEL_FORMAT_BLOB}: 656 * it has a different internal representation than the public representation 657 * {@link ImageFormat#JPEG}, this check will fail.</p> 658 * 659 * <p>Any invalid/undefined formats will raise an exception, including implementation-defined. 660 * </p> 661 * 662 * <p>Note that {@code @hide} and deprecated formats will not pass this check.</p> 663 * 664 * @param format image format 665 * @return the format 666 * 667 * @throws IllegalArgumentException if the format was not user-defined 668 */ 669 static int checkArgumentFormat(int format) { 670 // TODO: remove this hack , CTS shouldn't have been using internal constants 671 if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) { 672 Log.w(TAG, "RAW_OPAQUE is not yet a published format; allowing it anyway"); 673 return format; 674 } 675 676 if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) { 677 throw new IllegalArgumentException(String.format( 678 "format 0x%x was not defined in either ImageFormat or PixelFormat", format)); 679 } 680 681 return format; 682 } 683 684 /** 685 * Convert a public-visible {@code ImageFormat} into an internal format 686 * compatible with {@code graphics.h}. 687 * 688 * <p>In particular these formats are converted: 689 * <ul> 690 * <li>HAL_PIXEL_FORMAT_BLOB => ImageFormat.JPEG 691 * </ul> 692 * </p> 693 * 694 * <p>Passing in an implementation-defined format which has no public equivalent will fail; 695 * as will passing in a public format which has a different internal format equivalent. 696 * See {@link #checkArgumentFormat} for more details about a legal public format.</p> 697 * 698 * <p>All other formats are returned as-is, no further invalid check is performed.</p> 699 * 700 * <p>This function is the dual of {@link #imageFormatToInternal}.</p> 701 * 702 * @param format image format from {@link ImageFormat} or {@link PixelFormat} 703 * @return the converted image formats 704 * 705 * @throws IllegalArgumentException 706 * if {@code format} is {@code HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED} or 707 * {@link ImageFormat#JPEG} 708 * 709 * @see ImageFormat 710 * @see PixelFormat 711 * @see #checkArgumentFormat 712 */ 713 static int imageFormatToPublic(int format) { 714 switch (format) { 715 case HAL_PIXEL_FORMAT_BLOB: 716 return ImageFormat.JPEG; 717 case ImageFormat.JPEG: 718 throw new IllegalArgumentException( 719 "ImageFormat.JPEG is an unknown internal format"); 720 case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: 721 throw new IllegalArgumentException( 722 "IMPLEMENTATION_DEFINED must not leak to public API"); 723 default: 724 return format; 725 } 726 } 727 728 /** 729 * Convert image formats from internal to public formats (in-place). 730 * 731 * @param formats an array of image formats 732 * @return {@code formats} 733 * 734 * @see #imageFormatToPublic 735 */ 736 static int[] imageFormatToPublic(int[] formats) { 737 if (formats == null) { 738 return null; 739 } 740 741 for (int i = 0; i < formats.length; ++i) { 742 formats[i] = imageFormatToPublic(formats[i]); 743 } 744 745 return formats; 746 } 747 748 /** 749 * Convert a public format compatible with {@code ImageFormat} to an internal format 750 * from {@code graphics.h}. 751 * 752 * <p>In particular these formats are converted: 753 * <ul> 754 * <li>ImageFormat.JPEG => HAL_PIXEL_FORMAT_BLOB 755 * </ul> 756 * </p> 757 * 758 * <p>Passing in an implementation-defined format here will fail (it's not a public format); 759 * as will passing in an internal format which has a different public format equivalent. 760 * See {@link #checkArgumentFormat} for more details about a legal public format.</p> 761 * 762 * <p>All other formats are returned as-is, no invalid check is performed.</p> 763 * 764 * <p>This function is the dual of {@link #imageFormatToPublic}.</p> 765 * 766 * @param format public image format from {@link ImageFormat} or {@link PixelFormat} 767 * @return the converted image formats 768 * 769 * @see ImageFormat 770 * @see PixelFormat 771 * 772 * @throws IllegalArgumentException 773 * if {@code format} was {@code HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED} 774 */ 775 static int imageFormatToInternal(int format) { 776 switch (format) { 777 case ImageFormat.JPEG: 778 return HAL_PIXEL_FORMAT_BLOB; 779 case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: 780 throw new IllegalArgumentException( 781 "IMPLEMENTATION_DEFINED is not allowed via public API"); 782 default: 783 return format; 784 } 785 } 786 787 /** 788 * Convert image formats from public to internal formats (in-place). 789 * 790 * @param formats an array of image formats 791 * @return {@code formats} 792 * 793 * @see #imageFormatToInternal 794 * 795 * @hide 796 */ 797 public static int[] imageFormatToInternal(int[] formats) { 798 if (formats == null) { 799 return null; 800 } 801 802 for (int i = 0; i < formats.length; ++i) { 803 formats[i] = imageFormatToInternal(formats[i]); 804 } 805 806 return formats; 807 } 808 809 private Size[] getPublicFormatSizes(int format, boolean output) { 810 try { 811 checkArgumentFormatSupported(format, output); 812 } catch (IllegalArgumentException e) { 813 return null; 814 } 815 816 format = imageFormatToInternal(format); 817 818 return getInternalFormatSizes(format, output); 819 } 820 821 private Size[] getInternalFormatSizes(int format, boolean output) { 822 HashMap<Integer, Integer> formatsMap = getFormatsMap(output); 823 824 Integer sizesCount = formatsMap.get(format); 825 if (sizesCount == null) { 826 throw new IllegalArgumentException("format not available"); 827 } 828 829 int len = sizesCount; 830 Size[] sizes = new Size[len]; 831 int sizeIndex = 0; 832 833 for (StreamConfiguration config : mConfigurations) { 834 if (config.getFormat() == format && config.isOutput() == output) { 835 sizes[sizeIndex++] = config.getSize(); 836 } 837 } 838 839 if (sizeIndex != len) { 840 throw new AssertionError( 841 "Too few sizes (expected " + len + ", actual " + sizeIndex + ")"); 842 } 843 844 return sizes; 845 } 846 847 /** Get the list of publically visible output formats; does not include IMPL_DEFINED */ 848 private int[] getPublicFormats(boolean output) { 849 int[] formats = new int[getPublicFormatCount(output)]; 850 851 int i = 0; 852 853 for (int format : getFormatsMap(output).keySet()) { 854 if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) { 855 formats[i++] = format; 856 } 857 } 858 859 if (formats.length != i) { 860 throw new AssertionError("Too few formats " + i + ", expected " + formats.length); 861 } 862 863 return imageFormatToPublic(formats); 864 } 865 866 /** Get the format -> size count map for either output or input formats */ 867 private HashMap<Integer, Integer> getFormatsMap(boolean output) { 868 return output ? mOutputFormats : mInputFormats; 869 } 870 871 private long getInternalFormatDuration(int format, Size size, int duration) { 872 // assume format is already checked, since its internal 873 874 if (!arrayContains(getInternalFormatSizes(format, /*output*/true), size)) { 875 throw new IllegalArgumentException("size was not supported"); 876 } 877 878 StreamConfigurationDuration[] durations = getDurations(duration); 879 880 for (StreamConfigurationDuration configurationDuration : durations) { 881 if (configurationDuration.getFormat() == format && 882 configurationDuration.getWidth() == size.getWidth() && 883 configurationDuration.getHeight() == size.getHeight()) { 884 return configurationDuration.getDuration(); 885 } 886 } 887 888 return getDurationDefault(duration); 889 } 890 891 /** 892 * Get the durations array for the kind of duration 893 * 894 * @see #DURATION_MIN_FRAME 895 * @see #DURATION_STALL 896 * */ 897 private StreamConfigurationDuration[] getDurations(int duration) { 898 switch (duration) { 899 case DURATION_MIN_FRAME: 900 return mMinFrameDurations; 901 case DURATION_STALL: 902 return mStallDurations; 903 default: 904 throw new IllegalArgumentException("duration was invalid"); 905 } 906 } 907 908 private long getDurationDefault(int duration) { 909 switch (duration) { 910 case DURATION_MIN_FRAME: 911 return NO_MIN_FRAME_DURATION; 912 case DURATION_STALL: 913 return 0L; // OK. A lack of a stall duration implies a 0 stall duration 914 default: 915 throw new IllegalArgumentException("duration was invalid"); 916 } 917 } 918 919 /** Count the number of publicly-visible output formats */ 920 private int getPublicFormatCount(boolean output) { 921 HashMap<Integer, Integer> formatsMap = getFormatsMap(output); 922 923 int size = formatsMap.size(); 924 if (formatsMap.containsKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)) { 925 size -= 1; 926 } 927 return size; 928 } 929 930 private static <T> boolean arrayContains(T[] array, T element) { 931 if (array == null) { 932 return false; 933 } 934 935 for (T el : array) { 936 if (Objects.equals(el, element)) { 937 return true; 938 } 939 } 940 941 return false; 942 } 943 944 // from system/core/include/system/graphics.h 945 private static final int HAL_PIXEL_FORMAT_BLOB = 0x21; 946 private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22; 947 private static final int HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24; 948 949 /** 950 * @see #getDurations(int) 951 * @see #getDurationDefault(int) 952 */ 953 private static final int DURATION_MIN_FRAME = 0; 954 private static final int DURATION_STALL = 1; 955 956 private final StreamConfiguration[] mConfigurations; 957 private final StreamConfigurationDuration[] mMinFrameDurations; 958 private final StreamConfigurationDuration[] mStallDurations; 959 960 /** ImageFormat -> num output sizes mapping */ 961 private final HashMap</*ImageFormat*/Integer, /*Count*/Integer> mOutputFormats = 962 new HashMap<Integer, Integer>(); 963 /** ImageFormat -> num input sizes mapping */ 964 private final HashMap</*ImageFormat*/Integer, /*Count*/Integer> mInputFormats = 965 new HashMap<Integer, Integer>(); 966 967} 968