StreamConfigurationMap.java revision 3e4fed203fe7c945c53c6d6bb9f160932a1d15b3
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 * <!-- 361 * TODO: uncomment after adding input stream support 362 * <p>The minimum frame duration of a stream (of a particular format, size) is the same 363 * regardless of whether the stream is input or output.</p> 364 * --> 365 * 366 * @param format an image format from {@link ImageFormat} or {@link PixelFormat} 367 * @param size an output-compatible size 368 * @return a minimum frame duration {@code >} 0 in nanoseconds, or 369 * {@link #NO_MIN_FRAME_DURATION} if the minimum frame duration is not available (this 370 * can only occur on limited mode devices). 371 * 372 * @throws IllegalArgumentException if {@code format} or {@code size} was not supported 373 * @throws NullPointerException if {@code size} was {@code null} 374 * 375 * @see CaptureRequest#SENSOR_FRAME_DURATION 376 * @see #getOutputStallDuration(int, Size) 377 * @see ImageFormat 378 * @see PixelFormat 379 */ 380 public long getOutputMinFrameDuration(int format, Size size) { 381 checkNotNull(size, "size must not be null"); 382 checkArgumentFormatSupported(format, /*output*/true); 383 384 return getInternalFormatDuration(imageFormatToInternal(format), size, DURATION_MIN_FRAME); 385 } 386 387 /** 388 * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration} 389 * for the class/size combination (in nanoseconds). 390 * 391 * <p>This assumes a the {@code klass} is set up to use an implementation-defined format. 392 * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p> 393 * 394 * <p>{@code klass} should be one of the ones which is supported by 395 * {@link #isOutputSupportedFor(Class)}.</p> 396 * 397 * <p>{@code size} should be one of the ones returned by 398 * {@link #getOutputSizes(int)}.</p> 399 * 400 * <p>This should correspond to the frame duration when only that stream is active, with all 401 * processing (typically in {@code android.*.mode}) set to either {@code OFF} or {@code FAST}. 402 * </p> 403 * 404 * <p>When multiple streams are used in a request, the minimum frame duration will be 405 * {@code max(individual stream min durations)}.</p> 406 * 407 * <!-- 408 * TODO: uncomment after adding input stream support 409 * <p>The minimum frame duration of a stream (of a particular format, size) is the same 410 * regardless of whether the stream is input or output.</p> 411 * --> 412 * 413 * @param klass 414 * a class which is supported by {@link #isOutputSupportedFor(Class)} and has a 415 * non-empty array returned by {@link #getOutputSizes(Class)} 416 * @param size an output-compatible size 417 * @return a minimum frame duration {@code >} 0 in nanoseconds, or 418 * {@link #NO_MIN_FRAME_DURATION} if the minimum frame duration is not available (this 419 * can only occur on limited mode devices). 420 * 421 * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported 422 * @throws NullPointerException if {@code size} or {@code klass} was {@code null} 423 * 424 * @see CaptureRequest#SENSOR_FRAME_DURATION 425 * @see ImageFormat 426 * @see PixelFormat 427 */ 428 public <T> long getOutputMinFrameDuration(final Class<T> klass, final Size size) { 429 if (!isOutputSupportedFor(klass)) { 430 throw new IllegalArgumentException("klass was not supported"); 431 } 432 433 return getInternalFormatDuration(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 434 size, DURATION_MIN_FRAME); 435 } 436 437 /** 438 * Get the stall duration for the format/size combination (in nanoseconds). 439 * 440 * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p> 441 * <p>{@code size} should be one of the ones returned by 442 * {@link #getOutputSizes(int)}.</p> 443 * 444 * <p> 445 * A stall duration is how much extra time would get added to the normal minimum frame duration 446 * for a repeating request that has streams with non-zero stall. 447 * 448 * <p>For example, consider JPEG captures which have the following characteristics: 449 * 450 * <ul> 451 * <li>JPEG streams act like processed YUV streams in requests for which they are not included; 452 * in requests in which they are directly referenced, they act as JPEG streams. 453 * This is because supporting a JPEG stream requires the underlying YUV data to always be ready 454 * for use by a JPEG encoder, but the encoder will only be used (and impact frame duration) on 455 * requests that actually reference a JPEG stream. 456 * <li>The JPEG processor can run concurrently to the rest of the camera pipeline, but cannot 457 * process more than 1 capture at a time. 458 * </ul> 459 * 460 * <p>In other words, using a repeating YUV request would result in a steady frame rate 461 * (let's say it's 30 FPS). If a single JPEG request is submitted periodically, 462 * the frame rate will stay at 30 FPS (as long as we wait for the previous JPEG to return each 463 * time). If we try to submit a repeating YUV + JPEG request, then the frame rate will drop from 464 * 30 FPS.</p> 465 * 466 * <p>In general, submitting a new request with a non-0 stall time stream will <em>not</em> cause a 467 * frame rate drop unless there are still outstanding buffers for that stream from previous 468 * requests.</p> 469 * 470 * <p>Submitting a repeating request with streams (call this {@code S}) is the same as setting 471 * the minimum frame duration from the normal minimum frame duration corresponding to {@code S}, 472 * added with the maximum stall duration for {@code S}.</p> 473 * 474 * <p>If interleaving requests with and without a stall duration, a request will stall by the 475 * maximum of the remaining times for each can-stall stream with outstanding buffers.</p> 476 * 477 * <p>This means that a stalling request will not have an exposure start until the stall has 478 * completed.</p> 479 * 480 * <p>This should correspond to the stall duration when only that stream is active, with all 481 * processing (typically in {@code android.*.mode}) set to {@code FAST} or {@code OFF}. 482 * Setting any of the processing modes to {@code HIGH_QUALITY} effectively results in an 483 * indeterminate stall duration for all streams in a request (the regular stall calculation 484 * rules are ignored).</p> 485 * 486 * <p>The following formats may always have a stall duration: 487 * <ul> 488 * <li>{@link ImageFormat#JPEG JPEG} 489 * <li>{@link ImageFormat#RAW_SENSOR RAW16} 490 * </ul> 491 * </p> 492 * 493 * <p>The following formats will never have a stall duration: 494 * <ul> 495 * <li>{@link ImageFormat#YUV_420_888 YUV_420_888} 496 * <li>{@link #isOutputSupportedFor(Class) Implementation-Defined} 497 * </ul></p> 498 * 499 * <p> 500 * All other formats may or may not have an allowed stall duration on a per-capability basis; 501 * refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES 502 * android.request.availableCapabilities} for more details.</p> 503 * </p> 504 * 505 * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} 506 * for more information about calculating the max frame rate (absent stalls).</p> 507 * 508 * @param format an image format from {@link ImageFormat} or {@link PixelFormat} 509 * @param size an output-compatible size 510 * @return a stall duration {@code >=} 0 in nanoseconds 511 * 512 * @throws IllegalArgumentException if {@code format} or {@code size} was not supported 513 * @throws NullPointerException if {@code size} was {@code null} 514 * 515 * @see CaptureRequest#SENSOR_FRAME_DURATION 516 * @see ImageFormat 517 * @see PixelFormat 518 */ 519 public long getOutputStallDuration(int format, Size size) { 520 checkArgumentFormatSupported(format, /*output*/true); 521 522 return getInternalFormatDuration(imageFormatToInternal(format), 523 size, DURATION_STALL); 524 } 525 526 /** 527 * Get the stall duration for the class/size combination (in nanoseconds). 528 * 529 * <p>This assumes a the {@code klass} is set up to use an implementation-defined format. 530 * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p> 531 * 532 * <p>{@code klass} should be one of the ones with a non-empty array returned by 533 * {@link #getOutputSizes(Class)}.</p> 534 * 535 * <p>{@code size} should be one of the ones returned by 536 * {@link #getOutputSizes(Class)}.</p> 537 * 538 * <p>See {@link #getOutputStallDuration(int, Size)} for a definition of a 539 * <em>stall duration</em>.</p> 540 * 541 * @param klass 542 * a class which is supported by {@link #isOutputSupportedFor(Class)} and has a 543 * non-empty array returned by {@link #getOutputSizes(Class)} 544 * @param size an output-compatible size 545 * @return a minimum frame duration {@code >=} 0 in nanoseconds 546 * 547 * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported 548 * @throws NullPointerException if {@code size} or {@code klass} was {@code null} 549 * 550 * @see CaptureRequest#SENSOR_FRAME_DURATION 551 * @see ImageFormat 552 * @see PixelFormat 553 */ 554 public <T> long getOutputStallDuration(final Class<T> klass, final Size size) { 555 if (!isOutputSupportedFor(klass)) { 556 throw new IllegalArgumentException("klass was not supported"); 557 } 558 559 return getInternalFormatDuration(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 560 size, DURATION_STALL); 561 } 562 563 /** 564 * Check if this {@link StreamConfigurationMap} is equal to another 565 * {@link StreamConfigurationMap}. 566 * 567 * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p> 568 * 569 * @return {@code true} if the objects were equal, {@code false} otherwise 570 */ 571 @Override 572 public boolean equals(final Object obj) { 573 if (obj == null) { 574 return false; 575 } 576 if (this == obj) { 577 return true; 578 } 579 if (obj instanceof StreamConfigurationMap) { 580 final StreamConfigurationMap other = (StreamConfigurationMap) obj; 581 // XX: do we care about order? 582 return Arrays.equals(mConfigurations, other.mConfigurations) && 583 Arrays.equals(mMinFrameDurations, other.mMinFrameDurations) && 584 Arrays.equals(mStallDurations, other.mStallDurations); 585 } 586 return false; 587 } 588 589 /** 590 * {@inheritDoc} 591 */ 592 @Override 593 public int hashCode() { 594 // XX: do we care about order? 595 return HashCodeHelpers.hashCode(mConfigurations, mMinFrameDurations, mStallDurations); 596 } 597 598 // Check that the argument is supported by #getOutputFormats or #getInputFormats 599 private int checkArgumentFormatSupported(int format, boolean output) { 600 checkArgumentFormat(format); 601 602 int[] formats = output ? getOutputFormats() : getInputFormats(); 603 for (int i = 0; i < formats.length; ++i) { 604 if (format == formats[i]) { 605 return format; 606 } 607 } 608 609 throw new IllegalArgumentException(String.format( 610 "format %x is not supported by this stream configuration map", format)); 611 } 612 613 /** 614 * Ensures that the format is either user-defined or implementation defined. 615 * 616 * <p>If a format has a different internal representation than the public representation, 617 * passing in the public representation here will fail.</p> 618 * 619 * <p>For example if trying to use {@link ImageFormat#JPEG}: 620 * it has a different public representation than the internal representation 621 * {@code HAL_PIXEL_FORMAT_BLOB}, this check will fail.</p> 622 * 623 * <p>Any invalid/undefined formats will raise an exception.</p> 624 * 625 * @param format image format 626 * @return the format 627 * 628 * @throws IllegalArgumentException if the format was invalid 629 */ 630 static int checkArgumentFormatInternal(int format) { 631 switch (format) { 632 case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: 633 case HAL_PIXEL_FORMAT_BLOB: 634 return format; 635 case ImageFormat.JPEG: 636 throw new IllegalArgumentException( 637 "ImageFormat.JPEG is an unknown internal format"); 638 default: 639 return checkArgumentFormat(format); 640 } 641 } 642 643 /** 644 * Ensures that the format is publicly user-defined in either ImageFormat or PixelFormat. 645 * 646 * <p>If a format has a different public representation than the internal representation, 647 * passing in the internal representation here will fail.</p> 648 * 649 * <p>For example if trying to use {@code HAL_PIXEL_FORMAT_BLOB}: 650 * it has a different internal representation than the public representation 651 * {@link ImageFormat#JPEG}, this check will fail.</p> 652 * 653 * <p>Any invalid/undefined formats will raise an exception, including implementation-defined. 654 * </p> 655 * 656 * <p>Note that {@code @hide} and deprecated formats will not pass this check.</p> 657 * 658 * @param format image format 659 * @return the format 660 * 661 * @throws IllegalArgumentException if the format was not user-defined 662 */ 663 static int checkArgumentFormat(int format) { 664 // TODO: remove this hack , CTS shouldn't have been using internal constants 665 if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) { 666 Log.w(TAG, "RAW_OPAQUE is not yet a published format; allowing it anyway"); 667 return format; 668 } 669 670 if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) { 671 throw new IllegalArgumentException(String.format( 672 "format 0x%x was not defined in either ImageFormat or PixelFormat", format)); 673 } 674 675 return format; 676 } 677 678 /** 679 * Convert a public-visible {@code ImageFormat} into an internal format 680 * compatible with {@code graphics.h}. 681 * 682 * <p>In particular these formats are converted: 683 * <ul> 684 * <li>HAL_PIXEL_FORMAT_BLOB => ImageFormat.JPEG 685 * </ul> 686 * </p> 687 * 688 * <p>Passing in an implementation-defined format which has no public equivalent will fail; 689 * as will passing in a public format which has a different internal format equivalent. 690 * See {@link #checkArgumentFormat} for more details about a legal public format.</p> 691 * 692 * <p>All other formats are returned as-is, no further invalid check is performed.</p> 693 * 694 * <p>This function is the dual of {@link #imageFormatToInternal}.</p> 695 * 696 * @param format image format from {@link ImageFormat} or {@link PixelFormat} 697 * @return the converted image formats 698 * 699 * @throws IllegalArgumentException 700 * if {@code format} is {@code HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED} or 701 * {@link ImageFormat#JPEG} 702 * 703 * @see ImageFormat 704 * @see PixelFormat 705 * @see #checkArgumentFormat 706 */ 707 static int imageFormatToPublic(int format) { 708 switch (format) { 709 case HAL_PIXEL_FORMAT_BLOB: 710 return ImageFormat.JPEG; 711 case ImageFormat.JPEG: 712 throw new IllegalArgumentException( 713 "ImageFormat.JPEG is an unknown internal format"); 714 case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: 715 throw new IllegalArgumentException( 716 "IMPLEMENTATION_DEFINED must not leak to public API"); 717 default: 718 return format; 719 } 720 } 721 722 /** 723 * Convert image formats from internal to public formats (in-place). 724 * 725 * @param formats an array of image formats 726 * @return {@code formats} 727 * 728 * @see #imageFormatToPublic 729 */ 730 static int[] imageFormatToPublic(int[] formats) { 731 if (formats == null) { 732 return null; 733 } 734 735 for (int i = 0; i < formats.length; ++i) { 736 formats[i] = imageFormatToPublic(formats[i]); 737 } 738 739 return formats; 740 } 741 742 /** 743 * Convert a public format compatible with {@code ImageFormat} to an internal format 744 * from {@code graphics.h}. 745 * 746 * <p>In particular these formats are converted: 747 * <ul> 748 * <li>ImageFormat.JPEG => HAL_PIXEL_FORMAT_BLOB 749 * </ul> 750 * </p> 751 * 752 * <p>Passing in an implementation-defined format here will fail (it's not a public format); 753 * as will passing in an internal format which has a different public format equivalent. 754 * See {@link #checkArgumentFormat} for more details about a legal public format.</p> 755 * 756 * <p>All other formats are returned as-is, no invalid check is performed.</p> 757 * 758 * <p>This function is the dual of {@link #imageFormatToPublic}.</p> 759 * 760 * @param format public image format from {@link ImageFormat} or {@link PixelFormat} 761 * @return the converted image formats 762 * 763 * @see ImageFormat 764 * @see PixelFormat 765 * 766 * @throws IllegalArgumentException 767 * if {@code format} was {@code HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED} 768 */ 769 static int imageFormatToInternal(int format) { 770 switch (format) { 771 case ImageFormat.JPEG: 772 return HAL_PIXEL_FORMAT_BLOB; 773 case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: 774 throw new IllegalArgumentException( 775 "IMPLEMENTATION_DEFINED is not allowed via public API"); 776 default: 777 return format; 778 } 779 } 780 781 /** 782 * Convert image formats from public to internal formats (in-place). 783 * 784 * @param formats an array of image formats 785 * @return {@code formats} 786 * 787 * @see #imageFormatToInternal 788 * 789 * @hide 790 */ 791 public static int[] imageFormatToInternal(int[] formats) { 792 if (formats == null) { 793 return null; 794 } 795 796 for (int i = 0; i < formats.length; ++i) { 797 formats[i] = imageFormatToInternal(formats[i]); 798 } 799 800 return formats; 801 } 802 803 private Size[] getPublicFormatSizes(int format, boolean output) { 804 try { 805 checkArgumentFormatSupported(format, output); 806 } catch (IllegalArgumentException e) { 807 return null; 808 } 809 810 format = imageFormatToInternal(format); 811 812 return getInternalFormatSizes(format, output); 813 } 814 815 private Size[] getInternalFormatSizes(int format, boolean output) { 816 HashMap<Integer, Integer> formatsMap = getFormatsMap(output); 817 818 Integer sizesCount = formatsMap.get(format); 819 if (sizesCount == null) { 820 throw new IllegalArgumentException("format not available"); 821 } 822 823 int len = sizesCount; 824 Size[] sizes = new Size[len]; 825 int sizeIndex = 0; 826 827 for (StreamConfiguration config : mConfigurations) { 828 if (config.getFormat() == format && config.isOutput() == output) { 829 sizes[sizeIndex++] = config.getSize(); 830 } 831 } 832 833 if (sizeIndex != len) { 834 throw new AssertionError( 835 "Too few sizes (expected " + len + ", actual " + sizeIndex + ")"); 836 } 837 838 return sizes; 839 } 840 841 /** Get the list of publically visible output formats; does not include IMPL_DEFINED */ 842 private int[] getPublicFormats(boolean output) { 843 int[] formats = new int[getPublicFormatCount(output)]; 844 845 int i = 0; 846 847 for (int format : getFormatsMap(output).keySet()) { 848 if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) { 849 formats[i++] = format; 850 } 851 } 852 853 if (formats.length != i) { 854 throw new AssertionError("Too few formats " + i + ", expected " + formats.length); 855 } 856 857 return imageFormatToPublic(formats); 858 } 859 860 /** Get the format -> size count map for either output or input formats */ 861 private HashMap<Integer, Integer> getFormatsMap(boolean output) { 862 return output ? mOutputFormats : mInputFormats; 863 } 864 865 private long getInternalFormatDuration(int format, Size size, int duration) { 866 // assume format is already checked, since its internal 867 868 if (!arrayContains(getInternalFormatSizes(format, /*output*/true), size)) { 869 throw new IllegalArgumentException("size was not supported"); 870 } 871 872 StreamConfigurationDuration[] durations = getDurations(duration); 873 874 for (StreamConfigurationDuration configurationDuration : durations) { 875 if (configurationDuration.getFormat() == format && 876 configurationDuration.getWidth() == size.getWidth() && 877 configurationDuration.getHeight() == size.getHeight()) { 878 return configurationDuration.getDuration(); 879 } 880 } 881 882 return getDurationDefault(duration); 883 } 884 885 /** 886 * Get the durations array for the kind of duration 887 * 888 * @see #DURATION_MIN_FRAME 889 * @see #DURATION_STALL 890 * */ 891 private StreamConfigurationDuration[] getDurations(int duration) { 892 switch (duration) { 893 case DURATION_MIN_FRAME: 894 return mMinFrameDurations; 895 case DURATION_STALL: 896 return mStallDurations; 897 default: 898 throw new IllegalArgumentException("duration was invalid"); 899 } 900 } 901 902 private long getDurationDefault(int duration) { 903 switch (duration) { 904 case DURATION_MIN_FRAME: 905 return NO_MIN_FRAME_DURATION; 906 case DURATION_STALL: 907 return 0L; // OK. A lack of a stall duration implies a 0 stall duration 908 default: 909 throw new IllegalArgumentException("duration was invalid"); 910 } 911 } 912 913 /** Count the number of publicly-visible output formats */ 914 private int getPublicFormatCount(boolean output) { 915 HashMap<Integer, Integer> formatsMap = getFormatsMap(output); 916 917 int size = formatsMap.size(); 918 if (formatsMap.containsKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)) { 919 size -= 1; 920 } 921 return size; 922 } 923 924 private static <T> boolean arrayContains(T[] array, T element) { 925 if (array == null) { 926 return false; 927 } 928 929 for (T el : array) { 930 if (Objects.equals(el, element)) { 931 return true; 932 } 933 } 934 935 return false; 936 } 937 938 // from system/core/include/system/graphics.h 939 private static final int HAL_PIXEL_FORMAT_BLOB = 0x21; 940 private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22; 941 private static final int HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24; 942 943 /** 944 * @see #getDurations(int) 945 * @see #getDurationDefault(int) 946 */ 947 private static final int DURATION_MIN_FRAME = 0; 948 private static final int DURATION_STALL = 1; 949 950 private final StreamConfiguration[] mConfigurations; 951 private final StreamConfigurationDuration[] mMinFrameDurations; 952 private final StreamConfigurationDuration[] mStallDurations; 953 954 /** ImageFormat -> num output sizes mapping */ 955 private final HashMap</*ImageFormat*/Integer, /*Count*/Integer> mOutputFormats = 956 new HashMap<Integer, Integer>(); 957 /** ImageFormat -> num input sizes mapping */ 958 private final HashMap</*ImageFormat*/Integer, /*Count*/Integer> mInputFormats = 959 new HashMap<Integer, Integer>(); 960 961} 962