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 static android.media.Utils.intersectSortedDistinctRanges;
20 import static android.media.Utils.sortDistinctRanges;
21 
22 import android.annotation.IntRange;
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.annotation.SuppressLint;
26 import android.annotation.TestApi;
27 import android.compat.annotation.UnsupportedAppUsage;
28 import android.os.Build;
29 import android.os.Process;
30 import android.os.SystemProperties;
31 import android.sysprop.MediaProperties;
32 import android.util.Log;
33 import android.util.Pair;
34 import android.util.Range;
35 import android.util.Rational;
36 import android.util.Size;
37 
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.Collections;
41 import java.util.HashMap;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Set;
45 import java.util.Vector;
46 
47 /**
48  * Provides information about a given media codec available on the device. You can
49  * iterate through all codecs available by querying {@link MediaCodecList}. For example,
50  * here's how to find an encoder that supports a given MIME type:
51  * <pre>
52  * private static MediaCodecInfo selectCodec(String mimeType) {
53  *     int numCodecs = MediaCodecList.getCodecCount();
54  *     for (int i = 0; i &lt; numCodecs; i++) {
55  *         MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
56  *
57  *         if (!codecInfo.isEncoder()) {
58  *             continue;
59  *         }
60  *
61  *         String[] types = codecInfo.getSupportedTypes();
62  *         for (int j = 0; j &lt; types.length; j++) {
63  *             if (types[j].equalsIgnoreCase(mimeType)) {
64  *                 return codecInfo;
65  *             }
66  *         }
67  *     }
68  *     return null;
69  * }</pre>
70  *
71  */
72 public final class MediaCodecInfo {
73     private static final String TAG = "MediaCodecInfo";
74 
75     private static final int FLAG_IS_ENCODER = (1 << 0);
76     private static final int FLAG_IS_VENDOR = (1 << 1);
77     private static final int FLAG_IS_SOFTWARE_ONLY = (1 << 2);
78     private static final int FLAG_IS_HARDWARE_ACCELERATED = (1 << 3);
79 
80     private int mFlags;
81     private String mName;
82     private String mCanonicalName;
83     private Map<String, CodecCapabilities> mCaps;
84 
MediaCodecInfo( String name, String canonicalName, int flags, CodecCapabilities[] caps)85     /* package private */ MediaCodecInfo(
86             String name, String canonicalName, int flags, CodecCapabilities[] caps) {
87         mName = name;
88         mCanonicalName = canonicalName;
89         mFlags = flags;
90         mCaps = new HashMap<String, CodecCapabilities>();
91 
92         for (CodecCapabilities c: caps) {
93             mCaps.put(c.getMimeType(), c);
94         }
95     }
96 
97     /**
98      * Retrieve the codec name.
99      *
100      * <strong>Note:</strong> Implementations may provide multiple aliases (codec
101      * names) for the same underlying codec, any of which can be used to instantiate the same
102      * underlying codec in {@link MediaCodec#createByCodecName}.
103      *
104      * Applications targeting SDK < {@link android.os.Build.VERSION_CODES#Q}, cannot determine if
105      * the multiple codec names listed in MediaCodecList are in-fact for the same codec.
106      */
107     @NonNull
getName()108     public final String getName() {
109         return mName;
110     }
111 
112     /**
113      * Retrieve the underlying codec name.
114      *
115      * Device implementations may provide multiple aliases (codec names) for the same underlying
116      * codec to maintain backward app compatibility. This method returns the name of the underlying
117      * codec name, which must not be another alias. For non-aliases this is always the name of the
118      * codec.
119      */
120     @NonNull
getCanonicalName()121     public final String getCanonicalName() {
122         return mCanonicalName;
123     }
124 
125     /**
126      * Query if the codec is an alias for another underlying codec.
127      */
isAlias()128     public final boolean isAlias() {
129         return !mName.equals(mCanonicalName);
130     }
131 
132     /**
133      * Query if the codec is an encoder.
134      */
isEncoder()135     public final boolean isEncoder() {
136         return (mFlags & FLAG_IS_ENCODER) != 0;
137     }
138 
139     /**
140      * Query if the codec is provided by the Android platform (false) or the device manufacturer
141      * (true).
142      */
isVendor()143     public final boolean isVendor() {
144         return (mFlags & FLAG_IS_VENDOR) != 0;
145     }
146 
147     /**
148      * Query if the codec is software only. Software-only codecs are more secure as they run in
149      * a tighter security sandbox. On the other hand, software-only codecs do not provide any
150      * performance guarantees.
151      */
isSoftwareOnly()152     public final boolean isSoftwareOnly() {
153         return (mFlags & FLAG_IS_SOFTWARE_ONLY) != 0;
154     }
155 
156     /**
157      * Query if the codec is hardware accelerated. This attribute is provided by the device
158      * manufacturer. Note that it cannot be tested for correctness.
159      */
isHardwareAccelerated()160     public final boolean isHardwareAccelerated() {
161         return (mFlags & FLAG_IS_HARDWARE_ACCELERATED) != 0;
162     }
163 
164     /**
165      * Query the media types supported by the codec.
166      */
getSupportedTypes()167     public final String[] getSupportedTypes() {
168         Set<String> typeSet = mCaps.keySet();
169         String[] types = typeSet.toArray(new String[typeSet.size()]);
170         Arrays.sort(types);
171         return types;
172     }
173 
checkPowerOfTwo(int value, String message)174     private static int checkPowerOfTwo(int value, String message) {
175         if ((value & (value - 1)) != 0) {
176             throw new IllegalArgumentException(message);
177         }
178         return value;
179     }
180 
181     private static class Feature {
182         public String mName;
183         public int mValue;
184         public boolean mDefault;
185         public boolean mInternal;
Feature(String name, int value, boolean def)186         public Feature(String name, int value, boolean def) {
187             this(name, value, def, false /* internal */);
188         }
Feature(String name, int value, boolean def, boolean internal)189         public Feature(String name, int value, boolean def, boolean internal) {
190             mName = name;
191             mValue = value;
192             mDefault = def;
193             mInternal = internal;
194         }
195     }
196 
197     // COMMON CONSTANTS
198     private static final Range<Integer> POSITIVE_INTEGERS =
199             Range.create(1, Integer.MAX_VALUE);
200     private static final Range<Long> POSITIVE_LONGS =
201             Range.create(1L, Long.MAX_VALUE);
202     private static final Range<Rational> POSITIVE_RATIONALS =
203             Range.create(new Rational(1, Integer.MAX_VALUE),
204                          new Rational(Integer.MAX_VALUE, 1));
205     private static final Range<Integer> FRAME_RATE_RANGE = Range.create(0, 960);
206     private static final Range<Integer> BITRATE_RANGE = Range.create(0, 500000000);
207     private static final int DEFAULT_MAX_SUPPORTED_INSTANCES = 32;
208     private static final int MAX_SUPPORTED_INSTANCES_LIMIT = 256;
209 
210     private static final class LazyHolder {
211         private static final Range<Integer> SIZE_RANGE = Process.is64Bit()
212                 ? Range.create(1, 32768)
213                 : Range.create(1, MediaProperties.resolution_limit_32bit().orElse(4096));
214     }
getSizeRange()215     private static Range<Integer> getSizeRange() {
216         return LazyHolder.SIZE_RANGE;
217     }
218 
219     // found stuff that is not supported by framework (=> this should not happen)
220     private static final int ERROR_UNRECOGNIZED   = (1 << 0);
221     // found profile/level for which we don't have capability estimates
222     private static final int ERROR_UNSUPPORTED    = (1 << 1);
223     // have not found any profile/level for which we don't have capability estimate
224     private static final int ERROR_NONE_SUPPORTED = (1 << 2);
225 
226 
227     /**
228      * Encapsulates the capabilities of a given codec component.
229      * For example, what profile/level combinations it supports and what colorspaces
230      * it is capable of providing the decoded data in, as well as some
231      * codec-type specific capability flags.
232      * <p>You can get an instance for a given {@link MediaCodecInfo} object with
233      * {@link MediaCodecInfo#getCapabilitiesForType getCapabilitiesForType()}, passing a MIME type.
234      */
235     public static final class CodecCapabilities {
CodecCapabilities()236         public CodecCapabilities() {
237         }
238 
239         // CLASSIFICATION
240         private String mMime;
241         private int mMaxSupportedInstances;
242 
243         // LEGACY FIELDS
244 
245         // Enumerates supported profile/level combinations as defined
246         // by the type of encoded data. These combinations impose restrictions
247         // on video resolution, bitrate... and limit the available encoder tools
248         // such as B-frame support, arithmetic coding...
249         public CodecProfileLevel[] profileLevels;  // NOTE this array is modifiable by user
250 
251         // from MediaCodecConstants
252         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
253         public static final int COLOR_FormatMonochrome              = 1;
254         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
255         public static final int COLOR_Format8bitRGB332              = 2;
256         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
257         public static final int COLOR_Format12bitRGB444             = 3;
258         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
259         public static final int COLOR_Format16bitARGB4444           = 4;
260         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
261         public static final int COLOR_Format16bitARGB1555           = 5;
262 
263         /**
264          * 16 bits per pixel RGB color format, with 5-bit red & blue and 6-bit green component.
265          * <p>
266          * Using 16-bit little-endian representation, colors stored as Red 15:11, Green 10:5, Blue 4:0.
267          * <pre>
268          *            byte                   byte
269          *  <--------- i --------> | <------ i + 1 ------>
270          * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
271          * |     BLUE     |      GREEN      |     RED      |
272          * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
273          *  0           4  5     7   0     2  3           7
274          * bit
275          * </pre>
276          *
277          * This format corresponds to {@link android.graphics.PixelFormat#RGB_565} and
278          * {@link android.graphics.ImageFormat#RGB_565}.
279          */
280         public static final int COLOR_Format16bitRGB565             = 6;
281         /** @deprecated Use {@link #COLOR_Format16bitRGB565}. */
282         public static final int COLOR_Format16bitBGR565             = 7;
283         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
284         public static final int COLOR_Format18bitRGB666             = 8;
285         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
286         public static final int COLOR_Format18bitARGB1665           = 9;
287         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
288         public static final int COLOR_Format19bitARGB1666           = 10;
289 
290         /** @deprecated Use {@link #COLOR_Format24bitBGR888} or {@link #COLOR_FormatRGBFlexible}. */
291         public static final int COLOR_Format24bitRGB888             = 11;
292 
293         /**
294          * 24 bits per pixel RGB color format, with 8-bit red, green & blue components.
295          * <p>
296          * Using 24-bit little-endian representation, colors stored as Red 7:0, Green 15:8, Blue 23:16.
297          * <pre>
298          *         byte              byte             byte
299          *  <------ i -----> | <---- i+1 ----> | <---- i+2 ----->
300          * +-----------------+-----------------+-----------------+
301          * |       RED       |      GREEN      |       BLUE      |
302          * +-----------------+-----------------+-----------------+
303          * </pre>
304          *
305          * This format corresponds to {@link android.graphics.PixelFormat#RGB_888}, and can also be
306          * represented as a flexible format by {@link #COLOR_FormatRGBFlexible}.
307          */
308         public static final int COLOR_Format24bitBGR888             = 12;
309         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
310         public static final int COLOR_Format24bitARGB1887           = 13;
311         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
312         public static final int COLOR_Format25bitARGB1888           = 14;
313 
314         /**
315          * @deprecated Use {@link #COLOR_Format32bitABGR8888} Or {@link #COLOR_FormatRGBAFlexible}.
316          */
317         public static final int COLOR_Format32bitBGRA8888           = 15;
318         /**
319          * @deprecated Use {@link #COLOR_Format32bitABGR8888} Or {@link #COLOR_FormatRGBAFlexible}.
320          */
321         public static final int COLOR_Format32bitARGB8888           = 16;
322         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
323         public static final int COLOR_FormatYUV411Planar            = 17;
324         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
325         public static final int COLOR_FormatYUV411PackedPlanar      = 18;
326         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
327         public static final int COLOR_FormatYUV420Planar            = 19;
328         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
329         public static final int COLOR_FormatYUV420PackedPlanar      = 20;
330         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
331         public static final int COLOR_FormatYUV420SemiPlanar        = 21;
332 
333         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
334         public static final int COLOR_FormatYUV422Planar            = 22;
335         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
336         public static final int COLOR_FormatYUV422PackedPlanar      = 23;
337         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
338         public static final int COLOR_FormatYUV422SemiPlanar        = 24;
339 
340         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
341         public static final int COLOR_FormatYCbYCr                  = 25;
342         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
343         public static final int COLOR_FormatYCrYCb                  = 26;
344         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
345         public static final int COLOR_FormatCbYCrY                  = 27;
346         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
347         public static final int COLOR_FormatCrYCbY                  = 28;
348 
349         /** @deprecated Use {@link #COLOR_FormatYUV444Flexible}. */
350         public static final int COLOR_FormatYUV444Interleaved       = 29;
351 
352         /**
353          * SMIA 8-bit Bayer format.
354          * Each byte represents the top 8-bits of a 10-bit signal.
355          */
356         public static final int COLOR_FormatRawBayer8bit            = 30;
357         /**
358          * SMIA 10-bit Bayer format.
359          */
360         public static final int COLOR_FormatRawBayer10bit           = 31;
361 
362         /**
363          * SMIA 8-bit compressed Bayer format.
364          * Each byte represents a sample from the 10-bit signal that is compressed into 8-bits
365          * using DPCM/PCM compression, as defined by the SMIA Functional Specification.
366          */
367         public static final int COLOR_FormatRawBayer8bitcompressed  = 32;
368 
369         /** @deprecated Use {@link #COLOR_FormatL8}. */
370         public static final int COLOR_FormatL2                      = 33;
371         /** @deprecated Use {@link #COLOR_FormatL8}. */
372         public static final int COLOR_FormatL4                      = 34;
373 
374         /**
375          * 8 bits per pixel Y color format.
376          * <p>
377          * Each byte contains a single pixel.
378          * This format corresponds to {@link android.graphics.PixelFormat#L_8}.
379          */
380         public static final int COLOR_FormatL8                      = 35;
381 
382         /**
383          * 16 bits per pixel, little-endian Y color format.
384          * <p>
385          * <pre>
386          *            byte                   byte
387          *  <--------- i --------> | <------ i + 1 ------>
388          * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
389          * |                       Y                       |
390          * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
391          *  0                    7   0                    7
392          * bit
393          * </pre>
394          */
395         public static final int COLOR_FormatL16                     = 36;
396         /** @deprecated Use {@link #COLOR_FormatL16}. */
397         public static final int COLOR_FormatL24                     = 37;
398 
399         /**
400          * 32 bits per pixel, little-endian Y color format.
401          * <p>
402          * <pre>
403          *         byte              byte             byte              byte
404          *  <------ i -----> | <---- i+1 ----> | <---- i+2 ----> | <---- i+3 ----->
405          * +-----------------+-----------------+-----------------+-----------------+
406          * |                                   Y                                   |
407          * +-----------------+-----------------+-----------------+-----------------+
408          *  0               7 0               7 0               7 0               7
409          * bit
410          * </pre>
411          *
412          * @deprecated Use {@link #COLOR_FormatL16}.
413          */
414         public static final int COLOR_FormatL32                     = 38;
415 
416         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
417         public static final int COLOR_FormatYUV420PackedSemiPlanar  = 39;
418         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
419         public static final int COLOR_FormatYUV422PackedSemiPlanar  = 40;
420 
421         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
422         public static final int COLOR_Format18BitBGR666             = 41;
423 
424         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
425         public static final int COLOR_Format24BitARGB6666           = 42;
426         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
427         public static final int COLOR_Format24BitABGR6666           = 43;
428 
429         /**
430          * P010 is 10-bit-per component 4:2:0 YCbCr semiplanar format.
431          * <p>
432          * This format uses 24 allocated bits per pixel with 15 bits of
433          * data per pixel. Chroma planes are subsampled by 2 both
434          * horizontally and vertically. Each chroma and luma component
435          * has 16 allocated bits in little-endian configuration with 10
436          * MSB of actual data.
437          *
438          * <pre>
439          *            byte                   byte
440          *  <--------- i --------> | <------ i + 1 ------>
441          * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
442          * |     UNUSED      |      Y/Cb/Cr                |
443          * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
444          *  0               5 6   7 0                    7
445          * bit
446          * </pre>
447          *
448          * Use this format with {@link Image}. This format corresponds
449          * to {@link android.graphics.ImageFormat#YCBCR_P010}.
450          * <p>
451          */
452         @SuppressLint("AllUpper")
453         public static final int COLOR_FormatYUVP010                 = 54;
454 
455         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
456         public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100;
457         // COLOR_FormatSurface indicates that the data will be a GraphicBuffer metadata reference.
458         // Note: in OMX this is called OMX_COLOR_FormatAndroidOpaque.
459         public static final int COLOR_FormatSurface                   = 0x7F000789;
460 
461         /**
462          * 64 bits per pixel RGBA color format, with 16-bit signed
463          * floating point red, green, blue, and alpha components.
464          * <p>
465          *
466          * <pre>
467          *         byte              byte             byte              byte
468          *  <-- i -->|<- i+1 ->|<- i+2 ->|<- i+3 ->|<- i+4 ->|<- i+5 ->|<- i+6 ->|<- i+7 ->
469          * +---------+---------+-------------------+---------+---------+---------+---------+
470          * |        RED        |       GREEN       |       BLUE        |       ALPHA       |
471          * +---------+---------+-------------------+---------+---------+---------+---------+
472          *  0       7 0       7 0       7 0       7 0       7 0       7 0       7 0       7
473          * </pre>
474          *
475          * This corresponds to {@link android.graphics.PixelFormat#RGBA_F16}.
476          */
477         @SuppressLint("AllUpper")
478         public static final int COLOR_Format64bitABGRFloat            = 0x7F000F16;
479 
480         /**
481          * 32 bits per pixel RGBA color format, with 8-bit red, green, blue, and alpha components.
482          * <p>
483          * Using 32-bit little-endian representation, colors stored as Red 7:0, Green 15:8,
484          * Blue 23:16, and Alpha 31:24.
485          * <pre>
486          *         byte              byte             byte              byte
487          *  <------ i -----> | <---- i+1 ----> | <---- i+2 ----> | <---- i+3 ----->
488          * +-----------------+-----------------+-----------------+-----------------+
489          * |       RED       |      GREEN      |       BLUE      |      ALPHA      |
490          * +-----------------+-----------------+-----------------+-----------------+
491          * </pre>
492          *
493          * This corresponds to {@link android.graphics.PixelFormat#RGBA_8888}.
494          */
495         public static final int COLOR_Format32bitABGR8888             = 0x7F00A000;
496 
497         /**
498          * 32 bits per pixel RGBA color format, with 10-bit red, green,
499          * blue, and 2-bit alpha components.
500          * <p>
501          * Using 32-bit little-endian representation, colors stored as
502          * Red 9:0, Green 19:10, Blue 29:20, and Alpha 31:30.
503          * <pre>
504          *         byte              byte             byte              byte
505          *  <------ i -----> | <---- i+1 ----> | <---- i+2 ----> | <---- i+3 ----->
506          * +-----------------+---+-------------+-------+---------+-----------+-----+
507          * |       RED           |      GREEN          |       BLUE          |ALPHA|
508          * +-----------------+---+-------------+-------+---------+-----------+-----+
509          *  0               7 0 1 2           7 0     3 4       7 0         5 6   7
510          * </pre>
511          *
512          * This corresponds to {@link android.graphics.PixelFormat#RGBA_1010102}.
513          */
514         @SuppressLint("AllUpper")
515         public static final int COLOR_Format32bitABGR2101010          = 0x7F00AAA2;
516 
517         /**
518          * Flexible 12 bits per pixel, subsampled YUV color format with 8-bit chroma and luma
519          * components.
520          * <p>
521          * Chroma planes are subsampled by 2 both horizontally and vertically.
522          * Use this format with {@link Image}.
523          * This format corresponds to {@link android.graphics.ImageFormat#YUV_420_888},
524          * and can represent the {@link #COLOR_FormatYUV411Planar},
525          * {@link #COLOR_FormatYUV411PackedPlanar}, {@link #COLOR_FormatYUV420Planar},
526          * {@link #COLOR_FormatYUV420PackedPlanar}, {@link #COLOR_FormatYUV420SemiPlanar}
527          * and {@link #COLOR_FormatYUV420PackedSemiPlanar} formats.
528          *
529          * @see Image#getFormat
530          */
531         public static final int COLOR_FormatYUV420Flexible            = 0x7F420888;
532 
533         /**
534          * Flexible 16 bits per pixel, subsampled YUV color format with 8-bit chroma and luma
535          * components.
536          * <p>
537          * Chroma planes are horizontally subsampled by 2. Use this format with {@link Image}.
538          * This format corresponds to {@link android.graphics.ImageFormat#YUV_422_888},
539          * and can represent the {@link #COLOR_FormatYCbYCr}, {@link #COLOR_FormatYCrYCb},
540          * {@link #COLOR_FormatCbYCrY}, {@link #COLOR_FormatCrYCbY},
541          * {@link #COLOR_FormatYUV422Planar}, {@link #COLOR_FormatYUV422PackedPlanar},
542          * {@link #COLOR_FormatYUV422SemiPlanar} and {@link #COLOR_FormatYUV422PackedSemiPlanar}
543          * formats.
544          *
545          * @see Image#getFormat
546          */
547         public static final int COLOR_FormatYUV422Flexible            = 0x7F422888;
548 
549         /**
550          * Flexible 24 bits per pixel YUV color format with 8-bit chroma and luma
551          * components.
552          * <p>
553          * Chroma planes are not subsampled. Use this format with {@link Image}.
554          * This format corresponds to {@link android.graphics.ImageFormat#YUV_444_888},
555          * and can represent the {@link #COLOR_FormatYUV444Interleaved} format.
556          * @see Image#getFormat
557          */
558         public static final int COLOR_FormatYUV444Flexible            = 0x7F444888;
559 
560         /**
561          * Flexible 24 bits per pixel RGB color format with 8-bit red, green and blue
562          * components.
563          * <p>
564          * Use this format with {@link Image}. This format corresponds to
565          * {@link android.graphics.ImageFormat#FLEX_RGB_888}, and can represent
566          * {@link #COLOR_Format24bitBGR888} and {@link #COLOR_Format24bitRGB888} formats.
567          * @see Image#getFormat()
568          */
569         public static final int COLOR_FormatRGBFlexible               = 0x7F36B888;
570 
571         /**
572          * Flexible 32 bits per pixel RGBA color format with 8-bit red, green, blue, and alpha
573          * components.
574          * <p>
575          * Use this format with {@link Image}. This format corresponds to
576          * {@link android.graphics.ImageFormat#FLEX_RGBA_8888}, and can represent
577          * {@link #COLOR_Format32bitBGRA8888}, {@link #COLOR_Format32bitABGR8888} and
578          * {@link #COLOR_Format32bitARGB8888} formats.
579          *
580          * @see Image#getFormat()
581          */
582         public static final int COLOR_FormatRGBAFlexible              = 0x7F36A888;
583 
584         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
585         public static final int COLOR_QCOM_FormatYUV420SemiPlanar     = 0x7fa30c00;
586 
587         /**
588          * The color format for the media. This is one of the color constants defined in this class.
589          */
590         public int[] colorFormats; // NOTE this array is modifiable by user
591 
592         // FEATURES
593 
594         private int mFlagsSupported;
595         private int mFlagsRequired;
596         private int mFlagsVerified;
597 
598         /**
599          * <b>video decoder only</b>: codec supports seamless resolution changes.
600          */
601         public static final String FEATURE_AdaptivePlayback       = "adaptive-playback";
602 
603         /**
604          * <b>video decoder only</b>: codec supports secure decryption.
605          */
606         public static final String FEATURE_SecurePlayback         = "secure-playback";
607 
608         /**
609          * <b>video or audio decoder only</b>: codec supports tunneled playback.
610          */
611         public static final String FEATURE_TunneledPlayback       = "tunneled-playback";
612 
613         /**
614          * If true, the timestamp of each output buffer is derived from the timestamp of the input
615          * buffer that produced the output. If false, the timestamp of each output buffer is
616          * derived from the timestamp of the first input buffer.
617          */
618         public static final String FEATURE_DynamicTimestamp = "dynamic-timestamp";
619 
620         /**
621          * <b>decoder only</b>If true, the codec supports partial (including multiple) access units
622          * per input buffer.
623          */
624         public static final String FEATURE_FrameParsing = "frame-parsing";
625 
626         /**
627          * If true, the codec supports multiple access units (for decoding, or to output for
628          * encoders). If false, the codec only supports single access units. Producing multiple
629          * access units for output is an optional feature.
630          */
631         public static final String FEATURE_MultipleFrames = "multiple-frames";
632 
633         /**
634          * <b>video decoder only</b>: codec supports queuing partial frames.
635          */
636         public static final String FEATURE_PartialFrame = "partial-frame";
637 
638         /**
639          * <b>video encoder only</b>: codec supports intra refresh.
640          */
641         public static final String FEATURE_IntraRefresh = "intra-refresh";
642 
643         /**
644          * <b>decoder only</b>: codec supports low latency decoding.
645          * If supported, clients can enable the low latency mode for the decoder.
646          * When the mode is enabled, the decoder doesn't hold input and output data more than
647          * required by the codec standards.
648          */
649         public static final String FEATURE_LowLatency = "low-latency";
650 
651         /**
652          * Do not include in REGULAR_CODECS list in MediaCodecList.
653          */
654         private static final String FEATURE_SpecialCodec = "special-codec";
655 
656         /**
657          * <b>video encoder only</b>: codec supports quantization parameter bounds.
658          * @see MediaFormat#KEY_VIDEO_QP_MAX
659          * @see MediaFormat#KEY_VIDEO_QP_MIN
660          */
661         @SuppressLint("AllUpper")
662         public static final String FEATURE_QpBounds = "qp-bounds";
663 
664         /**
665          * <b>video encoder only</b>: codec supports exporting encoding statistics.
666          * Encoders with this feature can provide the App clients with the encoding statistics
667          * information about the frame.
668          * The scope of encoding statistics is controlled by
669          * {@link MediaFormat#KEY_VIDEO_ENCODING_STATISTICS_LEVEL}.
670          *
671          * @see MediaFormat#KEY_VIDEO_ENCODING_STATISTICS_LEVEL
672          */
673         @SuppressLint("AllUpper") // for consistency with other FEATURE_* constants
674         public static final String FEATURE_EncodingStatistics = "encoding-statistics";
675 
676         /**
677          * <b>video encoder only</b>: codec supports HDR editing.
678          * <p>
679          * HDR editing support means that the codec accepts 10-bit HDR
680          * input surface, and it is capable of generating any HDR
681          * metadata required from both YUV and RGB input when the
682          * metadata is not present. This feature is only meaningful when
683          * using an HDR capable profile (and 10-bit HDR input).
684          * <p>
685          * This feature implies that the codec is capable of encoding at
686          * least one HDR format, and that it supports RGBA_1010102 as
687          * well as P010, and optionally RGBA_FP16 input formats, and
688          * that the encoder can generate HDR metadata for all supported
689          * HDR input formats.
690          */
691         @SuppressLint("AllUpper")
692         public static final String FEATURE_HdrEditing = "hdr-editing";
693 
694         /**
695          * Query codec feature capabilities.
696          * <p>
697          * These features are supported to be used by the codec.  These
698          * include optional features that can be turned on, as well as
699          * features that are always on.
700          */
isFeatureSupported(String name)701         public final boolean isFeatureSupported(String name) {
702             return checkFeature(name, mFlagsSupported);
703         }
704 
705         /**
706          * Query codec feature requirements.
707          * <p>
708          * These features are required to be used by the codec, and as such,
709          * they are always turned on.
710          */
isFeatureRequired(String name)711         public final boolean isFeatureRequired(String name) {
712             return checkFeature(name, mFlagsRequired);
713         }
714 
715         private static final Feature[] decoderFeatures = {
716             new Feature(FEATURE_AdaptivePlayback, (1 << 0), true),
717             new Feature(FEATURE_SecurePlayback,   (1 << 1), false),
718             new Feature(FEATURE_TunneledPlayback, (1 << 2), false),
719             new Feature(FEATURE_PartialFrame,     (1 << 3), false),
720             new Feature(FEATURE_FrameParsing,     (1 << 4), false),
721             new Feature(FEATURE_MultipleFrames,   (1 << 5), false),
722             new Feature(FEATURE_DynamicTimestamp, (1 << 6), false),
723             new Feature(FEATURE_LowLatency,       (1 << 7), true),
724             // feature to exclude codec from REGULAR codec list
725             new Feature(FEATURE_SpecialCodec,     (1 << 30), false, true),
726         };
727 
728         private static final Feature[] encoderFeatures = {
729             new Feature(FEATURE_IntraRefresh, (1 << 0), false),
730             new Feature(FEATURE_MultipleFrames, (1 << 1), false),
731             new Feature(FEATURE_DynamicTimestamp, (1 << 2), false),
732             new Feature(FEATURE_QpBounds, (1 << 3), false),
733             new Feature(FEATURE_EncodingStatistics, (1 << 4), false),
734             new Feature(FEATURE_HdrEditing, (1 << 5), false),
735             // feature to exclude codec from REGULAR codec list
736             new Feature(FEATURE_SpecialCodec,     (1 << 30), false, true),
737         };
738 
739         /** @hide */
validFeatures()740         public String[] validFeatures() {
741             Feature[] features = getValidFeatures();
742             String[] res = new String[features.length];
743             for (int i = 0; i < res.length; i++) {
744                 if (!features[i].mInternal) {
745                     res[i] = features[i].mName;
746                 }
747             }
748             return res;
749         }
750 
getValidFeatures()751         private Feature[] getValidFeatures() {
752             if (!isEncoder()) {
753                 return decoderFeatures;
754             }
755             return encoderFeatures;
756         }
757 
checkFeature(String name, int flags)758         private boolean checkFeature(String name, int flags) {
759             for (Feature feat: getValidFeatures()) {
760                 if (feat.mName.equals(name)) {
761                     return (flags & feat.mValue) != 0;
762                 }
763             }
764             return false;
765         }
766 
767         /** @hide */
isRegular()768         public boolean isRegular() {
769             // regular codecs only require default features
770             for (Feature feat: getValidFeatures()) {
771                 if (!feat.mDefault && isFeatureRequired(feat.mName)) {
772                     return false;
773                 }
774             }
775             return true;
776         }
777 
778         /**
779          * Query whether codec supports a given {@link MediaFormat}.
780          *
781          * <p class=note>
782          * <strong>Note:</strong> On {@link android.os.Build.VERSION_CODES#LOLLIPOP},
783          * {@code format} must not contain a {@linkplain MediaFormat#KEY_FRAME_RATE
784          * frame rate}. Use
785          * <code class=prettyprint>format.setString(MediaFormat.KEY_FRAME_RATE, null)</code>
786          * to clear any existing frame rate setting in the format.
787          * <p>
788          *
789          * The following table summarizes the format keys considered by this method.
790          * This is especially important to consider when targeting a higher SDK version than the
791          * minimum SDK version, as this method will disregard some keys on devices below the target
792          * SDK version.
793          *
794          * <table style="width: 0%">
795          *  <thead>
796          *   <tr>
797          *    <th rowspan=3>OS Version(s)</th>
798          *    <td colspan=3>{@code MediaFormat} keys considered for</th>
799          *   </tr><tr>
800          *    <th>Audio Codecs</th>
801          *    <th>Video Codecs</th>
802          *    <th>Encoders</th>
803          *   </tr>
804          *  </thead>
805          *  <tbody>
806          *   <tr>
807          *    <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP}</td>
808          *    <td rowspan=3>{@link MediaFormat#KEY_MIME}<sup>*</sup>,<br>
809          *        {@link MediaFormat#KEY_SAMPLE_RATE},<br>
810          *        {@link MediaFormat#KEY_CHANNEL_COUNT},</td>
811          *    <td>{@link MediaFormat#KEY_MIME}<sup>*</sup>,<br>
812          *        {@link CodecCapabilities#FEATURE_AdaptivePlayback}<sup>D</sup>,<br>
813          *        {@link CodecCapabilities#FEATURE_SecurePlayback}<sup>D</sup>,<br>
814          *        {@link CodecCapabilities#FEATURE_TunneledPlayback}<sup>D</sup>,<br>
815          *        {@link MediaFormat#KEY_WIDTH},<br>
816          *        {@link MediaFormat#KEY_HEIGHT},<br>
817          *        <strong>no</strong> {@code KEY_FRAME_RATE}</td>
818          *    <td rowspan=10>as to the left, plus<br>
819          *        {@link MediaFormat#KEY_BITRATE_MODE},<br>
820          *        {@link MediaFormat#KEY_PROFILE}
821          *        (and/or {@link MediaFormat#KEY_AAC_PROFILE}<sup>~</sup>),<br>
822          *        <!-- {link MediaFormat#KEY_QUALITY},<br> -->
823          *        {@link MediaFormat#KEY_COMPLEXITY}
824          *        (and/or {@link MediaFormat#KEY_FLAC_COMPRESSION_LEVEL}<sup>~</sup>)</td>
825          *   </tr><tr>
826          *    <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}</td>
827          *    <td rowspan=2>as above, plus<br>
828          *        {@link MediaFormat#KEY_FRAME_RATE}</td>
829          *   </tr><tr>
830          *    <td>{@link android.os.Build.VERSION_CODES#M}</td>
831          *   </tr><tr>
832          *    <td>{@link android.os.Build.VERSION_CODES#N}</td>
833          *    <td rowspan=2>as above, plus<br>
834          *        {@link MediaFormat#KEY_PROFILE},<br>
835          *        <!-- {link MediaFormat#KEY_MAX_BIT_RATE},<br> -->
836          *        {@link MediaFormat#KEY_BIT_RATE}</td>
837          *    <td rowspan=2>as above, plus<br>
838          *        {@link MediaFormat#KEY_PROFILE},<br>
839          *        {@link MediaFormat#KEY_LEVEL}<sup>+</sup>,<br>
840          *        <!-- {link MediaFormat#KEY_MAX_BIT_RATE},<br> -->
841          *        {@link MediaFormat#KEY_BIT_RATE},<br>
842          *        {@link CodecCapabilities#FEATURE_IntraRefresh}<sup>E</sup></td>
843          *   </tr><tr>
844          *    <td>{@link android.os.Build.VERSION_CODES#N_MR1}</td>
845          *   </tr><tr>
846          *    <td>{@link android.os.Build.VERSION_CODES#O}</td>
847          *    <td rowspan=3 colspan=2>as above, plus<br>
848          *        {@link CodecCapabilities#FEATURE_PartialFrame}<sup>D</sup></td>
849          *   </tr><tr>
850          *    <td>{@link android.os.Build.VERSION_CODES#O_MR1}</td>
851          *   </tr><tr>
852          *    <td>{@link android.os.Build.VERSION_CODES#P}</td>
853          *   </tr><tr>
854          *    <td>{@link android.os.Build.VERSION_CODES#Q}</td>
855          *    <td colspan=2>as above, plus<br>
856          *        {@link CodecCapabilities#FEATURE_FrameParsing}<sup>D</sup>,<br>
857          *        {@link CodecCapabilities#FEATURE_MultipleFrames},<br>
858          *        {@link CodecCapabilities#FEATURE_DynamicTimestamp}</td>
859          *   </tr><tr>
860          *    <td>{@link android.os.Build.VERSION_CODES#R}</td>
861          *    <td colspan=2>as above, plus<br>
862          *        {@link CodecCapabilities#FEATURE_LowLatency}<sup>D</sup></td>
863          *   </tr>
864          *   <tr>
865          *    <td colspan=4>
866          *     <p class=note><strong>Notes:</strong><br>
867          *      *: must be specified; otherwise, method returns {@code false}.<br>
868          *      +: method does not verify that the format parameters are supported
869          *      by the specified level.<br>
870          *      D: decoders only<br>
871          *      E: encoders only<br>
872          *      ~: if both keys are provided values must match
873          *    </td>
874          *   </tr>
875          *  </tbody>
876          * </table>
877          *
878          * @param format media format with optional feature directives.
879          * @throws IllegalArgumentException if format is not a valid media format.
880          * @return whether the codec capabilities support the given format
881          *         and feature requests.
882          */
isFormatSupported(MediaFormat format)883         public final boolean isFormatSupported(MediaFormat format) {
884             final Map<String, Object> map = format.getMap();
885             final String mime = (String)map.get(MediaFormat.KEY_MIME);
886 
887             // mime must match if present
888             if (mime != null && !mMime.equalsIgnoreCase(mime)) {
889                 return false;
890             }
891 
892             // check feature support
893             for (Feature feat: getValidFeatures()) {
894                 if (feat.mInternal) {
895                     continue;
896                 }
897 
898                 Integer yesNo = (Integer)map.get(MediaFormat.KEY_FEATURE_ + feat.mName);
899                 if (yesNo == null) {
900                     continue;
901                 }
902                 if ((yesNo == 1 && !isFeatureSupported(feat.mName)) ||
903                         (yesNo == 0 && isFeatureRequired(feat.mName))) {
904                     return false;
905                 }
906             }
907 
908             Integer profile = (Integer)map.get(MediaFormat.KEY_PROFILE);
909             Integer level = (Integer)map.get(MediaFormat.KEY_LEVEL);
910 
911             if (profile != null) {
912                 if (!supportsProfileLevel(profile, level)) {
913                     return false;
914                 }
915 
916                 // If we recognize this profile, check that this format is supported by the
917                 // highest level supported by the codec for that profile. (Ignore specified
918                 // level beyond the above profile/level check as level is only used as a
919                 // guidance. E.g. AVC Level 1 CIF format is supported if codec supports level 1.1
920                 // even though max size for Level 1 is QCIF. However, MPEG2 Simple Profile
921                 // 1080p format is not supported even if codec supports Main Profile Level High,
922                 // as Simple Profile does not support 1080p.
923                 CodecCapabilities levelCaps = null;
924                 int maxLevel = 0;
925                 for (CodecProfileLevel pl : profileLevels) {
926                     if (pl.profile == profile && pl.level > maxLevel) {
927                         // H.263 levels are not completely ordered:
928                         // Level45 support only implies Level10 support
929                         if (!mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)
930                                 || pl.level != CodecProfileLevel.H263Level45
931                                 || maxLevel == CodecProfileLevel.H263Level10) {
932                             maxLevel = pl.level;
933                         }
934                     }
935                 }
936                 levelCaps = createFromProfileLevel(mMime, profile, maxLevel);
937                 // We must remove the profile from this format otherwise levelCaps.isFormatSupported
938                 // will get into this same condition and loop forever. Furthermore, since levelCaps
939                 // does not contain features and bitrate specific keys, keep only keys relevant for
940                 // a level check.
941                 Map<String, Object> levelCriticalFormatMap = new HashMap<>(map);
942                 final Set<String> criticalKeys =
943                     isVideo() ? VideoCapabilities.VIDEO_LEVEL_CRITICAL_FORMAT_KEYS :
944                     isAudio() ? AudioCapabilities.AUDIO_LEVEL_CRITICAL_FORMAT_KEYS :
945                     null;
946 
947                 // critical keys will always contain KEY_MIME, but should also contain others to be
948                 // meaningful
949                 if (criticalKeys != null && criticalKeys.size() > 1 && levelCaps != null) {
950                     levelCriticalFormatMap.keySet().retainAll(criticalKeys);
951 
952                     MediaFormat levelCriticalFormat = new MediaFormat(levelCriticalFormatMap);
953                     if (!levelCaps.isFormatSupported(levelCriticalFormat)) {
954                         return false;
955                     }
956                 }
957             }
958             if (mAudioCaps != null && !mAudioCaps.supportsFormat(format)) {
959                 return false;
960             }
961             if (mVideoCaps != null && !mVideoCaps.supportsFormat(format)) {
962                 return false;
963             }
964             if (mEncoderCaps != null && !mEncoderCaps.supportsFormat(format)) {
965                 return false;
966             }
967             return true;
968         }
969 
supportsBitrate( Range<Integer> bitrateRange, MediaFormat format)970         private static boolean supportsBitrate(
971                 Range<Integer> bitrateRange, MediaFormat format) {
972             Map<String, Object> map = format.getMap();
973 
974             // consider max bitrate over average bitrate for support
975             Integer maxBitrate = (Integer)map.get(MediaFormat.KEY_MAX_BIT_RATE);
976             Integer bitrate = (Integer)map.get(MediaFormat.KEY_BIT_RATE);
977             if (bitrate == null) {
978                 bitrate = maxBitrate;
979             } else if (maxBitrate != null) {
980                 bitrate = Math.max(bitrate, maxBitrate);
981             }
982 
983             if (bitrate != null && bitrate > 0) {
984                 return bitrateRange.contains(bitrate);
985             }
986 
987             return true;
988         }
989 
supportsProfileLevel(int profile, Integer level)990         private boolean supportsProfileLevel(int profile, Integer level) {
991             for (CodecProfileLevel pl: profileLevels) {
992                 if (pl.profile != profile) {
993                     continue;
994                 }
995 
996                 // No specific level requested
997                 if (level == null) {
998                     return true;
999                 }
1000 
1001                 // AAC doesn't use levels
1002                 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC)) {
1003                     return true;
1004                 }
1005 
1006                 // DTS doesn't use levels
1007                 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_DTS)
1008                         || mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_DTS_HD)
1009                         || mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_DTS_UHD)) {
1010                     return true;
1011                 }
1012 
1013                 // H.263 levels are not completely ordered:
1014                 // Level45 support only implies Level10 support
1015                 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) {
1016                     if (pl.level != level && pl.level == CodecProfileLevel.H263Level45
1017                             && level > CodecProfileLevel.H263Level10) {
1018                         continue;
1019                     }
1020                 }
1021 
1022                 // MPEG4 levels are not completely ordered:
1023                 // Level1 support only implies Level0 (and not Level0b) support
1024                 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) {
1025                     if (pl.level != level && pl.level == CodecProfileLevel.MPEG4Level1
1026                             && level > CodecProfileLevel.MPEG4Level0) {
1027                         continue;
1028                     }
1029                 }
1030 
1031                 // HEVC levels incorporate both tiers and levels. Verify tier support.
1032                 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
1033                     boolean supportsHighTier =
1034                         (pl.level & CodecProfileLevel.HEVCHighTierLevels) != 0;
1035                     boolean checkingHighTier = (level & CodecProfileLevel.HEVCHighTierLevels) != 0;
1036                     // high tier levels are only supported by other high tier levels
1037                     if (checkingHighTier && !supportsHighTier) {
1038                         continue;
1039                     }
1040                 }
1041 
1042                 if (pl.level >= level) {
1043                     // if we recognize the listed profile/level, we must also recognize the
1044                     // profile/level arguments.
1045                     if (createFromProfileLevel(mMime, profile, pl.level) != null) {
1046                         return createFromProfileLevel(mMime, profile, level) != null;
1047                     }
1048                     return true;
1049                 }
1050             }
1051             return false;
1052         }
1053 
1054         // errors while reading profile levels - accessed from sister capabilities
1055         int mError;
1056 
1057         private static final String TAG = "CodecCapabilities";
1058 
1059         // NEW-STYLE CAPABILITIES
1060         private AudioCapabilities mAudioCaps;
1061         private VideoCapabilities mVideoCaps;
1062         private EncoderCapabilities mEncoderCaps;
1063         private MediaFormat mDefaultFormat;
1064 
1065         /**
1066          * Returns a MediaFormat object with default values for configurations that have
1067          * defaults.
1068          */
getDefaultFormat()1069         public MediaFormat getDefaultFormat() {
1070             return mDefaultFormat;
1071         }
1072 
1073         /**
1074          * Returns the mime type for which this codec-capability object was created.
1075          */
getMimeType()1076         public String getMimeType() {
1077             return mMime;
1078         }
1079 
1080         /**
1081          * Returns the max number of the supported concurrent codec instances.
1082          * <p>
1083          * This is a hint for an upper bound. Applications should not expect to successfully
1084          * operate more instances than the returned value, but the actual number of
1085          * concurrently operable instances may be less as it depends on the available
1086          * resources at time of use.
1087          */
getMaxSupportedInstances()1088         public int getMaxSupportedInstances() {
1089             return mMaxSupportedInstances;
1090         }
1091 
isAudio()1092         private boolean isAudio() {
1093             return mAudioCaps != null;
1094         }
1095 
1096         /**
1097          * Returns the audio capabilities or {@code null} if this is not an audio codec.
1098          */
getAudioCapabilities()1099         public AudioCapabilities getAudioCapabilities() {
1100             return mAudioCaps;
1101         }
1102 
isEncoder()1103         private boolean isEncoder() {
1104             return mEncoderCaps != null;
1105         }
1106 
1107         /**
1108          * Returns the encoding capabilities or {@code null} if this is not an encoder.
1109          */
getEncoderCapabilities()1110         public EncoderCapabilities getEncoderCapabilities() {
1111             return mEncoderCaps;
1112         }
1113 
isVideo()1114         private boolean isVideo() {
1115             return mVideoCaps != null;
1116         }
1117 
1118         /**
1119          * Returns the video capabilities or {@code null} if this is not a video codec.
1120          */
getVideoCapabilities()1121         public VideoCapabilities getVideoCapabilities() {
1122             return mVideoCaps;
1123         }
1124 
1125         /** @hide */
dup()1126         public CodecCapabilities dup() {
1127             CodecCapabilities caps = new CodecCapabilities();
1128 
1129             // profileLevels and colorFormats may be modified by client.
1130             caps.profileLevels = Arrays.copyOf(profileLevels, profileLevels.length);
1131             caps.colorFormats = Arrays.copyOf(colorFormats, colorFormats.length);
1132 
1133             caps.mMime = mMime;
1134             caps.mMaxSupportedInstances = mMaxSupportedInstances;
1135             caps.mFlagsRequired = mFlagsRequired;
1136             caps.mFlagsSupported = mFlagsSupported;
1137             caps.mFlagsVerified = mFlagsVerified;
1138             caps.mAudioCaps = mAudioCaps;
1139             caps.mVideoCaps = mVideoCaps;
1140             caps.mEncoderCaps = mEncoderCaps;
1141             caps.mDefaultFormat = mDefaultFormat;
1142             caps.mCapabilitiesInfo = mCapabilitiesInfo;
1143 
1144             return caps;
1145         }
1146 
1147         /**
1148          * Retrieve the codec capabilities for a certain {@code mime type}, {@code
1149          * profile} and {@code level}.  If the type, or profile-level combination
1150          * is not understood by the framework, it returns null.
1151          * <p class=note> In {@link android.os.Build.VERSION_CODES#M}, calling this
1152          * method without calling any method of the {@link MediaCodecList} class beforehand
1153          * results in a {@link NullPointerException}.</p>
1154          */
createFromProfileLevel( String mime, int profile, int level)1155         public static CodecCapabilities createFromProfileLevel(
1156                 String mime, int profile, int level) {
1157             CodecProfileLevel pl = new CodecProfileLevel();
1158             pl.profile = profile;
1159             pl.level = level;
1160             MediaFormat defaultFormat = new MediaFormat();
1161             defaultFormat.setString(MediaFormat.KEY_MIME, mime);
1162 
1163             CodecCapabilities ret = new CodecCapabilities(
1164                 new CodecProfileLevel[] { pl }, new int[0], true /* encoder */,
1165                 defaultFormat, new MediaFormat() /* info */);
1166             if (ret.mError != 0) {
1167                 return null;
1168             }
1169             return ret;
1170         }
1171 
CodecCapabilities( CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, Map<String, Object>defaultFormatMap, Map<String, Object>capabilitiesMap)1172         /* package private */ CodecCapabilities(
1173                 CodecProfileLevel[] profLevs, int[] colFmts,
1174                 boolean encoder,
1175                 Map<String, Object>defaultFormatMap,
1176                 Map<String, Object>capabilitiesMap) {
1177             this(profLevs, colFmts, encoder,
1178                     new MediaFormat(defaultFormatMap),
1179                     new MediaFormat(capabilitiesMap));
1180         }
1181 
1182         private MediaFormat mCapabilitiesInfo;
1183 
CodecCapabilities( CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, MediaFormat defaultFormat, MediaFormat info)1184         /* package private */ CodecCapabilities(
1185                 CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder,
1186                 MediaFormat defaultFormat, MediaFormat info) {
1187             final Map<String, Object> map = info.getMap();
1188             colorFormats = colFmts;
1189             mFlagsVerified = 0; // TODO: remove as it is unused
1190             mDefaultFormat = defaultFormat;
1191             mCapabilitiesInfo = info;
1192             mMime = mDefaultFormat.getString(MediaFormat.KEY_MIME);
1193 
1194             /* VP9 introduced profiles around 2016, so some VP9 codecs may not advertise any
1195                supported profiles. Determine the level for them using the info they provide. */
1196             if (profLevs.length == 0 && mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) {
1197                 CodecProfileLevel profLev = new CodecProfileLevel();
1198                 profLev.profile = CodecProfileLevel.VP9Profile0;
1199                 profLev.level = VideoCapabilities.equivalentVP9Level(info);
1200                 profLevs = new CodecProfileLevel[] { profLev };
1201             }
1202             profileLevels = profLevs;
1203 
1204             if (mMime.toLowerCase().startsWith("audio/")) {
1205                 mAudioCaps = AudioCapabilities.create(info, this);
1206                 mAudioCaps.getDefaultFormat(mDefaultFormat);
1207             } else if (mMime.toLowerCase().startsWith("video/")
1208                     || mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC)) {
1209                 mVideoCaps = VideoCapabilities.create(info, this);
1210             }
1211             if (encoder) {
1212                 mEncoderCaps = EncoderCapabilities.create(info, this);
1213                 mEncoderCaps.getDefaultFormat(mDefaultFormat);
1214             }
1215 
1216             final Map<String, Object> global = MediaCodecList.getGlobalSettings();
1217             mMaxSupportedInstances = Utils.parseIntSafely(
1218                     global.get("max-concurrent-instances"), DEFAULT_MAX_SUPPORTED_INSTANCES);
1219 
1220             int maxInstances = Utils.parseIntSafely(
1221                     map.get("max-concurrent-instances"), mMaxSupportedInstances);
1222             mMaxSupportedInstances =
1223                     Range.create(1, MAX_SUPPORTED_INSTANCES_LIMIT).clamp(maxInstances);
1224 
1225             for (Feature feat: getValidFeatures()) {
1226                 String key = MediaFormat.KEY_FEATURE_ + feat.mName;
1227                 Integer yesNo = (Integer)map.get(key);
1228                 if (yesNo == null) {
1229                     continue;
1230                 }
1231                 if (yesNo > 0) {
1232                     mFlagsRequired |= feat.mValue;
1233                 }
1234                 mFlagsSupported |= feat.mValue;
1235                 if (!feat.mInternal) {
1236                     mDefaultFormat.setInteger(key, 1);
1237                 }
1238                 // TODO restrict features by mFlagsVerified once all codecs reliably verify them
1239             }
1240         }
1241     }
1242 
1243     /**
1244      * A class that supports querying the audio capabilities of a codec.
1245      */
1246     public static final class AudioCapabilities {
1247         private static final String TAG = "AudioCapabilities";
1248         private CodecCapabilities mParent;
1249         private Range<Integer> mBitrateRange;
1250 
1251         private int[] mSampleRates;
1252         private Range<Integer>[] mSampleRateRanges;
1253         private Range<Integer>[] mInputChannelRanges;
1254 
1255         private static final int MAX_INPUT_CHANNEL_COUNT = 30;
1256 
1257         /**
1258          * Returns the range of supported bitrates in bits/second.
1259          */
getBitrateRange()1260         public Range<Integer> getBitrateRange() {
1261             return mBitrateRange;
1262         }
1263 
1264         /**
1265          * Returns the array of supported sample rates if the codec
1266          * supports only discrete values.  Otherwise, it returns
1267          * {@code null}.  The array is sorted in ascending order.
1268          */
getSupportedSampleRates()1269         public int[] getSupportedSampleRates() {
1270             return mSampleRates != null ? Arrays.copyOf(mSampleRates, mSampleRates.length) : null;
1271         }
1272 
1273         /**
1274          * Returns the array of supported sample rate ranges.  The
1275          * array is sorted in ascending order, and the ranges are
1276          * distinct.
1277          */
getSupportedSampleRateRanges()1278         public Range<Integer>[] getSupportedSampleRateRanges() {
1279             return Arrays.copyOf(mSampleRateRanges, mSampleRateRanges.length);
1280         }
1281 
1282         /**
1283          * Returns the maximum number of input channels supported.
1284          *
1285          * Through {@link android.os.Build.VERSION_CODES#R}, this method indicated support
1286          * for any number of input channels between 1 and this maximum value.
1287          *
1288          * As of {@link android.os.Build.VERSION_CODES#S},
1289          * the implied lower limit of 1 channel is no longer valid.
1290          * As of {@link android.os.Build.VERSION_CODES#S}, {@link #getMaxInputChannelCount} is
1291          * superseded by {@link #getInputChannelCountRanges},
1292          * which returns an array of ranges of channels.
1293          * The {@link #getMaxInputChannelCount} method will return the highest value
1294          * in the ranges returned by {@link #getInputChannelCountRanges}
1295          *
1296          */
1297         @IntRange(from = 1, to = 255)
getMaxInputChannelCount()1298         public int getMaxInputChannelCount() {
1299             int overall_max = 0;
1300             for (int i = mInputChannelRanges.length - 1; i >= 0; i--) {
1301                 int lmax = mInputChannelRanges[i].getUpper();
1302                 if (lmax > overall_max) {
1303                     overall_max = lmax;
1304                 }
1305             }
1306             return overall_max;
1307         }
1308 
1309         /**
1310          * Returns the minimum number of input channels supported.
1311          * This is often 1, but does vary for certain mime types.
1312          *
1313          * This returns the lowest channel count in the ranges returned by
1314          * {@link #getInputChannelCountRanges}.
1315          */
1316         @IntRange(from = 1, to = 255)
getMinInputChannelCount()1317         public int getMinInputChannelCount() {
1318             int overall_min = MAX_INPUT_CHANNEL_COUNT;
1319             for (int i = mInputChannelRanges.length - 1; i >= 0; i--) {
1320                 int lmin = mInputChannelRanges[i].getLower();
1321                 if (lmin < overall_min) {
1322                     overall_min = lmin;
1323                 }
1324             }
1325             return overall_min;
1326         }
1327 
1328         /*
1329          * Returns an array of ranges representing the number of input channels supported.
1330          * The codec supports any number of input channels within this range.
1331          *
1332          * This supersedes the {@link #getMaxInputChannelCount} method.
1333          *
1334          * For many codecs, this will be a single range [1..N], for some N.
1335          */
1336         @SuppressLint("ArrayReturn")
1337         @NonNull
getInputChannelCountRanges()1338         public Range<Integer>[] getInputChannelCountRanges() {
1339             return Arrays.copyOf(mInputChannelRanges, mInputChannelRanges.length);
1340         }
1341 
1342         /* no public constructor */
AudioCapabilities()1343         private AudioCapabilities() { }
1344 
1345         /** @hide */
create( MediaFormat info, CodecCapabilities parent)1346         public static AudioCapabilities create(
1347                 MediaFormat info, CodecCapabilities parent) {
1348             AudioCapabilities caps = new AudioCapabilities();
1349             caps.init(info, parent);
1350             return caps;
1351         }
1352 
init(MediaFormat info, CodecCapabilities parent)1353         private void init(MediaFormat info, CodecCapabilities parent) {
1354             mParent = parent;
1355             initWithPlatformLimits();
1356             applyLevelLimits();
1357             parseFromInfo(info);
1358         }
1359 
initWithPlatformLimits()1360         private void initWithPlatformLimits() {
1361             mBitrateRange = Range.create(0, Integer.MAX_VALUE);
1362             mInputChannelRanges = new Range[] {Range.create(1, MAX_INPUT_CHANNEL_COUNT)};
1363             // mBitrateRange = Range.create(1, 320000);
1364             final int minSampleRate = SystemProperties.
1365                 getInt("ro.mediacodec.min_sample_rate", 7350);
1366             final int maxSampleRate = SystemProperties.
1367                 getInt("ro.mediacodec.max_sample_rate", 192000);
1368             mSampleRateRanges = new Range[] { Range.create(minSampleRate, maxSampleRate) };
1369             mSampleRates = null;
1370         }
1371 
supports(Integer sampleRate, Integer inputChannels)1372         private boolean supports(Integer sampleRate, Integer inputChannels) {
1373             // channels and sample rates are checked orthogonally
1374             if (inputChannels != null) {
1375                 int ix = Utils.binarySearchDistinctRanges(
1376                         mInputChannelRanges, inputChannels);
1377                 if (ix < 0) {
1378                     return false;
1379                 }
1380             }
1381             if (sampleRate != null) {
1382                 int ix = Utils.binarySearchDistinctRanges(
1383                         mSampleRateRanges, sampleRate);
1384                 if (ix < 0) {
1385                     return false;
1386                 }
1387             }
1388             return true;
1389         }
1390 
1391         /**
1392          * Query whether the sample rate is supported by the codec.
1393          */
isSampleRateSupported(int sampleRate)1394         public boolean isSampleRateSupported(int sampleRate) {
1395             return supports(sampleRate, null);
1396         }
1397 
1398         /** modifies rates */
limitSampleRates(int[] rates)1399         private void limitSampleRates(int[] rates) {
1400             Arrays.sort(rates);
1401             ArrayList<Range<Integer>> ranges = new ArrayList<Range<Integer>>();
1402             for (int rate: rates) {
1403                 if (supports(rate, null /* channels */)) {
1404                     ranges.add(Range.create(rate, rate));
1405                 }
1406             }
1407             mSampleRateRanges = ranges.toArray(new Range[ranges.size()]);
1408             createDiscreteSampleRates();
1409         }
1410 
createDiscreteSampleRates()1411         private void createDiscreteSampleRates() {
1412             mSampleRates = new int[mSampleRateRanges.length];
1413             for (int i = 0; i < mSampleRateRanges.length; i++) {
1414                 mSampleRates[i] = mSampleRateRanges[i].getLower();
1415             }
1416         }
1417 
1418         /** modifies rateRanges */
limitSampleRates(Range<Integer>[] rateRanges)1419         private void limitSampleRates(Range<Integer>[] rateRanges) {
1420             sortDistinctRanges(rateRanges);
1421             mSampleRateRanges = intersectSortedDistinctRanges(mSampleRateRanges, rateRanges);
1422 
1423             // check if all values are discrete
1424             for (Range<Integer> range: mSampleRateRanges) {
1425                 if (!range.getLower().equals(range.getUpper())) {
1426                     mSampleRates = null;
1427                     return;
1428                 }
1429             }
1430             createDiscreteSampleRates();
1431         }
1432 
applyLevelLimits()1433         private void applyLevelLimits() {
1434             int[] sampleRates = null;
1435             Range<Integer> sampleRateRange = null, bitRates = null;
1436             int maxChannels = MAX_INPUT_CHANNEL_COUNT;
1437             CodecProfileLevel[] profileLevels = mParent.profileLevels;
1438             String mime = mParent.getMimeType();
1439 
1440             if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MPEG)) {
1441                 sampleRates = new int[] {
1442                         8000, 11025, 12000,
1443                         16000, 22050, 24000,
1444                         32000, 44100, 48000 };
1445                 bitRates = Range.create(8000, 320000);
1446                 maxChannels = 2;
1447             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)) {
1448                 sampleRates = new int[] { 8000 };
1449                 bitRates = Range.create(4750, 12200);
1450                 maxChannels = 1;
1451             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)) {
1452                 sampleRates = new int[] { 16000 };
1453                 bitRates = Range.create(6600, 23850);
1454                 maxChannels = 1;
1455             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC)) {
1456                 sampleRates = new int[] {
1457                         7350, 8000,
1458                         11025, 12000, 16000,
1459                         22050, 24000, 32000,
1460                         44100, 48000, 64000,
1461                         88200, 96000 };
1462                 bitRates = Range.create(8000, 510000);
1463                 maxChannels = 48;
1464             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_VORBIS)) {
1465                 bitRates = Range.create(32000, 500000);
1466                 sampleRateRange = Range.create(8000, 192000);
1467                 maxChannels = 255;
1468             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_OPUS)) {
1469                 bitRates = Range.create(6000, 510000);
1470                 sampleRates = new int[] { 8000, 12000, 16000, 24000, 48000 };
1471                 maxChannels = 255;
1472             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW)) {
1473                 sampleRateRange = Range.create(1, 192000);
1474                 bitRates = Range.create(1, 10000000);
1475                 maxChannels = AudioSystem.OUT_CHANNEL_COUNT_MAX;
1476             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
1477                 sampleRateRange = Range.create(1, 655350);
1478                 // lossless codec, so bitrate is ignored
1479                 maxChannels = 255;
1480             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW)
1481                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)) {
1482                 sampleRates = new int[] { 8000 };
1483                 bitRates = Range.create(64000, 64000);
1484                 // platform allows multiple channels for this format
1485             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) {
1486                 sampleRates = new int[] { 8000 };
1487                 bitRates = Range.create(13000, 13000);
1488                 maxChannels = 1;
1489             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AC3)) {
1490                 maxChannels = 6;
1491             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_EAC3)) {
1492                 maxChannels = 16;
1493             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_EAC3_JOC)) {
1494                 sampleRates = new int[] { 48000 };
1495                 bitRates = Range.create(32000, 6144000);
1496                 maxChannels = 16;
1497             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AC4)) {
1498                 sampleRates = new int[] { 44100, 48000, 96000, 192000 };
1499                 bitRates = Range.create(16000, 2688000);
1500                 maxChannels = 24;
1501             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_DTS)) {
1502                 sampleRates = new int[] { 44100, 48000 };
1503                 bitRates = Range.create(96000, 1524000);
1504                 maxChannels = 6;
1505             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_DTS_HD)) {
1506                 for (CodecProfileLevel profileLevel: profileLevels) {
1507                     switch (profileLevel.profile) {
1508                         case CodecProfileLevel.DTS_HDProfileLBR:
1509                             sampleRates = new int[]{ 22050, 24000, 44100, 48000 };
1510                             bitRates = Range.create(32000, 768000);
1511                             break;
1512                         case CodecProfileLevel.DTS_HDProfileHRA:
1513                         case CodecProfileLevel.DTS_HDProfileMA:
1514                             sampleRates = new int[]{ 44100, 48000, 88200, 96000, 176400, 192000 };
1515                             bitRates = Range.create(96000, 24500000);
1516                             break;
1517                         default:
1518                             Log.w(TAG, "Unrecognized profile "
1519                                     + profileLevel.profile + " for " + mime);
1520                             mParent.mError |= ERROR_UNRECOGNIZED;
1521                             sampleRates = new int[]{ 44100, 48000, 88200, 96000, 176400, 192000 };
1522                             bitRates = Range.create(96000, 24500000);
1523                     }
1524                 }
1525                 maxChannels = 8;
1526             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_DTS_UHD)) {
1527                 for (CodecProfileLevel profileLevel: profileLevels) {
1528                     switch (profileLevel.profile) {
1529                         case CodecProfileLevel.DTS_UHDProfileP2:
1530                             sampleRates = new int[]{ 48000 };
1531                             bitRates = Range.create(96000, 768000);
1532                             maxChannels = 10;
1533                             break;
1534                         case CodecProfileLevel.DTS_UHDProfileP1:
1535                             sampleRates = new int[]{ 44100, 48000, 88200, 96000, 176400, 192000 };
1536                             bitRates = Range.create(96000, 24500000);
1537                             maxChannels = 32;
1538                             break;
1539                         default:
1540                             Log.w(TAG, "Unrecognized profile "
1541                                     + profileLevel.profile + " for " + mime);
1542                             mParent.mError |= ERROR_UNRECOGNIZED;
1543                             sampleRates = new int[]{ 44100, 48000, 88200, 96000, 176400, 192000 };
1544                             bitRates = Range.create(96000, 24500000);
1545                             maxChannels = 32;
1546                     }
1547                 }
1548             } else {
1549                 Log.w(TAG, "Unsupported mime " + mime);
1550                 mParent.mError |= ERROR_UNSUPPORTED;
1551             }
1552 
1553             // restrict ranges
1554             if (sampleRates != null) {
1555                 limitSampleRates(sampleRates);
1556             } else if (sampleRateRange != null) {
1557                 limitSampleRates(new Range[] { sampleRateRange });
1558             }
1559 
1560             Range<Integer> channelRange = Range.create(1, maxChannels);
1561 
1562             applyLimits(new Range[] { channelRange }, bitRates);
1563         }
1564 
applyLimits(Range<Integer>[] inputChannels, Range<Integer> bitRates)1565         private void applyLimits(Range<Integer>[] inputChannels, Range<Integer> bitRates) {
1566 
1567             // clamp & make a local copy
1568             Range<Integer>[] myInputChannels = new Range[inputChannels.length];
1569             for (int i = 0; i < inputChannels.length; i++) {
1570                 int lower = inputChannels[i].clamp(1);
1571                 int upper = inputChannels[i].clamp(MAX_INPUT_CHANNEL_COUNT);
1572                 myInputChannels[i] = Range.create(lower, upper);
1573             }
1574 
1575             // sort, intersect with existing, & save channel list
1576             sortDistinctRanges(myInputChannels);
1577             Range<Integer>[] joinedChannelList =
1578                             intersectSortedDistinctRanges(myInputChannels, mInputChannelRanges);
1579             mInputChannelRanges = joinedChannelList;
1580 
1581             if (bitRates != null) {
1582                 mBitrateRange = mBitrateRange.intersect(bitRates);
1583             }
1584         }
1585 
parseFromInfo(MediaFormat info)1586         private void parseFromInfo(MediaFormat info) {
1587             int maxInputChannels = MAX_INPUT_CHANNEL_COUNT;
1588             Range<Integer>[] channels = new Range[] { Range.create(1, maxInputChannels)};
1589             Range<Integer> bitRates = POSITIVE_INTEGERS;
1590 
1591             if (info.containsKey("sample-rate-ranges")) {
1592                 String[] rateStrings = info.getString("sample-rate-ranges").split(",");
1593                 Range<Integer>[] rateRanges = new Range[rateStrings.length];
1594                 for (int i = 0; i < rateStrings.length; i++) {
1595                     rateRanges[i] = Utils.parseIntRange(rateStrings[i], null);
1596                 }
1597                 limitSampleRates(rateRanges);
1598             }
1599 
1600             // we will prefer channel-ranges over max-channel-count
1601             if (info.containsKey("channel-ranges")) {
1602                 String[] channelStrings = info.getString("channel-ranges").split(",");
1603                 Range<Integer>[] channelRanges = new Range[channelStrings.length];
1604                 for (int i = 0; i < channelStrings.length; i++) {
1605                     channelRanges[i] = Utils.parseIntRange(channelStrings[i], null);
1606                 }
1607                 channels = channelRanges;
1608             } else if (info.containsKey("channel-range")) {
1609                 Range<Integer> oneRange = Utils.parseIntRange(info.getString("channel-range"),
1610                                                               null);
1611                 channels = new Range[] { oneRange };
1612             } else if (info.containsKey("max-channel-count")) {
1613                 maxInputChannels = Utils.parseIntSafely(
1614                         info.getString("max-channel-count"), maxInputChannels);
1615                 if (maxInputChannels == 0) {
1616                     channels = new Range[] {Range.create(0, 0)};
1617                 } else {
1618                     channels = new Range[] {Range.create(1, maxInputChannels)};
1619                 }
1620             } else if ((mParent.mError & ERROR_UNSUPPORTED) != 0) {
1621                 maxInputChannels = 0;
1622                 channels = new Range[] {Range.create(0, 0)};
1623             }
1624 
1625             if (info.containsKey("bitrate-range")) {
1626                 bitRates = bitRates.intersect(
1627                         Utils.parseIntRange(info.getString("bitrate-range"), bitRates));
1628             }
1629 
1630             applyLimits(channels, bitRates);
1631         }
1632 
1633         /** @hide */
getDefaultFormat(MediaFormat format)1634         public void getDefaultFormat(MediaFormat format) {
1635             // report settings that have only a single choice
1636             if (mBitrateRange.getLower().equals(mBitrateRange.getUpper())) {
1637                 format.setInteger(MediaFormat.KEY_BIT_RATE, mBitrateRange.getLower());
1638             }
1639             if (getMaxInputChannelCount() == 1) {
1640                 // mono-only format
1641                 format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
1642             }
1643             if (mSampleRates != null && mSampleRates.length == 1) {
1644                 format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRates[0]);
1645             }
1646         }
1647 
1648         /* package private */
1649         // must not contain KEY_PROFILE
1650         static final Set<String> AUDIO_LEVEL_CRITICAL_FORMAT_KEYS = Set.of(
1651                 // We don't set level-specific limits for audio codecs today. Key candidates would
1652                 // be sample rate, bit rate or channel count.
1653                 // MediaFormat.KEY_SAMPLE_RATE,
1654                 // MediaFormat.KEY_CHANNEL_COUNT,
1655                 // MediaFormat.KEY_BIT_RATE,
1656                 MediaFormat.KEY_MIME);
1657 
1658         /** @hide */
supportsFormat(MediaFormat format)1659         public boolean supportsFormat(MediaFormat format) {
1660             Map<String, Object> map = format.getMap();
1661             Integer sampleRate = (Integer)map.get(MediaFormat.KEY_SAMPLE_RATE);
1662             Integer channels = (Integer)map.get(MediaFormat.KEY_CHANNEL_COUNT);
1663 
1664             if (!supports(sampleRate, channels)) {
1665                 return false;
1666             }
1667 
1668             if (!CodecCapabilities.supportsBitrate(mBitrateRange, format)) {
1669                 return false;
1670             }
1671 
1672             // nothing to do for:
1673             // KEY_CHANNEL_MASK: codecs don't get this
1674             // KEY_IS_ADTS:      required feature for all AAC decoders
1675             return true;
1676         }
1677     }
1678 
1679     /**
1680      * A class that supports querying the video capabilities of a codec.
1681      */
1682     public static final class VideoCapabilities {
1683         private static final String TAG = "VideoCapabilities";
1684         private CodecCapabilities mParent;
1685         private Range<Integer> mBitrateRange;
1686 
1687         private Range<Integer> mHeightRange;
1688         private Range<Integer> mWidthRange;
1689         private Range<Integer> mBlockCountRange;
1690         private Range<Integer> mHorizontalBlockRange;
1691         private Range<Integer> mVerticalBlockRange;
1692         private Range<Rational> mAspectRatioRange;
1693         private Range<Rational> mBlockAspectRatioRange;
1694         private Range<Long> mBlocksPerSecondRange;
1695         private Map<Size, Range<Long>> mMeasuredFrameRates;
1696         private List<PerformancePoint> mPerformancePoints;
1697         private Range<Integer> mFrameRateRange;
1698 
1699         private int mBlockWidth;
1700         private int mBlockHeight;
1701         private int mWidthAlignment;
1702         private int mHeightAlignment;
1703         private int mSmallerDimensionUpperLimit;
1704 
1705         private boolean mAllowMbOverride; // allow XML to override calculated limits
1706 
1707         /**
1708          * Returns the range of supported bitrates in bits/second.
1709          */
getBitrateRange()1710         public Range<Integer> getBitrateRange() {
1711             return mBitrateRange;
1712         }
1713 
1714         /**
1715          * Returns the range of supported video widths.
1716          * <p class=note>
1717          * 32-bit processes will not support resolutions larger than 4096x4096 due to
1718          * the limited address space.
1719          */
getSupportedWidths()1720         public Range<Integer> getSupportedWidths() {
1721             return mWidthRange;
1722         }
1723 
1724         /**
1725          * Returns the range of supported video heights.
1726          * <p class=note>
1727          * 32-bit processes will not support resolutions larger than 4096x4096 due to
1728          * the limited address space.
1729          */
getSupportedHeights()1730         public Range<Integer> getSupportedHeights() {
1731             return mHeightRange;
1732         }
1733 
1734         /**
1735          * Returns the alignment requirement for video width (in pixels).
1736          *
1737          * This is a power-of-2 value that video width must be a
1738          * multiple of.
1739          */
getWidthAlignment()1740         public int getWidthAlignment() {
1741             return mWidthAlignment;
1742         }
1743 
1744         /**
1745          * Returns the alignment requirement for video height (in pixels).
1746          *
1747          * This is a power-of-2 value that video height must be a
1748          * multiple of.
1749          */
getHeightAlignment()1750         public int getHeightAlignment() {
1751             return mHeightAlignment;
1752         }
1753 
1754         /**
1755          * Return the upper limit on the smaller dimension of width or height.
1756          * <p></p>
1757          * Some codecs have a limit on the smaller dimension, whether it be
1758          * the width or the height.  E.g. a codec may only be able to handle
1759          * up to 1920x1080 both in landscape and portrait mode (1080x1920).
1760          * In this case the maximum width and height are both 1920, but the
1761          * smaller dimension limit will be 1080. For other codecs, this is
1762          * {@code Math.min(getSupportedWidths().getUpper(),
1763          * getSupportedHeights().getUpper())}.
1764          *
1765          * @hide
1766          */
getSmallerDimensionUpperLimit()1767         public int getSmallerDimensionUpperLimit() {
1768             return mSmallerDimensionUpperLimit;
1769         }
1770 
1771         /**
1772          * Returns the range of supported frame rates.
1773          * <p>
1774          * This is not a performance indicator.  Rather, it expresses the
1775          * limits specified in the coding standard, based on the complexities
1776          * of encoding material for later playback at a certain frame rate,
1777          * or the decoding of such material in non-realtime.
1778          */
getSupportedFrameRates()1779         public Range<Integer> getSupportedFrameRates() {
1780             return mFrameRateRange;
1781         }
1782 
1783         /**
1784          * Returns the range of supported video widths for a video height.
1785          * @param height the height of the video
1786          */
getSupportedWidthsFor(int height)1787         public Range<Integer> getSupportedWidthsFor(int height) {
1788             try {
1789                 Range<Integer> range = mWidthRange;
1790                 if (!mHeightRange.contains(height)
1791                         || (height % mHeightAlignment) != 0) {
1792                     throw new IllegalArgumentException("unsupported height");
1793                 }
1794                 final int heightInBlocks = Utils.divUp(height, mBlockHeight);
1795 
1796                 // constrain by block count and by block aspect ratio
1797                 final int minWidthInBlocks = Math.max(
1798                         Utils.divUp(mBlockCountRange.getLower(), heightInBlocks),
1799                         (int)Math.ceil(mBlockAspectRatioRange.getLower().doubleValue()
1800                                 * heightInBlocks));
1801                 final int maxWidthInBlocks = Math.min(
1802                         mBlockCountRange.getUpper() / heightInBlocks,
1803                         (int)(mBlockAspectRatioRange.getUpper().doubleValue()
1804                                 * heightInBlocks));
1805                 range = range.intersect(
1806                         (minWidthInBlocks - 1) * mBlockWidth + mWidthAlignment,
1807                         maxWidthInBlocks * mBlockWidth);
1808 
1809                 // constrain by smaller dimension limit
1810                 if (height > mSmallerDimensionUpperLimit) {
1811                     range = range.intersect(1, mSmallerDimensionUpperLimit);
1812                 }
1813 
1814                 // constrain by aspect ratio
1815                 range = range.intersect(
1816                         (int)Math.ceil(mAspectRatioRange.getLower().doubleValue()
1817                                 * height),
1818                         (int)(mAspectRatioRange.getUpper().doubleValue() * height));
1819                 return range;
1820             } catch (IllegalArgumentException e) {
1821                 // height is not supported because there are no suitable widths
1822                 Log.v(TAG, "could not get supported widths for " + height);
1823                 throw new IllegalArgumentException("unsupported height");
1824             }
1825         }
1826 
1827         /**
1828          * Returns the range of supported video heights for a video width
1829          * @param width the width of the video
1830          */
getSupportedHeightsFor(int width)1831         public Range<Integer> getSupportedHeightsFor(int width) {
1832             try {
1833                 Range<Integer> range = mHeightRange;
1834                 if (!mWidthRange.contains(width)
1835                         || (width % mWidthAlignment) != 0) {
1836                     throw new IllegalArgumentException("unsupported width");
1837                 }
1838                 final int widthInBlocks = Utils.divUp(width, mBlockWidth);
1839 
1840                 // constrain by block count and by block aspect ratio
1841                 final int minHeightInBlocks = Math.max(
1842                         Utils.divUp(mBlockCountRange.getLower(), widthInBlocks),
1843                         (int)Math.ceil(widthInBlocks /
1844                                 mBlockAspectRatioRange.getUpper().doubleValue()));
1845                 final int maxHeightInBlocks = Math.min(
1846                         mBlockCountRange.getUpper() / widthInBlocks,
1847                         (int)(widthInBlocks /
1848                                 mBlockAspectRatioRange.getLower().doubleValue()));
1849                 range = range.intersect(
1850                         (minHeightInBlocks - 1) * mBlockHeight + mHeightAlignment,
1851                         maxHeightInBlocks * mBlockHeight);
1852 
1853                 // constrain by smaller dimension limit
1854                 if (width > mSmallerDimensionUpperLimit) {
1855                     range = range.intersect(1, mSmallerDimensionUpperLimit);
1856                 }
1857 
1858                 // constrain by aspect ratio
1859                 range = range.intersect(
1860                         (int)Math.ceil(width /
1861                                 mAspectRatioRange.getUpper().doubleValue()),
1862                         (int)(width / mAspectRatioRange.getLower().doubleValue()));
1863                 return range;
1864             } catch (IllegalArgumentException e) {
1865                 // width is not supported because there are no suitable heights
1866                 Log.v(TAG, "could not get supported heights for " + width);
1867                 throw new IllegalArgumentException("unsupported width");
1868             }
1869         }
1870 
1871         /**
1872          * Returns the range of supported video frame rates for a video size.
1873          * <p>
1874          * This is not a performance indicator.  Rather, it expresses the limits specified in
1875          * the coding standard, based on the complexities of encoding material of a given
1876          * size for later playback at a certain frame rate, or the decoding of such material
1877          * in non-realtime.
1878 
1879          * @param width the width of the video
1880          * @param height the height of the video
1881          */
getSupportedFrameRatesFor(int width, int height)1882         public Range<Double> getSupportedFrameRatesFor(int width, int height) {
1883             Range<Integer> range = mHeightRange;
1884             if (!supports(width, height, null)) {
1885                 throw new IllegalArgumentException("unsupported size");
1886             }
1887             final int blockCount =
1888                 Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight);
1889 
1890             return Range.create(
1891                     Math.max(mBlocksPerSecondRange.getLower() / (double) blockCount,
1892                             (double) mFrameRateRange.getLower()),
1893                     Math.min(mBlocksPerSecondRange.getUpper() / (double) blockCount,
1894                             (double) mFrameRateRange.getUpper()));
1895         }
1896 
getBlockCount(int width, int height)1897         private int getBlockCount(int width, int height) {
1898             return Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight);
1899         }
1900 
1901         @NonNull
findClosestSize(int width, int height)1902         private Size findClosestSize(int width, int height) {
1903             int targetBlockCount = getBlockCount(width, height);
1904             Size closestSize = null;
1905             int minDiff = Integer.MAX_VALUE;
1906             for (Size size : mMeasuredFrameRates.keySet()) {
1907                 int diff = Math.abs(targetBlockCount -
1908                         getBlockCount(size.getWidth(), size.getHeight()));
1909                 if (diff < minDiff) {
1910                     minDiff = diff;
1911                     closestSize = size;
1912                 }
1913             }
1914             return closestSize;
1915         }
1916 
estimateFrameRatesFor(int width, int height)1917         private Range<Double> estimateFrameRatesFor(int width, int height) {
1918             Size size = findClosestSize(width, height);
1919             Range<Long> range = mMeasuredFrameRates.get(size);
1920             Double ratio = getBlockCount(size.getWidth(), size.getHeight())
1921                     / (double)Math.max(getBlockCount(width, height), 1);
1922             return Range.create(range.getLower() * ratio, range.getUpper() * ratio);
1923         }
1924 
1925         /**
1926          * Returns the range of achievable video frame rates for a video size.
1927          * May return {@code null}, if the codec did not publish any measurement
1928          * data.
1929          * <p>
1930          * This is a performance estimate provided by the device manufacturer based on statistical
1931          * sampling of full-speed decoding and encoding measurements in various configurations
1932          * of common video sizes supported by the codec. As such it should only be used to
1933          * compare individual codecs on the device. The value is not suitable for comparing
1934          * different devices or even different android releases for the same device.
1935          * <p>
1936          * <em>On {@link android.os.Build.VERSION_CODES#M} release</em> the returned range
1937          * corresponds to the fastest frame rates achieved in the tested configurations. As
1938          * such, it should not be used to gauge guaranteed or even average codec performance
1939          * on the device.
1940          * <p>
1941          * <em>On {@link android.os.Build.VERSION_CODES#N} release</em> the returned range
1942          * corresponds closer to sustained performance <em>in tested configurations</em>.
1943          * One can expect to achieve sustained performance higher than the lower limit more than
1944          * 50% of the time, and higher than half of the lower limit at least 90% of the time
1945          * <em>in tested configurations</em>.
1946          * Conversely, one can expect performance lower than twice the upper limit at least
1947          * 90% of the time.
1948          * <p class=note>
1949          * Tested configurations use a single active codec. For use cases where multiple
1950          * codecs are active, applications can expect lower and in most cases significantly lower
1951          * performance.
1952          * <p class=note>
1953          * The returned range value is interpolated from the nearest frame size(s) tested.
1954          * Codec performance is severely impacted by other activity on the device as well
1955          * as environmental factors (such as battery level, temperature or power source), and can
1956          * vary significantly even in a steady environment.
1957          * <p class=note>
1958          * Use this method in cases where only codec performance matters, e.g. to evaluate if
1959          * a codec has any chance of meeting a performance target. Codecs are listed
1960          * in {@link MediaCodecList} in the preferred order as defined by the device
1961          * manufacturer. As such, applications should use the first suitable codec in the
1962          * list to achieve the best balance between power use and performance.
1963          *
1964          * @param width the width of the video
1965          * @param height the height of the video
1966          *
1967          * @throws IllegalArgumentException if the video size is not supported.
1968          */
1969         @Nullable
getAchievableFrameRatesFor(int width, int height)1970         public Range<Double> getAchievableFrameRatesFor(int width, int height) {
1971             if (!supports(width, height, null)) {
1972                 throw new IllegalArgumentException("unsupported size");
1973             }
1974 
1975             if (mMeasuredFrameRates == null || mMeasuredFrameRates.size() <= 0) {
1976                 Log.w(TAG, "Codec did not publish any measurement data.");
1977                 return null;
1978             }
1979 
1980             return estimateFrameRatesFor(width, height);
1981         }
1982 
1983         /**
1984          * Video performance points are a set of standard performance points defined by number of
1985          * pixels, pixel rate and frame rate. Performance point represents an upper bound. This
1986          * means that it covers all performance points with fewer pixels, pixel rate and frame
1987          * rate.
1988          */
1989         public static final class PerformancePoint {
1990             private Size mBlockSize; // codec block size in macroblocks
1991             private int mWidth; // width in macroblocks
1992             private int mHeight; // height in macroblocks
1993             private int mMaxFrameRate; // max frames per second
1994             private long mMaxMacroBlockRate; // max macro block rate
1995 
1996             /**
1997              * Maximum number of macroblocks in the frame.
1998              *
1999              * Video frames are conceptually divided into 16-by-16 pixel blocks called macroblocks.
2000              * Most coding standards operate on these 16-by-16 pixel blocks; thus, codec performance
2001              * is characterized using such blocks.
2002              *
2003              * @hide
2004              */
2005             @TestApi
getMaxMacroBlocks()2006             public int getMaxMacroBlocks() {
2007                 return saturateLongToInt(mWidth * (long)mHeight);
2008             }
2009 
2010             /**
2011              * Maximum frame rate in frames per second.
2012              *
2013              * @hide
2014              */
2015             @TestApi
getMaxFrameRate()2016             public int getMaxFrameRate() {
2017                 return mMaxFrameRate;
2018             }
2019 
2020             /**
2021              * Maximum number of macroblocks processed per second.
2022              *
2023              * @hide
2024              */
2025             @TestApi
getMaxMacroBlockRate()2026             public long getMaxMacroBlockRate() {
2027                 return mMaxMacroBlockRate;
2028             }
2029 
2030             /** Convert to a debug string */
toString()2031             public String toString() {
2032                 int blockWidth = 16 * mBlockSize.getWidth();
2033                 int blockHeight = 16 * mBlockSize.getHeight();
2034                 int origRate = (int)Utils.divUp(mMaxMacroBlockRate, getMaxMacroBlocks());
2035                 String info = (mWidth * 16) + "x" + (mHeight * 16) + "@" + origRate;
2036                 if (origRate < mMaxFrameRate) {
2037                     info += ", max " + mMaxFrameRate + "fps";
2038                 }
2039                 if (blockWidth > 16 || blockHeight > 16) {
2040                     info += ", " + blockWidth + "x" + blockHeight + " blocks";
2041                 }
2042                 return "PerformancePoint(" + info + ")";
2043             }
2044 
2045             @Override
hashCode()2046             public int hashCode() {
2047                 // only max frame rate must equal between performance points that equal to one
2048                 // another
2049                 return mMaxFrameRate;
2050             }
2051 
2052             /**
2053              * Create a detailed performance point with custom max frame rate and macroblock size.
2054              *
2055              * @param width  frame width in pixels
2056              * @param height frame height in pixels
2057              * @param frameRate frames per second for frame width and height
2058              * @param maxFrameRate maximum frames per second for any frame size
2059              * @param blockSize block size for codec implementation. Must be powers of two in both
2060              *        width and height.
2061              *
2062              * @throws IllegalArgumentException if the blockSize dimensions are not powers of two.
2063              *
2064              * @hide
2065              */
2066             @TestApi
PerformancePoint( int width, int height, int frameRate, int maxFrameRate, @NonNull Size blockSize)2067             public PerformancePoint(
2068                     int width, int height, int frameRate, int maxFrameRate,
2069                     @NonNull Size blockSize) {
2070                 checkPowerOfTwo(blockSize.getWidth(), "block width");
2071                 checkPowerOfTwo(blockSize.getHeight(), "block height");
2072 
2073                 mBlockSize = new Size(Utils.divUp(blockSize.getWidth(), 16),
2074                                       Utils.divUp(blockSize.getHeight(), 16));
2075                 // these are guaranteed not to overflow as we decimate by 16
2076                 mWidth = (int)(Utils.divUp(Math.max(1L, width),
2077                                            Math.max(blockSize.getWidth(), 16))
2078                                * mBlockSize.getWidth());
2079                 mHeight = (int)(Utils.divUp(Math.max(1L, height),
2080                                             Math.max(blockSize.getHeight(), 16))
2081                                 * mBlockSize.getHeight());
2082                 mMaxFrameRate = Math.max(1, Math.max(frameRate, maxFrameRate));
2083                 mMaxMacroBlockRate = Math.max(1, frameRate) * getMaxMacroBlocks();
2084             }
2085 
2086             /**
2087              * Convert a performance point to a larger blocksize.
2088              *
2089              * @param pp performance point
2090              * @param blockSize block size for codec implementation
2091              *
2092              * @hide
2093              */
2094             @TestApi
PerformancePoint(@onNull PerformancePoint pp, @NonNull Size newBlockSize)2095             public PerformancePoint(@NonNull PerformancePoint pp, @NonNull Size newBlockSize) {
2096                 this(
2097                         pp.mWidth * 16, pp.mHeight * 16,
2098                         // guaranteed not to overflow as these were multiplied at construction
2099                         (int)Utils.divUp(pp.mMaxMacroBlockRate, pp.getMaxMacroBlocks()),
2100                         pp.mMaxFrameRate,
2101                         new Size(Math.max(newBlockSize.getWidth(), pp.mBlockSize.getWidth() * 16),
2102                                  Math.max(newBlockSize.getHeight(), pp.mBlockSize.getHeight() * 16))
2103                 );
2104             }
2105 
2106             /**
2107              * Create a performance point for a given frame size and frame rate.
2108              *
2109              * @param width width of the frame in pixels
2110              * @param height height of the frame in pixels
2111              * @param frameRate frame rate in frames per second
2112              */
PerformancePoint(int width, int height, int frameRate)2113             public PerformancePoint(int width, int height, int frameRate) {
2114                 this(width, height, frameRate, frameRate /* maxFrameRate */, new Size(16, 16));
2115             }
2116 
2117             /** Saturates a long value to int */
saturateLongToInt(long value)2118             private int saturateLongToInt(long value) {
2119                 if (value < Integer.MIN_VALUE) {
2120                     return Integer.MIN_VALUE;
2121                 } else if (value > Integer.MAX_VALUE) {
2122                     return Integer.MAX_VALUE;
2123                 } else {
2124                     return (int)value;
2125                 }
2126             }
2127 
2128             /* This method may overflow */
align(int value, int alignment)2129             private int align(int value, int alignment) {
2130                 return Utils.divUp(value, alignment) * alignment;
2131             }
2132 
2133             /** Checks that value is a power of two. */
checkPowerOfTwo2(int value, @NonNull String description)2134             private void checkPowerOfTwo2(int value, @NonNull String description) {
2135                 if (value == 0 || (value & (value - 1)) != 0) {
2136                     throw new IllegalArgumentException(
2137                             description + " (" + value + ") must be a power of 2");
2138                 }
2139             }
2140 
2141             /**
2142              * Checks whether the performance point covers a media format.
2143              *
2144              * @param format Stream format considered
2145              *
2146              * @return {@code true} if the performance point covers the format.
2147              */
covers(@onNull MediaFormat format)2148             public boolean covers(@NonNull MediaFormat format) {
2149                 PerformancePoint other = new PerformancePoint(
2150                         format.getInteger(MediaFormat.KEY_WIDTH, 0),
2151                         format.getInteger(MediaFormat.KEY_HEIGHT, 0),
2152                         // safely convert ceil(double) to int through float cast and Math.round
2153                         Math.round((float)(
2154                                 Math.ceil(format.getNumber(MediaFormat.KEY_FRAME_RATE, 0)
2155                                         .doubleValue()))));
2156                 return covers(other);
2157             }
2158 
2159             /**
2160              * Checks whether the performance point covers another performance point. Use this
2161              * method to determine if a performance point advertised by a codec covers the
2162              * performance point required. This method can also be used for loose ordering as this
2163              * method is transitive.
2164              *
2165              * @param other other performance point considered
2166              *
2167              * @return {@code true} if the performance point covers the other.
2168              */
covers(@onNull PerformancePoint other)2169             public boolean covers(@NonNull PerformancePoint other) {
2170                 // convert performance points to common block size
2171                 Size commonSize = getCommonBlockSize(other);
2172                 PerformancePoint aligned = new PerformancePoint(this, commonSize);
2173                 PerformancePoint otherAligned = new PerformancePoint(other, commonSize);
2174 
2175                 return (aligned.getMaxMacroBlocks() >= otherAligned.getMaxMacroBlocks()
2176                         && aligned.mMaxFrameRate >= otherAligned.mMaxFrameRate
2177                         && aligned.mMaxMacroBlockRate >= otherAligned.mMaxMacroBlockRate);
2178             }
2179 
getCommonBlockSize(@onNull PerformancePoint other)2180             private @NonNull Size getCommonBlockSize(@NonNull PerformancePoint other) {
2181                 return new Size(
2182                         Math.max(mBlockSize.getWidth(), other.mBlockSize.getWidth()) * 16,
2183                         Math.max(mBlockSize.getHeight(), other.mBlockSize.getHeight()) * 16);
2184             }
2185 
2186             @Override
equals(Object o)2187             public boolean equals(Object o) {
2188                 if (o instanceof PerformancePoint) {
2189                     // convert performance points to common block size
2190                     PerformancePoint other = (PerformancePoint)o;
2191                     Size commonSize = getCommonBlockSize(other);
2192                     PerformancePoint aligned = new PerformancePoint(this, commonSize);
2193                     PerformancePoint otherAligned = new PerformancePoint(other, commonSize);
2194 
2195                     return (aligned.getMaxMacroBlocks() == otherAligned.getMaxMacroBlocks()
2196                             && aligned.mMaxFrameRate == otherAligned.mMaxFrameRate
2197                             && aligned.mMaxMacroBlockRate == otherAligned.mMaxMacroBlockRate);
2198                 }
2199                 return false;
2200             }
2201 
2202             /** 480p 24fps */
2203             @NonNull
2204             public static final PerformancePoint SD_24 = new PerformancePoint(720, 480, 24);
2205             /** 576p 25fps */
2206             @NonNull
2207             public static final PerformancePoint SD_25 = new PerformancePoint(720, 576, 25);
2208             /** 480p 30fps */
2209             @NonNull
2210             public static final PerformancePoint SD_30 = new PerformancePoint(720, 480, 30);
2211             /** 480p 48fps */
2212             @NonNull
2213             public static final PerformancePoint SD_48 = new PerformancePoint(720, 480, 48);
2214             /** 576p 50fps */
2215             @NonNull
2216             public static final PerformancePoint SD_50 = new PerformancePoint(720, 576, 50);
2217             /** 480p 60fps */
2218             @NonNull
2219             public static final PerformancePoint SD_60 = new PerformancePoint(720, 480, 60);
2220 
2221             /** 720p 24fps */
2222             @NonNull
2223             public static final PerformancePoint HD_24 = new PerformancePoint(1280, 720, 24);
2224             /** 720p 25fps */
2225             @NonNull
2226             public static final PerformancePoint HD_25 = new PerformancePoint(1280, 720, 25);
2227             /** 720p 30fps */
2228             @NonNull
2229             public static final PerformancePoint HD_30 = new PerformancePoint(1280, 720, 30);
2230             /** 720p 50fps */
2231             @NonNull
2232             public static final PerformancePoint HD_50 = new PerformancePoint(1280, 720, 50);
2233             /** 720p 60fps */
2234             @NonNull
2235             public static final PerformancePoint HD_60 = new PerformancePoint(1280, 720, 60);
2236             /** 720p 100fps */
2237             @NonNull
2238             public static final PerformancePoint HD_100 = new PerformancePoint(1280, 720, 100);
2239             /** 720p 120fps */
2240             @NonNull
2241             public static final PerformancePoint HD_120 = new PerformancePoint(1280, 720, 120);
2242             /** 720p 200fps */
2243             @NonNull
2244             public static final PerformancePoint HD_200 = new PerformancePoint(1280, 720, 200);
2245             /** 720p 240fps */
2246             @NonNull
2247             public static final PerformancePoint HD_240 = new PerformancePoint(1280, 720, 240);
2248 
2249             /** 1080p 24fps */
2250             @NonNull
2251             public static final PerformancePoint FHD_24 = new PerformancePoint(1920, 1080, 24);
2252             /** 1080p 25fps */
2253             @NonNull
2254             public static final PerformancePoint FHD_25 = new PerformancePoint(1920, 1080, 25);
2255             /** 1080p 30fps */
2256             @NonNull
2257             public static final PerformancePoint FHD_30 = new PerformancePoint(1920, 1080, 30);
2258             /** 1080p 50fps */
2259             @NonNull
2260             public static final PerformancePoint FHD_50 = new PerformancePoint(1920, 1080, 50);
2261             /** 1080p 60fps */
2262             @NonNull
2263             public static final PerformancePoint FHD_60 = new PerformancePoint(1920, 1080, 60);
2264             /** 1080p 100fps */
2265             @NonNull
2266             public static final PerformancePoint FHD_100 = new PerformancePoint(1920, 1080, 100);
2267             /** 1080p 120fps */
2268             @NonNull
2269             public static final PerformancePoint FHD_120 = new PerformancePoint(1920, 1080, 120);
2270             /** 1080p 200fps */
2271             @NonNull
2272             public static final PerformancePoint FHD_200 = new PerformancePoint(1920, 1080, 200);
2273             /** 1080p 240fps */
2274             @NonNull
2275             public static final PerformancePoint FHD_240 = new PerformancePoint(1920, 1080, 240);
2276 
2277             /** 2160p 24fps */
2278             @NonNull
2279             public static final PerformancePoint UHD_24 = new PerformancePoint(3840, 2160, 24);
2280             /** 2160p 25fps */
2281             @NonNull
2282             public static final PerformancePoint UHD_25 = new PerformancePoint(3840, 2160, 25);
2283             /** 2160p 30fps */
2284             @NonNull
2285             public static final PerformancePoint UHD_30 = new PerformancePoint(3840, 2160, 30);
2286             /** 2160p 50fps */
2287             @NonNull
2288             public static final PerformancePoint UHD_50 = new PerformancePoint(3840, 2160, 50);
2289             /** 2160p 60fps */
2290             @NonNull
2291             public static final PerformancePoint UHD_60 = new PerformancePoint(3840, 2160, 60);
2292             /** 2160p 100fps */
2293             @NonNull
2294             public static final PerformancePoint UHD_100 = new PerformancePoint(3840, 2160, 100);
2295             /** 2160p 120fps */
2296             @NonNull
2297             public static final PerformancePoint UHD_120 = new PerformancePoint(3840, 2160, 120);
2298             /** 2160p 200fps */
2299             @NonNull
2300             public static final PerformancePoint UHD_200 = new PerformancePoint(3840, 2160, 200);
2301             /** 2160p 240fps */
2302             @NonNull
2303             public static final PerformancePoint UHD_240 = new PerformancePoint(3840, 2160, 240);
2304         }
2305 
2306         /**
2307          * Returns the supported performance points. May return {@code null} if the codec did not
2308          * publish any performance point information (e.g. the vendor codecs have not been updated
2309          * to the latest android release). May return an empty list if the codec published that
2310          * if does not guarantee any performance points.
2311          * <p>
2312          * This is a performance guarantee provided by the device manufacturer for hardware codecs
2313          * based on hardware capabilities of the device.
2314          * <p>
2315          * The returned list is sorted first by decreasing number of pixels, then by decreasing
2316          * width, and finally by decreasing frame rate.
2317          * Performance points assume a single active codec. For use cases where multiple
2318          * codecs are active, should use that highest pixel count, and add the frame rates of
2319          * each individual codec.
2320          * <p class=note>
2321          * 32-bit processes will not support resolutions larger than 4096x4096 due to
2322          * the limited address space, but performance points will be presented as is.
2323          * In other words, even though a component publishes a performance point for
2324          * a resolution higher than 4096x4096, it does not mean that the resolution is supported
2325          * for 32-bit processes.
2326          */
2327         @Nullable
getSupportedPerformancePoints()2328         public List<PerformancePoint> getSupportedPerformancePoints() {
2329             return mPerformancePoints;
2330         }
2331 
2332         /**
2333          * Returns whether a given video size ({@code width} and
2334          * {@code height}) and {@code frameRate} combination is supported.
2335          */
areSizeAndRateSupported( int width, int height, double frameRate)2336         public boolean areSizeAndRateSupported(
2337                 int width, int height, double frameRate) {
2338             return supports(width, height, frameRate);
2339         }
2340 
2341         /**
2342          * Returns whether a given video size ({@code width} and
2343          * {@code height}) is supported.
2344          */
isSizeSupported(int width, int height)2345         public boolean isSizeSupported(int width, int height) {
2346             return supports(width, height, null);
2347         }
2348 
supports(Integer width, Integer height, Number rate)2349         private boolean supports(Integer width, Integer height, Number rate) {
2350             boolean ok = true;
2351 
2352             if (ok && width != null) {
2353                 ok = mWidthRange.contains(width)
2354                         && (width % mWidthAlignment == 0);
2355             }
2356             if (ok && height != null) {
2357                 ok = mHeightRange.contains(height)
2358                         && (height % mHeightAlignment == 0);
2359             }
2360             if (ok && rate != null) {
2361                 ok = mFrameRateRange.contains(Utils.intRangeFor(rate.doubleValue()));
2362             }
2363             if (ok && height != null && width != null) {
2364                 ok = Math.min(height, width) <= mSmallerDimensionUpperLimit;
2365 
2366                 final int widthInBlocks = Utils.divUp(width, mBlockWidth);
2367                 final int heightInBlocks = Utils.divUp(height, mBlockHeight);
2368                 final int blockCount = widthInBlocks * heightInBlocks;
2369                 ok = ok && mBlockCountRange.contains(blockCount)
2370                         && mBlockAspectRatioRange.contains(
2371                                 new Rational(widthInBlocks, heightInBlocks))
2372                         && mAspectRatioRange.contains(new Rational(width, height));
2373                 if (ok && rate != null) {
2374                     double blocksPerSec = blockCount * rate.doubleValue();
2375                     ok = mBlocksPerSecondRange.contains(
2376                             Utils.longRangeFor(blocksPerSec));
2377                 }
2378             }
2379             return ok;
2380         }
2381 
2382         /* package private */
2383         // must not contain KEY_PROFILE
2384         static final Set<String> VIDEO_LEVEL_CRITICAL_FORMAT_KEYS = Set.of(
2385                 MediaFormat.KEY_WIDTH,
2386                 MediaFormat.KEY_HEIGHT,
2387                 MediaFormat.KEY_FRAME_RATE,
2388                 MediaFormat.KEY_BIT_RATE,
2389                 MediaFormat.KEY_MIME);
2390 
2391         /**
2392          * @hide
2393          * @throws java.lang.ClassCastException */
supportsFormat(MediaFormat format)2394         public boolean supportsFormat(MediaFormat format) {
2395             final Map<String, Object> map = format.getMap();
2396             Integer width = (Integer)map.get(MediaFormat.KEY_WIDTH);
2397             Integer height = (Integer)map.get(MediaFormat.KEY_HEIGHT);
2398             Number rate = (Number)map.get(MediaFormat.KEY_FRAME_RATE);
2399 
2400             if (!supports(width, height, rate)) {
2401                 return false;
2402             }
2403 
2404             if (!CodecCapabilities.supportsBitrate(mBitrateRange, format)) {
2405                 return false;
2406             }
2407 
2408             // we ignore color-format for now as it is not reliably reported by codec
2409             return true;
2410         }
2411 
2412         /* no public constructor */
VideoCapabilities()2413         private VideoCapabilities() { }
2414 
2415         /** @hide */
2416         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
create( MediaFormat info, CodecCapabilities parent)2417         public static VideoCapabilities create(
2418                 MediaFormat info, CodecCapabilities parent) {
2419             VideoCapabilities caps = new VideoCapabilities();
2420             caps.init(info, parent);
2421             return caps;
2422         }
2423 
init(MediaFormat info, CodecCapabilities parent)2424         private void init(MediaFormat info, CodecCapabilities parent) {
2425             mParent = parent;
2426             initWithPlatformLimits();
2427             applyLevelLimits();
2428             parseFromInfo(info);
2429             updateLimits();
2430         }
2431 
2432         /** @hide */
getBlockSize()2433         public Size getBlockSize() {
2434             return new Size(mBlockWidth, mBlockHeight);
2435         }
2436 
2437         /** @hide */
getBlockCountRange()2438         public Range<Integer> getBlockCountRange() {
2439             return mBlockCountRange;
2440         }
2441 
2442         /** @hide */
getBlocksPerSecondRange()2443         public Range<Long> getBlocksPerSecondRange() {
2444             return mBlocksPerSecondRange;
2445         }
2446 
2447         /** @hide */
getAspectRatioRange(boolean blocks)2448         public Range<Rational> getAspectRatioRange(boolean blocks) {
2449             return blocks ? mBlockAspectRatioRange : mAspectRatioRange;
2450         }
2451 
initWithPlatformLimits()2452         private void initWithPlatformLimits() {
2453             mBitrateRange = BITRATE_RANGE;
2454 
2455             mWidthRange  = getSizeRange();
2456             mHeightRange = getSizeRange();
2457             mFrameRateRange = FRAME_RATE_RANGE;
2458 
2459             mHorizontalBlockRange = getSizeRange();
2460             mVerticalBlockRange   = getSizeRange();
2461 
2462             // full positive ranges are supported as these get calculated
2463             mBlockCountRange      = POSITIVE_INTEGERS;
2464             mBlocksPerSecondRange = POSITIVE_LONGS;
2465 
2466             mBlockAspectRatioRange = POSITIVE_RATIONALS;
2467             mAspectRatioRange      = POSITIVE_RATIONALS;
2468 
2469             // YUV 4:2:0 requires 2:2 alignment
2470             mWidthAlignment = 2;
2471             mHeightAlignment = 2;
2472             mBlockWidth = 2;
2473             mBlockHeight = 2;
2474             mSmallerDimensionUpperLimit = getSizeRange().getUpper();
2475         }
2476 
getPerformancePoints(Map<String, Object> map)2477         private @Nullable List<PerformancePoint> getPerformancePoints(Map<String, Object> map) {
2478             Vector<PerformancePoint> ret = new Vector<>();
2479             final String prefix = "performance-point-";
2480             Set<String> keys = map.keySet();
2481             for (String key : keys) {
2482                 // looking for: performance-point-WIDTHxHEIGHT-range
2483                 if (!key.startsWith(prefix)) {
2484                     continue;
2485                 }
2486                 String subKey = key.substring(prefix.length());
2487                 if (subKey.equals("none") && ret.size() == 0) {
2488                     // This means that component knowingly did not publish performance points.
2489                     // This is different from when the component forgot to publish performance
2490                     // points.
2491                     return Collections.unmodifiableList(ret);
2492                 }
2493                 String[] temp = key.split("-");
2494                 if (temp.length != 4) {
2495                     continue;
2496                 }
2497                 String sizeStr = temp[2];
2498                 Size size = Utils.parseSize(sizeStr, null);
2499                 if (size == null || size.getWidth() * size.getHeight() <= 0) {
2500                     continue;
2501                 }
2502                 Range<Long> range = Utils.parseLongRange(map.get(key), null);
2503                 if (range == null || range.getLower() < 0 || range.getUpper() < 0) {
2504                     continue;
2505                 }
2506                 PerformancePoint given = new PerformancePoint(
2507                         size.getWidth(), size.getHeight(), range.getLower().intValue(),
2508                         range.getUpper().intValue(), new Size(mBlockWidth, mBlockHeight));
2509                 PerformancePoint rotated = new PerformancePoint(
2510                         size.getHeight(), size.getWidth(), range.getLower().intValue(),
2511                         range.getUpper().intValue(), new Size(mBlockWidth, mBlockHeight));
2512                 ret.add(given);
2513                 if (!given.covers(rotated)) {
2514                     ret.add(rotated);
2515                 }
2516             }
2517 
2518             // check if the component specified no performance point indication
2519             if (ret.size() == 0) {
2520                 return null;
2521             }
2522 
2523             // sort reversed by area first, then by frame rate
2524             ret.sort((a, b) ->
2525                      -((a.getMaxMacroBlocks() != b.getMaxMacroBlocks()) ?
2526                                (a.getMaxMacroBlocks() < b.getMaxMacroBlocks() ? -1 : 1) :
2527                        (a.getMaxMacroBlockRate() != b.getMaxMacroBlockRate()) ?
2528                                (a.getMaxMacroBlockRate() < b.getMaxMacroBlockRate() ? -1 : 1) :
2529                        (a.getMaxFrameRate() != b.getMaxFrameRate()) ?
2530                                (a.getMaxFrameRate() < b.getMaxFrameRate() ? -1 : 1) : 0));
2531 
2532             return Collections.unmodifiableList(ret);
2533         }
2534 
getMeasuredFrameRates(Map<String, Object> map)2535         private Map<Size, Range<Long>> getMeasuredFrameRates(Map<String, Object> map) {
2536             Map<Size, Range<Long>> ret = new HashMap<Size, Range<Long>>();
2537             final String prefix = "measured-frame-rate-";
2538             Set<String> keys = map.keySet();
2539             for (String key : keys) {
2540                 // looking for: measured-frame-rate-WIDTHxHEIGHT-range
2541                 if (!key.startsWith(prefix)) {
2542                     continue;
2543                 }
2544                 String subKey = key.substring(prefix.length());
2545                 String[] temp = key.split("-");
2546                 if (temp.length != 5) {
2547                     continue;
2548                 }
2549                 String sizeStr = temp[3];
2550                 Size size = Utils.parseSize(sizeStr, null);
2551                 if (size == null || size.getWidth() * size.getHeight() <= 0) {
2552                     continue;
2553                 }
2554                 Range<Long> range = Utils.parseLongRange(map.get(key), null);
2555                 if (range == null || range.getLower() < 0 || range.getUpper() < 0) {
2556                     continue;
2557                 }
2558                 ret.put(size, range);
2559             }
2560             return ret;
2561         }
2562 
parseWidthHeightRanges(Object o)2563         private static Pair<Range<Integer>, Range<Integer>> parseWidthHeightRanges(Object o) {
2564             Pair<Size, Size> range = Utils.parseSizeRange(o);
2565             if (range != null) {
2566                 try {
2567                     return Pair.create(
2568                             Range.create(range.first.getWidth(), range.second.getWidth()),
2569                             Range.create(range.first.getHeight(), range.second.getHeight()));
2570                 } catch (IllegalArgumentException e) {
2571                     Log.w(TAG, "could not parse size range '" + o + "'");
2572                 }
2573             }
2574             return null;
2575         }
2576 
2577         /** @hide */
equivalentVP9Level(MediaFormat info)2578         public static int equivalentVP9Level(MediaFormat info) {
2579             final Map<String, Object> map = info.getMap();
2580 
2581             Size blockSize = Utils.parseSize(map.get("block-size"), new Size(8, 8));
2582             int BS = blockSize.getWidth() * blockSize.getHeight();
2583 
2584             Range<Integer> counts = Utils.parseIntRange(map.get("block-count-range"), null);
2585             int FS = counts == null ? 0 : BS * counts.getUpper();
2586 
2587             Range<Long> blockRates =
2588                 Utils.parseLongRange(map.get("blocks-per-second-range"), null);
2589             long SR = blockRates == null ? 0 : BS * blockRates.getUpper();
2590 
2591             Pair<Range<Integer>, Range<Integer>> dimensionRanges =
2592                 parseWidthHeightRanges(map.get("size-range"));
2593             int D = dimensionRanges == null ? 0 : Math.max(
2594                     dimensionRanges.first.getUpper(), dimensionRanges.second.getUpper());
2595 
2596             Range<Integer> bitRates = Utils.parseIntRange(map.get("bitrate-range"), null);
2597             int BR = bitRates == null ? 0 : Utils.divUp(bitRates.getUpper(), 1000);
2598 
2599             if (SR <=      829440 && FS <=    36864 && BR <=    200 && D <=   512)
2600                 return CodecProfileLevel.VP9Level1;
2601             if (SR <=     2764800 && FS <=    73728 && BR <=    800 && D <=   768)
2602                 return CodecProfileLevel.VP9Level11;
2603             if (SR <=     4608000 && FS <=   122880 && BR <=   1800 && D <=   960)
2604                 return CodecProfileLevel.VP9Level2;
2605             if (SR <=     9216000 && FS <=   245760 && BR <=   3600 && D <=  1344)
2606                 return CodecProfileLevel.VP9Level21;
2607             if (SR <=    20736000 && FS <=   552960 && BR <=   7200 && D <=  2048)
2608                 return CodecProfileLevel.VP9Level3;
2609             if (SR <=    36864000 && FS <=   983040 && BR <=  12000 && D <=  2752)
2610                 return CodecProfileLevel.VP9Level31;
2611             if (SR <=    83558400 && FS <=  2228224 && BR <=  18000 && D <=  4160)
2612                 return CodecProfileLevel.VP9Level4;
2613             if (SR <=   160432128 && FS <=  2228224 && BR <=  30000 && D <=  4160)
2614                 return CodecProfileLevel.VP9Level41;
2615             if (SR <=   311951360 && FS <=  8912896 && BR <=  60000 && D <=  8384)
2616                 return CodecProfileLevel.VP9Level5;
2617             if (SR <=   588251136 && FS <=  8912896 && BR <= 120000 && D <=  8384)
2618                 return CodecProfileLevel.VP9Level51;
2619             if (SR <=  1176502272 && FS <=  8912896 && BR <= 180000 && D <=  8384)
2620                 return CodecProfileLevel.VP9Level52;
2621             if (SR <=  1176502272 && FS <= 35651584 && BR <= 180000 && D <= 16832)
2622                 return CodecProfileLevel.VP9Level6;
2623             if (SR <= 2353004544L && FS <= 35651584 && BR <= 240000 && D <= 16832)
2624                 return CodecProfileLevel.VP9Level61;
2625             if (SR <= 4706009088L && FS <= 35651584 && BR <= 480000 && D <= 16832)
2626                 return CodecProfileLevel.VP9Level62;
2627             // returning largest level
2628             return CodecProfileLevel.VP9Level62;
2629         }
2630 
parseFromInfo(MediaFormat info)2631         private void parseFromInfo(MediaFormat info) {
2632             final Map<String, Object> map = info.getMap();
2633             Size blockSize = new Size(mBlockWidth, mBlockHeight);
2634             Size alignment = new Size(mWidthAlignment, mHeightAlignment);
2635             Range<Integer> counts = null, widths = null, heights = null;
2636             Range<Integer> frameRates = null, bitRates = null;
2637             Range<Long> blockRates = null;
2638             Range<Rational> ratios = null, blockRatios = null;
2639 
2640             blockSize = Utils.parseSize(map.get("block-size"), blockSize);
2641             alignment = Utils.parseSize(map.get("alignment"), alignment);
2642             counts = Utils.parseIntRange(map.get("block-count-range"), null);
2643             blockRates =
2644                 Utils.parseLongRange(map.get("blocks-per-second-range"), null);
2645             mMeasuredFrameRates = getMeasuredFrameRates(map);
2646             mPerformancePoints = getPerformancePoints(map);
2647             Pair<Range<Integer>, Range<Integer>> sizeRanges =
2648                 parseWidthHeightRanges(map.get("size-range"));
2649             if (sizeRanges != null) {
2650                 widths = sizeRanges.first;
2651                 heights = sizeRanges.second;
2652             }
2653             // for now this just means using the smaller max size as 2nd
2654             // upper limit.
2655             // for now we are keeping the profile specific "width/height
2656             // in macroblocks" limits.
2657             if (map.containsKey("feature-can-swap-width-height")) {
2658                 if (widths != null) {
2659                     mSmallerDimensionUpperLimit =
2660                         Math.min(widths.getUpper(), heights.getUpper());
2661                     widths = heights = widths.extend(heights);
2662                 } else {
2663                     Log.w(TAG, "feature can-swap-width-height is best used with size-range");
2664                     mSmallerDimensionUpperLimit =
2665                         Math.min(mWidthRange.getUpper(), mHeightRange.getUpper());
2666                     mWidthRange = mHeightRange = mWidthRange.extend(mHeightRange);
2667                 }
2668             }
2669 
2670             ratios = Utils.parseRationalRange(
2671                     map.get("block-aspect-ratio-range"), null);
2672             blockRatios = Utils.parseRationalRange(
2673                     map.get("pixel-aspect-ratio-range"), null);
2674             frameRates = Utils.parseIntRange(map.get("frame-rate-range"), null);
2675             if (frameRates != null) {
2676                 try {
2677                     frameRates = frameRates.intersect(FRAME_RATE_RANGE);
2678                 } catch (IllegalArgumentException e) {
2679                     Log.w(TAG, "frame rate range (" + frameRates
2680                             + ") is out of limits: " + FRAME_RATE_RANGE);
2681                     frameRates = null;
2682                 }
2683             }
2684             bitRates = Utils.parseIntRange(map.get("bitrate-range"), null);
2685             if (bitRates != null) {
2686                 try {
2687                     bitRates = bitRates.intersect(BITRATE_RANGE);
2688                 } catch (IllegalArgumentException e) {
2689                     Log.w(TAG,  "bitrate range (" + bitRates
2690                             + ") is out of limits: " + BITRATE_RANGE);
2691                     bitRates = null;
2692                 }
2693             }
2694 
2695             checkPowerOfTwo(
2696                     blockSize.getWidth(), "block-size width must be power of two");
2697             checkPowerOfTwo(
2698                     blockSize.getHeight(), "block-size height must be power of two");
2699 
2700             checkPowerOfTwo(
2701                     alignment.getWidth(), "alignment width must be power of two");
2702             checkPowerOfTwo(
2703                     alignment.getHeight(), "alignment height must be power of two");
2704 
2705             // update block-size and alignment
2706             applyMacroBlockLimits(
2707                     Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE,
2708                     Long.MAX_VALUE, blockSize.getWidth(), blockSize.getHeight(),
2709                     alignment.getWidth(), alignment.getHeight());
2710 
2711             if ((mParent.mError & ERROR_UNSUPPORTED) != 0 || mAllowMbOverride) {
2712                 // codec supports profiles that we don't know.
2713                 // Use supplied values clipped to platform limits
2714                 if (widths != null) {
2715                     mWidthRange = getSizeRange().intersect(widths);
2716                 }
2717                 if (heights != null) {
2718                     mHeightRange = getSizeRange().intersect(heights);
2719                 }
2720                 if (counts != null) {
2721                     mBlockCountRange = POSITIVE_INTEGERS.intersect(
2722                             Utils.factorRange(counts, mBlockWidth * mBlockHeight
2723                                     / blockSize.getWidth() / blockSize.getHeight()));
2724                 }
2725                 if (blockRates != null) {
2726                     mBlocksPerSecondRange = POSITIVE_LONGS.intersect(
2727                             Utils.factorRange(blockRates, mBlockWidth * mBlockHeight
2728                                     / blockSize.getWidth() / blockSize.getHeight()));
2729                 }
2730                 if (blockRatios != null) {
2731                     mBlockAspectRatioRange = POSITIVE_RATIONALS.intersect(
2732                             Utils.scaleRange(blockRatios,
2733                                     mBlockHeight / blockSize.getHeight(),
2734                                     mBlockWidth / blockSize.getWidth()));
2735                 }
2736                 if (ratios != null) {
2737                     mAspectRatioRange = POSITIVE_RATIONALS.intersect(ratios);
2738                 }
2739                 if (frameRates != null) {
2740                     mFrameRateRange = FRAME_RATE_RANGE.intersect(frameRates);
2741                 }
2742                 if (bitRates != null) {
2743                     // only allow bitrate override if unsupported profiles were encountered
2744                     if ((mParent.mError & ERROR_UNSUPPORTED) != 0) {
2745                         mBitrateRange = BITRATE_RANGE.intersect(bitRates);
2746                     } else {
2747                         mBitrateRange = mBitrateRange.intersect(bitRates);
2748                     }
2749                 }
2750             } else {
2751                 // no unsupported profile/levels, so restrict values to known limits
2752                 if (widths != null) {
2753                     mWidthRange = mWidthRange.intersect(widths);
2754                 }
2755                 if (heights != null) {
2756                     mHeightRange = mHeightRange.intersect(heights);
2757                 }
2758                 if (counts != null) {
2759                     mBlockCountRange = mBlockCountRange.intersect(
2760                             Utils.factorRange(counts, mBlockWidth * mBlockHeight
2761                                     / blockSize.getWidth() / blockSize.getHeight()));
2762                 }
2763                 if (blockRates != null) {
2764                     mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(
2765                             Utils.factorRange(blockRates, mBlockWidth * mBlockHeight
2766                                     / blockSize.getWidth() / blockSize.getHeight()));
2767                 }
2768                 if (blockRatios != null) {
2769                     mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(
2770                             Utils.scaleRange(blockRatios,
2771                                     mBlockHeight / blockSize.getHeight(),
2772                                     mBlockWidth / blockSize.getWidth()));
2773                 }
2774                 if (ratios != null) {
2775                     mAspectRatioRange = mAspectRatioRange.intersect(ratios);
2776                 }
2777                 if (frameRates != null) {
2778                     mFrameRateRange = mFrameRateRange.intersect(frameRates);
2779                 }
2780                 if (bitRates != null) {
2781                     mBitrateRange = mBitrateRange.intersect(bitRates);
2782                 }
2783             }
2784             updateLimits();
2785         }
2786 
applyBlockLimits( int blockWidth, int blockHeight, Range<Integer> counts, Range<Long> rates, Range<Rational> ratios)2787         private void applyBlockLimits(
2788                 int blockWidth, int blockHeight,
2789                 Range<Integer> counts, Range<Long> rates, Range<Rational> ratios) {
2790             checkPowerOfTwo(blockWidth, "blockWidth must be a power of two");
2791             checkPowerOfTwo(blockHeight, "blockHeight must be a power of two");
2792 
2793             final int newBlockWidth = Math.max(blockWidth, mBlockWidth);
2794             final int newBlockHeight = Math.max(blockHeight, mBlockHeight);
2795 
2796             // factor will always be a power-of-2
2797             int factor =
2798                 newBlockWidth * newBlockHeight / mBlockWidth / mBlockHeight;
2799             if (factor != 1) {
2800                 mBlockCountRange = Utils.factorRange(mBlockCountRange, factor);
2801                 mBlocksPerSecondRange = Utils.factorRange(
2802                         mBlocksPerSecondRange, factor);
2803                 mBlockAspectRatioRange = Utils.scaleRange(
2804                         mBlockAspectRatioRange,
2805                         newBlockHeight / mBlockHeight,
2806                         newBlockWidth / mBlockWidth);
2807                 mHorizontalBlockRange = Utils.factorRange(
2808                         mHorizontalBlockRange, newBlockWidth / mBlockWidth);
2809                 mVerticalBlockRange = Utils.factorRange(
2810                         mVerticalBlockRange, newBlockHeight / mBlockHeight);
2811             }
2812             factor = newBlockWidth * newBlockHeight / blockWidth / blockHeight;
2813             if (factor != 1) {
2814                 counts = Utils.factorRange(counts, factor);
2815                 rates = Utils.factorRange(rates, factor);
2816                 ratios = Utils.scaleRange(
2817                         ratios, newBlockHeight / blockHeight,
2818                         newBlockWidth / blockWidth);
2819             }
2820             mBlockCountRange = mBlockCountRange.intersect(counts);
2821             mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(rates);
2822             mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(ratios);
2823             mBlockWidth = newBlockWidth;
2824             mBlockHeight = newBlockHeight;
2825         }
2826 
applyAlignment(int widthAlignment, int heightAlignment)2827         private void applyAlignment(int widthAlignment, int heightAlignment) {
2828             checkPowerOfTwo(widthAlignment, "widthAlignment must be a power of two");
2829             checkPowerOfTwo(heightAlignment, "heightAlignment must be a power of two");
2830 
2831             if (widthAlignment > mBlockWidth || heightAlignment > mBlockHeight) {
2832                 // maintain assumption that 0 < alignment <= block-size
2833                 applyBlockLimits(
2834                         Math.max(widthAlignment, mBlockWidth),
2835                         Math.max(heightAlignment, mBlockHeight),
2836                         POSITIVE_INTEGERS, POSITIVE_LONGS, POSITIVE_RATIONALS);
2837             }
2838 
2839             mWidthAlignment = Math.max(widthAlignment, mWidthAlignment);
2840             mHeightAlignment = Math.max(heightAlignment, mHeightAlignment);
2841 
2842             mWidthRange = Utils.alignRange(mWidthRange, mWidthAlignment);
2843             mHeightRange = Utils.alignRange(mHeightRange, mHeightAlignment);
2844         }
2845 
updateLimits()2846         private void updateLimits() {
2847             // pixels -> blocks <- counts
2848             mHorizontalBlockRange = mHorizontalBlockRange.intersect(
2849                     Utils.factorRange(mWidthRange, mBlockWidth));
2850             mHorizontalBlockRange = mHorizontalBlockRange.intersect(
2851                     Range.create(
2852                             mBlockCountRange.getLower() / mVerticalBlockRange.getUpper(),
2853                             mBlockCountRange.getUpper() / mVerticalBlockRange.getLower()));
2854             mVerticalBlockRange = mVerticalBlockRange.intersect(
2855                     Utils.factorRange(mHeightRange, mBlockHeight));
2856             mVerticalBlockRange = mVerticalBlockRange.intersect(
2857                     Range.create(
2858                             mBlockCountRange.getLower() / mHorizontalBlockRange.getUpper(),
2859                             mBlockCountRange.getUpper() / mHorizontalBlockRange.getLower()));
2860             mBlockCountRange = mBlockCountRange.intersect(
2861                     Range.create(
2862                             mHorizontalBlockRange.getLower()
2863                                     * mVerticalBlockRange.getLower(),
2864                             mHorizontalBlockRange.getUpper()
2865                                     * mVerticalBlockRange.getUpper()));
2866             mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(
2867                     new Rational(
2868                             mHorizontalBlockRange.getLower(), mVerticalBlockRange.getUpper()),
2869                     new Rational(
2870                             mHorizontalBlockRange.getUpper(), mVerticalBlockRange.getLower()));
2871 
2872             // blocks -> pixels
2873             mWidthRange = mWidthRange.intersect(
2874                     (mHorizontalBlockRange.getLower() - 1) * mBlockWidth + mWidthAlignment,
2875                     mHorizontalBlockRange.getUpper() * mBlockWidth);
2876             mHeightRange = mHeightRange.intersect(
2877                     (mVerticalBlockRange.getLower() - 1) * mBlockHeight + mHeightAlignment,
2878                     mVerticalBlockRange.getUpper() * mBlockHeight);
2879             mAspectRatioRange = mAspectRatioRange.intersect(
2880                     new Rational(mWidthRange.getLower(), mHeightRange.getUpper()),
2881                     new Rational(mWidthRange.getUpper(), mHeightRange.getLower()));
2882 
2883             mSmallerDimensionUpperLimit = Math.min(
2884                     mSmallerDimensionUpperLimit,
2885                     Math.min(mWidthRange.getUpper(), mHeightRange.getUpper()));
2886 
2887             // blocks -> rate
2888             mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(
2889                     mBlockCountRange.getLower() * (long)mFrameRateRange.getLower(),
2890                     mBlockCountRange.getUpper() * (long)mFrameRateRange.getUpper());
2891             mFrameRateRange = mFrameRateRange.intersect(
2892                     (int)(mBlocksPerSecondRange.getLower()
2893                             / mBlockCountRange.getUpper()),
2894                     (int)(mBlocksPerSecondRange.getUpper()
2895                             / (double)mBlockCountRange.getLower()));
2896         }
2897 
applyMacroBlockLimits( int maxHorizontalBlocks, int maxVerticalBlocks, int maxBlocks, long maxBlocksPerSecond, int blockWidth, int blockHeight, int widthAlignment, int heightAlignment)2898         private void applyMacroBlockLimits(
2899                 int maxHorizontalBlocks, int maxVerticalBlocks,
2900                 int maxBlocks, long maxBlocksPerSecond,
2901                 int blockWidth, int blockHeight,
2902                 int widthAlignment, int heightAlignment) {
2903             applyMacroBlockLimits(
2904                     1 /* minHorizontalBlocks */, 1 /* minVerticalBlocks */,
2905                     maxHorizontalBlocks, maxVerticalBlocks,
2906                     maxBlocks, maxBlocksPerSecond,
2907                     blockWidth, blockHeight, widthAlignment, heightAlignment);
2908         }
2909 
applyMacroBlockLimits( int minHorizontalBlocks, int minVerticalBlocks, int maxHorizontalBlocks, int maxVerticalBlocks, int maxBlocks, long maxBlocksPerSecond, int blockWidth, int blockHeight, int widthAlignment, int heightAlignment)2910         private void applyMacroBlockLimits(
2911                 int minHorizontalBlocks, int minVerticalBlocks,
2912                 int maxHorizontalBlocks, int maxVerticalBlocks,
2913                 int maxBlocks, long maxBlocksPerSecond,
2914                 int blockWidth, int blockHeight,
2915                 int widthAlignment, int heightAlignment) {
2916             applyAlignment(widthAlignment, heightAlignment);
2917             applyBlockLimits(
2918                     blockWidth, blockHeight, Range.create(1, maxBlocks),
2919                     Range.create(1L, maxBlocksPerSecond),
2920                     Range.create(
2921                             new Rational(1, maxVerticalBlocks),
2922                             new Rational(maxHorizontalBlocks, 1)));
2923             mHorizontalBlockRange =
2924                     mHorizontalBlockRange.intersect(
2925                             Utils.divUp(minHorizontalBlocks, (mBlockWidth / blockWidth)),
2926                             maxHorizontalBlocks / (mBlockWidth / blockWidth));
2927             mVerticalBlockRange =
2928                     mVerticalBlockRange.intersect(
2929                             Utils.divUp(minVerticalBlocks, (mBlockHeight / blockHeight)),
2930                             maxVerticalBlocks / (mBlockHeight / blockHeight));
2931         }
2932 
applyLevelLimits()2933         private void applyLevelLimits() {
2934             long maxBlocksPerSecond = 0;
2935             int maxBlocks = 0;
2936             int maxBps = 0;
2937             int maxDPBBlocks = 0;
2938 
2939             int errors = ERROR_NONE_SUPPORTED;
2940             CodecProfileLevel[] profileLevels = mParent.profileLevels;
2941             String mime = mParent.getMimeType();
2942 
2943             if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC)) {
2944                 maxBlocks = 99;
2945                 maxBlocksPerSecond = 1485;
2946                 maxBps = 64000;
2947                 maxDPBBlocks = 396;
2948                 for (CodecProfileLevel profileLevel: profileLevels) {
2949                     int MBPS = 0, FS = 0, BR = 0, DPB = 0;
2950                     boolean supported = true;
2951                     switch (profileLevel.level) {
2952                         case CodecProfileLevel.AVCLevel1:
2953                             MBPS =     1485; FS =     99; BR =     64; DPB =    396; break;
2954                         case CodecProfileLevel.AVCLevel1b:
2955                             MBPS =     1485; FS =     99; BR =    128; DPB =    396; break;
2956                         case CodecProfileLevel.AVCLevel11:
2957                             MBPS =     3000; FS =    396; BR =    192; DPB =    900; break;
2958                         case CodecProfileLevel.AVCLevel12:
2959                             MBPS =     6000; FS =    396; BR =    384; DPB =   2376; break;
2960                         case CodecProfileLevel.AVCLevel13:
2961                             MBPS =    11880; FS =    396; BR =    768; DPB =   2376; break;
2962                         case CodecProfileLevel.AVCLevel2:
2963                             MBPS =    11880; FS =    396; BR =   2000; DPB =   2376; break;
2964                         case CodecProfileLevel.AVCLevel21:
2965                             MBPS =    19800; FS =    792; BR =   4000; DPB =   4752; break;
2966                         case CodecProfileLevel.AVCLevel22:
2967                             MBPS =    20250; FS =   1620; BR =   4000; DPB =   8100; break;
2968                         case CodecProfileLevel.AVCLevel3:
2969                             MBPS =    40500; FS =   1620; BR =  10000; DPB =   8100; break;
2970                         case CodecProfileLevel.AVCLevel31:
2971                             MBPS =   108000; FS =   3600; BR =  14000; DPB =  18000; break;
2972                         case CodecProfileLevel.AVCLevel32:
2973                             MBPS =   216000; FS =   5120; BR =  20000; DPB =  20480; break;
2974                         case CodecProfileLevel.AVCLevel4:
2975                             MBPS =   245760; FS =   8192; BR =  20000; DPB =  32768; break;
2976                         case CodecProfileLevel.AVCLevel41:
2977                             MBPS =   245760; FS =   8192; BR =  50000; DPB =  32768; break;
2978                         case CodecProfileLevel.AVCLevel42:
2979                             MBPS =   522240; FS =   8704; BR =  50000; DPB =  34816; break;
2980                         case CodecProfileLevel.AVCLevel5:
2981                             MBPS =   589824; FS =  22080; BR = 135000; DPB = 110400; break;
2982                         case CodecProfileLevel.AVCLevel51:
2983                             MBPS =   983040; FS =  36864; BR = 240000; DPB = 184320; break;
2984                         case CodecProfileLevel.AVCLevel52:
2985                             MBPS =  2073600; FS =  36864; BR = 240000; DPB = 184320; break;
2986                         case CodecProfileLevel.AVCLevel6:
2987                             MBPS =  4177920; FS = 139264; BR = 240000; DPB = 696320; break;
2988                         case CodecProfileLevel.AVCLevel61:
2989                             MBPS =  8355840; FS = 139264; BR = 480000; DPB = 696320; break;
2990                         case CodecProfileLevel.AVCLevel62:
2991                             MBPS = 16711680; FS = 139264; BR = 800000; DPB = 696320; break;
2992                         default:
2993                             Log.w(TAG, "Unrecognized level "
2994                                     + profileLevel.level + " for " + mime);
2995                             errors |= ERROR_UNRECOGNIZED;
2996                     }
2997                     switch (profileLevel.profile) {
2998                         case CodecProfileLevel.AVCProfileConstrainedHigh:
2999                         case CodecProfileLevel.AVCProfileHigh:
3000                             BR *= 1250; break;
3001                         case CodecProfileLevel.AVCProfileHigh10:
3002                             BR *= 3000; break;
3003                         case CodecProfileLevel.AVCProfileExtended:
3004                         case CodecProfileLevel.AVCProfileHigh422:
3005                         case CodecProfileLevel.AVCProfileHigh444:
3006                             Log.w(TAG, "Unsupported profile "
3007                                     + profileLevel.profile + " for " + mime);
3008                             errors |= ERROR_UNSUPPORTED;
3009                             supported = false;
3010                             // fall through - treat as base profile
3011                         case CodecProfileLevel.AVCProfileConstrainedBaseline:
3012                         case CodecProfileLevel.AVCProfileBaseline:
3013                         case CodecProfileLevel.AVCProfileMain:
3014                             BR *= 1000; break;
3015                         default:
3016                             Log.w(TAG, "Unrecognized profile "
3017                                     + profileLevel.profile + " for " + mime);
3018                             errors |= ERROR_UNRECOGNIZED;
3019                             BR *= 1000;
3020                     }
3021                     if (supported) {
3022                         errors &= ~ERROR_NONE_SUPPORTED;
3023                     }
3024                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
3025                     maxBlocks = Math.max(FS, maxBlocks);
3026                     maxBps = Math.max(BR, maxBps);
3027                     maxDPBBlocks = Math.max(maxDPBBlocks, DPB);
3028                 }
3029 
3030                 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8));
3031                 applyMacroBlockLimits(
3032                         maxLengthInBlocks, maxLengthInBlocks,
3033                         maxBlocks, maxBlocksPerSecond,
3034                         16 /* blockWidth */, 16 /* blockHeight */,
3035                         1 /* widthAlignment */, 1 /* heightAlignment */);
3036             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG2)) {
3037                 int maxWidth = 11, maxHeight = 9, maxRate = 15;
3038                 maxBlocks = 99;
3039                 maxBlocksPerSecond = 1485;
3040                 maxBps = 64000;
3041                 for (CodecProfileLevel profileLevel: profileLevels) {
3042                     int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0;
3043                     boolean supported = true;
3044                     switch (profileLevel.profile) {
3045                         case CodecProfileLevel.MPEG2ProfileSimple:
3046                             switch (profileLevel.level) {
3047                                 case CodecProfileLevel.MPEG2LevelML:
3048                                     FR = 30; W = 45; H =  36; MBPS =  40500; FS =  1620; BR =  15000; break;
3049                                 default:
3050                                     Log.w(TAG, "Unrecognized profile/level "
3051                                             + profileLevel.profile + "/"
3052                                             + profileLevel.level + " for " + mime);
3053                                     errors |= ERROR_UNRECOGNIZED;
3054                             }
3055                             break;
3056                         case CodecProfileLevel.MPEG2ProfileMain:
3057                             switch (profileLevel.level) {
3058                                 case CodecProfileLevel.MPEG2LevelLL:
3059                                     FR = 30; W = 22; H =  18; MBPS =  11880; FS =   396; BR =  4000; break;
3060                                 case CodecProfileLevel.MPEG2LevelML:
3061                                     FR = 30; W = 45; H =  36; MBPS =  40500; FS =  1620; BR = 15000; break;
3062                                 case CodecProfileLevel.MPEG2LevelH14:
3063                                     FR = 60; W = 90; H =  68; MBPS = 183600; FS =  6120; BR = 60000; break;
3064                                 case CodecProfileLevel.MPEG2LevelHL:
3065                                     FR = 60; W = 120; H = 68; MBPS = 244800; FS =  8160; BR = 80000; break;
3066                                 case CodecProfileLevel.MPEG2LevelHP:
3067                                     FR = 60; W = 120; H = 68; MBPS = 489600; FS =  8160; BR = 80000; break;
3068                                 default:
3069                                     Log.w(TAG, "Unrecognized profile/level "
3070                                             + profileLevel.profile + "/"
3071                                             + profileLevel.level + " for " + mime);
3072                                     errors |= ERROR_UNRECOGNIZED;
3073                             }
3074                             break;
3075                         case CodecProfileLevel.MPEG2Profile422:
3076                         case CodecProfileLevel.MPEG2ProfileSNR:
3077                         case CodecProfileLevel.MPEG2ProfileSpatial:
3078                         case CodecProfileLevel.MPEG2ProfileHigh:
3079                             Log.i(TAG, "Unsupported profile "
3080                                     + profileLevel.profile + " for " + mime);
3081                             errors |= ERROR_UNSUPPORTED;
3082                             supported = false;
3083                             break;
3084                         default:
3085                             Log.w(TAG, "Unrecognized profile "
3086                                     + profileLevel.profile + " for " + mime);
3087                             errors |= ERROR_UNRECOGNIZED;
3088                     }
3089                     if (supported) {
3090                         errors &= ~ERROR_NONE_SUPPORTED;
3091                     }
3092                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
3093                     maxBlocks = Math.max(FS, maxBlocks);
3094                     maxBps = Math.max(BR * 1000, maxBps);
3095                     maxWidth = Math.max(W, maxWidth);
3096                     maxHeight = Math.max(H, maxHeight);
3097                     maxRate = Math.max(FR, maxRate);
3098                 }
3099                 applyMacroBlockLimits(maxWidth, maxHeight,
3100                         maxBlocks, maxBlocksPerSecond,
3101                         16 /* blockWidth */, 16 /* blockHeight */,
3102                         1 /* widthAlignment */, 1 /* heightAlignment */);
3103                 mFrameRateRange = mFrameRateRange.intersect(12, maxRate);
3104             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) {
3105                 int maxWidth = 11, maxHeight = 9, maxRate = 15;
3106                 maxBlocks = 99;
3107                 maxBlocksPerSecond = 1485;
3108                 maxBps = 64000;
3109                 for (CodecProfileLevel profileLevel: profileLevels) {
3110                     int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0;
3111                     boolean strict = false; // true: W, H and FR are individual max limits
3112                     boolean supported = true;
3113                     switch (profileLevel.profile) {
3114                         case CodecProfileLevel.MPEG4ProfileSimple:
3115                             switch (profileLevel.level) {
3116                                 case CodecProfileLevel.MPEG4Level0:
3117                                     strict = true;
3118                                     FR = 15; W = 11; H =  9; MBPS =  1485; FS =  99; BR =  64; break;
3119                                 case CodecProfileLevel.MPEG4Level1:
3120                                     FR = 30; W = 11; H =  9; MBPS =  1485; FS =  99; BR =  64; break;
3121                                 case CodecProfileLevel.MPEG4Level0b:
3122                                     strict = true;
3123                                     FR = 15; W = 11; H =  9; MBPS =  1485; FS =  99; BR = 128; break;
3124                                 case CodecProfileLevel.MPEG4Level2:
3125                                     FR = 30; W = 22; H = 18; MBPS =  5940; FS = 396; BR = 128; break;
3126                                 case CodecProfileLevel.MPEG4Level3:
3127                                     FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384; break;
3128                                 case CodecProfileLevel.MPEG4Level4a:
3129                                     FR = 30; W = 40; H = 30; MBPS = 36000; FS = 1200; BR = 4000; break;
3130                                 case CodecProfileLevel.MPEG4Level5:
3131                                     FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 8000; break;
3132                                 case CodecProfileLevel.MPEG4Level6:
3133                                     FR = 30; W = 80; H = 45; MBPS = 108000; FS = 3600; BR = 12000; break;
3134                                 default:
3135                                     Log.w(TAG, "Unrecognized profile/level "
3136                                             + profileLevel.profile + "/"
3137                                             + profileLevel.level + " for " + mime);
3138                                     errors |= ERROR_UNRECOGNIZED;
3139                             }
3140                             break;
3141                         case CodecProfileLevel.MPEG4ProfileAdvancedSimple:
3142                             switch (profileLevel.level) {
3143                                 case CodecProfileLevel.MPEG4Level0:
3144                                 case CodecProfileLevel.MPEG4Level1:
3145                                     FR = 30; W = 11; H =  9; MBPS =  2970; FS =   99; BR =  128; break;
3146                                 case CodecProfileLevel.MPEG4Level2:
3147                                     FR = 30; W = 22; H = 18; MBPS =  5940; FS =  396; BR =  384; break;
3148                                 case CodecProfileLevel.MPEG4Level3:
3149                                     FR = 30; W = 22; H = 18; MBPS = 11880; FS =  396; BR =  768; break;
3150                                 case CodecProfileLevel.MPEG4Level3b:
3151                                     FR = 30; W = 22; H = 18; MBPS = 11880; FS =  396; BR = 1500; break;
3152                                 case CodecProfileLevel.MPEG4Level4:
3153                                     FR = 30; W = 44; H = 36; MBPS = 23760; FS =  792; BR = 3000; break;
3154                                 case CodecProfileLevel.MPEG4Level5:
3155                                     FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 8000; break;
3156                                 default:
3157                                     Log.w(TAG, "Unrecognized profile/level "
3158                                             + profileLevel.profile + "/"
3159                                             + profileLevel.level + " for " + mime);
3160                                     errors |= ERROR_UNRECOGNIZED;
3161                             }
3162                             break;
3163                         case CodecProfileLevel.MPEG4ProfileMain:             // 2-4
3164                         case CodecProfileLevel.MPEG4ProfileNbit:             // 2
3165                         case CodecProfileLevel.MPEG4ProfileAdvancedRealTime: // 1-4
3166                         case CodecProfileLevel.MPEG4ProfileCoreScalable:     // 1-3
3167                         case CodecProfileLevel.MPEG4ProfileAdvancedCoding:   // 1-4
3168                         case CodecProfileLevel.MPEG4ProfileCore:             // 1-2
3169                         case CodecProfileLevel.MPEG4ProfileAdvancedCore:     // 1-4
3170                         case CodecProfileLevel.MPEG4ProfileSimpleScalable:   // 0-2
3171                         case CodecProfileLevel.MPEG4ProfileHybrid:           // 1-2
3172 
3173                         // Studio profiles are not supported by our codecs.
3174 
3175                         // Only profiles that can decode simple object types are considered.
3176                         // The following profiles are not able to.
3177                         case CodecProfileLevel.MPEG4ProfileBasicAnimated:    // 1-2
3178                         case CodecProfileLevel.MPEG4ProfileScalableTexture:  // 1
3179                         case CodecProfileLevel.MPEG4ProfileSimpleFace:       // 1-2
3180                         case CodecProfileLevel.MPEG4ProfileAdvancedScalable: // 1-3
3181                         case CodecProfileLevel.MPEG4ProfileSimpleFBA:        // 1-2
3182                             Log.i(TAG, "Unsupported profile "
3183                                     + profileLevel.profile + " for " + mime);
3184                             errors |= ERROR_UNSUPPORTED;
3185                             supported = false;
3186                             break;
3187                         default:
3188                             Log.w(TAG, "Unrecognized profile "
3189                                     + profileLevel.profile + " for " + mime);
3190                             errors |= ERROR_UNRECOGNIZED;
3191                     }
3192                     if (supported) {
3193                         errors &= ~ERROR_NONE_SUPPORTED;
3194                     }
3195                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
3196                     maxBlocks = Math.max(FS, maxBlocks);
3197                     maxBps = Math.max(BR * 1000, maxBps);
3198                     if (strict) {
3199                         maxWidth = Math.max(W, maxWidth);
3200                         maxHeight = Math.max(H, maxHeight);
3201                         maxRate = Math.max(FR, maxRate);
3202                     } else {
3203                         // assuming max 60 fps frame rate and 1:2 aspect ratio
3204                         int maxDim = (int)Math.sqrt(FS * 2);
3205                         maxWidth = Math.max(maxDim, maxWidth);
3206                         maxHeight = Math.max(maxDim, maxHeight);
3207                         maxRate = Math.max(Math.max(FR, 60), maxRate);
3208                     }
3209                 }
3210                 applyMacroBlockLimits(maxWidth, maxHeight,
3211                         maxBlocks, maxBlocksPerSecond,
3212                         16 /* blockWidth */, 16 /* blockHeight */,
3213                         1 /* widthAlignment */, 1 /* heightAlignment */);
3214                 mFrameRateRange = mFrameRateRange.intersect(12, maxRate);
3215             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) {
3216                 int maxWidth = 11, maxHeight = 9, maxRate = 15;
3217                 int minWidth = maxWidth, minHeight = maxHeight;
3218                 int minAlignment = 16;
3219                 maxBlocks = 99;
3220                 maxBlocksPerSecond = 1485;
3221                 maxBps = 64000;
3222                 for (CodecProfileLevel profileLevel: profileLevels) {
3223                     int MBPS = 0, BR = 0, FR = 0, W = 0, H = 0, minW = minWidth, minH = minHeight;
3224                     boolean strict = false; // true: support only sQCIF, QCIF (maybe CIF)
3225                     switch (profileLevel.level) {
3226                         case CodecProfileLevel.H263Level10:
3227                             strict = true; // only supports sQCIF & QCIF
3228                             FR = 15; W = 11; H =  9; BR =   1; MBPS =  W * H * FR; break;
3229                         case CodecProfileLevel.H263Level20:
3230                             strict = true; // only supports sQCIF, QCIF & CIF
3231                             FR = 30; W = 22; H = 18; BR =   2; MBPS =  W * H * 15; break;
3232                         case CodecProfileLevel.H263Level30:
3233                             strict = true; // only supports sQCIF, QCIF & CIF
3234                             FR = 30; W = 22; H = 18; BR =   6; MBPS =  W * H * FR; break;
3235                         case CodecProfileLevel.H263Level40:
3236                             strict = true; // only supports sQCIF, QCIF & CIF
3237                             FR = 30; W = 22; H = 18; BR =  32; MBPS =  W * H * FR; break;
3238                         case CodecProfileLevel.H263Level45:
3239                             // only implies level 10 support
3240                             strict = profileLevel.profile == CodecProfileLevel.H263ProfileBaseline
3241                                     || profileLevel.profile ==
3242                                             CodecProfileLevel.H263ProfileBackwardCompatible;
3243                             if (!strict) {
3244                                 minW = 1; minH = 1; minAlignment = 4;
3245                             }
3246                             FR = 15; W = 11; H =  9; BR =   2; MBPS =  W * H * FR; break;
3247                         case CodecProfileLevel.H263Level50:
3248                             // only supports 50fps for H > 15
3249                             minW = 1; minH = 1; minAlignment = 4;
3250                             FR = 60; W = 22; H = 18; BR =  64; MBPS =  W * H * 50; break;
3251                         case CodecProfileLevel.H263Level60:
3252                             // only supports 50fps for H > 15
3253                             minW = 1; minH = 1; minAlignment = 4;
3254                             FR = 60; W = 45; H = 18; BR = 128; MBPS =  W * H * 50; break;
3255                         case CodecProfileLevel.H263Level70:
3256                             // only supports 50fps for H > 30
3257                             minW = 1; minH = 1; minAlignment = 4;
3258                             FR = 60; W = 45; H = 36; BR = 256; MBPS =  W * H * 50; break;
3259                         default:
3260                             Log.w(TAG, "Unrecognized profile/level " + profileLevel.profile
3261                                     + "/" + profileLevel.level + " for " + mime);
3262                             errors |= ERROR_UNRECOGNIZED;
3263                     }
3264                     switch (profileLevel.profile) {
3265                         case CodecProfileLevel.H263ProfileBackwardCompatible:
3266                         case CodecProfileLevel.H263ProfileBaseline:
3267                         case CodecProfileLevel.H263ProfileH320Coding:
3268                         case CodecProfileLevel.H263ProfileHighCompression:
3269                         case CodecProfileLevel.H263ProfileHighLatency:
3270                         case CodecProfileLevel.H263ProfileInterlace:
3271                         case CodecProfileLevel.H263ProfileInternet:
3272                         case CodecProfileLevel.H263ProfileISWV2:
3273                         case CodecProfileLevel.H263ProfileISWV3:
3274                             break;
3275                         default:
3276                             Log.w(TAG, "Unrecognized profile "
3277                                     + profileLevel.profile + " for " + mime);
3278                             errors |= ERROR_UNRECOGNIZED;
3279                     }
3280                     if (strict) {
3281                         // Strict levels define sub-QCIF min size and enumerated sizes. We cannot
3282                         // express support for "only sQCIF & QCIF (& CIF)" using VideoCapabilities
3283                         // but we can express "only QCIF (& CIF)", so set minimume size at QCIF.
3284                         // minW = 8; minH = 6;
3285                         minW = 11; minH = 9;
3286                     } else {
3287                         // any support for non-strict levels (including unrecognized profiles or
3288                         // levels) allow custom frame size support beyond supported limits
3289                         // (other than bitrate)
3290                         mAllowMbOverride = true;
3291                     }
3292                     errors &= ~ERROR_NONE_SUPPORTED;
3293                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
3294                     maxBlocks = Math.max(W * H, maxBlocks);
3295                     maxBps = Math.max(BR * 64000, maxBps);
3296                     maxWidth = Math.max(W, maxWidth);
3297                     maxHeight = Math.max(H, maxHeight);
3298                     maxRate = Math.max(FR, maxRate);
3299                     minWidth = Math.min(minW, minWidth);
3300                     minHeight = Math.min(minH, minHeight);
3301                 }
3302                 // unless we encountered custom frame size support, limit size to QCIF and CIF
3303                 // using aspect ratio.
3304                 if (!mAllowMbOverride) {
3305                     mBlockAspectRatioRange =
3306                         Range.create(new Rational(11, 9), new Rational(11, 9));
3307                 }
3308                 applyMacroBlockLimits(
3309                         minWidth, minHeight,
3310                         maxWidth, maxHeight,
3311                         maxBlocks, maxBlocksPerSecond,
3312                         16 /* blockWidth */, 16 /* blockHeight */,
3313                         minAlignment /* widthAlignment */, minAlignment /* heightAlignment */);
3314                 mFrameRateRange = Range.create(1, maxRate);
3315             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8)) {
3316                 maxBlocks = Integer.MAX_VALUE;
3317                 maxBlocksPerSecond = Integer.MAX_VALUE;
3318 
3319                 // TODO: set to 100Mbps for now, need a number for VP8
3320                 maxBps = 100000000;
3321 
3322                 // profile levels are not indicative for VPx, but verify
3323                 // them nonetheless
3324                 for (CodecProfileLevel profileLevel: profileLevels) {
3325                     switch (profileLevel.level) {
3326                         case CodecProfileLevel.VP8Level_Version0:
3327                         case CodecProfileLevel.VP8Level_Version1:
3328                         case CodecProfileLevel.VP8Level_Version2:
3329                         case CodecProfileLevel.VP8Level_Version3:
3330                             break;
3331                         default:
3332                             Log.w(TAG, "Unrecognized level "
3333                                     + profileLevel.level + " for " + mime);
3334                             errors |= ERROR_UNRECOGNIZED;
3335                     }
3336                     switch (profileLevel.profile) {
3337                         case CodecProfileLevel.VP8ProfileMain:
3338                             break;
3339                         default:
3340                             Log.w(TAG, "Unrecognized profile "
3341                                     + profileLevel.profile + " for " + mime);
3342                             errors |= ERROR_UNRECOGNIZED;
3343                     }
3344                     errors &= ~ERROR_NONE_SUPPORTED;
3345                 }
3346 
3347                 final int blockSize = 16;
3348                 applyMacroBlockLimits(Short.MAX_VALUE, Short.MAX_VALUE,
3349                         maxBlocks, maxBlocksPerSecond, blockSize, blockSize,
3350                         1 /* widthAlignment */, 1 /* heightAlignment */);
3351             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) {
3352                 maxBlocksPerSecond = 829440;
3353                 maxBlocks = 36864;
3354                 maxBps = 200000;
3355                 int maxDim = 512;
3356 
3357                 for (CodecProfileLevel profileLevel: profileLevels) {
3358                     long SR = 0; // luma sample rate
3359                     int FS = 0;  // luma picture size
3360                     int BR = 0;  // bit rate kbps
3361                     int D = 0;   // luma dimension
3362                     switch (profileLevel.level) {
3363                         case CodecProfileLevel.VP9Level1:
3364                             SR =      829440; FS =    36864; BR =    200; D =   512; break;
3365                         case CodecProfileLevel.VP9Level11:
3366                             SR =     2764800; FS =    73728; BR =    800; D =   768; break;
3367                         case CodecProfileLevel.VP9Level2:
3368                             SR =     4608000; FS =   122880; BR =   1800; D =   960; break;
3369                         case CodecProfileLevel.VP9Level21:
3370                             SR =     9216000; FS =   245760; BR =   3600; D =  1344; break;
3371                         case CodecProfileLevel.VP9Level3:
3372                             SR =    20736000; FS =   552960; BR =   7200; D =  2048; break;
3373                         case CodecProfileLevel.VP9Level31:
3374                             SR =    36864000; FS =   983040; BR =  12000; D =  2752; break;
3375                         case CodecProfileLevel.VP9Level4:
3376                             SR =    83558400; FS =  2228224; BR =  18000; D =  4160; break;
3377                         case CodecProfileLevel.VP9Level41:
3378                             SR =   160432128; FS =  2228224; BR =  30000; D =  4160; break;
3379                         case CodecProfileLevel.VP9Level5:
3380                             SR =   311951360; FS =  8912896; BR =  60000; D =  8384; break;
3381                         case CodecProfileLevel.VP9Level51:
3382                             SR =   588251136; FS =  8912896; BR = 120000; D =  8384; break;
3383                         case CodecProfileLevel.VP9Level52:
3384                             SR =  1176502272; FS =  8912896; BR = 180000; D =  8384; break;
3385                         case CodecProfileLevel.VP9Level6:
3386                             SR =  1176502272; FS = 35651584; BR = 180000; D = 16832; break;
3387                         case CodecProfileLevel.VP9Level61:
3388                             SR = 2353004544L; FS = 35651584; BR = 240000; D = 16832; break;
3389                         case CodecProfileLevel.VP9Level62:
3390                             SR = 4706009088L; FS = 35651584; BR = 480000; D = 16832; break;
3391                         default:
3392                             Log.w(TAG, "Unrecognized level "
3393                                     + profileLevel.level + " for " + mime);
3394                             errors |= ERROR_UNRECOGNIZED;
3395                     }
3396                     switch (profileLevel.profile) {
3397                         case CodecProfileLevel.VP9Profile0:
3398                         case CodecProfileLevel.VP9Profile1:
3399                         case CodecProfileLevel.VP9Profile2:
3400                         case CodecProfileLevel.VP9Profile3:
3401                         case CodecProfileLevel.VP9Profile2HDR:
3402                         case CodecProfileLevel.VP9Profile3HDR:
3403                         case CodecProfileLevel.VP9Profile2HDR10Plus:
3404                         case CodecProfileLevel.VP9Profile3HDR10Plus:
3405                             break;
3406                         default:
3407                             Log.w(TAG, "Unrecognized profile "
3408                                     + profileLevel.profile + " for " + mime);
3409                             errors |= ERROR_UNRECOGNIZED;
3410                     }
3411                     errors &= ~ERROR_NONE_SUPPORTED;
3412                     maxBlocksPerSecond = Math.max(SR, maxBlocksPerSecond);
3413                     maxBlocks = Math.max(FS, maxBlocks);
3414                     maxBps = Math.max(BR * 1000, maxBps);
3415                     maxDim = Math.max(D, maxDim);
3416                 }
3417 
3418                 final int blockSize = 8;
3419                 int maxLengthInBlocks = Utils.divUp(maxDim, blockSize);
3420                 maxBlocks = Utils.divUp(maxBlocks, blockSize * blockSize);
3421                 maxBlocksPerSecond = Utils.divUp(maxBlocksPerSecond, blockSize * blockSize);
3422 
3423                 applyMacroBlockLimits(
3424                         maxLengthInBlocks, maxLengthInBlocks,
3425                         maxBlocks, maxBlocksPerSecond,
3426                         blockSize, blockSize,
3427                         1 /* widthAlignment */, 1 /* heightAlignment */);
3428             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
3429                 // CTBs are at least 8x8 so use 8x8 block size
3430                 maxBlocks = 36864 >> 6; // 192x192 pixels == 576 8x8 blocks
3431                 maxBlocksPerSecond = maxBlocks * 15;
3432                 maxBps = 128000;
3433                 for (CodecProfileLevel profileLevel: profileLevels) {
3434                     double FR = 0;
3435                     int FS = 0;
3436                     int BR = 0;
3437                     switch (profileLevel.level) {
3438                         /* The HEVC spec talks only in a very convoluted manner about the
3439                            existence of levels 1-3.1 for High tier, which could also be
3440                            understood as 'decoders and encoders should treat these levels
3441                            as if they were Main tier', so we do that. */
3442                         case CodecProfileLevel.HEVCMainTierLevel1:
3443                         case CodecProfileLevel.HEVCHighTierLevel1:
3444                             FR =    15; FS =    36864; BR =    128; break;
3445                         case CodecProfileLevel.HEVCMainTierLevel2:
3446                         case CodecProfileLevel.HEVCHighTierLevel2:
3447                             FR =    30; FS =   122880; BR =   1500; break;
3448                         case CodecProfileLevel.HEVCMainTierLevel21:
3449                         case CodecProfileLevel.HEVCHighTierLevel21:
3450                             FR =    30; FS =   245760; BR =   3000; break;
3451                         case CodecProfileLevel.HEVCMainTierLevel3:
3452                         case CodecProfileLevel.HEVCHighTierLevel3:
3453                             FR =    30; FS =   552960; BR =   6000; break;
3454                         case CodecProfileLevel.HEVCMainTierLevel31:
3455                         case CodecProfileLevel.HEVCHighTierLevel31:
3456                             FR = 33.75; FS =   983040; BR =  10000; break;
3457                         case CodecProfileLevel.HEVCMainTierLevel4:
3458                             FR =    30; FS =  2228224; BR =  12000; break;
3459                         case CodecProfileLevel.HEVCHighTierLevel4:
3460                             FR =    30; FS =  2228224; BR =  30000; break;
3461                         case CodecProfileLevel.HEVCMainTierLevel41:
3462                             FR =    60; FS =  2228224; BR =  20000; break;
3463                         case CodecProfileLevel.HEVCHighTierLevel41:
3464                             FR =    60; FS =  2228224; BR =  50000; break;
3465                         case CodecProfileLevel.HEVCMainTierLevel5:
3466                             FR =    30; FS =  8912896; BR =  25000; break;
3467                         case CodecProfileLevel.HEVCHighTierLevel5:
3468                             FR =    30; FS =  8912896; BR = 100000; break;
3469                         case CodecProfileLevel.HEVCMainTierLevel51:
3470                             FR =    60; FS =  8912896; BR =  40000; break;
3471                         case CodecProfileLevel.HEVCHighTierLevel51:
3472                             FR =    60; FS =  8912896; BR = 160000; break;
3473                         case CodecProfileLevel.HEVCMainTierLevel52:
3474                             FR =   120; FS =  8912896; BR =  60000; break;
3475                         case CodecProfileLevel.HEVCHighTierLevel52:
3476                             FR =   120; FS =  8912896; BR = 240000; break;
3477                         case CodecProfileLevel.HEVCMainTierLevel6:
3478                             FR =    30; FS = 35651584; BR =  60000; break;
3479                         case CodecProfileLevel.HEVCHighTierLevel6:
3480                             FR =    30; FS = 35651584; BR = 240000; break;
3481                         case CodecProfileLevel.HEVCMainTierLevel61:
3482                             FR =    60; FS = 35651584; BR = 120000; break;
3483                         case CodecProfileLevel.HEVCHighTierLevel61:
3484                             FR =    60; FS = 35651584; BR = 480000; break;
3485                         case CodecProfileLevel.HEVCMainTierLevel62:
3486                             FR =   120; FS = 35651584; BR = 240000; break;
3487                         case CodecProfileLevel.HEVCHighTierLevel62:
3488                             FR =   120; FS = 35651584; BR = 800000; break;
3489                         default:
3490                             Log.w(TAG, "Unrecognized level "
3491                                     + profileLevel.level + " for " + mime);
3492                             errors |= ERROR_UNRECOGNIZED;
3493                     }
3494                     switch (profileLevel.profile) {
3495                         case CodecProfileLevel.HEVCProfileMain:
3496                         case CodecProfileLevel.HEVCProfileMain10:
3497                         case CodecProfileLevel.HEVCProfileMainStill:
3498                         case CodecProfileLevel.HEVCProfileMain10HDR10:
3499                         case CodecProfileLevel.HEVCProfileMain10HDR10Plus:
3500                             break;
3501                         default:
3502                             Log.w(TAG, "Unrecognized profile "
3503                                     + profileLevel.profile + " for " + mime);
3504                             errors |= ERROR_UNRECOGNIZED;
3505                     }
3506 
3507                     /* DPB logic:
3508                     if      (width * height <= FS / 4)    DPB = 16;
3509                     else if (width * height <= FS / 2)    DPB = 12;
3510                     else if (width * height <= FS * 0.75) DPB = 8;
3511                     else                                  DPB = 6;
3512                     */
3513 
3514                     FS >>= 6; // convert pixels to blocks
3515                     errors &= ~ERROR_NONE_SUPPORTED;
3516                     maxBlocksPerSecond = Math.max((int)(FR * FS), maxBlocksPerSecond);
3517                     maxBlocks = Math.max(FS, maxBlocks);
3518                     maxBps = Math.max(BR * 1000, maxBps);
3519                 }
3520 
3521                 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8));
3522                 applyMacroBlockLimits(
3523                         maxLengthInBlocks, maxLengthInBlocks,
3524                         maxBlocks, maxBlocksPerSecond,
3525                         8 /* blockWidth */, 8 /* blockHeight */,
3526                         1 /* widthAlignment */, 1 /* heightAlignment */);
3527             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AV1)) {
3528                 maxBlocksPerSecond = 829440;
3529                 maxBlocks = 36864;
3530                 maxBps = 200000;
3531                 int maxDim = 512;
3532 
3533                 // Sample rate, Picture Size, Bit rate and luma dimension for AV1 Codec,
3534                 // corresponding to the definitions in
3535                 // "AV1 Bitstream & Decoding Process Specification", Annex A
3536                 // found at https://aomedia.org/av1-bitstream-and-decoding-process-specification/
3537                 for (CodecProfileLevel profileLevel: profileLevels) {
3538                     long SR = 0; // luma sample rate
3539                     int FS = 0;  // luma picture size
3540                     int BR = 0;  // bit rate kbps
3541                     int D = 0;   // luma D
3542                     switch (profileLevel.level) {
3543                         case CodecProfileLevel.AV1Level2:
3544                             SR =     5529600; FS =   147456; BR =   1500; D =  2048; break;
3545                         case CodecProfileLevel.AV1Level21:
3546                         case CodecProfileLevel.AV1Level22:
3547                         case CodecProfileLevel.AV1Level23:
3548                             SR =    10454400; FS =   278784; BR =   3000; D =  2816; break;
3549 
3550                         case CodecProfileLevel.AV1Level3:
3551                             SR =    24969600; FS =   665856; BR =   6000; D =  4352; break;
3552                         case CodecProfileLevel.AV1Level31:
3553                         case CodecProfileLevel.AV1Level32:
3554                         case CodecProfileLevel.AV1Level33:
3555                             SR =    39938400; FS =  1065024; BR =  10000; D =  5504; break;
3556 
3557                         case CodecProfileLevel.AV1Level4:
3558                             SR =    77856768; FS =  2359296; BR =  12000; D =  6144; break;
3559                         case CodecProfileLevel.AV1Level41:
3560                         case CodecProfileLevel.AV1Level42:
3561                         case CodecProfileLevel.AV1Level43:
3562                             SR =   155713536; FS =  2359296; BR =  20000; D =  6144; break;
3563 
3564                         case CodecProfileLevel.AV1Level5:
3565                             SR =   273715200; FS =  8912896; BR =  30000; D =  8192; break;
3566                         case CodecProfileLevel.AV1Level51:
3567                             SR =   547430400; FS =  8912896; BR =  40000; D =  8192; break;
3568                         case CodecProfileLevel.AV1Level52:
3569                             SR =  1094860800; FS =  8912896; BR =  60000; D =  8192; break;
3570                         case CodecProfileLevel.AV1Level53:
3571                             SR =  1176502272; FS =  8912896; BR =  60000; D =  8192; break;
3572 
3573                         case CodecProfileLevel.AV1Level6:
3574                             SR =  1176502272; FS = 35651584; BR =  60000; D = 16384; break;
3575                         case CodecProfileLevel.AV1Level61:
3576                             SR = 2189721600L; FS = 35651584; BR = 100000; D = 16384; break;
3577                         case CodecProfileLevel.AV1Level62:
3578                             SR = 4379443200L; FS = 35651584; BR = 160000; D = 16384; break;
3579                         case CodecProfileLevel.AV1Level63:
3580                             SR = 4706009088L; FS = 35651584; BR = 160000; D = 16384; break;
3581 
3582                         default:
3583                             Log.w(TAG, "Unrecognized level "
3584                                     + profileLevel.level + " for " + mime);
3585                             errors |= ERROR_UNRECOGNIZED;
3586                     }
3587                     switch (profileLevel.profile) {
3588                         case CodecProfileLevel.AV1ProfileMain8:
3589                         case CodecProfileLevel.AV1ProfileMain10:
3590                         case CodecProfileLevel.AV1ProfileMain10HDR10:
3591                         case CodecProfileLevel.AV1ProfileMain10HDR10Plus:
3592                             break;
3593                         default:
3594                             Log.w(TAG, "Unrecognized profile "
3595                                     + profileLevel.profile + " for " + mime);
3596                             errors |= ERROR_UNRECOGNIZED;
3597                     }
3598                     errors &= ~ERROR_NONE_SUPPORTED;
3599                     maxBlocksPerSecond = Math.max(SR, maxBlocksPerSecond);
3600                     maxBlocks = Math.max(FS, maxBlocks);
3601                     maxBps = Math.max(BR * 1000, maxBps);
3602                     maxDim = Math.max(D, maxDim);
3603                 }
3604 
3605                 final int blockSize = 8;
3606                 int maxLengthInBlocks = Utils.divUp(maxDim, blockSize);
3607                 maxBlocks = Utils.divUp(maxBlocks, blockSize * blockSize);
3608                 maxBlocksPerSecond = Utils.divUp(maxBlocksPerSecond, blockSize * blockSize);
3609                 applyMacroBlockLimits(
3610                         maxLengthInBlocks, maxLengthInBlocks,
3611                         maxBlocks, maxBlocksPerSecond,
3612                         blockSize, blockSize,
3613                         1 /* widthAlignment */, 1 /* heightAlignment */);
3614             } else {
3615                 Log.w(TAG, "Unsupported mime " + mime);
3616                 // using minimal bitrate here.  should be overriden by
3617                 // info from media_codecs.xml
3618                 maxBps = 64000;
3619                 errors |= ERROR_UNSUPPORTED;
3620             }
3621             mBitrateRange = Range.create(1, maxBps);
3622             mParent.mError |= errors;
3623         }
3624     }
3625 
3626     /**
3627      * A class that supports querying the encoding capabilities of a codec.
3628      */
3629     public static final class EncoderCapabilities {
3630         /**
3631          * Returns the supported range of quality values.
3632          *
3633          * Quality is implementation-specific. As a general rule, a higher quality
3634          * setting results in a better image quality and a lower compression ratio.
3635          */
getQualityRange()3636         public Range<Integer> getQualityRange() {
3637             return mQualityRange;
3638         }
3639 
3640         /**
3641          * Returns the supported range of encoder complexity values.
3642          * <p>
3643          * Some codecs may support multiple complexity levels, where higher
3644          * complexity values use more encoder tools (e.g. perform more
3645          * intensive calculations) to improve the quality or the compression
3646          * ratio.  Use a lower value to save power and/or time.
3647          */
getComplexityRange()3648         public Range<Integer> getComplexityRange() {
3649             return mComplexityRange;
3650         }
3651 
3652         /** Constant quality mode */
3653         public static final int BITRATE_MODE_CQ = 0;
3654         /** Variable bitrate mode */
3655         public static final int BITRATE_MODE_VBR = 1;
3656         /** Constant bitrate mode */
3657         public static final int BITRATE_MODE_CBR = 2;
3658         /** Constant bitrate mode with frame drops */
3659         public static final int BITRATE_MODE_CBR_FD =  3;
3660 
3661         private static final Feature[] bitrates = new Feature[] {
3662             new Feature("VBR", BITRATE_MODE_VBR, true),
3663             new Feature("CBR", BITRATE_MODE_CBR, false),
3664             new Feature("CQ",  BITRATE_MODE_CQ,  false),
3665             new Feature("CBR-FD", BITRATE_MODE_CBR_FD, false)
3666         };
3667 
parseBitrateMode(String mode)3668         private static int parseBitrateMode(String mode) {
3669             for (Feature feat: bitrates) {
3670                 if (feat.mName.equalsIgnoreCase(mode)) {
3671                     return feat.mValue;
3672                 }
3673             }
3674             return 0;
3675         }
3676 
3677         /**
3678          * Query whether a bitrate mode is supported.
3679          */
isBitrateModeSupported(int mode)3680         public boolean isBitrateModeSupported(int mode) {
3681             for (Feature feat: bitrates) {
3682                 if (mode == feat.mValue) {
3683                     return (mBitControl & (1 << mode)) != 0;
3684                 }
3685             }
3686             return false;
3687         }
3688 
3689         private Range<Integer> mQualityRange;
3690         private Range<Integer> mComplexityRange;
3691         private CodecCapabilities mParent;
3692 
3693         /* no public constructor */
EncoderCapabilities()3694         private EncoderCapabilities() { }
3695 
3696         /** @hide */
create( MediaFormat info, CodecCapabilities parent)3697         public static EncoderCapabilities create(
3698                 MediaFormat info, CodecCapabilities parent) {
3699             EncoderCapabilities caps = new EncoderCapabilities();
3700             caps.init(info, parent);
3701             return caps;
3702         }
3703 
init(MediaFormat info, CodecCapabilities parent)3704         private void init(MediaFormat info, CodecCapabilities parent) {
3705             // no support for complexity or quality yet
3706             mParent = parent;
3707             mComplexityRange = Range.create(0, 0);
3708             mQualityRange = Range.create(0, 0);
3709             mBitControl = (1 << BITRATE_MODE_VBR);
3710 
3711             applyLevelLimits();
3712             parseFromInfo(info);
3713         }
3714 
applyLevelLimits()3715         private void applyLevelLimits() {
3716             String mime = mParent.getMimeType();
3717             if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
3718                 mComplexityRange = Range.create(0, 8);
3719                 mBitControl = (1 << BITRATE_MODE_CQ);
3720             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)
3721                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)
3722                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW)
3723                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)
3724                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) {
3725                 mBitControl = (1 << BITRATE_MODE_CBR);
3726             }
3727         }
3728 
3729         private int mBitControl;
3730         private Integer mDefaultComplexity;
3731         private Integer mDefaultQuality;
3732         private String mQualityScale;
3733 
parseFromInfo(MediaFormat info)3734         private void parseFromInfo(MediaFormat info) {
3735             Map<String, Object> map = info.getMap();
3736 
3737             if (info.containsKey("complexity-range")) {
3738                 mComplexityRange = Utils
3739                         .parseIntRange(info.getString("complexity-range"), mComplexityRange);
3740                 // TODO should we limit this to level limits?
3741             }
3742             if (info.containsKey("quality-range")) {
3743                 mQualityRange = Utils
3744                         .parseIntRange(info.getString("quality-range"), mQualityRange);
3745             }
3746             if (info.containsKey("feature-bitrate-modes")) {
3747                 mBitControl = 0;
3748                 for (String mode: info.getString("feature-bitrate-modes").split(",")) {
3749                     mBitControl |= (1 << parseBitrateMode(mode));
3750                 }
3751             }
3752 
3753             try {
3754                 mDefaultComplexity = Integer.parseInt((String)map.get("complexity-default"));
3755             } catch (NumberFormatException e) { }
3756 
3757             try {
3758                 mDefaultQuality = Integer.parseInt((String)map.get("quality-default"));
3759             } catch (NumberFormatException e) { }
3760 
3761             mQualityScale = (String)map.get("quality-scale");
3762         }
3763 
supports( Integer complexity, Integer quality, Integer profile)3764         private boolean supports(
3765                 Integer complexity, Integer quality, Integer profile) {
3766             boolean ok = true;
3767             if (ok && complexity != null) {
3768                 ok = mComplexityRange.contains(complexity);
3769             }
3770             if (ok && quality != null) {
3771                 ok = mQualityRange.contains(quality);
3772             }
3773             if (ok && profile != null) {
3774                 for (CodecProfileLevel pl: mParent.profileLevels) {
3775                     if (pl.profile == profile) {
3776                         profile = null;
3777                         break;
3778                     }
3779                 }
3780                 ok = profile == null;
3781             }
3782             return ok;
3783         }
3784 
3785         /** @hide */
getDefaultFormat(MediaFormat format)3786         public void getDefaultFormat(MediaFormat format) {
3787             // don't list trivial quality/complexity as default for now
3788             if (!mQualityRange.getUpper().equals(mQualityRange.getLower())
3789                     && mDefaultQuality != null) {
3790                 format.setInteger(MediaFormat.KEY_QUALITY, mDefaultQuality);
3791             }
3792             if (!mComplexityRange.getUpper().equals(mComplexityRange.getLower())
3793                     && mDefaultComplexity != null) {
3794                 format.setInteger(MediaFormat.KEY_COMPLEXITY, mDefaultComplexity);
3795             }
3796             // bitrates are listed in order of preference
3797             for (Feature feat: bitrates) {
3798                 if ((mBitControl & (1 << feat.mValue)) != 0) {
3799                     format.setInteger(MediaFormat.KEY_BITRATE_MODE, feat.mValue);
3800                     break;
3801                 }
3802             }
3803         }
3804 
3805         /** @hide */
supportsFormat(MediaFormat format)3806         public boolean supportsFormat(MediaFormat format) {
3807             final Map<String, Object> map = format.getMap();
3808             final String mime = mParent.getMimeType();
3809 
3810             Integer mode = (Integer)map.get(MediaFormat.KEY_BITRATE_MODE);
3811             if (mode != null && !isBitrateModeSupported(mode)) {
3812                 return false;
3813             }
3814 
3815             Integer complexity = (Integer)map.get(MediaFormat.KEY_COMPLEXITY);
3816             if (MediaFormat.MIMETYPE_AUDIO_FLAC.equalsIgnoreCase(mime)) {
3817                 Integer flacComplexity =
3818                     (Integer)map.get(MediaFormat.KEY_FLAC_COMPRESSION_LEVEL);
3819                 if (complexity == null) {
3820                     complexity = flacComplexity;
3821                 } else if (flacComplexity != null && !complexity.equals(flacComplexity)) {
3822                     throw new IllegalArgumentException(
3823                             "conflicting values for complexity and " +
3824                             "flac-compression-level");
3825                 }
3826             }
3827 
3828             // other audio parameters
3829             Integer profile = (Integer)map.get(MediaFormat.KEY_PROFILE);
3830             if (MediaFormat.MIMETYPE_AUDIO_AAC.equalsIgnoreCase(mime)) {
3831                 Integer aacProfile = (Integer)map.get(MediaFormat.KEY_AAC_PROFILE);
3832                 if (profile == null) {
3833                     profile = aacProfile;
3834                 } else if (aacProfile != null && !aacProfile.equals(profile)) {
3835                     throw new IllegalArgumentException(
3836                             "conflicting values for profile and aac-profile");
3837                 }
3838             }
3839 
3840             Integer quality = (Integer)map.get(MediaFormat.KEY_QUALITY);
3841 
3842             return supports(complexity, quality, profile);
3843         }
3844     };
3845 
3846     /**
3847      * Encapsulates the profiles available for a codec component.
3848      * <p>You can get a set of {@link MediaCodecInfo.CodecProfileLevel} objects for a given
3849      * {@link MediaCodecInfo} object from the
3850      * {@link MediaCodecInfo.CodecCapabilities#profileLevels} field.
3851      */
3852     public static final class CodecProfileLevel {
3853         // These constants were originally in-line with OMX values, but this
3854         // correspondence is no longer maintained.
3855 
3856         // Profiles and levels for AVC Codec, corresponding to the definitions in
3857         // "SERIES H: AUDIOVISUAL AND MULTIMEDIA SYSTEMS,
3858         // Infrastructure of audiovisual services – Coding of moving video
3859         // Advanced video coding for generic audiovisual services"
3860         // found at
3861         // https://www.itu.int/rec/T-REC-H.264-201704-I
3862 
3863         /**
3864          * AVC Baseline profile.
3865          * See definition in
3866          * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
3867          * Annex A.
3868          */
3869         public static final int AVCProfileBaseline = 0x01;
3870 
3871         /**
3872          * AVC Main profile.
3873          * See definition in
3874          * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
3875          * Annex A.
3876          */
3877         public static final int AVCProfileMain     = 0x02;
3878 
3879         /**
3880          * AVC Extended profile.
3881          * See definition in
3882          * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
3883          * Annex A.
3884          */
3885         public static final int AVCProfileExtended = 0x04;
3886 
3887         /**
3888          * AVC High profile.
3889          * See definition in
3890          * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
3891          * Annex A.
3892          */
3893         public static final int AVCProfileHigh     = 0x08;
3894 
3895         /**
3896          * AVC High 10 profile.
3897          * See definition in
3898          * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
3899          * Annex A.
3900          */
3901         public static final int AVCProfileHigh10   = 0x10;
3902 
3903         /**
3904          * AVC High 4:2:2 profile.
3905          * See definition in
3906          * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
3907          * Annex A.
3908          */
3909         public static final int AVCProfileHigh422  = 0x20;
3910 
3911         /**
3912          * AVC High 4:4:4 profile.
3913          * See definition in
3914          * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
3915          * Annex A.
3916          */
3917         public static final int AVCProfileHigh444  = 0x40;
3918 
3919         /**
3920          * AVC Constrained Baseline profile.
3921          * See definition in
3922          * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
3923          * Annex A.
3924          */
3925         public static final int AVCProfileConstrainedBaseline = 0x10000;
3926 
3927         /**
3928          * AVC Constrained High profile.
3929          * See definition in
3930          * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
3931          * Annex A.
3932          */
3933         public static final int AVCProfileConstrainedHigh     = 0x80000;
3934 
3935         public static final int AVCLevel1       = 0x01;
3936         public static final int AVCLevel1b      = 0x02;
3937         public static final int AVCLevel11      = 0x04;
3938         public static final int AVCLevel12      = 0x08;
3939         public static final int AVCLevel13      = 0x10;
3940         public static final int AVCLevel2       = 0x20;
3941         public static final int AVCLevel21      = 0x40;
3942         public static final int AVCLevel22      = 0x80;
3943         public static final int AVCLevel3       = 0x100;
3944         public static final int AVCLevel31      = 0x200;
3945         public static final int AVCLevel32      = 0x400;
3946         public static final int AVCLevel4       = 0x800;
3947         public static final int AVCLevel41      = 0x1000;
3948         public static final int AVCLevel42      = 0x2000;
3949         public static final int AVCLevel5       = 0x4000;
3950         public static final int AVCLevel51      = 0x8000;
3951         public static final int AVCLevel52      = 0x10000;
3952         public static final int AVCLevel6       = 0x20000;
3953         public static final int AVCLevel61      = 0x40000;
3954         public static final int AVCLevel62      = 0x80000;
3955 
3956         public static final int H263ProfileBaseline             = 0x01;
3957         public static final int H263ProfileH320Coding           = 0x02;
3958         public static final int H263ProfileBackwardCompatible   = 0x04;
3959         public static final int H263ProfileISWV2                = 0x08;
3960         public static final int H263ProfileISWV3                = 0x10;
3961         public static final int H263ProfileHighCompression      = 0x20;
3962         public static final int H263ProfileInternet             = 0x40;
3963         public static final int H263ProfileInterlace            = 0x80;
3964         public static final int H263ProfileHighLatency          = 0x100;
3965 
3966         public static final int H263Level10      = 0x01;
3967         public static final int H263Level20      = 0x02;
3968         public static final int H263Level30      = 0x04;
3969         public static final int H263Level40      = 0x08;
3970         public static final int H263Level45      = 0x10;
3971         public static final int H263Level50      = 0x20;
3972         public static final int H263Level60      = 0x40;
3973         public static final int H263Level70      = 0x80;
3974 
3975         public static final int MPEG4ProfileSimple              = 0x01;
3976         public static final int MPEG4ProfileSimpleScalable      = 0x02;
3977         public static final int MPEG4ProfileCore                = 0x04;
3978         public static final int MPEG4ProfileMain                = 0x08;
3979         public static final int MPEG4ProfileNbit                = 0x10;
3980         public static final int MPEG4ProfileScalableTexture     = 0x20;
3981         public static final int MPEG4ProfileSimpleFace          = 0x40;
3982         public static final int MPEG4ProfileSimpleFBA           = 0x80;
3983         public static final int MPEG4ProfileBasicAnimated       = 0x100;
3984         public static final int MPEG4ProfileHybrid              = 0x200;
3985         public static final int MPEG4ProfileAdvancedRealTime    = 0x400;
3986         public static final int MPEG4ProfileCoreScalable        = 0x800;
3987         public static final int MPEG4ProfileAdvancedCoding      = 0x1000;
3988         public static final int MPEG4ProfileAdvancedCore        = 0x2000;
3989         public static final int MPEG4ProfileAdvancedScalable    = 0x4000;
3990         public static final int MPEG4ProfileAdvancedSimple      = 0x8000;
3991 
3992         public static final int MPEG4Level0      = 0x01;
3993         public static final int MPEG4Level0b     = 0x02;
3994         public static final int MPEG4Level1      = 0x04;
3995         public static final int MPEG4Level2      = 0x08;
3996         public static final int MPEG4Level3      = 0x10;
3997         public static final int MPEG4Level3b     = 0x18;
3998         public static final int MPEG4Level4      = 0x20;
3999         public static final int MPEG4Level4a     = 0x40;
4000         public static final int MPEG4Level5      = 0x80;
4001         public static final int MPEG4Level6      = 0x100;
4002 
4003         public static final int MPEG2ProfileSimple              = 0x00;
4004         public static final int MPEG2ProfileMain                = 0x01;
4005         public static final int MPEG2Profile422                 = 0x02;
4006         public static final int MPEG2ProfileSNR                 = 0x03;
4007         public static final int MPEG2ProfileSpatial             = 0x04;
4008         public static final int MPEG2ProfileHigh                = 0x05;
4009 
4010         public static final int MPEG2LevelLL     = 0x00;
4011         public static final int MPEG2LevelML     = 0x01;
4012         public static final int MPEG2LevelH14    = 0x02;
4013         public static final int MPEG2LevelHL     = 0x03;
4014         public static final int MPEG2LevelHP     = 0x04;
4015 
4016         public static final int AACObjectMain       = 1;
4017         public static final int AACObjectLC         = 2;
4018         public static final int AACObjectSSR        = 3;
4019         public static final int AACObjectLTP        = 4;
4020         public static final int AACObjectHE         = 5;
4021         public static final int AACObjectScalable   = 6;
4022         public static final int AACObjectERLC       = 17;
4023         public static final int AACObjectERScalable = 20;
4024         public static final int AACObjectLD         = 23;
4025         public static final int AACObjectHE_PS      = 29;
4026         public static final int AACObjectELD        = 39;
4027         /** xHE-AAC (includes USAC) */
4028         public static final int AACObjectXHE        = 42;
4029 
4030         public static final int VP8Level_Version0 = 0x01;
4031         public static final int VP8Level_Version1 = 0x02;
4032         public static final int VP8Level_Version2 = 0x04;
4033         public static final int VP8Level_Version3 = 0x08;
4034 
4035         public static final int VP8ProfileMain = 0x01;
4036 
4037         /** VP9 Profile 0 4:2:0 8-bit */
4038         public static final int VP9Profile0 = 0x01;
4039 
4040         /** VP9 Profile 1 4:2:2 8-bit */
4041         public static final int VP9Profile1 = 0x02;
4042 
4043         /** VP9 Profile 2 4:2:0 10-bit */
4044         public static final int VP9Profile2 = 0x04;
4045 
4046         /** VP9 Profile 3 4:2:2 10-bit */
4047         public static final int VP9Profile3 = 0x08;
4048 
4049         // HDR profiles also support passing HDR metadata
4050         /** VP9 Profile 2 4:2:0 10-bit HDR */
4051         public static final int VP9Profile2HDR = 0x1000;
4052 
4053         /** VP9 Profile 3 4:2:2 10-bit HDR */
4054         public static final int VP9Profile3HDR = 0x2000;
4055 
4056         /** VP9 Profile 2 4:2:0 10-bit HDR10Plus */
4057         public static final int VP9Profile2HDR10Plus = 0x4000;
4058 
4059         /** VP9 Profile 3 4:2:2 10-bit HDR10Plus */
4060         public static final int VP9Profile3HDR10Plus = 0x8000;
4061 
4062         public static final int VP9Level1  = 0x1;
4063         public static final int VP9Level11 = 0x2;
4064         public static final int VP9Level2  = 0x4;
4065         public static final int VP9Level21 = 0x8;
4066         public static final int VP9Level3  = 0x10;
4067         public static final int VP9Level31 = 0x20;
4068         public static final int VP9Level4  = 0x40;
4069         public static final int VP9Level41 = 0x80;
4070         public static final int VP9Level5  = 0x100;
4071         public static final int VP9Level51 = 0x200;
4072         public static final int VP9Level52 = 0x400;
4073         public static final int VP9Level6  = 0x800;
4074         public static final int VP9Level61 = 0x1000;
4075         public static final int VP9Level62 = 0x2000;
4076 
4077         public static final int HEVCProfileMain        = 0x01;
4078         public static final int HEVCProfileMain10      = 0x02;
4079         public static final int HEVCProfileMainStill   = 0x04;
4080         public static final int HEVCProfileMain10HDR10 = 0x1000;
4081         public static final int HEVCProfileMain10HDR10Plus = 0x2000;
4082 
4083         public static final int HEVCMainTierLevel1  = 0x1;
4084         public static final int HEVCHighTierLevel1  = 0x2;
4085         public static final int HEVCMainTierLevel2  = 0x4;
4086         public static final int HEVCHighTierLevel2  = 0x8;
4087         public static final int HEVCMainTierLevel21 = 0x10;
4088         public static final int HEVCHighTierLevel21 = 0x20;
4089         public static final int HEVCMainTierLevel3  = 0x40;
4090         public static final int HEVCHighTierLevel3  = 0x80;
4091         public static final int HEVCMainTierLevel31 = 0x100;
4092         public static final int HEVCHighTierLevel31 = 0x200;
4093         public static final int HEVCMainTierLevel4  = 0x400;
4094         public static final int HEVCHighTierLevel4  = 0x800;
4095         public static final int HEVCMainTierLevel41 = 0x1000;
4096         public static final int HEVCHighTierLevel41 = 0x2000;
4097         public static final int HEVCMainTierLevel5  = 0x4000;
4098         public static final int HEVCHighTierLevel5  = 0x8000;
4099         public static final int HEVCMainTierLevel51 = 0x10000;
4100         public static final int HEVCHighTierLevel51 = 0x20000;
4101         public static final int HEVCMainTierLevel52 = 0x40000;
4102         public static final int HEVCHighTierLevel52 = 0x80000;
4103         public static final int HEVCMainTierLevel6  = 0x100000;
4104         public static final int HEVCHighTierLevel6  = 0x200000;
4105         public static final int HEVCMainTierLevel61 = 0x400000;
4106         public static final int HEVCHighTierLevel61 = 0x800000;
4107         public static final int HEVCMainTierLevel62 = 0x1000000;
4108         public static final int HEVCHighTierLevel62 = 0x2000000;
4109 
4110         private static final int HEVCHighTierLevels =
4111             HEVCHighTierLevel1 | HEVCHighTierLevel2 | HEVCHighTierLevel21 | HEVCHighTierLevel3 |
4112             HEVCHighTierLevel31 | HEVCHighTierLevel4 | HEVCHighTierLevel41 | HEVCHighTierLevel5 |
4113             HEVCHighTierLevel51 | HEVCHighTierLevel52 | HEVCHighTierLevel6 | HEVCHighTierLevel61 |
4114             HEVCHighTierLevel62;
4115 
4116         public static final int DolbyVisionProfileDvavPer = 0x1;
4117         public static final int DolbyVisionProfileDvavPen = 0x2;
4118         public static final int DolbyVisionProfileDvheDer = 0x4;
4119         public static final int DolbyVisionProfileDvheDen = 0x8;
4120         public static final int DolbyVisionProfileDvheDtr = 0x10;
4121         public static final int DolbyVisionProfileDvheStn = 0x20;
4122         public static final int DolbyVisionProfileDvheDth = 0x40;
4123         public static final int DolbyVisionProfileDvheDtb = 0x80;
4124         public static final int DolbyVisionProfileDvheSt  = 0x100;
4125         public static final int DolbyVisionProfileDvavSe  = 0x200;
4126         /** Dolby Vision AV1 profile */
4127         @SuppressLint("AllUpper")
4128         public static final int DolbyVisionProfileDvav110 = 0x400;
4129 
4130         public static final int DolbyVisionLevelHd24    = 0x1;
4131         public static final int DolbyVisionLevelHd30    = 0x2;
4132         public static final int DolbyVisionLevelFhd24   = 0x4;
4133         public static final int DolbyVisionLevelFhd30   = 0x8;
4134         public static final int DolbyVisionLevelFhd60   = 0x10;
4135         public static final int DolbyVisionLevelUhd24   = 0x20;
4136         public static final int DolbyVisionLevelUhd30   = 0x40;
4137         public static final int DolbyVisionLevelUhd48   = 0x80;
4138         public static final int DolbyVisionLevelUhd60   = 0x100;
4139         @SuppressLint("AllUpper")
4140         public static final int DolbyVisionLevelUhd120  = 0x200;
4141         @SuppressLint("AllUpper")
4142         public static final int DolbyVisionLevel8k30    = 0x400;
4143         @SuppressLint("AllUpper")
4144         public static final int DolbyVisionLevel8k60    = 0x800;
4145 
4146         // Profiles and levels for AV1 Codec, corresponding to the definitions in
4147         // "AV1 Bitstream & Decoding Process Specification", Annex A
4148         // found at https://aomedia.org/av1-bitstream-and-decoding-process-specification/
4149 
4150         /**
4151          * AV1 Main profile 4:2:0 8-bit
4152          *
4153          * See definition in
4154          * <a href="https://aomedia.org/av1-bitstream-and-decoding-process-specification/">AV1 Specification</a>
4155          * Annex A.
4156          */
4157         public static final int AV1ProfileMain8   = 0x1;
4158 
4159         /**
4160          * AV1 Main profile 4:2:0 10-bit
4161          *
4162          * See definition in
4163          * <a href="https://aomedia.org/av1-bitstream-and-decoding-process-specification/">AV1 Specification</a>
4164          * Annex A.
4165          */
4166         public static final int AV1ProfileMain10  = 0x2;
4167 
4168 
4169         /** AV1 Main profile 4:2:0 10-bit with HDR10. */
4170         public static final int AV1ProfileMain10HDR10 = 0x1000;
4171 
4172         /** AV1 Main profile 4:2:0 10-bit with HDR10Plus. */
4173         public static final int AV1ProfileMain10HDR10Plus = 0x2000;
4174 
4175         public static final int AV1Level2       = 0x1;
4176         public static final int AV1Level21      = 0x2;
4177         public static final int AV1Level22      = 0x4;
4178         public static final int AV1Level23      = 0x8;
4179         public static final int AV1Level3       = 0x10;
4180         public static final int AV1Level31      = 0x20;
4181         public static final int AV1Level32      = 0x40;
4182         public static final int AV1Level33      = 0x80;
4183         public static final int AV1Level4       = 0x100;
4184         public static final int AV1Level41      = 0x200;
4185         public static final int AV1Level42      = 0x400;
4186         public static final int AV1Level43      = 0x800;
4187         public static final int AV1Level5       = 0x1000;
4188         public static final int AV1Level51      = 0x2000;
4189         public static final int AV1Level52      = 0x4000;
4190         public static final int AV1Level53      = 0x8000;
4191         public static final int AV1Level6       = 0x10000;
4192         public static final int AV1Level61      = 0x20000;
4193         public static final int AV1Level62      = 0x40000;
4194         public static final int AV1Level63      = 0x80000;
4195         public static final int AV1Level7       = 0x100000;
4196         public static final int AV1Level71      = 0x200000;
4197         public static final int AV1Level72      = 0x400000;
4198         public static final int AV1Level73      = 0x800000;
4199 
4200         /** DTS codec profile for DTS HRA. */
4201         @SuppressLint("AllUpper")
4202         public static final int DTS_HDProfileHRA = 0x1;
4203         /** DTS codec profile for DTS Express. */
4204         @SuppressLint("AllUpper")
4205         public static final int DTS_HDProfileLBR = 0x2;
4206         /** DTS codec profile for DTS-HD Master Audio */
4207         @SuppressLint("AllUpper")
4208         public static final int DTS_HDProfileMA = 0x4;
4209         /** DTS codec profile for DTS:X Profile 1 */
4210         @SuppressLint("AllUpper")
4211         public static final int DTS_UHDProfileP1 = 0x1;
4212         /** DTS codec profile for DTS:X Profile 2 */
4213         @SuppressLint("AllUpper")
4214         public static final int DTS_UHDProfileP2 = 0x2;
4215 
4216         // Profiles and levels for AC-4 Codec, corresponding to the definitions in
4217         // "The MIME codecs parameter", Annex E.13
4218         // found at https://www.etsi.org/deliver/etsi_ts/103100_103199/10319002/01.02.01_60/ts_10319002v010201p.pdf
4219         // profile = ((1 << bitstream_version) << 8) | (1 << presentation_version);
4220         // level = 1 << mdcompat;
4221 
4222         @SuppressLint("AllUpper")
4223         private static final int AC4BitstreamVersion0 = 0x01;
4224         @SuppressLint("AllUpper")
4225         private static final int AC4BitstreamVersion1 = 0x02;
4226         @SuppressLint("AllUpper")
4227         private static final int AC4BitstreamVersion2 = 0x04;
4228 
4229         @SuppressLint("AllUpper")
4230         private static final int AC4PresentationVersion0 = 0x01;
4231         @SuppressLint("AllUpper")
4232         private static final int AC4PresentationVersion1 = 0x02;
4233         @SuppressLint("AllUpper")
4234         private static final int AC4PresentationVersion2 = 0x04;
4235 
4236         /**
4237          * AC-4 codec profile with bitstream_version 0 and presentation_version 0
4238          * as per ETSI TS 103 190-2 v1.2.1
4239          */
4240         @SuppressLint("AllUpper")
4241         public static final int AC4Profile00 = AC4BitstreamVersion0 << 8 | AC4PresentationVersion0;
4242 
4243         /**
4244          * AC-4 codec profile with bitstream_version 1 and presentation_version 0
4245          * as per ETSI TS 103 190-2 v1.2.1
4246          */
4247         @SuppressLint("AllUpper")
4248         public static final int AC4Profile10 = AC4BitstreamVersion1 << 8 | AC4PresentationVersion0;
4249 
4250         /**
4251          * AC-4 codec profile with bitstream_version 1 and presentation_version 1
4252          * as per ETSI TS 103 190-2 v1.2.1
4253          */
4254         @SuppressLint("AllUpper")
4255         public static final int AC4Profile11 = AC4BitstreamVersion1 << 8 | AC4PresentationVersion1;
4256 
4257         /**
4258          * AC-4 codec profile with bitstream_version 2 and presentation_version 1
4259          * as per ETSI TS 103 190-2 v1.2.1
4260          */
4261         @SuppressLint("AllUpper")
4262         public static final int AC4Profile21 = AC4BitstreamVersion2 << 8 | AC4PresentationVersion1;
4263 
4264         /**
4265          * AC-4 codec profile with bitstream_version 2 and presentation_version 2
4266          * as per ETSI TS 103 190-2 v1.2.1
4267          */
4268         @SuppressLint("AllUpper")
4269         public static final int AC4Profile22 = AC4BitstreamVersion2 << 8 | AC4PresentationVersion2;
4270 
4271         /** AC-4 codec level corresponding to mdcompat 0 as per ETSI TS 103 190-2 v1.2.1 */
4272         @SuppressLint("AllUpper")
4273         public static final int AC4Level0       = 0x01;
4274         /** AC-4 codec level corresponding to mdcompat 1 as per ETSI TS 103 190-2 v1.2.1 */
4275         @SuppressLint("AllUpper")
4276         public static final int AC4Level1       = 0x02;
4277         /** AC-4 codec level corresponding to mdcompat 2 as per ETSI TS 103 190-2 v1.2.1 */
4278         @SuppressLint("AllUpper")
4279         public static final int AC4Level2       = 0x04;
4280         /** AC-4 codec level corresponding to mdcompat 3 as per ETSI TS 103 190-2 v1.2.1 */
4281         @SuppressLint("AllUpper")
4282         public static final int AC4Level3       = 0x08;
4283         /** AC-4 codec level corresponding to mdcompat 4 as per ETSI TS 103 190-2 v1.2.1 */
4284         @SuppressLint("AllUpper")
4285         public static final int AC4Level4       = 0x10;
4286 
4287         /**
4288          * The profile of the media content. Depending on the type of media this can be
4289          * one of the profile values defined in this class.
4290          */
4291         public int profile;
4292 
4293         /**
4294          * The level of the media content. Depending on the type of media this can be
4295          * one of the level values defined in this class.
4296          *
4297          * Note that VP9 decoder on platforms before {@link android.os.Build.VERSION_CODES#N} may
4298          * not advertise a profile level support. For those VP9 decoders, please use
4299          * {@link VideoCapabilities} to determine the codec capabilities.
4300          */
4301         public int level;
4302 
4303         @Override
equals(Object obj)4304         public boolean equals(Object obj) {
4305             if (obj == null) {
4306                 return false;
4307             }
4308             if (obj instanceof CodecProfileLevel) {
4309                 CodecProfileLevel other = (CodecProfileLevel)obj;
4310                 return other.profile == profile && other.level == level;
4311             }
4312             return false;
4313         }
4314 
4315         @Override
hashCode()4316         public int hashCode() {
4317             return Long.hashCode(((long)profile << Integer.SIZE) | level);
4318         }
4319     };
4320 
4321     /**
4322      * Enumerates the capabilities of the codec component. Since a single
4323      * component can support data of a variety of types, the type has to be
4324      * specified to yield a meaningful result.
4325      * @param type The MIME type to query
4326      */
getCapabilitiesForType( String type)4327     public final CodecCapabilities getCapabilitiesForType(
4328             String type) {
4329         CodecCapabilities caps = mCaps.get(type);
4330         if (caps == null) {
4331             throw new IllegalArgumentException("codec does not support type");
4332         }
4333         // clone writable object
4334         return caps.dup();
4335     }
4336 
4337     /** @hide */
makeRegular()4338     public MediaCodecInfo makeRegular() {
4339         ArrayList<CodecCapabilities> caps = new ArrayList<CodecCapabilities>();
4340         for (CodecCapabilities c: mCaps.values()) {
4341             if (c.isRegular()) {
4342                 caps.add(c);
4343             }
4344         }
4345         if (caps.size() == 0) {
4346             return null;
4347         } else if (caps.size() == mCaps.size()) {
4348             return this;
4349         }
4350 
4351         return new MediaCodecInfo(
4352                 mName, mCanonicalName, mFlags,
4353                 caps.toArray(new CodecCapabilities[caps.size()]));
4354     }
4355 }
4356