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