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 
getMeasuredFrameRates(Map<String, Object> map)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 
parseWidthHeightRanges(Object o)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 */
equivalentVP9Level(MediaFormat info)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 
parseFromInfo(MediaFormat info)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 
applyBlockLimits( int blockWidth, int blockHeight, Range<Integer> counts, Range<Long> rates, Range<Rational> ratios)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 
applyAlignment(int widthAlignment, int heightAlignment)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 
updateLimits()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 
applyMacroBlockLimits( int maxHorizontalBlocks, int maxVerticalBlocks, int maxBlocks, long maxBlocksPerSecond, int blockWidth, int blockHeight, int widthAlignment, int heightAlignment)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 
applyMacroBlockLimits( int minHorizontalBlocks, int minVerticalBlocks, int maxHorizontalBlocks, int maxVerticalBlocks, int maxBlocks, long maxBlocksPerSecond, int blockWidth, int blockHeight, int widthAlignment, int heightAlignment)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 
applyLevelLimits()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          */
getQualityRange()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          */
getComplexityRange()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 
parseBitrateMode(String mode)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          */
isBitrateModeSupported(int mode)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 */
EncoderCapabilities()3482         private EncoderCapabilities() { }
3483 
3484         /** @hide */
create( MediaFormat info, CodecCapabilities parent)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 
init(MediaFormat info, CodecCapabilities parent)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 
applyLevelLimits()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 
parseFromInfo(MediaFormat info)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 
supports( Integer complexity, Integer quality, Integer profile)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 */
getDefaultFormat(MediaFormat format)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 */
supportsFormat(MediaFormat format)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
equals(Object obj)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
hashCode()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      */
getCapabilitiesForType( String type)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 */
makeRegular()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