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