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