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