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