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