• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.media;
18 
19 import 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 
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 
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 */
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 
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 
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 
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 
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 
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 
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 
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          */
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          */
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 
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          */
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 */
3694         private EncoderCapabilities() { }
3695 
3696         /** @hide */
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 
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 
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 
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 
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 */
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 */
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
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
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      */
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 */
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