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