1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.media;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.util.Log;
22 import android.util.Pair;
23 import android.util.Range;
24 import android.util.Rational;
25 import android.util.Size;
26 
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.HashMap;
30 import java.util.Map;
31 import java.util.Set;
32 
33 import static android.media.Utils.intersectSortedDistinctRanges;
34 import static android.media.Utils.sortDistinctRanges;
35 
36 /**
37  * Provides information about a given media codec available on the device. You can
38  * iterate through all codecs available by querying {@link MediaCodecList}. For example,
39  * here's how to find an encoder that supports a given MIME type:
40  * <pre>
41  * private static MediaCodecInfo selectCodec(String mimeType) {
42  *     int numCodecs = MediaCodecList.getCodecCount();
43  *     for (int i = 0; i &lt; numCodecs; i++) {
44  *         MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
45  *
46  *         if (!codecInfo.isEncoder()) {
47  *             continue;
48  *         }
49  *
50  *         String[] types = codecInfo.getSupportedTypes();
51  *         for (int j = 0; j &lt; types.length; j++) {
52  *             if (types[j].equalsIgnoreCase(mimeType)) {
53  *                 return codecInfo;
54  *             }
55  *         }
56  *     }
57  *     return null;
58  * }</pre>
59  *
60  */
61 public final class MediaCodecInfo {
62     private boolean mIsEncoder;
63     private String mName;
64     private Map<String, CodecCapabilities> mCaps;
65 
MediaCodecInfo( String name, boolean isEncoder, CodecCapabilities[] caps)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      */
getName()79     public final String getName() {
80         return mName;
81     }
82 
83     /**
84      * Query if the codec is an encoder.
85      */
isEncoder()86     public final boolean isEncoder() {
87         return mIsEncoder;
88     }
89 
90     /**
91      * Query the media types supported by the codec.
92      */
getSupportedTypes()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 
checkPowerOfTwo(int value, String message)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;
Feature(String name, int value, boolean def)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 {
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          */
isFeatureSupported(String name)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          */
isFeatureRequired(String name)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 */
validFeatures()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 
getValidFeatures()514         private Feature[] getValidFeatures() {
515             if (!isEncoder()) {
516                 return decoderFeatures;
517             }
518             return encoderFeatures;
519         }
520 
checkFeature(String name, int flags)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 */
isRegular()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          */
isFormatSupported(MediaFormat format)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 
supportsBitrate( Range<Integer> bitrateRange, MediaFormat format)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 
supportsProfileLevel(int profile, Integer level)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          */
getDefaultFormat()774         public MediaFormat getDefaultFormat() {
775             return mDefaultFormat;
776         }
777 
778         /**
779          * Returns the mime type for which this codec-capability object was created.
780          */
getMimeType()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          */
getMaxSupportedInstances()793         public int getMaxSupportedInstances() {
794             return mMaxSupportedInstances;
795         }
796 
isAudio()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          */
getAudioCapabilities()804         public AudioCapabilities getAudioCapabilities() {
805             return mAudioCaps;
806         }
807 
isEncoder()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          */
getEncoderCapabilities()815         public EncoderCapabilities getEncoderCapabilities() {
816             return mEncoderCaps;
817         }
818 
isVideo()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          */
getVideoCapabilities()826         public VideoCapabilities getVideoCapabilities() {
827             return mVideoCaps;
828         }
829 
830         /** @hide */
dup()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          */
createFromProfileLevel( String mime, int profile, int level)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 
CodecCapabilities( CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags, Map<String, Object>defaultFormatMap, Map<String, Object>capabilitiesMap)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 
CodecCapabilities( CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags, MediaFormat defaultFormat, MediaFormat info)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          */
getBitrateRange()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          */
getSupportedSampleRates()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          */
getSupportedSampleRateRanges()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          */
getMaxInputChannelCount()978         public int getMaxInputChannelCount() {
979             return mMaxInputChannelCount;
980         }
981 
982         /* no public constructor */
AudioCapabilities()983         private AudioCapabilities() { }
984 
985         /** @hide */
create( MediaFormat info, CodecCapabilities parent)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 */
init(MediaFormat info, CodecCapabilities parent)994         public void init(MediaFormat info, CodecCapabilities parent) {
995             mParent = parent;
996             initWithPlatformLimits();
997             applyLevelLimits();
998             parseFromInfo(info);
999         }
1000 
initWithPlatformLimits()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 
supports(Integer sampleRate, Integer inputChannels)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          */
isSampleRateSupported(int sampleRate)1028         public boolean isSampleRateSupported(int sampleRate) {
1029             return supports(sampleRate, null);
1030         }
1031 
1032         /** modifies rates */
limitSampleRates(int[] 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 
createDiscreteSampleRates()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 */
limitSampleRates(Range<Integer>[] 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 
applyLevelLimits()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 
applyLimits(int maxInputChannels, Range<Integer> bitRates)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 
parseFromInfo(MediaFormat info)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 */
setDefaultFormat(MediaFormat format)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 */
supportsFormat(MediaFormat format)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          */
getBitrateRange()1239         public Range<Integer> getBitrateRange() {
1240             return mBitrateRange;
1241         }
1242 
1243         /**
1244          * Returns the range of supported video widths.
1245          */
getSupportedWidths()1246         public Range<Integer> getSupportedWidths() {
1247             return mWidthRange;
1248         }
1249 
1250         /**
1251          * Returns the range of supported video heights.
1252          */
getSupportedHeights()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          */
getWidthAlignment()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          */
getHeightAlignment()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          */
getSmallerDimensionUpperLimit()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          */
getSupportedFrameRates()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          */
getSupportedWidthsFor(int height)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          */
getSupportedHeightsFor(int width)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          */
getSupportedFrameRatesFor(int width, int height)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 
getBlockCount(int width, int height)1420         private int getBlockCount(int width, int height) {
1421             return Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight);
1422         }
1423 
1424         @NonNull
findClosestSize(int width, int height)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 
estimateFrameRatesFor(int width, int height)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
getAchievableFrameRatesFor(int width, int height)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          */
areSizeAndRateSupported( int width, int height, double frameRate)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          */
isSizeSupported(int width, int height)1519         public boolean isSizeSupported(int width, int height) {
1520             return supports(width, height, null);
1521         }
1522 
supports(Integer width, Integer height, Number rate)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 */
supportsFormat(MediaFormat format)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 */
VideoCapabilities()1578         private VideoCapabilities() { }
1579 
1580         /** @hide */
create( MediaFormat info, CodecCapabilities parent)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 */
init(MediaFormat info, CodecCapabilities parent)1589         public void init(MediaFormat info, CodecCapabilities parent) {
1590             mParent = parent;
1591             initWithPlatformLimits();
1592             applyLevelLimits();
1593             parseFromInfo(info);
1594             updateLimits();
1595         }
1596 
1597         /** @hide */
getBlockSize()1598         public Size getBlockSize() {
1599             return new Size(mBlockWidth, mBlockHeight);
1600         }
1601 
1602         /** @hide */
getBlockCountRange()1603         public Range<Integer> getBlockCountRange() {
1604             return mBlockCountRange;
1605         }
1606 
1607         /** @hide */
getBlocksPerSecondRange()1608         public Range<Long> getBlocksPerSecondRange() {
1609             return mBlocksPerSecondRange;
1610         }
1611 
1612         /** @hide */
getAspectRatioRange(boolean blocks)1613         public Range<Rational> getAspectRatioRange(boolean blocks) {
1614             return blocks ? mBlockAspectRatioRange : mAspectRatioRange;
1615         }
1616 
initWithPlatformLimits()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 
getMeasuredFrameRates(Map<String, Object> map)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 
parseWidthHeightRanges(Object o)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 */
equivalentVP9Level(MediaFormat info)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 
parseFromInfo(MediaFormat info)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 
applyBlockLimits( int blockWidth, int blockHeight, Range<Integer> counts, Range<Long> rates, Range<Rational> ratios)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 
applyAlignment(int widthAlignment, int heightAlignment)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 
updateLimits()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 
applyMacroBlockLimits( int maxHorizontalBlocks, int maxVerticalBlocks, int maxBlocks, long maxBlocksPerSecond, int blockWidth, int blockHeight, int widthAlignment, int heightAlignment)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 
applyMacroBlockLimits( int minHorizontalBlocks, int minVerticalBlocks, int maxHorizontalBlocks, int maxVerticalBlocks, int maxBlocks, long maxBlocksPerSecond, int blockWidth, int blockHeight, int widthAlignment, int heightAlignment)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 
applyLevelLimits()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          */
getQualityRange()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          */
getComplexityRange()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 
parseBitrateMode(String mode)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          */
isBitrateModeSupported(int mode)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 */
EncoderCapabilities()2697         private EncoderCapabilities() { }
2698 
2699         /** @hide */
create( MediaFormat info, CodecCapabilities parent)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 */
init(MediaFormat info, CodecCapabilities parent)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 
applyLevelLimits()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 
parseFromInfo(MediaFormat info)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 
supports( Integer complexity, Integer quality, Integer profile)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 */
setDefaultFormat(MediaFormat format)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 */
supportsFormat(MediaFormat format)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      */
getCapabilitiesForType( String type)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 */
makeRegular()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