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