• 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                 // remove profile from this format otherwise levelCaps.isFormatSupported will
938                 // get into this same conditon and loop forever.
939                 Map<String, Object> mapWithoutProfile = new HashMap<>(map);
940                 mapWithoutProfile.remove(MediaFormat.KEY_PROFILE);
941                 MediaFormat formatWithoutProfile = new MediaFormat(mapWithoutProfile);
942                 if (levelCaps != null && !levelCaps.isFormatSupported(formatWithoutProfile)) {
943                     return false;
944                 }
945             }
946             if (mAudioCaps != null && !mAudioCaps.supportsFormat(format)) {
947                 return false;
948             }
949             if (mVideoCaps != null && !mVideoCaps.supportsFormat(format)) {
950                 return false;
951             }
952             if (mEncoderCaps != null && !mEncoderCaps.supportsFormat(format)) {
953                 return false;
954             }
955             return true;
956         }
957 
supportsBitrate( Range<Integer> bitrateRange, MediaFormat format)958         private static boolean supportsBitrate(
959                 Range<Integer> bitrateRange, MediaFormat format) {
960             Map<String, Object> map = format.getMap();
961 
962             // consider max bitrate over average bitrate for support
963             Integer maxBitrate = (Integer)map.get(MediaFormat.KEY_MAX_BIT_RATE);
964             Integer bitrate = (Integer)map.get(MediaFormat.KEY_BIT_RATE);
965             if (bitrate == null) {
966                 bitrate = maxBitrate;
967             } else if (maxBitrate != null) {
968                 bitrate = Math.max(bitrate, maxBitrate);
969             }
970 
971             if (bitrate != null && bitrate > 0) {
972                 return bitrateRange.contains(bitrate);
973             }
974 
975             return true;
976         }
977 
supportsProfileLevel(int profile, Integer level)978         private boolean supportsProfileLevel(int profile, Integer level) {
979             for (CodecProfileLevel pl: profileLevels) {
980                 if (pl.profile != profile) {
981                     continue;
982                 }
983 
984                 // AAC does not use levels
985                 if (level == null || mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC)) {
986                     return true;
987                 }
988 
989                 // H.263 levels are not completely ordered:
990                 // Level45 support only implies Level10 support
991                 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) {
992                     if (pl.level != level && pl.level == CodecProfileLevel.H263Level45
993                             && level > CodecProfileLevel.H263Level10) {
994                         continue;
995                     }
996                 }
997 
998                 // MPEG4 levels are not completely ordered:
999                 // Level1 support only implies Level0 (and not Level0b) support
1000                 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) {
1001                     if (pl.level != level && pl.level == CodecProfileLevel.MPEG4Level1
1002                             && level > CodecProfileLevel.MPEG4Level0) {
1003                         continue;
1004                     }
1005                 }
1006 
1007                 // HEVC levels incorporate both tiers and levels. Verify tier support.
1008                 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
1009                     boolean supportsHighTier =
1010                         (pl.level & CodecProfileLevel.HEVCHighTierLevels) != 0;
1011                     boolean checkingHighTier = (level & CodecProfileLevel.HEVCHighTierLevels) != 0;
1012                     // high tier levels are only supported by other high tier levels
1013                     if (checkingHighTier && !supportsHighTier) {
1014                         continue;
1015                     }
1016                 }
1017 
1018                 if (pl.level >= level) {
1019                     // if we recognize the listed profile/level, we must also recognize the
1020                     // profile/level arguments.
1021                     if (createFromProfileLevel(mMime, profile, pl.level) != null) {
1022                         return createFromProfileLevel(mMime, profile, level) != null;
1023                     }
1024                     return true;
1025                 }
1026             }
1027             return false;
1028         }
1029 
1030         // errors while reading profile levels - accessed from sister capabilities
1031         int mError;
1032 
1033         private static final String TAG = "CodecCapabilities";
1034 
1035         // NEW-STYLE CAPABILITIES
1036         private AudioCapabilities mAudioCaps;
1037         private VideoCapabilities mVideoCaps;
1038         private EncoderCapabilities mEncoderCaps;
1039         private MediaFormat mDefaultFormat;
1040 
1041         /**
1042          * Returns a MediaFormat object with default values for configurations that have
1043          * defaults.
1044          */
getDefaultFormat()1045         public MediaFormat getDefaultFormat() {
1046             return mDefaultFormat;
1047         }
1048 
1049         /**
1050          * Returns the mime type for which this codec-capability object was created.
1051          */
getMimeType()1052         public String getMimeType() {
1053             return mMime;
1054         }
1055 
1056         /**
1057          * Returns the max number of the supported concurrent codec instances.
1058          * <p>
1059          * This is a hint for an upper bound. Applications should not expect to successfully
1060          * operate more instances than the returned value, but the actual number of
1061          * concurrently operable instances may be less as it depends on the available
1062          * resources at time of use.
1063          */
getMaxSupportedInstances()1064         public int getMaxSupportedInstances() {
1065             return mMaxSupportedInstances;
1066         }
1067 
isAudio()1068         private boolean isAudio() {
1069             return mAudioCaps != null;
1070         }
1071 
1072         /**
1073          * Returns the audio capabilities or {@code null} if this is not an audio codec.
1074          */
getAudioCapabilities()1075         public AudioCapabilities getAudioCapabilities() {
1076             return mAudioCaps;
1077         }
1078 
isEncoder()1079         private boolean isEncoder() {
1080             return mEncoderCaps != null;
1081         }
1082 
1083         /**
1084          * Returns the encoding capabilities or {@code null} if this is not an encoder.
1085          */
getEncoderCapabilities()1086         public EncoderCapabilities getEncoderCapabilities() {
1087             return mEncoderCaps;
1088         }
1089 
isVideo()1090         private boolean isVideo() {
1091             return mVideoCaps != null;
1092         }
1093 
1094         /**
1095          * Returns the video capabilities or {@code null} if this is not a video codec.
1096          */
getVideoCapabilities()1097         public VideoCapabilities getVideoCapabilities() {
1098             return mVideoCaps;
1099         }
1100 
1101         /** @hide */
dup()1102         public CodecCapabilities dup() {
1103             CodecCapabilities caps = new CodecCapabilities();
1104 
1105             // profileLevels and colorFormats may be modified by client.
1106             caps.profileLevels = Arrays.copyOf(profileLevels, profileLevels.length);
1107             caps.colorFormats = Arrays.copyOf(colorFormats, colorFormats.length);
1108 
1109             caps.mMime = mMime;
1110             caps.mMaxSupportedInstances = mMaxSupportedInstances;
1111             caps.mFlagsRequired = mFlagsRequired;
1112             caps.mFlagsSupported = mFlagsSupported;
1113             caps.mFlagsVerified = mFlagsVerified;
1114             caps.mAudioCaps = mAudioCaps;
1115             caps.mVideoCaps = mVideoCaps;
1116             caps.mEncoderCaps = mEncoderCaps;
1117             caps.mDefaultFormat = mDefaultFormat;
1118             caps.mCapabilitiesInfo = mCapabilitiesInfo;
1119 
1120             return caps;
1121         }
1122 
1123         /**
1124          * Retrieve the codec capabilities for a certain {@code mime type}, {@code
1125          * profile} and {@code level}.  If the type, or profile-level combination
1126          * is not understood by the framework, it returns null.
1127          * <p class=note> In {@link android.os.Build.VERSION_CODES#M}, calling this
1128          * method without calling any method of the {@link MediaCodecList} class beforehand
1129          * results in a {@link NullPointerException}.</p>
1130          */
createFromProfileLevel( String mime, int profile, int level)1131         public static CodecCapabilities createFromProfileLevel(
1132                 String mime, int profile, int level) {
1133             CodecProfileLevel pl = new CodecProfileLevel();
1134             pl.profile = profile;
1135             pl.level = level;
1136             MediaFormat defaultFormat = new MediaFormat();
1137             defaultFormat.setString(MediaFormat.KEY_MIME, mime);
1138 
1139             CodecCapabilities ret = new CodecCapabilities(
1140                 new CodecProfileLevel[] { pl }, new int[0], true /* encoder */,
1141                 defaultFormat, new MediaFormat() /* info */);
1142             if (ret.mError != 0) {
1143                 return null;
1144             }
1145             return ret;
1146         }
1147 
CodecCapabilities( CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, Map<String, Object>defaultFormatMap, Map<String, Object>capabilitiesMap)1148         /* package private */ CodecCapabilities(
1149                 CodecProfileLevel[] profLevs, int[] colFmts,
1150                 boolean encoder,
1151                 Map<String, Object>defaultFormatMap,
1152                 Map<String, Object>capabilitiesMap) {
1153             this(profLevs, colFmts, encoder,
1154                     new MediaFormat(defaultFormatMap),
1155                     new MediaFormat(capabilitiesMap));
1156         }
1157 
1158         private MediaFormat mCapabilitiesInfo;
1159 
CodecCapabilities( CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, MediaFormat defaultFormat, MediaFormat info)1160         /* package private */ CodecCapabilities(
1161                 CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder,
1162                 MediaFormat defaultFormat, MediaFormat info) {
1163             final Map<String, Object> map = info.getMap();
1164             colorFormats = colFmts;
1165             mFlagsVerified = 0; // TODO: remove as it is unused
1166             mDefaultFormat = defaultFormat;
1167             mCapabilitiesInfo = info;
1168             mMime = mDefaultFormat.getString(MediaFormat.KEY_MIME);
1169 
1170             /* VP9 introduced profiles around 2016, so some VP9 codecs may not advertise any
1171                supported profiles. Determine the level for them using the info they provide. */
1172             if (profLevs.length == 0 && mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) {
1173                 CodecProfileLevel profLev = new CodecProfileLevel();
1174                 profLev.profile = CodecProfileLevel.VP9Profile0;
1175                 profLev.level = VideoCapabilities.equivalentVP9Level(info);
1176                 profLevs = new CodecProfileLevel[] { profLev };
1177             }
1178             profileLevels = profLevs;
1179 
1180             if (mMime.toLowerCase().startsWith("audio/")) {
1181                 mAudioCaps = AudioCapabilities.create(info, this);
1182                 mAudioCaps.getDefaultFormat(mDefaultFormat);
1183             } else if (mMime.toLowerCase().startsWith("video/")
1184                     || mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC)) {
1185                 mVideoCaps = VideoCapabilities.create(info, this);
1186             }
1187             if (encoder) {
1188                 mEncoderCaps = EncoderCapabilities.create(info, this);
1189                 mEncoderCaps.getDefaultFormat(mDefaultFormat);
1190             }
1191 
1192             final Map<String, Object> global = MediaCodecList.getGlobalSettings();
1193             mMaxSupportedInstances = Utils.parseIntSafely(
1194                     global.get("max-concurrent-instances"), DEFAULT_MAX_SUPPORTED_INSTANCES);
1195 
1196             int maxInstances = Utils.parseIntSafely(
1197                     map.get("max-concurrent-instances"), mMaxSupportedInstances);
1198             mMaxSupportedInstances =
1199                     Range.create(1, MAX_SUPPORTED_INSTANCES_LIMIT).clamp(maxInstances);
1200 
1201             for (Feature feat: getValidFeatures()) {
1202                 String key = MediaFormat.KEY_FEATURE_ + feat.mName;
1203                 Integer yesNo = (Integer)map.get(key);
1204                 if (yesNo == null) {
1205                     continue;
1206                 }
1207                 if (yesNo > 0) {
1208                     mFlagsRequired |= feat.mValue;
1209                 }
1210                 mFlagsSupported |= feat.mValue;
1211                 if (!feat.mInternal) {
1212                     mDefaultFormat.setInteger(key, 1);
1213                 }
1214                 // TODO restrict features by mFlagsVerified once all codecs reliably verify them
1215             }
1216         }
1217     }
1218 
1219     /**
1220      * A class that supports querying the audio capabilities of a codec.
1221      */
1222     public static final class AudioCapabilities {
1223         private static final String TAG = "AudioCapabilities";
1224         private CodecCapabilities mParent;
1225         private Range<Integer> mBitrateRange;
1226 
1227         private int[] mSampleRates;
1228         private Range<Integer>[] mSampleRateRanges;
1229         private Range<Integer>[] mInputChannelRanges;
1230 
1231         private static final int MAX_INPUT_CHANNEL_COUNT = 30;
1232 
1233         /**
1234          * Returns the range of supported bitrates in bits/second.
1235          */
getBitrateRange()1236         public Range<Integer> getBitrateRange() {
1237             return mBitrateRange;
1238         }
1239 
1240         /**
1241          * Returns the array of supported sample rates if the codec
1242          * supports only discrete values.  Otherwise, it returns
1243          * {@code null}.  The array is sorted in ascending order.
1244          */
getSupportedSampleRates()1245         public int[] getSupportedSampleRates() {
1246             return mSampleRates != null ? Arrays.copyOf(mSampleRates, mSampleRates.length) : null;
1247         }
1248 
1249         /**
1250          * Returns the array of supported sample rate ranges.  The
1251          * array is sorted in ascending order, and the ranges are
1252          * distinct.
1253          */
getSupportedSampleRateRanges()1254         public Range<Integer>[] getSupportedSampleRateRanges() {
1255             return Arrays.copyOf(mSampleRateRanges, mSampleRateRanges.length);
1256         }
1257 
1258         /**
1259          * Returns the maximum number of input channels supported.
1260          *
1261          * Through {@link android.os.Build.VERSION_CODES#R}, this method indicated support
1262          * for any number of input channels between 1 and this maximum value.
1263          *
1264          * As of {@link android.os.Build.VERSION_CODES#S},
1265          * the implied lower limit of 1 channel is no longer valid.
1266          * As of {@link android.os.Build.VERSION_CODES#S}, {@link #getMaxInputChannelCount} is
1267          * superseded by {@link #getInputChannelCountRanges},
1268          * which returns an array of ranges of channels.
1269          * The {@link #getMaxInputChannelCount} method will return the highest value
1270          * in the ranges returned by {@link #getInputChannelCountRanges}
1271          *
1272          */
1273         @IntRange(from = 1, to = 255)
getMaxInputChannelCount()1274         public int getMaxInputChannelCount() {
1275             int overall_max = 0;
1276             for (int i = mInputChannelRanges.length - 1; i >= 0; i--) {
1277                 int lmax = mInputChannelRanges[i].getUpper();
1278                 if (lmax > overall_max) {
1279                     overall_max = lmax;
1280                 }
1281             }
1282             return overall_max;
1283         }
1284 
1285         /**
1286          * Returns the minimum number of input channels supported.
1287          * This is often 1, but does vary for certain mime types.
1288          *
1289          * This returns the lowest channel count in the ranges returned by
1290          * {@link #getInputChannelCountRanges}.
1291          */
1292         @IntRange(from = 1, to = 255)
getMinInputChannelCount()1293         public int getMinInputChannelCount() {
1294             int overall_min = MAX_INPUT_CHANNEL_COUNT;
1295             for (int i = mInputChannelRanges.length - 1; i >= 0; i--) {
1296                 int lmin = mInputChannelRanges[i].getLower();
1297                 if (lmin < overall_min) {
1298                     overall_min = lmin;
1299                 }
1300             }
1301             return overall_min;
1302         }
1303 
1304         /*
1305          * Returns an array of ranges representing the number of input channels supported.
1306          * The codec supports any number of input channels within this range.
1307          *
1308          * This supersedes the {@link #getMaxInputChannelCount} method.
1309          *
1310          * For many codecs, this will be a single range [1..N], for some N.
1311          */
1312         @SuppressLint("ArrayReturn")
1313         @NonNull
getInputChannelCountRanges()1314         public Range<Integer>[] getInputChannelCountRanges() {
1315             return Arrays.copyOf(mInputChannelRanges, mInputChannelRanges.length);
1316         }
1317 
1318         /* no public constructor */
AudioCapabilities()1319         private AudioCapabilities() { }
1320 
1321         /** @hide */
create( MediaFormat info, CodecCapabilities parent)1322         public static AudioCapabilities create(
1323                 MediaFormat info, CodecCapabilities parent) {
1324             AudioCapabilities caps = new AudioCapabilities();
1325             caps.init(info, parent);
1326             return caps;
1327         }
1328 
init(MediaFormat info, CodecCapabilities parent)1329         private void init(MediaFormat info, CodecCapabilities parent) {
1330             mParent = parent;
1331             initWithPlatformLimits();
1332             applyLevelLimits();
1333             parseFromInfo(info);
1334         }
1335 
initWithPlatformLimits()1336         private void initWithPlatformLimits() {
1337             mBitrateRange = Range.create(0, Integer.MAX_VALUE);
1338             mInputChannelRanges = new Range[] {Range.create(1, MAX_INPUT_CHANNEL_COUNT)};
1339             // mBitrateRange = Range.create(1, 320000);
1340             final int minSampleRate = SystemProperties.
1341                 getInt("ro.mediacodec.min_sample_rate", 7350);
1342             final int maxSampleRate = SystemProperties.
1343                 getInt("ro.mediacodec.max_sample_rate", 192000);
1344             mSampleRateRanges = new Range[] { Range.create(minSampleRate, maxSampleRate) };
1345             mSampleRates = null;
1346         }
1347 
supports(Integer sampleRate, Integer inputChannels)1348         private boolean supports(Integer sampleRate, Integer inputChannels) {
1349             // channels and sample rates are checked orthogonally
1350             if (inputChannels != null) {
1351                 int ix = Utils.binarySearchDistinctRanges(
1352                         mInputChannelRanges, inputChannels);
1353                 if (ix < 0) {
1354                     return false;
1355                 }
1356             }
1357             if (sampleRate != null) {
1358                 int ix = Utils.binarySearchDistinctRanges(
1359                         mSampleRateRanges, sampleRate);
1360                 if (ix < 0) {
1361                     return false;
1362                 }
1363             }
1364             return true;
1365         }
1366 
1367         /**
1368          * Query whether the sample rate is supported by the codec.
1369          */
isSampleRateSupported(int sampleRate)1370         public boolean isSampleRateSupported(int sampleRate) {
1371             return supports(sampleRate, null);
1372         }
1373 
1374         /** modifies rates */
limitSampleRates(int[] rates)1375         private void limitSampleRates(int[] rates) {
1376             Arrays.sort(rates);
1377             ArrayList<Range<Integer>> ranges = new ArrayList<Range<Integer>>();
1378             for (int rate: rates) {
1379                 if (supports(rate, null /* channels */)) {
1380                     ranges.add(Range.create(rate, rate));
1381                 }
1382             }
1383             mSampleRateRanges = ranges.toArray(new Range[ranges.size()]);
1384             createDiscreteSampleRates();
1385         }
1386 
createDiscreteSampleRates()1387         private void createDiscreteSampleRates() {
1388             mSampleRates = new int[mSampleRateRanges.length];
1389             for (int i = 0; i < mSampleRateRanges.length; i++) {
1390                 mSampleRates[i] = mSampleRateRanges[i].getLower();
1391             }
1392         }
1393 
1394         /** modifies rateRanges */
limitSampleRates(Range<Integer>[] rateRanges)1395         private void limitSampleRates(Range<Integer>[] rateRanges) {
1396             sortDistinctRanges(rateRanges);
1397             mSampleRateRanges = intersectSortedDistinctRanges(mSampleRateRanges, rateRanges);
1398 
1399             // check if all values are discrete
1400             for (Range<Integer> range: mSampleRateRanges) {
1401                 if (!range.getLower().equals(range.getUpper())) {
1402                     mSampleRates = null;
1403                     return;
1404                 }
1405             }
1406             createDiscreteSampleRates();
1407         }
1408 
applyLevelLimits()1409         private void applyLevelLimits() {
1410             int[] sampleRates = null;
1411             Range<Integer> sampleRateRange = null, bitRates = null;
1412             int maxChannels = MAX_INPUT_CHANNEL_COUNT;
1413             String mime = mParent.getMimeType();
1414 
1415             if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MPEG)) {
1416                 sampleRates = new int[] {
1417                         8000, 11025, 12000,
1418                         16000, 22050, 24000,
1419                         32000, 44100, 48000 };
1420                 bitRates = Range.create(8000, 320000);
1421                 maxChannels = 2;
1422             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)) {
1423                 sampleRates = new int[] { 8000 };
1424                 bitRates = Range.create(4750, 12200);
1425                 maxChannels = 1;
1426             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)) {
1427                 sampleRates = new int[] { 16000 };
1428                 bitRates = Range.create(6600, 23850);
1429                 maxChannels = 1;
1430             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC)) {
1431                 sampleRates = new int[] {
1432                         7350, 8000,
1433                         11025, 12000, 16000,
1434                         22050, 24000, 32000,
1435                         44100, 48000, 64000,
1436                         88200, 96000 };
1437                 bitRates = Range.create(8000, 510000);
1438                 maxChannels = 48;
1439             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_VORBIS)) {
1440                 bitRates = Range.create(32000, 500000);
1441                 sampleRateRange = Range.create(8000, 192000);
1442                 maxChannels = 255;
1443             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_OPUS)) {
1444                 bitRates = Range.create(6000, 510000);
1445                 sampleRates = new int[] { 8000, 12000, 16000, 24000, 48000 };
1446                 maxChannels = 255;
1447             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW)) {
1448                 sampleRateRange = Range.create(1, 96000);
1449                 bitRates = Range.create(1, 10000000);
1450                 maxChannels = AudioSystem.OUT_CHANNEL_COUNT_MAX;
1451             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
1452                 sampleRateRange = Range.create(1, 655350);
1453                 // lossless codec, so bitrate is ignored
1454                 maxChannels = 255;
1455             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW)
1456                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)) {
1457                 sampleRates = new int[] { 8000 };
1458                 bitRates = Range.create(64000, 64000);
1459                 // platform allows multiple channels for this format
1460             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) {
1461                 sampleRates = new int[] { 8000 };
1462                 bitRates = Range.create(13000, 13000);
1463                 maxChannels = 1;
1464             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AC3)) {
1465                 maxChannels = 6;
1466             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_EAC3)) {
1467                 maxChannels = 16;
1468             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_EAC3_JOC)) {
1469                 sampleRates = new int[] { 48000 };
1470                 bitRates = Range.create(32000, 6144000);
1471                 maxChannels = 16;
1472             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AC4)) {
1473                 sampleRates = new int[] { 44100, 48000, 96000, 192000 };
1474                 bitRates = Range.create(16000, 2688000);
1475                 maxChannels = 24;
1476             } else {
1477                 Log.w(TAG, "Unsupported mime " + mime);
1478                 mParent.mError |= ERROR_UNSUPPORTED;
1479             }
1480 
1481             // restrict ranges
1482             if (sampleRates != null) {
1483                 limitSampleRates(sampleRates);
1484             } else if (sampleRateRange != null) {
1485                 limitSampleRates(new Range[] { sampleRateRange });
1486             }
1487 
1488             Range<Integer> channelRange = Range.create(1, maxChannels);
1489 
1490             applyLimits(new Range[] { channelRange }, bitRates);
1491         }
1492 
applyLimits(Range<Integer>[] inputChannels, Range<Integer> bitRates)1493         private void applyLimits(Range<Integer>[] inputChannels, Range<Integer> bitRates) {
1494 
1495             // clamp & make a local copy
1496             Range<Integer>[] myInputChannels = new Range[inputChannels.length];
1497             for (int i = 0; i < inputChannels.length; i++) {
1498                 int lower = inputChannels[i].clamp(1);
1499                 int upper = inputChannels[i].clamp(MAX_INPUT_CHANNEL_COUNT);
1500                 myInputChannels[i] = Range.create(lower, upper);
1501             }
1502 
1503             // sort, intersect with existing, & save channel list
1504             sortDistinctRanges(myInputChannels);
1505             Range<Integer>[] joinedChannelList =
1506                             intersectSortedDistinctRanges(myInputChannels, mInputChannelRanges);
1507             mInputChannelRanges = joinedChannelList;
1508 
1509             if (bitRates != null) {
1510                 mBitrateRange = mBitrateRange.intersect(bitRates);
1511             }
1512         }
1513 
parseFromInfo(MediaFormat info)1514         private void parseFromInfo(MediaFormat info) {
1515             int maxInputChannels = MAX_INPUT_CHANNEL_COUNT;
1516             Range<Integer>[] channels = new Range[] { Range.create(1, maxInputChannels)};
1517             Range<Integer> bitRates = POSITIVE_INTEGERS;
1518 
1519             if (info.containsKey("sample-rate-ranges")) {
1520                 String[] rateStrings = info.getString("sample-rate-ranges").split(",");
1521                 Range<Integer>[] rateRanges = new Range[rateStrings.length];
1522                 for (int i = 0; i < rateStrings.length; i++) {
1523                     rateRanges[i] = Utils.parseIntRange(rateStrings[i], null);
1524                 }
1525                 limitSampleRates(rateRanges);
1526             }
1527 
1528             // we will prefer channel-ranges over max-channel-count
1529             if (info.containsKey("channel-ranges")) {
1530                 String[] channelStrings = info.getString("channel-ranges").split(",");
1531                 Range<Integer>[] channelRanges = new Range[channelStrings.length];
1532                 for (int i = 0; i < channelStrings.length; i++) {
1533                     channelRanges[i] = Utils.parseIntRange(channelStrings[i], null);
1534                 }
1535                 channels = channelRanges;
1536             } else if (info.containsKey("channel-range")) {
1537                 Range<Integer> oneRange = Utils.parseIntRange(info.getString("channel-range"),
1538                                                               null);
1539                 channels = new Range[] { oneRange };
1540             } else if (info.containsKey("max-channel-count")) {
1541                 maxInputChannels = Utils.parseIntSafely(
1542                         info.getString("max-channel-count"), maxInputChannels);
1543                 if (maxInputChannels == 0) {
1544                     channels = new Range[] {Range.create(0, 0)};
1545                 } else {
1546                     channels = new Range[] {Range.create(1, maxInputChannels)};
1547                 }
1548             } else if ((mParent.mError & ERROR_UNSUPPORTED) != 0) {
1549                 maxInputChannels = 0;
1550                 channels = new Range[] {Range.create(0, 0)};
1551             }
1552 
1553             if (info.containsKey("bitrate-range")) {
1554                 bitRates = bitRates.intersect(
1555                         Utils.parseIntRange(info.getString("bitrate-range"), bitRates));
1556             }
1557 
1558             applyLimits(channels, bitRates);
1559         }
1560 
1561         /** @hide */
getDefaultFormat(MediaFormat format)1562         public void getDefaultFormat(MediaFormat format) {
1563             // report settings that have only a single choice
1564             if (mBitrateRange.getLower().equals(mBitrateRange.getUpper())) {
1565                 format.setInteger(MediaFormat.KEY_BIT_RATE, mBitrateRange.getLower());
1566             }
1567             if (getMaxInputChannelCount() == 1) {
1568                 // mono-only format
1569                 format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
1570             }
1571             if (mSampleRates != null && mSampleRates.length == 1) {
1572                 format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRates[0]);
1573             }
1574         }
1575 
1576         /** @hide */
supportsFormat(MediaFormat format)1577         public boolean supportsFormat(MediaFormat format) {
1578             Map<String, Object> map = format.getMap();
1579             Integer sampleRate = (Integer)map.get(MediaFormat.KEY_SAMPLE_RATE);
1580             Integer channels = (Integer)map.get(MediaFormat.KEY_CHANNEL_COUNT);
1581 
1582             if (!supports(sampleRate, channels)) {
1583                 return false;
1584             }
1585 
1586             if (!CodecCapabilities.supportsBitrate(mBitrateRange, format)) {
1587                 return false;
1588             }
1589 
1590             // nothing to do for:
1591             // KEY_CHANNEL_MASK: codecs don't get this
1592             // KEY_IS_ADTS:      required feature for all AAC decoders
1593             return true;
1594         }
1595     }
1596 
1597     /**
1598      * A class that supports querying the video capabilities of a codec.
1599      */
1600     public static final class VideoCapabilities {
1601         private static final String TAG = "VideoCapabilities";
1602         private CodecCapabilities mParent;
1603         private Range<Integer> mBitrateRange;
1604 
1605         private Range<Integer> mHeightRange;
1606         private Range<Integer> mWidthRange;
1607         private Range<Integer> mBlockCountRange;
1608         private Range<Integer> mHorizontalBlockRange;
1609         private Range<Integer> mVerticalBlockRange;
1610         private Range<Rational> mAspectRatioRange;
1611         private Range<Rational> mBlockAspectRatioRange;
1612         private Range<Long> mBlocksPerSecondRange;
1613         private Map<Size, Range<Long>> mMeasuredFrameRates;
1614         private List<PerformancePoint> mPerformancePoints;
1615         private Range<Integer> mFrameRateRange;
1616 
1617         private int mBlockWidth;
1618         private int mBlockHeight;
1619         private int mWidthAlignment;
1620         private int mHeightAlignment;
1621         private int mSmallerDimensionUpperLimit;
1622 
1623         private boolean mAllowMbOverride; // allow XML to override calculated limits
1624 
1625         /**
1626          * Returns the range of supported bitrates in bits/second.
1627          */
getBitrateRange()1628         public Range<Integer> getBitrateRange() {
1629             return mBitrateRange;
1630         }
1631 
1632         /**
1633          * Returns the range of supported video widths.
1634          * <p class=note>
1635          * 32-bit processes will not support resolutions larger than 4096x4096 due to
1636          * the limited address space.
1637          */
getSupportedWidths()1638         public Range<Integer> getSupportedWidths() {
1639             return mWidthRange;
1640         }
1641 
1642         /**
1643          * Returns the range of supported video heights.
1644          * <p class=note>
1645          * 32-bit processes will not support resolutions larger than 4096x4096 due to
1646          * the limited address space.
1647          */
getSupportedHeights()1648         public Range<Integer> getSupportedHeights() {
1649             return mHeightRange;
1650         }
1651 
1652         /**
1653          * Returns the alignment requirement for video width (in pixels).
1654          *
1655          * This is a power-of-2 value that video width must be a
1656          * multiple of.
1657          */
getWidthAlignment()1658         public int getWidthAlignment() {
1659             return mWidthAlignment;
1660         }
1661 
1662         /**
1663          * Returns the alignment requirement for video height (in pixels).
1664          *
1665          * This is a power-of-2 value that video height must be a
1666          * multiple of.
1667          */
getHeightAlignment()1668         public int getHeightAlignment() {
1669             return mHeightAlignment;
1670         }
1671 
1672         /**
1673          * Return the upper limit on the smaller dimension of width or height.
1674          * <p></p>
1675          * Some codecs have a limit on the smaller dimension, whether it be
1676          * the width or the height.  E.g. a codec may only be able to handle
1677          * up to 1920x1080 both in landscape and portrait mode (1080x1920).
1678          * In this case the maximum width and height are both 1920, but the
1679          * smaller dimension limit will be 1080. For other codecs, this is
1680          * {@code Math.min(getSupportedWidths().getUpper(),
1681          * getSupportedHeights().getUpper())}.
1682          *
1683          * @hide
1684          */
getSmallerDimensionUpperLimit()1685         public int getSmallerDimensionUpperLimit() {
1686             return mSmallerDimensionUpperLimit;
1687         }
1688 
1689         /**
1690          * Returns the range of supported frame rates.
1691          * <p>
1692          * This is not a performance indicator.  Rather, it expresses the
1693          * limits specified in the coding standard, based on the complexities
1694          * of encoding material for later playback at a certain frame rate,
1695          * or the decoding of such material in non-realtime.
1696          */
getSupportedFrameRates()1697         public Range<Integer> getSupportedFrameRates() {
1698             return mFrameRateRange;
1699         }
1700 
1701         /**
1702          * Returns the range of supported video widths for a video height.
1703          * @param height the height of the video
1704          */
getSupportedWidthsFor(int height)1705         public Range<Integer> getSupportedWidthsFor(int height) {
1706             try {
1707                 Range<Integer> range = mWidthRange;
1708                 if (!mHeightRange.contains(height)
1709                         || (height % mHeightAlignment) != 0) {
1710                     throw new IllegalArgumentException("unsupported height");
1711                 }
1712                 final int heightInBlocks = Utils.divUp(height, mBlockHeight);
1713 
1714                 // constrain by block count and by block aspect ratio
1715                 final int minWidthInBlocks = Math.max(
1716                         Utils.divUp(mBlockCountRange.getLower(), heightInBlocks),
1717                         (int)Math.ceil(mBlockAspectRatioRange.getLower().doubleValue()
1718                                 * heightInBlocks));
1719                 final int maxWidthInBlocks = Math.min(
1720                         mBlockCountRange.getUpper() / heightInBlocks,
1721                         (int)(mBlockAspectRatioRange.getUpper().doubleValue()
1722                                 * heightInBlocks));
1723                 range = range.intersect(
1724                         (minWidthInBlocks - 1) * mBlockWidth + mWidthAlignment,
1725                         maxWidthInBlocks * mBlockWidth);
1726 
1727                 // constrain by smaller dimension limit
1728                 if (height > mSmallerDimensionUpperLimit) {
1729                     range = range.intersect(1, mSmallerDimensionUpperLimit);
1730                 }
1731 
1732                 // constrain by aspect ratio
1733                 range = range.intersect(
1734                         (int)Math.ceil(mAspectRatioRange.getLower().doubleValue()
1735                                 * height),
1736                         (int)(mAspectRatioRange.getUpper().doubleValue() * height));
1737                 return range;
1738             } catch (IllegalArgumentException e) {
1739                 // height is not supported because there are no suitable widths
1740                 Log.v(TAG, "could not get supported widths for " + height);
1741                 throw new IllegalArgumentException("unsupported height");
1742             }
1743         }
1744 
1745         /**
1746          * Returns the range of supported video heights for a video width
1747          * @param width the width of the video
1748          */
getSupportedHeightsFor(int width)1749         public Range<Integer> getSupportedHeightsFor(int width) {
1750             try {
1751                 Range<Integer> range = mHeightRange;
1752                 if (!mWidthRange.contains(width)
1753                         || (width % mWidthAlignment) != 0) {
1754                     throw new IllegalArgumentException("unsupported width");
1755                 }
1756                 final int widthInBlocks = Utils.divUp(width, mBlockWidth);
1757 
1758                 // constrain by block count and by block aspect ratio
1759                 final int minHeightInBlocks = Math.max(
1760                         Utils.divUp(mBlockCountRange.getLower(), widthInBlocks),
1761                         (int)Math.ceil(widthInBlocks /
1762                                 mBlockAspectRatioRange.getUpper().doubleValue()));
1763                 final int maxHeightInBlocks = Math.min(
1764                         mBlockCountRange.getUpper() / widthInBlocks,
1765                         (int)(widthInBlocks /
1766                                 mBlockAspectRatioRange.getLower().doubleValue()));
1767                 range = range.intersect(
1768                         (minHeightInBlocks - 1) * mBlockHeight + mHeightAlignment,
1769                         maxHeightInBlocks * mBlockHeight);
1770 
1771                 // constrain by smaller dimension limit
1772                 if (width > mSmallerDimensionUpperLimit) {
1773                     range = range.intersect(1, mSmallerDimensionUpperLimit);
1774                 }
1775 
1776                 // constrain by aspect ratio
1777                 range = range.intersect(
1778                         (int)Math.ceil(width /
1779                                 mAspectRatioRange.getUpper().doubleValue()),
1780                         (int)(width / mAspectRatioRange.getLower().doubleValue()));
1781                 return range;
1782             } catch (IllegalArgumentException e) {
1783                 // width is not supported because there are no suitable heights
1784                 Log.v(TAG, "could not get supported heights for " + width);
1785                 throw new IllegalArgumentException("unsupported width");
1786             }
1787         }
1788 
1789         /**
1790          * Returns the range of supported video frame rates for a video size.
1791          * <p>
1792          * This is not a performance indicator.  Rather, it expresses the limits specified in
1793          * the coding standard, based on the complexities of encoding material of a given
1794          * size for later playback at a certain frame rate, or the decoding of such material
1795          * in non-realtime.
1796 
1797          * @param width the width of the video
1798          * @param height the height of the video
1799          */
getSupportedFrameRatesFor(int width, int height)1800         public Range<Double> getSupportedFrameRatesFor(int width, int height) {
1801             Range<Integer> range = mHeightRange;
1802             if (!supports(width, height, null)) {
1803                 throw new IllegalArgumentException("unsupported size");
1804             }
1805             final int blockCount =
1806                 Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight);
1807 
1808             return Range.create(
1809                     Math.max(mBlocksPerSecondRange.getLower() / (double) blockCount,
1810                             (double) mFrameRateRange.getLower()),
1811                     Math.min(mBlocksPerSecondRange.getUpper() / (double) blockCount,
1812                             (double) mFrameRateRange.getUpper()));
1813         }
1814 
getBlockCount(int width, int height)1815         private int getBlockCount(int width, int height) {
1816             return Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight);
1817         }
1818 
1819         @NonNull
findClosestSize(int width, int height)1820         private Size findClosestSize(int width, int height) {
1821             int targetBlockCount = getBlockCount(width, height);
1822             Size closestSize = null;
1823             int minDiff = Integer.MAX_VALUE;
1824             for (Size size : mMeasuredFrameRates.keySet()) {
1825                 int diff = Math.abs(targetBlockCount -
1826                         getBlockCount(size.getWidth(), size.getHeight()));
1827                 if (diff < minDiff) {
1828                     minDiff = diff;
1829                     closestSize = size;
1830                 }
1831             }
1832             return closestSize;
1833         }
1834 
estimateFrameRatesFor(int width, int height)1835         private Range<Double> estimateFrameRatesFor(int width, int height) {
1836             Size size = findClosestSize(width, height);
1837             Range<Long> range = mMeasuredFrameRates.get(size);
1838             Double ratio = getBlockCount(size.getWidth(), size.getHeight())
1839                     / (double)Math.max(getBlockCount(width, height), 1);
1840             return Range.create(range.getLower() * ratio, range.getUpper() * ratio);
1841         }
1842 
1843         /**
1844          * Returns the range of achievable video frame rates for a video size.
1845          * May return {@code null}, if the codec did not publish any measurement
1846          * data.
1847          * <p>
1848          * This is a performance estimate provided by the device manufacturer based on statistical
1849          * sampling of full-speed decoding and encoding measurements in various configurations
1850          * of common video sizes supported by the codec. As such it should only be used to
1851          * compare individual codecs on the device. The value is not suitable for comparing
1852          * different devices or even different android releases for the same device.
1853          * <p>
1854          * <em>On {@link android.os.Build.VERSION_CODES#M} release</em> the returned range
1855          * corresponds to the fastest frame rates achieved in the tested configurations. As
1856          * such, it should not be used to gauge guaranteed or even average codec performance
1857          * on the device.
1858          * <p>
1859          * <em>On {@link android.os.Build.VERSION_CODES#N} release</em> the returned range
1860          * corresponds closer to sustained performance <em>in tested configurations</em>.
1861          * One can expect to achieve sustained performance higher than the lower limit more than
1862          * 50% of the time, and higher than half of the lower limit at least 90% of the time
1863          * <em>in tested configurations</em>.
1864          * Conversely, one can expect performance lower than twice the upper limit at least
1865          * 90% of the time.
1866          * <p class=note>
1867          * Tested configurations use a single active codec. For use cases where multiple
1868          * codecs are active, applications can expect lower and in most cases significantly lower
1869          * performance.
1870          * <p class=note>
1871          * The returned range value is interpolated from the nearest frame size(s) tested.
1872          * Codec performance is severely impacted by other activity on the device as well
1873          * as environmental factors (such as battery level, temperature or power source), and can
1874          * vary significantly even in a steady environment.
1875          * <p class=note>
1876          * Use this method in cases where only codec performance matters, e.g. to evaluate if
1877          * a codec has any chance of meeting a performance target. Codecs are listed
1878          * in {@link MediaCodecList} in the preferred order as defined by the device
1879          * manufacturer. As such, applications should use the first suitable codec in the
1880          * list to achieve the best balance between power use and performance.
1881          *
1882          * @param width the width of the video
1883          * @param height the height of the video
1884          *
1885          * @throws IllegalArgumentException if the video size is not supported.
1886          */
1887         @Nullable
getAchievableFrameRatesFor(int width, int height)1888         public Range<Double> getAchievableFrameRatesFor(int width, int height) {
1889             if (!supports(width, height, null)) {
1890                 throw new IllegalArgumentException("unsupported size");
1891             }
1892 
1893             if (mMeasuredFrameRates == null || mMeasuredFrameRates.size() <= 0) {
1894                 Log.w(TAG, "Codec did not publish any measurement data.");
1895                 return null;
1896             }
1897 
1898             return estimateFrameRatesFor(width, height);
1899         }
1900 
1901         /**
1902          * Video performance points are a set of standard performance points defined by number of
1903          * pixels, pixel rate and frame rate. Performance point represents an upper bound. This
1904          * means that it covers all performance points with fewer pixels, pixel rate and frame
1905          * rate.
1906          */
1907         public static final class PerformancePoint {
1908             private Size mBlockSize; // codec block size in macroblocks
1909             private int mWidth; // width in macroblocks
1910             private int mHeight; // height in macroblocks
1911             private int mMaxFrameRate; // max frames per second
1912             private long mMaxMacroBlockRate; // max macro block rate
1913 
1914             /**
1915              * Maximum number of macroblocks in the frame.
1916              *
1917              * Video frames are conceptually divided into 16-by-16 pixel blocks called macroblocks.
1918              * Most coding standards operate on these 16-by-16 pixel blocks; thus, codec performance
1919              * is characterized using such blocks.
1920              *
1921              * @hide
1922              */
1923             @TestApi
getMaxMacroBlocks()1924             public int getMaxMacroBlocks() {
1925                 return saturateLongToInt(mWidth * (long)mHeight);
1926             }
1927 
1928             /**
1929              * Maximum frame rate in frames per second.
1930              *
1931              * @hide
1932              */
1933             @TestApi
getMaxFrameRate()1934             public int getMaxFrameRate() {
1935                 return mMaxFrameRate;
1936             }
1937 
1938             /**
1939              * Maximum number of macroblocks processed per second.
1940              *
1941              * @hide
1942              */
1943             @TestApi
getMaxMacroBlockRate()1944             public long getMaxMacroBlockRate() {
1945                 return mMaxMacroBlockRate;
1946             }
1947 
1948             /** Convert to a debug string */
toString()1949             public String toString() {
1950                 int blockWidth = 16 * mBlockSize.getWidth();
1951                 int blockHeight = 16 * mBlockSize.getHeight();
1952                 int origRate = (int)Utils.divUp(mMaxMacroBlockRate, getMaxMacroBlocks());
1953                 String info = (mWidth * 16) + "x" + (mHeight * 16) + "@" + origRate;
1954                 if (origRate < mMaxFrameRate) {
1955                     info += ", max " + mMaxFrameRate + "fps";
1956                 }
1957                 if (blockWidth > 16 || blockHeight > 16) {
1958                     info += ", " + blockWidth + "x" + blockHeight + " blocks";
1959                 }
1960                 return "PerformancePoint(" + info + ")";
1961             }
1962 
1963             @Override
hashCode()1964             public int hashCode() {
1965                 // only max frame rate must equal between performance points that equal to one
1966                 // another
1967                 return mMaxFrameRate;
1968             }
1969 
1970             /**
1971              * Create a detailed performance point with custom max frame rate and macroblock size.
1972              *
1973              * @param width  frame width in pixels
1974              * @param height frame height in pixels
1975              * @param frameRate frames per second for frame width and height
1976              * @param maxFrameRate maximum frames per second for any frame size
1977              * @param blockSize block size for codec implementation. Must be powers of two in both
1978              *        width and height.
1979              *
1980              * @throws IllegalArgumentException if the blockSize dimensions are not powers of two.
1981              *
1982              * @hide
1983              */
1984             @TestApi
PerformancePoint( int width, int height, int frameRate, int maxFrameRate, @NonNull Size blockSize)1985             public PerformancePoint(
1986                     int width, int height, int frameRate, int maxFrameRate,
1987                     @NonNull Size blockSize) {
1988                 checkPowerOfTwo(blockSize.getWidth(), "block width");
1989                 checkPowerOfTwo(blockSize.getHeight(), "block height");
1990 
1991                 mBlockSize = new Size(Utils.divUp(blockSize.getWidth(), 16),
1992                                       Utils.divUp(blockSize.getHeight(), 16));
1993                 // these are guaranteed not to overflow as we decimate by 16
1994                 mWidth = (int)(Utils.divUp(Math.max(1L, width),
1995                                            Math.max(blockSize.getWidth(), 16))
1996                                * mBlockSize.getWidth());
1997                 mHeight = (int)(Utils.divUp(Math.max(1L, height),
1998                                             Math.max(blockSize.getHeight(), 16))
1999                                 * mBlockSize.getHeight());
2000                 mMaxFrameRate = Math.max(1, Math.max(frameRate, maxFrameRate));
2001                 mMaxMacroBlockRate = Math.max(1, frameRate) * getMaxMacroBlocks();
2002             }
2003 
2004             /**
2005              * Convert a performance point to a larger blocksize.
2006              *
2007              * @param pp performance point
2008              * @param blockSize block size for codec implementation
2009              *
2010              * @hide
2011              */
2012             @TestApi
PerformancePoint(@onNull PerformancePoint pp, @NonNull Size newBlockSize)2013             public PerformancePoint(@NonNull PerformancePoint pp, @NonNull Size newBlockSize) {
2014                 this(
2015                         pp.mWidth * 16, pp.mHeight * 16,
2016                         // guaranteed not to overflow as these were multiplied at construction
2017                         (int)Utils.divUp(pp.mMaxMacroBlockRate, pp.getMaxMacroBlocks()),
2018                         pp.mMaxFrameRate,
2019                         new Size(Math.max(newBlockSize.getWidth(), pp.mBlockSize.getWidth() * 16),
2020                                  Math.max(newBlockSize.getHeight(), pp.mBlockSize.getHeight() * 16))
2021                 );
2022             }
2023 
2024             /**
2025              * Create a performance point for a given frame size and frame rate.
2026              *
2027              * @param width width of the frame in pixels
2028              * @param height height of the frame in pixels
2029              * @param frameRate frame rate in frames per second
2030              */
PerformancePoint(int width, int height, int frameRate)2031             public PerformancePoint(int width, int height, int frameRate) {
2032                 this(width, height, frameRate, frameRate /* maxFrameRate */, new Size(16, 16));
2033             }
2034 
2035             /** Saturates a long value to int */
saturateLongToInt(long value)2036             private int saturateLongToInt(long value) {
2037                 if (value < Integer.MIN_VALUE) {
2038                     return Integer.MIN_VALUE;
2039                 } else if (value > Integer.MAX_VALUE) {
2040                     return Integer.MAX_VALUE;
2041                 } else {
2042                     return (int)value;
2043                 }
2044             }
2045 
2046             /* This method may overflow */
align(int value, int alignment)2047             private int align(int value, int alignment) {
2048                 return Utils.divUp(value, alignment) * alignment;
2049             }
2050 
2051             /** Checks that value is a power of two. */
checkPowerOfTwo2(int value, @NonNull String description)2052             private void checkPowerOfTwo2(int value, @NonNull String description) {
2053                 if (value == 0 || (value & (value - 1)) != 0) {
2054                     throw new IllegalArgumentException(
2055                             description + " (" + value + ") must be a power of 2");
2056                 }
2057             }
2058 
2059             /**
2060              * Checks whether the performance point covers a media format.
2061              *
2062              * @param format Stream format considered
2063              *
2064              * @return {@code true} if the performance point covers the format.
2065              */
covers(@onNull MediaFormat format)2066             public boolean covers(@NonNull MediaFormat format) {
2067                 PerformancePoint other = new PerformancePoint(
2068                         format.getInteger(MediaFormat.KEY_WIDTH, 0),
2069                         format.getInteger(MediaFormat.KEY_HEIGHT, 0),
2070                         // safely convert ceil(double) to int through float cast and Math.round
2071                         Math.round((float)(
2072                                 Math.ceil(format.getNumber(MediaFormat.KEY_FRAME_RATE, 0)
2073                                         .doubleValue()))));
2074                 return covers(other);
2075             }
2076 
2077             /**
2078              * Checks whether the performance point covers another performance point. Use this
2079              * method to determine if a performance point advertised by a codec covers the
2080              * performance point required. This method can also be used for loose ordering as this
2081              * method is transitive.
2082              *
2083              * @param other other performance point considered
2084              *
2085              * @return {@code true} if the performance point covers the other.
2086              */
covers(@onNull PerformancePoint other)2087             public boolean covers(@NonNull PerformancePoint other) {
2088                 // convert performance points to common block size
2089                 Size commonSize = getCommonBlockSize(other);
2090                 PerformancePoint aligned = new PerformancePoint(this, commonSize);
2091                 PerformancePoint otherAligned = new PerformancePoint(other, commonSize);
2092 
2093                 return (aligned.getMaxMacroBlocks() >= otherAligned.getMaxMacroBlocks()
2094                         && aligned.mMaxFrameRate >= otherAligned.mMaxFrameRate
2095                         && aligned.mMaxMacroBlockRate >= otherAligned.mMaxMacroBlockRate);
2096             }
2097 
getCommonBlockSize(@onNull PerformancePoint other)2098             private @NonNull Size getCommonBlockSize(@NonNull PerformancePoint other) {
2099                 return new Size(
2100                         Math.max(mBlockSize.getWidth(), other.mBlockSize.getWidth()) * 16,
2101                         Math.max(mBlockSize.getHeight(), other.mBlockSize.getHeight()) * 16);
2102             }
2103 
2104             @Override
equals(Object o)2105             public boolean equals(Object o) {
2106                 if (o instanceof PerformancePoint) {
2107                     // convert performance points to common block size
2108                     PerformancePoint other = (PerformancePoint)o;
2109                     Size commonSize = getCommonBlockSize(other);
2110                     PerformancePoint aligned = new PerformancePoint(this, commonSize);
2111                     PerformancePoint otherAligned = new PerformancePoint(other, commonSize);
2112 
2113                     return (aligned.getMaxMacroBlocks() == otherAligned.getMaxMacroBlocks()
2114                             && aligned.mMaxFrameRate == otherAligned.mMaxFrameRate
2115                             && aligned.mMaxMacroBlockRate == otherAligned.mMaxMacroBlockRate);
2116                 }
2117                 return false;
2118             }
2119 
2120             /** 480p 24fps */
2121             @NonNull
2122             public static final PerformancePoint SD_24 = new PerformancePoint(720, 480, 24);
2123             /** 576p 25fps */
2124             @NonNull
2125             public static final PerformancePoint SD_25 = new PerformancePoint(720, 576, 25);
2126             /** 480p 30fps */
2127             @NonNull
2128             public static final PerformancePoint SD_30 = new PerformancePoint(720, 480, 30);
2129             /** 480p 48fps */
2130             @NonNull
2131             public static final PerformancePoint SD_48 = new PerformancePoint(720, 480, 48);
2132             /** 576p 50fps */
2133             @NonNull
2134             public static final PerformancePoint SD_50 = new PerformancePoint(720, 576, 50);
2135             /** 480p 60fps */
2136             @NonNull
2137             public static final PerformancePoint SD_60 = new PerformancePoint(720, 480, 60);
2138 
2139             /** 720p 24fps */
2140             @NonNull
2141             public static final PerformancePoint HD_24 = new PerformancePoint(1280, 720, 24);
2142             /** 720p 25fps */
2143             @NonNull
2144             public static final PerformancePoint HD_25 = new PerformancePoint(1280, 720, 25);
2145             /** 720p 30fps */
2146             @NonNull
2147             public static final PerformancePoint HD_30 = new PerformancePoint(1280, 720, 30);
2148             /** 720p 50fps */
2149             @NonNull
2150             public static final PerformancePoint HD_50 = new PerformancePoint(1280, 720, 50);
2151             /** 720p 60fps */
2152             @NonNull
2153             public static final PerformancePoint HD_60 = new PerformancePoint(1280, 720, 60);
2154             /** 720p 100fps */
2155             @NonNull
2156             public static final PerformancePoint HD_100 = new PerformancePoint(1280, 720, 100);
2157             /** 720p 120fps */
2158             @NonNull
2159             public static final PerformancePoint HD_120 = new PerformancePoint(1280, 720, 120);
2160             /** 720p 200fps */
2161             @NonNull
2162             public static final PerformancePoint HD_200 = new PerformancePoint(1280, 720, 200);
2163             /** 720p 240fps */
2164             @NonNull
2165             public static final PerformancePoint HD_240 = new PerformancePoint(1280, 720, 240);
2166 
2167             /** 1080p 24fps */
2168             @NonNull
2169             public static final PerformancePoint FHD_24 = new PerformancePoint(1920, 1080, 24);
2170             /** 1080p 25fps */
2171             @NonNull
2172             public static final PerformancePoint FHD_25 = new PerformancePoint(1920, 1080, 25);
2173             /** 1080p 30fps */
2174             @NonNull
2175             public static final PerformancePoint FHD_30 = new PerformancePoint(1920, 1080, 30);
2176             /** 1080p 50fps */
2177             @NonNull
2178             public static final PerformancePoint FHD_50 = new PerformancePoint(1920, 1080, 50);
2179             /** 1080p 60fps */
2180             @NonNull
2181             public static final PerformancePoint FHD_60 = new PerformancePoint(1920, 1080, 60);
2182             /** 1080p 100fps */
2183             @NonNull
2184             public static final PerformancePoint FHD_100 = new PerformancePoint(1920, 1080, 100);
2185             /** 1080p 120fps */
2186             @NonNull
2187             public static final PerformancePoint FHD_120 = new PerformancePoint(1920, 1080, 120);
2188             /** 1080p 200fps */
2189             @NonNull
2190             public static final PerformancePoint FHD_200 = new PerformancePoint(1920, 1080, 200);
2191             /** 1080p 240fps */
2192             @NonNull
2193             public static final PerformancePoint FHD_240 = new PerformancePoint(1920, 1080, 240);
2194 
2195             /** 2160p 24fps */
2196             @NonNull
2197             public static final PerformancePoint UHD_24 = new PerformancePoint(3840, 2160, 24);
2198             /** 2160p 25fps */
2199             @NonNull
2200             public static final PerformancePoint UHD_25 = new PerformancePoint(3840, 2160, 25);
2201             /** 2160p 30fps */
2202             @NonNull
2203             public static final PerformancePoint UHD_30 = new PerformancePoint(3840, 2160, 30);
2204             /** 2160p 50fps */
2205             @NonNull
2206             public static final PerformancePoint UHD_50 = new PerformancePoint(3840, 2160, 50);
2207             /** 2160p 60fps */
2208             @NonNull
2209             public static final PerformancePoint UHD_60 = new PerformancePoint(3840, 2160, 60);
2210             /** 2160p 100fps */
2211             @NonNull
2212             public static final PerformancePoint UHD_100 = new PerformancePoint(3840, 2160, 100);
2213             /** 2160p 120fps */
2214             @NonNull
2215             public static final PerformancePoint UHD_120 = new PerformancePoint(3840, 2160, 120);
2216             /** 2160p 200fps */
2217             @NonNull
2218             public static final PerformancePoint UHD_200 = new PerformancePoint(3840, 2160, 200);
2219             /** 2160p 240fps */
2220             @NonNull
2221             public static final PerformancePoint UHD_240 = new PerformancePoint(3840, 2160, 240);
2222         }
2223 
2224         /**
2225          * Returns the supported performance points. May return {@code null} if the codec did not
2226          * publish any performance point information (e.g. the vendor codecs have not been updated
2227          * to the latest android release). May return an empty list if the codec published that
2228          * if does not guarantee any performance points.
2229          * <p>
2230          * This is a performance guarantee provided by the device manufacturer for hardware codecs
2231          * based on hardware capabilities of the device.
2232          * <p>
2233          * The returned list is sorted first by decreasing number of pixels, then by decreasing
2234          * width, and finally by decreasing frame rate.
2235          * Performance points assume a single active codec. For use cases where multiple
2236          * codecs are active, should use that highest pixel count, and add the frame rates of
2237          * each individual codec.
2238          * <p class=note>
2239          * 32-bit processes will not support resolutions larger than 4096x4096 due to
2240          * the limited address space, but performance points will be presented as is.
2241          * In other words, even though a component publishes a performance point for
2242          * a resolution higher than 4096x4096, it does not mean that the resolution is supported
2243          * for 32-bit processes.
2244          */
2245         @Nullable
getSupportedPerformancePoints()2246         public List<PerformancePoint> getSupportedPerformancePoints() {
2247             return mPerformancePoints;
2248         }
2249 
2250         /**
2251          * Returns whether a given video size ({@code width} and
2252          * {@code height}) and {@code frameRate} combination is supported.
2253          */
areSizeAndRateSupported( int width, int height, double frameRate)2254         public boolean areSizeAndRateSupported(
2255                 int width, int height, double frameRate) {
2256             return supports(width, height, frameRate);
2257         }
2258 
2259         /**
2260          * Returns whether a given video size ({@code width} and
2261          * {@code height}) is supported.
2262          */
isSizeSupported(int width, int height)2263         public boolean isSizeSupported(int width, int height) {
2264             return supports(width, height, null);
2265         }
2266 
supports(Integer width, Integer height, Number rate)2267         private boolean supports(Integer width, Integer height, Number rate) {
2268             boolean ok = true;
2269 
2270             if (ok && width != null) {
2271                 ok = mWidthRange.contains(width)
2272                         && (width % mWidthAlignment == 0);
2273             }
2274             if (ok && height != null) {
2275                 ok = mHeightRange.contains(height)
2276                         && (height % mHeightAlignment == 0);
2277             }
2278             if (ok && rate != null) {
2279                 ok = mFrameRateRange.contains(Utils.intRangeFor(rate.doubleValue()));
2280             }
2281             if (ok && height != null && width != null) {
2282                 ok = Math.min(height, width) <= mSmallerDimensionUpperLimit;
2283 
2284                 final int widthInBlocks = Utils.divUp(width, mBlockWidth);
2285                 final int heightInBlocks = Utils.divUp(height, mBlockHeight);
2286                 final int blockCount = widthInBlocks * heightInBlocks;
2287                 ok = ok && mBlockCountRange.contains(blockCount)
2288                         && mBlockAspectRatioRange.contains(
2289                                 new Rational(widthInBlocks, heightInBlocks))
2290                         && mAspectRatioRange.contains(new Rational(width, height));
2291                 if (ok && rate != null) {
2292                     double blocksPerSec = blockCount * rate.doubleValue();
2293                     ok = mBlocksPerSecondRange.contains(
2294                             Utils.longRangeFor(blocksPerSec));
2295                 }
2296             }
2297             return ok;
2298         }
2299 
2300         /**
2301          * @hide
2302          * @throws java.lang.ClassCastException */
supportsFormat(MediaFormat format)2303         public boolean supportsFormat(MediaFormat format) {
2304             final Map<String, Object> map = format.getMap();
2305             Integer width = (Integer)map.get(MediaFormat.KEY_WIDTH);
2306             Integer height = (Integer)map.get(MediaFormat.KEY_HEIGHT);
2307             Number rate = (Number)map.get(MediaFormat.KEY_FRAME_RATE);
2308 
2309             if (!supports(width, height, rate)) {
2310                 return false;
2311             }
2312 
2313             if (!CodecCapabilities.supportsBitrate(mBitrateRange, format)) {
2314                 return false;
2315             }
2316 
2317             // we ignore color-format for now as it is not reliably reported by codec
2318             return true;
2319         }
2320 
2321         /* no public constructor */
VideoCapabilities()2322         private VideoCapabilities() { }
2323 
2324         /** @hide */
2325         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
create( MediaFormat info, CodecCapabilities parent)2326         public static VideoCapabilities create(
2327                 MediaFormat info, CodecCapabilities parent) {
2328             VideoCapabilities caps = new VideoCapabilities();
2329             caps.init(info, parent);
2330             return caps;
2331         }
2332 
init(MediaFormat info, CodecCapabilities parent)2333         private void init(MediaFormat info, CodecCapabilities parent) {
2334             mParent = parent;
2335             initWithPlatformLimits();
2336             applyLevelLimits();
2337             parseFromInfo(info);
2338             updateLimits();
2339         }
2340 
2341         /** @hide */
getBlockSize()2342         public Size getBlockSize() {
2343             return new Size(mBlockWidth, mBlockHeight);
2344         }
2345 
2346         /** @hide */
getBlockCountRange()2347         public Range<Integer> getBlockCountRange() {
2348             return mBlockCountRange;
2349         }
2350 
2351         /** @hide */
getBlocksPerSecondRange()2352         public Range<Long> getBlocksPerSecondRange() {
2353             return mBlocksPerSecondRange;
2354         }
2355 
2356         /** @hide */
getAspectRatioRange(boolean blocks)2357         public Range<Rational> getAspectRatioRange(boolean blocks) {
2358             return blocks ? mBlockAspectRatioRange : mAspectRatioRange;
2359         }
2360 
initWithPlatformLimits()2361         private void initWithPlatformLimits() {
2362             mBitrateRange = BITRATE_RANGE;
2363 
2364             mWidthRange  = getSizeRange();
2365             mHeightRange = getSizeRange();
2366             mFrameRateRange = FRAME_RATE_RANGE;
2367 
2368             mHorizontalBlockRange = getSizeRange();
2369             mVerticalBlockRange   = getSizeRange();
2370 
2371             // full positive ranges are supported as these get calculated
2372             mBlockCountRange      = POSITIVE_INTEGERS;
2373             mBlocksPerSecondRange = POSITIVE_LONGS;
2374 
2375             mBlockAspectRatioRange = POSITIVE_RATIONALS;
2376             mAspectRatioRange      = POSITIVE_RATIONALS;
2377 
2378             // YUV 4:2:0 requires 2:2 alignment
2379             mWidthAlignment = 2;
2380             mHeightAlignment = 2;
2381             mBlockWidth = 2;
2382             mBlockHeight = 2;
2383             mSmallerDimensionUpperLimit = getSizeRange().getUpper();
2384         }
2385 
getPerformancePoints(Map<String, Object> map)2386         private @Nullable List<PerformancePoint> getPerformancePoints(Map<String, Object> map) {
2387             Vector<PerformancePoint> ret = new Vector<>();
2388             final String prefix = "performance-point-";
2389             Set<String> keys = map.keySet();
2390             for (String key : keys) {
2391                 // looking for: performance-point-WIDTHxHEIGHT-range
2392                 if (!key.startsWith(prefix)) {
2393                     continue;
2394                 }
2395                 String subKey = key.substring(prefix.length());
2396                 if (subKey.equals("none") && ret.size() == 0) {
2397                     // This means that component knowingly did not publish performance points.
2398                     // This is different from when the component forgot to publish performance
2399                     // points.
2400                     return Collections.unmodifiableList(ret);
2401                 }
2402                 String[] temp = key.split("-");
2403                 if (temp.length != 4) {
2404                     continue;
2405                 }
2406                 String sizeStr = temp[2];
2407                 Size size = Utils.parseSize(sizeStr, null);
2408                 if (size == null || size.getWidth() * size.getHeight() <= 0) {
2409                     continue;
2410                 }
2411                 Range<Long> range = Utils.parseLongRange(map.get(key), null);
2412                 if (range == null || range.getLower() < 0 || range.getUpper() < 0) {
2413                     continue;
2414                 }
2415                 PerformancePoint given = new PerformancePoint(
2416                         size.getWidth(), size.getHeight(), range.getLower().intValue(),
2417                         range.getUpper().intValue(), new Size(mBlockWidth, mBlockHeight));
2418                 PerformancePoint rotated = new PerformancePoint(
2419                         size.getHeight(), size.getWidth(), range.getLower().intValue(),
2420                         range.getUpper().intValue(), new Size(mBlockWidth, mBlockHeight));
2421                 ret.add(given);
2422                 if (!given.covers(rotated)) {
2423                     ret.add(rotated);
2424                 }
2425             }
2426 
2427             // check if the component specified no performance point indication
2428             if (ret.size() == 0) {
2429                 return null;
2430             }
2431 
2432             // sort reversed by area first, then by frame rate
2433             ret.sort((a, b) ->
2434                      -((a.getMaxMacroBlocks() != b.getMaxMacroBlocks()) ?
2435                                (a.getMaxMacroBlocks() < b.getMaxMacroBlocks() ? -1 : 1) :
2436                        (a.getMaxMacroBlockRate() != b.getMaxMacroBlockRate()) ?
2437                                (a.getMaxMacroBlockRate() < b.getMaxMacroBlockRate() ? -1 : 1) :
2438                        (a.getMaxFrameRate() != b.getMaxFrameRate()) ?
2439                                (a.getMaxFrameRate() < b.getMaxFrameRate() ? -1 : 1) : 0));
2440 
2441             return Collections.unmodifiableList(ret);
2442         }
2443 
2444         private Map<Size, Range<Long>> getMeasuredFrameRates(Map<String, Object> map) {
2445             Map<Size, Range<Long>> ret = new HashMap<Size, Range<Long>>();
2446             final String prefix = "measured-frame-rate-";
2447             Set<String> keys = map.keySet();
2448             for (String key : keys) {
2449                 // looking for: measured-frame-rate-WIDTHxHEIGHT-range
2450                 if (!key.startsWith(prefix)) {
2451                     continue;
2452                 }
2453                 String subKey = key.substring(prefix.length());
2454                 String[] temp = key.split("-");
2455                 if (temp.length != 5) {
2456                     continue;
2457                 }
2458                 String sizeStr = temp[3];
2459                 Size size = Utils.parseSize(sizeStr, null);
2460                 if (size == null || size.getWidth() * size.getHeight() <= 0) {
2461                     continue;
2462                 }
2463                 Range<Long> range = Utils.parseLongRange(map.get(key), null);
2464                 if (range == null || range.getLower() < 0 || range.getUpper() < 0) {
2465                     continue;
2466                 }
2467                 ret.put(size, range);
2468             }
2469             return ret;
2470         }
2471 
2472         private static Pair<Range<Integer>, Range<Integer>> parseWidthHeightRanges(Object o) {
2473             Pair<Size, Size> range = Utils.parseSizeRange(o);
2474             if (range != null) {
2475                 try {
2476                     return Pair.create(
2477                             Range.create(range.first.getWidth(), range.second.getWidth()),
2478                             Range.create(range.first.getHeight(), range.second.getHeight()));
2479                 } catch (IllegalArgumentException e) {
2480                     Log.w(TAG, "could not parse size range '" + o + "'");
2481                 }
2482             }
2483             return null;
2484         }
2485 
2486         /** @hide */
2487         public static int equivalentVP9Level(MediaFormat info) {
2488             final Map<String, Object> map = info.getMap();
2489 
2490             Size blockSize = Utils.parseSize(map.get("block-size"), new Size(8, 8));
2491             int BS = blockSize.getWidth() * blockSize.getHeight();
2492 
2493             Range<Integer> counts = Utils.parseIntRange(map.get("block-count-range"), null);
2494             int FS = counts == null ? 0 : BS * counts.getUpper();
2495 
2496             Range<Long> blockRates =
2497                 Utils.parseLongRange(map.get("blocks-per-second-range"), null);
2498             long SR = blockRates == null ? 0 : BS * blockRates.getUpper();
2499 
2500             Pair<Range<Integer>, Range<Integer>> dimensionRanges =
2501                 parseWidthHeightRanges(map.get("size-range"));
2502             int D = dimensionRanges == null ? 0 : Math.max(
2503                     dimensionRanges.first.getUpper(), dimensionRanges.second.getUpper());
2504 
2505             Range<Integer> bitRates = Utils.parseIntRange(map.get("bitrate-range"), null);
2506             int BR = bitRates == null ? 0 : Utils.divUp(bitRates.getUpper(), 1000);
2507 
2508             if (SR <=      829440 && FS <=    36864 && BR <=    200 && D <=   512)
2509                 return CodecProfileLevel.VP9Level1;
2510             if (SR <=     2764800 && FS <=    73728 && BR <=    800 && D <=   768)
2511                 return CodecProfileLevel.VP9Level11;
2512             if (SR <=     4608000 && FS <=   122880 && BR <=   1800 && D <=   960)
2513                 return CodecProfileLevel.VP9Level2;
2514             if (SR <=     9216000 && FS <=   245760 && BR <=   3600 && D <=  1344)
2515                 return CodecProfileLevel.VP9Level21;
2516             if (SR <=    20736000 && FS <=   552960 && BR <=   7200 && D <=  2048)
2517                 return CodecProfileLevel.VP9Level3;
2518             if (SR <=    36864000 && FS <=   983040 && BR <=  12000 && D <=  2752)
2519                 return CodecProfileLevel.VP9Level31;
2520             if (SR <=    83558400 && FS <=  2228224 && BR <=  18000 && D <=  4160)
2521                 return CodecProfileLevel.VP9Level4;
2522             if (SR <=   160432128 && FS <=  2228224 && BR <=  30000 && D <=  4160)
2523                 return CodecProfileLevel.VP9Level41;
2524             if (SR <=   311951360 && FS <=  8912896 && BR <=  60000 && D <=  8384)
2525                 return CodecProfileLevel.VP9Level5;
2526             if (SR <=   588251136 && FS <=  8912896 && BR <= 120000 && D <=  8384)
2527                 return CodecProfileLevel.VP9Level51;
2528             if (SR <=  1176502272 && FS <=  8912896 && BR <= 180000 && D <=  8384)
2529                 return CodecProfileLevel.VP9Level52;
2530             if (SR <=  1176502272 && FS <= 35651584 && BR <= 180000 && D <= 16832)
2531                 return CodecProfileLevel.VP9Level6;
2532             if (SR <= 2353004544L && FS <= 35651584 && BR <= 240000 && D <= 16832)
2533                 return CodecProfileLevel.VP9Level61;
2534             if (SR <= 4706009088L && FS <= 35651584 && BR <= 480000 && D <= 16832)
2535                 return CodecProfileLevel.VP9Level62;
2536             // returning largest level
2537             return CodecProfileLevel.VP9Level62;
2538         }
2539 
2540         private void parseFromInfo(MediaFormat info) {
2541             final Map<String, Object> map = info.getMap();
2542             Size blockSize = new Size(mBlockWidth, mBlockHeight);
2543             Size alignment = new Size(mWidthAlignment, mHeightAlignment);
2544             Range<Integer> counts = null, widths = null, heights = null;
2545             Range<Integer> frameRates = null, bitRates = null;
2546             Range<Long> blockRates = null;
2547             Range<Rational> ratios = null, blockRatios = null;
2548 
2549             blockSize = Utils.parseSize(map.get("block-size"), blockSize);
2550             alignment = Utils.parseSize(map.get("alignment"), alignment);
2551             counts = Utils.parseIntRange(map.get("block-count-range"), null);
2552             blockRates =
2553                 Utils.parseLongRange(map.get("blocks-per-second-range"), null);
2554             mMeasuredFrameRates = getMeasuredFrameRates(map);
2555             mPerformancePoints = getPerformancePoints(map);
2556             Pair<Range<Integer>, Range<Integer>> sizeRanges =
2557                 parseWidthHeightRanges(map.get("size-range"));
2558             if (sizeRanges != null) {
2559                 widths = sizeRanges.first;
2560                 heights = sizeRanges.second;
2561             }
2562             // for now this just means using the smaller max size as 2nd
2563             // upper limit.
2564             // for now we are keeping the profile specific "width/height
2565             // in macroblocks" limits.
2566             if (map.containsKey("feature-can-swap-width-height")) {
2567                 if (widths != null) {
2568                     mSmallerDimensionUpperLimit =
2569                         Math.min(widths.getUpper(), heights.getUpper());
2570                     widths = heights = widths.extend(heights);
2571                 } else {
2572                     Log.w(TAG, "feature can-swap-width-height is best used with size-range");
2573                     mSmallerDimensionUpperLimit =
2574                         Math.min(mWidthRange.getUpper(), mHeightRange.getUpper());
2575                     mWidthRange = mHeightRange = mWidthRange.extend(mHeightRange);
2576                 }
2577             }
2578 
2579             ratios = Utils.parseRationalRange(
2580                     map.get("block-aspect-ratio-range"), null);
2581             blockRatios = Utils.parseRationalRange(
2582                     map.get("pixel-aspect-ratio-range"), null);
2583             frameRates = Utils.parseIntRange(map.get("frame-rate-range"), null);
2584             if (frameRates != null) {
2585                 try {
2586                     frameRates = frameRates.intersect(FRAME_RATE_RANGE);
2587                 } catch (IllegalArgumentException e) {
2588                     Log.w(TAG, "frame rate range (" + frameRates
2589                             + ") is out of limits: " + FRAME_RATE_RANGE);
2590                     frameRates = null;
2591                 }
2592             }
2593             bitRates = Utils.parseIntRange(map.get("bitrate-range"), null);
2594             if (bitRates != null) {
2595                 try {
2596                     bitRates = bitRates.intersect(BITRATE_RANGE);
2597                 } catch (IllegalArgumentException e) {
2598                     Log.w(TAG,  "bitrate range (" + bitRates
2599                             + ") is out of limits: " + BITRATE_RANGE);
2600                     bitRates = null;
2601                 }
2602             }
2603 
2604             checkPowerOfTwo(
2605                     blockSize.getWidth(), "block-size width must be power of two");
2606             checkPowerOfTwo(
2607                     blockSize.getHeight(), "block-size height must be power of two");
2608 
2609             checkPowerOfTwo(
2610                     alignment.getWidth(), "alignment width must be power of two");
2611             checkPowerOfTwo(
2612                     alignment.getHeight(), "alignment height must be power of two");
2613 
2614             // update block-size and alignment
2615             applyMacroBlockLimits(
2616                     Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE,
2617                     Long.MAX_VALUE, blockSize.getWidth(), blockSize.getHeight(),
2618                     alignment.getWidth(), alignment.getHeight());
2619 
2620             if ((mParent.mError & ERROR_UNSUPPORTED) != 0 || mAllowMbOverride) {
2621                 // codec supports profiles that we don't know.
2622                 // Use supplied values clipped to platform limits
2623                 if (widths != null) {
2624                     mWidthRange = getSizeRange().intersect(widths);
2625                 }
2626                 if (heights != null) {
2627                     mHeightRange = getSizeRange().intersect(heights);
2628                 }
2629                 if (counts != null) {
2630                     mBlockCountRange = POSITIVE_INTEGERS.intersect(
2631                             Utils.factorRange(counts, mBlockWidth * mBlockHeight
2632                                     / blockSize.getWidth() / blockSize.getHeight()));
2633                 }
2634                 if (blockRates != null) {
2635                     mBlocksPerSecondRange = POSITIVE_LONGS.intersect(
2636                             Utils.factorRange(blockRates, mBlockWidth * mBlockHeight
2637                                     / blockSize.getWidth() / blockSize.getHeight()));
2638                 }
2639                 if (blockRatios != null) {
2640                     mBlockAspectRatioRange = POSITIVE_RATIONALS.intersect(
2641                             Utils.scaleRange(blockRatios,
2642                                     mBlockHeight / blockSize.getHeight(),
2643                                     mBlockWidth / blockSize.getWidth()));
2644                 }
2645                 if (ratios != null) {
2646                     mAspectRatioRange = POSITIVE_RATIONALS.intersect(ratios);
2647                 }
2648                 if (frameRates != null) {
2649                     mFrameRateRange = FRAME_RATE_RANGE.intersect(frameRates);
2650                 }
2651                 if (bitRates != null) {
2652                     // only allow bitrate override if unsupported profiles were encountered
2653                     if ((mParent.mError & ERROR_UNSUPPORTED) != 0) {
2654                         mBitrateRange = BITRATE_RANGE.intersect(bitRates);
2655                     } else {
2656                         mBitrateRange = mBitrateRange.intersect(bitRates);
2657                     }
2658                 }
2659             } else {
2660                 // no unsupported profile/levels, so restrict values to known limits
2661                 if (widths != null) {
2662                     mWidthRange = mWidthRange.intersect(widths);
2663                 }
2664                 if (heights != null) {
2665                     mHeightRange = mHeightRange.intersect(heights);
2666                 }
2667                 if (counts != null) {
2668                     mBlockCountRange = mBlockCountRange.intersect(
2669                             Utils.factorRange(counts, mBlockWidth * mBlockHeight
2670                                     / blockSize.getWidth() / blockSize.getHeight()));
2671                 }
2672                 if (blockRates != null) {
2673                     mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(
2674                             Utils.factorRange(blockRates, mBlockWidth * mBlockHeight
2675                                     / blockSize.getWidth() / blockSize.getHeight()));
2676                 }
2677                 if (blockRatios != null) {
2678                     mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(
2679                             Utils.scaleRange(blockRatios,
2680                                     mBlockHeight / blockSize.getHeight(),
2681                                     mBlockWidth / blockSize.getWidth()));
2682                 }
2683                 if (ratios != null) {
2684                     mAspectRatioRange = mAspectRatioRange.intersect(ratios);
2685                 }
2686                 if (frameRates != null) {
2687                     mFrameRateRange = mFrameRateRange.intersect(frameRates);
2688                 }
2689                 if (bitRates != null) {
2690                     mBitrateRange = mBitrateRange.intersect(bitRates);
2691                 }
2692             }
2693             updateLimits();
2694         }
2695 
2696         private void applyBlockLimits(
2697                 int blockWidth, int blockHeight,
2698                 Range<Integer> counts, Range<Long> rates, Range<Rational> ratios) {
2699             checkPowerOfTwo(blockWidth, "blockWidth must be a power of two");
2700             checkPowerOfTwo(blockHeight, "blockHeight must be a power of two");
2701 
2702             final int newBlockWidth = Math.max(blockWidth, mBlockWidth);
2703             final int newBlockHeight = Math.max(blockHeight, mBlockHeight);
2704 
2705             // factor will always be a power-of-2
2706             int factor =
2707                 newBlockWidth * newBlockHeight / mBlockWidth / mBlockHeight;
2708             if (factor != 1) {
2709                 mBlockCountRange = Utils.factorRange(mBlockCountRange, factor);
2710                 mBlocksPerSecondRange = Utils.factorRange(
2711                         mBlocksPerSecondRange, factor);
2712                 mBlockAspectRatioRange = Utils.scaleRange(
2713                         mBlockAspectRatioRange,
2714                         newBlockHeight / mBlockHeight,
2715                         newBlockWidth / mBlockWidth);
2716                 mHorizontalBlockRange = Utils.factorRange(
2717                         mHorizontalBlockRange, newBlockWidth / mBlockWidth);
2718                 mVerticalBlockRange = Utils.factorRange(
2719                         mVerticalBlockRange, newBlockHeight / mBlockHeight);
2720             }
2721             factor = newBlockWidth * newBlockHeight / blockWidth / blockHeight;
2722             if (factor != 1) {
2723                 counts = Utils.factorRange(counts, factor);
2724                 rates = Utils.factorRange(rates, factor);
2725                 ratios = Utils.scaleRange(
2726                         ratios, newBlockHeight / blockHeight,
2727                         newBlockWidth / blockWidth);
2728             }
2729             mBlockCountRange = mBlockCountRange.intersect(counts);
2730             mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(rates);
2731             mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(ratios);
2732             mBlockWidth = newBlockWidth;
2733             mBlockHeight = newBlockHeight;
2734         }
2735 
2736         private void applyAlignment(int widthAlignment, int heightAlignment) {
2737             checkPowerOfTwo(widthAlignment, "widthAlignment must be a power of two");
2738             checkPowerOfTwo(heightAlignment, "heightAlignment must be a power of two");
2739 
2740             if (widthAlignment > mBlockWidth || heightAlignment > mBlockHeight) {
2741                 // maintain assumption that 0 < alignment <= block-size
2742                 applyBlockLimits(
2743                         Math.max(widthAlignment, mBlockWidth),
2744                         Math.max(heightAlignment, mBlockHeight),
2745                         POSITIVE_INTEGERS, POSITIVE_LONGS, POSITIVE_RATIONALS);
2746             }
2747 
2748             mWidthAlignment = Math.max(widthAlignment, mWidthAlignment);
2749             mHeightAlignment = Math.max(heightAlignment, mHeightAlignment);
2750 
2751             mWidthRange = Utils.alignRange(mWidthRange, mWidthAlignment);
2752             mHeightRange = Utils.alignRange(mHeightRange, mHeightAlignment);
2753         }
2754 
2755         private void updateLimits() {
2756             // pixels -> blocks <- counts
2757             mHorizontalBlockRange = mHorizontalBlockRange.intersect(
2758                     Utils.factorRange(mWidthRange, mBlockWidth));
2759             mHorizontalBlockRange = mHorizontalBlockRange.intersect(
2760                     Range.create(
2761                             mBlockCountRange.getLower() / mVerticalBlockRange.getUpper(),
2762                             mBlockCountRange.getUpper() / mVerticalBlockRange.getLower()));
2763             mVerticalBlockRange = mVerticalBlockRange.intersect(
2764                     Utils.factorRange(mHeightRange, mBlockHeight));
2765             mVerticalBlockRange = mVerticalBlockRange.intersect(
2766                     Range.create(
2767                             mBlockCountRange.getLower() / mHorizontalBlockRange.getUpper(),
2768                             mBlockCountRange.getUpper() / mHorizontalBlockRange.getLower()));
2769             mBlockCountRange = mBlockCountRange.intersect(
2770                     Range.create(
2771                             mHorizontalBlockRange.getLower()
2772                                     * mVerticalBlockRange.getLower(),
2773                             mHorizontalBlockRange.getUpper()
2774                                     * mVerticalBlockRange.getUpper()));
2775             mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(
2776                     new Rational(
2777                             mHorizontalBlockRange.getLower(), mVerticalBlockRange.getUpper()),
2778                     new Rational(
2779                             mHorizontalBlockRange.getUpper(), mVerticalBlockRange.getLower()));
2780 
2781             // blocks -> pixels
2782             mWidthRange = mWidthRange.intersect(
2783                     (mHorizontalBlockRange.getLower() - 1) * mBlockWidth + mWidthAlignment,
2784                     mHorizontalBlockRange.getUpper() * mBlockWidth);
2785             mHeightRange = mHeightRange.intersect(
2786                     (mVerticalBlockRange.getLower() - 1) * mBlockHeight + mHeightAlignment,
2787                     mVerticalBlockRange.getUpper() * mBlockHeight);
2788             mAspectRatioRange = mAspectRatioRange.intersect(
2789                     new Rational(mWidthRange.getLower(), mHeightRange.getUpper()),
2790                     new Rational(mWidthRange.getUpper(), mHeightRange.getLower()));
2791 
2792             mSmallerDimensionUpperLimit = Math.min(
2793                     mSmallerDimensionUpperLimit,
2794                     Math.min(mWidthRange.getUpper(), mHeightRange.getUpper()));
2795 
2796             // blocks -> rate
2797             mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(
2798                     mBlockCountRange.getLower() * (long)mFrameRateRange.getLower(),
2799                     mBlockCountRange.getUpper() * (long)mFrameRateRange.getUpper());
2800             mFrameRateRange = mFrameRateRange.intersect(
2801                     (int)(mBlocksPerSecondRange.getLower()
2802                             / mBlockCountRange.getUpper()),
2803                     (int)(mBlocksPerSecondRange.getUpper()
2804                             / (double)mBlockCountRange.getLower()));
2805         }
2806 
2807         private void applyMacroBlockLimits(
2808                 int maxHorizontalBlocks, int maxVerticalBlocks,
2809                 int maxBlocks, long maxBlocksPerSecond,
2810                 int blockWidth, int blockHeight,
2811                 int widthAlignment, int heightAlignment) {
2812             applyMacroBlockLimits(
2813                     1 /* minHorizontalBlocks */, 1 /* minVerticalBlocks */,
2814                     maxHorizontalBlocks, maxVerticalBlocks,
2815                     maxBlocks, maxBlocksPerSecond,
2816                     blockWidth, blockHeight, widthAlignment, heightAlignment);
2817         }
2818 
2819         private void applyMacroBlockLimits(
2820                 int minHorizontalBlocks, int minVerticalBlocks,
2821                 int maxHorizontalBlocks, int maxVerticalBlocks,
2822                 int maxBlocks, long maxBlocksPerSecond,
2823                 int blockWidth, int blockHeight,
2824                 int widthAlignment, int heightAlignment) {
2825             applyAlignment(widthAlignment, heightAlignment);
2826             applyBlockLimits(
2827                     blockWidth, blockHeight, Range.create(1, maxBlocks),
2828                     Range.create(1L, maxBlocksPerSecond),
2829                     Range.create(
2830                             new Rational(1, maxVerticalBlocks),
2831                             new Rational(maxHorizontalBlocks, 1)));
2832             mHorizontalBlockRange =
2833                     mHorizontalBlockRange.intersect(
2834                             Utils.divUp(minHorizontalBlocks, (mBlockWidth / blockWidth)),
2835                             maxHorizontalBlocks / (mBlockWidth / blockWidth));
2836             mVerticalBlockRange =
2837                     mVerticalBlockRange.intersect(
2838                             Utils.divUp(minVerticalBlocks, (mBlockHeight / blockHeight)),
2839                             maxVerticalBlocks / (mBlockHeight / blockHeight));
2840         }
2841 
2842         private void applyLevelLimits() {
2843             long maxBlocksPerSecond = 0;
2844             int maxBlocks = 0;
2845             int maxBps = 0;
2846             int maxDPBBlocks = 0;
2847 
2848             int errors = ERROR_NONE_SUPPORTED;
2849             CodecProfileLevel[] profileLevels = mParent.profileLevels;
2850             String mime = mParent.getMimeType();
2851 
2852             if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC)) {
2853                 maxBlocks = 99;
2854                 maxBlocksPerSecond = 1485;
2855                 maxBps = 64000;
2856                 maxDPBBlocks = 396;
2857                 for (CodecProfileLevel profileLevel: profileLevels) {
2858                     int MBPS = 0, FS = 0, BR = 0, DPB = 0;
2859                     boolean supported = true;
2860                     switch (profileLevel.level) {
2861                         case CodecProfileLevel.AVCLevel1:
2862                             MBPS =     1485; FS =     99; BR =     64; DPB =    396; break;
2863                         case CodecProfileLevel.AVCLevel1b:
2864                             MBPS =     1485; FS =     99; BR =    128; DPB =    396; break;
2865                         case CodecProfileLevel.AVCLevel11:
2866                             MBPS =     3000; FS =    396; BR =    192; DPB =    900; break;
2867                         case CodecProfileLevel.AVCLevel12:
2868                             MBPS =     6000; FS =    396; BR =    384; DPB =   2376; break;
2869                         case CodecProfileLevel.AVCLevel13:
2870                             MBPS =    11880; FS =    396; BR =    768; DPB =   2376; break;
2871                         case CodecProfileLevel.AVCLevel2:
2872                             MBPS =    11880; FS =    396; BR =   2000; DPB =   2376; break;
2873                         case CodecProfileLevel.AVCLevel21:
2874                             MBPS =    19800; FS =    792; BR =   4000; DPB =   4752; break;
2875                         case CodecProfileLevel.AVCLevel22:
2876                             MBPS =    20250; FS =   1620; BR =   4000; DPB =   8100; break;
2877                         case CodecProfileLevel.AVCLevel3:
2878                             MBPS =    40500; FS =   1620; BR =  10000; DPB =   8100; break;
2879                         case CodecProfileLevel.AVCLevel31:
2880                             MBPS =   108000; FS =   3600; BR =  14000; DPB =  18000; break;
2881                         case CodecProfileLevel.AVCLevel32:
2882                             MBPS =   216000; FS =   5120; BR =  20000; DPB =  20480; break;
2883                         case CodecProfileLevel.AVCLevel4:
2884                             MBPS =   245760; FS =   8192; BR =  20000; DPB =  32768; break;
2885                         case CodecProfileLevel.AVCLevel41:
2886                             MBPS =   245760; FS =   8192; BR =  50000; DPB =  32768; break;
2887                         case CodecProfileLevel.AVCLevel42:
2888                             MBPS =   522240; FS =   8704; BR =  50000; DPB =  34816; break;
2889                         case CodecProfileLevel.AVCLevel5:
2890                             MBPS =   589824; FS =  22080; BR = 135000; DPB = 110400; break;
2891                         case CodecProfileLevel.AVCLevel51:
2892                             MBPS =   983040; FS =  36864; BR = 240000; DPB = 184320; break;
2893                         case CodecProfileLevel.AVCLevel52:
2894                             MBPS =  2073600; FS =  36864; BR = 240000; DPB = 184320; break;
2895                         case CodecProfileLevel.AVCLevel6:
2896                             MBPS =  4177920; FS = 139264; BR = 240000; DPB = 696320; break;
2897                         case CodecProfileLevel.AVCLevel61:
2898                             MBPS =  8355840; FS = 139264; BR = 480000; DPB = 696320; break;
2899                         case CodecProfileLevel.AVCLevel62:
2900                             MBPS = 16711680; FS = 139264; BR = 800000; DPB = 696320; break;
2901                         default:
2902                             Log.w(TAG, "Unrecognized level "
2903                                     + profileLevel.level + " for " + mime);
2904                             errors |= ERROR_UNRECOGNIZED;
2905                     }
2906                     switch (profileLevel.profile) {
2907                         case CodecProfileLevel.AVCProfileConstrainedHigh:
2908                         case CodecProfileLevel.AVCProfileHigh:
2909                             BR *= 1250; break;
2910                         case CodecProfileLevel.AVCProfileHigh10:
2911                             BR *= 3000; break;
2912                         case CodecProfileLevel.AVCProfileExtended:
2913                         case CodecProfileLevel.AVCProfileHigh422:
2914                         case CodecProfileLevel.AVCProfileHigh444:
2915                             Log.w(TAG, "Unsupported profile "
2916                                     + profileLevel.profile + " for " + mime);
2917                             errors |= ERROR_UNSUPPORTED;
2918                             supported = false;
2919                             // fall through - treat as base profile
2920                         case CodecProfileLevel.AVCProfileConstrainedBaseline:
2921                         case CodecProfileLevel.AVCProfileBaseline:
2922                         case CodecProfileLevel.AVCProfileMain:
2923                             BR *= 1000; break;
2924                         default:
2925                             Log.w(TAG, "Unrecognized profile "
2926                                     + profileLevel.profile + " for " + mime);
2927                             errors |= ERROR_UNRECOGNIZED;
2928                             BR *= 1000;
2929                     }
2930                     if (supported) {
2931                         errors &= ~ERROR_NONE_SUPPORTED;
2932                     }
2933                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
2934                     maxBlocks = Math.max(FS, maxBlocks);
2935                     maxBps = Math.max(BR, maxBps);
2936                     maxDPBBlocks = Math.max(maxDPBBlocks, DPB);
2937                 }
2938 
2939                 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8));
2940                 applyMacroBlockLimits(
2941                         maxLengthInBlocks, maxLengthInBlocks,
2942                         maxBlocks, maxBlocksPerSecond,
2943                         16 /* blockWidth */, 16 /* blockHeight */,
2944                         1 /* widthAlignment */, 1 /* heightAlignment */);
2945             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG2)) {
2946                 int maxWidth = 11, maxHeight = 9, maxRate = 15;
2947                 maxBlocks = 99;
2948                 maxBlocksPerSecond = 1485;
2949                 maxBps = 64000;
2950                 for (CodecProfileLevel profileLevel: profileLevels) {
2951                     int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0;
2952                     boolean supported = true;
2953                     switch (profileLevel.profile) {
2954                         case CodecProfileLevel.MPEG2ProfileSimple:
2955                             switch (profileLevel.level) {
2956                                 case CodecProfileLevel.MPEG2LevelML:
2957                                     FR = 30; W = 45; H =  36; MBPS =  40500; FS =  1620; BR =  15000; break;
2958                                 default:
2959                                     Log.w(TAG, "Unrecognized profile/level "
2960                                             + profileLevel.profile + "/"
2961                                             + profileLevel.level + " for " + mime);
2962                                     errors |= ERROR_UNRECOGNIZED;
2963                             }
2964                             break;
2965                         case CodecProfileLevel.MPEG2ProfileMain:
2966                             switch (profileLevel.level) {
2967                                 case CodecProfileLevel.MPEG2LevelLL:
2968                                     FR = 30; W = 22; H =  18; MBPS =  11880; FS =   396; BR =  4000; break;
2969                                 case CodecProfileLevel.MPEG2LevelML:
2970                                     FR = 30; W = 45; H =  36; MBPS =  40500; FS =  1620; BR = 15000; break;
2971                                 case CodecProfileLevel.MPEG2LevelH14:
2972                                     FR = 60; W = 90; H =  68; MBPS = 183600; FS =  6120; BR = 60000; break;
2973                                 case CodecProfileLevel.MPEG2LevelHL:
2974                                     FR = 60; W = 120; H = 68; MBPS = 244800; FS =  8160; BR = 80000; break;
2975                                 case CodecProfileLevel.MPEG2LevelHP:
2976                                     FR = 60; W = 120; H = 68; MBPS = 489600; FS =  8160; BR = 80000; break;
2977                                 default:
2978                                     Log.w(TAG, "Unrecognized profile/level "
2979                                             + profileLevel.profile + "/"
2980                                             + profileLevel.level + " for " + mime);
2981                                     errors |= ERROR_UNRECOGNIZED;
2982                             }
2983                             break;
2984                         case CodecProfileLevel.MPEG2Profile422:
2985                         case CodecProfileLevel.MPEG2ProfileSNR:
2986                         case CodecProfileLevel.MPEG2ProfileSpatial:
2987                         case CodecProfileLevel.MPEG2ProfileHigh:
2988                             Log.i(TAG, "Unsupported profile "
2989                                     + profileLevel.profile + " for " + mime);
2990                             errors |= ERROR_UNSUPPORTED;
2991                             supported = false;
2992                             break;
2993                         default:
2994                             Log.w(TAG, "Unrecognized profile "
2995                                     + profileLevel.profile + " for " + mime);
2996                             errors |= ERROR_UNRECOGNIZED;
2997                     }
2998                     if (supported) {
2999                         errors &= ~ERROR_NONE_SUPPORTED;
3000                     }
3001                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
3002                     maxBlocks = Math.max(FS, maxBlocks);
3003                     maxBps = Math.max(BR * 1000, maxBps);
3004                     maxWidth = Math.max(W, maxWidth);
3005                     maxHeight = Math.max(H, maxHeight);
3006                     maxRate = Math.max(FR, maxRate);
3007                 }
3008                 applyMacroBlockLimits(maxWidth, maxHeight,
3009                         maxBlocks, maxBlocksPerSecond,
3010                         16 /* blockWidth */, 16 /* blockHeight */,
3011                         1 /* widthAlignment */, 1 /* heightAlignment */);
3012                 mFrameRateRange = mFrameRateRange.intersect(12, maxRate);
3013             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) {
3014                 int maxWidth = 11, maxHeight = 9, maxRate = 15;
3015                 maxBlocks = 99;
3016                 maxBlocksPerSecond = 1485;
3017                 maxBps = 64000;
3018                 for (CodecProfileLevel profileLevel: profileLevels) {
3019                     int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0;
3020                     boolean strict = false; // true: W, H and FR are individual max limits
3021                     boolean supported = true;
3022                     switch (profileLevel.profile) {
3023                         case CodecProfileLevel.MPEG4ProfileSimple:
3024                             switch (profileLevel.level) {
3025                                 case CodecProfileLevel.MPEG4Level0:
3026                                     strict = true;
3027                                     FR = 15; W = 11; H =  9; MBPS =  1485; FS =  99; BR =  64; break;
3028                                 case CodecProfileLevel.MPEG4Level1:
3029                                     FR = 30; W = 11; H =  9; MBPS =  1485; FS =  99; BR =  64; break;
3030                                 case CodecProfileLevel.MPEG4Level0b:
3031                                     strict = true;
3032                                     FR = 15; W = 11; H =  9; MBPS =  1485; FS =  99; BR = 128; break;
3033                                 case CodecProfileLevel.MPEG4Level2:
3034                                     FR = 30; W = 22; H = 18; MBPS =  5940; FS = 396; BR = 128; break;
3035                                 case CodecProfileLevel.MPEG4Level3:
3036                                     FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384; break;
3037                                 case CodecProfileLevel.MPEG4Level4a:
3038                                     FR = 30; W = 40; H = 30; MBPS = 36000; FS = 1200; BR = 4000; break;
3039                                 case CodecProfileLevel.MPEG4Level5:
3040                                     FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 8000; break;
3041                                 case CodecProfileLevel.MPEG4Level6:
3042                                     FR = 30; W = 80; H = 45; MBPS = 108000; FS = 3600; BR = 12000; break;
3043                                 default:
3044                                     Log.w(TAG, "Unrecognized profile/level "
3045                                             + profileLevel.profile + "/"
3046                                             + profileLevel.level + " for " + mime);
3047                                     errors |= ERROR_UNRECOGNIZED;
3048                             }
3049                             break;
3050                         case CodecProfileLevel.MPEG4ProfileAdvancedSimple:
3051                             switch (profileLevel.level) {
3052                                 case CodecProfileLevel.MPEG4Level0:
3053                                 case CodecProfileLevel.MPEG4Level1:
3054                                     FR = 30; W = 11; H =  9; MBPS =  2970; FS =   99; BR =  128; break;
3055                                 case CodecProfileLevel.MPEG4Level2:
3056                                     FR = 30; W = 22; H = 18; MBPS =  5940; FS =  396; BR =  384; break;
3057                                 case CodecProfileLevel.MPEG4Level3:
3058                                     FR = 30; W = 22; H = 18; MBPS = 11880; FS =  396; BR =  768; break;
3059                                 case CodecProfileLevel.MPEG4Level3b:
3060                                     FR = 30; W = 22; H = 18; MBPS = 11880; FS =  396; BR = 1500; break;
3061                                 case CodecProfileLevel.MPEG4Level4:
3062                                     FR = 30; W = 44; H = 36; MBPS = 23760; FS =  792; BR = 3000; break;
3063                                 case CodecProfileLevel.MPEG4Level5:
3064                                     FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 8000; break;
3065                                 default:
3066                                     Log.w(TAG, "Unrecognized profile/level "
3067                                             + profileLevel.profile + "/"
3068                                             + profileLevel.level + " for " + mime);
3069                                     errors |= ERROR_UNRECOGNIZED;
3070                             }
3071                             break;
3072                         case CodecProfileLevel.MPEG4ProfileMain:             // 2-4
3073                         case CodecProfileLevel.MPEG4ProfileNbit:             // 2
3074                         case CodecProfileLevel.MPEG4ProfileAdvancedRealTime: // 1-4
3075                         case CodecProfileLevel.MPEG4ProfileCoreScalable:     // 1-3
3076                         case CodecProfileLevel.MPEG4ProfileAdvancedCoding:   // 1-4
3077                         case CodecProfileLevel.MPEG4ProfileCore:             // 1-2
3078                         case CodecProfileLevel.MPEG4ProfileAdvancedCore:     // 1-4
3079                         case CodecProfileLevel.MPEG4ProfileSimpleScalable:   // 0-2
3080                         case CodecProfileLevel.MPEG4ProfileHybrid:           // 1-2
3081 
3082                         // Studio profiles are not supported by our codecs.
3083 
3084                         // Only profiles that can decode simple object types are considered.
3085                         // The following profiles are not able to.
3086                         case CodecProfileLevel.MPEG4ProfileBasicAnimated:    // 1-2
3087                         case CodecProfileLevel.MPEG4ProfileScalableTexture:  // 1
3088                         case CodecProfileLevel.MPEG4ProfileSimpleFace:       // 1-2
3089                         case CodecProfileLevel.MPEG4ProfileAdvancedScalable: // 1-3
3090                         case CodecProfileLevel.MPEG4ProfileSimpleFBA:        // 1-2
3091                             Log.i(TAG, "Unsupported profile "
3092                                     + profileLevel.profile + " for " + mime);
3093                             errors |= ERROR_UNSUPPORTED;
3094                             supported = false;
3095                             break;
3096                         default:
3097                             Log.w(TAG, "Unrecognized profile "
3098                                     + profileLevel.profile + " for " + mime);
3099                             errors |= ERROR_UNRECOGNIZED;
3100                     }
3101                     if (supported) {
3102                         errors &= ~ERROR_NONE_SUPPORTED;
3103                     }
3104                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
3105                     maxBlocks = Math.max(FS, maxBlocks);
3106                     maxBps = Math.max(BR * 1000, maxBps);
3107                     if (strict) {
3108                         maxWidth = Math.max(W, maxWidth);
3109                         maxHeight = Math.max(H, maxHeight);
3110                         maxRate = Math.max(FR, maxRate);
3111                     } else {
3112                         // assuming max 60 fps frame rate and 1:2 aspect ratio
3113                         int maxDim = (int)Math.sqrt(FS * 2);
3114                         maxWidth = Math.max(maxDim, maxWidth);
3115                         maxHeight = Math.max(maxDim, maxHeight);
3116                         maxRate = Math.max(Math.max(FR, 60), maxRate);
3117                     }
3118                 }
3119                 applyMacroBlockLimits(maxWidth, maxHeight,
3120                         maxBlocks, maxBlocksPerSecond,
3121                         16 /* blockWidth */, 16 /* blockHeight */,
3122                         1 /* widthAlignment */, 1 /* heightAlignment */);
3123                 mFrameRateRange = mFrameRateRange.intersect(12, maxRate);
3124             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) {
3125                 int maxWidth = 11, maxHeight = 9, maxRate = 15;
3126                 int minWidth = maxWidth, minHeight = maxHeight;
3127                 int minAlignment = 16;
3128                 maxBlocks = 99;
3129                 maxBlocksPerSecond = 1485;
3130                 maxBps = 64000;
3131                 for (CodecProfileLevel profileLevel: profileLevels) {
3132                     int MBPS = 0, BR = 0, FR = 0, W = 0, H = 0, minW = minWidth, minH = minHeight;
3133                     boolean strict = false; // true: support only sQCIF, QCIF (maybe CIF)
3134                     switch (profileLevel.level) {
3135                         case CodecProfileLevel.H263Level10:
3136                             strict = true; // only supports sQCIF & QCIF
3137                             FR = 15; W = 11; H =  9; BR =   1; MBPS =  W * H * FR; break;
3138                         case CodecProfileLevel.H263Level20:
3139                             strict = true; // only supports sQCIF, QCIF & CIF
3140                             FR = 30; W = 22; H = 18; BR =   2; MBPS =  W * H * 15; break;
3141                         case CodecProfileLevel.H263Level30:
3142                             strict = true; // only supports sQCIF, QCIF & CIF
3143                             FR = 30; W = 22; H = 18; BR =   6; MBPS =  W * H * FR; break;
3144                         case CodecProfileLevel.H263Level40:
3145                             strict = true; // only supports sQCIF, QCIF & CIF
3146                             FR = 30; W = 22; H = 18; BR =  32; MBPS =  W * H * FR; break;
3147                         case CodecProfileLevel.H263Level45:
3148                             // only implies level 10 support
3149                             strict = profileLevel.profile == CodecProfileLevel.H263ProfileBaseline
3150                                     || profileLevel.profile ==
3151                                             CodecProfileLevel.H263ProfileBackwardCompatible;
3152                             if (!strict) {
3153                                 minW = 1; minH = 1; minAlignment = 4;
3154                             }
3155                             FR = 15; W = 11; H =  9; BR =   2; MBPS =  W * H * FR; break;
3156                         case CodecProfileLevel.H263Level50:
3157                             // only supports 50fps for H > 15
3158                             minW = 1; minH = 1; minAlignment = 4;
3159                             FR = 60; W = 22; H = 18; BR =  64; MBPS =  W * H * 50; break;
3160                         case CodecProfileLevel.H263Level60:
3161                             // only supports 50fps for H > 15
3162                             minW = 1; minH = 1; minAlignment = 4;
3163                             FR = 60; W = 45; H = 18; BR = 128; MBPS =  W * H * 50; break;
3164                         case CodecProfileLevel.H263Level70:
3165                             // only supports 50fps for H > 30
3166                             minW = 1; minH = 1; minAlignment = 4;
3167                             FR = 60; W = 45; H = 36; BR = 256; MBPS =  W * H * 50; break;
3168                         default:
3169                             Log.w(TAG, "Unrecognized profile/level " + profileLevel.profile
3170                                     + "/" + profileLevel.level + " for " + mime);
3171                             errors |= ERROR_UNRECOGNIZED;
3172                     }
3173                     switch (profileLevel.profile) {
3174                         case CodecProfileLevel.H263ProfileBackwardCompatible:
3175                         case CodecProfileLevel.H263ProfileBaseline:
3176                         case CodecProfileLevel.H263ProfileH320Coding:
3177                         case CodecProfileLevel.H263ProfileHighCompression:
3178                         case CodecProfileLevel.H263ProfileHighLatency:
3179                         case CodecProfileLevel.H263ProfileInterlace:
3180                         case CodecProfileLevel.H263ProfileInternet:
3181                         case CodecProfileLevel.H263ProfileISWV2:
3182                         case CodecProfileLevel.H263ProfileISWV3:
3183                             break;
3184                         default:
3185                             Log.w(TAG, "Unrecognized profile "
3186                                     + profileLevel.profile + " for " + mime);
3187                             errors |= ERROR_UNRECOGNIZED;
3188                     }
3189                     if (strict) {
3190                         // Strict levels define sub-QCIF min size and enumerated sizes. We cannot
3191                         // express support for "only sQCIF & QCIF (& CIF)" using VideoCapabilities
3192                         // but we can express "only QCIF (& CIF)", so set minimume size at QCIF.
3193                         // minW = 8; minH = 6;
3194                         minW = 11; minH = 9;
3195                     } else {
3196                         // any support for non-strict levels (including unrecognized profiles or
3197                         // levels) allow custom frame size support beyond supported limits
3198                         // (other than bitrate)
3199                         mAllowMbOverride = true;
3200                     }
3201                     errors &= ~ERROR_NONE_SUPPORTED;
3202                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
3203                     maxBlocks = Math.max(W * H, maxBlocks);
3204                     maxBps = Math.max(BR * 64000, maxBps);
3205                     maxWidth = Math.max(W, maxWidth);
3206                     maxHeight = Math.max(H, maxHeight);
3207                     maxRate = Math.max(FR, maxRate);
3208                     minWidth = Math.min(minW, minWidth);
3209                     minHeight = Math.min(minH, minHeight);
3210                 }
3211                 // unless we encountered custom frame size support, limit size to QCIF and CIF
3212                 // using aspect ratio.
3213                 if (!mAllowMbOverride) {
3214                     mBlockAspectRatioRange =
3215                         Range.create(new Rational(11, 9), new Rational(11, 9));
3216                 }
3217                 applyMacroBlockLimits(
3218                         minWidth, minHeight,
3219                         maxWidth, maxHeight,
3220                         maxBlocks, maxBlocksPerSecond,
3221                         16 /* blockWidth */, 16 /* blockHeight */,
3222                         minAlignment /* widthAlignment */, minAlignment /* heightAlignment */);
3223                 mFrameRateRange = Range.create(1, maxRate);
3224             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8)) {
3225                 maxBlocks = Integer.MAX_VALUE;
3226                 maxBlocksPerSecond = Integer.MAX_VALUE;
3227 
3228                 // TODO: set to 100Mbps for now, need a number for VP8
3229                 maxBps = 100000000;
3230 
3231                 // profile levels are not indicative for VPx, but verify
3232                 // them nonetheless
3233                 for (CodecProfileLevel profileLevel: profileLevels) {
3234                     switch (profileLevel.level) {
3235                         case CodecProfileLevel.VP8Level_Version0:
3236                         case CodecProfileLevel.VP8Level_Version1:
3237                         case CodecProfileLevel.VP8Level_Version2:
3238                         case CodecProfileLevel.VP8Level_Version3:
3239                             break;
3240                         default:
3241                             Log.w(TAG, "Unrecognized level "
3242                                     + profileLevel.level + " for " + mime);
3243                             errors |= ERROR_UNRECOGNIZED;
3244                     }
3245                     switch (profileLevel.profile) {
3246                         case CodecProfileLevel.VP8ProfileMain:
3247                             break;
3248                         default:
3249                             Log.w(TAG, "Unrecognized profile "
3250                                     + profileLevel.profile + " for " + mime);
3251                             errors |= ERROR_UNRECOGNIZED;
3252                     }
3253                     errors &= ~ERROR_NONE_SUPPORTED;
3254                 }
3255 
3256                 final int blockSize = 16;
3257                 applyMacroBlockLimits(Short.MAX_VALUE, Short.MAX_VALUE,
3258                         maxBlocks, maxBlocksPerSecond, blockSize, blockSize,
3259                         1 /* widthAlignment */, 1 /* heightAlignment */);
3260             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) {
3261                 maxBlocksPerSecond = 829440;
3262                 maxBlocks = 36864;
3263                 maxBps = 200000;
3264                 int maxDim = 512;
3265 
3266                 for (CodecProfileLevel profileLevel: profileLevels) {
3267                     long SR = 0; // luma sample rate
3268                     int FS = 0;  // luma picture size
3269                     int BR = 0;  // bit rate kbps
3270                     int D = 0;   // luma dimension
3271                     switch (profileLevel.level) {
3272                         case CodecProfileLevel.VP9Level1:
3273                             SR =      829440; FS =    36864; BR =    200; D =   512; break;
3274                         case CodecProfileLevel.VP9Level11:
3275                             SR =     2764800; FS =    73728; BR =    800; D =   768; break;
3276                         case CodecProfileLevel.VP9Level2:
3277                             SR =     4608000; FS =   122880; BR =   1800; D =   960; break;
3278                         case CodecProfileLevel.VP9Level21:
3279                             SR =     9216000; FS =   245760; BR =   3600; D =  1344; break;
3280                         case CodecProfileLevel.VP9Level3:
3281                             SR =    20736000; FS =   552960; BR =   7200; D =  2048; break;
3282                         case CodecProfileLevel.VP9Level31:
3283                             SR =    36864000; FS =   983040; BR =  12000; D =  2752; break;
3284                         case CodecProfileLevel.VP9Level4:
3285                             SR =    83558400; FS =  2228224; BR =  18000; D =  4160; break;
3286                         case CodecProfileLevel.VP9Level41:
3287                             SR =   160432128; FS =  2228224; BR =  30000; D =  4160; break;
3288                         case CodecProfileLevel.VP9Level5:
3289                             SR =   311951360; FS =  8912896; BR =  60000; D =  8384; break;
3290                         case CodecProfileLevel.VP9Level51:
3291                             SR =   588251136; FS =  8912896; BR = 120000; D =  8384; break;
3292                         case CodecProfileLevel.VP9Level52:
3293                             SR =  1176502272; FS =  8912896; BR = 180000; D =  8384; break;
3294                         case CodecProfileLevel.VP9Level6:
3295                             SR =  1176502272; FS = 35651584; BR = 180000; D = 16832; break;
3296                         case CodecProfileLevel.VP9Level61:
3297                             SR = 2353004544L; FS = 35651584; BR = 240000; D = 16832; break;
3298                         case CodecProfileLevel.VP9Level62:
3299                             SR = 4706009088L; FS = 35651584; BR = 480000; D = 16832; break;
3300                         default:
3301                             Log.w(TAG, "Unrecognized level "
3302                                     + profileLevel.level + " for " + mime);
3303                             errors |= ERROR_UNRECOGNIZED;
3304                     }
3305                     switch (profileLevel.profile) {
3306                         case CodecProfileLevel.VP9Profile0:
3307                         case CodecProfileLevel.VP9Profile1:
3308                         case CodecProfileLevel.VP9Profile2:
3309                         case CodecProfileLevel.VP9Profile3:
3310                         case CodecProfileLevel.VP9Profile2HDR:
3311                         case CodecProfileLevel.VP9Profile3HDR:
3312                         case CodecProfileLevel.VP9Profile2HDR10Plus:
3313                         case CodecProfileLevel.VP9Profile3HDR10Plus:
3314                             break;
3315                         default:
3316                             Log.w(TAG, "Unrecognized profile "
3317                                     + profileLevel.profile + " for " + mime);
3318                             errors |= ERROR_UNRECOGNIZED;
3319                     }
3320                     errors &= ~ERROR_NONE_SUPPORTED;
3321                     maxBlocksPerSecond = Math.max(SR, maxBlocksPerSecond);
3322                     maxBlocks = Math.max(FS, maxBlocks);
3323                     maxBps = Math.max(BR * 1000, maxBps);
3324                     maxDim = Math.max(D, maxDim);
3325                 }
3326 
3327                 final int blockSize = 8;
3328                 int maxLengthInBlocks = Utils.divUp(maxDim, blockSize);
3329                 maxBlocks = Utils.divUp(maxBlocks, blockSize * blockSize);
3330                 maxBlocksPerSecond = Utils.divUp(maxBlocksPerSecond, blockSize * blockSize);
3331 
3332                 applyMacroBlockLimits(
3333                         maxLengthInBlocks, maxLengthInBlocks,
3334                         maxBlocks, maxBlocksPerSecond,
3335                         blockSize, blockSize,
3336                         1 /* widthAlignment */, 1 /* heightAlignment */);
3337             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
3338                 // CTBs are at least 8x8 so use 8x8 block size
3339                 maxBlocks = 36864 >> 6; // 192x192 pixels == 576 8x8 blocks
3340                 maxBlocksPerSecond = maxBlocks * 15;
3341                 maxBps = 128000;
3342                 for (CodecProfileLevel profileLevel: profileLevels) {
3343                     double FR = 0;
3344                     int FS = 0;
3345                     int BR = 0;
3346                     switch (profileLevel.level) {
3347                         /* The HEVC spec talks only in a very convoluted manner about the
3348                            existence of levels 1-3.1 for High tier, which could also be
3349                            understood as 'decoders and encoders should treat these levels
3350                            as if they were Main tier', so we do that. */
3351                         case CodecProfileLevel.HEVCMainTierLevel1:
3352                         case CodecProfileLevel.HEVCHighTierLevel1:
3353                             FR =    15; FS =    36864; BR =    128; break;
3354                         case CodecProfileLevel.HEVCMainTierLevel2:
3355                         case CodecProfileLevel.HEVCHighTierLevel2:
3356                             FR =    30; FS =   122880; BR =   1500; break;
3357                         case CodecProfileLevel.HEVCMainTierLevel21:
3358                         case CodecProfileLevel.HEVCHighTierLevel21:
3359                             FR =    30; FS =   245760; BR =   3000; break;
3360                         case CodecProfileLevel.HEVCMainTierLevel3:
3361                         case CodecProfileLevel.HEVCHighTierLevel3:
3362                             FR =    30; FS =   552960; BR =   6000; break;
3363                         case CodecProfileLevel.HEVCMainTierLevel31:
3364                         case CodecProfileLevel.HEVCHighTierLevel31:
3365                             FR = 33.75; FS =   983040; BR =  10000; break;
3366                         case CodecProfileLevel.HEVCMainTierLevel4:
3367                             FR =    30; FS =  2228224; BR =  12000; break;
3368                         case CodecProfileLevel.HEVCHighTierLevel4:
3369                             FR =    30; FS =  2228224; BR =  30000; break;
3370                         case CodecProfileLevel.HEVCMainTierLevel41:
3371                             FR =    60; FS =  2228224; BR =  20000; break;
3372                         case CodecProfileLevel.HEVCHighTierLevel41:
3373                             FR =    60; FS =  2228224; BR =  50000; break;
3374                         case CodecProfileLevel.HEVCMainTierLevel5:
3375                             FR =    30; FS =  8912896; BR =  25000; break;
3376                         case CodecProfileLevel.HEVCHighTierLevel5:
3377                             FR =    30; FS =  8912896; BR = 100000; break;
3378                         case CodecProfileLevel.HEVCMainTierLevel51:
3379                             FR =    60; FS =  8912896; BR =  40000; break;
3380                         case CodecProfileLevel.HEVCHighTierLevel51:
3381                             FR =    60; FS =  8912896; BR = 160000; break;
3382                         case CodecProfileLevel.HEVCMainTierLevel52:
3383                             FR =   120; FS =  8912896; BR =  60000; break;
3384                         case CodecProfileLevel.HEVCHighTierLevel52:
3385                             FR =   120; FS =  8912896; BR = 240000; break;
3386                         case CodecProfileLevel.HEVCMainTierLevel6:
3387                             FR =    30; FS = 35651584; BR =  60000; break;
3388                         case CodecProfileLevel.HEVCHighTierLevel6:
3389                             FR =    30; FS = 35651584; BR = 240000; break;
3390                         case CodecProfileLevel.HEVCMainTierLevel61:
3391                             FR =    60; FS = 35651584; BR = 120000; break;
3392                         case CodecProfileLevel.HEVCHighTierLevel61:
3393                             FR =    60; FS = 35651584; BR = 480000; break;
3394                         case CodecProfileLevel.HEVCMainTierLevel62:
3395                             FR =   120; FS = 35651584; BR = 240000; break;
3396                         case CodecProfileLevel.HEVCHighTierLevel62:
3397                             FR =   120; FS = 35651584; BR = 800000; break;
3398                         default:
3399                             Log.w(TAG, "Unrecognized level "
3400                                     + profileLevel.level + " for " + mime);
3401                             errors |= ERROR_UNRECOGNIZED;
3402                     }
3403                     switch (profileLevel.profile) {
3404                         case CodecProfileLevel.HEVCProfileMain:
3405                         case CodecProfileLevel.HEVCProfileMain10:
3406                         case CodecProfileLevel.HEVCProfileMainStill:
3407                         case CodecProfileLevel.HEVCProfileMain10HDR10:
3408                         case CodecProfileLevel.HEVCProfileMain10HDR10Plus:
3409                             break;
3410                         default:
3411                             Log.w(TAG, "Unrecognized profile "
3412                                     + profileLevel.profile + " for " + mime);
3413                             errors |= ERROR_UNRECOGNIZED;
3414                     }
3415 
3416                     /* DPB logic:
3417                     if      (width * height <= FS / 4)    DPB = 16;
3418                     else if (width * height <= FS / 2)    DPB = 12;
3419                     else if (width * height <= FS * 0.75) DPB = 8;
3420                     else                                  DPB = 6;
3421                     */
3422 
3423                     FS >>= 6; // convert pixels to blocks
3424                     errors &= ~ERROR_NONE_SUPPORTED;
3425                     maxBlocksPerSecond = Math.max((int)(FR * FS), maxBlocksPerSecond);
3426                     maxBlocks = Math.max(FS, maxBlocks);
3427                     maxBps = Math.max(BR * 1000, maxBps);
3428                 }
3429 
3430                 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8));
3431                 applyMacroBlockLimits(
3432                         maxLengthInBlocks, maxLengthInBlocks,
3433                         maxBlocks, maxBlocksPerSecond,
3434                         8 /* blockWidth */, 8 /* blockHeight */,
3435                         1 /* widthAlignment */, 1 /* heightAlignment */);
3436             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AV1)) {
3437                 maxBlocksPerSecond = 829440;
3438                 maxBlocks = 36864;
3439                 maxBps = 200000;
3440                 int maxDim = 512;
3441 
3442                 // Sample rate, Picture Size, Bit rate and luma dimension for AV1 Codec,
3443                 // corresponding to the definitions in
3444                 // "AV1 Bitstream & Decoding Process Specification", Annex A
3445                 // found at https://aomedia.org/av1-bitstream-and-decoding-process-specification/
3446                 for (CodecProfileLevel profileLevel: profileLevels) {
3447                     long SR = 0; // luma sample rate
3448                     int FS = 0;  // luma picture size
3449                     int BR = 0;  // bit rate kbps
3450                     int D = 0;   // luma D
3451                     switch (profileLevel.level) {
3452                         case CodecProfileLevel.AV1Level2:
3453                             SR =     5529600; FS =   147456; BR =   1500; D =  2048; break;
3454                         case CodecProfileLevel.AV1Level21:
3455                         case CodecProfileLevel.AV1Level22:
3456                         case CodecProfileLevel.AV1Level23:
3457                             SR =    10454400; FS =   278784; BR =   3000; D =  2816; break;
3458 
3459                         case CodecProfileLevel.AV1Level3:
3460                             SR =    24969600; FS =   665856; BR =   6000; D =  4352; break;
3461                         case CodecProfileLevel.AV1Level31:
3462                         case CodecProfileLevel.AV1Level32:
3463                         case CodecProfileLevel.AV1Level33:
3464                             SR =    39938400; FS =  1065024; BR =  10000; D =  5504; break;
3465 
3466                         case CodecProfileLevel.AV1Level4:
3467                             SR =    77856768; FS =  2359296; BR =  12000; D =  6144; break;
3468                         case CodecProfileLevel.AV1Level41:
3469                         case CodecProfileLevel.AV1Level42:
3470                         case CodecProfileLevel.AV1Level43:
3471                             SR =   155713536; FS =  2359296; BR =  20000; D =  6144; break;
3472 
3473                         case CodecProfileLevel.AV1Level5:
3474                             SR =   273715200; FS =  8912896; BR =  30000; D =  8192; break;
3475                         case CodecProfileLevel.AV1Level51:
3476                             SR =   547430400; FS =  8912896; BR =  40000; D =  8192; break;
3477                         case CodecProfileLevel.AV1Level52:
3478                             SR =  1094860800; FS =  8912896; BR =  60000; D =  8192; break;
3479                         case CodecProfileLevel.AV1Level53:
3480                             SR =  1176502272; FS =  8912896; BR =  60000; D =  8192; break;
3481 
3482                         case CodecProfileLevel.AV1Level6:
3483                             SR =  1176502272; FS = 35651584; BR =  60000; D = 16384; break;
3484                         case CodecProfileLevel.AV1Level61:
3485                             SR = 2189721600L; FS = 35651584; BR = 100000; D = 16384; break;
3486                         case CodecProfileLevel.AV1Level62:
3487                             SR = 4379443200L; FS = 35651584; BR = 160000; D = 16384; break;
3488                         case CodecProfileLevel.AV1Level63:
3489                             SR = 4706009088L; FS = 35651584; BR = 160000; D = 16384; break;
3490 
3491                         default:
3492                             Log.w(TAG, "Unrecognized level "
3493                                     + profileLevel.level + " for " + mime);
3494                             errors |= ERROR_UNRECOGNIZED;
3495                     }
3496                     switch (profileLevel.profile) {
3497                         case CodecProfileLevel.AV1ProfileMain8:
3498                         case CodecProfileLevel.AV1ProfileMain10:
3499                         case CodecProfileLevel.AV1ProfileMain10HDR10:
3500                         case CodecProfileLevel.AV1ProfileMain10HDR10Plus:
3501                             break;
3502                         default:
3503                             Log.w(TAG, "Unrecognized profile "
3504                                     + profileLevel.profile + " for " + mime);
3505                             errors |= ERROR_UNRECOGNIZED;
3506                     }
3507                     errors &= ~ERROR_NONE_SUPPORTED;
3508                     maxBlocksPerSecond = Math.max(SR, maxBlocksPerSecond);
3509                     maxBlocks = Math.max(FS, maxBlocks);
3510                     maxBps = Math.max(BR * 1000, maxBps);
3511                     maxDim = Math.max(D, maxDim);
3512                 }
3513 
3514                 final int blockSize = 8;
3515                 int maxLengthInBlocks = Utils.divUp(maxDim, blockSize);
3516                 maxBlocks = Utils.divUp(maxBlocks, blockSize * blockSize);
3517                 maxBlocksPerSecond = Utils.divUp(maxBlocksPerSecond, blockSize * blockSize);
3518                 applyMacroBlockLimits(
3519                         maxLengthInBlocks, maxLengthInBlocks,
3520                         maxBlocks, maxBlocksPerSecond,
3521                         blockSize, blockSize,
3522                         1 /* widthAlignment */, 1 /* heightAlignment */);
3523             } else {
3524                 Log.w(TAG, "Unsupported mime " + mime);
3525                 // using minimal bitrate here.  should be overriden by
3526                 // info from media_codecs.xml
3527                 maxBps = 64000;
3528                 errors |= ERROR_UNSUPPORTED;
3529             }
3530             mBitrateRange = Range.create(1, maxBps);
3531             mParent.mError |= errors;
3532         }
3533     }
3534 
3535     /**
3536      * A class that supports querying the encoding capabilities of a codec.
3537      */
3538     public static final class EncoderCapabilities {
3539         /**
3540          * Returns the supported range of quality values.
3541          *
3542          * Quality is implementation-specific. As a general rule, a higher quality
3543          * setting results in a better image quality and a lower compression ratio.
3544          */
3545         public Range<Integer> getQualityRange() {
3546             return mQualityRange;
3547         }
3548 
3549         /**
3550          * Returns the supported range of encoder complexity values.
3551          * <p>
3552          * Some codecs may support multiple complexity levels, where higher
3553          * complexity values use more encoder tools (e.g. perform more
3554          * intensive calculations) to improve the quality or the compression
3555          * ratio.  Use a lower value to save power and/or time.
3556          */
3557         public Range<Integer> getComplexityRange() {
3558             return mComplexityRange;
3559         }
3560 
3561         /** Constant quality mode */
3562         public static final int BITRATE_MODE_CQ = 0;
3563         /** Variable bitrate mode */
3564         public static final int BITRATE_MODE_VBR = 1;
3565         /** Constant bitrate mode */
3566         public static final int BITRATE_MODE_CBR = 2;
3567         /** Constant bitrate mode with frame drops */
3568         public static final int BITRATE_MODE_CBR_FD =  3;
3569 
3570         private static final Feature[] bitrates = new Feature[] {
3571             new Feature("VBR", BITRATE_MODE_VBR, true),
3572             new Feature("CBR", BITRATE_MODE_CBR, false),
3573             new Feature("CQ",  BITRATE_MODE_CQ,  false),
3574             new Feature("CBR-FD", BITRATE_MODE_CBR_FD, false)
3575         };
3576 
3577         private static int parseBitrateMode(String mode) {
3578             for (Feature feat: bitrates) {
3579                 if (feat.mName.equalsIgnoreCase(mode)) {
3580                     return feat.mValue;
3581                 }
3582             }
3583             return 0;
3584         }
3585 
3586         /**
3587          * Query whether a bitrate mode is supported.
3588          */
3589         public boolean isBitrateModeSupported(int mode) {
3590             for (Feature feat: bitrates) {
3591                 if (mode == feat.mValue) {
3592                     return (mBitControl & (1 << mode)) != 0;
3593                 }
3594             }
3595             return false;
3596         }
3597 
3598         private Range<Integer> mQualityRange;
3599         private Range<Integer> mComplexityRange;
3600         private CodecCapabilities mParent;
3601 
3602         /* no public constructor */
3603         private EncoderCapabilities() { }
3604 
3605         /** @hide */
3606         public static EncoderCapabilities create(
3607                 MediaFormat info, CodecCapabilities parent) {
3608             EncoderCapabilities caps = new EncoderCapabilities();
3609             caps.init(info, parent);
3610             return caps;
3611         }
3612 
3613         private void init(MediaFormat info, CodecCapabilities parent) {
3614             // no support for complexity or quality yet
3615             mParent = parent;
3616             mComplexityRange = Range.create(0, 0);
3617             mQualityRange = Range.create(0, 0);
3618             mBitControl = (1 << BITRATE_MODE_VBR);
3619 
3620             applyLevelLimits();
3621             parseFromInfo(info);
3622         }
3623 
3624         private void applyLevelLimits() {
3625             String mime = mParent.getMimeType();
3626             if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
3627                 mComplexityRange = Range.create(0, 8);
3628                 mBitControl = (1 << BITRATE_MODE_CQ);
3629             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)
3630                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)
3631                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW)
3632                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)
3633                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) {
3634                 mBitControl = (1 << BITRATE_MODE_CBR);
3635             }
3636         }
3637 
3638         private int mBitControl;
3639         private Integer mDefaultComplexity;
3640         private Integer mDefaultQuality;
3641         private String mQualityScale;
3642 
3643         private void parseFromInfo(MediaFormat info) {
3644             Map<String, Object> map = info.getMap();
3645 
3646             if (info.containsKey("complexity-range")) {
3647                 mComplexityRange = Utils
3648                         .parseIntRange(info.getString("complexity-range"), mComplexityRange);
3649                 // TODO should we limit this to level limits?
3650             }
3651             if (info.containsKey("quality-range")) {
3652                 mQualityRange = Utils
3653                         .parseIntRange(info.getString("quality-range"), mQualityRange);
3654             }
3655             if (info.containsKey("feature-bitrate-modes")) {
3656                 mBitControl = 0;
3657                 for (String mode: info.getString("feature-bitrate-modes").split(",")) {
3658                     mBitControl |= (1 << parseBitrateMode(mode));
3659                 }
3660             }
3661 
3662             try {
3663                 mDefaultComplexity = Integer.parseInt((String)map.get("complexity-default"));
3664             } catch (NumberFormatException e) { }
3665 
3666             try {
3667                 mDefaultQuality = Integer.parseInt((String)map.get("quality-default"));
3668             } catch (NumberFormatException e) { }
3669 
3670             mQualityScale = (String)map.get("quality-scale");
3671         }
3672 
3673         private boolean supports(
3674                 Integer complexity, Integer quality, Integer profile) {
3675             boolean ok = true;
3676             if (ok && complexity != null) {
3677                 ok = mComplexityRange.contains(complexity);
3678             }
3679             if (ok && quality != null) {
3680                 ok = mQualityRange.contains(quality);
3681             }
3682             if (ok && profile != null) {
3683                 for (CodecProfileLevel pl: mParent.profileLevels) {
3684                     if (pl.profile == profile) {
3685                         profile = null;
3686                         break;
3687                     }
3688                 }
3689                 ok = profile == null;
3690             }
3691             return ok;
3692         }
3693 
3694         /** @hide */
3695         public void getDefaultFormat(MediaFormat format) {
3696             // don't list trivial quality/complexity as default for now
3697             if (!mQualityRange.getUpper().equals(mQualityRange.getLower())
3698                     && mDefaultQuality != null) {
3699                 format.setInteger(MediaFormat.KEY_QUALITY, mDefaultQuality);
3700             }
3701             if (!mComplexityRange.getUpper().equals(mComplexityRange.getLower())
3702                     && mDefaultComplexity != null) {
3703                 format.setInteger(MediaFormat.KEY_COMPLEXITY, mDefaultComplexity);
3704             }
3705             // bitrates are listed in order of preference
3706             for (Feature feat: bitrates) {
3707                 if ((mBitControl & (1 << feat.mValue)) != 0) {
3708                     format.setInteger(MediaFormat.KEY_BITRATE_MODE, feat.mValue);
3709                     break;
3710                 }
3711             }
3712         }
3713 
3714         /** @hide */
3715         public boolean supportsFormat(MediaFormat format) {
3716             final Map<String, Object> map = format.getMap();
3717             final String mime = mParent.getMimeType();
3718 
3719             Integer mode = (Integer)map.get(MediaFormat.KEY_BITRATE_MODE);
3720             if (mode != null && !isBitrateModeSupported(mode)) {
3721                 return false;
3722             }
3723 
3724             Integer complexity = (Integer)map.get(MediaFormat.KEY_COMPLEXITY);
3725             if (MediaFormat.MIMETYPE_AUDIO_FLAC.equalsIgnoreCase(mime)) {
3726                 Integer flacComplexity =
3727                     (Integer)map.get(MediaFormat.KEY_FLAC_COMPRESSION_LEVEL);
3728                 if (complexity == null) {
3729                     complexity = flacComplexity;
3730                 } else if (flacComplexity != null && !complexity.equals(flacComplexity)) {
3731                     throw new IllegalArgumentException(
3732                             "conflicting values for complexity and " +
3733                             "flac-compression-level");
3734                 }
3735             }
3736 
3737             // other audio parameters
3738             Integer profile = (Integer)map.get(MediaFormat.KEY_PROFILE);
3739             if (MediaFormat.MIMETYPE_AUDIO_AAC.equalsIgnoreCase(mime)) {
3740                 Integer aacProfile = (Integer)map.get(MediaFormat.KEY_AAC_PROFILE);
3741                 if (profile == null) {
3742                     profile = aacProfile;
3743                 } else if (aacProfile != null && !aacProfile.equals(profile)) {
3744                     throw new IllegalArgumentException(
3745                             "conflicting values for profile and aac-profile");
3746                 }
3747             }
3748 
3749             Integer quality = (Integer)map.get(MediaFormat.KEY_QUALITY);
3750 
3751             return supports(complexity, quality, profile);
3752         }
3753     };
3754 
3755     /**
3756      * Encapsulates the profiles available for a codec component.
3757      * <p>You can get a set of {@link MediaCodecInfo.CodecProfileLevel} objects for a given
3758      * {@link MediaCodecInfo} object from the
3759      * {@link MediaCodecInfo.CodecCapabilities#profileLevels} field.
3760      */
3761     public static final class CodecProfileLevel {
3762         // These constants were originally in-line with OMX values, but this
3763         // correspondence is no longer maintained.
3764 
3765         // Profiles and levels for AVC Codec, corresponding to the definitions in
3766         // "SERIES H: AUDIOVISUAL AND MULTIMEDIA SYSTEMS,
3767         // Infrastructure of audiovisual services – Coding of moving video
3768         // Advanced video coding for generic audiovisual services"
3769         // found at
3770         // https://www.itu.int/rec/T-REC-H.264-201704-I
3771 
3772         /**
3773          * AVC Baseline profile.
3774          * See definition in
3775          * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
3776          * Annex A.
3777          */
3778         public static final int AVCProfileBaseline = 0x01;
3779 
3780         /**
3781          * AVC Main profile.
3782          * See definition in
3783          * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
3784          * Annex A.
3785          */
3786         public static final int AVCProfileMain     = 0x02;
3787 
3788         /**
3789          * AVC Extended profile.
3790          * See definition in
3791          * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
3792          * Annex A.
3793          */
3794         public static final int AVCProfileExtended = 0x04;
3795 
3796         /**
3797          * AVC High profile.
3798          * See definition in
3799          * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
3800          * Annex A.
3801          */
3802         public static final int AVCProfileHigh     = 0x08;
3803 
3804         /**
3805          * AVC High 10 profile.
3806          * See definition in
3807          * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
3808          * Annex A.
3809          */
3810         public static final int AVCProfileHigh10   = 0x10;
3811 
3812         /**
3813          * AVC High 4:2:2 profile.
3814          * See definition in
3815          * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
3816          * Annex A.
3817          */
3818         public static final int AVCProfileHigh422  = 0x20;
3819 
3820         /**
3821          * AVC High 4:4:4 profile.
3822          * See definition in
3823          * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
3824          * Annex A.
3825          */
3826         public static final int AVCProfileHigh444  = 0x40;
3827 
3828         /**
3829          * AVC Constrained Baseline profile.
3830          * See definition in
3831          * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
3832          * Annex A.
3833          */
3834         public static final int AVCProfileConstrainedBaseline = 0x10000;
3835 
3836         /**
3837          * AVC Constrained High profile.
3838          * See definition in
3839          * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
3840          * Annex A.
3841          */
3842         public static final int AVCProfileConstrainedHigh     = 0x80000;
3843 
3844         public static final int AVCLevel1       = 0x01;
3845         public static final int AVCLevel1b      = 0x02;
3846         public static final int AVCLevel11      = 0x04;
3847         public static final int AVCLevel12      = 0x08;
3848         public static final int AVCLevel13      = 0x10;
3849         public static final int AVCLevel2       = 0x20;
3850         public static final int AVCLevel21      = 0x40;
3851         public static final int AVCLevel22      = 0x80;
3852         public static final int AVCLevel3       = 0x100;
3853         public static final int AVCLevel31      = 0x200;
3854         public static final int AVCLevel32      = 0x400;
3855         public static final int AVCLevel4       = 0x800;
3856         public static final int AVCLevel41      = 0x1000;
3857         public static final int AVCLevel42      = 0x2000;
3858         public static final int AVCLevel5       = 0x4000;
3859         public static final int AVCLevel51      = 0x8000;
3860         public static final int AVCLevel52      = 0x10000;
3861         public static final int AVCLevel6       = 0x20000;
3862         public static final int AVCLevel61      = 0x40000;
3863         public static final int AVCLevel62      = 0x80000;
3864 
3865         public static final int H263ProfileBaseline             = 0x01;
3866         public static final int H263ProfileH320Coding           = 0x02;
3867         public static final int H263ProfileBackwardCompatible   = 0x04;
3868         public static final int H263ProfileISWV2                = 0x08;
3869         public static final int H263ProfileISWV3                = 0x10;
3870         public static final int H263ProfileHighCompression      = 0x20;
3871         public static final int H263ProfileInternet             = 0x40;
3872         public static final int H263ProfileInterlace            = 0x80;
3873         public static final int H263ProfileHighLatency          = 0x100;
3874 
3875         public static final int H263Level10      = 0x01;
3876         public static final int H263Level20      = 0x02;
3877         public static final int H263Level30      = 0x04;
3878         public static final int H263Level40      = 0x08;
3879         public static final int H263Level45      = 0x10;
3880         public static final int H263Level50      = 0x20;
3881         public static final int H263Level60      = 0x40;
3882         public static final int H263Level70      = 0x80;
3883 
3884         public static final int MPEG4ProfileSimple              = 0x01;
3885         public static final int MPEG4ProfileSimpleScalable      = 0x02;
3886         public static final int MPEG4ProfileCore                = 0x04;
3887         public static final int MPEG4ProfileMain                = 0x08;
3888         public static final int MPEG4ProfileNbit                = 0x10;
3889         public static final int MPEG4ProfileScalableTexture     = 0x20;
3890         public static final int MPEG4ProfileSimpleFace          = 0x40;
3891         public static final int MPEG4ProfileSimpleFBA           = 0x80;
3892         public static final int MPEG4ProfileBasicAnimated       = 0x100;
3893         public static final int MPEG4ProfileHybrid              = 0x200;
3894         public static final int MPEG4ProfileAdvancedRealTime    = 0x400;
3895         public static final int MPEG4ProfileCoreScalable        = 0x800;
3896         public static final int MPEG4ProfileAdvancedCoding      = 0x1000;
3897         public static final int MPEG4ProfileAdvancedCore        = 0x2000;
3898         public static final int MPEG4ProfileAdvancedScalable    = 0x4000;
3899         public static final int MPEG4ProfileAdvancedSimple      = 0x8000;
3900 
3901         public static final int MPEG4Level0      = 0x01;
3902         public static final int MPEG4Level0b     = 0x02;
3903         public static final int MPEG4Level1      = 0x04;
3904         public static final int MPEG4Level2      = 0x08;
3905         public static final int MPEG4Level3      = 0x10;
3906         public static final int MPEG4Level3b     = 0x18;
3907         public static final int MPEG4Level4      = 0x20;
3908         public static final int MPEG4Level4a     = 0x40;
3909         public static final int MPEG4Level5      = 0x80;
3910         public static final int MPEG4Level6      = 0x100;
3911 
3912         public static final int MPEG2ProfileSimple              = 0x00;
3913         public static final int MPEG2ProfileMain                = 0x01;
3914         public static final int MPEG2Profile422                 = 0x02;
3915         public static final int MPEG2ProfileSNR                 = 0x03;
3916         public static final int MPEG2ProfileSpatial             = 0x04;
3917         public static final int MPEG2ProfileHigh                = 0x05;
3918 
3919         public static final int MPEG2LevelLL     = 0x00;
3920         public static final int MPEG2LevelML     = 0x01;
3921         public static final int MPEG2LevelH14    = 0x02;
3922         public static final int MPEG2LevelHL     = 0x03;
3923         public static final int MPEG2LevelHP     = 0x04;
3924 
3925         public static final int AACObjectMain       = 1;
3926         public static final int AACObjectLC         = 2;
3927         public static final int AACObjectSSR        = 3;
3928         public static final int AACObjectLTP        = 4;
3929         public static final int AACObjectHE         = 5;
3930         public static final int AACObjectScalable   = 6;
3931         public static final int AACObjectERLC       = 17;
3932         public static final int AACObjectERScalable = 20;
3933         public static final int AACObjectLD         = 23;
3934         public static final int AACObjectHE_PS      = 29;
3935         public static final int AACObjectELD        = 39;
3936         /** xHE-AAC (includes USAC) */
3937         public static final int AACObjectXHE        = 42;
3938 
3939         public static final int VP8Level_Version0 = 0x01;
3940         public static final int VP8Level_Version1 = 0x02;
3941         public static final int VP8Level_Version2 = 0x04;
3942         public static final int VP8Level_Version3 = 0x08;
3943 
3944         public static final int VP8ProfileMain = 0x01;
3945 
3946         /** VP9 Profile 0 4:2:0 8-bit */
3947         public static final int VP9Profile0 = 0x01;
3948 
3949         /** VP9 Profile 1 4:2:2 8-bit */
3950         public static final int VP9Profile1 = 0x02;
3951 
3952         /** VP9 Profile 2 4:2:0 10-bit */
3953         public static final int VP9Profile2 = 0x04;
3954 
3955         /** VP9 Profile 3 4:2:2 10-bit */
3956         public static final int VP9Profile3 = 0x08;
3957 
3958         // HDR profiles also support passing HDR metadata
3959         /** VP9 Profile 2 4:2:0 10-bit HDR */
3960         public static final int VP9Profile2HDR = 0x1000;
3961 
3962         /** VP9 Profile 3 4:2:2 10-bit HDR */
3963         public static final int VP9Profile3HDR = 0x2000;
3964 
3965         /** VP9 Profile 2 4:2:0 10-bit HDR10Plus */
3966         public static final int VP9Profile2HDR10Plus = 0x4000;
3967 
3968         /** VP9 Profile 3 4:2:2 10-bit HDR10Plus */
3969         public static final int VP9Profile3HDR10Plus = 0x8000;
3970 
3971         public static final int VP9Level1  = 0x1;
3972         public static final int VP9Level11 = 0x2;
3973         public static final int VP9Level2  = 0x4;
3974         public static final int VP9Level21 = 0x8;
3975         public static final int VP9Level3  = 0x10;
3976         public static final int VP9Level31 = 0x20;
3977         public static final int VP9Level4  = 0x40;
3978         public static final int VP9Level41 = 0x80;
3979         public static final int VP9Level5  = 0x100;
3980         public static final int VP9Level51 = 0x200;
3981         public static final int VP9Level52 = 0x400;
3982         public static final int VP9Level6  = 0x800;
3983         public static final int VP9Level61 = 0x1000;
3984         public static final int VP9Level62 = 0x2000;
3985 
3986         public static final int HEVCProfileMain        = 0x01;
3987         public static final int HEVCProfileMain10      = 0x02;
3988         public static final int HEVCProfileMainStill   = 0x04;
3989         public static final int HEVCProfileMain10HDR10 = 0x1000;
3990         public static final int HEVCProfileMain10HDR10Plus = 0x2000;
3991 
3992         public static final int HEVCMainTierLevel1  = 0x1;
3993         public static final int HEVCHighTierLevel1  = 0x2;
3994         public static final int HEVCMainTierLevel2  = 0x4;
3995         public static final int HEVCHighTierLevel2  = 0x8;
3996         public static final int HEVCMainTierLevel21 = 0x10;
3997         public static final int HEVCHighTierLevel21 = 0x20;
3998         public static final int HEVCMainTierLevel3  = 0x40;
3999         public static final int HEVCHighTierLevel3  = 0x80;
4000         public static final int HEVCMainTierLevel31 = 0x100;
4001         public static final int HEVCHighTierLevel31 = 0x200;
4002         public static final int HEVCMainTierLevel4  = 0x400;
4003         public static final int HEVCHighTierLevel4  = 0x800;
4004         public static final int HEVCMainTierLevel41 = 0x1000;
4005         public static final int HEVCHighTierLevel41 = 0x2000;
4006         public static final int HEVCMainTierLevel5  = 0x4000;
4007         public static final int HEVCHighTierLevel5  = 0x8000;
4008         public static final int HEVCMainTierLevel51 = 0x10000;
4009         public static final int HEVCHighTierLevel51 = 0x20000;
4010         public static final int HEVCMainTierLevel52 = 0x40000;
4011         public static final int HEVCHighTierLevel52 = 0x80000;
4012         public static final int HEVCMainTierLevel6  = 0x100000;
4013         public static final int HEVCHighTierLevel6  = 0x200000;
4014         public static final int HEVCMainTierLevel61 = 0x400000;
4015         public static final int HEVCHighTierLevel61 = 0x800000;
4016         public static final int HEVCMainTierLevel62 = 0x1000000;
4017         public static final int HEVCHighTierLevel62 = 0x2000000;
4018 
4019         private static final int HEVCHighTierLevels =
4020             HEVCHighTierLevel1 | HEVCHighTierLevel2 | HEVCHighTierLevel21 | HEVCHighTierLevel3 |
4021             HEVCHighTierLevel31 | HEVCHighTierLevel4 | HEVCHighTierLevel41 | HEVCHighTierLevel5 |
4022             HEVCHighTierLevel51 | HEVCHighTierLevel52 | HEVCHighTierLevel6 | HEVCHighTierLevel61 |
4023             HEVCHighTierLevel62;
4024 
4025         public static final int DolbyVisionProfileDvavPer = 0x1;
4026         public static final int DolbyVisionProfileDvavPen = 0x2;
4027         public static final int DolbyVisionProfileDvheDer = 0x4;
4028         public static final int DolbyVisionProfileDvheDen = 0x8;
4029         public static final int DolbyVisionProfileDvheDtr = 0x10;
4030         public static final int DolbyVisionProfileDvheStn = 0x20;
4031         public static final int DolbyVisionProfileDvheDth = 0x40;
4032         public static final int DolbyVisionProfileDvheDtb = 0x80;
4033         public static final int DolbyVisionProfileDvheSt  = 0x100;
4034         public static final int DolbyVisionProfileDvavSe  = 0x200;
4035         /** Dolby Vision AV1 profile */
4036         @SuppressLint("AllUpper")
4037         public static final int DolbyVisionProfileDvav110 = 0x400;
4038 
4039         public static final int DolbyVisionLevelHd24    = 0x1;
4040         public static final int DolbyVisionLevelHd30    = 0x2;
4041         public static final int DolbyVisionLevelFhd24   = 0x4;
4042         public static final int DolbyVisionLevelFhd30   = 0x8;
4043         public static final int DolbyVisionLevelFhd60   = 0x10;
4044         public static final int DolbyVisionLevelUhd24   = 0x20;
4045         public static final int DolbyVisionLevelUhd30   = 0x40;
4046         public static final int DolbyVisionLevelUhd48   = 0x80;
4047         public static final int DolbyVisionLevelUhd60   = 0x100;
4048         @SuppressLint("AllUpper")
4049         public static final int DolbyVisionLevelUhd120  = 0x200;
4050         @SuppressLint("AllUpper")
4051         public static final int DolbyVisionLevel8k30    = 0x400;
4052         @SuppressLint("AllUpper")
4053         public static final int DolbyVisionLevel8k60    = 0x800;
4054 
4055         // Profiles and levels for AV1 Codec, corresponding to the definitions in
4056         // "AV1 Bitstream & Decoding Process Specification", Annex A
4057         // found at https://aomedia.org/av1-bitstream-and-decoding-process-specification/
4058 
4059         /**
4060          * AV1 Main profile 4:2:0 8-bit
4061          *
4062          * See definition in
4063          * <a href="https://aomedia.org/av1-bitstream-and-decoding-process-specification/">AV1 Specification</a>
4064          * Annex A.
4065          */
4066         public static final int AV1ProfileMain8   = 0x1;
4067 
4068         /**
4069          * AV1 Main profile 4:2:0 10-bit
4070          *
4071          * See definition in
4072          * <a href="https://aomedia.org/av1-bitstream-and-decoding-process-specification/">AV1 Specification</a>
4073          * Annex A.
4074          */
4075         public static final int AV1ProfileMain10  = 0x2;
4076 
4077 
4078         /** AV1 Main profile 4:2:0 10-bit with HDR10. */
4079         public static final int AV1ProfileMain10HDR10 = 0x1000;
4080 
4081         /** AV1 Main profile 4:2:0 10-bit with HDR10Plus. */
4082         public static final int AV1ProfileMain10HDR10Plus = 0x2000;
4083 
4084         public static final int AV1Level2       = 0x1;
4085         public static final int AV1Level21      = 0x2;
4086         public static final int AV1Level22      = 0x4;
4087         public static final int AV1Level23      = 0x8;
4088         public static final int AV1Level3       = 0x10;
4089         public static final int AV1Level31      = 0x20;
4090         public static final int AV1Level32      = 0x40;
4091         public static final int AV1Level33      = 0x80;
4092         public static final int AV1Level4       = 0x100;
4093         public static final int AV1Level41      = 0x200;
4094         public static final int AV1Level42      = 0x400;
4095         public static final int AV1Level43      = 0x800;
4096         public static final int AV1Level5       = 0x1000;
4097         public static final int AV1Level51      = 0x2000;
4098         public static final int AV1Level52      = 0x4000;
4099         public static final int AV1Level53      = 0x8000;
4100         public static final int AV1Level6       = 0x10000;
4101         public static final int AV1Level61      = 0x20000;
4102         public static final int AV1Level62      = 0x40000;
4103         public static final int AV1Level63      = 0x80000;
4104         public static final int AV1Level7       = 0x100000;
4105         public static final int AV1Level71      = 0x200000;
4106         public static final int AV1Level72      = 0x400000;
4107         public static final int AV1Level73      = 0x800000;
4108 
4109         /**
4110          * The profile of the media content. Depending on the type of media this can be
4111          * one of the profile values defined in this class.
4112          */
4113         public int profile;
4114 
4115         /**
4116          * The level of the media content. Depending on the type of media this can be
4117          * one of the level values defined in this class.
4118          *
4119          * Note that VP9 decoder on platforms before {@link android.os.Build.VERSION_CODES#N} may
4120          * not advertise a profile level support. For those VP9 decoders, please use
4121          * {@link VideoCapabilities} to determine the codec capabilities.
4122          */
4123         public int level;
4124 
4125         @Override
4126         public boolean equals(Object obj) {
4127             if (obj == null) {
4128                 return false;
4129             }
4130             if (obj instanceof CodecProfileLevel) {
4131                 CodecProfileLevel other = (CodecProfileLevel)obj;
4132                 return other.profile == profile && other.level == level;
4133             }
4134             return false;
4135         }
4136 
4137         @Override
4138         public int hashCode() {
4139             return Long.hashCode(((long)profile << Integer.SIZE) | level);
4140         }
4141     };
4142 
4143     /**
4144      * Enumerates the capabilities of the codec component. Since a single
4145      * component can support data of a variety of types, the type has to be
4146      * specified to yield a meaningful result.
4147      * @param type The MIME type to query
4148      */
4149     public final CodecCapabilities getCapabilitiesForType(
4150             String type) {
4151         CodecCapabilities caps = mCaps.get(type);
4152         if (caps == null) {
4153             throw new IllegalArgumentException("codec does not support type");
4154         }
4155         // clone writable object
4156         return caps.dup();
4157     }
4158 
4159     /** @hide */
4160     public MediaCodecInfo makeRegular() {
4161         ArrayList<CodecCapabilities> caps = new ArrayList<CodecCapabilities>();
4162         for (CodecCapabilities c: mCaps.values()) {
4163             if (c.isRegular()) {
4164                 caps.add(c);
4165             }
4166         }
4167         if (caps.size() == 0) {
4168             return null;
4169         } else if (caps.size() == mCaps.size()) {
4170             return this;
4171         }
4172 
4173         return new MediaCodecInfo(
4174                 mName, mCanonicalName, mFlags,
4175                 caps.toArray(new CodecCapabilities[caps.size()]));
4176     }
4177 }
4178