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.util.Log;
     20 import android.util.Pair;
     21 import android.util.Range;
     22 import android.util.Rational;
     23 import android.util.Size;
     24 
     25 import java.util.ArrayList;
     26 import java.util.Arrays;
     27 import java.util.Comparator;
     28 import java.util.HashMap;
     29 import java.util.Map;
     30 import java.util.Set;
     31 
     32 import static android.media.Utils.intersectSortedDistinctRanges;
     33 import static android.media.Utils.sortDistinctRanges;
     34 import static com.android.internal.util.Preconditions.checkArgumentPositive;
     35 import static com.android.internal.util.Preconditions.checkNotNull;
     36 
     37 /**
     38  * Provides information about a given media codec available on the device. You can
     39  * iterate through all codecs available by querying {@link MediaCodecList}. For example,
     40  * here's how to find an encoder that supports a given MIME type:
     41  * <pre>
     42  * private static MediaCodecInfo selectCodec(String mimeType) {
     43  *     int numCodecs = MediaCodecList.getCodecCount();
     44  *     for (int i = 0; i &lt; numCodecs; i++) {
     45  *         MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
     46  *
     47  *         if (!codecInfo.isEncoder()) {
     48  *             continue;
     49  *         }
     50  *
     51  *         String[] types = codecInfo.getSupportedTypes();
     52  *         for (int j = 0; j &lt; types.length; j++) {
     53  *             if (types[j].equalsIgnoreCase(mimeType)) {
     54  *                 return codecInfo;
     55  *             }
     56  *         }
     57  *     }
     58  *     return null;
     59  * }</pre>
     60  *
     61  */
     62 public final class MediaCodecInfo {
     63     private boolean mIsEncoder;
     64     private String mName;
     65     private Map<String, CodecCapabilities> mCaps;
     66 
     67     /* package private */ MediaCodecInfo(
     68             String name, boolean isEncoder, CodecCapabilities[] caps) {
     69         mName = name;
     70         mIsEncoder = isEncoder;
     71         mCaps = new HashMap<String, CodecCapabilities>();
     72         for (CodecCapabilities c: caps) {
     73             mCaps.put(c.getMimeType(), c);
     74         }
     75     }
     76 
     77     /**
     78      * Retrieve the codec name.
     79      */
     80     public final String getName() {
     81         return mName;
     82     }
     83 
     84     /**
     85      * Query if the codec is an encoder.
     86      */
     87     public final boolean isEncoder() {
     88         return mIsEncoder;
     89     }
     90 
     91     /**
     92      * Query the media types supported by the codec.
     93      */
     94     public final String[] getSupportedTypes() {
     95         Set<String> typeSet = mCaps.keySet();
     96         String[] types = typeSet.toArray(new String[typeSet.size()]);
     97         Arrays.sort(types);
     98         return types;
     99     }
    100 
    101     private static int checkPowerOfTwo(int value, String message) {
    102         if ((value & (value - 1)) != 0) {
    103             throw new IllegalArgumentException(message);
    104         }
    105         return value;
    106     }
    107 
    108     private static class Feature {
    109         public String mName;
    110         public int mValue;
    111         public boolean mDefault;
    112         public Feature(String name, int value, boolean def) {
    113             mName = name;
    114             mValue = value;
    115             mDefault = def;
    116         }
    117     }
    118 
    119     // COMMON CONSTANTS
    120     private static final Range<Integer> POSITIVE_INTEGERS =
    121         Range.create(1, Integer.MAX_VALUE);
    122     private static final Range<Long> POSITIVE_LONGS =
    123         Range.create(1l, Long.MAX_VALUE);
    124     private static final Range<Rational> POSITIVE_RATIONALS =
    125         Range.create(new Rational(1, Integer.MAX_VALUE),
    126                      new Rational(Integer.MAX_VALUE, 1));
    127     private static final Range<Integer> SIZE_RANGE = Range.create(1, 32768);
    128     private static final Range<Integer> FRAME_RATE_RANGE = Range.create(0, 960);
    129 
    130     // found stuff that is not supported by framework (=> this should not happen)
    131     private static final int ERROR_UNRECOGNIZED   = (1 << 0);
    132     // found profile/level for which we don't have capability estimates
    133     private static final int ERROR_UNSUPPORTED    = (1 << 1);
    134     // have not found any profile/level for which we don't have capability estimate
    135     private static final int ERROR_NONE_SUPPORTED = (1 << 2);
    136 
    137 
    138     /**
    139      * Encapsulates the capabilities of a given codec component.
    140      * For example, what profile/level combinations it supports and what colorspaces
    141      * it is capable of providing the decoded data in, as well as some
    142      * codec-type specific capability flags.
    143      * <p>You can get an instance for a given {@link MediaCodecInfo} object with
    144      * {@link MediaCodecInfo#getCapabilitiesForType getCapabilitiesForType()}, passing a MIME type.
    145      */
    146     public static final class CodecCapabilities {
    147         public CodecCapabilities() {
    148         }
    149 
    150         // CLASSIFICATION
    151         private String mMime;
    152 
    153         // LEGACY FIELDS
    154 
    155         // Enumerates supported profile/level combinations as defined
    156         // by the type of encoded data. These combinations impose restrictions
    157         // on video resolution, bitrate... and limit the available encoder tools
    158         // such as B-frame support, arithmetic coding...
    159         public CodecProfileLevel[] profileLevels;  // NOTE this array is modifiable by user
    160 
    161         // from OMX_COLOR_FORMATTYPE
    162         public static final int COLOR_FormatMonochrome              = 1;
    163         public static final int COLOR_Format8bitRGB332              = 2;
    164         public static final int COLOR_Format12bitRGB444             = 3;
    165         public static final int COLOR_Format16bitARGB4444           = 4;
    166         public static final int COLOR_Format16bitARGB1555           = 5;
    167         public static final int COLOR_Format16bitRGB565             = 6;
    168         public static final int COLOR_Format16bitBGR565             = 7;
    169         public static final int COLOR_Format18bitRGB666             = 8;
    170         public static final int COLOR_Format18bitARGB1665           = 9;
    171         public static final int COLOR_Format19bitARGB1666           = 10;
    172         public static final int COLOR_Format24bitRGB888             = 11;
    173         public static final int COLOR_Format24bitBGR888             = 12;
    174         public static final int COLOR_Format24bitARGB1887           = 13;
    175         public static final int COLOR_Format25bitARGB1888           = 14;
    176         public static final int COLOR_Format32bitBGRA8888           = 15;
    177         public static final int COLOR_Format32bitARGB8888           = 16;
    178         public static final int COLOR_FormatYUV411Planar            = 17;
    179         public static final int COLOR_FormatYUV411PackedPlanar      = 18;
    180         public static final int COLOR_FormatYUV420Planar            = 19;
    181         public static final int COLOR_FormatYUV420PackedPlanar      = 20;
    182         public static final int COLOR_FormatYUV420SemiPlanar        = 21;
    183         public static final int COLOR_FormatYUV422Planar            = 22;
    184         public static final int COLOR_FormatYUV422PackedPlanar      = 23;
    185         public static final int COLOR_FormatYUV422SemiPlanar        = 24;
    186         public static final int COLOR_FormatYCbYCr                  = 25;
    187         public static final int COLOR_FormatYCrYCb                  = 26;
    188         public static final int COLOR_FormatCbYCrY                  = 27;
    189         public static final int COLOR_FormatCrYCbY                  = 28;
    190         public static final int COLOR_FormatYUV444Interleaved       = 29;
    191         public static final int COLOR_FormatRawBayer8bit            = 30;
    192         public static final int COLOR_FormatRawBayer10bit           = 31;
    193         public static final int COLOR_FormatRawBayer8bitcompressed  = 32;
    194         public static final int COLOR_FormatL2                      = 33;
    195         public static final int COLOR_FormatL4                      = 34;
    196         public static final int COLOR_FormatL8                      = 35;
    197         public static final int COLOR_FormatL16                     = 36;
    198         public static final int COLOR_FormatL24                     = 37;
    199         public static final int COLOR_FormatL32                     = 38;
    200         public static final int COLOR_FormatYUV420PackedSemiPlanar  = 39;
    201         public static final int COLOR_FormatYUV422PackedSemiPlanar  = 40;
    202         public static final int COLOR_Format18BitBGR666             = 41;
    203         public static final int COLOR_Format24BitARGB6666           = 42;
    204         public static final int COLOR_Format24BitABGR6666           = 43;
    205 
    206         public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100;
    207         // COLOR_FormatSurface indicates that the data will be a GraphicBuffer metadata reference.
    208         // In OMX this is called OMX_COLOR_FormatAndroidOpaque.
    209         public static final int COLOR_FormatSurface                   = 0x7F000789;
    210         // This corresponds to YUV_420_888 format
    211         public static final int COLOR_FormatYUV420Flexible            = 0x7F420888;
    212         public static final int COLOR_QCOM_FormatYUV420SemiPlanar     = 0x7fa30c00;
    213 
    214         /**
    215          * Defined in the OpenMAX IL specs, color format values are drawn from
    216          * OMX_COLOR_FORMATTYPE.
    217          */
    218         public int[] colorFormats; // NOTE this array is modifiable by user
    219 
    220         // FEATURES
    221 
    222         private int mFlagsSupported;
    223         private int mFlagsRequired;
    224         private int mFlagsVerified;
    225 
    226         /**
    227          * <b>video decoder only</b>: codec supports seamless resolution changes.
    228          */
    229         public static final String FEATURE_AdaptivePlayback       = "adaptive-playback";
    230 
    231         /**
    232          * <b>video decoder only</b>: codec supports secure decryption.
    233          */
    234         public static final String FEATURE_SecurePlayback         = "secure-playback";
    235 
    236         /**
    237          * <b>video or audio decoder only</b>: codec supports tunneled playback.
    238          */
    239         public static final String FEATURE_TunneledPlayback       = "tunneled-playback";
    240 
    241         /**
    242          * Query codec feature capabilities.
    243          * <p>
    244          * These features are supported to be used by the codec.  These
    245          * include optional features that can be turned on, as well as
    246          * features that are always on.
    247          */
    248         public final boolean isFeatureSupported(String name) {
    249             return checkFeature(name, mFlagsSupported);
    250         }
    251 
    252         /**
    253          * Query codec feature requirements.
    254          * <p>
    255          * These features are required to be used by the codec, and as such,
    256          * they are always turned on.
    257          */
    258         public final boolean isFeatureRequired(String name) {
    259             return checkFeature(name, mFlagsRequired);
    260         }
    261 
    262         private static final Feature[] decoderFeatures = {
    263             new Feature(FEATURE_AdaptivePlayback, (1 << 0), true),
    264             new Feature(FEATURE_SecurePlayback,   (1 << 1), false),
    265             new Feature(FEATURE_TunneledPlayback, (1 << 2), false),
    266         };
    267 
    268         /** @hide */
    269         public String[] validFeatures() {
    270             Feature[] features = getValidFeatures();
    271             String[] res = new String[features.length];
    272             for (int i = 0; i < res.length; i++) {
    273                 res[i] = features[i].mName;
    274             }
    275             return res;
    276         }
    277 
    278         private Feature[] getValidFeatures() {
    279             if (!isEncoder()) {
    280                 return decoderFeatures;
    281             }
    282             return new Feature[] {};
    283         }
    284 
    285         private boolean checkFeature(String name, int flags) {
    286             for (Feature feat: getValidFeatures()) {
    287                 if (feat.mName.equals(name)) {
    288                     return (flags & feat.mValue) != 0;
    289                 }
    290             }
    291             return false;
    292         }
    293 
    294         /** @hide */
    295         public boolean isRegular() {
    296             // regular codecs only require default features
    297             for (Feature feat: getValidFeatures()) {
    298                 if (!feat.mDefault && isFeatureRequired(feat.mName)) {
    299                     return false;
    300                 }
    301             }
    302             return true;
    303         }
    304 
    305         /**
    306          * Query whether codec supports a given {@link MediaFormat}.
    307          * @param format media format with optional feature directives.
    308          * @throws IllegalArgumentException if format is not a valid media format.
    309          * @return whether the codec capabilities support the given format
    310          *         and feature requests.
    311          */
    312         public final boolean isFormatSupported(MediaFormat format) {
    313             final Map<String, Object> map = format.getMap();
    314             final String mime = (String)map.get(MediaFormat.KEY_MIME);
    315 
    316             // mime must match if present
    317             if (mime != null && !mMime.equalsIgnoreCase(mime)) {
    318                 return false;
    319             }
    320 
    321             // check feature support
    322             for (Feature feat: getValidFeatures()) {
    323                 Integer yesNo = (Integer)map.get(MediaFormat.KEY_FEATURE_ + feat.mName);
    324                 if (yesNo == null) {
    325                     continue;
    326                 }
    327                 if ((yesNo == 1 && !isFeatureSupported(feat.mName)) ||
    328                         (yesNo == 0 && isFeatureRequired(feat.mName))) {
    329                     return false;
    330                 }
    331             }
    332             if (mAudioCaps != null && !mAudioCaps.supportsFormat(format)) {
    333                 return false;
    334             }
    335             if (mVideoCaps != null && !mVideoCaps.supportsFormat(format)) {
    336                 return false;
    337             }
    338             if (mEncoderCaps != null && !mEncoderCaps.supportsFormat(format)) {
    339                 return false;
    340             }
    341             return true;
    342         }
    343 
    344         // errors while reading profile levels - accessed from sister capabilities
    345         int mError;
    346 
    347         private static final String TAG = "CodecCapabilities";
    348 
    349         // NEW-STYLE CAPABILITIES
    350         private AudioCapabilities mAudioCaps;
    351         private VideoCapabilities mVideoCaps;
    352         private EncoderCapabilities mEncoderCaps;
    353         private MediaFormat mDefaultFormat;
    354 
    355         /**
    356          * Returns a MediaFormat object with default values for configurations that have
    357          * defaults.
    358          */
    359         public MediaFormat getDefaultFormat() {
    360             return mDefaultFormat;
    361         }
    362 
    363         /**
    364          * Returns the mime type for which this codec-capability object was created.
    365          */
    366         public String getMimeType() {
    367             return mMime;
    368         }
    369 
    370         private boolean isAudio() {
    371             return mAudioCaps != null;
    372         }
    373 
    374         /**
    375          * Returns the audio capabilities or {@code null} if this is not an audio codec.
    376          */
    377         public AudioCapabilities getAudioCapabilities() {
    378             return mAudioCaps;
    379         }
    380 
    381         private boolean isEncoder() {
    382             return mEncoderCaps != null;
    383         }
    384 
    385         /**
    386          * Returns the encoding capabilities or {@code null} if this is not an encoder.
    387          */
    388         public EncoderCapabilities getEncoderCapabilities() {
    389             return mEncoderCaps;
    390         }
    391 
    392         private boolean isVideo() {
    393             return mVideoCaps != null;
    394         }
    395 
    396         /**
    397          * Returns the video capabilities or {@code null} if this is not a video codec.
    398          */
    399         public VideoCapabilities getVideoCapabilities() {
    400             return mVideoCaps;
    401         }
    402 
    403         /** @hide */
    404         public CodecCapabilities dup() {
    405             return new CodecCapabilities(
    406                 // clone writable arrays
    407                 Arrays.copyOf(profileLevels, profileLevels.length),
    408                 Arrays.copyOf(colorFormats, colorFormats.length),
    409                 isEncoder(),
    410                 mFlagsVerified,
    411                 mDefaultFormat,
    412                 mCapabilitiesInfo);
    413         }
    414 
    415         /**
    416          * Retrieve the codec capabilities for a certain {@code mime type}, {@code
    417          * profile} and {@code level}.  If the type, or profile-level combination
    418          * is not understood by the framework, it returns null.
    419          */
    420         public static CodecCapabilities createFromProfileLevel(
    421                 String mime, int profile, int level) {
    422             CodecProfileLevel pl = new CodecProfileLevel();
    423             pl.profile = profile;
    424             pl.level = level;
    425             MediaFormat defaultFormat = new MediaFormat();
    426             defaultFormat.setString(MediaFormat.KEY_MIME, mime);
    427 
    428             CodecCapabilities ret = new CodecCapabilities(
    429                 new CodecProfileLevel[] { pl }, new int[0], true /* encoder */,
    430                 0 /* flags */, defaultFormat, new MediaFormat() /* info */);
    431             if (ret.mError != 0) {
    432                 return null;
    433             }
    434             return ret;
    435         }
    436 
    437         /* package private */ CodecCapabilities(
    438                 CodecProfileLevel[] profLevs, int[] colFmts,
    439                 boolean encoder, int flags,
    440                 Map<String, Object>defaultFormatMap,
    441                 Map<String, Object>capabilitiesMap) {
    442             this(profLevs, colFmts, encoder, flags,
    443                     new MediaFormat(defaultFormatMap),
    444                     new MediaFormat(capabilitiesMap));
    445         }
    446 
    447         private MediaFormat mCapabilitiesInfo;
    448 
    449         /* package private */ CodecCapabilities(
    450                 CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags,
    451                 MediaFormat defaultFormat, MediaFormat info) {
    452             final Map<String, Object> map = info.getMap();
    453             profileLevels = profLevs;
    454             colorFormats = colFmts;
    455             mFlagsVerified = flags;
    456             mDefaultFormat = defaultFormat;
    457             mCapabilitiesInfo = info;
    458             mMime = mDefaultFormat.getString(MediaFormat.KEY_MIME);
    459 
    460             if (mMime.toLowerCase().startsWith("audio/")) {
    461                 mAudioCaps = AudioCapabilities.create(info, this);
    462                 mAudioCaps.setDefaultFormat(mDefaultFormat);
    463             } else if (mMime.toLowerCase().startsWith("video/")) {
    464                 mVideoCaps = VideoCapabilities.create(info, this);
    465             }
    466             if (encoder) {
    467                 mEncoderCaps = EncoderCapabilities.create(info, this);
    468                 mEncoderCaps.setDefaultFormat(mDefaultFormat);
    469             }
    470 
    471             for (Feature feat: getValidFeatures()) {
    472                 String key = MediaFormat.KEY_FEATURE_ + feat.mName;
    473                 Integer yesNo = (Integer)map.get(key);
    474                 if (yesNo == null) {
    475                     continue;
    476                 }
    477                 if (yesNo > 0) {
    478                     mFlagsRequired |= feat.mValue;
    479                 }
    480                 mFlagsSupported |= feat.mValue;
    481                 mDefaultFormat.setInteger(key, 1);
    482                 // TODO restrict features by mFlagsVerified once all codecs reliably verify them
    483             }
    484         }
    485     }
    486 
    487     /**
    488      * A class that supports querying the audio capabilities of a codec.
    489      */
    490     public static final class AudioCapabilities {
    491         private static final String TAG = "AudioCapabilities";
    492         private CodecCapabilities mParent;
    493         private Range<Integer> mBitrateRange;
    494 
    495         private int[] mSampleRates;
    496         private Range<Integer>[] mSampleRateRanges;
    497         private int mMaxInputChannelCount;
    498 
    499         private static final int MAX_INPUT_CHANNEL_COUNT = 30;
    500 
    501         /**
    502          * Returns the range of supported bitrates in bits/second.
    503          */
    504         public Range<Integer> getBitrateRange() {
    505             return mBitrateRange;
    506         }
    507 
    508         /**
    509          * Returns the array of supported sample rates if the codec
    510          * supports only discrete values.  Otherwise, it returns
    511          * {@code null}.  The array is sorted in ascending order.
    512          */
    513         public int[] getSupportedSampleRates() {
    514             return Arrays.copyOf(mSampleRates, mSampleRates.length);
    515         }
    516 
    517         /**
    518          * Returns the array of supported sample rate ranges.  The
    519          * array is sorted in ascending order, and the ranges are
    520          * distinct.
    521          */
    522         public Range<Integer>[] getSupportedSampleRateRanges() {
    523             return Arrays.copyOf(mSampleRateRanges, mSampleRateRanges.length);
    524         }
    525 
    526         /**
    527          * Returns the maximum number of input channels supported.  The codec
    528          * supports any number of channels between 1 and this maximum value.
    529          */
    530         public int getMaxInputChannelCount() {
    531             return mMaxInputChannelCount;
    532         }
    533 
    534         /* no public constructor */
    535         private AudioCapabilities() { }
    536 
    537         /** @hide */
    538         public static AudioCapabilities create(
    539                 MediaFormat info, CodecCapabilities parent) {
    540             AudioCapabilities caps = new AudioCapabilities();
    541             caps.init(info, parent);
    542             return caps;
    543         }
    544 
    545         /** @hide */
    546         public void init(MediaFormat info, CodecCapabilities parent) {
    547             mParent = parent;
    548             initWithPlatformLimits();
    549             applyLevelLimits();
    550             parseFromInfo(info);
    551         }
    552 
    553         private void initWithPlatformLimits() {
    554             mBitrateRange = Range.create(0, Integer.MAX_VALUE);
    555             mMaxInputChannelCount = MAX_INPUT_CHANNEL_COUNT;
    556             // mBitrateRange = Range.create(1, 320000);
    557             mSampleRateRanges = new Range[] { Range.create(8000, 96000) };
    558             mSampleRates = null;
    559         }
    560 
    561         private boolean supports(Integer sampleRate, Integer inputChannels) {
    562             // channels and sample rates are checked orthogonally
    563             if (inputChannels != null &&
    564                     (inputChannels < 1 || inputChannels > mMaxInputChannelCount)) {
    565                 return false;
    566             }
    567             if (sampleRate != null) {
    568                 int ix = Utils.binarySearchDistinctRanges(
    569                         mSampleRateRanges, sampleRate);
    570                 if (ix < 0) {
    571                     return false;
    572                 }
    573             }
    574             return true;
    575         }
    576 
    577         /**
    578          * Query whether the sample rate is supported by the codec.
    579          */
    580         public boolean isSampleRateSupported(int sampleRate) {
    581             return supports(sampleRate, null);
    582         }
    583 
    584         /** modifies rates */
    585         private void limitSampleRates(int[] rates) {
    586             Arrays.sort(rates);
    587             ArrayList<Range<Integer>> ranges = new ArrayList<Range<Integer>>();
    588             for (int rate: rates) {
    589                 if (supports(rate, null /* channels */)) {
    590                     ranges.add(Range.create(rate, rate));
    591                 }
    592             }
    593             mSampleRateRanges = ranges.toArray(new Range[ranges.size()]);
    594             createDiscreteSampleRates();
    595         }
    596 
    597         private void createDiscreteSampleRates() {
    598             mSampleRates = new int[mSampleRateRanges.length];
    599             for (int i = 0; i < mSampleRateRanges.length; i++) {
    600                 mSampleRates[i] = mSampleRateRanges[i].getLower();
    601             }
    602         }
    603 
    604         /** modifies rateRanges */
    605         private void limitSampleRates(Range<Integer>[] rateRanges) {
    606             sortDistinctRanges(rateRanges);
    607             mSampleRateRanges = intersectSortedDistinctRanges(mSampleRateRanges, rateRanges);
    608 
    609             // check if all values are discrete
    610             for (Range<Integer> range: mSampleRateRanges) {
    611                 if (!range.getLower().equals(range.getUpper())) {
    612                     mSampleRates = null;
    613                     return;
    614                 }
    615             }
    616             createDiscreteSampleRates();
    617         }
    618 
    619         private void applyLevelLimits() {
    620             int[] sampleRates = null;
    621             Range<Integer> sampleRateRange = null, bitRates = null;
    622             int maxChannels = 0;
    623             String mime = mParent.getMimeType();
    624 
    625             if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MPEG)) {
    626                 sampleRates = new int[] {
    627                         8000, 11025, 12000,
    628                         16000, 22050, 24000,
    629                         32000, 44100, 48000 };
    630                 bitRates = Range.create(8000, 320000);
    631                 maxChannels = 2;
    632             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)) {
    633                 sampleRates = new int[] { 8000 };
    634                 bitRates = Range.create(4750, 12200);
    635                 maxChannels = 1;
    636             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)) {
    637                 sampleRates = new int[] { 16000 };
    638                 bitRates = Range.create(6600, 23850);
    639                 maxChannels = 1;
    640             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC)) {
    641                 sampleRates = new int[] {
    642                         7350, 8000,
    643                         11025, 12000, 16000,
    644                         22050, 24000, 32000,
    645                         44100, 48000, 64000,
    646                         88200, 96000 };
    647                 bitRates = Range.create(8000, 510000);
    648                 maxChannels = 48;
    649             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_VORBIS)) {
    650                 bitRates = Range.create(32000, 500000);
    651                 sampleRates = new int[] { 8000, 12000, 16000, 24000, 48000, 192000 };
    652                 maxChannels = 255;
    653             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_OPUS)) {
    654                 bitRates = Range.create(6000, 510000);
    655                 sampleRates = new int[] { 8000, 12000, 16000, 24000, 48000 };
    656                 maxChannels = 255;
    657             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW)) {
    658                 sampleRateRange = Range.create(1, 96000);
    659                 bitRates = Range.create(1, 10000000);
    660                 maxChannels = 8;
    661             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
    662                 sampleRateRange = Range.create(1, 655350);
    663                 // lossless codec, so bitrate is ignored
    664                 maxChannels = 255;
    665             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW)
    666                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)) {
    667                 sampleRates = new int[] { 8000 };
    668                 bitRates = Range.create(64000, 64000);
    669                 // platform allows multiple channels for this format
    670             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) {
    671                 sampleRates = new int[] { 8000 };
    672                 bitRates = Range.create(13000, 13000);
    673                 maxChannels = 1;
    674             } else {
    675                 Log.w(TAG, "Unsupported mime " + mime);
    676                 mParent.mError |= ERROR_UNSUPPORTED;
    677             }
    678 
    679             // restrict ranges
    680             if (sampleRates != null) {
    681                 limitSampleRates(sampleRates);
    682             } else if (sampleRateRange != null) {
    683                 limitSampleRates(new Range[] { sampleRateRange });
    684             }
    685             applyLimits(maxChannels, bitRates);
    686         }
    687 
    688         private void applyLimits(int maxInputChannels, Range<Integer> bitRates) {
    689             mMaxInputChannelCount = Range.create(1, mMaxInputChannelCount)
    690                     .clamp(maxInputChannels);
    691             if (bitRates != null) {
    692                 mBitrateRange = mBitrateRange.intersect(bitRates);
    693             }
    694         }
    695 
    696         private void parseFromInfo(MediaFormat info) {
    697             int maxInputChannels = MAX_INPUT_CHANNEL_COUNT;
    698             Range<Integer> bitRates = POSITIVE_INTEGERS;
    699 
    700             if (info.containsKey("sample-rate-ranges")) {
    701                 String[] rateStrings = info.getString("sample-rate-ranges").split(",");
    702                 Range<Integer>[] rateRanges = new Range[rateStrings.length];
    703                 for (int i = 0; i < rateStrings.length; i++) {
    704                     rateRanges[i] = Utils.parseIntRange(rateStrings[i], null);
    705                 }
    706                 limitSampleRates(rateRanges);
    707             }
    708             if (info.containsKey("max-channel-count")) {
    709                 maxInputChannels = Utils.parseIntSafely(
    710                         info.getString("max-channel-count"), maxInputChannels);
    711             }
    712             if (info.containsKey("bitrate-range")) {
    713                 bitRates = bitRates.intersect(
    714                         Utils.parseIntRange(info.getString("bitrate"), bitRates));
    715             }
    716             applyLimits(maxInputChannels, bitRates);
    717         }
    718 
    719         /** @hide */
    720         public void setDefaultFormat(MediaFormat format) {
    721             // report settings that have only a single choice
    722             if (mBitrateRange.getLower().equals(mBitrateRange.getUpper())) {
    723                 format.setInteger(MediaFormat.KEY_BIT_RATE, mBitrateRange.getLower());
    724             }
    725             if (mMaxInputChannelCount == 1) {
    726                 // mono-only format
    727                 format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
    728             }
    729             if (mSampleRates != null && mSampleRates.length == 1) {
    730                 format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRates[0]);
    731             }
    732         }
    733 
    734         /** @hide */
    735         public boolean supportsFormat(MediaFormat format) {
    736             Map<String, Object> map = format.getMap();
    737             Integer sampleRate = (Integer)map.get(MediaFormat.KEY_SAMPLE_RATE);
    738             Integer channels = (Integer)map.get(MediaFormat.KEY_CHANNEL_COUNT);
    739             if (!supports(sampleRate, channels)) {
    740                 return false;
    741             }
    742 
    743             // nothing to do for:
    744             // KEY_CHANNEL_MASK: codecs don't get this
    745             // KEY_IS_ADTS:      required feature for all AAC decoders
    746             return true;
    747         }
    748     }
    749 
    750     /**
    751      * A class that supports querying the video capabilities of a codec.
    752      */
    753     public static final class VideoCapabilities {
    754         private static final String TAG = "VideoCapabilities";
    755         private CodecCapabilities mParent;
    756         private Range<Integer> mBitrateRange;
    757 
    758         private Range<Integer> mHeightRange;
    759         private Range<Integer> mWidthRange;
    760         private Range<Integer> mBlockCountRange;
    761         private Range<Integer> mHorizontalBlockRange;
    762         private Range<Integer> mVerticalBlockRange;
    763         private Range<Rational> mAspectRatioRange;
    764         private Range<Rational> mBlockAspectRatioRange;
    765         private Range<Long> mBlocksPerSecondRange;
    766         private Range<Integer> mFrameRateRange;
    767 
    768         private int mBlockWidth;
    769         private int mBlockHeight;
    770         private int mWidthAlignment;
    771         private int mHeightAlignment;
    772         private int mSmallerDimensionUpperLimit;
    773 
    774         /**
    775          * Returns the range of supported bitrates in bits/second.
    776          */
    777         public Range<Integer> getBitrateRange() {
    778             return mBitrateRange;
    779         }
    780 
    781         /**
    782          * Returns the range of supported video widths.
    783          */
    784         public Range<Integer> getSupportedWidths() {
    785             return mWidthRange;
    786         }
    787 
    788         /**
    789          * Returns the range of supported video heights.
    790          */
    791         public Range<Integer> getSupportedHeights() {
    792             return mHeightRange;
    793         }
    794 
    795         /**
    796          * Returns the alignment requirement for video width (in pixels).
    797          *
    798          * This is a power-of-2 value that video width must be a
    799          * multiple of.
    800          */
    801         public int getWidthAlignment() {
    802             return mWidthAlignment;
    803         }
    804 
    805         /**
    806          * Returns the alignment requirement for video height (in pixels).
    807          *
    808          * This is a power-of-2 value that video height must be a
    809          * multiple of.
    810          */
    811         public int getHeightAlignment() {
    812             return mHeightAlignment;
    813         }
    814 
    815         /**
    816          * Return the upper limit on the smaller dimension of width or height.
    817          * <p></p>
    818          * Some codecs have a limit on the smaller dimension, whether it be
    819          * the width or the height.  E.g. a codec may only be able to handle
    820          * up to 1920x1080 both in landscape and portrait mode (1080x1920).
    821          * In this case the maximum width and height are both 1920, but the
    822          * smaller dimension limit will be 1080. For other codecs, this is
    823          * {@code Math.min(getSupportedWidths().getUpper(),
    824          * getSupportedHeights().getUpper())}.
    825          *
    826          * @hide
    827          */
    828         public int getSmallerDimensionUpperLimit() {
    829             return mSmallerDimensionUpperLimit;
    830         }
    831 
    832         /**
    833          * Returns the range of supported frame rates.
    834          * <p>
    835          * This is not a performance indicator.  Rather, it expresses the
    836          * limits specified in the coding standard, based on the complexities
    837          * of encoding material for later playback at a certain frame rate,
    838          * or the decoding of such material in non-realtime.
    839          */
    840         public Range<Integer> getSupportedFrameRates() {
    841             return mFrameRateRange;
    842         }
    843 
    844         /**
    845          * Returns the range of supported video widths for a video height.
    846          * @param height the height of the video
    847          */
    848         public Range<Integer> getSupportedWidthsFor(int height) {
    849             try {
    850                 Range<Integer> range = mWidthRange;
    851                 if (!mHeightRange.contains(height)
    852                         || (height % mHeightAlignment) != 0) {
    853                     throw new IllegalArgumentException("unsupported height");
    854                 }
    855                 final int heightInBlocks = Utils.divUp(height, mBlockHeight);
    856 
    857                 // constrain by block count and by block aspect ratio
    858                 final int minWidthInBlocks = Math.max(
    859                         Utils.divUp(mBlockCountRange.getLower(), heightInBlocks),
    860                         (int)Math.ceil(mBlockAspectRatioRange.getLower().doubleValue()
    861                                 * heightInBlocks));
    862                 final int maxWidthInBlocks = Math.min(
    863                         mBlockCountRange.getUpper() / heightInBlocks,
    864                         (int)(mBlockAspectRatioRange.getUpper().doubleValue()
    865                                 * heightInBlocks));
    866                 range = range.intersect(
    867                         (minWidthInBlocks - 1) * mBlockWidth + mWidthAlignment,
    868                         maxWidthInBlocks * mBlockWidth);
    869 
    870                 // constrain by smaller dimension limit
    871                 if (height > mSmallerDimensionUpperLimit) {
    872                     range = range.intersect(1, mSmallerDimensionUpperLimit);
    873                 }
    874 
    875                 // constrain by aspect ratio
    876                 range = range.intersect(
    877                         (int)Math.ceil(mAspectRatioRange.getLower().doubleValue()
    878                                 * height),
    879                         (int)(mAspectRatioRange.getUpper().doubleValue() * height));
    880                 return range;
    881             } catch (IllegalArgumentException e) {
    882                 // should not be here
    883                 Log.w(TAG, "could not get supported widths for " + height , e);
    884                 throw new IllegalArgumentException("unsupported height");
    885             }
    886         }
    887 
    888         /**
    889          * Returns the range of supported video heights for a video width
    890          * @param width the width of the video
    891          */
    892         public Range<Integer> getSupportedHeightsFor(int width) {
    893             try {
    894                 Range<Integer> range = mHeightRange;
    895                 if (!mWidthRange.contains(width)
    896                         || (width % mWidthAlignment) != 0) {
    897                     throw new IllegalArgumentException("unsupported width");
    898                 }
    899                 final int widthInBlocks = Utils.divUp(width, mBlockWidth);
    900 
    901                 // constrain by block count and by block aspect ratio
    902                 final int minHeightInBlocks = Math.max(
    903                         Utils.divUp(mBlockCountRange.getLower(), widthInBlocks),
    904                         (int)Math.ceil(widthInBlocks /
    905                                 mBlockAspectRatioRange.getUpper().doubleValue()));
    906                 final int maxHeightInBlocks = Math.min(
    907                         mBlockCountRange.getUpper() / widthInBlocks,
    908                         (int)(widthInBlocks /
    909                                 mBlockAspectRatioRange.getLower().doubleValue()));
    910                 range = range.intersect(
    911                         (minHeightInBlocks - 1) * mBlockHeight + mHeightAlignment,
    912                         maxHeightInBlocks * mBlockHeight);
    913 
    914                 // constrain by smaller dimension limit
    915                 if (width > mSmallerDimensionUpperLimit) {
    916                     range = range.intersect(1, mSmallerDimensionUpperLimit);
    917                 }
    918 
    919                 // constrain by aspect ratio
    920                 range = range.intersect(
    921                         (int)Math.ceil(width /
    922                                 mAspectRatioRange.getUpper().doubleValue()),
    923                         (int)(width / mAspectRatioRange.getLower().doubleValue()));
    924                 return range;
    925             } catch (IllegalArgumentException e) {
    926                 // should not be here
    927                 Log.w(TAG, "could not get supported heights for " + width , e);
    928                 throw new IllegalArgumentException("unsupported width");
    929             }
    930         }
    931 
    932         /**
    933          * Returns the range of supported video frame rates for a video size.
    934          * <p>
    935          * This is not a performance indicator.  Rather, it expresses the limits specified in
    936          * the coding standard, based on the complexities of encoding material of a given
    937          * size for later playback at a certain frame rate, or the decoding of such material
    938          * in non-realtime.
    939 
    940          * @param width the width of the video
    941          * @param height the height of the video
    942          */
    943         public Range<Double> getSupportedFrameRatesFor(int width, int height) {
    944             Range<Integer> range = mHeightRange;
    945             if (!supports(width, height, null)) {
    946                 throw new IllegalArgumentException("unsupported size");
    947             }
    948             final int blockCount =
    949                 Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight);
    950 
    951             return Range.create(
    952                     Math.max(mBlocksPerSecondRange.getLower() / (double) blockCount,
    953                             (double) mFrameRateRange.getLower()),
    954                     Math.min(mBlocksPerSecondRange.getUpper() / (double) blockCount,
    955                             (double) mFrameRateRange.getUpper()));
    956         }
    957 
    958         /**
    959          * Returns whether a given video size ({@code width} and
    960          * {@code height}) and {@code frameRate} combination is supported.
    961          */
    962         public boolean areSizeAndRateSupported(
    963                 int width, int height, double frameRate) {
    964             return supports(width, height, frameRate);
    965         }
    966 
    967         /**
    968          * Returns whether a given video size ({@code width} and
    969          * {@code height}) is supported.
    970          */
    971         public boolean isSizeSupported(int width, int height) {
    972             return supports(width, height, null);
    973         }
    974 
    975         private boolean supports(
    976                 Integer width, Integer height, Double rate) {
    977             boolean ok = true;
    978 
    979             if (ok && width != null) {
    980                 ok = mWidthRange.contains(width)
    981                         && (width % mWidthAlignment == 0);
    982             }
    983             if (ok && height != null) {
    984                 ok = mHeightRange.contains(height)
    985                         && (height % mHeightAlignment == 0);
    986             }
    987             if (ok && rate != null) {
    988                 ok = mFrameRateRange.contains(Utils.intRangeFor(rate));
    989             }
    990             if (ok && height != null && width != null) {
    991                 ok = Math.min(height, width) <= mSmallerDimensionUpperLimit;
    992 
    993                 final int widthInBlocks = Utils.divUp(width, mBlockWidth);
    994                 final int heightInBlocks = Utils.divUp(height, mBlockHeight);
    995                 final int blockCount = widthInBlocks * heightInBlocks;
    996                 ok = ok && mBlockCountRange.contains(blockCount)
    997                         && mBlockAspectRatioRange.contains(
    998                                 new Rational(widthInBlocks, heightInBlocks))
    999                         && mAspectRatioRange.contains(new Rational(width, height));
   1000                 if (ok && rate != null) {
   1001                     double blocksPerSec = blockCount * rate;
   1002                     ok = mBlocksPerSecondRange.contains(
   1003                             Utils.longRangeFor(blocksPerSec));
   1004                 }
   1005             }
   1006             return ok;
   1007         }
   1008 
   1009         /**
   1010          * @hide
   1011          * @throws java.lang.ClassCastException */
   1012         public boolean supportsFormat(MediaFormat format) {
   1013             final Map<String, Object> map = format.getMap();
   1014             Integer width = (Integer)map.get(MediaFormat.KEY_WIDTH);
   1015             Integer height = (Integer)map.get(MediaFormat.KEY_HEIGHT);
   1016             Double rate = (Double)map.get(MediaFormat.KEY_FRAME_RATE);
   1017 
   1018             // we ignore color-format for now as it is not reliably reported by codec
   1019 
   1020             return supports(width, height, rate);
   1021         }
   1022 
   1023         /* no public constructor */
   1024         private VideoCapabilities() { }
   1025 
   1026         /** @hide */
   1027         public static VideoCapabilities create(
   1028                 MediaFormat info, CodecCapabilities parent) {
   1029             VideoCapabilities caps = new VideoCapabilities();
   1030             caps.init(info, parent);
   1031             return caps;
   1032         }
   1033 
   1034         /** @hide */
   1035         public void init(MediaFormat info, CodecCapabilities parent) {
   1036             mParent = parent;
   1037             initWithPlatformLimits();
   1038             applyLevelLimits();
   1039             parseFromInfo(info);
   1040             updateLimits();
   1041         }
   1042 
   1043         /** @hide */
   1044         public Size getBlockSize() {
   1045             return new Size(mBlockWidth, mBlockHeight);
   1046         }
   1047 
   1048         /** @hide */
   1049         public Range<Integer> getBlockCountRange() {
   1050             return mBlockCountRange;
   1051         }
   1052 
   1053         /** @hide */
   1054         public Range<Long> getBlocksPerSecondRange() {
   1055             return mBlocksPerSecondRange;
   1056         }
   1057 
   1058         /** @hide */
   1059         public Range<Rational> getAspectRatioRange(boolean blocks) {
   1060             return blocks ? mBlockAspectRatioRange : mAspectRatioRange;
   1061         }
   1062 
   1063         private void initWithPlatformLimits() {
   1064             mBitrateRange = Range.create(0, Integer.MAX_VALUE);
   1065 
   1066             mWidthRange  = SIZE_RANGE;
   1067             mHeightRange = SIZE_RANGE;
   1068             mFrameRateRange = FRAME_RATE_RANGE;
   1069 
   1070             mHorizontalBlockRange = SIZE_RANGE;
   1071             mVerticalBlockRange   = SIZE_RANGE;
   1072 
   1073             // full positive ranges are supported as these get calculated
   1074             mBlockCountRange      = POSITIVE_INTEGERS;
   1075             mBlocksPerSecondRange = POSITIVE_LONGS;
   1076 
   1077             mBlockAspectRatioRange = POSITIVE_RATIONALS;
   1078             mAspectRatioRange      = POSITIVE_RATIONALS;
   1079 
   1080             // YUV 4:2:0 requires 2:2 alignment
   1081             mWidthAlignment = 2;
   1082             mHeightAlignment = 2;
   1083             mBlockWidth = 2;
   1084             mBlockHeight = 2;
   1085             mSmallerDimensionUpperLimit = SIZE_RANGE.getUpper();
   1086         }
   1087 
   1088         private void parseFromInfo(MediaFormat info) {
   1089             final Map<String, Object> map = info.getMap();
   1090             Size blockSize = new Size(mBlockWidth, mBlockHeight);
   1091             Size alignment = new Size(mWidthAlignment, mHeightAlignment);
   1092             Range<Integer> counts = null, widths = null, heights = null;
   1093             Range<Integer> frameRates = null;
   1094             Range<Long> blockRates = null;
   1095             Range<Rational> ratios = null, blockRatios = null;
   1096 
   1097             blockSize = Utils.parseSize(map.get("block-size"), blockSize);
   1098             alignment = Utils.parseSize(map.get("alignment"), alignment);
   1099             counts = Utils.parseIntRange(map.get("block-count-range"), null);
   1100             blockRates =
   1101                 Utils.parseLongRange(map.get("blocks-per-second-range"), null);
   1102             {
   1103                 Object o = map.get("size-range");
   1104                 Pair<Size, Size> sizeRange = Utils.parseSizeRange(o);
   1105                 if (sizeRange != null) {
   1106                     try {
   1107                         widths = Range.create(
   1108                                 sizeRange.first.getWidth(),
   1109                                 sizeRange.second.getWidth());
   1110                         heights = Range.create(
   1111                                 sizeRange.first.getHeight(),
   1112                                 sizeRange.second.getHeight());
   1113                     } catch (IllegalArgumentException e) {
   1114                         Log.w(TAG, "could not parse size range '" + o + "'");
   1115                         widths = null;
   1116                         heights = null;
   1117                     }
   1118                 }
   1119             }
   1120             // for now this just means using the smaller max size as 2nd
   1121             // upper limit.
   1122             // for now we are keeping the profile specific "width/height
   1123             // in macroblocks" limits.
   1124             if (Integer.valueOf(1).equals(map.get("feature-can-swap-width-height"))) {
   1125                 if (widths != null) {
   1126                     mSmallerDimensionUpperLimit =
   1127                         Math.min(widths.getUpper(), heights.getUpper());
   1128                     widths = heights = widths.extend(heights);
   1129                 } else {
   1130                     Log.w(TAG, "feature can-swap-width-height is best used with size-range");
   1131                     mSmallerDimensionUpperLimit =
   1132                         Math.min(mWidthRange.getUpper(), mHeightRange.getUpper());
   1133                     mWidthRange = mHeightRange = mWidthRange.extend(mHeightRange);
   1134                 }
   1135             }
   1136 
   1137             ratios = Utils.parseRationalRange(
   1138                     map.get("block-aspect-ratio-range"), null);
   1139             blockRatios = Utils.parseRationalRange(
   1140                     map.get("pixel-aspect-ratio-range"), null);
   1141             frameRates = Utils.parseIntRange(map.get("frame-rate-range"), null);
   1142             if (frameRates != null) {
   1143                 try {
   1144                     frameRates = frameRates.intersect(FRAME_RATE_RANGE);
   1145                 } catch (IllegalArgumentException e) {
   1146                     Log.w(TAG, "frame rate range (" + frameRates
   1147                             + ") is out of limits: " + FRAME_RATE_RANGE);
   1148                     frameRates = null;
   1149                 }
   1150             }
   1151 
   1152             checkPowerOfTwo(
   1153                     blockSize.getWidth(), "block-size width must be power of two");
   1154             checkPowerOfTwo(
   1155                     blockSize.getHeight(), "block-size height must be power of two");
   1156 
   1157             checkPowerOfTwo(
   1158                     alignment.getWidth(), "alignment width must be power of two");
   1159             checkPowerOfTwo(
   1160                     alignment.getHeight(), "alignment height must be power of two");
   1161 
   1162             // update block-size and alignment
   1163             applyMacroBlockLimits(
   1164                     Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE,
   1165                     Long.MAX_VALUE, blockSize.getWidth(), blockSize.getHeight(),
   1166                     alignment.getWidth(), alignment.getHeight());
   1167 
   1168             if ((mParent.mError & ERROR_UNSUPPORTED) != 0) {
   1169                 // codec supports profiles that we don't know.
   1170                 // Use supplied values clipped to platform limits
   1171                 if (widths != null) {
   1172                     mWidthRange = SIZE_RANGE.intersect(widths);
   1173                 }
   1174                 if (heights != null) {
   1175                     mHeightRange = SIZE_RANGE.intersect(heights);
   1176                 }
   1177                 if (counts != null) {
   1178                     mBlockCountRange = POSITIVE_INTEGERS.intersect(
   1179                             Utils.factorRange(counts, mBlockWidth * mBlockHeight
   1180                                     / blockSize.getWidth() / blockSize.getHeight()));
   1181                 }
   1182                 if (blockRates != null) {
   1183                     mBlocksPerSecondRange = POSITIVE_LONGS.intersect(
   1184                             Utils.factorRange(blockRates, mBlockWidth * mBlockHeight
   1185                                     / blockSize.getWidth() / blockSize.getHeight()));
   1186                 }
   1187                 if (blockRatios != null) {
   1188                     mBlockAspectRatioRange = POSITIVE_RATIONALS.intersect(
   1189                             Utils.scaleRange(blockRatios,
   1190                                     mBlockHeight / blockSize.getHeight(),
   1191                                     mBlockWidth / blockSize.getWidth()));
   1192                 }
   1193                 if (ratios != null) {
   1194                     mAspectRatioRange = POSITIVE_RATIONALS.intersect(ratios);
   1195                 }
   1196                 if (frameRates != null) {
   1197                     mFrameRateRange = FRAME_RATE_RANGE.intersect(frameRates);
   1198                 }
   1199             } else {
   1200                 // no unsupported profile/levels, so restrict values to known limits
   1201                 if (widths != null) {
   1202                     mWidthRange = mWidthRange.intersect(widths);
   1203                 }
   1204                 if (heights != null) {
   1205                     mHeightRange = mHeightRange.intersect(heights);
   1206                 }
   1207                 if (counts != null) {
   1208                     mBlockCountRange = mBlockCountRange.intersect(
   1209                             Utils.factorRange(counts, mBlockWidth * mBlockHeight
   1210                                     / blockSize.getWidth() / blockSize.getHeight()));
   1211                 }
   1212                 if (blockRates != null) {
   1213                     mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(
   1214                             Utils.factorRange(blockRates, mBlockWidth * mBlockHeight
   1215                                     / blockSize.getWidth() / blockSize.getHeight()));
   1216                 }
   1217                 if (blockRatios != null) {
   1218                     mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(
   1219                             Utils.scaleRange(blockRatios,
   1220                                     mBlockHeight / blockSize.getHeight(),
   1221                                     mBlockWidth / blockSize.getWidth()));
   1222                 }
   1223                 if (ratios != null) {
   1224                     mAspectRatioRange = mAspectRatioRange.intersect(ratios);
   1225                 }
   1226                 if (frameRates != null) {
   1227                     mFrameRateRange = mFrameRateRange.intersect(frameRates);
   1228                 }
   1229             }
   1230             updateLimits();
   1231         }
   1232 
   1233         private void applyBlockLimits(
   1234                 int blockWidth, int blockHeight,
   1235                 Range<Integer> counts, Range<Long> rates, Range<Rational> ratios) {
   1236             checkPowerOfTwo(blockWidth, "blockWidth must be a power of two");
   1237             checkPowerOfTwo(blockHeight, "blockHeight must be a power of two");
   1238 
   1239             final int newBlockWidth = Math.max(blockWidth, mBlockWidth);
   1240             final int newBlockHeight = Math.max(blockHeight, mBlockHeight);
   1241 
   1242             // factor will always be a power-of-2
   1243             int factor =
   1244                 newBlockWidth * newBlockHeight / mBlockWidth / mBlockHeight;
   1245             if (factor != 1) {
   1246                 mBlockCountRange = Utils.factorRange(mBlockCountRange, factor);
   1247                 mBlocksPerSecondRange = Utils.factorRange(
   1248                         mBlocksPerSecondRange, factor);
   1249                 mBlockAspectRatioRange = Utils.scaleRange(
   1250                         mBlockAspectRatioRange,
   1251                         newBlockHeight / mBlockHeight,
   1252                         newBlockWidth / mBlockWidth);
   1253                 mHorizontalBlockRange = Utils.factorRange(
   1254                         mHorizontalBlockRange, newBlockWidth / mBlockWidth);
   1255                 mVerticalBlockRange = Utils.factorRange(
   1256                         mVerticalBlockRange, newBlockHeight / mBlockHeight);
   1257             }
   1258             factor = newBlockWidth * newBlockHeight / blockWidth / blockHeight;
   1259             if (factor != 1) {
   1260                 counts = Utils.factorRange(counts, factor);
   1261                 rates = Utils.factorRange(rates, factor);
   1262                 ratios = Utils.scaleRange(
   1263                         ratios, newBlockHeight / blockHeight,
   1264                         newBlockWidth / blockWidth);
   1265             }
   1266             mBlockCountRange = mBlockCountRange.intersect(counts);
   1267             mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(rates);
   1268             mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(ratios);
   1269             mBlockWidth = newBlockWidth;
   1270             mBlockHeight = newBlockHeight;
   1271         }
   1272 
   1273         private void applyAlignment(int widthAlignment, int heightAlignment) {
   1274             checkPowerOfTwo(widthAlignment, "widthAlignment must be a power of two");
   1275             checkPowerOfTwo(heightAlignment, "heightAlignment must be a power of two");
   1276 
   1277             if (widthAlignment > mBlockWidth || heightAlignment > mBlockHeight) {
   1278                 // maintain assumption that 0 < alignment <= block-size
   1279                 applyBlockLimits(
   1280                         Math.max(widthAlignment, mBlockWidth),
   1281                         Math.max(heightAlignment, mBlockHeight),
   1282                         POSITIVE_INTEGERS, POSITIVE_LONGS, POSITIVE_RATIONALS);
   1283             }
   1284 
   1285             mWidthAlignment = Math.max(widthAlignment, mWidthAlignment);
   1286             mHeightAlignment = Math.max(heightAlignment, mHeightAlignment);
   1287 
   1288             mWidthRange = Utils.alignRange(mWidthRange, mWidthAlignment);
   1289             mHeightRange = Utils.alignRange(mHeightRange, mHeightAlignment);
   1290         }
   1291 
   1292         private void updateLimits() {
   1293             // pixels -> blocks <- counts
   1294             mHorizontalBlockRange = mHorizontalBlockRange.intersect(
   1295                     Utils.factorRange(mWidthRange, mBlockWidth));
   1296             mHorizontalBlockRange = mHorizontalBlockRange.intersect(
   1297                     Range.create(
   1298                             mBlockCountRange.getLower() / mVerticalBlockRange.getUpper(),
   1299                             mBlockCountRange.getUpper() / mVerticalBlockRange.getLower()));
   1300             mVerticalBlockRange = mVerticalBlockRange.intersect(
   1301                     Utils.factorRange(mHeightRange, mBlockHeight));
   1302             mVerticalBlockRange = mVerticalBlockRange.intersect(
   1303                     Range.create(
   1304                             mBlockCountRange.getLower() / mHorizontalBlockRange.getUpper(),
   1305                             mBlockCountRange.getUpper() / mHorizontalBlockRange.getLower()));
   1306             mBlockCountRange = mBlockCountRange.intersect(
   1307                     Range.create(
   1308                             mHorizontalBlockRange.getLower()
   1309                                     * mVerticalBlockRange.getLower(),
   1310                             mHorizontalBlockRange.getUpper()
   1311                                     * mVerticalBlockRange.getUpper()));
   1312             mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(
   1313                     new Rational(
   1314                             mHorizontalBlockRange.getLower(), mVerticalBlockRange.getUpper()),
   1315                     new Rational(
   1316                             mHorizontalBlockRange.getUpper(), mVerticalBlockRange.getLower()));
   1317 
   1318             // blocks -> pixels
   1319             mWidthRange = mWidthRange.intersect(
   1320                     (mHorizontalBlockRange.getLower() - 1) * mBlockWidth + mWidthAlignment,
   1321                     mHorizontalBlockRange.getUpper() * mBlockWidth);
   1322             mHeightRange = mHeightRange.intersect(
   1323                     (mVerticalBlockRange.getLower() - 1) * mBlockHeight + mHeightAlignment,
   1324                     mVerticalBlockRange.getUpper() * mBlockHeight);
   1325             mAspectRatioRange = mAspectRatioRange.intersect(
   1326                     new Rational(mWidthRange.getLower(), mHeightRange.getUpper()),
   1327                     new Rational(mWidthRange.getUpper(), mHeightRange.getLower()));
   1328 
   1329             mSmallerDimensionUpperLimit = Math.min(
   1330                     mSmallerDimensionUpperLimit,
   1331                     Math.min(mWidthRange.getUpper(), mHeightRange.getUpper()));
   1332 
   1333             // blocks -> rate
   1334             mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(
   1335                     mBlockCountRange.getLower() * (long)mFrameRateRange.getLower(),
   1336                     mBlockCountRange.getUpper() * (long)mFrameRateRange.getUpper());
   1337             mFrameRateRange = mFrameRateRange.intersect(
   1338                     (int)(mBlocksPerSecondRange.getLower()
   1339                             / mBlockCountRange.getUpper()),
   1340                     (int)(mBlocksPerSecondRange.getUpper()
   1341                             / (double)mBlockCountRange.getLower()));
   1342         }
   1343 
   1344         private void applyMacroBlockLimits(
   1345                 int maxHorizontalBlocks, int maxVerticalBlocks,
   1346                 int maxBlocks, long maxBlocksPerSecond,
   1347                 int blockWidth, int blockHeight,
   1348                 int widthAlignment, int heightAlignment) {
   1349             applyAlignment(widthAlignment, heightAlignment);
   1350             applyBlockLimits(
   1351                     blockWidth, blockHeight, Range.create(1, maxBlocks),
   1352                     Range.create(1L, maxBlocksPerSecond),
   1353                     Range.create(
   1354                             new Rational(1, maxVerticalBlocks),
   1355                             new Rational(maxHorizontalBlocks, 1)));
   1356             mHorizontalBlockRange =
   1357                     mHorizontalBlockRange.intersect(
   1358                             1, maxHorizontalBlocks / (mBlockWidth / blockWidth));
   1359             mVerticalBlockRange =
   1360                     mVerticalBlockRange.intersect(
   1361                             1, maxVerticalBlocks / (mBlockHeight / blockHeight));
   1362         }
   1363 
   1364         private void applyLevelLimits() {
   1365             int maxBlocksPerSecond = 0;
   1366             int maxBlocks = 0;
   1367             int maxBps = 0;
   1368             int maxDPBBlocks = 0;
   1369 
   1370             int errors = ERROR_NONE_SUPPORTED;
   1371             CodecProfileLevel[] profileLevels = mParent.profileLevels;
   1372             String mime = mParent.getMimeType();
   1373 
   1374             if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC)) {
   1375                 maxBlocks = 99;
   1376                 maxBlocksPerSecond = 1485;
   1377                 maxBps = 64000;
   1378                 maxDPBBlocks = 396;
   1379                 for (CodecProfileLevel profileLevel: profileLevels) {
   1380                     int MBPS = 0, FS = 0, BR = 0, DPB = 0;
   1381                     boolean supported = true;
   1382                     switch (profileLevel.level) {
   1383                         case CodecProfileLevel.AVCLevel1:
   1384                             MBPS =    1485; FS =    99; BR =     64; DPB =    396; break;
   1385                         case CodecProfileLevel.AVCLevel1b:
   1386                             MBPS =    1485; FS =    99; BR =    128; DPB =    396; break;
   1387                         case CodecProfileLevel.AVCLevel11:
   1388                             MBPS =    3000; FS =   396; BR =    192; DPB =    900; break;
   1389                         case CodecProfileLevel.AVCLevel12:
   1390                             MBPS =    6000; FS =   396; BR =    384; DPB =   2376; break;
   1391                         case CodecProfileLevel.AVCLevel13:
   1392                             MBPS =   11880; FS =   396; BR =    768; DPB =   2376; break;
   1393                         case CodecProfileLevel.AVCLevel2:
   1394                             MBPS =   11880; FS =   396; BR =   2000; DPB =   2376; break;
   1395                         case CodecProfileLevel.AVCLevel21:
   1396                             MBPS =   19800; FS =   792; BR =   4000; DPB =   4752; break;
   1397                         case CodecProfileLevel.AVCLevel22:
   1398                             MBPS =   20250; FS =  1620; BR =   4000; DPB =   8100; break;
   1399                         case CodecProfileLevel.AVCLevel3:
   1400                             MBPS =   40500; FS =  1620; BR =  10000; DPB =   8100; break;
   1401                         case CodecProfileLevel.AVCLevel31:
   1402                             MBPS =  108000; FS =  3600; BR =  14000; DPB =  18000; break;
   1403                         case CodecProfileLevel.AVCLevel32:
   1404                             MBPS =  216000; FS =  5120; BR =  20000; DPB =  20480; break;
   1405                         case CodecProfileLevel.AVCLevel4:
   1406                             MBPS =  245760; FS =  8192; BR =  20000; DPB =  32768; break;
   1407                         case CodecProfileLevel.AVCLevel41:
   1408                             MBPS =  245760; FS =  8192; BR =  50000; DPB =  32768; break;
   1409                         case CodecProfileLevel.AVCLevel42:
   1410                             MBPS =  522240; FS =  8704; BR =  50000; DPB =  34816; break;
   1411                         case CodecProfileLevel.AVCLevel5:
   1412                             MBPS =  589824; FS = 22080; BR = 135000; DPB = 110400; break;
   1413                         case CodecProfileLevel.AVCLevel51:
   1414                             MBPS =  983040; FS = 36864; BR = 240000; DPB = 184320; break;
   1415                         case CodecProfileLevel.AVCLevel52:
   1416                             MBPS = 2073600; FS = 36864; BR = 240000; DPB = 184320; break;
   1417                         default:
   1418                             Log.w(TAG, "Unrecognized level "
   1419                                     + profileLevel.level + " for " + mime);
   1420                             errors |= ERROR_UNRECOGNIZED;
   1421                     }
   1422                     switch (profileLevel.profile) {
   1423                         case CodecProfileLevel.AVCProfileHigh:
   1424                             BR *= 1250; break;
   1425                         case CodecProfileLevel.AVCProfileHigh10:
   1426                             BR *= 3000; break;
   1427                         case CodecProfileLevel.AVCProfileExtended:
   1428                         case CodecProfileLevel.AVCProfileHigh422:
   1429                         case CodecProfileLevel.AVCProfileHigh444:
   1430                             Log.w(TAG, "Unsupported profile "
   1431                                     + profileLevel.profile + " for " + mime);
   1432                             errors |= ERROR_UNSUPPORTED;
   1433                             supported = false;
   1434                             // fall through - treat as base profile
   1435                         case CodecProfileLevel.AVCProfileBaseline:
   1436                         case CodecProfileLevel.AVCProfileMain:
   1437                             BR *= 1000; break;
   1438                         default:
   1439                             Log.w(TAG, "Unrecognized profile "
   1440                                     + profileLevel.profile + " for " + mime);
   1441                             errors |= ERROR_UNRECOGNIZED;
   1442                             BR *= 1000;
   1443                     }
   1444                     if (supported) {
   1445                         errors &= ~ERROR_NONE_SUPPORTED;
   1446                     }
   1447                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
   1448                     maxBlocks = Math.max(FS, maxBlocks);
   1449                     maxBps = Math.max(BR, maxBps);
   1450                     maxDPBBlocks = Math.max(maxDPBBlocks, DPB);
   1451                 }
   1452 
   1453                 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8));
   1454                 applyMacroBlockLimits(
   1455                         maxLengthInBlocks, maxLengthInBlocks,
   1456                         maxBlocks, maxBlocksPerSecond,
   1457                         16 /* blockWidth */, 16 /* blockHeight */,
   1458                         1 /* widthAlignment */, 1 /* heightAlignment */);
   1459             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) {
   1460                 int maxWidth = 11, maxHeight = 9, maxRate = 15;
   1461                 maxBlocks = 99;
   1462                 maxBlocksPerSecond = 1485;
   1463                 maxBps = 64000;
   1464                 for (CodecProfileLevel profileLevel: profileLevels) {
   1465                     int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0;
   1466                     boolean supported = true;
   1467                     switch (profileLevel.profile) {
   1468                         case CodecProfileLevel.MPEG4ProfileSimple:
   1469                             switch (profileLevel.level) {
   1470                                 case CodecProfileLevel.MPEG4Level0:
   1471                                     FR = 15; W = 11; H =  9; MBPS =  1485; FS =  99; BR =  64; break;
   1472                                 case CodecProfileLevel.MPEG4Level1:
   1473                                     FR = 30; W = 11; H =  9; MBPS =  1485; FS =  99; BR =  64; break;
   1474                                 case CodecProfileLevel.MPEG4Level0b:
   1475                                     FR = 30; W = 11; H =  9; MBPS =  1485; FS =  99; BR = 128; break;
   1476                                 case CodecProfileLevel.MPEG4Level2:
   1477                                     FR = 30; W = 22; H = 18; MBPS =  5940; FS = 396; BR = 128; break;
   1478                                 case CodecProfileLevel.MPEG4Level3:
   1479                                     FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384; break;
   1480                                 case CodecProfileLevel.MPEG4Level4:
   1481                                 case CodecProfileLevel.MPEG4Level4a:
   1482                                 case CodecProfileLevel.MPEG4Level5:
   1483                                     // While MPEG4 SP does not have level 4 or 5, some vendors
   1484                                     // report it. Use the same limits as level 3, but mark as
   1485                                     // unsupported.
   1486                                     FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384;
   1487                                     supported = false;
   1488                                     break;
   1489                                 default:
   1490                                     Log.w(TAG, "Unrecognized profile/level "
   1491                                             + profileLevel.profile + "/"
   1492                                             + profileLevel.level + " for " + mime);
   1493                                     errors |= ERROR_UNRECOGNIZED;
   1494                             }
   1495                             break;
   1496                         case CodecProfileLevel.MPEG4ProfileAdvancedSimple:
   1497                             switch (profileLevel.level) {
   1498                                 case CodecProfileLevel.MPEG4Level0:
   1499                                 case CodecProfileLevel.MPEG4Level1:
   1500                                     FR = 30; W = 11; H =  9; MBPS =  2970; FS =   99; BR =  128; break;
   1501                                 case CodecProfileLevel.MPEG4Level2:
   1502                                     FR = 30; W = 22; H = 18; MBPS =  5940; FS =  396; BR =  384; break;
   1503                                 case CodecProfileLevel.MPEG4Level3:
   1504                                     FR = 30; W = 22; H = 18; MBPS = 11880; FS =  396; BR =  768; break;
   1505                                 // case CodecProfileLevel.MPEG4Level3b:
   1506                                 // TODO: MPEG4 level 3b is not defined in OMX
   1507                                 //  MBPS = 11880; FS =  396; BR = 1500; break;
   1508                                 case CodecProfileLevel.MPEG4Level4:
   1509                                 case CodecProfileLevel.MPEG4Level4a:
   1510                                     // TODO: MPEG4 level 4a is not defined in spec
   1511                                     FR = 30; W = 44; H = 36; MBPS = 23760; FS =  792; BR = 3000; break;
   1512                                 case CodecProfileLevel.MPEG4Level5:
   1513                                     FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 8000; break;
   1514                                 default:
   1515                                     Log.w(TAG, "Unrecognized profile/level "
   1516                                             + profileLevel.profile + "/"
   1517                                             + profileLevel.level + " for " + mime);
   1518                                     errors |= ERROR_UNRECOGNIZED;
   1519                             }
   1520                             break;
   1521                         case CodecProfileLevel.MPEG4ProfileMain:             // 2-4
   1522                         case CodecProfileLevel.MPEG4ProfileNbit:             // 2
   1523                         case CodecProfileLevel.MPEG4ProfileAdvancedRealTime: // 1-4
   1524                         case CodecProfileLevel.MPEG4ProfileCoreScalable:     // 1-3
   1525                         case CodecProfileLevel.MPEG4ProfileAdvancedCoding:   // 1-4
   1526                         case CodecProfileLevel.MPEG4ProfileCore:             // 1-2
   1527                         case CodecProfileLevel.MPEG4ProfileAdvancedCore:     // 1-4
   1528                         case CodecProfileLevel.MPEG4ProfileSimpleScalable:   // 0-2
   1529                         case CodecProfileLevel.MPEG4ProfileAdvancedScalable: // 1-3
   1530                         case CodecProfileLevel.MPEG4ProfileHybrid:           // 1-2
   1531                         case CodecProfileLevel.MPEG4ProfileBasicAnimated:    // 1-2
   1532                         case CodecProfileLevel.MPEG4ProfileScalableTexture:  // 1
   1533                         case CodecProfileLevel.MPEG4ProfileSimpleFace:       // 1-2
   1534                         case CodecProfileLevel.MPEG4ProfileSimpleFBA:        // 1-2
   1535                             Log.i(TAG, "Unsupported profile "
   1536                                     + profileLevel.profile + " for " + mime);
   1537                             errors |= ERROR_UNSUPPORTED;
   1538                             supported = false;
   1539                             break;
   1540                         default:
   1541                             Log.w(TAG, "Unrecognized profile "
   1542                                     + profileLevel.profile + " for " + mime);
   1543                             errors |= ERROR_UNRECOGNIZED;
   1544                     }
   1545                     if (supported) {
   1546                         errors &= ~ERROR_NONE_SUPPORTED;
   1547                     }
   1548                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
   1549                     maxBlocks = Math.max(FS, maxBlocks);
   1550                     maxBps = Math.max(BR * 1000, maxBps);
   1551                     maxWidth = Math.max(W, maxWidth);
   1552                     maxHeight = Math.max(H, maxHeight);
   1553                     maxRate = Math.max(FR, maxRate);
   1554                 }
   1555                 applyMacroBlockLimits(maxWidth, maxHeight,
   1556                         maxBlocks, maxBlocksPerSecond,
   1557                         16 /* blockWidth */, 16 /* blockHeight */,
   1558                         1 /* widthAlignment */, 1 /* heightAlignment */);
   1559                 mFrameRateRange = mFrameRateRange.intersect(12, maxRate);
   1560             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) {
   1561                 int maxWidth = 11, maxHeight = 9, maxRate = 15;
   1562                 maxBlocks = 99;
   1563                 maxBlocksPerSecond = 1485;
   1564                 maxBps = 64000;
   1565                 for (CodecProfileLevel profileLevel: profileLevels) {
   1566                     int MBPS = 0, BR = 0, FR = 0, W = 0, H = 0;
   1567                     switch (profileLevel.level) {
   1568                         case CodecProfileLevel.H263Level10:
   1569                             FR = 15; W = 11; H =  9; BR =   1; MBPS =  W * H * FR; break;
   1570                         case CodecProfileLevel.H263Level20:
   1571                             // only supports CIF, 0..QCIF
   1572                             FR = 30; W = 22; H = 18; BR =   2; MBPS =  W * H * FR; break;
   1573                         case CodecProfileLevel.H263Level30:
   1574                             // only supports CIF, 0..QCIF
   1575                             FR = 30; W = 22; H = 18; BR =   6; MBPS =  W * H * FR; break;
   1576                         case CodecProfileLevel.H263Level40:
   1577                             // only supports CIF, 0..QCIF
   1578                             FR = 30; W = 22; H = 18; BR =  32; MBPS =  W * H * FR; break;
   1579                         case CodecProfileLevel.H263Level45:
   1580                             // only implies level 10 support
   1581                             FR = 30; W = 11; H =  9; BR =   2; MBPS =  W * H * FR; break;
   1582                         case CodecProfileLevel.H263Level50:
   1583                             // only supports 50fps for H > 15
   1584                             FR = 60; W = 22; H = 18; BR =  64; MBPS =  W * H * 50; break;
   1585                         case CodecProfileLevel.H263Level60:
   1586                             // only supports 50fps for H > 15
   1587                             FR = 60; W = 45; H = 18; BR = 128; MBPS =  W * H * 50; break;
   1588                         case CodecProfileLevel.H263Level70:
   1589                             // only supports 50fps for H > 30
   1590                             FR = 60; W = 45; H = 36; BR = 256; MBPS =  W * H * 50; break;
   1591                         default:
   1592                             Log.w(TAG, "Unrecognized profile/level " + profileLevel.profile
   1593                                     + "/" + profileLevel.level + " for " + mime);
   1594                             errors |= ERROR_UNRECOGNIZED;
   1595                     }
   1596                     switch (profileLevel.profile) {
   1597                         case CodecProfileLevel.H263ProfileBackwardCompatible:
   1598                         case CodecProfileLevel.H263ProfileBaseline:
   1599                         case CodecProfileLevel.H263ProfileH320Coding:
   1600                         case CodecProfileLevel.H263ProfileHighCompression:
   1601                         case CodecProfileLevel.H263ProfileHighLatency:
   1602                         case CodecProfileLevel.H263ProfileInterlace:
   1603                         case CodecProfileLevel.H263ProfileInternet:
   1604                         case CodecProfileLevel.H263ProfileISWV2:
   1605                         case CodecProfileLevel.H263ProfileISWV3:
   1606                             break;
   1607                         default:
   1608                             Log.w(TAG, "Unrecognized profile "
   1609                                     + profileLevel.profile + " for " + mime);
   1610                             errors |= ERROR_UNRECOGNIZED;
   1611                     }
   1612                     errors &= ~ERROR_NONE_SUPPORTED;
   1613                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
   1614                     maxBlocks = Math.max(W * H, maxBlocks);
   1615                     maxBps = Math.max(BR * 64000, maxBps);
   1616                     maxWidth = Math.max(W, maxWidth);
   1617                     maxHeight = Math.max(H, maxHeight);
   1618                     maxRate = Math.max(FR, maxRate);
   1619                 }
   1620                 applyMacroBlockLimits(maxWidth, maxHeight,
   1621                         maxBlocks, maxBlocksPerSecond,
   1622                         16 /* blockWidth */, 16 /* blockHeight */,
   1623                         1 /* widthAlignment */, 1 /* heightAlignment */);
   1624                 mFrameRateRange = Range.create(1, maxRate);
   1625             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8) ||
   1626                     mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) {
   1627                 maxBlocks = maxBlocksPerSecond = Integer.MAX_VALUE;
   1628 
   1629                 // TODO: set to 100Mbps for now, need a number for VPX
   1630                 maxBps = 100000000;
   1631 
   1632                 // profile levels are not indicative for VPx, but verify
   1633                 // them nonetheless
   1634                 for (CodecProfileLevel profileLevel: profileLevels) {
   1635                     switch (profileLevel.level) {
   1636                         case CodecProfileLevel.VP8Level_Version0:
   1637                         case CodecProfileLevel.VP8Level_Version1:
   1638                         case CodecProfileLevel.VP8Level_Version2:
   1639                         case CodecProfileLevel.VP8Level_Version3:
   1640                             break;
   1641                         default:
   1642                             Log.w(TAG, "Unrecognized level "
   1643                                     + profileLevel.level + " for " + mime);
   1644                             errors |= ERROR_UNRECOGNIZED;
   1645                     }
   1646                     switch (profileLevel.profile) {
   1647                         case CodecProfileLevel.VP8ProfileMain:
   1648                             break;
   1649                         default:
   1650                             Log.w(TAG, "Unrecognized profile "
   1651                                     + profileLevel.profile + " for " + mime);
   1652                             errors |= ERROR_UNRECOGNIZED;
   1653                     }
   1654                     errors &= ~ERROR_NONE_SUPPORTED;
   1655                 }
   1656 
   1657                 final int blockSize =
   1658                     mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8) ? 16 : 8;
   1659                 applyMacroBlockLimits(Short.MAX_VALUE, Short.MAX_VALUE,
   1660                         maxBlocks, maxBlocksPerSecond, blockSize, blockSize,
   1661                         1 /* widthAlignment */, 1 /* heightAlignment */);
   1662             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
   1663                 maxBlocks = 36864;
   1664                 maxBlocksPerSecond = maxBlocks * 15;
   1665                 maxBps = 128000;
   1666                 for (CodecProfileLevel profileLevel: profileLevels) {
   1667                     double FR = 0;
   1668                     int FS = 0;
   1669                     int BR = 0;
   1670                     switch (profileLevel.level) {
   1671                         case CodecProfileLevel.HEVCMainTierLevel1:
   1672                         case CodecProfileLevel.HEVCHighTierLevel1:
   1673                             FR =    15; FS =    36864; BR =    128; break;
   1674                         case CodecProfileLevel.HEVCMainTierLevel2:
   1675                         case CodecProfileLevel.HEVCHighTierLevel2:
   1676                             FR =    30; FS =   122880; BR =   1500; break;
   1677                         case CodecProfileLevel.HEVCMainTierLevel21:
   1678                         case CodecProfileLevel.HEVCHighTierLevel21:
   1679                             FR =    30; FS =   245760; BR =   3000; break;
   1680                         case CodecProfileLevel.HEVCMainTierLevel3:
   1681                         case CodecProfileLevel.HEVCHighTierLevel3:
   1682                             FR =    30; FS =   552960; BR =   6000; break;
   1683                         case CodecProfileLevel.HEVCMainTierLevel31:
   1684                         case CodecProfileLevel.HEVCHighTierLevel31:
   1685                             FR = 33.75; FS =   983040; BR =  10000; break;
   1686                         case CodecProfileLevel.HEVCMainTierLevel4:
   1687                             FR =    30; FS =  2228224; BR =  12000; break;
   1688                         case CodecProfileLevel.HEVCHighTierLevel4:
   1689                             FR =    30; FS =  2228224; BR =  30000; break;
   1690                         case CodecProfileLevel.HEVCMainTierLevel41:
   1691                             FR =    60; FS =  2228224; BR =  20000; break;
   1692                         case CodecProfileLevel.HEVCHighTierLevel41:
   1693                             FR =    60; FS =  2228224; BR =  50000; break;
   1694                         case CodecProfileLevel.HEVCMainTierLevel5:
   1695                             FR =    30; FS =  8912896; BR =  25000; break;
   1696                         case CodecProfileLevel.HEVCHighTierLevel5:
   1697                             FR =    30; FS =  8912896; BR = 100000; break;
   1698                         case CodecProfileLevel.HEVCMainTierLevel51:
   1699                             FR =    60; FS =  8912896; BR =  40000; break;
   1700                         case CodecProfileLevel.HEVCHighTierLevel51:
   1701                             FR =    60; FS =  8912896; BR = 160000; break;
   1702                         case CodecProfileLevel.HEVCMainTierLevel52:
   1703                             FR =   120; FS =  8912896; BR =  60000; break;
   1704                         case CodecProfileLevel.HEVCHighTierLevel52:
   1705                             FR =   120; FS =  8912896; BR = 240000; break;
   1706                         case CodecProfileLevel.HEVCMainTierLevel6:
   1707                             FR =    30; FS = 35651584; BR =  60000; break;
   1708                         case CodecProfileLevel.HEVCHighTierLevel6:
   1709                             FR =    30; FS = 35651584; BR = 240000; break;
   1710                         case CodecProfileLevel.HEVCMainTierLevel61:
   1711                             FR =    60; FS = 35651584; BR = 120000; break;
   1712                         case CodecProfileLevel.HEVCHighTierLevel61:
   1713                             FR =    60; FS = 35651584; BR = 480000; break;
   1714                         case CodecProfileLevel.HEVCMainTierLevel62:
   1715                             FR =   120; FS = 35651584; BR = 240000; break;
   1716                         case CodecProfileLevel.HEVCHighTierLevel62:
   1717                             FR =   120; FS = 35651584; BR = 800000; break;
   1718                         default:
   1719                             Log.w(TAG, "Unrecognized level "
   1720                                     + profileLevel.level + " for " + mime);
   1721                             errors |= ERROR_UNRECOGNIZED;
   1722                     }
   1723                     switch (profileLevel.profile) {
   1724                         case CodecProfileLevel.HEVCProfileMain:
   1725                         case CodecProfileLevel.HEVCProfileMain10:
   1726                             break;
   1727                         default:
   1728                             Log.w(TAG, "Unrecognized profile "
   1729                                     + profileLevel.profile + " for " + mime);
   1730                             errors |= ERROR_UNRECOGNIZED;
   1731                     }
   1732 
   1733                     /* DPB logic:
   1734                     if      (width * height <= FS / 4)    DPB = 16;
   1735                     else if (width * height <= FS / 2)    DPB = 12;
   1736                     else if (width * height <= FS * 0.75) DPB = 8;
   1737                     else                                  DPB = 6;
   1738                     */
   1739 
   1740                     errors &= ~ERROR_NONE_SUPPORTED;
   1741                     maxBlocksPerSecond = Math.max((int)(FR * FS), maxBlocksPerSecond);
   1742                     maxBlocks = Math.max(FS, maxBlocks);
   1743                     maxBps = Math.max(BR * 1000, maxBps);
   1744                 }
   1745 
   1746                 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8));
   1747                 // CTBs are at least 8x8
   1748                 maxBlocks = Utils.divUp(maxBlocks, 8 * 8);
   1749                 maxBlocksPerSecond = Utils.divUp(maxBlocksPerSecond, 8 * 8);
   1750                 maxLengthInBlocks = Utils.divUp(maxLengthInBlocks, 8);
   1751 
   1752                 applyMacroBlockLimits(
   1753                         maxLengthInBlocks, maxLengthInBlocks,
   1754                         maxBlocks, maxBlocksPerSecond,
   1755                         8 /* blockWidth */, 8 /* blockHeight */,
   1756                         1 /* widthAlignment */, 1 /* heightAlignment */);
   1757             } else {
   1758                 Log.w(TAG, "Unsupported mime " + mime);
   1759                 // using minimal bitrate here.  should be overriden by
   1760                 // info from media_codecs.xml
   1761                 maxBps = 64000;
   1762                 errors |= ERROR_UNSUPPORTED;
   1763             }
   1764             mBitrateRange = Range.create(1, maxBps);
   1765             mParent.mError |= errors;
   1766         }
   1767     }
   1768 
   1769     /**
   1770      * A class that supports querying the encoding capabilities of a codec.
   1771      */
   1772     public static final class EncoderCapabilities {
   1773         /**
   1774          * Returns the supported range of quality values.
   1775          *
   1776          * @hide
   1777          */
   1778         public Range<Integer> getQualityRange() {
   1779             return mQualityRange;
   1780         }
   1781 
   1782         /**
   1783          * Returns the supported range of encoder complexity values.
   1784          * <p>
   1785          * Some codecs may support multiple complexity levels, where higher
   1786          * complexity values use more encoder tools (e.g. perform more
   1787          * intensive calculations) to improve the quality or the compression
   1788          * ratio.  Use a lower value to save power and/or time.
   1789          */
   1790         public Range<Integer> getComplexityRange() {
   1791             return mComplexityRange;
   1792         }
   1793 
   1794         /** Constant quality mode */
   1795         public static final int BITRATE_MODE_CQ = 0;
   1796         /** Variable bitrate mode */
   1797         public static final int BITRATE_MODE_VBR = 1;
   1798         /** Constant bitrate mode */
   1799         public static final int BITRATE_MODE_CBR = 2;
   1800 
   1801         private static final Feature[] bitrates = new Feature[] {
   1802             new Feature("VBR", BITRATE_MODE_VBR, true),
   1803             new Feature("CBR", BITRATE_MODE_CBR, false),
   1804             new Feature("CQ",  BITRATE_MODE_CQ,  false)
   1805         };
   1806 
   1807         private static int parseBitrateMode(String mode) {
   1808             for (Feature feat: bitrates) {
   1809                 if (feat.mName.equalsIgnoreCase(mode)) {
   1810                     return feat.mValue;
   1811                 }
   1812             }
   1813             return 0;
   1814         }
   1815 
   1816         /**
   1817          * Query whether a bitrate mode is supported.
   1818          */
   1819         public boolean isBitrateModeSupported(int mode) {
   1820             for (Feature feat: bitrates) {
   1821                 if (mode == feat.mValue) {
   1822                     return (mBitControl & (1 << mode)) != 0;
   1823                 }
   1824             }
   1825             return false;
   1826         }
   1827 
   1828         private Range<Integer> mQualityRange;
   1829         private Range<Integer> mComplexityRange;
   1830         private CodecCapabilities mParent;
   1831 
   1832         /* no public constructor */
   1833         private EncoderCapabilities() { }
   1834 
   1835         /** @hide */
   1836         public static EncoderCapabilities create(
   1837                 MediaFormat info, CodecCapabilities parent) {
   1838             EncoderCapabilities caps = new EncoderCapabilities();
   1839             caps.init(info, parent);
   1840             return caps;
   1841         }
   1842 
   1843         /** @hide */
   1844         public void init(MediaFormat info, CodecCapabilities parent) {
   1845             // no support for complexity or quality yet
   1846             mParent = parent;
   1847             mComplexityRange = Range.create(0, 0);
   1848             mQualityRange = Range.create(0, 0);
   1849             mBitControl = (1 << BITRATE_MODE_VBR);
   1850 
   1851             applyLevelLimits();
   1852             parseFromInfo(info);
   1853         }
   1854 
   1855         private void applyLevelLimits() {
   1856             String mime = mParent.getMimeType();
   1857             if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
   1858                 mComplexityRange = Range.create(0, 8);
   1859                 mBitControl = (1 << BITRATE_MODE_CQ);
   1860             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)
   1861                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)
   1862                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW)
   1863                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)
   1864                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) {
   1865                 mBitControl = (1 << BITRATE_MODE_CBR);
   1866             }
   1867         }
   1868 
   1869         private int mBitControl;
   1870         private Integer mDefaultComplexity;
   1871         private Integer mDefaultQuality;
   1872         private String mQualityScale;
   1873 
   1874         private void parseFromInfo(MediaFormat info) {
   1875             Map<String, Object> map = info.getMap();
   1876 
   1877             if (info.containsKey("complexity-range")) {
   1878                 mComplexityRange = Utils
   1879                         .parseIntRange(info.getString("complexity-range"), mComplexityRange);
   1880                 // TODO should we limit this to level limits?
   1881             }
   1882             if (info.containsKey("quality-range")) {
   1883                 mQualityRange = Utils
   1884                         .parseIntRange(info.getString("quality-range"), mQualityRange);
   1885             }
   1886             if (info.containsKey("feature-bitrate-control")) {
   1887                 for (String mode: info.getString("feature-bitrate-control").split(",")) {
   1888                     mBitControl |= parseBitrateMode(mode);
   1889                 }
   1890             }
   1891 
   1892             try {
   1893                 mDefaultComplexity = Integer.parseInt((String)map.get("complexity-default"));
   1894             } catch (NumberFormatException e) { }
   1895 
   1896             try {
   1897                 mDefaultQuality = Integer.parseInt((String)map.get("quality-default"));
   1898             } catch (NumberFormatException e) { }
   1899 
   1900             mQualityScale = (String)map.get("quality-scale");
   1901         }
   1902 
   1903         private boolean supports(
   1904                 Integer complexity, Integer quality, Integer profile) {
   1905             boolean ok = true;
   1906             if (ok && complexity != null) {
   1907                 ok = mComplexityRange.contains(complexity);
   1908             }
   1909             if (ok && quality != null) {
   1910                 ok = mQualityRange.contains(quality);
   1911             }
   1912             if (ok && profile != null) {
   1913                 for (CodecProfileLevel pl: mParent.profileLevels) {
   1914                     if (pl.profile == profile) {
   1915                         profile = null;
   1916                         break;
   1917                     }
   1918                 }
   1919                 ok = profile == null;
   1920             }
   1921             return ok;
   1922         }
   1923 
   1924         /** @hide */
   1925         public void setDefaultFormat(MediaFormat format) {
   1926             // don't list trivial quality/complexity as default for now
   1927             if (!mQualityRange.getUpper().equals(mQualityRange.getLower())
   1928                     && mDefaultQuality != null) {
   1929                 format.setInteger(MediaFormat.KEY_QUALITY, mDefaultQuality);
   1930             }
   1931             if (!mComplexityRange.getUpper().equals(mComplexityRange.getLower())
   1932                     && mDefaultComplexity != null) {
   1933                 format.setInteger(MediaFormat.KEY_COMPLEXITY, mDefaultComplexity);
   1934             }
   1935             // bitrates are listed in order of preference
   1936             for (Feature feat: bitrates) {
   1937                 if ((mBitControl & (1 << feat.mValue)) != 0) {
   1938                     format.setInteger(MediaFormat.KEY_BITRATE_MODE, feat.mValue);
   1939                     break;
   1940                 }
   1941             }
   1942         }
   1943 
   1944         /** @hide */
   1945         public boolean supportsFormat(MediaFormat format) {
   1946             final Map<String, Object> map = format.getMap();
   1947             final String mime = mParent.getMimeType();
   1948 
   1949             Integer mode = (Integer)map.get(MediaFormat.KEY_BITRATE_MODE);
   1950             if (mode != null && !isBitrateModeSupported(mode)) {
   1951                 return false;
   1952             }
   1953 
   1954             Integer complexity = (Integer)map.get(MediaFormat.KEY_COMPLEXITY);
   1955             if (MediaFormat.MIMETYPE_AUDIO_FLAC.equalsIgnoreCase(mime)) {
   1956                 Integer flacComplexity =
   1957                     (Integer)map.get(MediaFormat.KEY_FLAC_COMPRESSION_LEVEL);
   1958                 if (complexity == null) {
   1959                     complexity = flacComplexity;
   1960                 } else if (flacComplexity != null && complexity != flacComplexity) {
   1961                     throw new IllegalArgumentException(
   1962                             "conflicting values for complexity and " +
   1963                             "flac-compression-level");
   1964                 }
   1965             }
   1966 
   1967             // other audio parameters
   1968             Integer profile = (Integer)map.get(MediaFormat.KEY_PROFILE);
   1969             if (MediaFormat.MIMETYPE_AUDIO_AAC.equalsIgnoreCase(mime)) {
   1970                 Integer aacProfile = (Integer)map.get(MediaFormat.KEY_AAC_PROFILE);
   1971                 if (profile == null) {
   1972                     profile = aacProfile;
   1973                 } else if (aacProfile != null && aacProfile != profile) {
   1974                     throw new IllegalArgumentException(
   1975                             "conflicting values for profile and aac-profile");
   1976                 }
   1977             }
   1978 
   1979             Integer quality = (Integer)map.get(MediaFormat.KEY_QUALITY);
   1980 
   1981             return supports(complexity, quality, profile);
   1982         }
   1983     };
   1984 
   1985     /**
   1986      * Encapsulates the profiles available for a codec component.
   1987      * <p>You can get a set of {@link MediaCodecInfo.CodecProfileLevel} objects for a given
   1988      * {@link MediaCodecInfo} object from the
   1989      * {@link MediaCodecInfo.CodecCapabilities#profileLevels} field.
   1990      */
   1991     public static final class CodecProfileLevel {
   1992         // from OMX_VIDEO_AVCPROFILETYPE
   1993         public static final int AVCProfileBaseline = 0x01;
   1994         public static final int AVCProfileMain     = 0x02;
   1995         public static final int AVCProfileExtended = 0x04;
   1996         public static final int AVCProfileHigh     = 0x08;
   1997         public static final int AVCProfileHigh10   = 0x10;
   1998         public static final int AVCProfileHigh422  = 0x20;
   1999         public static final int AVCProfileHigh444  = 0x40;
   2000 
   2001         // from OMX_VIDEO_AVCLEVELTYPE
   2002         public static final int AVCLevel1       = 0x01;
   2003         public static final int AVCLevel1b      = 0x02;
   2004         public static final int AVCLevel11      = 0x04;
   2005         public static final int AVCLevel12      = 0x08;
   2006         public static final int AVCLevel13      = 0x10;
   2007         public static final int AVCLevel2       = 0x20;
   2008         public static final int AVCLevel21      = 0x40;
   2009         public static final int AVCLevel22      = 0x80;
   2010         public static final int AVCLevel3       = 0x100;
   2011         public static final int AVCLevel31      = 0x200;
   2012         public static final int AVCLevel32      = 0x400;
   2013         public static final int AVCLevel4       = 0x800;
   2014         public static final int AVCLevel41      = 0x1000;
   2015         public static final int AVCLevel42      = 0x2000;
   2016         public static final int AVCLevel5       = 0x4000;
   2017         public static final int AVCLevel51      = 0x8000;
   2018         public static final int AVCLevel52      = 0x10000;
   2019 
   2020         // from OMX_VIDEO_H263PROFILETYPE
   2021         public static final int H263ProfileBaseline             = 0x01;
   2022         public static final int H263ProfileH320Coding           = 0x02;
   2023         public static final int H263ProfileBackwardCompatible   = 0x04;
   2024         public static final int H263ProfileISWV2                = 0x08;
   2025         public static final int H263ProfileISWV3                = 0x10;
   2026         public static final int H263ProfileHighCompression      = 0x20;
   2027         public static final int H263ProfileInternet             = 0x40;
   2028         public static final int H263ProfileInterlace            = 0x80;
   2029         public static final int H263ProfileHighLatency          = 0x100;
   2030 
   2031         // from OMX_VIDEO_H263LEVELTYPE
   2032         public static final int H263Level10      = 0x01;
   2033         public static final int H263Level20      = 0x02;
   2034         public static final int H263Level30      = 0x04;
   2035         public static final int H263Level40      = 0x08;
   2036         public static final int H263Level45      = 0x10;
   2037         public static final int H263Level50      = 0x20;
   2038         public static final int H263Level60      = 0x40;
   2039         public static final int H263Level70      = 0x80;
   2040 
   2041         // from OMX_VIDEO_MPEG4PROFILETYPE
   2042         public static final int MPEG4ProfileSimple              = 0x01;
   2043         public static final int MPEG4ProfileSimpleScalable      = 0x02;
   2044         public static final int MPEG4ProfileCore                = 0x04;
   2045         public static final int MPEG4ProfileMain                = 0x08;
   2046         public static final int MPEG4ProfileNbit                = 0x10;
   2047         public static final int MPEG4ProfileScalableTexture     = 0x20;
   2048         public static final int MPEG4ProfileSimpleFace          = 0x40;
   2049         public static final int MPEG4ProfileSimpleFBA           = 0x80;
   2050         public static final int MPEG4ProfileBasicAnimated       = 0x100;
   2051         public static final int MPEG4ProfileHybrid              = 0x200;
   2052         public static final int MPEG4ProfileAdvancedRealTime    = 0x400;
   2053         public static final int MPEG4ProfileCoreScalable        = 0x800;
   2054         public static final int MPEG4ProfileAdvancedCoding      = 0x1000;
   2055         public static final int MPEG4ProfileAdvancedCore        = 0x2000;
   2056         public static final int MPEG4ProfileAdvancedScalable    = 0x4000;
   2057         public static final int MPEG4ProfileAdvancedSimple      = 0x8000;
   2058 
   2059         // from OMX_VIDEO_MPEG4LEVELTYPE
   2060         public static final int MPEG4Level0      = 0x01;
   2061         public static final int MPEG4Level0b     = 0x02;
   2062         public static final int MPEG4Level1      = 0x04;
   2063         public static final int MPEG4Level2      = 0x08;
   2064         public static final int MPEG4Level3      = 0x10;
   2065         public static final int MPEG4Level4      = 0x20;
   2066         public static final int MPEG4Level4a     = 0x40;
   2067         public static final int MPEG4Level5      = 0x80;
   2068 
   2069         // from OMX_AUDIO_AACPROFILETYPE
   2070         public static final int AACObjectMain       = 1;
   2071         public static final int AACObjectLC         = 2;
   2072         public static final int AACObjectSSR        = 3;
   2073         public static final int AACObjectLTP        = 4;
   2074         public static final int AACObjectHE         = 5;
   2075         public static final int AACObjectScalable   = 6;
   2076         public static final int AACObjectERLC       = 17;
   2077         public static final int AACObjectLD         = 23;
   2078         public static final int AACObjectHE_PS      = 29;
   2079         public static final int AACObjectELD        = 39;
   2080 
   2081         // from OMX_VIDEO_VP8LEVELTYPE
   2082         public static final int VP8Level_Version0 = 0x01;
   2083         public static final int VP8Level_Version1 = 0x02;
   2084         public static final int VP8Level_Version2 = 0x04;
   2085         public static final int VP8Level_Version3 = 0x08;
   2086 
   2087         // from OMX_VIDEO_VP8PROFILETYPE
   2088         public static final int VP8ProfileMain = 0x01;
   2089 
   2090         // from OMX_VIDEO_HEVCPROFILETYPE
   2091         public static final int HEVCProfileMain   = 0x01;
   2092         public static final int HEVCProfileMain10 = 0x02;
   2093 
   2094         // from OMX_VIDEO_HEVCLEVELTYPE
   2095         public static final int HEVCMainTierLevel1  = 0x1;
   2096         public static final int HEVCHighTierLevel1  = 0x2;
   2097         public static final int HEVCMainTierLevel2  = 0x4;
   2098         public static final int HEVCHighTierLevel2  = 0x8;
   2099         public static final int HEVCMainTierLevel21 = 0x10;
   2100         public static final int HEVCHighTierLevel21 = 0x20;
   2101         public static final int HEVCMainTierLevel3  = 0x40;
   2102         public static final int HEVCHighTierLevel3  = 0x80;
   2103         public static final int HEVCMainTierLevel31 = 0x100;
   2104         public static final int HEVCHighTierLevel31 = 0x200;
   2105         public static final int HEVCMainTierLevel4  = 0x400;
   2106         public static final int HEVCHighTierLevel4  = 0x800;
   2107         public static final int HEVCMainTierLevel41 = 0x1000;
   2108         public static final int HEVCHighTierLevel41 = 0x2000;
   2109         public static final int HEVCMainTierLevel5  = 0x4000;
   2110         public static final int HEVCHighTierLevel5  = 0x8000;
   2111         public static final int HEVCMainTierLevel51 = 0x10000;
   2112         public static final int HEVCHighTierLevel51 = 0x20000;
   2113         public static final int HEVCMainTierLevel52 = 0x40000;
   2114         public static final int HEVCHighTierLevel52 = 0x80000;
   2115         public static final int HEVCMainTierLevel6  = 0x100000;
   2116         public static final int HEVCHighTierLevel6  = 0x200000;
   2117         public static final int HEVCMainTierLevel61 = 0x400000;
   2118         public static final int HEVCHighTierLevel61 = 0x800000;
   2119         public static final int HEVCMainTierLevel62 = 0x1000000;
   2120         public static final int HEVCHighTierLevel62 = 0x2000000;
   2121 
   2122         /**
   2123          * Defined in the OpenMAX IL specs, depending on the type of media
   2124          * this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE,
   2125          * OMX_VIDEO_MPEG4PROFILETYPE or OMX_VIDEO_VP8PROFILETYPE.
   2126          */
   2127         public int profile;
   2128 
   2129         /**
   2130          * Defined in the OpenMAX IL specs, depending on the type of media
   2131          * this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE
   2132          * OMX_VIDEO_MPEG4LEVELTYPE or OMX_VIDEO_VP8LEVELTYPE.
   2133          */
   2134         public int level;
   2135     };
   2136 
   2137     /**
   2138      * Enumerates the capabilities of the codec component. Since a single
   2139      * component can support data of a variety of types, the type has to be
   2140      * specified to yield a meaningful result.
   2141      * @param type The MIME type to query
   2142      */
   2143     public final CodecCapabilities getCapabilitiesForType(
   2144             String type) {
   2145         CodecCapabilities caps = mCaps.get(type);
   2146         if (caps == null) {
   2147             throw new IllegalArgumentException("codec does not support type");
   2148         }
   2149         // clone writable object
   2150         return caps.dup();
   2151     }
   2152 
   2153     /** @hide */
   2154     public MediaCodecInfo makeRegular() {
   2155         ArrayList<CodecCapabilities> caps = new ArrayList<CodecCapabilities>();
   2156         for (CodecCapabilities c: mCaps.values()) {
   2157             if (c.isRegular()) {
   2158                 caps.add(c);
   2159             }
   2160         }
   2161         if (caps.size() == 0) {
   2162             return null;
   2163         } else if (caps.size() == mCaps.size()) {
   2164             return this;
   2165         }
   2166 
   2167         return new MediaCodecInfo(
   2168                 mName, mIsEncoder,
   2169                 caps.toArray(new CodecCapabilities[caps.size()]));
   2170     }
   2171 }
   2172