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