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