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          * Query codec feature capabilities.
    464          * <p>
    465          * These features are supported to be used by the codec.  These
    466          * include optional features that can be turned on, as well as
    467          * features that are always on.
    468          */
    469         public final boolean isFeatureSupported(String name) {
    470             return checkFeature(name, mFlagsSupported);
    471         }
    472 
    473         /**
    474          * Query codec feature requirements.
    475          * <p>
    476          * These features are required to be used by the codec, and as such,
    477          * they are always turned on.
    478          */
    479         public final boolean isFeatureRequired(String name) {
    480             return checkFeature(name, mFlagsRequired);
    481         }
    482 
    483         private static final Feature[] decoderFeatures = {
    484             new Feature(FEATURE_AdaptivePlayback, (1 << 0), true),
    485             new Feature(FEATURE_SecurePlayback,   (1 << 1), false),
    486             new Feature(FEATURE_TunneledPlayback, (1 << 2), false),
    487         };
    488 
    489         /** @hide */
    490         public String[] validFeatures() {
    491             Feature[] features = getValidFeatures();
    492             String[] res = new String[features.length];
    493             for (int i = 0; i < res.length; i++) {
    494                 res[i] = features[i].mName;
    495             }
    496             return res;
    497         }
    498 
    499         private Feature[] getValidFeatures() {
    500             if (!isEncoder()) {
    501                 return decoderFeatures;
    502             }
    503             return new Feature[] {};
    504         }
    505 
    506         private boolean checkFeature(String name, int flags) {
    507             for (Feature feat: getValidFeatures()) {
    508                 if (feat.mName.equals(name)) {
    509                     return (flags & feat.mValue) != 0;
    510                 }
    511             }
    512             return false;
    513         }
    514 
    515         /** @hide */
    516         public boolean isRegular() {
    517             // regular codecs only require default features
    518             for (Feature feat: getValidFeatures()) {
    519                 if (!feat.mDefault && isFeatureRequired(feat.mName)) {
    520                     return false;
    521                 }
    522             }
    523             return true;
    524         }
    525 
    526         /**
    527          * Query whether codec supports a given {@link MediaFormat}.
    528          *
    529          * <p class=note>
    530          * <strong>Note:</strong> On {@link android.os.Build.VERSION_CODES#LOLLIPOP},
    531          * {@code format} must not contain a {@linkplain MediaFormat#KEY_FRAME_RATE
    532          * frame rate}. Use
    533          * <code class=prettyprint>format.setString(MediaFormat.KEY_FRAME_RATE, null)</code>
    534          * to clear any existing frame rate setting in the format.
    535          *
    536          * @param format media format with optional feature directives.
    537          * @throws IllegalArgumentException if format is not a valid media format.
    538          * @return whether the codec capabilities support the given format
    539          *         and feature requests.
    540          */
    541         public final boolean isFormatSupported(MediaFormat format) {
    542             final Map<String, Object> map = format.getMap();
    543             final String mime = (String)map.get(MediaFormat.KEY_MIME);
    544 
    545             // mime must match if present
    546             if (mime != null && !mMime.equalsIgnoreCase(mime)) {
    547                 return false;
    548             }
    549 
    550             // check feature support
    551             for (Feature feat: getValidFeatures()) {
    552                 Integer yesNo = (Integer)map.get(MediaFormat.KEY_FEATURE_ + feat.mName);
    553                 if (yesNo == null) {
    554                     continue;
    555                 }
    556                 if ((yesNo == 1 && !isFeatureSupported(feat.mName)) ||
    557                         (yesNo == 0 && isFeatureRequired(feat.mName))) {
    558                     return false;
    559                 }
    560             }
    561             if (mAudioCaps != null && !mAudioCaps.supportsFormat(format)) {
    562                 return false;
    563             }
    564             if (mVideoCaps != null && !mVideoCaps.supportsFormat(format)) {
    565                 return false;
    566             }
    567             if (mEncoderCaps != null && !mEncoderCaps.supportsFormat(format)) {
    568                 return false;
    569             }
    570             return true;
    571         }
    572 
    573         // errors while reading profile levels - accessed from sister capabilities
    574         int mError;
    575 
    576         private static final String TAG = "CodecCapabilities";
    577 
    578         // NEW-STYLE CAPABILITIES
    579         private AudioCapabilities mAudioCaps;
    580         private VideoCapabilities mVideoCaps;
    581         private EncoderCapabilities mEncoderCaps;
    582         private MediaFormat mDefaultFormat;
    583 
    584         /**
    585          * Returns a MediaFormat object with default values for configurations that have
    586          * defaults.
    587          */
    588         public MediaFormat getDefaultFormat() {
    589             return mDefaultFormat;
    590         }
    591 
    592         /**
    593          * Returns the mime type for which this codec-capability object was created.
    594          */
    595         public String getMimeType() {
    596             return mMime;
    597         }
    598 
    599         /**
    600          * Returns the max number of the supported concurrent codec instances.
    601          * <p>
    602          * This is a hint for an upper bound. Applications should not expect to successfully
    603          * operate more instances than the returned value, but the actual number of
    604          * concurrently operable instances may be less as it depends on the available
    605          * resources at time of use.
    606          */
    607         public int getMaxSupportedInstances() {
    608             return mMaxSupportedInstances;
    609         }
    610 
    611         private boolean isAudio() {
    612             return mAudioCaps != null;
    613         }
    614 
    615         /**
    616          * Returns the audio capabilities or {@code null} if this is not an audio codec.
    617          */
    618         public AudioCapabilities getAudioCapabilities() {
    619             return mAudioCaps;
    620         }
    621 
    622         private boolean isEncoder() {
    623             return mEncoderCaps != null;
    624         }
    625 
    626         /**
    627          * Returns the encoding capabilities or {@code null} if this is not an encoder.
    628          */
    629         public EncoderCapabilities getEncoderCapabilities() {
    630             return mEncoderCaps;
    631         }
    632 
    633         private boolean isVideo() {
    634             return mVideoCaps != null;
    635         }
    636 
    637         /**
    638          * Returns the video capabilities or {@code null} if this is not a video codec.
    639          */
    640         public VideoCapabilities getVideoCapabilities() {
    641             return mVideoCaps;
    642         }
    643 
    644         /** @hide */
    645         public CodecCapabilities dup() {
    646             return new CodecCapabilities(
    647                 // clone writable arrays
    648                 Arrays.copyOf(profileLevels, profileLevels.length),
    649                 Arrays.copyOf(colorFormats, colorFormats.length),
    650                 isEncoder(),
    651                 mFlagsVerified,
    652                 mDefaultFormat,
    653                 mCapabilitiesInfo);
    654         }
    655 
    656         /**
    657          * Retrieve the codec capabilities for a certain {@code mime type}, {@code
    658          * profile} and {@code level}.  If the type, or profile-level combination
    659          * is not understood by the framework, it returns null.
    660          */
    661         public static CodecCapabilities createFromProfileLevel(
    662                 String mime, int profile, int level) {
    663             CodecProfileLevel pl = new CodecProfileLevel();
    664             pl.profile = profile;
    665             pl.level = level;
    666             MediaFormat defaultFormat = new MediaFormat();
    667             defaultFormat.setString(MediaFormat.KEY_MIME, mime);
    668 
    669             CodecCapabilities ret = new CodecCapabilities(
    670                 new CodecProfileLevel[] { pl }, new int[0], true /* encoder */,
    671                 0 /* flags */, defaultFormat, new MediaFormat() /* info */);
    672             if (ret.mError != 0) {
    673                 return null;
    674             }
    675             return ret;
    676         }
    677 
    678         /* package private */ CodecCapabilities(
    679                 CodecProfileLevel[] profLevs, int[] colFmts,
    680                 boolean encoder, int flags,
    681                 Map<String, Object>defaultFormatMap,
    682                 Map<String, Object>capabilitiesMap) {
    683             this(profLevs, colFmts, encoder, flags,
    684                     new MediaFormat(defaultFormatMap),
    685                     new MediaFormat(capabilitiesMap));
    686         }
    687 
    688         private MediaFormat mCapabilitiesInfo;
    689 
    690         /* package private */ CodecCapabilities(
    691                 CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags,
    692                 MediaFormat defaultFormat, MediaFormat info) {
    693             final Map<String, Object> map = info.getMap();
    694             profileLevels = profLevs;
    695             colorFormats = colFmts;
    696             mFlagsVerified = flags;
    697             mDefaultFormat = defaultFormat;
    698             mCapabilitiesInfo = info;
    699             mMime = mDefaultFormat.getString(MediaFormat.KEY_MIME);
    700 
    701             if (mMime.toLowerCase().startsWith("audio/")) {
    702                 mAudioCaps = AudioCapabilities.create(info, this);
    703                 mAudioCaps.setDefaultFormat(mDefaultFormat);
    704             } else if (mMime.toLowerCase().startsWith("video/")) {
    705                 mVideoCaps = VideoCapabilities.create(info, this);
    706             }
    707             if (encoder) {
    708                 mEncoderCaps = EncoderCapabilities.create(info, this);
    709                 mEncoderCaps.setDefaultFormat(mDefaultFormat);
    710             }
    711 
    712             final Map<String, Object> global = MediaCodecList.getGlobalSettings();
    713             mMaxSupportedInstances = Utils.parseIntSafely(
    714                     global.get("max-concurrent-instances"), DEFAULT_MAX_SUPPORTED_INSTANCES);
    715 
    716             int maxInstances = Utils.parseIntSafely(
    717                     map.get("max-concurrent-instances"), mMaxSupportedInstances);
    718             mMaxSupportedInstances =
    719                     Range.create(1, MAX_SUPPORTED_INSTANCES_LIMIT).clamp(maxInstances);
    720 
    721             for (Feature feat: getValidFeatures()) {
    722                 String key = MediaFormat.KEY_FEATURE_ + feat.mName;
    723                 Integer yesNo = (Integer)map.get(key);
    724                 if (yesNo == null) {
    725                     continue;
    726                 }
    727                 if (yesNo > 0) {
    728                     mFlagsRequired |= feat.mValue;
    729                 }
    730                 mFlagsSupported |= feat.mValue;
    731                 mDefaultFormat.setInteger(key, 1);
    732                 // TODO restrict features by mFlagsVerified once all codecs reliably verify them
    733             }
    734         }
    735     }
    736 
    737     /**
    738      * A class that supports querying the audio capabilities of a codec.
    739      */
    740     public static final class AudioCapabilities {
    741         private static final String TAG = "AudioCapabilities";
    742         private CodecCapabilities mParent;
    743         private Range<Integer> mBitrateRange;
    744 
    745         private int[] mSampleRates;
    746         private Range<Integer>[] mSampleRateRanges;
    747         private int mMaxInputChannelCount;
    748 
    749         private static final int MAX_INPUT_CHANNEL_COUNT = 30;
    750 
    751         /**
    752          * Returns the range of supported bitrates in bits/second.
    753          */
    754         public Range<Integer> getBitrateRange() {
    755             return mBitrateRange;
    756         }
    757 
    758         /**
    759          * Returns the array of supported sample rates if the codec
    760          * supports only discrete values.  Otherwise, it returns
    761          * {@code null}.  The array is sorted in ascending order.
    762          */
    763         public int[] getSupportedSampleRates() {
    764             return Arrays.copyOf(mSampleRates, mSampleRates.length);
    765         }
    766 
    767         /**
    768          * Returns the array of supported sample rate ranges.  The
    769          * array is sorted in ascending order, and the ranges are
    770          * distinct.
    771          */
    772         public Range<Integer>[] getSupportedSampleRateRanges() {
    773             return Arrays.copyOf(mSampleRateRanges, mSampleRateRanges.length);
    774         }
    775 
    776         /**
    777          * Returns the maximum number of input channels supported.  The codec
    778          * supports any number of channels between 1 and this maximum value.
    779          */
    780         public int getMaxInputChannelCount() {
    781             return mMaxInputChannelCount;
    782         }
    783 
    784         /* no public constructor */
    785         private AudioCapabilities() { }
    786 
    787         /** @hide */
    788         public static AudioCapabilities create(
    789                 MediaFormat info, CodecCapabilities parent) {
    790             AudioCapabilities caps = new AudioCapabilities();
    791             caps.init(info, parent);
    792             return caps;
    793         }
    794 
    795         /** @hide */
    796         public void init(MediaFormat info, CodecCapabilities parent) {
    797             mParent = parent;
    798             initWithPlatformLimits();
    799             applyLevelLimits();
    800             parseFromInfo(info);
    801         }
    802 
    803         private void initWithPlatformLimits() {
    804             mBitrateRange = Range.create(0, Integer.MAX_VALUE);
    805             mMaxInputChannelCount = MAX_INPUT_CHANNEL_COUNT;
    806             // mBitrateRange = Range.create(1, 320000);
    807             mSampleRateRanges = new Range[] { Range.create(8000, 96000) };
    808             mSampleRates = null;
    809         }
    810 
    811         private boolean supports(Integer sampleRate, Integer inputChannels) {
    812             // channels and sample rates are checked orthogonally
    813             if (inputChannels != null &&
    814                     (inputChannels < 1 || inputChannels > mMaxInputChannelCount)) {
    815                 return false;
    816             }
    817             if (sampleRate != null) {
    818                 int ix = Utils.binarySearchDistinctRanges(
    819                         mSampleRateRanges, sampleRate);
    820                 if (ix < 0) {
    821                     return false;
    822                 }
    823             }
    824             return true;
    825         }
    826 
    827         /**
    828          * Query whether the sample rate is supported by the codec.
    829          */
    830         public boolean isSampleRateSupported(int sampleRate) {
    831             return supports(sampleRate, null);
    832         }
    833 
    834         /** modifies rates */
    835         private void limitSampleRates(int[] rates) {
    836             Arrays.sort(rates);
    837             ArrayList<Range<Integer>> ranges = new ArrayList<Range<Integer>>();
    838             for (int rate: rates) {
    839                 if (supports(rate, null /* channels */)) {
    840                     ranges.add(Range.create(rate, rate));
    841                 }
    842             }
    843             mSampleRateRanges = ranges.toArray(new Range[ranges.size()]);
    844             createDiscreteSampleRates();
    845         }
    846 
    847         private void createDiscreteSampleRates() {
    848             mSampleRates = new int[mSampleRateRanges.length];
    849             for (int i = 0; i < mSampleRateRanges.length; i++) {
    850                 mSampleRates[i] = mSampleRateRanges[i].getLower();
    851             }
    852         }
    853 
    854         /** modifies rateRanges */
    855         private void limitSampleRates(Range<Integer>[] rateRanges) {
    856             sortDistinctRanges(rateRanges);
    857             mSampleRateRanges = intersectSortedDistinctRanges(mSampleRateRanges, rateRanges);
    858 
    859             // check if all values are discrete
    860             for (Range<Integer> range: mSampleRateRanges) {
    861                 if (!range.getLower().equals(range.getUpper())) {
    862                     mSampleRates = null;
    863                     return;
    864                 }
    865             }
    866             createDiscreteSampleRates();
    867         }
    868 
    869         private void applyLevelLimits() {
    870             int[] sampleRates = null;
    871             Range<Integer> sampleRateRange = null, bitRates = null;
    872             int maxChannels = 0;
    873             String mime = mParent.getMimeType();
    874 
    875             if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MPEG)) {
    876                 sampleRates = new int[] {
    877                         8000, 11025, 12000,
    878                         16000, 22050, 24000,
    879                         32000, 44100, 48000 };
    880                 bitRates = Range.create(8000, 320000);
    881                 maxChannels = 2;
    882             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)) {
    883                 sampleRates = new int[] { 8000 };
    884                 bitRates = Range.create(4750, 12200);
    885                 maxChannels = 1;
    886             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)) {
    887                 sampleRates = new int[] { 16000 };
    888                 bitRates = Range.create(6600, 23850);
    889                 maxChannels = 1;
    890             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC)) {
    891                 sampleRates = new int[] {
    892                         7350, 8000,
    893                         11025, 12000, 16000,
    894                         22050, 24000, 32000,
    895                         44100, 48000, 64000,
    896                         88200, 96000 };
    897                 bitRates = Range.create(8000, 510000);
    898                 maxChannels = 48;
    899             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_VORBIS)) {
    900                 bitRates = Range.create(32000, 500000);
    901                 sampleRateRange = Range.create(8000, 192000);
    902                 maxChannels = 255;
    903             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_OPUS)) {
    904                 bitRates = Range.create(6000, 510000);
    905                 sampleRates = new int[] { 8000, 12000, 16000, 24000, 48000 };
    906                 maxChannels = 255;
    907             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW)) {
    908                 sampleRateRange = Range.create(1, 96000);
    909                 bitRates = Range.create(1, 10000000);
    910                 maxChannels = 8;
    911             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
    912                 sampleRateRange = Range.create(1, 655350);
    913                 // lossless codec, so bitrate is ignored
    914                 maxChannels = 255;
    915             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW)
    916                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)) {
    917                 sampleRates = new int[] { 8000 };
    918                 bitRates = Range.create(64000, 64000);
    919                 // platform allows multiple channels for this format
    920             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) {
    921                 sampleRates = new int[] { 8000 };
    922                 bitRates = Range.create(13000, 13000);
    923                 maxChannels = 1;
    924             } else {
    925                 Log.w(TAG, "Unsupported mime " + mime);
    926                 mParent.mError |= ERROR_UNSUPPORTED;
    927             }
    928 
    929             // restrict ranges
    930             if (sampleRates != null) {
    931                 limitSampleRates(sampleRates);
    932             } else if (sampleRateRange != null) {
    933                 limitSampleRates(new Range[] { sampleRateRange });
    934             }
    935             applyLimits(maxChannels, bitRates);
    936         }
    937 
    938         private void applyLimits(int maxInputChannels, Range<Integer> bitRates) {
    939             mMaxInputChannelCount = Range.create(1, mMaxInputChannelCount)
    940                     .clamp(maxInputChannels);
    941             if (bitRates != null) {
    942                 mBitrateRange = mBitrateRange.intersect(bitRates);
    943             }
    944         }
    945 
    946         private void parseFromInfo(MediaFormat info) {
    947             int maxInputChannels = MAX_INPUT_CHANNEL_COUNT;
    948             Range<Integer> bitRates = POSITIVE_INTEGERS;
    949 
    950             if (info.containsKey("sample-rate-ranges")) {
    951                 String[] rateStrings = info.getString("sample-rate-ranges").split(",");
    952                 Range<Integer>[] rateRanges = new Range[rateStrings.length];
    953                 for (int i = 0; i < rateStrings.length; i++) {
    954                     rateRanges[i] = Utils.parseIntRange(rateStrings[i], null);
    955                 }
    956                 limitSampleRates(rateRanges);
    957             }
    958             if (info.containsKey("max-channel-count")) {
    959                 maxInputChannels = Utils.parseIntSafely(
    960                         info.getString("max-channel-count"), maxInputChannels);
    961             }
    962             if (info.containsKey("bitrate-range")) {
    963                 bitRates = bitRates.intersect(
    964                         Utils.parseIntRange(info.getString("bitrate-range"), bitRates));
    965             }
    966             applyLimits(maxInputChannels, bitRates);
    967         }
    968 
    969         /** @hide */
    970         public void setDefaultFormat(MediaFormat format) {
    971             // report settings that have only a single choice
    972             if (mBitrateRange.getLower().equals(mBitrateRange.getUpper())) {
    973                 format.setInteger(MediaFormat.KEY_BIT_RATE, mBitrateRange.getLower());
    974             }
    975             if (mMaxInputChannelCount == 1) {
    976                 // mono-only format
    977                 format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
    978             }
    979             if (mSampleRates != null && mSampleRates.length == 1) {
    980                 format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRates[0]);
    981             }
    982         }
    983 
    984         /** @hide */
    985         public boolean supportsFormat(MediaFormat format) {
    986             Map<String, Object> map = format.getMap();
    987             Integer sampleRate = (Integer)map.get(MediaFormat.KEY_SAMPLE_RATE);
    988             Integer channels = (Integer)map.get(MediaFormat.KEY_CHANNEL_COUNT);
    989             if (!supports(sampleRate, channels)) {
    990                 return false;
    991             }
    992 
    993             // nothing to do for:
    994             // KEY_CHANNEL_MASK: codecs don't get this
    995             // KEY_IS_ADTS:      required feature for all AAC decoders
    996             return true;
    997         }
    998     }
    999 
   1000     /**
   1001      * A class that supports querying the video capabilities of a codec.
   1002      */
   1003     public static final class VideoCapabilities {
   1004         private static final String TAG = "VideoCapabilities";
   1005         private CodecCapabilities mParent;
   1006         private Range<Integer> mBitrateRange;
   1007 
   1008         private Range<Integer> mHeightRange;
   1009         private Range<Integer> mWidthRange;
   1010         private Range<Integer> mBlockCountRange;
   1011         private Range<Integer> mHorizontalBlockRange;
   1012         private Range<Integer> mVerticalBlockRange;
   1013         private Range<Rational> mAspectRatioRange;
   1014         private Range<Rational> mBlockAspectRatioRange;
   1015         private Range<Long> mBlocksPerSecondRange;
   1016         private Map<Size, Range<Long>> mMeasuredFrameRates;
   1017         private Range<Integer> mFrameRateRange;
   1018 
   1019         private int mBlockWidth;
   1020         private int mBlockHeight;
   1021         private int mWidthAlignment;
   1022         private int mHeightAlignment;
   1023         private int mSmallerDimensionUpperLimit;
   1024 
   1025         /**
   1026          * Returns the range of supported bitrates in bits/second.
   1027          */
   1028         public Range<Integer> getBitrateRange() {
   1029             return mBitrateRange;
   1030         }
   1031 
   1032         /**
   1033          * Returns the range of supported video widths.
   1034          */
   1035         public Range<Integer> getSupportedWidths() {
   1036             return mWidthRange;
   1037         }
   1038 
   1039         /**
   1040          * Returns the range of supported video heights.
   1041          */
   1042         public Range<Integer> getSupportedHeights() {
   1043             return mHeightRange;
   1044         }
   1045 
   1046         /**
   1047          * Returns the alignment requirement for video width (in pixels).
   1048          *
   1049          * This is a power-of-2 value that video width must be a
   1050          * multiple of.
   1051          */
   1052         public int getWidthAlignment() {
   1053             return mWidthAlignment;
   1054         }
   1055 
   1056         /**
   1057          * Returns the alignment requirement for video height (in pixels).
   1058          *
   1059          * This is a power-of-2 value that video height must be a
   1060          * multiple of.
   1061          */
   1062         public int getHeightAlignment() {
   1063             return mHeightAlignment;
   1064         }
   1065 
   1066         /**
   1067          * Return the upper limit on the smaller dimension of width or height.
   1068          * <p></p>
   1069          * Some codecs have a limit on the smaller dimension, whether it be
   1070          * the width or the height.  E.g. a codec may only be able to handle
   1071          * up to 1920x1080 both in landscape and portrait mode (1080x1920).
   1072          * In this case the maximum width and height are both 1920, but the
   1073          * smaller dimension limit will be 1080. For other codecs, this is
   1074          * {@code Math.min(getSupportedWidths().getUpper(),
   1075          * getSupportedHeights().getUpper())}.
   1076          *
   1077          * @hide
   1078          */
   1079         public int getSmallerDimensionUpperLimit() {
   1080             return mSmallerDimensionUpperLimit;
   1081         }
   1082 
   1083         /**
   1084          * Returns the range of supported frame rates.
   1085          * <p>
   1086          * This is not a performance indicator.  Rather, it expresses the
   1087          * limits specified in the coding standard, based on the complexities
   1088          * of encoding material for later playback at a certain frame rate,
   1089          * or the decoding of such material in non-realtime.
   1090          */
   1091         public Range<Integer> getSupportedFrameRates() {
   1092             return mFrameRateRange;
   1093         }
   1094 
   1095         /**
   1096          * Returns the range of supported video widths for a video height.
   1097          * @param height the height of the video
   1098          */
   1099         public Range<Integer> getSupportedWidthsFor(int height) {
   1100             try {
   1101                 Range<Integer> range = mWidthRange;
   1102                 if (!mHeightRange.contains(height)
   1103                         || (height % mHeightAlignment) != 0) {
   1104                     throw new IllegalArgumentException("unsupported height");
   1105                 }
   1106                 final int heightInBlocks = Utils.divUp(height, mBlockHeight);
   1107 
   1108                 // constrain by block count and by block aspect ratio
   1109                 final int minWidthInBlocks = Math.max(
   1110                         Utils.divUp(mBlockCountRange.getLower(), heightInBlocks),
   1111                         (int)Math.ceil(mBlockAspectRatioRange.getLower().doubleValue()
   1112                                 * heightInBlocks));
   1113                 final int maxWidthInBlocks = Math.min(
   1114                         mBlockCountRange.getUpper() / heightInBlocks,
   1115                         (int)(mBlockAspectRatioRange.getUpper().doubleValue()
   1116                                 * heightInBlocks));
   1117                 range = range.intersect(
   1118                         (minWidthInBlocks - 1) * mBlockWidth + mWidthAlignment,
   1119                         maxWidthInBlocks * mBlockWidth);
   1120 
   1121                 // constrain by smaller dimension limit
   1122                 if (height > mSmallerDimensionUpperLimit) {
   1123                     range = range.intersect(1, mSmallerDimensionUpperLimit);
   1124                 }
   1125 
   1126                 // constrain by aspect ratio
   1127                 range = range.intersect(
   1128                         (int)Math.ceil(mAspectRatioRange.getLower().doubleValue()
   1129                                 * height),
   1130                         (int)(mAspectRatioRange.getUpper().doubleValue() * height));
   1131                 return range;
   1132             } catch (IllegalArgumentException e) {
   1133                 // height is not supported because there are no suitable widths
   1134                 Log.v(TAG, "could not get supported widths for " + height);
   1135                 throw new IllegalArgumentException("unsupported height");
   1136             }
   1137         }
   1138 
   1139         /**
   1140          * Returns the range of supported video heights for a video width
   1141          * @param width the width of the video
   1142          */
   1143         public Range<Integer> getSupportedHeightsFor(int width) {
   1144             try {
   1145                 Range<Integer> range = mHeightRange;
   1146                 if (!mWidthRange.contains(width)
   1147                         || (width % mWidthAlignment) != 0) {
   1148                     throw new IllegalArgumentException("unsupported width");
   1149                 }
   1150                 final int widthInBlocks = Utils.divUp(width, mBlockWidth);
   1151 
   1152                 // constrain by block count and by block aspect ratio
   1153                 final int minHeightInBlocks = Math.max(
   1154                         Utils.divUp(mBlockCountRange.getLower(), widthInBlocks),
   1155                         (int)Math.ceil(widthInBlocks /
   1156                                 mBlockAspectRatioRange.getUpper().doubleValue()));
   1157                 final int maxHeightInBlocks = Math.min(
   1158                         mBlockCountRange.getUpper() / widthInBlocks,
   1159                         (int)(widthInBlocks /
   1160                                 mBlockAspectRatioRange.getLower().doubleValue()));
   1161                 range = range.intersect(
   1162                         (minHeightInBlocks - 1) * mBlockHeight + mHeightAlignment,
   1163                         maxHeightInBlocks * mBlockHeight);
   1164 
   1165                 // constrain by smaller dimension limit
   1166                 if (width > mSmallerDimensionUpperLimit) {
   1167                     range = range.intersect(1, mSmallerDimensionUpperLimit);
   1168                 }
   1169 
   1170                 // constrain by aspect ratio
   1171                 range = range.intersect(
   1172                         (int)Math.ceil(width /
   1173                                 mAspectRatioRange.getUpper().doubleValue()),
   1174                         (int)(width / mAspectRatioRange.getLower().doubleValue()));
   1175                 return range;
   1176             } catch (IllegalArgumentException e) {
   1177                 // width is not supported because there are no suitable heights
   1178                 Log.v(TAG, "could not get supported heights for " + width);
   1179                 throw new IllegalArgumentException("unsupported width");
   1180             }
   1181         }
   1182 
   1183         /**
   1184          * Returns the range of supported video frame rates for a video size.
   1185          * <p>
   1186          * This is not a performance indicator.  Rather, it expresses the limits specified in
   1187          * the coding standard, based on the complexities of encoding material of a given
   1188          * size for later playback at a certain frame rate, or the decoding of such material
   1189          * in non-realtime.
   1190 
   1191          * @param width the width of the video
   1192          * @param height the height of the video
   1193          */
   1194         public Range<Double> getSupportedFrameRatesFor(int width, int height) {
   1195             Range<Integer> range = mHeightRange;
   1196             if (!supports(width, height, null)) {
   1197                 throw new IllegalArgumentException("unsupported size");
   1198             }
   1199             final int blockCount =
   1200                 Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight);
   1201 
   1202             return Range.create(
   1203                     Math.max(mBlocksPerSecondRange.getLower() / (double) blockCount,
   1204                             (double) mFrameRateRange.getLower()),
   1205                     Math.min(mBlocksPerSecondRange.getUpper() / (double) blockCount,
   1206                             (double) mFrameRateRange.getUpper()));
   1207         }
   1208 
   1209         private int getBlockCount(int width, int height) {
   1210             return Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight);
   1211         }
   1212 
   1213         @NonNull
   1214         private Size findClosestSize(int width, int height) {
   1215             int targetBlockCount = getBlockCount(width, height);
   1216             Size closestSize = null;
   1217             int minDiff = Integer.MAX_VALUE;
   1218             for (Size size : mMeasuredFrameRates.keySet()) {
   1219                 int diff = Math.abs(targetBlockCount -
   1220                         getBlockCount(size.getWidth(), size.getHeight()));
   1221                 if (diff < minDiff) {
   1222                     minDiff = diff;
   1223                     closestSize = size;
   1224                 }
   1225             }
   1226             return closestSize;
   1227         }
   1228 
   1229         private Range<Double> estimateFrameRatesFor(int width, int height) {
   1230             Size size = findClosestSize(width, height);
   1231             Range<Long> range = mMeasuredFrameRates.get(size);
   1232             Double ratio = (double)(size.getWidth() * size.getHeight()) / (width * height);
   1233             return Range.create(range.getLower() * ratio, range.getUpper() * ratio);
   1234         }
   1235 
   1236         /**
   1237          * Returns the range of achievable video frame rates for a video size.
   1238          * May return {@code null}, if the codec did not publish any measurement
   1239          * data.
   1240          * <p>
   1241          * This is a performance estimate provided by the device manufacturer
   1242          * based on full-speed decoding and encoding measurements in various configurations
   1243          * of common video sizes supported by the codec. As such it should only be used to
   1244          * compare individual codecs on the device. The value is not suitable for comparing
   1245          * different devices or even different android releases for the same device.
   1246          * <p>
   1247          * The returned range corresponds to the fastest frame rates achieved in the tested
   1248          * configurations. It is interpolated from the nearest frame size(s) tested. Codec
   1249          * performance is severely impacted by other activity on the device, and can vary
   1250          * significantly.
   1251          * <p class=note>
   1252          * Use this method in cases where only codec performance matters, e.g. to evaluate if
   1253          * a codec has any chance of meeting a performance target. Codecs are listed
   1254          * in {@link MediaCodecList} in the preferred order as defined by the device
   1255          * manufacturer. As such, applications should use the first suitable codec in the
   1256          * list to achieve the best balance between power use and performance.
   1257          *
   1258          * @param width the width of the video
   1259          * @param height the height of the video
   1260          *
   1261          * @throws IllegalArgumentException if the video size is not supported.
   1262          */
   1263         @Nullable
   1264         public Range<Double> getAchievableFrameRatesFor(int width, int height) {
   1265             if (!supports(width, height, null)) {
   1266                 throw new IllegalArgumentException("unsupported size");
   1267             }
   1268 
   1269             if (mMeasuredFrameRates == null || mMeasuredFrameRates.size() <= 0) {
   1270                 Log.w(TAG, "Codec did not publish any measurement data.");
   1271                 return null;
   1272             }
   1273 
   1274             return estimateFrameRatesFor(width, height);
   1275         }
   1276 
   1277         /**
   1278          * Returns whether a given video size ({@code width} and
   1279          * {@code height}) and {@code frameRate} combination is supported.
   1280          */
   1281         public boolean areSizeAndRateSupported(
   1282                 int width, int height, double frameRate) {
   1283             return supports(width, height, frameRate);
   1284         }
   1285 
   1286         /**
   1287          * Returns whether a given video size ({@code width} and
   1288          * {@code height}) is supported.
   1289          */
   1290         public boolean isSizeSupported(int width, int height) {
   1291             return supports(width, height, null);
   1292         }
   1293 
   1294         private boolean supports(
   1295                 Integer width, Integer height, Number rate) {
   1296             boolean ok = true;
   1297 
   1298             if (ok && width != null) {
   1299                 ok = mWidthRange.contains(width)
   1300                         && (width % mWidthAlignment == 0);
   1301             }
   1302             if (ok && height != null) {
   1303                 ok = mHeightRange.contains(height)
   1304                         && (height % mHeightAlignment == 0);
   1305             }
   1306             if (ok && rate != null) {
   1307                 ok = mFrameRateRange.contains(Utils.intRangeFor(rate.doubleValue()));
   1308             }
   1309             if (ok && height != null && width != null) {
   1310                 ok = Math.min(height, width) <= mSmallerDimensionUpperLimit;
   1311 
   1312                 final int widthInBlocks = Utils.divUp(width, mBlockWidth);
   1313                 final int heightInBlocks = Utils.divUp(height, mBlockHeight);
   1314                 final int blockCount = widthInBlocks * heightInBlocks;
   1315                 ok = ok && mBlockCountRange.contains(blockCount)
   1316                         && mBlockAspectRatioRange.contains(
   1317                                 new Rational(widthInBlocks, heightInBlocks))
   1318                         && mAspectRatioRange.contains(new Rational(width, height));
   1319                 if (ok && rate != null) {
   1320                     double blocksPerSec = blockCount * rate.doubleValue();
   1321                     ok = mBlocksPerSecondRange.contains(
   1322                             Utils.longRangeFor(blocksPerSec));
   1323                 }
   1324             }
   1325             return ok;
   1326         }
   1327 
   1328         /**
   1329          * @hide
   1330          * @throws java.lang.ClassCastException */
   1331         public boolean supportsFormat(MediaFormat format) {
   1332             final Map<String, Object> map = format.getMap();
   1333             Integer width = (Integer)map.get(MediaFormat.KEY_WIDTH);
   1334             Integer height = (Integer)map.get(MediaFormat.KEY_HEIGHT);
   1335             Number rate = (Number)map.get(MediaFormat.KEY_FRAME_RATE);
   1336 
   1337             // we ignore color-format for now as it is not reliably reported by codec
   1338 
   1339             return supports(width, height, rate);
   1340         }
   1341 
   1342         /* no public constructor */
   1343         private VideoCapabilities() { }
   1344 
   1345         /** @hide */
   1346         public static VideoCapabilities create(
   1347                 MediaFormat info, CodecCapabilities parent) {
   1348             VideoCapabilities caps = new VideoCapabilities();
   1349             caps.init(info, parent);
   1350             return caps;
   1351         }
   1352 
   1353         /** @hide */
   1354         public void init(MediaFormat info, CodecCapabilities parent) {
   1355             mParent = parent;
   1356             initWithPlatformLimits();
   1357             applyLevelLimits();
   1358             parseFromInfo(info);
   1359             updateLimits();
   1360         }
   1361 
   1362         /** @hide */
   1363         public Size getBlockSize() {
   1364             return new Size(mBlockWidth, mBlockHeight);
   1365         }
   1366 
   1367         /** @hide */
   1368         public Range<Integer> getBlockCountRange() {
   1369             return mBlockCountRange;
   1370         }
   1371 
   1372         /** @hide */
   1373         public Range<Long> getBlocksPerSecondRange() {
   1374             return mBlocksPerSecondRange;
   1375         }
   1376 
   1377         /** @hide */
   1378         public Range<Rational> getAspectRatioRange(boolean blocks) {
   1379             return blocks ? mBlockAspectRatioRange : mAspectRatioRange;
   1380         }
   1381 
   1382         private void initWithPlatformLimits() {
   1383             mBitrateRange = BITRATE_RANGE;
   1384 
   1385             mWidthRange  = SIZE_RANGE;
   1386             mHeightRange = SIZE_RANGE;
   1387             mFrameRateRange = FRAME_RATE_RANGE;
   1388 
   1389             mHorizontalBlockRange = SIZE_RANGE;
   1390             mVerticalBlockRange   = SIZE_RANGE;
   1391 
   1392             // full positive ranges are supported as these get calculated
   1393             mBlockCountRange      = POSITIVE_INTEGERS;
   1394             mBlocksPerSecondRange = POSITIVE_LONGS;
   1395 
   1396             mBlockAspectRatioRange = POSITIVE_RATIONALS;
   1397             mAspectRatioRange      = POSITIVE_RATIONALS;
   1398 
   1399             // YUV 4:2:0 requires 2:2 alignment
   1400             mWidthAlignment = 2;
   1401             mHeightAlignment = 2;
   1402             mBlockWidth = 2;
   1403             mBlockHeight = 2;
   1404             mSmallerDimensionUpperLimit = SIZE_RANGE.getUpper();
   1405         }
   1406 
   1407         private Map<Size, Range<Long>> getMeasuredFrameRates(Map<String, Object> map) {
   1408             Map<Size, Range<Long>> ret = new HashMap<Size, Range<Long>>();
   1409             final String prefix = "measured-frame-rate-";
   1410             Set<String> keys = map.keySet();
   1411             for (String key : keys) {
   1412                 // looking for: measured-frame-rate-WIDTHxHEIGHT-range
   1413                 if (!key.startsWith(prefix)) {
   1414                     continue;
   1415                 }
   1416                 String subKey = key.substring(prefix.length());
   1417                 String[] temp = key.split("-");
   1418                 if (temp.length != 5) {
   1419                     continue;
   1420                 }
   1421                 String sizeStr = temp[3];
   1422                 Size size = Utils.parseSize(sizeStr, null);
   1423                 if (size == null || size.getWidth() * size.getHeight() <= 0) {
   1424                     continue;
   1425                 }
   1426                 Range<Long> range = Utils.parseLongRange(map.get(key), null);
   1427                 if (range == null || range.getLower() < 0 || range.getUpper() < 0) {
   1428                     continue;
   1429                 }
   1430                 ret.put(size, range);
   1431             }
   1432             return ret;
   1433         }
   1434 
   1435         private void parseFromInfo(MediaFormat info) {
   1436             final Map<String, Object> map = info.getMap();
   1437             Size blockSize = new Size(mBlockWidth, mBlockHeight);
   1438             Size alignment = new Size(mWidthAlignment, mHeightAlignment);
   1439             Range<Integer> counts = null, widths = null, heights = null;
   1440             Range<Integer> frameRates = null, bitRates = null;
   1441             Range<Long> blockRates = null;
   1442             Range<Rational> ratios = null, blockRatios = null;
   1443 
   1444             blockSize = Utils.parseSize(map.get("block-size"), blockSize);
   1445             alignment = Utils.parseSize(map.get("alignment"), alignment);
   1446             counts = Utils.parseIntRange(map.get("block-count-range"), null);
   1447             blockRates =
   1448                 Utils.parseLongRange(map.get("blocks-per-second-range"), null);
   1449             mMeasuredFrameRates = getMeasuredFrameRates(map);
   1450             {
   1451                 Object o = map.get("size-range");
   1452                 Pair<Size, Size> sizeRange = Utils.parseSizeRange(o);
   1453                 if (sizeRange != null) {
   1454                     try {
   1455                         widths = Range.create(
   1456                                 sizeRange.first.getWidth(),
   1457                                 sizeRange.second.getWidth());
   1458                         heights = Range.create(
   1459                                 sizeRange.first.getHeight(),
   1460                                 sizeRange.second.getHeight());
   1461                     } catch (IllegalArgumentException e) {
   1462                         Log.w(TAG, "could not parse size range '" + o + "'");
   1463                         widths = null;
   1464                         heights = null;
   1465                     }
   1466                 }
   1467             }
   1468             // for now this just means using the smaller max size as 2nd
   1469             // upper limit.
   1470             // for now we are keeping the profile specific "width/height
   1471             // in macroblocks" limits.
   1472             if (map.containsKey("feature-can-swap-width-height")) {
   1473                 if (widths != null) {
   1474                     mSmallerDimensionUpperLimit =
   1475                         Math.min(widths.getUpper(), heights.getUpper());
   1476                     widths = heights = widths.extend(heights);
   1477                 } else {
   1478                     Log.w(TAG, "feature can-swap-width-height is best used with size-range");
   1479                     mSmallerDimensionUpperLimit =
   1480                         Math.min(mWidthRange.getUpper(), mHeightRange.getUpper());
   1481                     mWidthRange = mHeightRange = mWidthRange.extend(mHeightRange);
   1482                 }
   1483             }
   1484 
   1485             ratios = Utils.parseRationalRange(
   1486                     map.get("block-aspect-ratio-range"), null);
   1487             blockRatios = Utils.parseRationalRange(
   1488                     map.get("pixel-aspect-ratio-range"), null);
   1489             frameRates = Utils.parseIntRange(map.get("frame-rate-range"), null);
   1490             if (frameRates != null) {
   1491                 try {
   1492                     frameRates = frameRates.intersect(FRAME_RATE_RANGE);
   1493                 } catch (IllegalArgumentException e) {
   1494                     Log.w(TAG, "frame rate range (" + frameRates
   1495                             + ") is out of limits: " + FRAME_RATE_RANGE);
   1496                     frameRates = null;
   1497                 }
   1498             }
   1499             bitRates = Utils.parseIntRange(map.get("bitrate-range"), null);
   1500             if (bitRates != null) {
   1501                 try {
   1502                     bitRates = bitRates.intersect(BITRATE_RANGE);
   1503                 } catch (IllegalArgumentException e) {
   1504                     Log.w(TAG,  "bitrate range (" + bitRates
   1505                             + ") is out of limits: " + BITRATE_RANGE);
   1506                     bitRates = null;
   1507                 }
   1508             }
   1509 
   1510             checkPowerOfTwo(
   1511                     blockSize.getWidth(), "block-size width must be power of two");
   1512             checkPowerOfTwo(
   1513                     blockSize.getHeight(), "block-size height must be power of two");
   1514 
   1515             checkPowerOfTwo(
   1516                     alignment.getWidth(), "alignment width must be power of two");
   1517             checkPowerOfTwo(
   1518                     alignment.getHeight(), "alignment height must be power of two");
   1519 
   1520             // update block-size and alignment
   1521             applyMacroBlockLimits(
   1522                     Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE,
   1523                     Long.MAX_VALUE, blockSize.getWidth(), blockSize.getHeight(),
   1524                     alignment.getWidth(), alignment.getHeight());
   1525 
   1526             if ((mParent.mError & ERROR_UNSUPPORTED) != 0) {
   1527                 // codec supports profiles that we don't know.
   1528                 // Use supplied values clipped to platform limits
   1529                 if (widths != null) {
   1530                     mWidthRange = SIZE_RANGE.intersect(widths);
   1531                 }
   1532                 if (heights != null) {
   1533                     mHeightRange = SIZE_RANGE.intersect(heights);
   1534                 }
   1535                 if (counts != null) {
   1536                     mBlockCountRange = POSITIVE_INTEGERS.intersect(
   1537                             Utils.factorRange(counts, mBlockWidth * mBlockHeight
   1538                                     / blockSize.getWidth() / blockSize.getHeight()));
   1539                 }
   1540                 if (blockRates != null) {
   1541                     mBlocksPerSecondRange = POSITIVE_LONGS.intersect(
   1542                             Utils.factorRange(blockRates, mBlockWidth * mBlockHeight
   1543                                     / blockSize.getWidth() / blockSize.getHeight()));
   1544                 }
   1545                 if (blockRatios != null) {
   1546                     mBlockAspectRatioRange = POSITIVE_RATIONALS.intersect(
   1547                             Utils.scaleRange(blockRatios,
   1548                                     mBlockHeight / blockSize.getHeight(),
   1549                                     mBlockWidth / blockSize.getWidth()));
   1550                 }
   1551                 if (ratios != null) {
   1552                     mAspectRatioRange = POSITIVE_RATIONALS.intersect(ratios);
   1553                 }
   1554                 if (frameRates != null) {
   1555                     mFrameRateRange = FRAME_RATE_RANGE.intersect(frameRates);
   1556                 }
   1557                 if (bitRates != null) {
   1558                     mBitrateRange = BITRATE_RANGE.intersect(bitRates);
   1559                 }
   1560             } else {
   1561                 // no unsupported profile/levels, so restrict values to known limits
   1562                 if (widths != null) {
   1563                     mWidthRange = mWidthRange.intersect(widths);
   1564                 }
   1565                 if (heights != null) {
   1566                     mHeightRange = mHeightRange.intersect(heights);
   1567                 }
   1568                 if (counts != null) {
   1569                     mBlockCountRange = mBlockCountRange.intersect(
   1570                             Utils.factorRange(counts, mBlockWidth * mBlockHeight
   1571                                     / blockSize.getWidth() / blockSize.getHeight()));
   1572                 }
   1573                 if (blockRates != null) {
   1574                     mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(
   1575                             Utils.factorRange(blockRates, mBlockWidth * mBlockHeight
   1576                                     / blockSize.getWidth() / blockSize.getHeight()));
   1577                 }
   1578                 if (blockRatios != null) {
   1579                     mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(
   1580                             Utils.scaleRange(blockRatios,
   1581                                     mBlockHeight / blockSize.getHeight(),
   1582                                     mBlockWidth / blockSize.getWidth()));
   1583                 }
   1584                 if (ratios != null) {
   1585                     mAspectRatioRange = mAspectRatioRange.intersect(ratios);
   1586                 }
   1587                 if (frameRates != null) {
   1588                     mFrameRateRange = mFrameRateRange.intersect(frameRates);
   1589                 }
   1590                 if (bitRates != null) {
   1591                     mBitrateRange = mBitrateRange.intersect(bitRates);
   1592                 }
   1593             }
   1594             updateLimits();
   1595         }
   1596 
   1597         private void applyBlockLimits(
   1598                 int blockWidth, int blockHeight,
   1599                 Range<Integer> counts, Range<Long> rates, Range<Rational> ratios) {
   1600             checkPowerOfTwo(blockWidth, "blockWidth must be a power of two");
   1601             checkPowerOfTwo(blockHeight, "blockHeight must be a power of two");
   1602 
   1603             final int newBlockWidth = Math.max(blockWidth, mBlockWidth);
   1604             final int newBlockHeight = Math.max(blockHeight, mBlockHeight);
   1605 
   1606             // factor will always be a power-of-2
   1607             int factor =
   1608                 newBlockWidth * newBlockHeight / mBlockWidth / mBlockHeight;
   1609             if (factor != 1) {
   1610                 mBlockCountRange = Utils.factorRange(mBlockCountRange, factor);
   1611                 mBlocksPerSecondRange = Utils.factorRange(
   1612                         mBlocksPerSecondRange, factor);
   1613                 mBlockAspectRatioRange = Utils.scaleRange(
   1614                         mBlockAspectRatioRange,
   1615                         newBlockHeight / mBlockHeight,
   1616                         newBlockWidth / mBlockWidth);
   1617                 mHorizontalBlockRange = Utils.factorRange(
   1618                         mHorizontalBlockRange, newBlockWidth / mBlockWidth);
   1619                 mVerticalBlockRange = Utils.factorRange(
   1620                         mVerticalBlockRange, newBlockHeight / mBlockHeight);
   1621             }
   1622             factor = newBlockWidth * newBlockHeight / blockWidth / blockHeight;
   1623             if (factor != 1) {
   1624                 counts = Utils.factorRange(counts, factor);
   1625                 rates = Utils.factorRange(rates, factor);
   1626                 ratios = Utils.scaleRange(
   1627                         ratios, newBlockHeight / blockHeight,
   1628                         newBlockWidth / blockWidth);
   1629             }
   1630             mBlockCountRange = mBlockCountRange.intersect(counts);
   1631             mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(rates);
   1632             mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(ratios);
   1633             mBlockWidth = newBlockWidth;
   1634             mBlockHeight = newBlockHeight;
   1635         }
   1636 
   1637         private void applyAlignment(int widthAlignment, int heightAlignment) {
   1638             checkPowerOfTwo(widthAlignment, "widthAlignment must be a power of two");
   1639             checkPowerOfTwo(heightAlignment, "heightAlignment must be a power of two");
   1640 
   1641             if (widthAlignment > mBlockWidth || heightAlignment > mBlockHeight) {
   1642                 // maintain assumption that 0 < alignment <= block-size
   1643                 applyBlockLimits(
   1644                         Math.max(widthAlignment, mBlockWidth),
   1645                         Math.max(heightAlignment, mBlockHeight),
   1646                         POSITIVE_INTEGERS, POSITIVE_LONGS, POSITIVE_RATIONALS);
   1647             }
   1648 
   1649             mWidthAlignment = Math.max(widthAlignment, mWidthAlignment);
   1650             mHeightAlignment = Math.max(heightAlignment, mHeightAlignment);
   1651 
   1652             mWidthRange = Utils.alignRange(mWidthRange, mWidthAlignment);
   1653             mHeightRange = Utils.alignRange(mHeightRange, mHeightAlignment);
   1654         }
   1655 
   1656         private void updateLimits() {
   1657             // pixels -> blocks <- counts
   1658             mHorizontalBlockRange = mHorizontalBlockRange.intersect(
   1659                     Utils.factorRange(mWidthRange, mBlockWidth));
   1660             mHorizontalBlockRange = mHorizontalBlockRange.intersect(
   1661                     Range.create(
   1662                             mBlockCountRange.getLower() / mVerticalBlockRange.getUpper(),
   1663                             mBlockCountRange.getUpper() / mVerticalBlockRange.getLower()));
   1664             mVerticalBlockRange = mVerticalBlockRange.intersect(
   1665                     Utils.factorRange(mHeightRange, mBlockHeight));
   1666             mVerticalBlockRange = mVerticalBlockRange.intersect(
   1667                     Range.create(
   1668                             mBlockCountRange.getLower() / mHorizontalBlockRange.getUpper(),
   1669                             mBlockCountRange.getUpper() / mHorizontalBlockRange.getLower()));
   1670             mBlockCountRange = mBlockCountRange.intersect(
   1671                     Range.create(
   1672                             mHorizontalBlockRange.getLower()
   1673                                     * mVerticalBlockRange.getLower(),
   1674                             mHorizontalBlockRange.getUpper()
   1675                                     * mVerticalBlockRange.getUpper()));
   1676             mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(
   1677                     new Rational(
   1678                             mHorizontalBlockRange.getLower(), mVerticalBlockRange.getUpper()),
   1679                     new Rational(
   1680                             mHorizontalBlockRange.getUpper(), mVerticalBlockRange.getLower()));
   1681 
   1682             // blocks -> pixels
   1683             mWidthRange = mWidthRange.intersect(
   1684                     (mHorizontalBlockRange.getLower() - 1) * mBlockWidth + mWidthAlignment,
   1685                     mHorizontalBlockRange.getUpper() * mBlockWidth);
   1686             mHeightRange = mHeightRange.intersect(
   1687                     (mVerticalBlockRange.getLower() - 1) * mBlockHeight + mHeightAlignment,
   1688                     mVerticalBlockRange.getUpper() * mBlockHeight);
   1689             mAspectRatioRange = mAspectRatioRange.intersect(
   1690                     new Rational(mWidthRange.getLower(), mHeightRange.getUpper()),
   1691                     new Rational(mWidthRange.getUpper(), mHeightRange.getLower()));
   1692 
   1693             mSmallerDimensionUpperLimit = Math.min(
   1694                     mSmallerDimensionUpperLimit,
   1695                     Math.min(mWidthRange.getUpper(), mHeightRange.getUpper()));
   1696 
   1697             // blocks -> rate
   1698             mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(
   1699                     mBlockCountRange.getLower() * (long)mFrameRateRange.getLower(),
   1700                     mBlockCountRange.getUpper() * (long)mFrameRateRange.getUpper());
   1701             mFrameRateRange = mFrameRateRange.intersect(
   1702                     (int)(mBlocksPerSecondRange.getLower()
   1703                             / mBlockCountRange.getUpper()),
   1704                     (int)(mBlocksPerSecondRange.getUpper()
   1705                             / (double)mBlockCountRange.getLower()));
   1706         }
   1707 
   1708         private void applyMacroBlockLimits(
   1709                 int maxHorizontalBlocks, int maxVerticalBlocks,
   1710                 int maxBlocks, long maxBlocksPerSecond,
   1711                 int blockWidth, int blockHeight,
   1712                 int widthAlignment, int heightAlignment) {
   1713             applyAlignment(widthAlignment, heightAlignment);
   1714             applyBlockLimits(
   1715                     blockWidth, blockHeight, Range.create(1, maxBlocks),
   1716                     Range.create(1L, maxBlocksPerSecond),
   1717                     Range.create(
   1718                             new Rational(1, maxVerticalBlocks),
   1719                             new Rational(maxHorizontalBlocks, 1)));
   1720             mHorizontalBlockRange =
   1721                     mHorizontalBlockRange.intersect(
   1722                             1, maxHorizontalBlocks / (mBlockWidth / blockWidth));
   1723             mVerticalBlockRange =
   1724                     mVerticalBlockRange.intersect(
   1725                             1, maxVerticalBlocks / (mBlockHeight / blockHeight));
   1726         }
   1727 
   1728         private void applyLevelLimits() {
   1729             int maxBlocksPerSecond = 0;
   1730             int maxBlocks = 0;
   1731             int maxBps = 0;
   1732             int maxDPBBlocks = 0;
   1733 
   1734             int errors = ERROR_NONE_SUPPORTED;
   1735             CodecProfileLevel[] profileLevels = mParent.profileLevels;
   1736             String mime = mParent.getMimeType();
   1737 
   1738             if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC)) {
   1739                 maxBlocks = 99;
   1740                 maxBlocksPerSecond = 1485;
   1741                 maxBps = 64000;
   1742                 maxDPBBlocks = 396;
   1743                 for (CodecProfileLevel profileLevel: profileLevels) {
   1744                     int MBPS = 0, FS = 0, BR = 0, DPB = 0;
   1745                     boolean supported = true;
   1746                     switch (profileLevel.level) {
   1747                         case CodecProfileLevel.AVCLevel1:
   1748                             MBPS =    1485; FS =    99; BR =     64; DPB =    396; break;
   1749                         case CodecProfileLevel.AVCLevel1b:
   1750                             MBPS =    1485; FS =    99; BR =    128; DPB =    396; break;
   1751                         case CodecProfileLevel.AVCLevel11:
   1752                             MBPS =    3000; FS =   396; BR =    192; DPB =    900; break;
   1753                         case CodecProfileLevel.AVCLevel12:
   1754                             MBPS =    6000; FS =   396; BR =    384; DPB =   2376; break;
   1755                         case CodecProfileLevel.AVCLevel13:
   1756                             MBPS =   11880; FS =   396; BR =    768; DPB =   2376; break;
   1757                         case CodecProfileLevel.AVCLevel2:
   1758                             MBPS =   11880; FS =   396; BR =   2000; DPB =   2376; break;
   1759                         case CodecProfileLevel.AVCLevel21:
   1760                             MBPS =   19800; FS =   792; BR =   4000; DPB =   4752; break;
   1761                         case CodecProfileLevel.AVCLevel22:
   1762                             MBPS =   20250; FS =  1620; BR =   4000; DPB =   8100; break;
   1763                         case CodecProfileLevel.AVCLevel3:
   1764                             MBPS =   40500; FS =  1620; BR =  10000; DPB =   8100; break;
   1765                         case CodecProfileLevel.AVCLevel31:
   1766                             MBPS =  108000; FS =  3600; BR =  14000; DPB =  18000; break;
   1767                         case CodecProfileLevel.AVCLevel32:
   1768                             MBPS =  216000; FS =  5120; BR =  20000; DPB =  20480; break;
   1769                         case CodecProfileLevel.AVCLevel4:
   1770                             MBPS =  245760; FS =  8192; BR =  20000; DPB =  32768; break;
   1771                         case CodecProfileLevel.AVCLevel41:
   1772                             MBPS =  245760; FS =  8192; BR =  50000; DPB =  32768; break;
   1773                         case CodecProfileLevel.AVCLevel42:
   1774                             MBPS =  522240; FS =  8704; BR =  50000; DPB =  34816; break;
   1775                         case CodecProfileLevel.AVCLevel5:
   1776                             MBPS =  589824; FS = 22080; BR = 135000; DPB = 110400; break;
   1777                         case CodecProfileLevel.AVCLevel51:
   1778                             MBPS =  983040; FS = 36864; BR = 240000; DPB = 184320; break;
   1779                         case CodecProfileLevel.AVCLevel52:
   1780                             MBPS = 2073600; FS = 36864; BR = 240000; DPB = 184320; break;
   1781                         default:
   1782                             Log.w(TAG, "Unrecognized level "
   1783                                     + profileLevel.level + " for " + mime);
   1784                             errors |= ERROR_UNRECOGNIZED;
   1785                     }
   1786                     switch (profileLevel.profile) {
   1787                         case CodecProfileLevel.AVCProfileHigh:
   1788                             BR *= 1250; break;
   1789                         case CodecProfileLevel.AVCProfileHigh10:
   1790                             BR *= 3000; break;
   1791                         case CodecProfileLevel.AVCProfileExtended:
   1792                         case CodecProfileLevel.AVCProfileHigh422:
   1793                         case CodecProfileLevel.AVCProfileHigh444:
   1794                             Log.w(TAG, "Unsupported profile "
   1795                                     + profileLevel.profile + " for " + mime);
   1796                             errors |= ERROR_UNSUPPORTED;
   1797                             supported = false;
   1798                             // fall through - treat as base profile
   1799                         case CodecProfileLevel.AVCProfileBaseline:
   1800                         case CodecProfileLevel.AVCProfileMain:
   1801                             BR *= 1000; break;
   1802                         default:
   1803                             Log.w(TAG, "Unrecognized profile "
   1804                                     + profileLevel.profile + " for " + mime);
   1805                             errors |= ERROR_UNRECOGNIZED;
   1806                             BR *= 1000;
   1807                     }
   1808                     if (supported) {
   1809                         errors &= ~ERROR_NONE_SUPPORTED;
   1810                     }
   1811                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
   1812                     maxBlocks = Math.max(FS, maxBlocks);
   1813                     maxBps = Math.max(BR, maxBps);
   1814                     maxDPBBlocks = Math.max(maxDPBBlocks, DPB);
   1815                 }
   1816 
   1817                 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8));
   1818                 applyMacroBlockLimits(
   1819                         maxLengthInBlocks, maxLengthInBlocks,
   1820                         maxBlocks, maxBlocksPerSecond,
   1821                         16 /* blockWidth */, 16 /* blockHeight */,
   1822                         1 /* widthAlignment */, 1 /* heightAlignment */);
   1823             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG2)) {
   1824                 int maxWidth = 11, maxHeight = 9, maxRate = 15;
   1825                 maxBlocks = 99;
   1826                 maxBlocksPerSecond = 1485;
   1827                 maxBps = 64000;
   1828                 for (CodecProfileLevel profileLevel: profileLevels) {
   1829                     int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0;
   1830                     boolean supported = true;
   1831                     switch (profileLevel.profile) {
   1832                         case CodecProfileLevel.MPEG2ProfileSimple:
   1833                             switch (profileLevel.level) {
   1834                                 case CodecProfileLevel.MPEG2LevelML:
   1835                                     FR = 30; W = 45; H =  36; MBPS =  48600; FS =  1620; BR =  15000; break;
   1836                                 default:
   1837                                     Log.w(TAG, "Unrecognized profile/level "
   1838                                             + profileLevel.profile + "/"
   1839                                             + profileLevel.level + " for " + mime);
   1840                                     errors |= ERROR_UNRECOGNIZED;
   1841                             }
   1842                             break;
   1843                         case CodecProfileLevel.MPEG2ProfileMain:
   1844                             switch (profileLevel.level) {
   1845                                 case CodecProfileLevel.MPEG2LevelLL:
   1846                                     FR = 30; W = 22; H =  18; MBPS =  11880; FS =  396; BR =  4000; break;
   1847                                 case CodecProfileLevel.MPEG2LevelML:
   1848                                     FR = 30; W = 45; H =  36; MBPS =  48600; FS =  1620; BR =  15000; break;
   1849                                 case CodecProfileLevel.MPEG2LevelH14:
   1850                                     FR = 60; W = 90; H =  68; MBPS =  367200; FS =  6120; BR = 60000; break;
   1851                                 case CodecProfileLevel.MPEG2LevelHL:
   1852                                     FR = 60; W = 120; H = 68; MBPS =  489600; FS =  8160; BR = 80000; break;
   1853                                 default:
   1854                                     Log.w(TAG, "Unrecognized profile/level "
   1855                                             + profileLevel.profile + "/"
   1856                                             + profileLevel.level + " for " + mime);
   1857                                     errors |= ERROR_UNRECOGNIZED;
   1858                             }
   1859                             break;
   1860                         case CodecProfileLevel.MPEG2Profile422:
   1861                         case CodecProfileLevel.MPEG2ProfileSNR:
   1862                         case CodecProfileLevel.MPEG2ProfileSpatial:
   1863                         case CodecProfileLevel.MPEG2ProfileHigh:
   1864                             Log.i(TAG, "Unsupported profile "
   1865                                     + profileLevel.profile + " for " + mime);
   1866                             errors |= ERROR_UNSUPPORTED;
   1867                             supported = false;
   1868                             break;
   1869                         default:
   1870                             Log.w(TAG, "Unrecognized profile "
   1871                                     + profileLevel.profile + " for " + mime);
   1872                             errors |= ERROR_UNRECOGNIZED;
   1873                     }
   1874                     if (supported) {
   1875                         errors &= ~ERROR_NONE_SUPPORTED;
   1876                     }
   1877                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
   1878                     maxBlocks = Math.max(FS, maxBlocks);
   1879                     maxBps = Math.max(BR * 1000, maxBps);
   1880                     maxWidth = Math.max(W, maxWidth);
   1881                     maxHeight = Math.max(H, maxHeight);
   1882                     maxRate = Math.max(FR, maxRate);
   1883                 }
   1884                 applyMacroBlockLimits(maxWidth, maxHeight,
   1885                         maxBlocks, maxBlocksPerSecond,
   1886                         16 /* blockWidth */, 16 /* blockHeight */,
   1887                         1 /* widthAlignment */, 1 /* heightAlignment */);
   1888                 mFrameRateRange = mFrameRateRange.intersect(12, maxRate);
   1889             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) {
   1890                 int maxWidth = 11, maxHeight = 9, maxRate = 15;
   1891                 maxBlocks = 99;
   1892                 maxBlocksPerSecond = 1485;
   1893                 maxBps = 64000;
   1894                 for (CodecProfileLevel profileLevel: profileLevels) {
   1895                     int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0;
   1896                     boolean supported = true;
   1897                     switch (profileLevel.profile) {
   1898                         case CodecProfileLevel.MPEG4ProfileSimple:
   1899                             switch (profileLevel.level) {
   1900                                 case CodecProfileLevel.MPEG4Level0:
   1901                                     FR = 15; W = 11; H =  9; MBPS =  1485; FS =  99; BR =  64; break;
   1902                                 case CodecProfileLevel.MPEG4Level1:
   1903                                     FR = 30; W = 11; H =  9; MBPS =  1485; FS =  99; BR =  64; break;
   1904                                 case CodecProfileLevel.MPEG4Level0b:
   1905                                     FR = 30; W = 11; H =  9; MBPS =  1485; FS =  99; BR = 128; break;
   1906                                 case CodecProfileLevel.MPEG4Level2:
   1907                                     FR = 30; W = 22; H = 18; MBPS =  5940; FS = 396; BR = 128; break;
   1908                                 case CodecProfileLevel.MPEG4Level3:
   1909                                     FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384; break;
   1910                                 case CodecProfileLevel.MPEG4Level4:
   1911                                 case CodecProfileLevel.MPEG4Level4a:
   1912                                 case CodecProfileLevel.MPEG4Level5:
   1913                                     // While MPEG4 SP does not have level 4 or 5, some vendors
   1914                                     // report it. Use the same limits as level 3, but mark as
   1915                                     // unsupported.
   1916                                     FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384;
   1917                                     supported = false;
   1918                                     break;
   1919                                 default:
   1920                                     Log.w(TAG, "Unrecognized profile/level "
   1921                                             + profileLevel.profile + "/"
   1922                                             + profileLevel.level + " for " + mime);
   1923                                     errors |= ERROR_UNRECOGNIZED;
   1924                             }
   1925                             break;
   1926                         case CodecProfileLevel.MPEG4ProfileAdvancedSimple:
   1927                             switch (profileLevel.level) {
   1928                                 case CodecProfileLevel.MPEG4Level0:
   1929                                 case CodecProfileLevel.MPEG4Level1:
   1930                                     FR = 30; W = 11; H =  9; MBPS =  2970; FS =   99; BR =  128; break;
   1931                                 case CodecProfileLevel.MPEG4Level2:
   1932                                     FR = 30; W = 22; H = 18; MBPS =  5940; FS =  396; BR =  384; break;
   1933                                 case CodecProfileLevel.MPEG4Level3:
   1934                                     FR = 30; W = 22; H = 18; MBPS = 11880; FS =  396; BR =  768; break;
   1935                                 // case CodecProfileLevel.MPEG4Level3b:
   1936                                 // TODO: MPEG4 level 3b is not defined in OMX
   1937                                 //  MBPS = 11880; FS =  396; BR = 1500; break;
   1938                                 case CodecProfileLevel.MPEG4Level4:
   1939                                 case CodecProfileLevel.MPEG4Level4a:
   1940                                     // TODO: MPEG4 level 4a is not defined in spec
   1941                                     FR = 30; W = 44; H = 36; MBPS = 23760; FS =  792; BR = 3000; break;
   1942                                 case CodecProfileLevel.MPEG4Level5:
   1943                                     FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 8000; break;
   1944                                 default:
   1945                                     Log.w(TAG, "Unrecognized profile/level "
   1946                                             + profileLevel.profile + "/"
   1947                                             + profileLevel.level + " for " + mime);
   1948                                     errors |= ERROR_UNRECOGNIZED;
   1949                             }
   1950                             break;
   1951                         case CodecProfileLevel.MPEG4ProfileMain:             // 2-4
   1952                         case CodecProfileLevel.MPEG4ProfileNbit:             // 2
   1953                         case CodecProfileLevel.MPEG4ProfileAdvancedRealTime: // 1-4
   1954                         case CodecProfileLevel.MPEG4ProfileCoreScalable:     // 1-3
   1955                         case CodecProfileLevel.MPEG4ProfileAdvancedCoding:   // 1-4
   1956                         case CodecProfileLevel.MPEG4ProfileCore:             // 1-2
   1957                         case CodecProfileLevel.MPEG4ProfileAdvancedCore:     // 1-4
   1958                         case CodecProfileLevel.MPEG4ProfileSimpleScalable:   // 0-2
   1959                         case CodecProfileLevel.MPEG4ProfileAdvancedScalable: // 1-3
   1960                         case CodecProfileLevel.MPEG4ProfileHybrid:           // 1-2
   1961                         case CodecProfileLevel.MPEG4ProfileBasicAnimated:    // 1-2
   1962                         case CodecProfileLevel.MPEG4ProfileScalableTexture:  // 1
   1963                         case CodecProfileLevel.MPEG4ProfileSimpleFace:       // 1-2
   1964                         case CodecProfileLevel.MPEG4ProfileSimpleFBA:        // 1-2
   1965                             Log.i(TAG, "Unsupported profile "
   1966                                     + profileLevel.profile + " for " + mime);
   1967                             errors |= ERROR_UNSUPPORTED;
   1968                             supported = false;
   1969                             break;
   1970                         default:
   1971                             Log.w(TAG, "Unrecognized profile "
   1972                                     + profileLevel.profile + " for " + mime);
   1973                             errors |= ERROR_UNRECOGNIZED;
   1974                     }
   1975                     if (supported) {
   1976                         errors &= ~ERROR_NONE_SUPPORTED;
   1977                     }
   1978                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
   1979                     maxBlocks = Math.max(FS, maxBlocks);
   1980                     maxBps = Math.max(BR * 1000, maxBps);
   1981                     maxWidth = Math.max(W, maxWidth);
   1982                     maxHeight = Math.max(H, maxHeight);
   1983                     maxRate = Math.max(FR, maxRate);
   1984                 }
   1985                 applyMacroBlockLimits(maxWidth, maxHeight,
   1986                         maxBlocks, maxBlocksPerSecond,
   1987                         16 /* blockWidth */, 16 /* blockHeight */,
   1988                         1 /* widthAlignment */, 1 /* heightAlignment */);
   1989                 mFrameRateRange = mFrameRateRange.intersect(12, maxRate);
   1990             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) {
   1991                 int maxWidth = 11, maxHeight = 9, maxRate = 15;
   1992                 maxBlocks = 99;
   1993                 maxBlocksPerSecond = 1485;
   1994                 maxBps = 64000;
   1995                 for (CodecProfileLevel profileLevel: profileLevels) {
   1996                     int MBPS = 0, BR = 0, FR = 0, W = 0, H = 0;
   1997                     switch (profileLevel.level) {
   1998                         case CodecProfileLevel.H263Level10:
   1999                             FR = 15; W = 11; H =  9; BR =   1; MBPS =  W * H * FR; break;
   2000                         case CodecProfileLevel.H263Level20:
   2001                             // only supports CIF, 0..QCIF
   2002                             FR = 30; W = 22; H = 18; BR =   2; MBPS =  W * H * FR; break;
   2003                         case CodecProfileLevel.H263Level30:
   2004                             // only supports CIF, 0..QCIF
   2005                             FR = 30; W = 22; H = 18; BR =   6; MBPS =  W * H * FR; break;
   2006                         case CodecProfileLevel.H263Level40:
   2007                             // only supports CIF, 0..QCIF
   2008                             FR = 30; W = 22; H = 18; BR =  32; MBPS =  W * H * FR; break;
   2009                         case CodecProfileLevel.H263Level45:
   2010                             // only implies level 10 support
   2011                             FR = 30; W = 11; H =  9; BR =   2; MBPS =  W * H * FR; break;
   2012                         case CodecProfileLevel.H263Level50:
   2013                             // only supports 50fps for H > 15
   2014                             FR = 60; W = 22; H = 18; BR =  64; MBPS =  W * H * 50; break;
   2015                         case CodecProfileLevel.H263Level60:
   2016                             // only supports 50fps for H > 15
   2017                             FR = 60; W = 45; H = 18; BR = 128; MBPS =  W * H * 50; break;
   2018                         case CodecProfileLevel.H263Level70:
   2019                             // only supports 50fps for H > 30
   2020                             FR = 60; W = 45; H = 36; BR = 256; MBPS =  W * H * 50; break;
   2021                         default:
   2022                             Log.w(TAG, "Unrecognized profile/level " + profileLevel.profile
   2023                                     + "/" + profileLevel.level + " for " + mime);
   2024                             errors |= ERROR_UNRECOGNIZED;
   2025                     }
   2026                     switch (profileLevel.profile) {
   2027                         case CodecProfileLevel.H263ProfileBackwardCompatible:
   2028                         case CodecProfileLevel.H263ProfileBaseline:
   2029                         case CodecProfileLevel.H263ProfileH320Coding:
   2030                         case CodecProfileLevel.H263ProfileHighCompression:
   2031                         case CodecProfileLevel.H263ProfileHighLatency:
   2032                         case CodecProfileLevel.H263ProfileInterlace:
   2033                         case CodecProfileLevel.H263ProfileInternet:
   2034                         case CodecProfileLevel.H263ProfileISWV2:
   2035                         case CodecProfileLevel.H263ProfileISWV3:
   2036                             break;
   2037                         default:
   2038                             Log.w(TAG, "Unrecognized profile "
   2039                                     + profileLevel.profile + " for " + mime);
   2040                             errors |= ERROR_UNRECOGNIZED;
   2041                     }
   2042                     errors &= ~ERROR_NONE_SUPPORTED;
   2043                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
   2044                     maxBlocks = Math.max(W * H, maxBlocks);
   2045                     maxBps = Math.max(BR * 64000, maxBps);
   2046                     maxWidth = Math.max(W, maxWidth);
   2047                     maxHeight = Math.max(H, maxHeight);
   2048                     maxRate = Math.max(FR, maxRate);
   2049                 }
   2050                 applyMacroBlockLimits(maxWidth, maxHeight,
   2051                         maxBlocks, maxBlocksPerSecond,
   2052                         16 /* blockWidth */, 16 /* blockHeight */,
   2053                         1 /* widthAlignment */, 1 /* heightAlignment */);
   2054                 mFrameRateRange = Range.create(1, maxRate);
   2055             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8) ||
   2056                     mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) {
   2057                 maxBlocks = maxBlocksPerSecond = Integer.MAX_VALUE;
   2058 
   2059                 // TODO: set to 100Mbps for now, need a number for VPX
   2060                 maxBps = 100000000;
   2061 
   2062                 // profile levels are not indicative for VPx, but verify
   2063                 // them nonetheless
   2064                 for (CodecProfileLevel profileLevel: profileLevels) {
   2065                     switch (profileLevel.level) {
   2066                         case CodecProfileLevel.VP8Level_Version0:
   2067                         case CodecProfileLevel.VP8Level_Version1:
   2068                         case CodecProfileLevel.VP8Level_Version2:
   2069                         case CodecProfileLevel.VP8Level_Version3:
   2070                             break;
   2071                         default:
   2072                             Log.w(TAG, "Unrecognized level "
   2073                                     + profileLevel.level + " for " + mime);
   2074                             errors |= ERROR_UNRECOGNIZED;
   2075                     }
   2076                     switch (profileLevel.profile) {
   2077                         case CodecProfileLevel.VP8ProfileMain:
   2078                             break;
   2079                         default:
   2080                             Log.w(TAG, "Unrecognized profile "
   2081                                     + profileLevel.profile + " for " + mime);
   2082                             errors |= ERROR_UNRECOGNIZED;
   2083                     }
   2084                     errors &= ~ERROR_NONE_SUPPORTED;
   2085                 }
   2086 
   2087                 final int blockSize =
   2088                     mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8) ? 16 : 8;
   2089                 applyMacroBlockLimits(Short.MAX_VALUE, Short.MAX_VALUE,
   2090                         maxBlocks, maxBlocksPerSecond, blockSize, blockSize,
   2091                         1 /* widthAlignment */, 1 /* heightAlignment */);
   2092             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
   2093                 maxBlocks = 36864;
   2094                 maxBlocksPerSecond = maxBlocks * 15;
   2095                 maxBps = 128000;
   2096                 for (CodecProfileLevel profileLevel: profileLevels) {
   2097                     double FR = 0;
   2098                     int FS = 0;
   2099                     int BR = 0;
   2100                     switch (profileLevel.level) {
   2101                         case CodecProfileLevel.HEVCMainTierLevel1:
   2102                         case CodecProfileLevel.HEVCHighTierLevel1:
   2103                             FR =    15; FS =    36864; BR =    128; break;
   2104                         case CodecProfileLevel.HEVCMainTierLevel2:
   2105                         case CodecProfileLevel.HEVCHighTierLevel2:
   2106                             FR =    30; FS =   122880; BR =   1500; break;
   2107                         case CodecProfileLevel.HEVCMainTierLevel21:
   2108                         case CodecProfileLevel.HEVCHighTierLevel21:
   2109                             FR =    30; FS =   245760; BR =   3000; break;
   2110                         case CodecProfileLevel.HEVCMainTierLevel3:
   2111                         case CodecProfileLevel.HEVCHighTierLevel3:
   2112                             FR =    30; FS =   552960; BR =   6000; break;
   2113                         case CodecProfileLevel.HEVCMainTierLevel31:
   2114                         case CodecProfileLevel.HEVCHighTierLevel31:
   2115                             FR = 33.75; FS =   983040; BR =  10000; break;
   2116                         case CodecProfileLevel.HEVCMainTierLevel4:
   2117                             FR =    30; FS =  2228224; BR =  12000; break;
   2118                         case CodecProfileLevel.HEVCHighTierLevel4:
   2119                             FR =    30; FS =  2228224; BR =  30000; break;
   2120                         case CodecProfileLevel.HEVCMainTierLevel41:
   2121                             FR =    60; FS =  2228224; BR =  20000; break;
   2122                         case CodecProfileLevel.HEVCHighTierLevel41:
   2123                             FR =    60; FS =  2228224; BR =  50000; break;
   2124                         case CodecProfileLevel.HEVCMainTierLevel5:
   2125                             FR =    30; FS =  8912896; BR =  25000; break;
   2126                         case CodecProfileLevel.HEVCHighTierLevel5:
   2127                             FR =    30; FS =  8912896; BR = 100000; break;
   2128                         case CodecProfileLevel.HEVCMainTierLevel51:
   2129                             FR =    60; FS =  8912896; BR =  40000; break;
   2130                         case CodecProfileLevel.HEVCHighTierLevel51:
   2131                             FR =    60; FS =  8912896; BR = 160000; break;
   2132                         case CodecProfileLevel.HEVCMainTierLevel52:
   2133                             FR =   120; FS =  8912896; BR =  60000; break;
   2134                         case CodecProfileLevel.HEVCHighTierLevel52:
   2135                             FR =   120; FS =  8912896; BR = 240000; break;
   2136                         case CodecProfileLevel.HEVCMainTierLevel6:
   2137                             FR =    30; FS = 35651584; BR =  60000; break;
   2138                         case CodecProfileLevel.HEVCHighTierLevel6:
   2139                             FR =    30; FS = 35651584; BR = 240000; break;
   2140                         case CodecProfileLevel.HEVCMainTierLevel61:
   2141                             FR =    60; FS = 35651584; BR = 120000; break;
   2142                         case CodecProfileLevel.HEVCHighTierLevel61:
   2143                             FR =    60; FS = 35651584; BR = 480000; break;
   2144                         case CodecProfileLevel.HEVCMainTierLevel62:
   2145                             FR =   120; FS = 35651584; BR = 240000; break;
   2146                         case CodecProfileLevel.HEVCHighTierLevel62:
   2147                             FR =   120; FS = 35651584; BR = 800000; break;
   2148                         default:
   2149                             Log.w(TAG, "Unrecognized level "
   2150                                     + profileLevel.level + " for " + mime);
   2151                             errors |= ERROR_UNRECOGNIZED;
   2152                     }
   2153                     switch (profileLevel.profile) {
   2154                         case CodecProfileLevel.HEVCProfileMain:
   2155                         case CodecProfileLevel.HEVCProfileMain10:
   2156                             break;
   2157                         default:
   2158                             Log.w(TAG, "Unrecognized profile "
   2159                                     + profileLevel.profile + " for " + mime);
   2160                             errors |= ERROR_UNRECOGNIZED;
   2161                     }
   2162 
   2163                     /* DPB logic:
   2164                     if      (width * height <= FS / 4)    DPB = 16;
   2165                     else if (width * height <= FS / 2)    DPB = 12;
   2166                     else if (width * height <= FS * 0.75) DPB = 8;
   2167                     else                                  DPB = 6;
   2168                     */
   2169 
   2170                     errors &= ~ERROR_NONE_SUPPORTED;
   2171                     maxBlocksPerSecond = Math.max((int)(FR * FS), maxBlocksPerSecond);
   2172                     maxBlocks = Math.max(FS, maxBlocks);
   2173                     maxBps = Math.max(BR * 1000, maxBps);
   2174                 }
   2175 
   2176                 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8));
   2177                 // CTBs are at least 8x8
   2178                 maxBlocks = Utils.divUp(maxBlocks, 8 * 8);
   2179                 maxBlocksPerSecond = Utils.divUp(maxBlocksPerSecond, 8 * 8);
   2180                 maxLengthInBlocks = Utils.divUp(maxLengthInBlocks, 8);
   2181 
   2182                 applyMacroBlockLimits(
   2183                         maxLengthInBlocks, maxLengthInBlocks,
   2184                         maxBlocks, maxBlocksPerSecond,
   2185                         8 /* blockWidth */, 8 /* blockHeight */,
   2186                         1 /* widthAlignment */, 1 /* heightAlignment */);
   2187             } else {
   2188                 Log.w(TAG, "Unsupported mime " + mime);
   2189                 // using minimal bitrate here.  should be overriden by
   2190                 // info from media_codecs.xml
   2191                 maxBps = 64000;
   2192                 errors |= ERROR_UNSUPPORTED;
   2193             }
   2194             mBitrateRange = Range.create(1, maxBps);
   2195             mParent.mError |= errors;
   2196         }
   2197     }
   2198 
   2199     /**
   2200      * A class that supports querying the encoding capabilities of a codec.
   2201      */
   2202     public static final class EncoderCapabilities {
   2203         /**
   2204          * Returns the supported range of quality values.
   2205          *
   2206          * @hide
   2207          */
   2208         public Range<Integer> getQualityRange() {
   2209             return mQualityRange;
   2210         }
   2211 
   2212         /**
   2213          * Returns the supported range of encoder complexity values.
   2214          * <p>
   2215          * Some codecs may support multiple complexity levels, where higher
   2216          * complexity values use more encoder tools (e.g. perform more
   2217          * intensive calculations) to improve the quality or the compression
   2218          * ratio.  Use a lower value to save power and/or time.
   2219          */
   2220         public Range<Integer> getComplexityRange() {
   2221             return mComplexityRange;
   2222         }
   2223 
   2224         /** Constant quality mode */
   2225         public static final int BITRATE_MODE_CQ = 0;
   2226         /** Variable bitrate mode */
   2227         public static final int BITRATE_MODE_VBR = 1;
   2228         /** Constant bitrate mode */
   2229         public static final int BITRATE_MODE_CBR = 2;
   2230 
   2231         private static final Feature[] bitrates = new Feature[] {
   2232             new Feature("VBR", BITRATE_MODE_VBR, true),
   2233             new Feature("CBR", BITRATE_MODE_CBR, false),
   2234             new Feature("CQ",  BITRATE_MODE_CQ,  false)
   2235         };
   2236 
   2237         private static int parseBitrateMode(String mode) {
   2238             for (Feature feat: bitrates) {
   2239                 if (feat.mName.equalsIgnoreCase(mode)) {
   2240                     return feat.mValue;
   2241                 }
   2242             }
   2243             return 0;
   2244         }
   2245 
   2246         /**
   2247          * Query whether a bitrate mode is supported.
   2248          */
   2249         public boolean isBitrateModeSupported(int mode) {
   2250             for (Feature feat: bitrates) {
   2251                 if (mode == feat.mValue) {
   2252                     return (mBitControl & (1 << mode)) != 0;
   2253                 }
   2254             }
   2255             return false;
   2256         }
   2257 
   2258         private Range<Integer> mQualityRange;
   2259         private Range<Integer> mComplexityRange;
   2260         private CodecCapabilities mParent;
   2261 
   2262         /* no public constructor */
   2263         private EncoderCapabilities() { }
   2264 
   2265         /** @hide */
   2266         public static EncoderCapabilities create(
   2267                 MediaFormat info, CodecCapabilities parent) {
   2268             EncoderCapabilities caps = new EncoderCapabilities();
   2269             caps.init(info, parent);
   2270             return caps;
   2271         }
   2272 
   2273         /** @hide */
   2274         public void init(MediaFormat info, CodecCapabilities parent) {
   2275             // no support for complexity or quality yet
   2276             mParent = parent;
   2277             mComplexityRange = Range.create(0, 0);
   2278             mQualityRange = Range.create(0, 0);
   2279             mBitControl = (1 << BITRATE_MODE_VBR);
   2280 
   2281             applyLevelLimits();
   2282             parseFromInfo(info);
   2283         }
   2284 
   2285         private void applyLevelLimits() {
   2286             String mime = mParent.getMimeType();
   2287             if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
   2288                 mComplexityRange = Range.create(0, 8);
   2289                 mBitControl = (1 << BITRATE_MODE_CQ);
   2290             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)
   2291                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)
   2292                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW)
   2293                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)
   2294                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) {
   2295                 mBitControl = (1 << BITRATE_MODE_CBR);
   2296             }
   2297         }
   2298 
   2299         private int mBitControl;
   2300         private Integer mDefaultComplexity;
   2301         private Integer mDefaultQuality;
   2302         private String mQualityScale;
   2303 
   2304         private void parseFromInfo(MediaFormat info) {
   2305             Map<String, Object> map = info.getMap();
   2306 
   2307             if (info.containsKey("complexity-range")) {
   2308                 mComplexityRange = Utils
   2309                         .parseIntRange(info.getString("complexity-range"), mComplexityRange);
   2310                 // TODO should we limit this to level limits?
   2311             }
   2312             if (info.containsKey("quality-range")) {
   2313                 mQualityRange = Utils
   2314                         .parseIntRange(info.getString("quality-range"), mQualityRange);
   2315             }
   2316             if (info.containsKey("feature-bitrate-control")) {
   2317                 for (String mode: info.getString("feature-bitrate-control").split(",")) {
   2318                     mBitControl |= parseBitrateMode(mode);
   2319                 }
   2320             }
   2321 
   2322             try {
   2323                 mDefaultComplexity = Integer.parseInt((String)map.get("complexity-default"));
   2324             } catch (NumberFormatException e) { }
   2325 
   2326             try {
   2327                 mDefaultQuality = Integer.parseInt((String)map.get("quality-default"));
   2328             } catch (NumberFormatException e) { }
   2329 
   2330             mQualityScale = (String)map.get("quality-scale");
   2331         }
   2332 
   2333         private boolean supports(
   2334                 Integer complexity, Integer quality, Integer profile) {
   2335             boolean ok = true;
   2336             if (ok && complexity != null) {
   2337                 ok = mComplexityRange.contains(complexity);
   2338             }
   2339             if (ok && quality != null) {
   2340                 ok = mQualityRange.contains(quality);
   2341             }
   2342             if (ok && profile != null) {
   2343                 for (CodecProfileLevel pl: mParent.profileLevels) {
   2344                     if (pl.profile == profile) {
   2345                         profile = null;
   2346                         break;
   2347                     }
   2348                 }
   2349                 ok = profile == null;
   2350             }
   2351             return ok;
   2352         }
   2353 
   2354         /** @hide */
   2355         public void setDefaultFormat(MediaFormat format) {
   2356             // don't list trivial quality/complexity as default for now
   2357             if (!mQualityRange.getUpper().equals(mQualityRange.getLower())
   2358                     && mDefaultQuality != null) {
   2359                 format.setInteger(MediaFormat.KEY_QUALITY, mDefaultQuality);
   2360             }
   2361             if (!mComplexityRange.getUpper().equals(mComplexityRange.getLower())
   2362                     && mDefaultComplexity != null) {
   2363                 format.setInteger(MediaFormat.KEY_COMPLEXITY, mDefaultComplexity);
   2364             }
   2365             // bitrates are listed in order of preference
   2366             for (Feature feat: bitrates) {
   2367                 if ((mBitControl & (1 << feat.mValue)) != 0) {
   2368                     format.setInteger(MediaFormat.KEY_BITRATE_MODE, feat.mValue);
   2369                     break;
   2370                 }
   2371             }
   2372         }
   2373 
   2374         /** @hide */
   2375         public boolean supportsFormat(MediaFormat format) {
   2376             final Map<String, Object> map = format.getMap();
   2377             final String mime = mParent.getMimeType();
   2378 
   2379             Integer mode = (Integer)map.get(MediaFormat.KEY_BITRATE_MODE);
   2380             if (mode != null && !isBitrateModeSupported(mode)) {
   2381                 return false;
   2382             }
   2383 
   2384             Integer complexity = (Integer)map.get(MediaFormat.KEY_COMPLEXITY);
   2385             if (MediaFormat.MIMETYPE_AUDIO_FLAC.equalsIgnoreCase(mime)) {
   2386                 Integer flacComplexity =
   2387                     (Integer)map.get(MediaFormat.KEY_FLAC_COMPRESSION_LEVEL);
   2388                 if (complexity == null) {
   2389                     complexity = flacComplexity;
   2390                 } else if (flacComplexity != null && !complexity.equals(flacComplexity)) {
   2391                     throw new IllegalArgumentException(
   2392                             "conflicting values for complexity and " +
   2393                             "flac-compression-level");
   2394                 }
   2395             }
   2396 
   2397             // other audio parameters
   2398             Integer profile = (Integer)map.get(MediaFormat.KEY_PROFILE);
   2399             if (MediaFormat.MIMETYPE_AUDIO_AAC.equalsIgnoreCase(mime)) {
   2400                 Integer aacProfile = (Integer)map.get(MediaFormat.KEY_AAC_PROFILE);
   2401                 if (profile == null) {
   2402                     profile = aacProfile;
   2403                 } else if (aacProfile != null && !aacProfile.equals(profile)) {
   2404                     throw new IllegalArgumentException(
   2405                             "conflicting values for profile and aac-profile");
   2406                 }
   2407             }
   2408 
   2409             Integer quality = (Integer)map.get(MediaFormat.KEY_QUALITY);
   2410 
   2411             return supports(complexity, quality, profile);
   2412         }
   2413     };
   2414 
   2415     /**
   2416      * Encapsulates the profiles available for a codec component.
   2417      * <p>You can get a set of {@link MediaCodecInfo.CodecProfileLevel} objects for a given
   2418      * {@link MediaCodecInfo} object from the
   2419      * {@link MediaCodecInfo.CodecCapabilities#profileLevels} field.
   2420      */
   2421     public static final class CodecProfileLevel {
   2422         // from OMX_VIDEO_AVCPROFILETYPE
   2423         public static final int AVCProfileBaseline = 0x01;
   2424         public static final int AVCProfileMain     = 0x02;
   2425         public static final int AVCProfileExtended = 0x04;
   2426         public static final int AVCProfileHigh     = 0x08;
   2427         public static final int AVCProfileHigh10   = 0x10;
   2428         public static final int AVCProfileHigh422  = 0x20;
   2429         public static final int AVCProfileHigh444  = 0x40;
   2430 
   2431         // from OMX_VIDEO_AVCLEVELTYPE
   2432         public static final int AVCLevel1       = 0x01;
   2433         public static final int AVCLevel1b      = 0x02;
   2434         public static final int AVCLevel11      = 0x04;
   2435         public static final int AVCLevel12      = 0x08;
   2436         public static final int AVCLevel13      = 0x10;
   2437         public static final int AVCLevel2       = 0x20;
   2438         public static final int AVCLevel21      = 0x40;
   2439         public static final int AVCLevel22      = 0x80;
   2440         public static final int AVCLevel3       = 0x100;
   2441         public static final int AVCLevel31      = 0x200;
   2442         public static final int AVCLevel32      = 0x400;
   2443         public static final int AVCLevel4       = 0x800;
   2444         public static final int AVCLevel41      = 0x1000;
   2445         public static final int AVCLevel42      = 0x2000;
   2446         public static final int AVCLevel5       = 0x4000;
   2447         public static final int AVCLevel51      = 0x8000;
   2448         public static final int AVCLevel52      = 0x10000;
   2449 
   2450         // from OMX_VIDEO_H263PROFILETYPE
   2451         public static final int H263ProfileBaseline             = 0x01;
   2452         public static final int H263ProfileH320Coding           = 0x02;
   2453         public static final int H263ProfileBackwardCompatible   = 0x04;
   2454         public static final int H263ProfileISWV2                = 0x08;
   2455         public static final int H263ProfileISWV3                = 0x10;
   2456         public static final int H263ProfileHighCompression      = 0x20;
   2457         public static final int H263ProfileInternet             = 0x40;
   2458         public static final int H263ProfileInterlace            = 0x80;
   2459         public static final int H263ProfileHighLatency          = 0x100;
   2460 
   2461         // from OMX_VIDEO_H263LEVELTYPE
   2462         public static final int H263Level10      = 0x01;
   2463         public static final int H263Level20      = 0x02;
   2464         public static final int H263Level30      = 0x04;
   2465         public static final int H263Level40      = 0x08;
   2466         public static final int H263Level45      = 0x10;
   2467         public static final int H263Level50      = 0x20;
   2468         public static final int H263Level60      = 0x40;
   2469         public static final int H263Level70      = 0x80;
   2470 
   2471         // from OMX_VIDEO_MPEG4PROFILETYPE
   2472         public static final int MPEG4ProfileSimple              = 0x01;
   2473         public static final int MPEG4ProfileSimpleScalable      = 0x02;
   2474         public static final int MPEG4ProfileCore                = 0x04;
   2475         public static final int MPEG4ProfileMain                = 0x08;
   2476         public static final int MPEG4ProfileNbit                = 0x10;
   2477         public static final int MPEG4ProfileScalableTexture     = 0x20;
   2478         public static final int MPEG4ProfileSimpleFace          = 0x40;
   2479         public static final int MPEG4ProfileSimpleFBA           = 0x80;
   2480         public static final int MPEG4ProfileBasicAnimated       = 0x100;
   2481         public static final int MPEG4ProfileHybrid              = 0x200;
   2482         public static final int MPEG4ProfileAdvancedRealTime    = 0x400;
   2483         public static final int MPEG4ProfileCoreScalable        = 0x800;
   2484         public static final int MPEG4ProfileAdvancedCoding      = 0x1000;
   2485         public static final int MPEG4ProfileAdvancedCore        = 0x2000;
   2486         public static final int MPEG4ProfileAdvancedScalable    = 0x4000;
   2487         public static final int MPEG4ProfileAdvancedSimple      = 0x8000;
   2488 
   2489         // from OMX_VIDEO_MPEG4LEVELTYPE
   2490         public static final int MPEG4Level0      = 0x01;
   2491         public static final int MPEG4Level0b     = 0x02;
   2492         public static final int MPEG4Level1      = 0x04;
   2493         public static final int MPEG4Level2      = 0x08;
   2494         public static final int MPEG4Level3      = 0x10;
   2495         public static final int MPEG4Level4      = 0x20;
   2496         public static final int MPEG4Level4a     = 0x40;
   2497         public static final int MPEG4Level5      = 0x80;
   2498 
   2499         // from OMX_VIDEO_MPEG2PROFILETYPE
   2500         public static final int MPEG2ProfileSimple              = 0x00;
   2501         public static final int MPEG2ProfileMain                = 0x01;
   2502         public static final int MPEG2Profile422                 = 0x02;
   2503         public static final int MPEG2ProfileSNR                 = 0x03;
   2504         public static final int MPEG2ProfileSpatial             = 0x04;
   2505         public static final int MPEG2ProfileHigh                = 0x05;
   2506 
   2507         // from OMX_VIDEO_MPEG2LEVELTYPE
   2508         public static final int MPEG2LevelLL     = 0x00;
   2509         public static final int MPEG2LevelML     = 0x01;
   2510         public static final int MPEG2LevelH14    = 0x02;
   2511         public static final int MPEG2LevelHL     = 0x03;
   2512 
   2513         // from OMX_AUDIO_AACPROFILETYPE
   2514         public static final int AACObjectMain       = 1;
   2515         public static final int AACObjectLC         = 2;
   2516         public static final int AACObjectSSR        = 3;
   2517         public static final int AACObjectLTP        = 4;
   2518         public static final int AACObjectHE         = 5;
   2519         public static final int AACObjectScalable   = 6;
   2520         public static final int AACObjectERLC       = 17;
   2521         public static final int AACObjectLD         = 23;
   2522         public static final int AACObjectHE_PS      = 29;
   2523         public static final int AACObjectELD        = 39;
   2524 
   2525         // from OMX_VIDEO_VP8LEVELTYPE
   2526         public static final int VP8Level_Version0 = 0x01;
   2527         public static final int VP8Level_Version1 = 0x02;
   2528         public static final int VP8Level_Version2 = 0x04;
   2529         public static final int VP8Level_Version3 = 0x08;
   2530 
   2531         // from OMX_VIDEO_VP8PROFILETYPE
   2532         public static final int VP8ProfileMain = 0x01;
   2533 
   2534         // from OMX_VIDEO_HEVCPROFILETYPE
   2535         public static final int HEVCProfileMain   = 0x01;
   2536         public static final int HEVCProfileMain10 = 0x02;
   2537 
   2538         // from OMX_VIDEO_HEVCLEVELTYPE
   2539         public static final int HEVCMainTierLevel1  = 0x1;
   2540         public static final int HEVCHighTierLevel1  = 0x2;
   2541         public static final int HEVCMainTierLevel2  = 0x4;
   2542         public static final int HEVCHighTierLevel2  = 0x8;
   2543         public static final int HEVCMainTierLevel21 = 0x10;
   2544         public static final int HEVCHighTierLevel21 = 0x20;
   2545         public static final int HEVCMainTierLevel3  = 0x40;
   2546         public static final int HEVCHighTierLevel3  = 0x80;
   2547         public static final int HEVCMainTierLevel31 = 0x100;
   2548         public static final int HEVCHighTierLevel31 = 0x200;
   2549         public static final int HEVCMainTierLevel4  = 0x400;
   2550         public static final int HEVCHighTierLevel4  = 0x800;
   2551         public static final int HEVCMainTierLevel41 = 0x1000;
   2552         public static final int HEVCHighTierLevel41 = 0x2000;
   2553         public static final int HEVCMainTierLevel5  = 0x4000;
   2554         public static final int HEVCHighTierLevel5  = 0x8000;
   2555         public static final int HEVCMainTierLevel51 = 0x10000;
   2556         public static final int HEVCHighTierLevel51 = 0x20000;
   2557         public static final int HEVCMainTierLevel52 = 0x40000;
   2558         public static final int HEVCHighTierLevel52 = 0x80000;
   2559         public static final int HEVCMainTierLevel6  = 0x100000;
   2560         public static final int HEVCHighTierLevel6  = 0x200000;
   2561         public static final int HEVCMainTierLevel61 = 0x400000;
   2562         public static final int HEVCHighTierLevel61 = 0x800000;
   2563         public static final int HEVCMainTierLevel62 = 0x1000000;
   2564         public static final int HEVCHighTierLevel62 = 0x2000000;
   2565 
   2566         /**
   2567          * Defined in the OpenMAX IL specs, depending on the type of media
   2568          * this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE,
   2569          * OMX_VIDEO_MPEG4PROFILETYPE or OMX_VIDEO_VP8PROFILETYPE.
   2570          */
   2571         public int profile;
   2572 
   2573         /**
   2574          * Defined in the OpenMAX IL specs, depending on the type of media
   2575          * this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE
   2576          * OMX_VIDEO_MPEG4LEVELTYPE or OMX_VIDEO_VP8LEVELTYPE.
   2577          */
   2578         public int level;
   2579     };
   2580 
   2581     /**
   2582      * Enumerates the capabilities of the codec component. Since a single
   2583      * component can support data of a variety of types, the type has to be
   2584      * specified to yield a meaningful result.
   2585      * @param type The MIME type to query
   2586      */
   2587     public final CodecCapabilities getCapabilitiesForType(
   2588             String type) {
   2589         CodecCapabilities caps = mCaps.get(type);
   2590         if (caps == null) {
   2591             throw new IllegalArgumentException("codec does not support type");
   2592         }
   2593         // clone writable object
   2594         return caps.dup();
   2595     }
   2596 
   2597     /** @hide */
   2598     public MediaCodecInfo makeRegular() {
   2599         ArrayList<CodecCapabilities> caps = new ArrayList<CodecCapabilities>();
   2600         for (CodecCapabilities c: mCaps.values()) {
   2601             if (c.isRegular()) {
   2602                 caps.add(c);
   2603             }
   2604         }
   2605         if (caps.size() == 0) {
   2606             return null;
   2607         } else if (caps.size() == mCaps.size()) {
   2608             return this;
   2609         }
   2610 
   2611         return new MediaCodecInfo(
   2612                 mName, mIsEncoder,
   2613                 caps.toArray(new CodecCapabilities[caps.size()]));
   2614     }
   2615 }
   2616