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