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