Home | History | Annotate | Download | only in media
      1 /*
      2  * Copyright (C) 2012 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.media;
     18 
     19 import android.annotation.NonNull;
     20 import android.annotation.Nullable;
     21 import android.util.Log;
     22 import android.util.Pair;
     23 import android.util.Range;
     24 import android.util.Rational;
     25 import android.util.Size;
     26 
     27 import java.util.ArrayList;
     28 import java.util.Arrays;
     29 import java.util.HashMap;
     30 import java.util.Map;
     31 import java.util.Set;
     32 
     33 import static android.media.Utils.intersectSortedDistinctRanges;
     34 import static android.media.Utils.sortDistinctRanges;
     35 
     36 /**
     37  * Provides information about a given media codec available on the device. You can
     38  * iterate through all codecs available by querying {@link MediaCodecList}. For example,
     39  * here's how to find an encoder that supports a given MIME type:
     40  * <pre>
     41  * private static MediaCodecInfo selectCodec(String mimeType) {
     42  *     int numCodecs = MediaCodecList.getCodecCount();
     43  *     for (int i = 0; i &lt; numCodecs; i++) {
     44  *         MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
     45  *
     46  *         if (!codecInfo.isEncoder()) {
     47  *             continue;
     48  *         }
     49  *
     50  *         String[] types = codecInfo.getSupportedTypes();
     51  *         for (int j = 0; j &lt; types.length; j++) {
     52  *             if (types[j].equalsIgnoreCase(mimeType)) {
     53  *                 return codecInfo;
     54  *             }
     55  *         }
     56  *     }
     57  *     return null;
     58  * }</pre>
     59  *
     60  */
     61 public final class MediaCodecInfo {
     62     private boolean mIsEncoder;
     63     private String mName;
     64     private Map<String, CodecCapabilities> mCaps;
     65 
     66     /* package private */ MediaCodecInfo(
     67             String name, boolean isEncoder, CodecCapabilities[] caps) {
     68         mName = name;
     69         mIsEncoder = isEncoder;
     70         mCaps = new HashMap<String, CodecCapabilities>();
     71         for (CodecCapabilities c: caps) {
     72             mCaps.put(c.getMimeType(), c);
     73         }
     74     }
     75 
     76     /**
     77      * Retrieve the codec name.
     78      */
     79     public final String getName() {
     80         return mName;
     81     }
     82 
     83     /**
     84      * Query if the codec is an encoder.
     85      */
     86     public final boolean isEncoder() {
     87         return mIsEncoder;
     88     }
     89 
     90     /**
     91      * Query the media types supported by the codec.
     92      */
     93     public final String[] getSupportedTypes() {
     94         Set<String> typeSet = mCaps.keySet();
     95         String[] types = typeSet.toArray(new String[typeSet.size()]);
     96         Arrays.sort(types);
     97         return types;
     98     }
     99 
    100     private static int checkPowerOfTwo(int value, String message) {
    101         if ((value & (value - 1)) != 0) {
    102             throw new IllegalArgumentException(message);
    103         }
    104         return value;
    105     }
    106 
    107     private static class Feature {
    108         public String mName;
    109         public int mValue;
    110         public boolean mDefault;
    111         public Feature(String name, int value, boolean def) {
    112             mName = name;
    113             mValue = value;
    114             mDefault = def;
    115         }
    116     }
    117 
    118     // COMMON CONSTANTS
    119     private static final Range<Integer> POSITIVE_INTEGERS =
    120         Range.create(1, Integer.MAX_VALUE);
    121     private static final Range<Long> POSITIVE_LONGS =
    122         Range.create(1l, Long.MAX_VALUE);
    123     private static final Range<Rational> POSITIVE_RATIONALS =
    124         Range.create(new Rational(1, Integer.MAX_VALUE),
    125                      new Rational(Integer.MAX_VALUE, 1));
    126     private static final Range<Integer> SIZE_RANGE = Range.create(1, 32768);
    127     private static final Range<Integer> FRAME_RATE_RANGE = Range.create(0, 960);
    128     private static final Range<Integer> BITRATE_RANGE = Range.create(0, 500000000);
    129     private static final int DEFAULT_MAX_SUPPORTED_INSTANCES = 32;
    130     private static final int MAX_SUPPORTED_INSTANCES_LIMIT = 256;
    131 
    132     // found stuff that is not supported by framework (=> this should not happen)
    133     private static final int ERROR_UNRECOGNIZED   = (1 << 0);
    134     // found profile/level for which we don't have capability estimates
    135     private static final int ERROR_UNSUPPORTED    = (1 << 1);
    136     // have not found any profile/level for which we don't have capability estimate
    137     private static final int ERROR_NONE_SUPPORTED = (1 << 2);
    138 
    139 
    140     /**
    141      * Encapsulates the capabilities of a given codec component.
    142      * For example, what profile/level combinations it supports and what colorspaces
    143      * it is capable of providing the decoded data in, as well as some
    144      * codec-type specific capability flags.
    145      * <p>You can get an instance for a given {@link MediaCodecInfo} object with
    146      * {@link MediaCodecInfo#getCapabilitiesForType getCapabilitiesForType()}, passing a MIME type.
    147      */
    148     public static final class CodecCapabilities {
    149         public CodecCapabilities() {
    150         }
    151 
    152         // CLASSIFICATION
    153         private String mMime;
    154         private int mMaxSupportedInstances;
    155 
    156         // LEGACY FIELDS
    157 
    158         // Enumerates supported profile/level combinations as defined
    159         // by the type of encoded data. These combinations impose restrictions
    160         // on video resolution, bitrate... and limit the available encoder tools
    161         // such as B-frame support, arithmetic coding...
    162         public CodecProfileLevel[] profileLevels;  // NOTE this array is modifiable by user
    163 
    164         // from OMX_COLOR_FORMATTYPE
    165         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
    166         public static final int COLOR_FormatMonochrome              = 1;
    167         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
    168         public static final int COLOR_Format8bitRGB332              = 2;
    169         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
    170         public static final int COLOR_Format12bitRGB444             = 3;
    171         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
    172         public static final int COLOR_Format16bitARGB4444           = 4;
    173         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
    174         public static final int COLOR_Format16bitARGB1555           = 5;
    175 
    176         /**
    177          * 16 bits per pixel RGB color format, with 5-bit red & blue and 6-bit green component.
    178          * <p>
    179          * Using 16-bit little-endian representation, colors stored as Red 15:11, Green 10:5, Blue 4:0.
    180          * <pre>
    181          *            byte                   byte
    182          *  <--------- i --------> | <------ i + 1 ------>
    183          * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    184          * |     BLUE     |      GREEN      |     RED      |
    185          * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    186          *  0           4  5     7   0     2  3           7
    187          * bit
    188          * </pre>
    189          *
    190          * This format corresponds to {@link android.graphics.PixelFormat#RGB_565} and
    191          * {@link android.graphics.ImageFormat#RGB_565}.
    192          */
    193         public static final int COLOR_Format16bitRGB565             = 6;
    194         /** @deprecated Use {@link #COLOR_Format16bitRGB565}. */
    195         public static final int COLOR_Format16bitBGR565             = 7;
    196         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
    197         public static final int COLOR_Format18bitRGB666             = 8;
    198         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
    199         public static final int COLOR_Format18bitARGB1665           = 9;
    200         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
    201         public static final int COLOR_Format19bitARGB1666           = 10;
    202 
    203         /** @deprecated Use {@link #COLOR_Format24bitBGR888} or {@link #COLOR_FormatRGBFlexible}. */
    204         public static final int COLOR_Format24bitRGB888             = 11;
    205 
    206         /**
    207          * 24 bits per pixel RGB color format, with 8-bit red, green & blue components.
    208          * <p>
    209          * Using 24-bit little-endian representation, colors stored as Red 7:0, Green 15:8, Blue 23:16.
    210          * <pre>
    211          *         byte              byte             byte
    212          *  <------ i -----> | <---- i+1 ----> | <---- i+2 ----->
    213          * +-----------------+-----------------+-----------------+
    214          * |       RED       |      GREEN      |       BLUE      |
    215          * +-----------------+-----------------+-----------------+
    216          * </pre>
    217          *
    218          * This format corresponds to {@link android.graphics.PixelFormat#RGB_888}, and can also be
    219          * represented as a flexible format by {@link #COLOR_FormatRGBFlexible}.
    220          */
    221         public static final int COLOR_Format24bitBGR888             = 12;
    222         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
    223         public static final int COLOR_Format24bitARGB1887           = 13;
    224         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
    225         public static final int COLOR_Format25bitARGB1888           = 14;
    226 
    227         /**
    228          * @deprecated Use {@link #COLOR_Format32bitABGR8888} Or {@link #COLOR_FormatRGBAFlexible}.
    229          */
    230         public static final int COLOR_Format32bitBGRA8888           = 15;
    231         /**
    232          * @deprecated Use {@link #COLOR_Format32bitABGR8888} Or {@link #COLOR_FormatRGBAFlexible}.
    233          */
    234         public static final int COLOR_Format32bitARGB8888           = 16;
    235         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
    236         public static final int COLOR_FormatYUV411Planar            = 17;
    237         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
    238         public static final int COLOR_FormatYUV411PackedPlanar      = 18;
    239         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
    240         public static final int COLOR_FormatYUV420Planar            = 19;
    241         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
    242         public static final int COLOR_FormatYUV420PackedPlanar      = 20;
    243         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
    244         public static final int COLOR_FormatYUV420SemiPlanar        = 21;
    245 
    246         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
    247         public static final int COLOR_FormatYUV422Planar            = 22;
    248         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
    249         public static final int COLOR_FormatYUV422PackedPlanar      = 23;
    250         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
    251         public static final int COLOR_FormatYUV422SemiPlanar        = 24;
    252 
    253         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
    254         public static final int COLOR_FormatYCbYCr                  = 25;
    255         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
    256         public static final int COLOR_FormatYCrYCb                  = 26;
    257         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
    258         public static final int COLOR_FormatCbYCrY                  = 27;
    259         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
    260         public static final int COLOR_FormatCrYCbY                  = 28;
    261 
    262         /** @deprecated Use {@link #COLOR_FormatYUV444Flexible}. */
    263         public static final int COLOR_FormatYUV444Interleaved       = 29;
    264 
    265         /**
    266          * SMIA 8-bit Bayer format.
    267          * Each byte represents the top 8-bits of a 10-bit signal.
    268          */
    269         public static final int COLOR_FormatRawBayer8bit            = 30;
    270         /**
    271          * SMIA 10-bit Bayer format.
    272          */
    273         public static final int COLOR_FormatRawBayer10bit           = 31;
    274 
    275         /**
    276          * SMIA 8-bit compressed Bayer format.
    277          * Each byte represents a sample from the 10-bit signal that is compressed into 8-bits
    278          * using DPCM/PCM compression, as defined by the SMIA Functional Specification.
    279          */
    280         public static final int COLOR_FormatRawBayer8bitcompressed  = 32;
    281 
    282         /** @deprecated Use {@link #COLOR_FormatL8}. */
    283         public static final int COLOR_FormatL2                      = 33;
    284         /** @deprecated Use {@link #COLOR_FormatL8}. */
    285         public static final int COLOR_FormatL4                      = 34;
    286 
    287         /**
    288          * 8 bits per pixel Y color format.
    289          * <p>
    290          * Each byte contains a single pixel.
    291          * This format corresponds to {@link android.graphics.PixelFormat#L_8}.
    292          */
    293         public static final int COLOR_FormatL8                      = 35;
    294 
    295         /**
    296          * 16 bits per pixel, little-endian Y color format.
    297          * <p>
    298          * <pre>
    299          *            byte                   byte
    300          *  <--------- i --------> | <------ i + 1 ------>
    301          * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    302          * |                       Y                       |
    303          * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    304          *  0                    7   0                    7
    305          * bit
    306          * </pre>
    307          */
    308         public static final int COLOR_FormatL16                     = 36;
    309         /** @deprecated Use {@link #COLOR_FormatL16}. */
    310         public static final int COLOR_FormatL24                     = 37;
    311 
    312         /**
    313          * 32 bits per pixel, little-endian Y color format.
    314          * <p>
    315          * <pre>
    316          *         byte              byte             byte              byte
    317          *  <------ i -----> | <---- i+1 ----> | <---- i+2 ----> | <---- i+3 ----->
    318          * +-----------------+-----------------+-----------------+-----------------+
    319          * |                                   Y                                   |
    320          * +-----------------+-----------------+-----------------+-----------------+
    321          *  0               7 0               7 0               7 0               7
    322          * bit
    323          * </pre>
    324          *
    325          * @deprecated Use {@link #COLOR_FormatL16}.
    326          */
    327         public static final int COLOR_FormatL32                     = 38;
    328 
    329         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
    330         public static final int COLOR_FormatYUV420PackedSemiPlanar  = 39;
    331         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
    332         public static final int COLOR_FormatYUV422PackedSemiPlanar  = 40;
    333 
    334         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
    335         public static final int COLOR_Format18BitBGR666             = 41;
    336 
    337         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
    338         public static final int COLOR_Format24BitARGB6666           = 42;
    339         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
    340         public static final int COLOR_Format24BitABGR6666           = 43;
    341 
    342         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
    343         public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100;
    344         // COLOR_FormatSurface indicates that the data will be a GraphicBuffer metadata reference.
    345         // In OMX this is called OMX_COLOR_FormatAndroidOpaque.
    346         public static final int COLOR_FormatSurface                   = 0x7F000789;
    347 
    348         /**
    349          * 32 bits per pixel RGBA color format, with 8-bit red, green, blue, and alpha components.
    350          * <p>
    351          * Using 32-bit little-endian representation, colors stored as Red 7:0, Green 15:8,
    352          * Blue 23:16, and Alpha 31:24.
    353          * <pre>
    354          *         byte              byte             byte              byte
    355          *  <------ i -----> | <---- i+1 ----> | <---- i+2 ----> | <---- i+3 ----->
    356          * +-----------------+-----------------+-----------------+-----------------+
    357          * |       RED       |      GREEN      |       BLUE      |      ALPHA      |
    358          * +-----------------+-----------------+-----------------+-----------------+
    359          * </pre>
    360          *
    361          * This corresponds to {@link android.graphics.PixelFormat#RGBA_8888}.
    362          */
    363         public static final int COLOR_Format32bitABGR8888             = 0x7F00A000;
    364 
    365         /**
    366          * Flexible 12 bits per pixel, subsampled YUV color format with 8-bit chroma and luma
    367          * components.
    368          * <p>
    369          * Chroma planes are subsampled by 2 both horizontally and vertically.
    370          * Use this format with {@link Image}.
    371          * This format corresponds to {@link android.graphics.ImageFormat#YUV_420_888},
    372          * and can represent the {@link #COLOR_FormatYUV411Planar},
    373          * {@link #COLOR_FormatYUV411PackedPlanar}, {@link #COLOR_FormatYUV420Planar},
    374          * {@link #COLOR_FormatYUV420PackedPlanar}, {@link #COLOR_FormatYUV420SemiPlanar}
    375          * and {@link #COLOR_FormatYUV420PackedSemiPlanar} formats.
    376          *
    377          * @see Image#getFormat
    378          */
    379         public static final int COLOR_FormatYUV420Flexible            = 0x7F420888;
    380 
    381         /**
    382          * Flexible 16 bits per pixel, subsampled YUV color format with 8-bit chroma and luma
    383          * components.
    384          * <p>
    385          * Chroma planes are horizontally subsampled by 2. Use this format with {@link Image}.
    386          * This format corresponds to {@link android.graphics.ImageFormat#YUV_422_888},
    387          * and can represent the {@link #COLOR_FormatYCbYCr}, {@link #COLOR_FormatYCrYCb},
    388          * {@link #COLOR_FormatCbYCrY}, {@link #COLOR_FormatCrYCbY},
    389          * {@link #COLOR_FormatYUV422Planar}, {@link #COLOR_FormatYUV422PackedPlanar},
    390          * {@link #COLOR_FormatYUV422SemiPlanar} and {@link #COLOR_FormatYUV422PackedSemiPlanar}
    391          * formats.
    392          *
    393          * @see Image#getFormat
    394          */
    395         public static final int COLOR_FormatYUV422Flexible            = 0x7F422888;
    396 
    397         /**
    398          * Flexible 24 bits per pixel YUV color format with 8-bit chroma and luma
    399          * components.
    400          * <p>
    401          * Chroma planes are not subsampled. Use this format with {@link Image}.
    402          * This format corresponds to {@link android.graphics.ImageFormat#YUV_444_888},
    403          * and can represent the {@link #COLOR_FormatYUV444Interleaved} format.
    404          * @see Image#getFormat
    405          */
    406         public static final int COLOR_FormatYUV444Flexible            = 0x7F444888;
    407 
    408         /**
    409          * Flexible 24 bits per pixel RGB color format with 8-bit red, green and blue
    410          * components.
    411          * <p>
    412          * Use this format with {@link Image}. This format corresponds to
    413          * {@link android.graphics.ImageFormat#FLEX_RGB_888}, and can represent
    414          * {@link #COLOR_Format24bitBGR888} and {@link #COLOR_Format24bitRGB888} formats.
    415          * @see Image#getFormat.
    416          */
    417         public static final int COLOR_FormatRGBFlexible               = 0x7F36B888;
    418 
    419         /**
    420          * Flexible 32 bits per pixel RGBA color format with 8-bit red, green, blue, and alpha
    421          * components.
    422          * <p>
    423          * Use this format with {@link Image}. This format corresponds to
    424          * {@link android.graphics.ImageFormat#FLEX_RGBA_8888}, and can represent
    425          * {@link #COLOR_Format32bitBGRA8888}, {@link #COLOR_Format32bitABGR8888} and
    426          * {@link #COLOR_Format32bitARGB8888} formats.
    427          *
    428          * @see Image#getFormat
    429          */
    430         public static final int COLOR_FormatRGBAFlexible              = 0x7F36A888;
    431 
    432         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
    433         public static final int COLOR_QCOM_FormatYUV420SemiPlanar     = 0x7fa30c00;
    434 
    435         /**
    436          * Defined in the OpenMAX IL specs, color format values are drawn from
    437          * OMX_COLOR_FORMATTYPE.
    438          */
    439         public int[] colorFormats; // NOTE this array is modifiable by user
    440 
    441         // FEATURES
    442 
    443         private int mFlagsSupported;
    444         private int mFlagsRequired;
    445         private int mFlagsVerified;
    446 
    447         /**
    448          * <b>video decoder only</b>: codec supports seamless resolution changes.
    449          */
    450         public static final String FEATURE_AdaptivePlayback       = "adaptive-playback";
    451 
    452         /**
    453          * <b>video decoder only</b>: codec supports secure decryption.
    454          */
    455         public static final String FEATURE_SecurePlayback         = "secure-playback";
    456 
    457         /**
    458          * <b>video or audio decoder only</b>: codec supports tunneled playback.
    459          */
    460         public static final String FEATURE_TunneledPlayback       = "tunneled-playback";
    461 
    462         /**
    463          * <b>video encoder only</b>: codec supports intra refresh.
    464          */
    465         public static final String FEATURE_IntraRefresh = "intra-refresh";
    466 
    467         /**
    468          * Query codec feature capabilities.
    469          * <p>
    470          * These features are supported to be used by the codec.  These
    471          * include optional features that can be turned on, as well as
    472          * features that are always on.
    473          */
    474         public final boolean isFeatureSupported(String name) {
    475             return checkFeature(name, mFlagsSupported);
    476         }
    477 
    478         /**
    479          * Query codec feature requirements.
    480          * <p>
    481          * These features are required to be used by the codec, and as such,
    482          * they are always turned on.
    483          */
    484         public final boolean isFeatureRequired(String name) {
    485             return checkFeature(name, mFlagsRequired);
    486         }
    487 
    488         private static final Feature[] decoderFeatures = {
    489             new Feature(FEATURE_AdaptivePlayback, (1 << 0), true),
    490             new Feature(FEATURE_SecurePlayback,   (1 << 1), false),
    491             new Feature(FEATURE_TunneledPlayback, (1 << 2), false),
    492         };
    493 
    494         private static final Feature[] encoderFeatures = {
    495             new Feature(FEATURE_IntraRefresh, (1 << 0), false),
    496         };
    497 
    498         /** @hide */
    499         public String[] validFeatures() {
    500             Feature[] features = getValidFeatures();
    501             String[] res = new String[features.length];
    502             for (int i = 0; i < res.length; i++) {
    503                 res[i] = features[i].mName;
    504             }
    505             return res;
    506         }
    507 
    508         private Feature[] getValidFeatures() {
    509             if (!isEncoder()) {
    510                 return decoderFeatures;
    511             }
    512             return encoderFeatures;
    513         }
    514 
    515         private boolean checkFeature(String name, int flags) {
    516             for (Feature feat: getValidFeatures()) {
    517                 if (feat.mName.equals(name)) {
    518                     return (flags & feat.mValue) != 0;
    519                 }
    520             }
    521             return false;
    522         }
    523 
    524         /** @hide */
    525         public boolean isRegular() {
    526             // regular codecs only require default features
    527             for (Feature feat: getValidFeatures()) {
    528                 if (!feat.mDefault && isFeatureRequired(feat.mName)) {
    529                     return false;
    530                 }
    531             }
    532             return true;
    533         }
    534 
    535         /**
    536          * Query whether codec supports a given {@link MediaFormat}.
    537          *
    538          * <p class=note>
    539          * <strong>Note:</strong> On {@link android.os.Build.VERSION_CODES#LOLLIPOP},
    540          * {@code format} must not contain a {@linkplain MediaFormat#KEY_FRAME_RATE
    541          * frame rate}. Use
    542          * <code class=prettyprint>format.setString(MediaFormat.KEY_FRAME_RATE, null)</code>
    543          * to clear any existing frame rate setting in the format.
    544          * <p>
    545          *
    546          * The following table summarizes the format keys considered by this method.
    547          *
    548          * <table style="width: 0%">
    549          *  <thead>
    550          *   <tr>
    551          *    <th rowspan=3>OS Version(s)</th>
    552          *    <td colspan=3>{@code MediaFormat} keys considered for</th>
    553          *   </tr><tr>
    554          *    <th>Audio Codecs</th>
    555          *    <th>Video Codecs</th>
    556          *    <th>Encoders</th>
    557          *   </tr>
    558          *  </thead>
    559          *  <tbody>
    560          *   <tr>
    561          *    <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP}</th>
    562          *    <td rowspan=3>{@link MediaFormat#KEY_MIME}<sup>*</sup>,<br>
    563          *        {@link MediaFormat#KEY_SAMPLE_RATE},<br>
    564          *        {@link MediaFormat#KEY_CHANNEL_COUNT},</td>
    565          *    <td>{@link MediaFormat#KEY_MIME}<sup>*</sup>,<br>
    566          *        {@link CodecCapabilities#FEATURE_AdaptivePlayback}<sup>D</sup>,<br>
    567          *        {@link CodecCapabilities#FEATURE_SecurePlayback}<sup>D</sup>,<br>
    568          *        {@link CodecCapabilities#FEATURE_TunneledPlayback}<sup>D</sup>,<br>
    569          *        {@link MediaFormat#KEY_WIDTH},<br>
    570          *        {@link MediaFormat#KEY_HEIGHT},<br>
    571          *        <strong>no</strong> {@code KEY_FRAME_RATE}</td>
    572          *    <td rowspan=4>{@link MediaFormat#KEY_BITRATE_MODE},<br>
    573          *        {@link MediaFormat#KEY_PROFILE}
    574          *        (and/or {@link MediaFormat#KEY_AAC_PROFILE}<sup>~</sup>),<br>
    575          *        <!-- {link MediaFormat#KEY_QUALITY},<br> -->
    576          *        {@link MediaFormat#KEY_COMPLEXITY}
    577          *        (and/or {@link MediaFormat#KEY_FLAC_COMPRESSION_LEVEL}<sup>~</sup>)</td>
    578          *   </tr><tr>
    579          *    <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}</th>
    580          *    <td rowspan=2>as above, plus<br>
    581          *        {@link MediaFormat#KEY_FRAME_RATE}</td>
    582          *   </tr><tr>
    583          *    <td>{@link android.os.Build.VERSION_CODES#M}</th>
    584          *   </tr><tr>
    585          *    <td>{@link android.os.Build.VERSION_CODES#N}</th>
    586          *    <td>as above, plus<br>
    587          *        {@link MediaFormat#KEY_PROFILE},<br>
    588          *        <!-- {link MediaFormat#KEY_MAX_BIT_RATE},<br> -->
    589          *        {@link MediaFormat#KEY_BIT_RATE}</td>
    590          *    <td>as above, plus<br>
    591          *        {@link MediaFormat#KEY_PROFILE},<br>
    592          *        {@link MediaFormat#KEY_LEVEL}<sup>+</sup>,<br>
    593          *        <!-- {link MediaFormat#KEY_MAX_BIT_RATE},<br> -->
    594          *        {@link MediaFormat#KEY_BIT_RATE},<br>
    595          *        {@link CodecCapabilities#FEATURE_IntraRefresh}<sup>E</sup></td>
    596          *   </tr>
    597          *   <tr>
    598          *    <td colspan=4>
    599          *     <p class=note><strong>Notes:</strong><br>
    600          *      *: must be specified; otherwise, method returns {@code false}.<br>
    601          *      +: method does not verify that the format parameters are supported
    602          *      by the specified level.<br>
    603          *      D: decoders only<br>
    604          *      E: encoders only<br>
    605          *      ~: if both keys are provided values must match
    606          *    </td>
    607          *   </tr>
    608          *  </tbody>
    609          * </table>
    610          *
    611          * @param format media format with optional feature directives.
    612          * @throws IllegalArgumentException if format is not a valid media format.
    613          * @return whether the codec capabilities support the given format
    614          *         and feature requests.
    615          */
    616         public final boolean isFormatSupported(MediaFormat format) {
    617             final Map<String, Object> map = format.getMap();
    618             final String mime = (String)map.get(MediaFormat.KEY_MIME);
    619 
    620             // mime must match if present
    621             if (mime != null && !mMime.equalsIgnoreCase(mime)) {
    622                 return false;
    623             }
    624 
    625             // check feature support
    626             for (Feature feat: getValidFeatures()) {
    627                 Integer yesNo = (Integer)map.get(MediaFormat.KEY_FEATURE_ + feat.mName);
    628                 if (yesNo == null) {
    629                     continue;
    630                 }
    631                 if ((yesNo == 1 && !isFeatureSupported(feat.mName)) ||
    632                         (yesNo == 0 && isFeatureRequired(feat.mName))) {
    633                     return false;
    634                 }
    635             }
    636 
    637             Integer profile = (Integer)map.get(MediaFormat.KEY_PROFILE);
    638             Integer level = (Integer)map.get(MediaFormat.KEY_LEVEL);
    639 
    640             if (profile != null) {
    641                 if (!supportsProfileLevel(profile, level)) {
    642                     return false;
    643                 }
    644 
    645                 // If we recognize this profile, check that this format is supported by the
    646                 // highest level supported by the codec for that profile. (Ignore specified
    647                 // level beyond the above profile/level check as level is only used as a
    648                 // guidance. E.g. AVC Level 1 CIF format is supported if codec supports level 1.1
    649                 // even though max size for Level 1 is QCIF. However, MPEG2 Simple Profile
    650                 // 1080p format is not supported even if codec supports Main Profile Level High,
    651                 // as Simple Profile does not support 1080p.
    652                 CodecCapabilities levelCaps = null;
    653                 int maxLevel = 0;
    654                 for (CodecProfileLevel pl : profileLevels) {
    655                     if (pl.profile == profile && pl.level > maxLevel) {
    656                         maxLevel = pl.level;
    657                     }
    658                 }
    659                 levelCaps = createFromProfileLevel(mMime, profile, maxLevel);
    660                 // remove profile from this format otherwise levelCaps.isFormatSupported will
    661                 // get into this same conditon and loop forever.
    662                 Map<String, Object> mapWithoutProfile = new HashMap<>(map);
    663                 mapWithoutProfile.remove(MediaFormat.KEY_PROFILE);
    664                 MediaFormat formatWithoutProfile = new MediaFormat(mapWithoutProfile);
    665                 if (levelCaps != null && !levelCaps.isFormatSupported(formatWithoutProfile)) {
    666                     return false;
    667                 }
    668             }
    669             if (mAudioCaps != null && !mAudioCaps.supportsFormat(format)) {
    670                 return false;
    671             }
    672             if (mVideoCaps != null && !mVideoCaps.supportsFormat(format)) {
    673                 return false;
    674             }
    675             if (mEncoderCaps != null && !mEncoderCaps.supportsFormat(format)) {
    676                 return false;
    677             }
    678             return true;
    679         }
    680 
    681         private static boolean supportsBitrate(
    682                 Range<Integer> bitrateRange, MediaFormat format) {
    683             Map<String, Object> map = format.getMap();
    684 
    685             // consider max bitrate over average bitrate for support
    686             Integer maxBitrate = (Integer)map.get(MediaFormat.KEY_MAX_BIT_RATE);
    687             Integer bitrate = (Integer)map.get(MediaFormat.KEY_BIT_RATE);
    688             if (bitrate == null) {
    689                 bitrate = maxBitrate;
    690             } else if (maxBitrate != null) {
    691                 bitrate = Math.max(bitrate, maxBitrate);
    692             }
    693 
    694             if (bitrate != null && bitrate > 0) {
    695                 return bitrateRange.contains(bitrate);
    696             }
    697 
    698             return true;
    699         }
    700 
    701         private boolean supportsProfileLevel(int profile, Integer level) {
    702             for (CodecProfileLevel pl: profileLevels) {
    703                 if (pl.profile != profile) {
    704                     continue;
    705                 }
    706 
    707                 // AAC does not use levels
    708                 if (level == null || mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC)) {
    709                     return true;
    710                 }
    711 
    712                 // H.263 levels are not completely ordered:
    713                 // Level45 support only implies Level10 support
    714                 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) {
    715                     if (pl.level != level && pl.level == CodecProfileLevel.H263Level45
    716                             && level > CodecProfileLevel.H263Level10) {
    717                         continue;
    718                     }
    719                 }
    720 
    721                 // MPEG4 levels are not completely ordered:
    722                 // Level1 support only implies Level0 (and not Level0b) support
    723                 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) {
    724                     if (pl.level != level && pl.level == CodecProfileLevel.MPEG4Level1
    725                             && level > CodecProfileLevel.MPEG4Level0) {
    726                         continue;
    727                     }
    728                 }
    729 
    730                 // HEVC levels incorporate both tiers and levels. Verify tier support.
    731                 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
    732                     boolean supportsHighTier =
    733                         (pl.level & CodecProfileLevel.HEVCHighTierLevels) != 0;
    734                     boolean checkingHighTier = (level & CodecProfileLevel.HEVCHighTierLevels) != 0;
    735                     // high tier levels are only supported by other high tier levels
    736                     if (checkingHighTier && !supportsHighTier) {
    737                         continue;
    738                     }
    739                 }
    740 
    741                 if (pl.level >= level) {
    742                     // if we recognize the listed profile/level, we must also recognize the
    743                     // profile/level arguments.
    744                     if (createFromProfileLevel(mMime, profile, pl.level) != null) {
    745                         return createFromProfileLevel(mMime, profile, level) != null;
    746                     }
    747                     return true;
    748                 }
    749             }
    750             return false;
    751         }
    752 
    753         // errors while reading profile levels - accessed from sister capabilities
    754         int mError;
    755 
    756         private static final String TAG = "CodecCapabilities";
    757 
    758         // NEW-STYLE CAPABILITIES
    759         private AudioCapabilities mAudioCaps;
    760         private VideoCapabilities mVideoCaps;
    761         private EncoderCapabilities mEncoderCaps;
    762         private MediaFormat mDefaultFormat;
    763 
    764         /**
    765          * Returns a MediaFormat object with default values for configurations that have
    766          * defaults.
    767          */
    768         public MediaFormat getDefaultFormat() {
    769             return mDefaultFormat;
    770         }
    771 
    772         /**
    773          * Returns the mime type for which this codec-capability object was created.
    774          */
    775         public String getMimeType() {
    776             return mMime;
    777         }
    778 
    779         /**
    780          * Returns the max number of the supported concurrent codec instances.
    781          * <p>
    782          * This is a hint for an upper bound. Applications should not expect to successfully
    783          * operate more instances than the returned value, but the actual number of
    784          * concurrently operable instances may be less as it depends on the available
    785          * resources at time of use.
    786          */
    787         public int getMaxSupportedInstances() {
    788             return mMaxSupportedInstances;
    789         }
    790 
    791         private boolean isAudio() {
    792             return mAudioCaps != null;
    793         }
    794 
    795         /**
    796          * Returns the audio capabilities or {@code null} if this is not an audio codec.
    797          */
    798         public AudioCapabilities getAudioCapabilities() {
    799             return mAudioCaps;
    800         }
    801 
    802         private boolean isEncoder() {
    803             return mEncoderCaps != null;
    804         }
    805 
    806         /**
    807          * Returns the encoding capabilities or {@code null} if this is not an encoder.
    808          */
    809         public EncoderCapabilities getEncoderCapabilities() {
    810             return mEncoderCaps;
    811         }
    812 
    813         private boolean isVideo() {
    814             return mVideoCaps != null;
    815         }
    816 
    817         /**
    818          * Returns the video capabilities or {@code null} if this is not a video codec.
    819          */
    820         public VideoCapabilities getVideoCapabilities() {
    821             return mVideoCaps;
    822         }
    823 
    824         /** @hide */
    825         public CodecCapabilities dup() {
    826             return new CodecCapabilities(
    827                 // clone writable arrays
    828                 Arrays.copyOf(profileLevels, profileLevels.length),
    829                 Arrays.copyOf(colorFormats, colorFormats.length),
    830                 isEncoder(),
    831                 mFlagsVerified,
    832                 mDefaultFormat,
    833                 mCapabilitiesInfo);
    834         }
    835 
    836         /**
    837          * Retrieve the codec capabilities for a certain {@code mime type}, {@code
    838          * profile} and {@code level}.  If the type, or profile-level combination
    839          * is not understood by the framework, it returns null.
    840          * <p class=note> In {@link android.os.Build.VERSION_CODES#M}, calling this
    841          * method without calling any method of the {@link MediaCodecList} class beforehand
    842          * results in a {@link NullPointerException}.</p>
    843          */
    844         public static CodecCapabilities createFromProfileLevel(
    845                 String mime, int profile, int level) {
    846             CodecProfileLevel pl = new CodecProfileLevel();
    847             pl.profile = profile;
    848             pl.level = level;
    849             MediaFormat defaultFormat = new MediaFormat();
    850             defaultFormat.setString(MediaFormat.KEY_MIME, mime);
    851 
    852             CodecCapabilities ret = new CodecCapabilities(
    853                 new CodecProfileLevel[] { pl }, new int[0], true /* encoder */,
    854                 0 /* flags */, defaultFormat, new MediaFormat() /* info */);
    855             if (ret.mError != 0) {
    856                 return null;
    857             }
    858             return ret;
    859         }
    860 
    861         /* package private */ CodecCapabilities(
    862                 CodecProfileLevel[] profLevs, int[] colFmts,
    863                 boolean encoder, int flags,
    864                 Map<String, Object>defaultFormatMap,
    865                 Map<String, Object>capabilitiesMap) {
    866             this(profLevs, colFmts, encoder, flags,
    867                     new MediaFormat(defaultFormatMap),
    868                     new MediaFormat(capabilitiesMap));
    869         }
    870 
    871         private MediaFormat mCapabilitiesInfo;
    872 
    873         /* package private */ CodecCapabilities(
    874                 CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags,
    875                 MediaFormat defaultFormat, MediaFormat info) {
    876             final Map<String, Object> map = info.getMap();
    877             colorFormats = colFmts;
    878             mFlagsVerified = flags;
    879             mDefaultFormat = defaultFormat;
    880             mCapabilitiesInfo = info;
    881             mMime = mDefaultFormat.getString(MediaFormat.KEY_MIME);
    882 
    883             /* VP9 introduced profiles around 2016, so some VP9 codecs may not advertise any
    884                supported profiles. Determine the level for them using the info they provide. */
    885             if (profLevs.length == 0 && mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) {
    886                 CodecProfileLevel profLev = new CodecProfileLevel();
    887                 profLev.profile = CodecProfileLevel.VP9Profile0;
    888                 profLev.level = VideoCapabilities.equivalentVP9Level(info);
    889                 profLevs = new CodecProfileLevel[] { profLev };
    890             }
    891             profileLevels = profLevs;
    892 
    893             if (mMime.toLowerCase().startsWith("audio/")) {
    894                 mAudioCaps = AudioCapabilities.create(info, this);
    895                 mAudioCaps.setDefaultFormat(mDefaultFormat);
    896             } else if (mMime.toLowerCase().startsWith("video/")) {
    897                 mVideoCaps = VideoCapabilities.create(info, this);
    898             }
    899             if (encoder) {
    900                 mEncoderCaps = EncoderCapabilities.create(info, this);
    901                 mEncoderCaps.setDefaultFormat(mDefaultFormat);
    902             }
    903 
    904             final Map<String, Object> global = MediaCodecList.getGlobalSettings();
    905             mMaxSupportedInstances = Utils.parseIntSafely(
    906                     global.get("max-concurrent-instances"), DEFAULT_MAX_SUPPORTED_INSTANCES);
    907 
    908             int maxInstances = Utils.parseIntSafely(
    909                     map.get("max-concurrent-instances"), mMaxSupportedInstances);
    910             mMaxSupportedInstances =
    911                     Range.create(1, MAX_SUPPORTED_INSTANCES_LIMIT).clamp(maxInstances);
    912 
    913             for (Feature feat: getValidFeatures()) {
    914                 String key = MediaFormat.KEY_FEATURE_ + feat.mName;
    915                 Integer yesNo = (Integer)map.get(key);
    916                 if (yesNo == null) {
    917                     continue;
    918                 }
    919                 if (yesNo > 0) {
    920                     mFlagsRequired |= feat.mValue;
    921                 }
    922                 mFlagsSupported |= feat.mValue;
    923                 mDefaultFormat.setInteger(key, 1);
    924                 // TODO restrict features by mFlagsVerified once all codecs reliably verify them
    925             }
    926         }
    927     }
    928 
    929     /**
    930      * A class that supports querying the audio capabilities of a codec.
    931      */
    932     public static final class AudioCapabilities {
    933         private static final String TAG = "AudioCapabilities";
    934         private CodecCapabilities mParent;
    935         private Range<Integer> mBitrateRange;
    936 
    937         private int[] mSampleRates;
    938         private Range<Integer>[] mSampleRateRanges;
    939         private int mMaxInputChannelCount;
    940 
    941         private static final int MAX_INPUT_CHANNEL_COUNT = 30;
    942 
    943         /**
    944          * Returns the range of supported bitrates in bits/second.
    945          */
    946         public Range<Integer> getBitrateRange() {
    947             return mBitrateRange;
    948         }
    949 
    950         /**
    951          * Returns the array of supported sample rates if the codec
    952          * supports only discrete values.  Otherwise, it returns
    953          * {@code null}.  The array is sorted in ascending order.
    954          */
    955         public int[] getSupportedSampleRates() {
    956             return Arrays.copyOf(mSampleRates, mSampleRates.length);
    957         }
    958 
    959         /**
    960          * Returns the array of supported sample rate ranges.  The
    961          * array is sorted in ascending order, and the ranges are
    962          * distinct.
    963          */
    964         public Range<Integer>[] getSupportedSampleRateRanges() {
    965             return Arrays.copyOf(mSampleRateRanges, mSampleRateRanges.length);
    966         }
    967 
    968         /**
    969          * Returns the maximum number of input channels supported.  The codec
    970          * supports any number of channels between 1 and this maximum value.
    971          */
    972         public int getMaxInputChannelCount() {
    973             return mMaxInputChannelCount;
    974         }
    975 
    976         /* no public constructor */
    977         private AudioCapabilities() { }
    978 
    979         /** @hide */
    980         public static AudioCapabilities create(
    981                 MediaFormat info, CodecCapabilities parent) {
    982             AudioCapabilities caps = new AudioCapabilities();
    983             caps.init(info, parent);
    984             return caps;
    985         }
    986 
    987         /** @hide */
    988         public void init(MediaFormat info, CodecCapabilities parent) {
    989             mParent = parent;
    990             initWithPlatformLimits();
    991             applyLevelLimits();
    992             parseFromInfo(info);
    993         }
    994 
    995         private void initWithPlatformLimits() {
    996             mBitrateRange = Range.create(0, Integer.MAX_VALUE);
    997             mMaxInputChannelCount = MAX_INPUT_CHANNEL_COUNT;
    998             // mBitrateRange = Range.create(1, 320000);
    999             mSampleRateRanges = new Range[] { Range.create(8000, 96000) };
   1000             mSampleRates = null;
   1001         }
   1002 
   1003         private boolean supports(Integer sampleRate, Integer inputChannels) {
   1004             // channels and sample rates are checked orthogonally
   1005             if (inputChannels != null &&
   1006                     (inputChannels < 1 || inputChannels > mMaxInputChannelCount)) {
   1007                 return false;
   1008             }
   1009             if (sampleRate != null) {
   1010                 int ix = Utils.binarySearchDistinctRanges(
   1011                         mSampleRateRanges, sampleRate);
   1012                 if (ix < 0) {
   1013                     return false;
   1014                 }
   1015             }
   1016             return true;
   1017         }
   1018 
   1019         /**
   1020          * Query whether the sample rate is supported by the codec.
   1021          */
   1022         public boolean isSampleRateSupported(int sampleRate) {
   1023             return supports(sampleRate, null);
   1024         }
   1025 
   1026         /** modifies rates */
   1027         private void limitSampleRates(int[] rates) {
   1028             Arrays.sort(rates);
   1029             ArrayList<Range<Integer>> ranges = new ArrayList<Range<Integer>>();
   1030             for (int rate: rates) {
   1031                 if (supports(rate, null /* channels */)) {
   1032                     ranges.add(Range.create(rate, rate));
   1033                 }
   1034             }
   1035             mSampleRateRanges = ranges.toArray(new Range[ranges.size()]);
   1036             createDiscreteSampleRates();
   1037         }
   1038 
   1039         private void createDiscreteSampleRates() {
   1040             mSampleRates = new int[mSampleRateRanges.length];
   1041             for (int i = 0; i < mSampleRateRanges.length; i++) {
   1042                 mSampleRates[i] = mSampleRateRanges[i].getLower();
   1043             }
   1044         }
   1045 
   1046         /** modifies rateRanges */
   1047         private void limitSampleRates(Range<Integer>[] rateRanges) {
   1048             sortDistinctRanges(rateRanges);
   1049             mSampleRateRanges = intersectSortedDistinctRanges(mSampleRateRanges, rateRanges);
   1050 
   1051             // check if all values are discrete
   1052             for (Range<Integer> range: mSampleRateRanges) {
   1053                 if (!range.getLower().equals(range.getUpper())) {
   1054                     mSampleRates = null;
   1055                     return;
   1056                 }
   1057             }
   1058             createDiscreteSampleRates();
   1059         }
   1060 
   1061         private void applyLevelLimits() {
   1062             int[] sampleRates = null;
   1063             Range<Integer> sampleRateRange = null, bitRates = null;
   1064             int maxChannels = 0;
   1065             String mime = mParent.getMimeType();
   1066 
   1067             if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MPEG)) {
   1068                 sampleRates = new int[] {
   1069                         8000, 11025, 12000,
   1070                         16000, 22050, 24000,
   1071                         32000, 44100, 48000 };
   1072                 bitRates = Range.create(8000, 320000);
   1073                 maxChannels = 2;
   1074             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)) {
   1075                 sampleRates = new int[] { 8000 };
   1076                 bitRates = Range.create(4750, 12200);
   1077                 maxChannels = 1;
   1078             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)) {
   1079                 sampleRates = new int[] { 16000 };
   1080                 bitRates = Range.create(6600, 23850);
   1081                 maxChannels = 1;
   1082             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC)) {
   1083                 sampleRates = new int[] {
   1084                         7350, 8000,
   1085                         11025, 12000, 16000,
   1086                         22050, 24000, 32000,
   1087                         44100, 48000, 64000,
   1088                         88200, 96000 };
   1089                 bitRates = Range.create(8000, 510000);
   1090                 maxChannels = 48;
   1091             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_VORBIS)) {
   1092                 bitRates = Range.create(32000, 500000);
   1093                 sampleRateRange = Range.create(8000, 192000);
   1094                 maxChannels = 255;
   1095             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_OPUS)) {
   1096                 bitRates = Range.create(6000, 510000);
   1097                 sampleRates = new int[] { 8000, 12000, 16000, 24000, 48000 };
   1098                 maxChannels = 255;
   1099             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW)) {
   1100                 sampleRateRange = Range.create(1, 96000);
   1101                 bitRates = Range.create(1, 10000000);
   1102                 maxChannels = AudioTrack.CHANNEL_COUNT_MAX;
   1103             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
   1104                 sampleRateRange = Range.create(1, 655350);
   1105                 // lossless codec, so bitrate is ignored
   1106                 maxChannels = 255;
   1107             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW)
   1108                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)) {
   1109                 sampleRates = new int[] { 8000 };
   1110                 bitRates = Range.create(64000, 64000);
   1111                 // platform allows multiple channels for this format
   1112             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) {
   1113                 sampleRates = new int[] { 8000 };
   1114                 bitRates = Range.create(13000, 13000);
   1115                 maxChannels = 1;
   1116             } else {
   1117                 Log.w(TAG, "Unsupported mime " + mime);
   1118                 mParent.mError |= ERROR_UNSUPPORTED;
   1119             }
   1120 
   1121             // restrict ranges
   1122             if (sampleRates != null) {
   1123                 limitSampleRates(sampleRates);
   1124             } else if (sampleRateRange != null) {
   1125                 limitSampleRates(new Range[] { sampleRateRange });
   1126             }
   1127             applyLimits(maxChannels, bitRates);
   1128         }
   1129 
   1130         private void applyLimits(int maxInputChannels, Range<Integer> bitRates) {
   1131             mMaxInputChannelCount = Range.create(1, mMaxInputChannelCount)
   1132                     .clamp(maxInputChannels);
   1133             if (bitRates != null) {
   1134                 mBitrateRange = mBitrateRange.intersect(bitRates);
   1135             }
   1136         }
   1137 
   1138         private void parseFromInfo(MediaFormat info) {
   1139             int maxInputChannels = MAX_INPUT_CHANNEL_COUNT;
   1140             Range<Integer> bitRates = POSITIVE_INTEGERS;
   1141 
   1142             if (info.containsKey("sample-rate-ranges")) {
   1143                 String[] rateStrings = info.getString("sample-rate-ranges").split(",");
   1144                 Range<Integer>[] rateRanges = new Range[rateStrings.length];
   1145                 for (int i = 0; i < rateStrings.length; i++) {
   1146                     rateRanges[i] = Utils.parseIntRange(rateStrings[i], null);
   1147                 }
   1148                 limitSampleRates(rateRanges);
   1149             }
   1150             if (info.containsKey("max-channel-count")) {
   1151                 maxInputChannels = Utils.parseIntSafely(
   1152                         info.getString("max-channel-count"), maxInputChannels);
   1153             }
   1154             if (info.containsKey("bitrate-range")) {
   1155                 bitRates = bitRates.intersect(
   1156                         Utils.parseIntRange(info.getString("bitrate-range"), bitRates));
   1157             }
   1158             applyLimits(maxInputChannels, bitRates);
   1159         }
   1160 
   1161         /** @hide */
   1162         public void setDefaultFormat(MediaFormat format) {
   1163             // report settings that have only a single choice
   1164             if (mBitrateRange.getLower().equals(mBitrateRange.getUpper())) {
   1165                 format.setInteger(MediaFormat.KEY_BIT_RATE, mBitrateRange.getLower());
   1166             }
   1167             if (mMaxInputChannelCount == 1) {
   1168                 // mono-only format
   1169                 format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
   1170             }
   1171             if (mSampleRates != null && mSampleRates.length == 1) {
   1172                 format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRates[0]);
   1173             }
   1174         }
   1175 
   1176         /** @hide */
   1177         public boolean supportsFormat(MediaFormat format) {
   1178             Map<String, Object> map = format.getMap();
   1179             Integer sampleRate = (Integer)map.get(MediaFormat.KEY_SAMPLE_RATE);
   1180             Integer channels = (Integer)map.get(MediaFormat.KEY_CHANNEL_COUNT);
   1181 
   1182             if (!supports(sampleRate, channels)) {
   1183                 return false;
   1184             }
   1185 
   1186             if (!CodecCapabilities.supportsBitrate(mBitrateRange, format)) {
   1187                 return false;
   1188             }
   1189 
   1190             // nothing to do for:
   1191             // KEY_CHANNEL_MASK: codecs don't get this
   1192             // KEY_IS_ADTS:      required feature for all AAC decoders
   1193             return true;
   1194         }
   1195     }
   1196 
   1197     /**
   1198      * A class that supports querying the video capabilities of a codec.
   1199      */
   1200     public static final class VideoCapabilities {
   1201         private static final String TAG = "VideoCapabilities";
   1202         private CodecCapabilities mParent;
   1203         private Range<Integer> mBitrateRange;
   1204 
   1205         private Range<Integer> mHeightRange;
   1206         private Range<Integer> mWidthRange;
   1207         private Range<Integer> mBlockCountRange;
   1208         private Range<Integer> mHorizontalBlockRange;
   1209         private Range<Integer> mVerticalBlockRange;
   1210         private Range<Rational> mAspectRatioRange;
   1211         private Range<Rational> mBlockAspectRatioRange;
   1212         private Range<Long> mBlocksPerSecondRange;
   1213         private Map<Size, Range<Long>> mMeasuredFrameRates;
   1214         private Range<Integer> mFrameRateRange;
   1215 
   1216         private int mBlockWidth;
   1217         private int mBlockHeight;
   1218         private int mWidthAlignment;
   1219         private int mHeightAlignment;
   1220         private int mSmallerDimensionUpperLimit;
   1221 
   1222         private boolean mAllowMbOverride; // allow XML to override calculated limits
   1223 
   1224         /**
   1225          * Returns the range of supported bitrates in bits/second.
   1226          */
   1227         public Range<Integer> getBitrateRange() {
   1228             return mBitrateRange;
   1229         }
   1230 
   1231         /**
   1232          * Returns the range of supported video widths.
   1233          */
   1234         public Range<Integer> getSupportedWidths() {
   1235             return mWidthRange;
   1236         }
   1237 
   1238         /**
   1239          * Returns the range of supported video heights.
   1240          */
   1241         public Range<Integer> getSupportedHeights() {
   1242             return mHeightRange;
   1243         }
   1244 
   1245         /**
   1246          * Returns the alignment requirement for video width (in pixels).
   1247          *
   1248          * This is a power-of-2 value that video width must be a
   1249          * multiple of.
   1250          */
   1251         public int getWidthAlignment() {
   1252             return mWidthAlignment;
   1253         }
   1254 
   1255         /**
   1256          * Returns the alignment requirement for video height (in pixels).
   1257          *
   1258          * This is a power-of-2 value that video height must be a
   1259          * multiple of.
   1260          */
   1261         public int getHeightAlignment() {
   1262             return mHeightAlignment;
   1263         }
   1264 
   1265         /**
   1266          * Return the upper limit on the smaller dimension of width or height.
   1267          * <p></p>
   1268          * Some codecs have a limit on the smaller dimension, whether it be
   1269          * the width or the height.  E.g. a codec may only be able to handle
   1270          * up to 1920x1080 both in landscape and portrait mode (1080x1920).
   1271          * In this case the maximum width and height are both 1920, but the
   1272          * smaller dimension limit will be 1080. For other codecs, this is
   1273          * {@code Math.min(getSupportedWidths().getUpper(),
   1274          * getSupportedHeights().getUpper())}.
   1275          *
   1276          * @hide
   1277          */
   1278         public int getSmallerDimensionUpperLimit() {
   1279             return mSmallerDimensionUpperLimit;
   1280         }
   1281 
   1282         /**
   1283          * Returns the range of supported frame rates.
   1284          * <p>
   1285          * This is not a performance indicator.  Rather, it expresses the
   1286          * limits specified in the coding standard, based on the complexities
   1287          * of encoding material for later playback at a certain frame rate,
   1288          * or the decoding of such material in non-realtime.
   1289          */
   1290         public Range<Integer> getSupportedFrameRates() {
   1291             return mFrameRateRange;
   1292         }
   1293 
   1294         /**
   1295          * Returns the range of supported video widths for a video height.
   1296          * @param height the height of the video
   1297          */
   1298         public Range<Integer> getSupportedWidthsFor(int height) {
   1299             try {
   1300                 Range<Integer> range = mWidthRange;
   1301                 if (!mHeightRange.contains(height)
   1302                         || (height % mHeightAlignment) != 0) {
   1303                     throw new IllegalArgumentException("unsupported height");
   1304                 }
   1305                 final int heightInBlocks = Utils.divUp(height, mBlockHeight);
   1306 
   1307                 // constrain by block count and by block aspect ratio
   1308                 final int minWidthInBlocks = Math.max(
   1309                         Utils.divUp(mBlockCountRange.getLower(), heightInBlocks),
   1310                         (int)Math.ceil(mBlockAspectRatioRange.getLower().doubleValue()
   1311                                 * heightInBlocks));
   1312                 final int maxWidthInBlocks = Math.min(
   1313                         mBlockCountRange.getUpper() / heightInBlocks,
   1314                         (int)(mBlockAspectRatioRange.getUpper().doubleValue()
   1315                                 * heightInBlocks));
   1316                 range = range.intersect(
   1317                         (minWidthInBlocks - 1) * mBlockWidth + mWidthAlignment,
   1318                         maxWidthInBlocks * mBlockWidth);
   1319 
   1320                 // constrain by smaller dimension limit
   1321                 if (height > mSmallerDimensionUpperLimit) {
   1322                     range = range.intersect(1, mSmallerDimensionUpperLimit);
   1323                 }
   1324 
   1325                 // constrain by aspect ratio
   1326                 range = range.intersect(
   1327                         (int)Math.ceil(mAspectRatioRange.getLower().doubleValue()
   1328                                 * height),
   1329                         (int)(mAspectRatioRange.getUpper().doubleValue() * height));
   1330                 return range;
   1331             } catch (IllegalArgumentException e) {
   1332                 // height is not supported because there are no suitable widths
   1333                 Log.v(TAG, "could not get supported widths for " + height);
   1334                 throw new IllegalArgumentException("unsupported height");
   1335             }
   1336         }
   1337 
   1338         /**
   1339          * Returns the range of supported video heights for a video width
   1340          * @param width the width of the video
   1341          */
   1342         public Range<Integer> getSupportedHeightsFor(int width) {
   1343             try {
   1344                 Range<Integer> range = mHeightRange;
   1345                 if (!mWidthRange.contains(width)
   1346                         || (width % mWidthAlignment) != 0) {
   1347                     throw new IllegalArgumentException("unsupported width");
   1348                 }
   1349                 final int widthInBlocks = Utils.divUp(width, mBlockWidth);
   1350 
   1351                 // constrain by block count and by block aspect ratio
   1352                 final int minHeightInBlocks = Math.max(
   1353                         Utils.divUp(mBlockCountRange.getLower(), widthInBlocks),
   1354                         (int)Math.ceil(widthInBlocks /
   1355                                 mBlockAspectRatioRange.getUpper().doubleValue()));
   1356                 final int maxHeightInBlocks = Math.min(
   1357                         mBlockCountRange.getUpper() / widthInBlocks,
   1358                         (int)(widthInBlocks /
   1359                                 mBlockAspectRatioRange.getLower().doubleValue()));
   1360                 range = range.intersect(
   1361                         (minHeightInBlocks - 1) * mBlockHeight + mHeightAlignment,
   1362                         maxHeightInBlocks * mBlockHeight);
   1363 
   1364                 // constrain by smaller dimension limit
   1365                 if (width > mSmallerDimensionUpperLimit) {
   1366                     range = range.intersect(1, mSmallerDimensionUpperLimit);
   1367                 }
   1368 
   1369                 // constrain by aspect ratio
   1370                 range = range.intersect(
   1371                         (int)Math.ceil(width /
   1372                                 mAspectRatioRange.getUpper().doubleValue()),
   1373                         (int)(width / mAspectRatioRange.getLower().doubleValue()));
   1374                 return range;
   1375             } catch (IllegalArgumentException e) {
   1376                 // width is not supported because there are no suitable heights
   1377                 Log.v(TAG, "could not get supported heights for " + width);
   1378                 throw new IllegalArgumentException("unsupported width");
   1379             }
   1380         }
   1381 
   1382         /**
   1383          * Returns the range of supported video frame rates for a video size.
   1384          * <p>
   1385          * This is not a performance indicator.  Rather, it expresses the limits specified in
   1386          * the coding standard, based on the complexities of encoding material of a given
   1387          * size for later playback at a certain frame rate, or the decoding of such material
   1388          * in non-realtime.
   1389 
   1390          * @param width the width of the video
   1391          * @param height the height of the video
   1392          */
   1393         public Range<Double> getSupportedFrameRatesFor(int width, int height) {
   1394             Range<Integer> range = mHeightRange;
   1395             if (!supports(width, height, null)) {
   1396                 throw new IllegalArgumentException("unsupported size");
   1397             }
   1398             final int blockCount =
   1399                 Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight);
   1400 
   1401             return Range.create(
   1402                     Math.max(mBlocksPerSecondRange.getLower() / (double) blockCount,
   1403                             (double) mFrameRateRange.getLower()),
   1404                     Math.min(mBlocksPerSecondRange.getUpper() / (double) blockCount,
   1405                             (double) mFrameRateRange.getUpper()));
   1406         }
   1407 
   1408         private int getBlockCount(int width, int height) {
   1409             return Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight);
   1410         }
   1411 
   1412         @NonNull
   1413         private Size findClosestSize(int width, int height) {
   1414             int targetBlockCount = getBlockCount(width, height);
   1415             Size closestSize = null;
   1416             int minDiff = Integer.MAX_VALUE;
   1417             for (Size size : mMeasuredFrameRates.keySet()) {
   1418                 int diff = Math.abs(targetBlockCount -
   1419                         getBlockCount(size.getWidth(), size.getHeight()));
   1420                 if (diff < minDiff) {
   1421                     minDiff = diff;
   1422                     closestSize = size;
   1423                 }
   1424             }
   1425             return closestSize;
   1426         }
   1427 
   1428         private Range<Double> estimateFrameRatesFor(int width, int height) {
   1429             Size size = findClosestSize(width, height);
   1430             Range<Long> range = mMeasuredFrameRates.get(size);
   1431             Double ratio = getBlockCount(size.getWidth(), size.getHeight())
   1432                     / (double)Math.max(getBlockCount(width, height), 1);
   1433             return Range.create(range.getLower() * ratio, range.getUpper() * ratio);
   1434         }
   1435 
   1436         /**
   1437          * Returns the range of achievable video frame rates for a video size.
   1438          * May return {@code null}, if the codec did not publish any measurement
   1439          * data.
   1440          * <p>
   1441          * This is a performance estimate provided by the device manufacturer based on statistical
   1442          * sampling of full-speed decoding and encoding measurements in various configurations
   1443          * of common video sizes supported by the codec. As such it should only be used to
   1444          * compare individual codecs on the device. The value is not suitable for comparing
   1445          * different devices or even different android releases for the same device.
   1446          * <p>
   1447          * <em>On {@link android.os.Build.VERSION_CODES#M} release</em> the returned range
   1448          * corresponds to the fastest frame rates achieved in the tested configurations. As
   1449          * such, it should not be used to gauge guaranteed or even average codec performance
   1450          * on the device.
   1451          * <p>
   1452          * <em>On {@link android.os.Build.VERSION_CODES#N} release</em> the returned range
   1453          * corresponds closer to sustained performance <em>in tested configurations</em>.
   1454          * One can expect to achieve sustained performance higher than the lower limit more than
   1455          * 50% of the time, and higher than half of the lower limit at least 90% of the time
   1456          * <em>in tested configurations</em>.
   1457          * Conversely, one can expect performance lower than twice the upper limit at least
   1458          * 90% of the time.
   1459          * <p class=note>
   1460          * Tested configurations use a single active codec. For use cases where multiple
   1461          * codecs are active, applications can expect lower and in most cases significantly lower
   1462          * performance.
   1463          * <p class=note>
   1464          * The returned range value is interpolated from the nearest frame size(s) tested.
   1465          * Codec performance is severely impacted by other activity on the device as well
   1466          * as environmental factors (such as battery level, temperature or power source), and can
   1467          * vary significantly even in a steady environment.
   1468          * <p class=note>
   1469          * Use this method in cases where only codec performance matters, e.g. to evaluate if
   1470          * a codec has any chance of meeting a performance target. Codecs are listed
   1471          * in {@link MediaCodecList} in the preferred order as defined by the device
   1472          * manufacturer. As such, applications should use the first suitable codec in the
   1473          * list to achieve the best balance between power use and performance.
   1474          *
   1475          * @param width the width of the video
   1476          * @param height the height of the video
   1477          *
   1478          * @throws IllegalArgumentException if the video size is not supported.
   1479          */
   1480         @Nullable
   1481         public Range<Double> getAchievableFrameRatesFor(int width, int height) {
   1482             if (!supports(width, height, null)) {
   1483                 throw new IllegalArgumentException("unsupported size");
   1484             }
   1485 
   1486             if (mMeasuredFrameRates == null || mMeasuredFrameRates.size() <= 0) {
   1487                 Log.w(TAG, "Codec did not publish any measurement data.");
   1488                 return null;
   1489             }
   1490 
   1491             return estimateFrameRatesFor(width, height);
   1492         }
   1493 
   1494         /**
   1495          * Returns whether a given video size ({@code width} and
   1496          * {@code height}) and {@code frameRate} combination is supported.
   1497          */
   1498         public boolean areSizeAndRateSupported(
   1499                 int width, int height, double frameRate) {
   1500             return supports(width, height, frameRate);
   1501         }
   1502 
   1503         /**
   1504          * Returns whether a given video size ({@code width} and
   1505          * {@code height}) is supported.
   1506          */
   1507         public boolean isSizeSupported(int width, int height) {
   1508             return supports(width, height, null);
   1509         }
   1510 
   1511         private boolean supports(Integer width, Integer height, Number rate) {
   1512             boolean ok = true;
   1513 
   1514             if (ok && width != null) {
   1515                 ok = mWidthRange.contains(width)
   1516                         && (width % mWidthAlignment == 0);
   1517             }
   1518             if (ok && height != null) {
   1519                 ok = mHeightRange.contains(height)
   1520                         && (height % mHeightAlignment == 0);
   1521             }
   1522             if (ok && rate != null) {
   1523                 ok = mFrameRateRange.contains(Utils.intRangeFor(rate.doubleValue()));
   1524             }
   1525             if (ok && height != null && width != null) {
   1526                 ok = Math.min(height, width) <= mSmallerDimensionUpperLimit;
   1527 
   1528                 final int widthInBlocks = Utils.divUp(width, mBlockWidth);
   1529                 final int heightInBlocks = Utils.divUp(height, mBlockHeight);
   1530                 final int blockCount = widthInBlocks * heightInBlocks;
   1531                 ok = ok && mBlockCountRange.contains(blockCount)
   1532                         && mBlockAspectRatioRange.contains(
   1533                                 new Rational(widthInBlocks, heightInBlocks))
   1534                         && mAspectRatioRange.contains(new Rational(width, height));
   1535                 if (ok && rate != null) {
   1536                     double blocksPerSec = blockCount * rate.doubleValue();
   1537                     ok = mBlocksPerSecondRange.contains(
   1538                             Utils.longRangeFor(blocksPerSec));
   1539                 }
   1540             }
   1541             return ok;
   1542         }
   1543 
   1544         /**
   1545          * @hide
   1546          * @throws java.lang.ClassCastException */
   1547         public boolean supportsFormat(MediaFormat format) {
   1548             final Map<String, Object> map = format.getMap();
   1549             Integer width = (Integer)map.get(MediaFormat.KEY_WIDTH);
   1550             Integer height = (Integer)map.get(MediaFormat.KEY_HEIGHT);
   1551             Number rate = (Number)map.get(MediaFormat.KEY_FRAME_RATE);
   1552 
   1553             if (!supports(width, height, rate)) {
   1554                 return false;
   1555             }
   1556 
   1557             if (!CodecCapabilities.supportsBitrate(mBitrateRange, format)) {
   1558                 return false;
   1559             }
   1560 
   1561             // we ignore color-format for now as it is not reliably reported by codec
   1562             return true;
   1563         }
   1564 
   1565         /* no public constructor */
   1566         private VideoCapabilities() { }
   1567 
   1568         /** @hide */
   1569         public static VideoCapabilities create(
   1570                 MediaFormat info, CodecCapabilities parent) {
   1571             VideoCapabilities caps = new VideoCapabilities();
   1572             caps.init(info, parent);
   1573             return caps;
   1574         }
   1575 
   1576         /** @hide */
   1577         public void init(MediaFormat info, CodecCapabilities parent) {
   1578             mParent = parent;
   1579             initWithPlatformLimits();
   1580             applyLevelLimits();
   1581             parseFromInfo(info);
   1582             updateLimits();
   1583         }
   1584 
   1585         /** @hide */
   1586         public Size getBlockSize() {
   1587             return new Size(mBlockWidth, mBlockHeight);
   1588         }
   1589 
   1590         /** @hide */
   1591         public Range<Integer> getBlockCountRange() {
   1592             return mBlockCountRange;
   1593         }
   1594 
   1595         /** @hide */
   1596         public Range<Long> getBlocksPerSecondRange() {
   1597             return mBlocksPerSecondRange;
   1598         }
   1599 
   1600         /** @hide */
   1601         public Range<Rational> getAspectRatioRange(boolean blocks) {
   1602             return blocks ? mBlockAspectRatioRange : mAspectRatioRange;
   1603         }
   1604 
   1605         private void initWithPlatformLimits() {
   1606             mBitrateRange = BITRATE_RANGE;
   1607 
   1608             mWidthRange  = SIZE_RANGE;
   1609             mHeightRange = SIZE_RANGE;
   1610             mFrameRateRange = FRAME_RATE_RANGE;
   1611 
   1612             mHorizontalBlockRange = SIZE_RANGE;
   1613             mVerticalBlockRange   = SIZE_RANGE;
   1614 
   1615             // full positive ranges are supported as these get calculated
   1616             mBlockCountRange      = POSITIVE_INTEGERS;
   1617             mBlocksPerSecondRange = POSITIVE_LONGS;
   1618 
   1619             mBlockAspectRatioRange = POSITIVE_RATIONALS;
   1620             mAspectRatioRange      = POSITIVE_RATIONALS;
   1621 
   1622             // YUV 4:2:0 requires 2:2 alignment
   1623             mWidthAlignment = 2;
   1624             mHeightAlignment = 2;
   1625             mBlockWidth = 2;
   1626             mBlockHeight = 2;
   1627             mSmallerDimensionUpperLimit = SIZE_RANGE.getUpper();
   1628         }
   1629 
   1630         private Map<Size, Range<Long>> getMeasuredFrameRates(Map<String, Object> map) {
   1631             Map<Size, Range<Long>> ret = new HashMap<Size, Range<Long>>();
   1632             final String prefix = "measured-frame-rate-";
   1633             Set<String> keys = map.keySet();
   1634             for (String key : keys) {
   1635                 // looking for: measured-frame-rate-WIDTHxHEIGHT-range
   1636                 if (!key.startsWith(prefix)) {
   1637                     continue;
   1638                 }
   1639                 String subKey = key.substring(prefix.length());
   1640                 String[] temp = key.split("-");
   1641                 if (temp.length != 5) {
   1642                     continue;
   1643                 }
   1644                 String sizeStr = temp[3];
   1645                 Size size = Utils.parseSize(sizeStr, null);
   1646                 if (size == null || size.getWidth() * size.getHeight() <= 0) {
   1647                     continue;
   1648                 }
   1649                 Range<Long> range = Utils.parseLongRange(map.get(key), null);
   1650                 if (range == null || range.getLower() < 0 || range.getUpper() < 0) {
   1651                     continue;
   1652                 }
   1653                 ret.put(size, range);
   1654             }
   1655             return ret;
   1656         }
   1657 
   1658         private static Pair<Range<Integer>, Range<Integer>> parseWidthHeightRanges(Object o) {
   1659             Pair<Size, Size> range = Utils.parseSizeRange(o);
   1660             if (range != null) {
   1661                 try {
   1662                     return Pair.create(
   1663                             Range.create(range.first.getWidth(), range.second.getWidth()),
   1664                             Range.create(range.first.getHeight(), range.second.getHeight()));
   1665                 } catch (IllegalArgumentException e) {
   1666                     Log.w(TAG, "could not parse size range '" + o + "'");
   1667                 }
   1668             }
   1669             return null;
   1670         }
   1671 
   1672         /** @hide */
   1673         public static int equivalentVP9Level(MediaFormat info) {
   1674             final Map<String, Object> map = info.getMap();
   1675 
   1676             Size blockSize = Utils.parseSize(map.get("block-size"), new Size(8, 8));
   1677             int BS = blockSize.getWidth() * blockSize.getHeight();
   1678 
   1679             Range<Integer> counts = Utils.parseIntRange(map.get("block-count-range"), null);
   1680             int FS = counts == null ? 0 : BS * counts.getUpper();
   1681 
   1682             Range<Long> blockRates =
   1683                 Utils.parseLongRange(map.get("blocks-per-second-range"), null);
   1684             long SR = blockRates == null ? 0 : BS * blockRates.getUpper();
   1685 
   1686             Pair<Range<Integer>, Range<Integer>> dimensionRanges =
   1687                 parseWidthHeightRanges(map.get("size-range"));
   1688             int D = dimensionRanges == null ? 0 : Math.max(
   1689                     dimensionRanges.first.getUpper(), dimensionRanges.second.getUpper());
   1690 
   1691             Range<Integer> bitRates = Utils.parseIntRange(map.get("bitrate-range"), null);
   1692             int BR = bitRates == null ? 0 : Utils.divUp(bitRates.getUpper(), 1000);
   1693 
   1694             if (SR <=      829440 && FS <=    36864 && BR <=    200 && D <=   512)
   1695                 return CodecProfileLevel.VP9Level1;
   1696             if (SR <=     2764800 && FS <=    73728 && BR <=    800 && D <=   768)
   1697                 return CodecProfileLevel.VP9Level11;
   1698             if (SR <=     4608000 && FS <=   122880 && BR <=   1800 && D <=   960)
   1699                 return CodecProfileLevel.VP9Level2;
   1700             if (SR <=     9216000 && FS <=   245760 && BR <=   3600 && D <=  1344)
   1701                 return CodecProfileLevel.VP9Level21;
   1702             if (SR <=    20736000 && FS <=   552960 && BR <=   7200 && D <=  2048)
   1703                 return CodecProfileLevel.VP9Level3;
   1704             if (SR <=    36864000 && FS <=   983040 && BR <=  12000 && D <=  2752)
   1705                 return CodecProfileLevel.VP9Level31;
   1706             if (SR <=    83558400 && FS <=  2228224 && BR <=  18000 && D <=  4160)
   1707                 return CodecProfileLevel.VP9Level4;
   1708             if (SR <=   160432128 && FS <=  2228224 && BR <=  30000 && D <=  4160)
   1709                 return CodecProfileLevel.VP9Level41;
   1710             if (SR <=   311951360 && FS <=  8912896 && BR <=  60000 && D <=  8384)
   1711                 return CodecProfileLevel.VP9Level5;
   1712             if (SR <=   588251136 && FS <=  8912896 && BR <= 120000 && D <=  8384)
   1713                 return CodecProfileLevel.VP9Level51;
   1714             if (SR <=  1176502272 && FS <=  8912896 && BR <= 180000 && D <=  8384)
   1715                 return CodecProfileLevel.VP9Level52;
   1716             if (SR <=  1176502272 && FS <= 35651584 && BR <= 180000 && D <= 16832)
   1717                 return CodecProfileLevel.VP9Level6;
   1718             if (SR <= 2353004544L && FS <= 35651584 && BR <= 240000 && D <= 16832)
   1719                 return CodecProfileLevel.VP9Level61;
   1720             if (SR <= 4706009088L && FS <= 35651584 && BR <= 480000 && D <= 16832)
   1721                 return CodecProfileLevel.VP9Level62;
   1722             // returning largest level
   1723             return CodecProfileLevel.VP9Level62;
   1724         }
   1725 
   1726         private void parseFromInfo(MediaFormat info) {
   1727             final Map<String, Object> map = info.getMap();
   1728             Size blockSize = new Size(mBlockWidth, mBlockHeight);
   1729             Size alignment = new Size(mWidthAlignment, mHeightAlignment);
   1730             Range<Integer> counts = null, widths = null, heights = null;
   1731             Range<Integer> frameRates = null, bitRates = null;
   1732             Range<Long> blockRates = null;
   1733             Range<Rational> ratios = null, blockRatios = null;
   1734 
   1735             blockSize = Utils.parseSize(map.get("block-size"), blockSize);
   1736             alignment = Utils.parseSize(map.get("alignment"), alignment);
   1737             counts = Utils.parseIntRange(map.get("block-count-range"), null);
   1738             blockRates =
   1739                 Utils.parseLongRange(map.get("blocks-per-second-range"), null);
   1740             mMeasuredFrameRates = getMeasuredFrameRates(map);
   1741             Pair<Range<Integer>, Range<Integer>> sizeRanges =
   1742                 parseWidthHeightRanges(map.get("size-range"));
   1743             if (sizeRanges != null) {
   1744                 widths = sizeRanges.first;
   1745                 heights = sizeRanges.second;
   1746             }
   1747             // for now this just means using the smaller max size as 2nd
   1748             // upper limit.
   1749             // for now we are keeping the profile specific "width/height
   1750             // in macroblocks" limits.
   1751             if (map.containsKey("feature-can-swap-width-height")) {
   1752                 if (widths != null) {
   1753                     mSmallerDimensionUpperLimit =
   1754                         Math.min(widths.getUpper(), heights.getUpper());
   1755                     widths = heights = widths.extend(heights);
   1756                 } else {
   1757                     Log.w(TAG, "feature can-swap-width-height is best used with size-range");
   1758                     mSmallerDimensionUpperLimit =
   1759                         Math.min(mWidthRange.getUpper(), mHeightRange.getUpper());
   1760                     mWidthRange = mHeightRange = mWidthRange.extend(mHeightRange);
   1761                 }
   1762             }
   1763 
   1764             ratios = Utils.parseRationalRange(
   1765                     map.get("block-aspect-ratio-range"), null);
   1766             blockRatios = Utils.parseRationalRange(
   1767                     map.get("pixel-aspect-ratio-range"), null);
   1768             frameRates = Utils.parseIntRange(map.get("frame-rate-range"), null);
   1769             if (frameRates != null) {
   1770                 try {
   1771                     frameRates = frameRates.intersect(FRAME_RATE_RANGE);
   1772                 } catch (IllegalArgumentException e) {
   1773                     Log.w(TAG, "frame rate range (" + frameRates
   1774                             + ") is out of limits: " + FRAME_RATE_RANGE);
   1775                     frameRates = null;
   1776                 }
   1777             }
   1778             bitRates = Utils.parseIntRange(map.get("bitrate-range"), null);
   1779             if (bitRates != null) {
   1780                 try {
   1781                     bitRates = bitRates.intersect(BITRATE_RANGE);
   1782                 } catch (IllegalArgumentException e) {
   1783                     Log.w(TAG,  "bitrate range (" + bitRates
   1784                             + ") is out of limits: " + BITRATE_RANGE);
   1785                     bitRates = null;
   1786                 }
   1787             }
   1788 
   1789             checkPowerOfTwo(
   1790                     blockSize.getWidth(), "block-size width must be power of two");
   1791             checkPowerOfTwo(
   1792                     blockSize.getHeight(), "block-size height must be power of two");
   1793 
   1794             checkPowerOfTwo(
   1795                     alignment.getWidth(), "alignment width must be power of two");
   1796             checkPowerOfTwo(
   1797                     alignment.getHeight(), "alignment height must be power of two");
   1798 
   1799             // update block-size and alignment
   1800             applyMacroBlockLimits(
   1801                     Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE,
   1802                     Long.MAX_VALUE, blockSize.getWidth(), blockSize.getHeight(),
   1803                     alignment.getWidth(), alignment.getHeight());
   1804 
   1805             if ((mParent.mError & ERROR_UNSUPPORTED) != 0 || mAllowMbOverride) {
   1806                 // codec supports profiles that we don't know.
   1807                 // Use supplied values clipped to platform limits
   1808                 if (widths != null) {
   1809                     mWidthRange = SIZE_RANGE.intersect(widths);
   1810                 }
   1811                 if (heights != null) {
   1812                     mHeightRange = SIZE_RANGE.intersect(heights);
   1813                 }
   1814                 if (counts != null) {
   1815                     mBlockCountRange = POSITIVE_INTEGERS.intersect(
   1816                             Utils.factorRange(counts, mBlockWidth * mBlockHeight
   1817                                     / blockSize.getWidth() / blockSize.getHeight()));
   1818                 }
   1819                 if (blockRates != null) {
   1820                     mBlocksPerSecondRange = POSITIVE_LONGS.intersect(
   1821                             Utils.factorRange(blockRates, mBlockWidth * mBlockHeight
   1822                                     / blockSize.getWidth() / blockSize.getHeight()));
   1823                 }
   1824                 if (blockRatios != null) {
   1825                     mBlockAspectRatioRange = POSITIVE_RATIONALS.intersect(
   1826                             Utils.scaleRange(blockRatios,
   1827                                     mBlockHeight / blockSize.getHeight(),
   1828                                     mBlockWidth / blockSize.getWidth()));
   1829                 }
   1830                 if (ratios != null) {
   1831                     mAspectRatioRange = POSITIVE_RATIONALS.intersect(ratios);
   1832                 }
   1833                 if (frameRates != null) {
   1834                     mFrameRateRange = FRAME_RATE_RANGE.intersect(frameRates);
   1835                 }
   1836                 if (bitRates != null) {
   1837                     // only allow bitrate override if unsupported profiles were encountered
   1838                     if ((mParent.mError & ERROR_UNSUPPORTED) != 0) {
   1839                         mBitrateRange = BITRATE_RANGE.intersect(bitRates);
   1840                     } else {
   1841                         mBitrateRange = mBitrateRange.intersect(bitRates);
   1842                     }
   1843                 }
   1844             } else {
   1845                 // no unsupported profile/levels, so restrict values to known limits
   1846                 if (widths != null) {
   1847                     mWidthRange = mWidthRange.intersect(widths);
   1848                 }
   1849                 if (heights != null) {
   1850                     mHeightRange = mHeightRange.intersect(heights);
   1851                 }
   1852                 if (counts != null) {
   1853                     mBlockCountRange = mBlockCountRange.intersect(
   1854                             Utils.factorRange(counts, mBlockWidth * mBlockHeight
   1855                                     / blockSize.getWidth() / blockSize.getHeight()));
   1856                 }
   1857                 if (blockRates != null) {
   1858                     mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(
   1859                             Utils.factorRange(blockRates, mBlockWidth * mBlockHeight
   1860                                     / blockSize.getWidth() / blockSize.getHeight()));
   1861                 }
   1862                 if (blockRatios != null) {
   1863                     mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(
   1864                             Utils.scaleRange(blockRatios,
   1865                                     mBlockHeight / blockSize.getHeight(),
   1866                                     mBlockWidth / blockSize.getWidth()));
   1867                 }
   1868                 if (ratios != null) {
   1869                     mAspectRatioRange = mAspectRatioRange.intersect(ratios);
   1870                 }
   1871                 if (frameRates != null) {
   1872                     mFrameRateRange = mFrameRateRange.intersect(frameRates);
   1873                 }
   1874                 if (bitRates != null) {
   1875                     mBitrateRange = mBitrateRange.intersect(bitRates);
   1876                 }
   1877             }
   1878             updateLimits();
   1879         }
   1880 
   1881         private void applyBlockLimits(
   1882                 int blockWidth, int blockHeight,
   1883                 Range<Integer> counts, Range<Long> rates, Range<Rational> ratios) {
   1884             checkPowerOfTwo(blockWidth, "blockWidth must be a power of two");
   1885             checkPowerOfTwo(blockHeight, "blockHeight must be a power of two");
   1886 
   1887             final int newBlockWidth = Math.max(blockWidth, mBlockWidth);
   1888             final int newBlockHeight = Math.max(blockHeight, mBlockHeight);
   1889 
   1890             // factor will always be a power-of-2
   1891             int factor =
   1892                 newBlockWidth * newBlockHeight / mBlockWidth / mBlockHeight;
   1893             if (factor != 1) {
   1894                 mBlockCountRange = Utils.factorRange(mBlockCountRange, factor);
   1895                 mBlocksPerSecondRange = Utils.factorRange(
   1896                         mBlocksPerSecondRange, factor);
   1897                 mBlockAspectRatioRange = Utils.scaleRange(
   1898                         mBlockAspectRatioRange,
   1899                         newBlockHeight / mBlockHeight,
   1900                         newBlockWidth / mBlockWidth);
   1901                 mHorizontalBlockRange = Utils.factorRange(
   1902                         mHorizontalBlockRange, newBlockWidth / mBlockWidth);
   1903                 mVerticalBlockRange = Utils.factorRange(
   1904                         mVerticalBlockRange, newBlockHeight / mBlockHeight);
   1905             }
   1906             factor = newBlockWidth * newBlockHeight / blockWidth / blockHeight;
   1907             if (factor != 1) {
   1908                 counts = Utils.factorRange(counts, factor);
   1909                 rates = Utils.factorRange(rates, factor);
   1910                 ratios = Utils.scaleRange(
   1911                         ratios, newBlockHeight / blockHeight,
   1912                         newBlockWidth / blockWidth);
   1913             }
   1914             mBlockCountRange = mBlockCountRange.intersect(counts);
   1915             mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(rates);
   1916             mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(ratios);
   1917             mBlockWidth = newBlockWidth;
   1918             mBlockHeight = newBlockHeight;
   1919         }
   1920 
   1921         private void applyAlignment(int widthAlignment, int heightAlignment) {
   1922             checkPowerOfTwo(widthAlignment, "widthAlignment must be a power of two");
   1923             checkPowerOfTwo(heightAlignment, "heightAlignment must be a power of two");
   1924 
   1925             if (widthAlignment > mBlockWidth || heightAlignment > mBlockHeight) {
   1926                 // maintain assumption that 0 < alignment <= block-size
   1927                 applyBlockLimits(
   1928                         Math.max(widthAlignment, mBlockWidth),
   1929                         Math.max(heightAlignment, mBlockHeight),
   1930                         POSITIVE_INTEGERS, POSITIVE_LONGS, POSITIVE_RATIONALS);
   1931             }
   1932 
   1933             mWidthAlignment = Math.max(widthAlignment, mWidthAlignment);
   1934             mHeightAlignment = Math.max(heightAlignment, mHeightAlignment);
   1935 
   1936             mWidthRange = Utils.alignRange(mWidthRange, mWidthAlignment);
   1937             mHeightRange = Utils.alignRange(mHeightRange, mHeightAlignment);
   1938         }
   1939 
   1940         private void updateLimits() {
   1941             // pixels -> blocks <- counts
   1942             mHorizontalBlockRange = mHorizontalBlockRange.intersect(
   1943                     Utils.factorRange(mWidthRange, mBlockWidth));
   1944             mHorizontalBlockRange = mHorizontalBlockRange.intersect(
   1945                     Range.create(
   1946                             mBlockCountRange.getLower() / mVerticalBlockRange.getUpper(),
   1947                             mBlockCountRange.getUpper() / mVerticalBlockRange.getLower()));
   1948             mVerticalBlockRange = mVerticalBlockRange.intersect(
   1949                     Utils.factorRange(mHeightRange, mBlockHeight));
   1950             mVerticalBlockRange = mVerticalBlockRange.intersect(
   1951                     Range.create(
   1952                             mBlockCountRange.getLower() / mHorizontalBlockRange.getUpper(),
   1953                             mBlockCountRange.getUpper() / mHorizontalBlockRange.getLower()));
   1954             mBlockCountRange = mBlockCountRange.intersect(
   1955                     Range.create(
   1956                             mHorizontalBlockRange.getLower()
   1957                                     * mVerticalBlockRange.getLower(),
   1958                             mHorizontalBlockRange.getUpper()
   1959                                     * mVerticalBlockRange.getUpper()));
   1960             mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(
   1961                     new Rational(
   1962                             mHorizontalBlockRange.getLower(), mVerticalBlockRange.getUpper()),
   1963                     new Rational(
   1964                             mHorizontalBlockRange.getUpper(), mVerticalBlockRange.getLower()));
   1965 
   1966             // blocks -> pixels
   1967             mWidthRange = mWidthRange.intersect(
   1968                     (mHorizontalBlockRange.getLower() - 1) * mBlockWidth + mWidthAlignment,
   1969                     mHorizontalBlockRange.getUpper() * mBlockWidth);
   1970             mHeightRange = mHeightRange.intersect(
   1971                     (mVerticalBlockRange.getLower() - 1) * mBlockHeight + mHeightAlignment,
   1972                     mVerticalBlockRange.getUpper() * mBlockHeight);
   1973             mAspectRatioRange = mAspectRatioRange.intersect(
   1974                     new Rational(mWidthRange.getLower(), mHeightRange.getUpper()),
   1975                     new Rational(mWidthRange.getUpper(), mHeightRange.getLower()));
   1976 
   1977             mSmallerDimensionUpperLimit = Math.min(
   1978                     mSmallerDimensionUpperLimit,
   1979                     Math.min(mWidthRange.getUpper(), mHeightRange.getUpper()));
   1980 
   1981             // blocks -> rate
   1982             mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(
   1983                     mBlockCountRange.getLower() * (long)mFrameRateRange.getLower(),
   1984                     mBlockCountRange.getUpper() * (long)mFrameRateRange.getUpper());
   1985             mFrameRateRange = mFrameRateRange.intersect(
   1986                     (int)(mBlocksPerSecondRange.getLower()
   1987                             / mBlockCountRange.getUpper()),
   1988                     (int)(mBlocksPerSecondRange.getUpper()
   1989                             / (double)mBlockCountRange.getLower()));
   1990         }
   1991 
   1992         private void applyMacroBlockLimits(
   1993                 int maxHorizontalBlocks, int maxVerticalBlocks,
   1994                 int maxBlocks, long maxBlocksPerSecond,
   1995                 int blockWidth, int blockHeight,
   1996                 int widthAlignment, int heightAlignment) {
   1997             applyMacroBlockLimits(
   1998                     1 /* minHorizontalBlocks */, 1 /* minVerticalBlocks */,
   1999                     maxHorizontalBlocks, maxVerticalBlocks,
   2000                     maxBlocks, maxBlocksPerSecond,
   2001                     blockWidth, blockHeight, widthAlignment, heightAlignment);
   2002         }
   2003 
   2004         private void applyMacroBlockLimits(
   2005                 int minHorizontalBlocks, int minVerticalBlocks,
   2006                 int maxHorizontalBlocks, int maxVerticalBlocks,
   2007                 int maxBlocks, long maxBlocksPerSecond,
   2008                 int blockWidth, int blockHeight,
   2009                 int widthAlignment, int heightAlignment) {
   2010             applyAlignment(widthAlignment, heightAlignment);
   2011             applyBlockLimits(
   2012                     blockWidth, blockHeight, Range.create(1, maxBlocks),
   2013                     Range.create(1L, maxBlocksPerSecond),
   2014                     Range.create(
   2015                             new Rational(1, maxVerticalBlocks),
   2016                             new Rational(maxHorizontalBlocks, 1)));
   2017             mHorizontalBlockRange =
   2018                     mHorizontalBlockRange.intersect(
   2019                             Utils.divUp(minHorizontalBlocks, (mBlockWidth / blockWidth)),
   2020                             maxHorizontalBlocks / (mBlockWidth / blockWidth));
   2021             mVerticalBlockRange =
   2022                     mVerticalBlockRange.intersect(
   2023                             Utils.divUp(minVerticalBlocks, (mBlockHeight / blockHeight)),
   2024                             maxVerticalBlocks / (mBlockHeight / blockHeight));
   2025         }
   2026 
   2027         private void applyLevelLimits() {
   2028             long maxBlocksPerSecond = 0;
   2029             int maxBlocks = 0;
   2030             int maxBps = 0;
   2031             int maxDPBBlocks = 0;
   2032 
   2033             int errors = ERROR_NONE_SUPPORTED;
   2034             CodecProfileLevel[] profileLevels = mParent.profileLevels;
   2035             String mime = mParent.getMimeType();
   2036 
   2037             if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC)) {
   2038                 maxBlocks = 99;
   2039                 maxBlocksPerSecond = 1485;
   2040                 maxBps = 64000;
   2041                 maxDPBBlocks = 396;
   2042                 for (CodecProfileLevel profileLevel: profileLevels) {
   2043                     int MBPS = 0, FS = 0, BR = 0, DPB = 0;
   2044                     boolean supported = true;
   2045                     switch (profileLevel.level) {
   2046                         case CodecProfileLevel.AVCLevel1:
   2047                             MBPS =    1485; FS =    99; BR =     64; DPB =    396; break;
   2048                         case CodecProfileLevel.AVCLevel1b:
   2049                             MBPS =    1485; FS =    99; BR =    128; DPB =    396; break;
   2050                         case CodecProfileLevel.AVCLevel11:
   2051                             MBPS =    3000; FS =   396; BR =    192; DPB =    900; break;
   2052                         case CodecProfileLevel.AVCLevel12:
   2053                             MBPS =    6000; FS =   396; BR =    384; DPB =   2376; break;
   2054                         case CodecProfileLevel.AVCLevel13:
   2055                             MBPS =   11880; FS =   396; BR =    768; DPB =   2376; break;
   2056                         case CodecProfileLevel.AVCLevel2:
   2057                             MBPS =   11880; FS =   396; BR =   2000; DPB =   2376; break;
   2058                         case CodecProfileLevel.AVCLevel21:
   2059                             MBPS =   19800; FS =   792; BR =   4000; DPB =   4752; break;
   2060                         case CodecProfileLevel.AVCLevel22:
   2061                             MBPS =   20250; FS =  1620; BR =   4000; DPB =   8100; break;
   2062                         case CodecProfileLevel.AVCLevel3:
   2063                             MBPS =   40500; FS =  1620; BR =  10000; DPB =   8100; break;
   2064                         case CodecProfileLevel.AVCLevel31:
   2065                             MBPS =  108000; FS =  3600; BR =  14000; DPB =  18000; break;
   2066                         case CodecProfileLevel.AVCLevel32:
   2067                             MBPS =  216000; FS =  5120; BR =  20000; DPB =  20480; break;
   2068                         case CodecProfileLevel.AVCLevel4:
   2069                             MBPS =  245760; FS =  8192; BR =  20000; DPB =  32768; break;
   2070                         case CodecProfileLevel.AVCLevel41:
   2071                             MBPS =  245760; FS =  8192; BR =  50000; DPB =  32768; break;
   2072                         case CodecProfileLevel.AVCLevel42:
   2073                             MBPS =  522240; FS =  8704; BR =  50000; DPB =  34816; break;
   2074                         case CodecProfileLevel.AVCLevel5:
   2075                             MBPS =  589824; FS = 22080; BR = 135000; DPB = 110400; break;
   2076                         case CodecProfileLevel.AVCLevel51:
   2077                             MBPS =  983040; FS = 36864; BR = 240000; DPB = 184320; break;
   2078                         case CodecProfileLevel.AVCLevel52:
   2079                             MBPS = 2073600; FS = 36864; BR = 240000; DPB = 184320; break;
   2080                         default:
   2081                             Log.w(TAG, "Unrecognized level "
   2082                                     + profileLevel.level + " for " + mime);
   2083                             errors |= ERROR_UNRECOGNIZED;
   2084                     }
   2085                     switch (profileLevel.profile) {
   2086                         case CodecProfileLevel.AVCProfileHigh:
   2087                             BR *= 1250; break;
   2088                         case CodecProfileLevel.AVCProfileHigh10:
   2089                             BR *= 3000; break;
   2090                         case CodecProfileLevel.AVCProfileExtended:
   2091                         case CodecProfileLevel.AVCProfileHigh422:
   2092                         case CodecProfileLevel.AVCProfileHigh444:
   2093                             Log.w(TAG, "Unsupported profile "
   2094                                     + profileLevel.profile + " for " + mime);
   2095                             errors |= ERROR_UNSUPPORTED;
   2096                             supported = false;
   2097                             // fall through - treat as base profile
   2098                         case CodecProfileLevel.AVCProfileBaseline:
   2099                         case CodecProfileLevel.AVCProfileMain:
   2100                             BR *= 1000; break;
   2101                         default:
   2102                             Log.w(TAG, "Unrecognized profile "
   2103                                     + profileLevel.profile + " for " + mime);
   2104                             errors |= ERROR_UNRECOGNIZED;
   2105                             BR *= 1000;
   2106                     }
   2107                     if (supported) {
   2108                         errors &= ~ERROR_NONE_SUPPORTED;
   2109                     }
   2110                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
   2111                     maxBlocks = Math.max(FS, maxBlocks);
   2112                     maxBps = Math.max(BR, maxBps);
   2113                     maxDPBBlocks = Math.max(maxDPBBlocks, DPB);
   2114                 }
   2115 
   2116                 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8));
   2117                 applyMacroBlockLimits(
   2118                         maxLengthInBlocks, maxLengthInBlocks,
   2119                         maxBlocks, maxBlocksPerSecond,
   2120                         16 /* blockWidth */, 16 /* blockHeight */,
   2121                         1 /* widthAlignment */, 1 /* heightAlignment */);
   2122             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG2)) {
   2123                 int maxWidth = 11, maxHeight = 9, maxRate = 15;
   2124                 maxBlocks = 99;
   2125                 maxBlocksPerSecond = 1485;
   2126                 maxBps = 64000;
   2127                 for (CodecProfileLevel profileLevel: profileLevels) {
   2128                     int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0;
   2129                     boolean supported = true;
   2130                     switch (profileLevel.profile) {
   2131                         case CodecProfileLevel.MPEG2ProfileSimple:
   2132                             switch (profileLevel.level) {
   2133                                 case CodecProfileLevel.MPEG2LevelML:
   2134                                     FR = 30; W = 45; H =  36; MBPS =  40500; FS =  1620; BR =  15000; break;
   2135                                 default:
   2136                                     Log.w(TAG, "Unrecognized profile/level "
   2137                                             + profileLevel.profile + "/"
   2138                                             + profileLevel.level + " for " + mime);
   2139                                     errors |= ERROR_UNRECOGNIZED;
   2140                             }
   2141                             break;
   2142                         case CodecProfileLevel.MPEG2ProfileMain:
   2143                             switch (profileLevel.level) {
   2144                                 case CodecProfileLevel.MPEG2LevelLL:
   2145                                     FR = 30; W = 22; H =  18; MBPS =  11880; FS =   396; BR =  4000; break;
   2146                                 case CodecProfileLevel.MPEG2LevelML:
   2147                                     FR = 30; W = 45; H =  36; MBPS =  40500; FS =  1620; BR = 15000; break;
   2148                                 case CodecProfileLevel.MPEG2LevelH14:
   2149                                     FR = 60; W = 90; H =  68; MBPS = 183600; FS =  6120; BR = 60000; break;
   2150                                 case CodecProfileLevel.MPEG2LevelHL:
   2151                                     FR = 60; W = 120; H = 68; MBPS = 244800; FS =  8160; BR = 80000; break;
   2152                                 case CodecProfileLevel.MPEG2LevelHP:
   2153                                     FR = 60; W = 120; H = 68; MBPS = 489600; FS =  8160; BR = 80000; break;
   2154                                 default:
   2155                                     Log.w(TAG, "Unrecognized profile/level "
   2156                                             + profileLevel.profile + "/"
   2157                                             + profileLevel.level + " for " + mime);
   2158                                     errors |= ERROR_UNRECOGNIZED;
   2159                             }
   2160                             break;
   2161                         case CodecProfileLevel.MPEG2Profile422:
   2162                         case CodecProfileLevel.MPEG2ProfileSNR:
   2163                         case CodecProfileLevel.MPEG2ProfileSpatial:
   2164                         case CodecProfileLevel.MPEG2ProfileHigh:
   2165                             Log.i(TAG, "Unsupported profile "
   2166                                     + profileLevel.profile + " for " + mime);
   2167                             errors |= ERROR_UNSUPPORTED;
   2168                             supported = false;
   2169                             break;
   2170                         default:
   2171                             Log.w(TAG, "Unrecognized profile "
   2172                                     + profileLevel.profile + " for " + mime);
   2173                             errors |= ERROR_UNRECOGNIZED;
   2174                     }
   2175                     if (supported) {
   2176                         errors &= ~ERROR_NONE_SUPPORTED;
   2177                     }
   2178                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
   2179                     maxBlocks = Math.max(FS, maxBlocks);
   2180                     maxBps = Math.max(BR * 1000, maxBps);
   2181                     maxWidth = Math.max(W, maxWidth);
   2182                     maxHeight = Math.max(H, maxHeight);
   2183                     maxRate = Math.max(FR, maxRate);
   2184                 }
   2185                 applyMacroBlockLimits(maxWidth, maxHeight,
   2186                         maxBlocks, maxBlocksPerSecond,
   2187                         16 /* blockWidth */, 16 /* blockHeight */,
   2188                         1 /* widthAlignment */, 1 /* heightAlignment */);
   2189                 mFrameRateRange = mFrameRateRange.intersect(12, maxRate);
   2190             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) {
   2191                 int maxWidth = 11, maxHeight = 9, maxRate = 15;
   2192                 maxBlocks = 99;
   2193                 maxBlocksPerSecond = 1485;
   2194                 maxBps = 64000;
   2195                 for (CodecProfileLevel profileLevel: profileLevels) {
   2196                     int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0;
   2197                     boolean strict = false; // true: W, H and FR are individual max limits
   2198                     boolean supported = true;
   2199                     switch (profileLevel.profile) {
   2200                         case CodecProfileLevel.MPEG4ProfileSimple:
   2201                             switch (profileLevel.level) {
   2202                                 case CodecProfileLevel.MPEG4Level0:
   2203                                     strict = true;
   2204                                     FR = 15; W = 11; H =  9; MBPS =  1485; FS =  99; BR =  64; break;
   2205                                 case CodecProfileLevel.MPEG4Level1:
   2206                                     FR = 30; W = 11; H =  9; MBPS =  1485; FS =  99; BR =  64; break;
   2207                                 case CodecProfileLevel.MPEG4Level0b:
   2208                                     strict = true;
   2209                                     FR = 15; W = 11; H =  9; MBPS =  1485; FS =  99; BR = 128; break;
   2210                                 case CodecProfileLevel.MPEG4Level2:
   2211                                     FR = 30; W = 22; H = 18; MBPS =  5940; FS = 396; BR = 128; break;
   2212                                 case CodecProfileLevel.MPEG4Level3:
   2213                                     FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384; break;
   2214                                 case CodecProfileLevel.MPEG4Level4a:
   2215                                     FR = 30; W = 40; H = 30; MBPS = 36000; FS = 1200; BR = 4000; break;
   2216                                 case CodecProfileLevel.MPEG4Level5:
   2217                                     FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 8000; break;
   2218                                 case CodecProfileLevel.MPEG4Level6:
   2219                                     FR = 30; W = 80; H = 45; MBPS = 108000; FS = 3600; BR = 12000; break;
   2220                                 default:
   2221                                     Log.w(TAG, "Unrecognized profile/level "
   2222                                             + profileLevel.profile + "/"
   2223                                             + profileLevel.level + " for " + mime);
   2224                                     errors |= ERROR_UNRECOGNIZED;
   2225                             }
   2226                             break;
   2227                         case CodecProfileLevel.MPEG4ProfileAdvancedSimple:
   2228                             switch (profileLevel.level) {
   2229                                 case CodecProfileLevel.MPEG4Level0:
   2230                                 case CodecProfileLevel.MPEG4Level1:
   2231                                     FR = 30; W = 11; H =  9; MBPS =  2970; FS =   99; BR =  128; break;
   2232                                 case CodecProfileLevel.MPEG4Level2:
   2233                                     FR = 30; W = 22; H = 18; MBPS =  5940; FS =  396; BR =  384; break;
   2234                                 case CodecProfileLevel.MPEG4Level3:
   2235                                     FR = 30; W = 22; H = 18; MBPS = 11880; FS =  396; BR =  768; break;
   2236                                 case CodecProfileLevel.MPEG4Level3b:
   2237                                     FR = 30; W = 22; H = 18; MBPS = 11880; FS =  396; BR = 1500; break;
   2238                                 case CodecProfileLevel.MPEG4Level4:
   2239                                     FR = 30; W = 44; H = 36; MBPS = 23760; FS =  792; BR = 3000; break;
   2240                                 case CodecProfileLevel.MPEG4Level5:
   2241                                     FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 8000; break;
   2242                                 default:
   2243                                     Log.w(TAG, "Unrecognized profile/level "
   2244                                             + profileLevel.profile + "/"
   2245                                             + profileLevel.level + " for " + mime);
   2246                                     errors |= ERROR_UNRECOGNIZED;
   2247                             }
   2248                             break;
   2249                         case CodecProfileLevel.MPEG4ProfileMain:             // 2-4
   2250                         case CodecProfileLevel.MPEG4ProfileNbit:             // 2
   2251                         case CodecProfileLevel.MPEG4ProfileAdvancedRealTime: // 1-4
   2252                         case CodecProfileLevel.MPEG4ProfileCoreScalable:     // 1-3
   2253                         case CodecProfileLevel.MPEG4ProfileAdvancedCoding:   // 1-4
   2254                         case CodecProfileLevel.MPEG4ProfileCore:             // 1-2
   2255                         case CodecProfileLevel.MPEG4ProfileAdvancedCore:     // 1-4
   2256                         case CodecProfileLevel.MPEG4ProfileSimpleScalable:   // 0-2
   2257                         case CodecProfileLevel.MPEG4ProfileHybrid:           // 1-2
   2258 
   2259                         // Studio profiles are not supported by our codecs.
   2260 
   2261                         // Only profiles that can decode simple object types are considered.
   2262                         // The following profiles are not able to.
   2263                         case CodecProfileLevel.MPEG4ProfileBasicAnimated:    // 1-2
   2264                         case CodecProfileLevel.MPEG4ProfileScalableTexture:  // 1
   2265                         case CodecProfileLevel.MPEG4ProfileSimpleFace:       // 1-2
   2266                         case CodecProfileLevel.MPEG4ProfileAdvancedScalable: // 1-3
   2267                         case CodecProfileLevel.MPEG4ProfileSimpleFBA:        // 1-2
   2268                             Log.i(TAG, "Unsupported profile "
   2269                                     + profileLevel.profile + " for " + mime);
   2270                             errors |= ERROR_UNSUPPORTED;
   2271                             supported = false;
   2272                             break;
   2273                         default:
   2274                             Log.w(TAG, "Unrecognized profile "
   2275                                     + profileLevel.profile + " for " + mime);
   2276                             errors |= ERROR_UNRECOGNIZED;
   2277                     }
   2278                     if (supported) {
   2279                         errors &= ~ERROR_NONE_SUPPORTED;
   2280                     }
   2281                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
   2282                     maxBlocks = Math.max(FS, maxBlocks);
   2283                     maxBps = Math.max(BR * 1000, maxBps);
   2284                     if (strict) {
   2285                         maxWidth = Math.max(W, maxWidth);
   2286                         maxHeight = Math.max(H, maxHeight);
   2287                         maxRate = Math.max(FR, maxRate);
   2288                     } else {
   2289                         // assuming max 60 fps frame rate and 1:2 aspect ratio
   2290                         int maxDim = (int)Math.sqrt(FS * 2);
   2291                         maxWidth = Math.max(maxDim, maxWidth);
   2292                         maxHeight = Math.max(maxDim, maxHeight);
   2293                         maxRate = Math.max(Math.max(FR, 60), maxRate);
   2294                     }
   2295                 }
   2296                 applyMacroBlockLimits(maxWidth, maxHeight,
   2297                         maxBlocks, maxBlocksPerSecond,
   2298                         16 /* blockWidth */, 16 /* blockHeight */,
   2299                         1 /* widthAlignment */, 1 /* heightAlignment */);
   2300                 mFrameRateRange = mFrameRateRange.intersect(12, maxRate);
   2301             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) {
   2302                 int maxWidth = 11, maxHeight = 9, maxRate = 15;
   2303                 int minWidth = maxWidth, minHeight = maxHeight;
   2304                 int minAlignment = 16;
   2305                 maxBlocks = 99;
   2306                 maxBlocksPerSecond = 1485;
   2307                 maxBps = 64000;
   2308                 for (CodecProfileLevel profileLevel: profileLevels) {
   2309                     int MBPS = 0, BR = 0, FR = 0, W = 0, H = 0, minW = minWidth, minH = minHeight;
   2310                     boolean strict = false; // true: support only sQCIF, QCIF (maybe CIF)
   2311                     switch (profileLevel.level) {
   2312                         case CodecProfileLevel.H263Level10:
   2313                             strict = true; // only supports sQCIF & QCIF
   2314                             FR = 15; W = 11; H =  9; BR =   1; MBPS =  W * H * FR; break;
   2315                         case CodecProfileLevel.H263Level20:
   2316                             strict = true; // only supports sQCIF, QCIF & CIF
   2317                             FR = 30; W = 22; H = 18; BR =   2; MBPS =  W * H * 15; break;
   2318                         case CodecProfileLevel.H263Level30:
   2319                             strict = true; // only supports sQCIF, QCIF & CIF
   2320                             FR = 30; W = 22; H = 18; BR =   6; MBPS =  W * H * FR; break;
   2321                         case CodecProfileLevel.H263Level40:
   2322                             strict = true; // only supports sQCIF, QCIF & CIF
   2323                             FR = 30; W = 22; H = 18; BR =  32; MBPS =  W * H * FR; break;
   2324                         case CodecProfileLevel.H263Level45:
   2325                             // only implies level 10 support
   2326                             strict = profileLevel.profile == CodecProfileLevel.H263ProfileBaseline
   2327                                     || profileLevel.profile ==
   2328                                             CodecProfileLevel.H263ProfileBackwardCompatible;
   2329                             if (!strict) {
   2330                                 minW = 1; minH = 1; minAlignment = 4;
   2331                             }
   2332                             FR = 15; W = 11; H =  9; BR =   2; MBPS =  W * H * FR; break;
   2333                         case CodecProfileLevel.H263Level50:
   2334                             // only supports 50fps for H > 15
   2335                             minW = 1; minH = 1; minAlignment = 4;
   2336                             FR = 60; W = 22; H = 18; BR =  64; MBPS =  W * H * 50; break;
   2337                         case CodecProfileLevel.H263Level60:
   2338                             // only supports 50fps for H > 15
   2339                             minW = 1; minH = 1; minAlignment = 4;
   2340                             FR = 60; W = 45; H = 18; BR = 128; MBPS =  W * H * 50; break;
   2341                         case CodecProfileLevel.H263Level70:
   2342                             // only supports 50fps for H > 30
   2343                             minW = 1; minH = 1; minAlignment = 4;
   2344                             FR = 60; W = 45; H = 36; BR = 256; MBPS =  W * H * 50; break;
   2345                         default:
   2346                             Log.w(TAG, "Unrecognized profile/level " + profileLevel.profile
   2347                                     + "/" + profileLevel.level + " for " + mime);
   2348                             errors |= ERROR_UNRECOGNIZED;
   2349                     }
   2350                     switch (profileLevel.profile) {
   2351                         case CodecProfileLevel.H263ProfileBackwardCompatible:
   2352                         case CodecProfileLevel.H263ProfileBaseline:
   2353                         case CodecProfileLevel.H263ProfileH320Coding:
   2354                         case CodecProfileLevel.H263ProfileHighCompression:
   2355                         case CodecProfileLevel.H263ProfileHighLatency:
   2356                         case CodecProfileLevel.H263ProfileInterlace:
   2357                         case CodecProfileLevel.H263ProfileInternet:
   2358                         case CodecProfileLevel.H263ProfileISWV2:
   2359                         case CodecProfileLevel.H263ProfileISWV3:
   2360                             break;
   2361                         default:
   2362                             Log.w(TAG, "Unrecognized profile "
   2363                                     + profileLevel.profile + " for " + mime);
   2364                             errors |= ERROR_UNRECOGNIZED;
   2365                     }
   2366                     if (strict) {
   2367                         // Strict levels define sub-QCIF min size and enumerated sizes. We cannot
   2368                         // express support for "only sQCIF & QCIF (& CIF)" using VideoCapabilities
   2369                         // but we can express "only QCIF (& CIF)", so set minimume size at QCIF.
   2370                         // minW = 8; minH = 6;
   2371                         minW = 11; minH = 9;
   2372                     } else {
   2373                         // any support for non-strict levels (including unrecognized profiles or
   2374                         // levels) allow custom frame size support beyond supported limits
   2375                         // (other than bitrate)
   2376                         mAllowMbOverride = true;
   2377                     }
   2378                     errors &= ~ERROR_NONE_SUPPORTED;
   2379                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
   2380                     maxBlocks = Math.max(W * H, maxBlocks);
   2381                     maxBps = Math.max(BR * 64000, maxBps);
   2382                     maxWidth = Math.max(W, maxWidth);
   2383                     maxHeight = Math.max(H, maxHeight);
   2384                     maxRate = Math.max(FR, maxRate);
   2385                     minWidth = Math.min(minW, minWidth);
   2386                     minHeight = Math.min(minH, minHeight);
   2387                 }
   2388                 // unless we encountered custom frame size support, limit size to QCIF and CIF
   2389                 // using aspect ratio.
   2390                 if (!mAllowMbOverride) {
   2391                     mBlockAspectRatioRange =
   2392                         Range.create(new Rational(11, 9), new Rational(11, 9));
   2393                 }
   2394                 applyMacroBlockLimits(
   2395                         minWidth, minHeight,
   2396                         maxWidth, maxHeight,
   2397                         maxBlocks, maxBlocksPerSecond,
   2398                         16 /* blockWidth */, 16 /* blockHeight */,
   2399                         minAlignment /* widthAlignment */, minAlignment /* heightAlignment */);
   2400                 mFrameRateRange = Range.create(1, maxRate);
   2401             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8)) {
   2402                 maxBlocks = Integer.MAX_VALUE;
   2403                 maxBlocksPerSecond = Integer.MAX_VALUE;
   2404 
   2405                 // TODO: set to 100Mbps for now, need a number for VP8
   2406                 maxBps = 100000000;
   2407 
   2408                 // profile levels are not indicative for VPx, but verify
   2409                 // them nonetheless
   2410                 for (CodecProfileLevel profileLevel: profileLevels) {
   2411                     switch (profileLevel.level) {
   2412                         case CodecProfileLevel.VP8Level_Version0:
   2413                         case CodecProfileLevel.VP8Level_Version1:
   2414                         case CodecProfileLevel.VP8Level_Version2:
   2415                         case CodecProfileLevel.VP8Level_Version3:
   2416                             break;
   2417                         default:
   2418                             Log.w(TAG, "Unrecognized level "
   2419                                     + profileLevel.level + " for " + mime);
   2420                             errors |= ERROR_UNRECOGNIZED;
   2421                     }
   2422                     switch (profileLevel.profile) {
   2423                         case CodecProfileLevel.VP8ProfileMain:
   2424                             break;
   2425                         default:
   2426                             Log.w(TAG, "Unrecognized profile "
   2427                                     + profileLevel.profile + " for " + mime);
   2428                             errors |= ERROR_UNRECOGNIZED;
   2429                     }
   2430                     errors &= ~ERROR_NONE_SUPPORTED;
   2431                 }
   2432 
   2433                 final int blockSize = 16;
   2434                 applyMacroBlockLimits(Short.MAX_VALUE, Short.MAX_VALUE,
   2435                         maxBlocks, maxBlocksPerSecond, blockSize, blockSize,
   2436                         1 /* widthAlignment */, 1 /* heightAlignment */);
   2437             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) {
   2438                 maxBlocksPerSecond = 829440;
   2439                 maxBlocks = 36864;
   2440                 maxBps = 200000;
   2441                 int maxDim = 512;
   2442 
   2443                 for (CodecProfileLevel profileLevel: profileLevels) {
   2444                     long SR = 0; // luma sample rate
   2445                     int FS = 0;  // luma picture size
   2446                     int BR = 0;  // bit rate kbps
   2447                     int D = 0;   // luma dimension
   2448                     switch (profileLevel.level) {
   2449                         case CodecProfileLevel.VP9Level1:
   2450                             SR =      829440; FS =    36864; BR =    200; D =   512; break;
   2451                         case CodecProfileLevel.VP9Level11:
   2452                             SR =     2764800; FS =    73728; BR =    800; D =   768; break;
   2453                         case CodecProfileLevel.VP9Level2:
   2454                             SR =     4608000; FS =   122880; BR =   1800; D =   960; break;
   2455                         case CodecProfileLevel.VP9Level21:
   2456                             SR =     9216000; FS =   245760; BR =   3600; D =  1344; break;
   2457                         case CodecProfileLevel.VP9Level3:
   2458                             SR =    20736000; FS =   552960; BR =   7200; D =  2048; break;
   2459                         case CodecProfileLevel.VP9Level31:
   2460                             SR =    36864000; FS =   983040; BR =  12000; D =  2752; break;
   2461                         case CodecProfileLevel.VP9Level4:
   2462                             SR =    83558400; FS =  2228224; BR =  18000; D =  4160; break;
   2463                         case CodecProfileLevel.VP9Level41:
   2464                             SR =   160432128; FS =  2228224; BR =  30000; D =  4160; break;
   2465                         case CodecProfileLevel.VP9Level5:
   2466                             SR =   311951360; FS =  8912896; BR =  60000; D =  8384; break;
   2467                         case CodecProfileLevel.VP9Level51:
   2468                             SR =   588251136; FS =  8912896; BR = 120000; D =  8384; break;
   2469                         case CodecProfileLevel.VP9Level52:
   2470                             SR =  1176502272; FS =  8912896; BR = 180000; D =  8384; break;
   2471                         case CodecProfileLevel.VP9Level6:
   2472                             SR =  1176502272; FS = 35651584; BR = 180000; D = 16832; break;
   2473                         case CodecProfileLevel.VP9Level61:
   2474                             SR = 2353004544L; FS = 35651584; BR = 240000; D = 16832; break;
   2475                         case CodecProfileLevel.VP9Level62:
   2476                             SR = 4706009088L; FS = 35651584; BR = 480000; D = 16832; break;
   2477                         default:
   2478                             Log.w(TAG, "Unrecognized level "
   2479                                     + profileLevel.level + " for " + mime);
   2480                             errors |= ERROR_UNRECOGNIZED;
   2481                     }
   2482                     switch (profileLevel.profile) {
   2483                         case CodecProfileLevel.VP9Profile0:
   2484                         case CodecProfileLevel.VP9Profile1:
   2485                         case CodecProfileLevel.VP9Profile2:
   2486                         case CodecProfileLevel.VP9Profile3:
   2487                         case CodecProfileLevel.VP9Profile2HDR:
   2488                         case CodecProfileLevel.VP9Profile3HDR:
   2489                             break;
   2490                         default:
   2491                             Log.w(TAG, "Unrecognized profile "
   2492                                     + profileLevel.profile + " for " + mime);
   2493                             errors |= ERROR_UNRECOGNIZED;
   2494                     }
   2495                     errors &= ~ERROR_NONE_SUPPORTED;
   2496                     maxBlocksPerSecond = Math.max(SR, maxBlocksPerSecond);
   2497                     maxBlocks = Math.max(FS, maxBlocks);
   2498                     maxBps = Math.max(BR * 1000, maxBps);
   2499                     maxDim = Math.max(D, maxDim);
   2500                 }
   2501 
   2502                 final int blockSize = 8;
   2503                 int maxLengthInBlocks = Utils.divUp(maxDim, blockSize);
   2504                 maxBlocks = Utils.divUp(maxBlocks, blockSize * blockSize);
   2505                 maxBlocksPerSecond = Utils.divUp(maxBlocksPerSecond, blockSize * blockSize);
   2506 
   2507                 applyMacroBlockLimits(
   2508                         maxLengthInBlocks, maxLengthInBlocks,
   2509                         maxBlocks, maxBlocksPerSecond,
   2510                         blockSize, blockSize,
   2511                         1 /* widthAlignment */, 1 /* heightAlignment */);
   2512             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
   2513                 // CTBs are at least 8x8 so use 8x8 block size
   2514                 maxBlocks = 36864 >> 6; // 192x192 pixels == 576 8x8 blocks
   2515                 maxBlocksPerSecond = maxBlocks * 15;
   2516                 maxBps = 128000;
   2517                 for (CodecProfileLevel profileLevel: profileLevels) {
   2518                     double FR = 0;
   2519                     int FS = 0;
   2520                     int BR = 0;
   2521                     switch (profileLevel.level) {
   2522                         /* The HEVC spec talks only in a very convoluted manner about the
   2523                            existence of levels 1-3.1 for High tier, which could also be
   2524                            understood as 'decoders and encoders should treat these levels
   2525                            as if they were Main tier', so we do that. */
   2526                         case CodecProfileLevel.HEVCMainTierLevel1:
   2527                         case CodecProfileLevel.HEVCHighTierLevel1:
   2528                             FR =    15; FS =    36864; BR =    128; break;
   2529                         case CodecProfileLevel.HEVCMainTierLevel2:
   2530                         case CodecProfileLevel.HEVCHighTierLevel2:
   2531                             FR =    30; FS =   122880; BR =   1500; break;
   2532                         case CodecProfileLevel.HEVCMainTierLevel21:
   2533                         case CodecProfileLevel.HEVCHighTierLevel21:
   2534                             FR =    30; FS =   245760; BR =   3000; break;
   2535                         case CodecProfileLevel.HEVCMainTierLevel3:
   2536                         case CodecProfileLevel.HEVCHighTierLevel3:
   2537                             FR =    30; FS =   552960; BR =   6000; break;
   2538                         case CodecProfileLevel.HEVCMainTierLevel31:
   2539                         case CodecProfileLevel.HEVCHighTierLevel31:
   2540                             FR = 33.75; FS =   983040; BR =  10000; break;
   2541                         case CodecProfileLevel.HEVCMainTierLevel4:
   2542                             FR =    30; FS =  2228224; BR =  12000; break;
   2543                         case CodecProfileLevel.HEVCHighTierLevel4:
   2544                             FR =    30; FS =  2228224; BR =  30000; break;
   2545                         case CodecProfileLevel.HEVCMainTierLevel41:
   2546                             FR =    60; FS =  2228224; BR =  20000; break;
   2547                         case CodecProfileLevel.HEVCHighTierLevel41:
   2548                             FR =    60; FS =  2228224; BR =  50000; break;
   2549                         case CodecProfileLevel.HEVCMainTierLevel5:
   2550                             FR =    30; FS =  8912896; BR =  25000; break;
   2551                         case CodecProfileLevel.HEVCHighTierLevel5:
   2552                             FR =    30; FS =  8912896; BR = 100000; break;
   2553                         case CodecProfileLevel.HEVCMainTierLevel51:
   2554                             FR =    60; FS =  8912896; BR =  40000; break;
   2555                         case CodecProfileLevel.HEVCHighTierLevel51:
   2556                             FR =    60; FS =  8912896; BR = 160000; break;
   2557                         case CodecProfileLevel.HEVCMainTierLevel52:
   2558                             FR =   120; FS =  8912896; BR =  60000; break;
   2559                         case CodecProfileLevel.HEVCHighTierLevel52:
   2560                             FR =   120; FS =  8912896; BR = 240000; break;
   2561                         case CodecProfileLevel.HEVCMainTierLevel6:
   2562                             FR =    30; FS = 35651584; BR =  60000; break;
   2563                         case CodecProfileLevel.HEVCHighTierLevel6:
   2564                             FR =    30; FS = 35651584; BR = 240000; break;
   2565                         case CodecProfileLevel.HEVCMainTierLevel61:
   2566                             FR =    60; FS = 35651584; BR = 120000; break;
   2567                         case CodecProfileLevel.HEVCHighTierLevel61:
   2568                             FR =    60; FS = 35651584; BR = 480000; break;
   2569                         case CodecProfileLevel.HEVCMainTierLevel62:
   2570                             FR =   120; FS = 35651584; BR = 240000; break;
   2571                         case CodecProfileLevel.HEVCHighTierLevel62:
   2572                             FR =   120; FS = 35651584; BR = 800000; break;
   2573                         default:
   2574                             Log.w(TAG, "Unrecognized level "
   2575                                     + profileLevel.level + " for " + mime);
   2576                             errors |= ERROR_UNRECOGNIZED;
   2577                     }
   2578                     switch (profileLevel.profile) {
   2579                         case CodecProfileLevel.HEVCProfileMain:
   2580                         case CodecProfileLevel.HEVCProfileMain10:
   2581                         case CodecProfileLevel.HEVCProfileMain10HDR10:
   2582                             break;
   2583                         default:
   2584                             Log.w(TAG, "Unrecognized profile "
   2585                                     + profileLevel.profile + " for " + mime);
   2586                             errors |= ERROR_UNRECOGNIZED;
   2587                     }
   2588 
   2589                     /* DPB logic:
   2590                     if      (width * height <= FS / 4)    DPB = 16;
   2591                     else if (width * height <= FS / 2)    DPB = 12;
   2592                     else if (width * height <= FS * 0.75) DPB = 8;
   2593                     else                                  DPB = 6;
   2594                     */
   2595 
   2596                     FS >>= 6; // convert pixels to blocks
   2597                     errors &= ~ERROR_NONE_SUPPORTED;
   2598                     maxBlocksPerSecond = Math.max((int)(FR * FS), maxBlocksPerSecond);
   2599                     maxBlocks = Math.max(FS, maxBlocks);
   2600                     maxBps = Math.max(BR * 1000, maxBps);
   2601                 }
   2602 
   2603                 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8));
   2604                 applyMacroBlockLimits(
   2605                         maxLengthInBlocks, maxLengthInBlocks,
   2606                         maxBlocks, maxBlocksPerSecond,
   2607                         8 /* blockWidth */, 8 /* blockHeight */,
   2608                         1 /* widthAlignment */, 1 /* heightAlignment */);
   2609             } else {
   2610                 Log.w(TAG, "Unsupported mime " + mime);
   2611                 // using minimal bitrate here.  should be overriden by
   2612                 // info from media_codecs.xml
   2613                 maxBps = 64000;
   2614                 errors |= ERROR_UNSUPPORTED;
   2615             }
   2616             mBitrateRange = Range.create(1, maxBps);
   2617             mParent.mError |= errors;
   2618         }
   2619     }
   2620 
   2621     /**
   2622      * A class that supports querying the encoding capabilities of a codec.
   2623      */
   2624     public static final class EncoderCapabilities {
   2625         /**
   2626          * Returns the supported range of quality values.
   2627          *
   2628          * @hide
   2629          */
   2630         public Range<Integer> getQualityRange() {
   2631             return mQualityRange;
   2632         }
   2633 
   2634         /**
   2635          * Returns the supported range of encoder complexity values.
   2636          * <p>
   2637          * Some codecs may support multiple complexity levels, where higher
   2638          * complexity values use more encoder tools (e.g. perform more
   2639          * intensive calculations) to improve the quality or the compression
   2640          * ratio.  Use a lower value to save power and/or time.
   2641          */
   2642         public Range<Integer> getComplexityRange() {
   2643             return mComplexityRange;
   2644         }
   2645 
   2646         /** Constant quality mode */
   2647         public static final int BITRATE_MODE_CQ = 0;
   2648         /** Variable bitrate mode */
   2649         public static final int BITRATE_MODE_VBR = 1;
   2650         /** Constant bitrate mode */
   2651         public static final int BITRATE_MODE_CBR = 2;
   2652 
   2653         private static final Feature[] bitrates = new Feature[] {
   2654             new Feature("VBR", BITRATE_MODE_VBR, true),
   2655             new Feature("CBR", BITRATE_MODE_CBR, false),
   2656             new Feature("CQ",  BITRATE_MODE_CQ,  false)
   2657         };
   2658 
   2659         private static int parseBitrateMode(String mode) {
   2660             for (Feature feat: bitrates) {
   2661                 if (feat.mName.equalsIgnoreCase(mode)) {
   2662                     return feat.mValue;
   2663                 }
   2664             }
   2665             return 0;
   2666         }
   2667 
   2668         /**
   2669          * Query whether a bitrate mode is supported.
   2670          */
   2671         public boolean isBitrateModeSupported(int mode) {
   2672             for (Feature feat: bitrates) {
   2673                 if (mode == feat.mValue) {
   2674                     return (mBitControl & (1 << mode)) != 0;
   2675                 }
   2676             }
   2677             return false;
   2678         }
   2679 
   2680         private Range<Integer> mQualityRange;
   2681         private Range<Integer> mComplexityRange;
   2682         private CodecCapabilities mParent;
   2683 
   2684         /* no public constructor */
   2685         private EncoderCapabilities() { }
   2686 
   2687         /** @hide */
   2688         public static EncoderCapabilities create(
   2689                 MediaFormat info, CodecCapabilities parent) {
   2690             EncoderCapabilities caps = new EncoderCapabilities();
   2691             caps.init(info, parent);
   2692             return caps;
   2693         }
   2694 
   2695         /** @hide */
   2696         public void init(MediaFormat info, CodecCapabilities parent) {
   2697             // no support for complexity or quality yet
   2698             mParent = parent;
   2699             mComplexityRange = Range.create(0, 0);
   2700             mQualityRange = Range.create(0, 0);
   2701             mBitControl = (1 << BITRATE_MODE_VBR);
   2702 
   2703             applyLevelLimits();
   2704             parseFromInfo(info);
   2705         }
   2706 
   2707         private void applyLevelLimits() {
   2708             String mime = mParent.getMimeType();
   2709             if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
   2710                 mComplexityRange = Range.create(0, 8);
   2711                 mBitControl = (1 << BITRATE_MODE_CQ);
   2712             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)
   2713                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)
   2714                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW)
   2715                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)
   2716                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) {
   2717                 mBitControl = (1 << BITRATE_MODE_CBR);
   2718             }
   2719         }
   2720 
   2721         private int mBitControl;
   2722         private Integer mDefaultComplexity;
   2723         private Integer mDefaultQuality;
   2724         private String mQualityScale;
   2725 
   2726         private void parseFromInfo(MediaFormat info) {
   2727             Map<String, Object> map = info.getMap();
   2728 
   2729             if (info.containsKey("complexity-range")) {
   2730                 mComplexityRange = Utils
   2731                         .parseIntRange(info.getString("complexity-range"), mComplexityRange);
   2732                 // TODO should we limit this to level limits?
   2733             }
   2734             if (info.containsKey("quality-range")) {
   2735                 mQualityRange = Utils
   2736                         .parseIntRange(info.getString("quality-range"), mQualityRange);
   2737             }
   2738             if (info.containsKey("feature-bitrate-control")) {
   2739                 for (String mode: info.getString("feature-bitrate-control").split(",")) {
   2740                     mBitControl |= parseBitrateMode(mode);
   2741                 }
   2742             }
   2743 
   2744             try {
   2745                 mDefaultComplexity = Integer.parseInt((String)map.get("complexity-default"));
   2746             } catch (NumberFormatException e) { }
   2747 
   2748             try {
   2749                 mDefaultQuality = Integer.parseInt((String)map.get("quality-default"));
   2750             } catch (NumberFormatException e) { }
   2751 
   2752             mQualityScale = (String)map.get("quality-scale");
   2753         }
   2754 
   2755         private boolean supports(
   2756                 Integer complexity, Integer quality, Integer profile) {
   2757             boolean ok = true;
   2758             if (ok && complexity != null) {
   2759                 ok = mComplexityRange.contains(complexity);
   2760             }
   2761             if (ok && quality != null) {
   2762                 ok = mQualityRange.contains(quality);
   2763             }
   2764             if (ok && profile != null) {
   2765                 for (CodecProfileLevel pl: mParent.profileLevels) {
   2766                     if (pl.profile == profile) {
   2767                         profile = null;
   2768                         break;
   2769                     }
   2770                 }
   2771                 ok = profile == null;
   2772             }
   2773             return ok;
   2774         }
   2775 
   2776         /** @hide */
   2777         public void setDefaultFormat(MediaFormat format) {
   2778             // don't list trivial quality/complexity as default for now
   2779             if (!mQualityRange.getUpper().equals(mQualityRange.getLower())
   2780                     && mDefaultQuality != null) {
   2781                 format.setInteger(MediaFormat.KEY_QUALITY, mDefaultQuality);
   2782             }
   2783             if (!mComplexityRange.getUpper().equals(mComplexityRange.getLower())
   2784                     && mDefaultComplexity != null) {
   2785                 format.setInteger(MediaFormat.KEY_COMPLEXITY, mDefaultComplexity);
   2786             }
   2787             // bitrates are listed in order of preference
   2788             for (Feature feat: bitrates) {
   2789                 if ((mBitControl & (1 << feat.mValue)) != 0) {
   2790                     format.setInteger(MediaFormat.KEY_BITRATE_MODE, feat.mValue);
   2791                     break;
   2792                 }
   2793             }
   2794         }
   2795 
   2796         /** @hide */
   2797         public boolean supportsFormat(MediaFormat format) {
   2798             final Map<String, Object> map = format.getMap();
   2799             final String mime = mParent.getMimeType();
   2800 
   2801             Integer mode = (Integer)map.get(MediaFormat.KEY_BITRATE_MODE);
   2802             if (mode != null && !isBitrateModeSupported(mode)) {
   2803                 return false;
   2804             }
   2805 
   2806             Integer complexity = (Integer)map.get(MediaFormat.KEY_COMPLEXITY);
   2807             if (MediaFormat.MIMETYPE_AUDIO_FLAC.equalsIgnoreCase(mime)) {
   2808                 Integer flacComplexity =
   2809                     (Integer)map.get(MediaFormat.KEY_FLAC_COMPRESSION_LEVEL);
   2810                 if (complexity == null) {
   2811                     complexity = flacComplexity;
   2812                 } else if (flacComplexity != null && !complexity.equals(flacComplexity)) {
   2813                     throw new IllegalArgumentException(
   2814                             "conflicting values for complexity and " +
   2815                             "flac-compression-level");
   2816                 }
   2817             }
   2818 
   2819             // other audio parameters
   2820             Integer profile = (Integer)map.get(MediaFormat.KEY_PROFILE);
   2821             if (MediaFormat.MIMETYPE_AUDIO_AAC.equalsIgnoreCase(mime)) {
   2822                 Integer aacProfile = (Integer)map.get(MediaFormat.KEY_AAC_PROFILE);
   2823                 if (profile == null) {
   2824                     profile = aacProfile;
   2825                 } else if (aacProfile != null && !aacProfile.equals(profile)) {
   2826                     throw new IllegalArgumentException(
   2827                             "conflicting values for profile and aac-profile");
   2828                 }
   2829             }
   2830 
   2831             Integer quality = (Integer)map.get(MediaFormat.KEY_QUALITY);
   2832 
   2833             return supports(complexity, quality, profile);
   2834         }
   2835     };
   2836 
   2837     /**
   2838      * Encapsulates the profiles available for a codec component.
   2839      * <p>You can get a set of {@link MediaCodecInfo.CodecProfileLevel} objects for a given
   2840      * {@link MediaCodecInfo} object from the
   2841      * {@link MediaCodecInfo.CodecCapabilities#profileLevels} field.
   2842      */
   2843     public static final class CodecProfileLevel {
   2844         // from OMX_VIDEO_AVCPROFILETYPE
   2845         public static final int AVCProfileBaseline = 0x01;
   2846         public static final int AVCProfileMain     = 0x02;
   2847         public static final int AVCProfileExtended = 0x04;
   2848         public static final int AVCProfileHigh     = 0x08;
   2849         public static final int AVCProfileHigh10   = 0x10;
   2850         public static final int AVCProfileHigh422  = 0x20;
   2851         public static final int AVCProfileHigh444  = 0x40;
   2852 
   2853         // from OMX_VIDEO_AVCLEVELTYPE
   2854         public static final int AVCLevel1       = 0x01;
   2855         public static final int AVCLevel1b      = 0x02;
   2856         public static final int AVCLevel11      = 0x04;
   2857         public static final int AVCLevel12      = 0x08;
   2858         public static final int AVCLevel13      = 0x10;
   2859         public static final int AVCLevel2       = 0x20;
   2860         public static final int AVCLevel21      = 0x40;
   2861         public static final int AVCLevel22      = 0x80;
   2862         public static final int AVCLevel3       = 0x100;
   2863         public static final int AVCLevel31      = 0x200;
   2864         public static final int AVCLevel32      = 0x400;
   2865         public static final int AVCLevel4       = 0x800;
   2866         public static final int AVCLevel41      = 0x1000;
   2867         public static final int AVCLevel42      = 0x2000;
   2868         public static final int AVCLevel5       = 0x4000;
   2869         public static final int AVCLevel51      = 0x8000;
   2870         public static final int AVCLevel52      = 0x10000;
   2871 
   2872         // from OMX_VIDEO_H263PROFILETYPE
   2873         public static final int H263ProfileBaseline             = 0x01;
   2874         public static final int H263ProfileH320Coding           = 0x02;
   2875         public static final int H263ProfileBackwardCompatible   = 0x04;
   2876         public static final int H263ProfileISWV2                = 0x08;
   2877         public static final int H263ProfileISWV3                = 0x10;
   2878         public static final int H263ProfileHighCompression      = 0x20;
   2879         public static final int H263ProfileInternet             = 0x40;
   2880         public static final int H263ProfileInterlace            = 0x80;
   2881         public static final int H263ProfileHighLatency          = 0x100;
   2882 
   2883         // from OMX_VIDEO_H263LEVELTYPE
   2884         public static final int H263Level10      = 0x01;
   2885         public static final int H263Level20      = 0x02;
   2886         public static final int H263Level30      = 0x04;
   2887         public static final int H263Level40      = 0x08;
   2888         public static final int H263Level45      = 0x10;
   2889         public static final int H263Level50      = 0x20;
   2890         public static final int H263Level60      = 0x40;
   2891         public static final int H263Level70      = 0x80;
   2892 
   2893         // from OMX_VIDEO_MPEG4PROFILETYPE
   2894         public static final int MPEG4ProfileSimple              = 0x01;
   2895         public static final int MPEG4ProfileSimpleScalable      = 0x02;
   2896         public static final int MPEG4ProfileCore                = 0x04;
   2897         public static final int MPEG4ProfileMain                = 0x08;
   2898         public static final int MPEG4ProfileNbit                = 0x10;
   2899         public static final int MPEG4ProfileScalableTexture     = 0x20;
   2900         public static final int MPEG4ProfileSimpleFace          = 0x40;
   2901         public static final int MPEG4ProfileSimpleFBA           = 0x80;
   2902         public static final int MPEG4ProfileBasicAnimated       = 0x100;
   2903         public static final int MPEG4ProfileHybrid              = 0x200;
   2904         public static final int MPEG4ProfileAdvancedRealTime    = 0x400;
   2905         public static final int MPEG4ProfileCoreScalable        = 0x800;
   2906         public static final int MPEG4ProfileAdvancedCoding      = 0x1000;
   2907         public static final int MPEG4ProfileAdvancedCore        = 0x2000;
   2908         public static final int MPEG4ProfileAdvancedScalable    = 0x4000;
   2909         public static final int MPEG4ProfileAdvancedSimple      = 0x8000;
   2910 
   2911         // from OMX_VIDEO_MPEG4LEVELTYPE
   2912         public static final int MPEG4Level0      = 0x01;
   2913         public static final int MPEG4Level0b     = 0x02;
   2914         public static final int MPEG4Level1      = 0x04;
   2915         public static final int MPEG4Level2      = 0x08;
   2916         public static final int MPEG4Level3      = 0x10;
   2917         public static final int MPEG4Level3b     = 0x18;
   2918         public static final int MPEG4Level4      = 0x20;
   2919         public static final int MPEG4Level4a     = 0x40;
   2920         public static final int MPEG4Level5      = 0x80;
   2921         public static final int MPEG4Level6      = 0x100;
   2922 
   2923         // from OMX_VIDEO_MPEG2PROFILETYPE
   2924         public static final int MPEG2ProfileSimple              = 0x00;
   2925         public static final int MPEG2ProfileMain                = 0x01;
   2926         public static final int MPEG2Profile422                 = 0x02;
   2927         public static final int MPEG2ProfileSNR                 = 0x03;
   2928         public static final int MPEG2ProfileSpatial             = 0x04;
   2929         public static final int MPEG2ProfileHigh                = 0x05;
   2930 
   2931         // from OMX_VIDEO_MPEG2LEVELTYPE
   2932         public static final int MPEG2LevelLL     = 0x00;
   2933         public static final int MPEG2LevelML     = 0x01;
   2934         public static final int MPEG2LevelH14    = 0x02;
   2935         public static final int MPEG2LevelHL     = 0x03;
   2936         public static final int MPEG2LevelHP     = 0x04;
   2937 
   2938         // from OMX_AUDIO_AACPROFILETYPE
   2939         public static final int AACObjectMain       = 1;
   2940         public static final int AACObjectLC         = 2;
   2941         public static final int AACObjectSSR        = 3;
   2942         public static final int AACObjectLTP        = 4;
   2943         public static final int AACObjectHE         = 5;
   2944         public static final int AACObjectScalable   = 6;
   2945         public static final int AACObjectERLC       = 17;
   2946         public static final int AACObjectLD         = 23;
   2947         public static final int AACObjectHE_PS      = 29;
   2948         public static final int AACObjectELD        = 39;
   2949 
   2950         // from OMX_VIDEO_VP8LEVELTYPE
   2951         public static final int VP8Level_Version0 = 0x01;
   2952         public static final int VP8Level_Version1 = 0x02;
   2953         public static final int VP8Level_Version2 = 0x04;
   2954         public static final int VP8Level_Version3 = 0x08;
   2955 
   2956         // from OMX_VIDEO_VP8PROFILETYPE
   2957         public static final int VP8ProfileMain = 0x01;
   2958 
   2959         // from OMX_VIDEO_VP9PROFILETYPE
   2960         public static final int VP9Profile0 = 0x01;
   2961         public static final int VP9Profile1 = 0x02;
   2962         public static final int VP9Profile2 = 0x04;
   2963         public static final int VP9Profile3 = 0x08;
   2964         // HDR profiles also support passing HDR metadata
   2965         public static final int VP9Profile2HDR = 0x1000;
   2966         public static final int VP9Profile3HDR = 0x2000;
   2967 
   2968         // from OMX_VIDEO_VP9LEVELTYPE
   2969         public static final int VP9Level1  = 0x1;
   2970         public static final int VP9Level11 = 0x2;
   2971         public static final int VP9Level2  = 0x4;
   2972         public static final int VP9Level21 = 0x8;
   2973         public static final int VP9Level3  = 0x10;
   2974         public static final int VP9Level31 = 0x20;
   2975         public static final int VP9Level4  = 0x40;
   2976         public static final int VP9Level41 = 0x80;
   2977         public static final int VP9Level5  = 0x100;
   2978         public static final int VP9Level51 = 0x200;
   2979         public static final int VP9Level52 = 0x400;
   2980         public static final int VP9Level6  = 0x800;
   2981         public static final int VP9Level61 = 0x1000;
   2982         public static final int VP9Level62 = 0x2000;
   2983 
   2984         // from OMX_VIDEO_HEVCPROFILETYPE
   2985         public static final int HEVCProfileMain        = 0x01;
   2986         public static final int HEVCProfileMain10      = 0x02;
   2987         public static final int HEVCProfileMain10HDR10 = 0x1000;
   2988 
   2989         // from OMX_VIDEO_HEVCLEVELTYPE
   2990         public static final int HEVCMainTierLevel1  = 0x1;
   2991         public static final int HEVCHighTierLevel1  = 0x2;
   2992         public static final int HEVCMainTierLevel2  = 0x4;
   2993         public static final int HEVCHighTierLevel2  = 0x8;
   2994         public static final int HEVCMainTierLevel21 = 0x10;
   2995         public static final int HEVCHighTierLevel21 = 0x20;
   2996         public static final int HEVCMainTierLevel3  = 0x40;
   2997         public static final int HEVCHighTierLevel3  = 0x80;
   2998         public static final int HEVCMainTierLevel31 = 0x100;
   2999         public static final int HEVCHighTierLevel31 = 0x200;
   3000         public static final int HEVCMainTierLevel4  = 0x400;
   3001         public static final int HEVCHighTierLevel4  = 0x800;
   3002         public static final int HEVCMainTierLevel41 = 0x1000;
   3003         public static final int HEVCHighTierLevel41 = 0x2000;
   3004         public static final int HEVCMainTierLevel5  = 0x4000;
   3005         public static final int HEVCHighTierLevel5  = 0x8000;
   3006         public static final int HEVCMainTierLevel51 = 0x10000;
   3007         public static final int HEVCHighTierLevel51 = 0x20000;
   3008         public static final int HEVCMainTierLevel52 = 0x40000;
   3009         public static final int HEVCHighTierLevel52 = 0x80000;
   3010         public static final int HEVCMainTierLevel6  = 0x100000;
   3011         public static final int HEVCHighTierLevel6  = 0x200000;
   3012         public static final int HEVCMainTierLevel61 = 0x400000;
   3013         public static final int HEVCHighTierLevel61 = 0x800000;
   3014         public static final int HEVCMainTierLevel62 = 0x1000000;
   3015         public static final int HEVCHighTierLevel62 = 0x2000000;
   3016 
   3017         private static final int HEVCHighTierLevels =
   3018             HEVCHighTierLevel1 | HEVCHighTierLevel2 | HEVCHighTierLevel21 | HEVCHighTierLevel3 |
   3019             HEVCHighTierLevel31 | HEVCHighTierLevel4 | HEVCHighTierLevel41 | HEVCHighTierLevel5 |
   3020             HEVCHighTierLevel51 | HEVCHighTierLevel52 | HEVCHighTierLevel6 | HEVCHighTierLevel61 |
   3021             HEVCHighTierLevel62;
   3022 
   3023         // from OMX_VIDEO_DOLBYVISIONPROFILETYPE
   3024         public static final int DolbyVisionProfileDvavPer = 0x1;
   3025         public static final int DolbyVisionProfileDvavPen = 0x2;
   3026         public static final int DolbyVisionProfileDvheDer = 0x4;
   3027         public static final int DolbyVisionProfileDvheDen = 0x8;
   3028         public static final int DolbyVisionProfileDvheDtr = 0x10;
   3029         public static final int DolbyVisionProfileDvheStn = 0x20;
   3030         public static final int DolbyVisionProfileDvheDth = 0x40;
   3031         public static final int DolbyVisionProfileDvheDtb = 0x80;
   3032 
   3033         // from OMX_VIDEO_DOLBYVISIONLEVELTYPE
   3034         public static final int DolbyVisionLevelHd24    = 0x1;
   3035         public static final int DolbyVisionLevelHd30    = 0x2;
   3036         public static final int DolbyVisionLevelFhd24   = 0x4;
   3037         public static final int DolbyVisionLevelFhd30   = 0x8;
   3038         public static final int DolbyVisionLevelFhd60   = 0x10;
   3039         public static final int DolbyVisionLevelUhd24   = 0x20;
   3040         public static final int DolbyVisionLevelUhd30   = 0x40;
   3041         public static final int DolbyVisionLevelUhd48   = 0x80;
   3042         public static final int DolbyVisionLevelUhd60   = 0x100;
   3043 
   3044         /**
   3045          * Defined in the OpenMAX IL specs, depending on the type of media
   3046          * this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE,
   3047          * OMX_VIDEO_MPEG4PROFILETYPE, OMX_VIDEO_VP8PROFILETYPE or OMX_VIDEO_VP9PROFILETYPE.
   3048          */
   3049         public int profile;
   3050 
   3051         /**
   3052          * Defined in the OpenMAX IL specs, depending on the type of media
   3053          * this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE
   3054          * OMX_VIDEO_MPEG4LEVELTYPE, OMX_VIDEO_VP8LEVELTYPE or OMX_VIDEO_VP9LEVELTYPE.
   3055          *
   3056          * Note that VP9 decoder on platforms before {@link android.os.Build.VERSION_CODES#N} may
   3057          * not advertise a profile level support. For those VP9 decoders, please use
   3058          * {@link VideoCapabilities} to determine the codec capabilities.
   3059          */
   3060         public int level;
   3061     };
   3062 
   3063     /**
   3064      * Enumerates the capabilities of the codec component. Since a single
   3065      * component can support data of a variety of types, the type has to be
   3066      * specified to yield a meaningful result.
   3067      * @param type The MIME type to query
   3068      */
   3069     public final CodecCapabilities getCapabilitiesForType(
   3070             String type) {
   3071         CodecCapabilities caps = mCaps.get(type);
   3072         if (caps == null) {
   3073             throw new IllegalArgumentException("codec does not support type");
   3074         }
   3075         // clone writable object
   3076         return caps.dup();
   3077     }
   3078 
   3079     /** @hide */
   3080     public MediaCodecInfo makeRegular() {
   3081         ArrayList<CodecCapabilities> caps = new ArrayList<CodecCapabilities>();
   3082         for (CodecCapabilities c: mCaps.values()) {
   3083             if (c.isRegular()) {
   3084                 caps.add(c);
   3085             }
   3086         }
   3087         if (caps.size() == 0) {
   3088             return null;
   3089         } else if (caps.size() == mCaps.size()) {
   3090             return this;
   3091         }
   3092 
   3093         return new MediaCodecInfo(
   3094                 mName, mIsEncoder,
   3095                 caps.toArray(new CodecCapabilities[caps.size()]));
   3096     }
   3097 }
   3098