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 android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.util.Log;
22 import android.util.Pair;
23 import android.util.Range;
24 import android.util.Rational;
25 import android.util.Size;
26 
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.HashMap;
30 import java.util.Map;
31 import java.util.Set;
32 
33 import static android.media.Utils.intersectSortedDistinctRanges;
34 import static android.media.Utils.sortDistinctRanges;
35 
36 /**
37  * Provides information about a given media codec available on the device. You can
38  * iterate through all codecs available by querying {@link MediaCodecList}. For example,
39  * here's how to find an encoder that supports a given MIME type:
40  * <pre>
41  * private static MediaCodecInfo selectCodec(String mimeType) {
42  *     int numCodecs = MediaCodecList.getCodecCount();
43  *     for (int i = 0; i &lt; numCodecs; i++) {
44  *         MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
45  *
46  *         if (!codecInfo.isEncoder()) {
47  *             continue;
48  *         }
49  *
50  *         String[] types = codecInfo.getSupportedTypes();
51  *         for (int j = 0; j &lt; types.length; j++) {
52  *             if (types[j].equalsIgnoreCase(mimeType)) {
53  *                 return codecInfo;
54  *             }
55  *         }
56  *     }
57  *     return null;
58  * }</pre>
59  *
60  */
61 public final class MediaCodecInfo {
62     private boolean mIsEncoder;
63     private String mName;
64     private Map<String, CodecCapabilities> mCaps;
65 
MediaCodecInfo( String name, boolean isEncoder, CodecCapabilities[] caps)66     /* package private */ MediaCodecInfo(
67             String name, boolean isEncoder, CodecCapabilities[] caps) {
68         mName = name;
69         mIsEncoder = isEncoder;
70         mCaps = new HashMap<String, CodecCapabilities>();
71         for (CodecCapabilities c: caps) {
72             mCaps.put(c.getMimeType(), c);
73         }
74     }
75 
76     /**
77      * Retrieve the codec name.
78      */
getName()79     public final String getName() {
80         return mName;
81     }
82 
83     /**
84      * Query if the codec is an encoder.
85      */
isEncoder()86     public final boolean isEncoder() {
87         return mIsEncoder;
88     }
89 
90     /**
91      * Query the media types supported by the codec.
92      */
getSupportedTypes()93     public final String[] getSupportedTypes() {
94         Set<String> typeSet = mCaps.keySet();
95         String[] types = typeSet.toArray(new String[typeSet.size()]);
96         Arrays.sort(types);
97         return types;
98     }
99 
checkPowerOfTwo(int value, String message)100     private static int checkPowerOfTwo(int value, String message) {
101         if ((value & (value - 1)) != 0) {
102             throw new IllegalArgumentException(message);
103         }
104         return value;
105     }
106 
107     private static class Feature {
108         public String mName;
109         public int mValue;
110         public boolean mDefault;
Feature(String name, int value, boolean def)111         public Feature(String name, int value, boolean def) {
112             mName = name;
113             mValue = value;
114             mDefault = def;
115         }
116     }
117 
118     // COMMON CONSTANTS
119     private static final Range<Integer> POSITIVE_INTEGERS =
120         Range.create(1, Integer.MAX_VALUE);
121     private static final Range<Long> POSITIVE_LONGS =
122         Range.create(1l, Long.MAX_VALUE);
123     private static final Range<Rational> POSITIVE_RATIONALS =
124         Range.create(new Rational(1, Integer.MAX_VALUE),
125                      new Rational(Integer.MAX_VALUE, 1));
126     private static final Range<Integer> SIZE_RANGE = Range.create(1, 32768);
127     private static final Range<Integer> FRAME_RATE_RANGE = Range.create(0, 960);
128     private static final Range<Integer> BITRATE_RANGE = Range.create(0, 500000000);
129     private static final int DEFAULT_MAX_SUPPORTED_INSTANCES = 32;
130     private static final int MAX_SUPPORTED_INSTANCES_LIMIT = 256;
131 
132     // found stuff that is not supported by framework (=> this should not happen)
133     private static final int ERROR_UNRECOGNIZED   = (1 << 0);
134     // found profile/level for which we don't have capability estimates
135     private static final int ERROR_UNSUPPORTED    = (1 << 1);
136     // have not found any profile/level for which we don't have capability estimate
137     private static final int ERROR_NONE_SUPPORTED = (1 << 2);
138 
139 
140     /**
141      * Encapsulates the capabilities of a given codec component.
142      * For example, what profile/level combinations it supports and what colorspaces
143      * it is capable of providing the decoded data in, as well as some
144      * codec-type specific capability flags.
145      * <p>You can get an instance for a given {@link MediaCodecInfo} object with
146      * {@link MediaCodecInfo#getCapabilitiesForType getCapabilitiesForType()}, passing a MIME type.
147      */
148     public static final class CodecCapabilities {
CodecCapabilities()149         public CodecCapabilities() {
150         }
151 
152         // CLASSIFICATION
153         private String mMime;
154         private int mMaxSupportedInstances;
155 
156         // LEGACY FIELDS
157 
158         // Enumerates supported profile/level combinations as defined
159         // by the type of encoded data. These combinations impose restrictions
160         // on video resolution, bitrate... and limit the available encoder tools
161         // such as B-frame support, arithmetic coding...
162         public CodecProfileLevel[] profileLevels;  // NOTE this array is modifiable by user
163 
164         // from OMX_COLOR_FORMATTYPE
165         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
166         public static final int COLOR_FormatMonochrome              = 1;
167         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
168         public static final int COLOR_Format8bitRGB332              = 2;
169         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
170         public static final int COLOR_Format12bitRGB444             = 3;
171         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
172         public static final int COLOR_Format16bitARGB4444           = 4;
173         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
174         public static final int COLOR_Format16bitARGB1555           = 5;
175 
176         /**
177          * 16 bits per pixel RGB color format, with 5-bit red & blue and 6-bit green component.
178          * <p>
179          * Using 16-bit little-endian representation, colors stored as Red 15:11, Green 10:5, Blue 4:0.
180          * <pre>
181          *            byte                   byte
182          *  <--------- i --------> | <------ i + 1 ------>
183          * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
184          * |     BLUE     |      GREEN      |     RED      |
185          * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
186          *  0           4  5     7   0     2  3           7
187          * bit
188          * </pre>
189          *
190          * This format corresponds to {@link android.graphics.PixelFormat#RGB_565} and
191          * {@link android.graphics.ImageFormat#RGB_565}.
192          */
193         public static final int COLOR_Format16bitRGB565             = 6;
194         /** @deprecated Use {@link #COLOR_Format16bitRGB565}. */
195         public static final int COLOR_Format16bitBGR565             = 7;
196         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
197         public static final int COLOR_Format18bitRGB666             = 8;
198         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
199         public static final int COLOR_Format18bitARGB1665           = 9;
200         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
201         public static final int COLOR_Format19bitARGB1666           = 10;
202 
203         /** @deprecated Use {@link #COLOR_Format24bitBGR888} or {@link #COLOR_FormatRGBFlexible}. */
204         public static final int COLOR_Format24bitRGB888             = 11;
205 
206         /**
207          * 24 bits per pixel RGB color format, with 8-bit red, green & blue components.
208          * <p>
209          * Using 24-bit little-endian representation, colors stored as Red 7:0, Green 15:8, Blue 23:16.
210          * <pre>
211          *         byte              byte             byte
212          *  <------ i -----> | <---- i+1 ----> | <---- i+2 ----->
213          * +-----------------+-----------------+-----------------+
214          * |       RED       |      GREEN      |       BLUE      |
215          * +-----------------+-----------------+-----------------+
216          * </pre>
217          *
218          * This format corresponds to {@link android.graphics.PixelFormat#RGB_888}, and can also be
219          * represented as a flexible format by {@link #COLOR_FormatRGBFlexible}.
220          */
221         public static final int COLOR_Format24bitBGR888             = 12;
222         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
223         public static final int COLOR_Format24bitARGB1887           = 13;
224         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
225         public static final int COLOR_Format25bitARGB1888           = 14;
226 
227         /**
228          * @deprecated Use {@link #COLOR_Format32bitABGR8888} Or {@link #COLOR_FormatRGBAFlexible}.
229          */
230         public static final int COLOR_Format32bitBGRA8888           = 15;
231         /**
232          * @deprecated Use {@link #COLOR_Format32bitABGR8888} Or {@link #COLOR_FormatRGBAFlexible}.
233          */
234         public static final int COLOR_Format32bitARGB8888           = 16;
235         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
236         public static final int COLOR_FormatYUV411Planar            = 17;
237         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
238         public static final int COLOR_FormatYUV411PackedPlanar      = 18;
239         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
240         public static final int COLOR_FormatYUV420Planar            = 19;
241         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
242         public static final int COLOR_FormatYUV420PackedPlanar      = 20;
243         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
244         public static final int COLOR_FormatYUV420SemiPlanar        = 21;
245 
246         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
247         public static final int COLOR_FormatYUV422Planar            = 22;
248         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
249         public static final int COLOR_FormatYUV422PackedPlanar      = 23;
250         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
251         public static final int COLOR_FormatYUV422SemiPlanar        = 24;
252 
253         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
254         public static final int COLOR_FormatYCbYCr                  = 25;
255         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
256         public static final int COLOR_FormatYCrYCb                  = 26;
257         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
258         public static final int COLOR_FormatCbYCrY                  = 27;
259         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
260         public static final int COLOR_FormatCrYCbY                  = 28;
261 
262         /** @deprecated Use {@link #COLOR_FormatYUV444Flexible}. */
263         public static final int COLOR_FormatYUV444Interleaved       = 29;
264 
265         /**
266          * SMIA 8-bit Bayer format.
267          * Each byte represents the top 8-bits of a 10-bit signal.
268          */
269         public static final int COLOR_FormatRawBayer8bit            = 30;
270         /**
271          * SMIA 10-bit Bayer format.
272          */
273         public static final int COLOR_FormatRawBayer10bit           = 31;
274 
275         /**
276          * SMIA 8-bit compressed Bayer format.
277          * Each byte represents a sample from the 10-bit signal that is compressed into 8-bits
278          * using DPCM/PCM compression, as defined by the SMIA Functional Specification.
279          */
280         public static final int COLOR_FormatRawBayer8bitcompressed  = 32;
281 
282         /** @deprecated Use {@link #COLOR_FormatL8}. */
283         public static final int COLOR_FormatL2                      = 33;
284         /** @deprecated Use {@link #COLOR_FormatL8}. */
285         public static final int COLOR_FormatL4                      = 34;
286 
287         /**
288          * 8 bits per pixel Y color format.
289          * <p>
290          * Each byte contains a single pixel.
291          * This format corresponds to {@link android.graphics.PixelFormat#L_8}.
292          */
293         public static final int COLOR_FormatL8                      = 35;
294 
295         /**
296          * 16 bits per pixel, little-endian Y color format.
297          * <p>
298          * <pre>
299          *            byte                   byte
300          *  <--------- i --------> | <------ i + 1 ------>
301          * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
302          * |                       Y                       |
303          * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
304          *  0                    7   0                    7
305          * bit
306          * </pre>
307          */
308         public static final int COLOR_FormatL16                     = 36;
309         /** @deprecated Use {@link #COLOR_FormatL16}. */
310         public static final int COLOR_FormatL24                     = 37;
311 
312         /**
313          * 32 bits per pixel, little-endian Y color format.
314          * <p>
315          * <pre>
316          *         byte              byte             byte              byte
317          *  <------ i -----> | <---- i+1 ----> | <---- i+2 ----> | <---- i+3 ----->
318          * +-----------------+-----------------+-----------------+-----------------+
319          * |                                   Y                                   |
320          * +-----------------+-----------------+-----------------+-----------------+
321          *  0               7 0               7 0               7 0               7
322          * bit
323          * </pre>
324          *
325          * @deprecated Use {@link #COLOR_FormatL16}.
326          */
327         public static final int COLOR_FormatL32                     = 38;
328 
329         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
330         public static final int COLOR_FormatYUV420PackedSemiPlanar  = 39;
331         /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */
332         public static final int COLOR_FormatYUV422PackedSemiPlanar  = 40;
333 
334         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
335         public static final int COLOR_Format18BitBGR666             = 41;
336 
337         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
338         public static final int COLOR_Format24BitARGB6666           = 42;
339         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
340         public static final int COLOR_Format24BitABGR6666           = 43;
341 
342         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
343         public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100;
344         // COLOR_FormatSurface indicates that the data will be a GraphicBuffer metadata reference.
345         // In OMX this is called OMX_COLOR_FormatAndroidOpaque.
346         public static final int COLOR_FormatSurface                   = 0x7F000789;
347 
348         /**
349          * 32 bits per pixel RGBA color format, with 8-bit red, green, blue, and alpha components.
350          * <p>
351          * Using 32-bit little-endian representation, colors stored as Red 7:0, Green 15:8,
352          * Blue 23:16, and Alpha 31:24.
353          * <pre>
354          *         byte              byte             byte              byte
355          *  <------ i -----> | <---- i+1 ----> | <---- i+2 ----> | <---- i+3 ----->
356          * +-----------------+-----------------+-----------------+-----------------+
357          * |       RED       |      GREEN      |       BLUE      |      ALPHA      |
358          * +-----------------+-----------------+-----------------+-----------------+
359          * </pre>
360          *
361          * This corresponds to {@link android.graphics.PixelFormat#RGBA_8888}.
362          */
363         public static final int COLOR_Format32bitABGR8888             = 0x7F00A000;
364 
365         /**
366          * Flexible 12 bits per pixel, subsampled YUV color format with 8-bit chroma and luma
367          * components.
368          * <p>
369          * Chroma planes are subsampled by 2 both horizontally and vertically.
370          * Use this format with {@link Image}.
371          * This format corresponds to {@link android.graphics.ImageFormat#YUV_420_888},
372          * and can represent the {@link #COLOR_FormatYUV411Planar},
373          * {@link #COLOR_FormatYUV411PackedPlanar}, {@link #COLOR_FormatYUV420Planar},
374          * {@link #COLOR_FormatYUV420PackedPlanar}, {@link #COLOR_FormatYUV420SemiPlanar}
375          * and {@link #COLOR_FormatYUV420PackedSemiPlanar} formats.
376          *
377          * @see Image#getFormat
378          */
379         public static final int COLOR_FormatYUV420Flexible            = 0x7F420888;
380 
381         /**
382          * Flexible 16 bits per pixel, subsampled YUV color format with 8-bit chroma and luma
383          * components.
384          * <p>
385          * Chroma planes are horizontally subsampled by 2. Use this format with {@link Image}.
386          * This format corresponds to {@link android.graphics.ImageFormat#YUV_422_888},
387          * and can represent the {@link #COLOR_FormatYCbYCr}, {@link #COLOR_FormatYCrYCb},
388          * {@link #COLOR_FormatCbYCrY}, {@link #COLOR_FormatCrYCbY},
389          * {@link #COLOR_FormatYUV422Planar}, {@link #COLOR_FormatYUV422PackedPlanar},
390          * {@link #COLOR_FormatYUV422SemiPlanar} and {@link #COLOR_FormatYUV422PackedSemiPlanar}
391          * formats.
392          *
393          * @see Image#getFormat
394          */
395         public static final int COLOR_FormatYUV422Flexible            = 0x7F422888;
396 
397         /**
398          * Flexible 24 bits per pixel YUV color format with 8-bit chroma and luma
399          * components.
400          * <p>
401          * Chroma planes are not subsampled. Use this format with {@link Image}.
402          * This format corresponds to {@link android.graphics.ImageFormat#YUV_444_888},
403          * and can represent the {@link #COLOR_FormatYUV444Interleaved} format.
404          * @see Image#getFormat
405          */
406         public static final int COLOR_FormatYUV444Flexible            = 0x7F444888;
407 
408         /**
409          * Flexible 24 bits per pixel RGB color format with 8-bit red, green and blue
410          * components.
411          * <p>
412          * Use this format with {@link Image}. This format corresponds to
413          * {@link android.graphics.ImageFormat#FLEX_RGB_888}, and can represent
414          * {@link #COLOR_Format24bitBGR888} and {@link #COLOR_Format24bitRGB888} formats.
415          * @see Image#getFormat.
416          */
417         public static final int COLOR_FormatRGBFlexible               = 0x7F36B888;
418 
419         /**
420          * Flexible 32 bits per pixel RGBA color format with 8-bit red, green, blue, and alpha
421          * components.
422          * <p>
423          * Use this format with {@link Image}. This format corresponds to
424          * {@link android.graphics.ImageFormat#FLEX_RGBA_8888}, and can represent
425          * {@link #COLOR_Format32bitBGRA8888}, {@link #COLOR_Format32bitABGR8888} and
426          * {@link #COLOR_Format32bitARGB8888} formats.
427          *
428          * @see Image#getFormat
429          */
430         public static final int COLOR_FormatRGBAFlexible              = 0x7F36A888;
431 
432         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
433         public static final int COLOR_QCOM_FormatYUV420SemiPlanar     = 0x7fa30c00;
434 
435         /**
436          * Defined in the OpenMAX IL specs, color format values are drawn from
437          * OMX_COLOR_FORMATTYPE.
438          */
439         public int[] colorFormats; // NOTE this array is modifiable by user
440 
441         // FEATURES
442 
443         private int mFlagsSupported;
444         private int mFlagsRequired;
445         private int mFlagsVerified;
446 
447         /**
448          * <b>video decoder only</b>: codec supports seamless resolution changes.
449          */
450         public static final String FEATURE_AdaptivePlayback       = "adaptive-playback";
451 
452         /**
453          * <b>video decoder only</b>: codec supports secure decryption.
454          */
455         public static final String FEATURE_SecurePlayback         = "secure-playback";
456 
457         /**
458          * <b>video or audio decoder only</b>: codec supports tunneled playback.
459          */
460         public static final String FEATURE_TunneledPlayback       = "tunneled-playback";
461 
462         /**
463          * Query codec feature capabilities.
464          * <p>
465          * These features are supported to be used by the codec.  These
466          * include optional features that can be turned on, as well as
467          * features that are always on.
468          */
isFeatureSupported(String name)469         public final boolean isFeatureSupported(String name) {
470             return checkFeature(name, mFlagsSupported);
471         }
472 
473         /**
474          * Query codec feature requirements.
475          * <p>
476          * These features are required to be used by the codec, and as such,
477          * they are always turned on.
478          */
isFeatureRequired(String name)479         public final boolean isFeatureRequired(String name) {
480             return checkFeature(name, mFlagsRequired);
481         }
482 
483         private static final Feature[] decoderFeatures = {
484             new Feature(FEATURE_AdaptivePlayback, (1 << 0), true),
485             new Feature(FEATURE_SecurePlayback,   (1 << 1), false),
486             new Feature(FEATURE_TunneledPlayback, (1 << 2), false),
487         };
488 
489         /** @hide */
validFeatures()490         public String[] validFeatures() {
491             Feature[] features = getValidFeatures();
492             String[] res = new String[features.length];
493             for (int i = 0; i < res.length; i++) {
494                 res[i] = features[i].mName;
495             }
496             return res;
497         }
498 
getValidFeatures()499         private Feature[] getValidFeatures() {
500             if (!isEncoder()) {
501                 return decoderFeatures;
502             }
503             return new Feature[] {};
504         }
505 
checkFeature(String name, int flags)506         private boolean checkFeature(String name, int flags) {
507             for (Feature feat: getValidFeatures()) {
508                 if (feat.mName.equals(name)) {
509                     return (flags & feat.mValue) != 0;
510                 }
511             }
512             return false;
513         }
514 
515         /** @hide */
isRegular()516         public boolean isRegular() {
517             // regular codecs only require default features
518             for (Feature feat: getValidFeatures()) {
519                 if (!feat.mDefault && isFeatureRequired(feat.mName)) {
520                     return false;
521                 }
522             }
523             return true;
524         }
525 
526         /**
527          * Query whether codec supports a given {@link MediaFormat}.
528          *
529          * <p class=note>
530          * <strong>Note:</strong> On {@link android.os.Build.VERSION_CODES#LOLLIPOP},
531          * {@code format} must not contain a {@linkplain MediaFormat#KEY_FRAME_RATE
532          * frame rate}. Use
533          * <code class=prettyprint>format.setString(MediaFormat.KEY_FRAME_RATE, null)</code>
534          * to clear any existing frame rate setting in the format.
535          *
536          * @param format media format with optional feature directives.
537          * @throws IllegalArgumentException if format is not a valid media format.
538          * @return whether the codec capabilities support the given format
539          *         and feature requests.
540          */
isFormatSupported(MediaFormat format)541         public final boolean isFormatSupported(MediaFormat format) {
542             final Map<String, Object> map = format.getMap();
543             final String mime = (String)map.get(MediaFormat.KEY_MIME);
544 
545             // mime must match if present
546             if (mime != null && !mMime.equalsIgnoreCase(mime)) {
547                 return false;
548             }
549 
550             // check feature support
551             for (Feature feat: getValidFeatures()) {
552                 Integer yesNo = (Integer)map.get(MediaFormat.KEY_FEATURE_ + feat.mName);
553                 if (yesNo == null) {
554                     continue;
555                 }
556                 if ((yesNo == 1 && !isFeatureSupported(feat.mName)) ||
557                         (yesNo == 0 && isFeatureRequired(feat.mName))) {
558                     return false;
559                 }
560             }
561             if (mAudioCaps != null && !mAudioCaps.supportsFormat(format)) {
562                 return false;
563             }
564             if (mVideoCaps != null && !mVideoCaps.supportsFormat(format)) {
565                 return false;
566             }
567             if (mEncoderCaps != null && !mEncoderCaps.supportsFormat(format)) {
568                 return false;
569             }
570             return true;
571         }
572 
573         // errors while reading profile levels - accessed from sister capabilities
574         int mError;
575 
576         private static final String TAG = "CodecCapabilities";
577 
578         // NEW-STYLE CAPABILITIES
579         private AudioCapabilities mAudioCaps;
580         private VideoCapabilities mVideoCaps;
581         private EncoderCapabilities mEncoderCaps;
582         private MediaFormat mDefaultFormat;
583 
584         /**
585          * Returns a MediaFormat object with default values for configurations that have
586          * defaults.
587          */
getDefaultFormat()588         public MediaFormat getDefaultFormat() {
589             return mDefaultFormat;
590         }
591 
592         /**
593          * Returns the mime type for which this codec-capability object was created.
594          */
getMimeType()595         public String getMimeType() {
596             return mMime;
597         }
598 
599         /**
600          * Returns the max number of the supported concurrent codec instances.
601          * <p>
602          * This is a hint for an upper bound. Applications should not expect to successfully
603          * operate more instances than the returned value, but the actual number of
604          * concurrently operable instances may be less as it depends on the available
605          * resources at time of use.
606          */
getMaxSupportedInstances()607         public int getMaxSupportedInstances() {
608             return mMaxSupportedInstances;
609         }
610 
isAudio()611         private boolean isAudio() {
612             return mAudioCaps != null;
613         }
614 
615         /**
616          * Returns the audio capabilities or {@code null} if this is not an audio codec.
617          */
getAudioCapabilities()618         public AudioCapabilities getAudioCapabilities() {
619             return mAudioCaps;
620         }
621 
isEncoder()622         private boolean isEncoder() {
623             return mEncoderCaps != null;
624         }
625 
626         /**
627          * Returns the encoding capabilities or {@code null} if this is not an encoder.
628          */
getEncoderCapabilities()629         public EncoderCapabilities getEncoderCapabilities() {
630             return mEncoderCaps;
631         }
632 
isVideo()633         private boolean isVideo() {
634             return mVideoCaps != null;
635         }
636 
637         /**
638          * Returns the video capabilities or {@code null} if this is not a video codec.
639          */
getVideoCapabilities()640         public VideoCapabilities getVideoCapabilities() {
641             return mVideoCaps;
642         }
643 
644         /** @hide */
dup()645         public CodecCapabilities dup() {
646             return new CodecCapabilities(
647                 // clone writable arrays
648                 Arrays.copyOf(profileLevels, profileLevels.length),
649                 Arrays.copyOf(colorFormats, colorFormats.length),
650                 isEncoder(),
651                 mFlagsVerified,
652                 mDefaultFormat,
653                 mCapabilitiesInfo);
654         }
655 
656         /**
657          * Retrieve the codec capabilities for a certain {@code mime type}, {@code
658          * profile} and {@code level}.  If the type, or profile-level combination
659          * is not understood by the framework, it returns null.
660          */
createFromProfileLevel( String mime, int profile, int level)661         public static CodecCapabilities createFromProfileLevel(
662                 String mime, int profile, int level) {
663             CodecProfileLevel pl = new CodecProfileLevel();
664             pl.profile = profile;
665             pl.level = level;
666             MediaFormat defaultFormat = new MediaFormat();
667             defaultFormat.setString(MediaFormat.KEY_MIME, mime);
668 
669             CodecCapabilities ret = new CodecCapabilities(
670                 new CodecProfileLevel[] { pl }, new int[0], true /* encoder */,
671                 0 /* flags */, defaultFormat, new MediaFormat() /* info */);
672             if (ret.mError != 0) {
673                 return null;
674             }
675             return ret;
676         }
677 
CodecCapabilities( CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags, Map<String, Object>defaultFormatMap, Map<String, Object>capabilitiesMap)678         /* package private */ CodecCapabilities(
679                 CodecProfileLevel[] profLevs, int[] colFmts,
680                 boolean encoder, int flags,
681                 Map<String, Object>defaultFormatMap,
682                 Map<String, Object>capabilitiesMap) {
683             this(profLevs, colFmts, encoder, flags,
684                     new MediaFormat(defaultFormatMap),
685                     new MediaFormat(capabilitiesMap));
686         }
687 
688         private MediaFormat mCapabilitiesInfo;
689 
CodecCapabilities( CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags, MediaFormat defaultFormat, MediaFormat info)690         /* package private */ CodecCapabilities(
691                 CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags,
692                 MediaFormat defaultFormat, MediaFormat info) {
693             final Map<String, Object> map = info.getMap();
694             profileLevels = profLevs;
695             colorFormats = colFmts;
696             mFlagsVerified = flags;
697             mDefaultFormat = defaultFormat;
698             mCapabilitiesInfo = info;
699             mMime = mDefaultFormat.getString(MediaFormat.KEY_MIME);
700 
701             if (mMime.toLowerCase().startsWith("audio/")) {
702                 mAudioCaps = AudioCapabilities.create(info, this);
703                 mAudioCaps.setDefaultFormat(mDefaultFormat);
704             } else if (mMime.toLowerCase().startsWith("video/")) {
705                 mVideoCaps = VideoCapabilities.create(info, this);
706             }
707             if (encoder) {
708                 mEncoderCaps = EncoderCapabilities.create(info, this);
709                 mEncoderCaps.setDefaultFormat(mDefaultFormat);
710             }
711 
712             final Map<String, Object> global = MediaCodecList.getGlobalSettings();
713             mMaxSupportedInstances = Utils.parseIntSafely(
714                     global.get("max-concurrent-instances"), DEFAULT_MAX_SUPPORTED_INSTANCES);
715 
716             int maxInstances = Utils.parseIntSafely(
717                     map.get("max-concurrent-instances"), mMaxSupportedInstances);
718             mMaxSupportedInstances =
719                     Range.create(1, MAX_SUPPORTED_INSTANCES_LIMIT).clamp(maxInstances);
720 
721             for (Feature feat: getValidFeatures()) {
722                 String key = MediaFormat.KEY_FEATURE_ + feat.mName;
723                 Integer yesNo = (Integer)map.get(key);
724                 if (yesNo == null) {
725                     continue;
726                 }
727                 if (yesNo > 0) {
728                     mFlagsRequired |= feat.mValue;
729                 }
730                 mFlagsSupported |= feat.mValue;
731                 mDefaultFormat.setInteger(key, 1);
732                 // TODO restrict features by mFlagsVerified once all codecs reliably verify them
733             }
734         }
735     }
736 
737     /**
738      * A class that supports querying the audio capabilities of a codec.
739      */
740     public static final class AudioCapabilities {
741         private static final String TAG = "AudioCapabilities";
742         private CodecCapabilities mParent;
743         private Range<Integer> mBitrateRange;
744 
745         private int[] mSampleRates;
746         private Range<Integer>[] mSampleRateRanges;
747         private int mMaxInputChannelCount;
748 
749         private static final int MAX_INPUT_CHANNEL_COUNT = 30;
750 
751         /**
752          * Returns the range of supported bitrates in bits/second.
753          */
getBitrateRange()754         public Range<Integer> getBitrateRange() {
755             return mBitrateRange;
756         }
757 
758         /**
759          * Returns the array of supported sample rates if the codec
760          * supports only discrete values.  Otherwise, it returns
761          * {@code null}.  The array is sorted in ascending order.
762          */
getSupportedSampleRates()763         public int[] getSupportedSampleRates() {
764             return Arrays.copyOf(mSampleRates, mSampleRates.length);
765         }
766 
767         /**
768          * Returns the array of supported sample rate ranges.  The
769          * array is sorted in ascending order, and the ranges are
770          * distinct.
771          */
getSupportedSampleRateRanges()772         public Range<Integer>[] getSupportedSampleRateRanges() {
773             return Arrays.copyOf(mSampleRateRanges, mSampleRateRanges.length);
774         }
775 
776         /**
777          * Returns the maximum number of input channels supported.  The codec
778          * supports any number of channels between 1 and this maximum value.
779          */
getMaxInputChannelCount()780         public int getMaxInputChannelCount() {
781             return mMaxInputChannelCount;
782         }
783 
784         /* no public constructor */
AudioCapabilities()785         private AudioCapabilities() { }
786 
787         /** @hide */
create( MediaFormat info, CodecCapabilities parent)788         public static AudioCapabilities create(
789                 MediaFormat info, CodecCapabilities parent) {
790             AudioCapabilities caps = new AudioCapabilities();
791             caps.init(info, parent);
792             return caps;
793         }
794 
795         /** @hide */
init(MediaFormat info, CodecCapabilities parent)796         public void init(MediaFormat info, CodecCapabilities parent) {
797             mParent = parent;
798             initWithPlatformLimits();
799             applyLevelLimits();
800             parseFromInfo(info);
801         }
802 
initWithPlatformLimits()803         private void initWithPlatformLimits() {
804             mBitrateRange = Range.create(0, Integer.MAX_VALUE);
805             mMaxInputChannelCount = MAX_INPUT_CHANNEL_COUNT;
806             // mBitrateRange = Range.create(1, 320000);
807             mSampleRateRanges = new Range[] { Range.create(8000, 96000) };
808             mSampleRates = null;
809         }
810 
supports(Integer sampleRate, Integer inputChannels)811         private boolean supports(Integer sampleRate, Integer inputChannels) {
812             // channels and sample rates are checked orthogonally
813             if (inputChannels != null &&
814                     (inputChannels < 1 || inputChannels > mMaxInputChannelCount)) {
815                 return false;
816             }
817             if (sampleRate != null) {
818                 int ix = Utils.binarySearchDistinctRanges(
819                         mSampleRateRanges, sampleRate);
820                 if (ix < 0) {
821                     return false;
822                 }
823             }
824             return true;
825         }
826 
827         /**
828          * Query whether the sample rate is supported by the codec.
829          */
isSampleRateSupported(int sampleRate)830         public boolean isSampleRateSupported(int sampleRate) {
831             return supports(sampleRate, null);
832         }
833 
834         /** modifies rates */
limitSampleRates(int[] rates)835         private void limitSampleRates(int[] rates) {
836             Arrays.sort(rates);
837             ArrayList<Range<Integer>> ranges = new ArrayList<Range<Integer>>();
838             for (int rate: rates) {
839                 if (supports(rate, null /* channels */)) {
840                     ranges.add(Range.create(rate, rate));
841                 }
842             }
843             mSampleRateRanges = ranges.toArray(new Range[ranges.size()]);
844             createDiscreteSampleRates();
845         }
846 
createDiscreteSampleRates()847         private void createDiscreteSampleRates() {
848             mSampleRates = new int[mSampleRateRanges.length];
849             for (int i = 0; i < mSampleRateRanges.length; i++) {
850                 mSampleRates[i] = mSampleRateRanges[i].getLower();
851             }
852         }
853 
854         /** modifies rateRanges */
limitSampleRates(Range<Integer>[] rateRanges)855         private void limitSampleRates(Range<Integer>[] rateRanges) {
856             sortDistinctRanges(rateRanges);
857             mSampleRateRanges = intersectSortedDistinctRanges(mSampleRateRanges, rateRanges);
858 
859             // check if all values are discrete
860             for (Range<Integer> range: mSampleRateRanges) {
861                 if (!range.getLower().equals(range.getUpper())) {
862                     mSampleRates = null;
863                     return;
864                 }
865             }
866             createDiscreteSampleRates();
867         }
868 
applyLevelLimits()869         private void applyLevelLimits() {
870             int[] sampleRates = null;
871             Range<Integer> sampleRateRange = null, bitRates = null;
872             int maxChannels = 0;
873             String mime = mParent.getMimeType();
874 
875             if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MPEG)) {
876                 sampleRates = new int[] {
877                         8000, 11025, 12000,
878                         16000, 22050, 24000,
879                         32000, 44100, 48000 };
880                 bitRates = Range.create(8000, 320000);
881                 maxChannels = 2;
882             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)) {
883                 sampleRates = new int[] { 8000 };
884                 bitRates = Range.create(4750, 12200);
885                 maxChannels = 1;
886             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)) {
887                 sampleRates = new int[] { 16000 };
888                 bitRates = Range.create(6600, 23850);
889                 maxChannels = 1;
890             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC)) {
891                 sampleRates = new int[] {
892                         7350, 8000,
893                         11025, 12000, 16000,
894                         22050, 24000, 32000,
895                         44100, 48000, 64000,
896                         88200, 96000 };
897                 bitRates = Range.create(8000, 510000);
898                 maxChannels = 48;
899             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_VORBIS)) {
900                 bitRates = Range.create(32000, 500000);
901                 sampleRateRange = Range.create(8000, 192000);
902                 maxChannels = 255;
903             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_OPUS)) {
904                 bitRates = Range.create(6000, 510000);
905                 sampleRates = new int[] { 8000, 12000, 16000, 24000, 48000 };
906                 maxChannels = 255;
907             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW)) {
908                 sampleRateRange = Range.create(1, 96000);
909                 bitRates = Range.create(1, 10000000);
910                 maxChannels = 8;
911             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
912                 sampleRateRange = Range.create(1, 655350);
913                 // lossless codec, so bitrate is ignored
914                 maxChannels = 255;
915             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW)
916                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)) {
917                 sampleRates = new int[] { 8000 };
918                 bitRates = Range.create(64000, 64000);
919                 // platform allows multiple channels for this format
920             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) {
921                 sampleRates = new int[] { 8000 };
922                 bitRates = Range.create(13000, 13000);
923                 maxChannels = 1;
924             } else {
925                 Log.w(TAG, "Unsupported mime " + mime);
926                 mParent.mError |= ERROR_UNSUPPORTED;
927             }
928 
929             // restrict ranges
930             if (sampleRates != null) {
931                 limitSampleRates(sampleRates);
932             } else if (sampleRateRange != null) {
933                 limitSampleRates(new Range[] { sampleRateRange });
934             }
935             applyLimits(maxChannels, bitRates);
936         }
937 
applyLimits(int maxInputChannels, Range<Integer> bitRates)938         private void applyLimits(int maxInputChannels, Range<Integer> bitRates) {
939             mMaxInputChannelCount = Range.create(1, mMaxInputChannelCount)
940                     .clamp(maxInputChannels);
941             if (bitRates != null) {
942                 mBitrateRange = mBitrateRange.intersect(bitRates);
943             }
944         }
945 
parseFromInfo(MediaFormat info)946         private void parseFromInfo(MediaFormat info) {
947             int maxInputChannels = MAX_INPUT_CHANNEL_COUNT;
948             Range<Integer> bitRates = POSITIVE_INTEGERS;
949 
950             if (info.containsKey("sample-rate-ranges")) {
951                 String[] rateStrings = info.getString("sample-rate-ranges").split(",");
952                 Range<Integer>[] rateRanges = new Range[rateStrings.length];
953                 for (int i = 0; i < rateStrings.length; i++) {
954                     rateRanges[i] = Utils.parseIntRange(rateStrings[i], null);
955                 }
956                 limitSampleRates(rateRanges);
957             }
958             if (info.containsKey("max-channel-count")) {
959                 maxInputChannels = Utils.parseIntSafely(
960                         info.getString("max-channel-count"), maxInputChannels);
961             }
962             if (info.containsKey("bitrate-range")) {
963                 bitRates = bitRates.intersect(
964                         Utils.parseIntRange(info.getString("bitrate-range"), bitRates));
965             }
966             applyLimits(maxInputChannels, bitRates);
967         }
968 
969         /** @hide */
setDefaultFormat(MediaFormat format)970         public void setDefaultFormat(MediaFormat format) {
971             // report settings that have only a single choice
972             if (mBitrateRange.getLower().equals(mBitrateRange.getUpper())) {
973                 format.setInteger(MediaFormat.KEY_BIT_RATE, mBitrateRange.getLower());
974             }
975             if (mMaxInputChannelCount == 1) {
976                 // mono-only format
977                 format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
978             }
979             if (mSampleRates != null && mSampleRates.length == 1) {
980                 format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRates[0]);
981             }
982         }
983 
984         /** @hide */
supportsFormat(MediaFormat format)985         public boolean supportsFormat(MediaFormat format) {
986             Map<String, Object> map = format.getMap();
987             Integer sampleRate = (Integer)map.get(MediaFormat.KEY_SAMPLE_RATE);
988             Integer channels = (Integer)map.get(MediaFormat.KEY_CHANNEL_COUNT);
989             if (!supports(sampleRate, channels)) {
990                 return false;
991             }
992 
993             // nothing to do for:
994             // KEY_CHANNEL_MASK: codecs don't get this
995             // KEY_IS_ADTS:      required feature for all AAC decoders
996             return true;
997         }
998     }
999 
1000     /**
1001      * A class that supports querying the video capabilities of a codec.
1002      */
1003     public static final class VideoCapabilities {
1004         private static final String TAG = "VideoCapabilities";
1005         private CodecCapabilities mParent;
1006         private Range<Integer> mBitrateRange;
1007 
1008         private Range<Integer> mHeightRange;
1009         private Range<Integer> mWidthRange;
1010         private Range<Integer> mBlockCountRange;
1011         private Range<Integer> mHorizontalBlockRange;
1012         private Range<Integer> mVerticalBlockRange;
1013         private Range<Rational> mAspectRatioRange;
1014         private Range<Rational> mBlockAspectRatioRange;
1015         private Range<Long> mBlocksPerSecondRange;
1016         private Map<Size, Range<Long>> mMeasuredFrameRates;
1017         private Range<Integer> mFrameRateRange;
1018 
1019         private int mBlockWidth;
1020         private int mBlockHeight;
1021         private int mWidthAlignment;
1022         private int mHeightAlignment;
1023         private int mSmallerDimensionUpperLimit;
1024 
1025         /**
1026          * Returns the range of supported bitrates in bits/second.
1027          */
getBitrateRange()1028         public Range<Integer> getBitrateRange() {
1029             return mBitrateRange;
1030         }
1031 
1032         /**
1033          * Returns the range of supported video widths.
1034          */
getSupportedWidths()1035         public Range<Integer> getSupportedWidths() {
1036             return mWidthRange;
1037         }
1038 
1039         /**
1040          * Returns the range of supported video heights.
1041          */
getSupportedHeights()1042         public Range<Integer> getSupportedHeights() {
1043             return mHeightRange;
1044         }
1045 
1046         /**
1047          * Returns the alignment requirement for video width (in pixels).
1048          *
1049          * This is a power-of-2 value that video width must be a
1050          * multiple of.
1051          */
getWidthAlignment()1052         public int getWidthAlignment() {
1053             return mWidthAlignment;
1054         }
1055 
1056         /**
1057          * Returns the alignment requirement for video height (in pixels).
1058          *
1059          * This is a power-of-2 value that video height must be a
1060          * multiple of.
1061          */
getHeightAlignment()1062         public int getHeightAlignment() {
1063             return mHeightAlignment;
1064         }
1065 
1066         /**
1067          * Return the upper limit on the smaller dimension of width or height.
1068          * <p></p>
1069          * Some codecs have a limit on the smaller dimension, whether it be
1070          * the width or the height.  E.g. a codec may only be able to handle
1071          * up to 1920x1080 both in landscape and portrait mode (1080x1920).
1072          * In this case the maximum width and height are both 1920, but the
1073          * smaller dimension limit will be 1080. For other codecs, this is
1074          * {@code Math.min(getSupportedWidths().getUpper(),
1075          * getSupportedHeights().getUpper())}.
1076          *
1077          * @hide
1078          */
getSmallerDimensionUpperLimit()1079         public int getSmallerDimensionUpperLimit() {
1080             return mSmallerDimensionUpperLimit;
1081         }
1082 
1083         /**
1084          * Returns the range of supported frame rates.
1085          * <p>
1086          * This is not a performance indicator.  Rather, it expresses the
1087          * limits specified in the coding standard, based on the complexities
1088          * of encoding material for later playback at a certain frame rate,
1089          * or the decoding of such material in non-realtime.
1090          */
getSupportedFrameRates()1091         public Range<Integer> getSupportedFrameRates() {
1092             return mFrameRateRange;
1093         }
1094 
1095         /**
1096          * Returns the range of supported video widths for a video height.
1097          * @param height the height of the video
1098          */
getSupportedWidthsFor(int height)1099         public Range<Integer> getSupportedWidthsFor(int height) {
1100             try {
1101                 Range<Integer> range = mWidthRange;
1102                 if (!mHeightRange.contains(height)
1103                         || (height % mHeightAlignment) != 0) {
1104                     throw new IllegalArgumentException("unsupported height");
1105                 }
1106                 final int heightInBlocks = Utils.divUp(height, mBlockHeight);
1107 
1108                 // constrain by block count and by block aspect ratio
1109                 final int minWidthInBlocks = Math.max(
1110                         Utils.divUp(mBlockCountRange.getLower(), heightInBlocks),
1111                         (int)Math.ceil(mBlockAspectRatioRange.getLower().doubleValue()
1112                                 * heightInBlocks));
1113                 final int maxWidthInBlocks = Math.min(
1114                         mBlockCountRange.getUpper() / heightInBlocks,
1115                         (int)(mBlockAspectRatioRange.getUpper().doubleValue()
1116                                 * heightInBlocks));
1117                 range = range.intersect(
1118                         (minWidthInBlocks - 1) * mBlockWidth + mWidthAlignment,
1119                         maxWidthInBlocks * mBlockWidth);
1120 
1121                 // constrain by smaller dimension limit
1122                 if (height > mSmallerDimensionUpperLimit) {
1123                     range = range.intersect(1, mSmallerDimensionUpperLimit);
1124                 }
1125 
1126                 // constrain by aspect ratio
1127                 range = range.intersect(
1128                         (int)Math.ceil(mAspectRatioRange.getLower().doubleValue()
1129                                 * height),
1130                         (int)(mAspectRatioRange.getUpper().doubleValue() * height));
1131                 return range;
1132             } catch (IllegalArgumentException e) {
1133                 // height is not supported because there are no suitable widths
1134                 Log.v(TAG, "could not get supported widths for " + height);
1135                 throw new IllegalArgumentException("unsupported height");
1136             }
1137         }
1138 
1139         /**
1140          * Returns the range of supported video heights for a video width
1141          * @param width the width of the video
1142          */
getSupportedHeightsFor(int width)1143         public Range<Integer> getSupportedHeightsFor(int width) {
1144             try {
1145                 Range<Integer> range = mHeightRange;
1146                 if (!mWidthRange.contains(width)
1147                         || (width % mWidthAlignment) != 0) {
1148                     throw new IllegalArgumentException("unsupported width");
1149                 }
1150                 final int widthInBlocks = Utils.divUp(width, mBlockWidth);
1151 
1152                 // constrain by block count and by block aspect ratio
1153                 final int minHeightInBlocks = Math.max(
1154                         Utils.divUp(mBlockCountRange.getLower(), widthInBlocks),
1155                         (int)Math.ceil(widthInBlocks /
1156                                 mBlockAspectRatioRange.getUpper().doubleValue()));
1157                 final int maxHeightInBlocks = Math.min(
1158                         mBlockCountRange.getUpper() / widthInBlocks,
1159                         (int)(widthInBlocks /
1160                                 mBlockAspectRatioRange.getLower().doubleValue()));
1161                 range = range.intersect(
1162                         (minHeightInBlocks - 1) * mBlockHeight + mHeightAlignment,
1163                         maxHeightInBlocks * mBlockHeight);
1164 
1165                 // constrain by smaller dimension limit
1166                 if (width > mSmallerDimensionUpperLimit) {
1167                     range = range.intersect(1, mSmallerDimensionUpperLimit);
1168                 }
1169 
1170                 // constrain by aspect ratio
1171                 range = range.intersect(
1172                         (int)Math.ceil(width /
1173                                 mAspectRatioRange.getUpper().doubleValue()),
1174                         (int)(width / mAspectRatioRange.getLower().doubleValue()));
1175                 return range;
1176             } catch (IllegalArgumentException e) {
1177                 // width is not supported because there are no suitable heights
1178                 Log.v(TAG, "could not get supported heights for " + width);
1179                 throw new IllegalArgumentException("unsupported width");
1180             }
1181         }
1182 
1183         /**
1184          * Returns the range of supported video frame rates for a video size.
1185          * <p>
1186          * This is not a performance indicator.  Rather, it expresses the limits specified in
1187          * the coding standard, based on the complexities of encoding material of a given
1188          * size for later playback at a certain frame rate, or the decoding of such material
1189          * in non-realtime.
1190 
1191          * @param width the width of the video
1192          * @param height the height of the video
1193          */
getSupportedFrameRatesFor(int width, int height)1194         public Range<Double> getSupportedFrameRatesFor(int width, int height) {
1195             Range<Integer> range = mHeightRange;
1196             if (!supports(width, height, null)) {
1197                 throw new IllegalArgumentException("unsupported size");
1198             }
1199             final int blockCount =
1200                 Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight);
1201 
1202             return Range.create(
1203                     Math.max(mBlocksPerSecondRange.getLower() / (double) blockCount,
1204                             (double) mFrameRateRange.getLower()),
1205                     Math.min(mBlocksPerSecondRange.getUpper() / (double) blockCount,
1206                             (double) mFrameRateRange.getUpper()));
1207         }
1208 
getBlockCount(int width, int height)1209         private int getBlockCount(int width, int height) {
1210             return Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight);
1211         }
1212 
1213         @NonNull
findClosestSize(int width, int height)1214         private Size findClosestSize(int width, int height) {
1215             int targetBlockCount = getBlockCount(width, height);
1216             Size closestSize = null;
1217             int minDiff = Integer.MAX_VALUE;
1218             for (Size size : mMeasuredFrameRates.keySet()) {
1219                 int diff = Math.abs(targetBlockCount -
1220                         getBlockCount(size.getWidth(), size.getHeight()));
1221                 if (diff < minDiff) {
1222                     minDiff = diff;
1223                     closestSize = size;
1224                 }
1225             }
1226             return closestSize;
1227         }
1228 
estimateFrameRatesFor(int width, int height)1229         private Range<Double> estimateFrameRatesFor(int width, int height) {
1230             Size size = findClosestSize(width, height);
1231             Range<Long> range = mMeasuredFrameRates.get(size);
1232             Double ratio = (double)(size.getWidth() * size.getHeight()) / (width * height);
1233             return Range.create(range.getLower() * ratio, range.getUpper() * ratio);
1234         }
1235 
1236         /**
1237          * Returns the range of achievable video frame rates for a video size.
1238          * May return {@code null}, if the codec did not publish any measurement
1239          * data.
1240          * <p>
1241          * This is a performance estimate provided by the device manufacturer
1242          * based on full-speed decoding and encoding measurements in various configurations
1243          * of common video sizes supported by the codec. As such it should only be used to
1244          * compare individual codecs on the device. The value is not suitable for comparing
1245          * different devices or even different android releases for the same device.
1246          * <p>
1247          * The returned range corresponds to the fastest frame rates achieved in the tested
1248          * configurations. It is interpolated from the nearest frame size(s) tested. Codec
1249          * performance is severely impacted by other activity on the device, and can vary
1250          * significantly.
1251          * <p class=note>
1252          * Use this method in cases where only codec performance matters, e.g. to evaluate if
1253          * a codec has any chance of meeting a performance target. Codecs are listed
1254          * in {@link MediaCodecList} in the preferred order as defined by the device
1255          * manufacturer. As such, applications should use the first suitable codec in the
1256          * list to achieve the best balance between power use and performance.
1257          *
1258          * @param width the width of the video
1259          * @param height the height of the video
1260          *
1261          * @throws IllegalArgumentException if the video size is not supported.
1262          */
1263         @Nullable
getAchievableFrameRatesFor(int width, int height)1264         public Range<Double> getAchievableFrameRatesFor(int width, int height) {
1265             if (!supports(width, height, null)) {
1266                 throw new IllegalArgumentException("unsupported size");
1267             }
1268 
1269             if (mMeasuredFrameRates == null || mMeasuredFrameRates.size() <= 0) {
1270                 Log.w(TAG, "Codec did not publish any measurement data.");
1271                 return null;
1272             }
1273 
1274             return estimateFrameRatesFor(width, height);
1275         }
1276 
1277         /**
1278          * Returns whether a given video size ({@code width} and
1279          * {@code height}) and {@code frameRate} combination is supported.
1280          */
areSizeAndRateSupported( int width, int height, double frameRate)1281         public boolean areSizeAndRateSupported(
1282                 int width, int height, double frameRate) {
1283             return supports(width, height, frameRate);
1284         }
1285 
1286         /**
1287          * Returns whether a given video size ({@code width} and
1288          * {@code height}) is supported.
1289          */
isSizeSupported(int width, int height)1290         public boolean isSizeSupported(int width, int height) {
1291             return supports(width, height, null);
1292         }
1293 
supports( Integer width, Integer height, Number rate)1294         private boolean supports(
1295                 Integer width, Integer height, Number rate) {
1296             boolean ok = true;
1297 
1298             if (ok && width != null) {
1299                 ok = mWidthRange.contains(width)
1300                         && (width % mWidthAlignment == 0);
1301             }
1302             if (ok && height != null) {
1303                 ok = mHeightRange.contains(height)
1304                         && (height % mHeightAlignment == 0);
1305             }
1306             if (ok && rate != null) {
1307                 ok = mFrameRateRange.contains(Utils.intRangeFor(rate.doubleValue()));
1308             }
1309             if (ok && height != null && width != null) {
1310                 ok = Math.min(height, width) <= mSmallerDimensionUpperLimit;
1311 
1312                 final int widthInBlocks = Utils.divUp(width, mBlockWidth);
1313                 final int heightInBlocks = Utils.divUp(height, mBlockHeight);
1314                 final int blockCount = widthInBlocks * heightInBlocks;
1315                 ok = ok && mBlockCountRange.contains(blockCount)
1316                         && mBlockAspectRatioRange.contains(
1317                                 new Rational(widthInBlocks, heightInBlocks))
1318                         && mAspectRatioRange.contains(new Rational(width, height));
1319                 if (ok && rate != null) {
1320                     double blocksPerSec = blockCount * rate.doubleValue();
1321                     ok = mBlocksPerSecondRange.contains(
1322                             Utils.longRangeFor(blocksPerSec));
1323                 }
1324             }
1325             return ok;
1326         }
1327 
1328         /**
1329          * @hide
1330          * @throws java.lang.ClassCastException */
supportsFormat(MediaFormat format)1331         public boolean supportsFormat(MediaFormat format) {
1332             final Map<String, Object> map = format.getMap();
1333             Integer width = (Integer)map.get(MediaFormat.KEY_WIDTH);
1334             Integer height = (Integer)map.get(MediaFormat.KEY_HEIGHT);
1335             Number rate = (Number)map.get(MediaFormat.KEY_FRAME_RATE);
1336 
1337             // we ignore color-format for now as it is not reliably reported by codec
1338 
1339             return supports(width, height, rate);
1340         }
1341 
1342         /* no public constructor */
VideoCapabilities()1343         private VideoCapabilities() { }
1344 
1345         /** @hide */
create( MediaFormat info, CodecCapabilities parent)1346         public static VideoCapabilities create(
1347                 MediaFormat info, CodecCapabilities parent) {
1348             VideoCapabilities caps = new VideoCapabilities();
1349             caps.init(info, parent);
1350             return caps;
1351         }
1352 
1353         /** @hide */
init(MediaFormat info, CodecCapabilities parent)1354         public void init(MediaFormat info, CodecCapabilities parent) {
1355             mParent = parent;
1356             initWithPlatformLimits();
1357             applyLevelLimits();
1358             parseFromInfo(info);
1359             updateLimits();
1360         }
1361 
1362         /** @hide */
getBlockSize()1363         public Size getBlockSize() {
1364             return new Size(mBlockWidth, mBlockHeight);
1365         }
1366 
1367         /** @hide */
getBlockCountRange()1368         public Range<Integer> getBlockCountRange() {
1369             return mBlockCountRange;
1370         }
1371 
1372         /** @hide */
getBlocksPerSecondRange()1373         public Range<Long> getBlocksPerSecondRange() {
1374             return mBlocksPerSecondRange;
1375         }
1376 
1377         /** @hide */
getAspectRatioRange(boolean blocks)1378         public Range<Rational> getAspectRatioRange(boolean blocks) {
1379             return blocks ? mBlockAspectRatioRange : mAspectRatioRange;
1380         }
1381 
initWithPlatformLimits()1382         private void initWithPlatformLimits() {
1383             mBitrateRange = BITRATE_RANGE;
1384 
1385             mWidthRange  = SIZE_RANGE;
1386             mHeightRange = SIZE_RANGE;
1387             mFrameRateRange = FRAME_RATE_RANGE;
1388 
1389             mHorizontalBlockRange = SIZE_RANGE;
1390             mVerticalBlockRange   = SIZE_RANGE;
1391 
1392             // full positive ranges are supported as these get calculated
1393             mBlockCountRange      = POSITIVE_INTEGERS;
1394             mBlocksPerSecondRange = POSITIVE_LONGS;
1395 
1396             mBlockAspectRatioRange = POSITIVE_RATIONALS;
1397             mAspectRatioRange      = POSITIVE_RATIONALS;
1398 
1399             // YUV 4:2:0 requires 2:2 alignment
1400             mWidthAlignment = 2;
1401             mHeightAlignment = 2;
1402             mBlockWidth = 2;
1403             mBlockHeight = 2;
1404             mSmallerDimensionUpperLimit = SIZE_RANGE.getUpper();
1405         }
1406 
getMeasuredFrameRates(Map<String, Object> map)1407         private Map<Size, Range<Long>> getMeasuredFrameRates(Map<String, Object> map) {
1408             Map<Size, Range<Long>> ret = new HashMap<Size, Range<Long>>();
1409             final String prefix = "measured-frame-rate-";
1410             Set<String> keys = map.keySet();
1411             for (String key : keys) {
1412                 // looking for: measured-frame-rate-WIDTHxHEIGHT-range
1413                 if (!key.startsWith(prefix)) {
1414                     continue;
1415                 }
1416                 String subKey = key.substring(prefix.length());
1417                 String[] temp = key.split("-");
1418                 if (temp.length != 5) {
1419                     continue;
1420                 }
1421                 String sizeStr = temp[3];
1422                 Size size = Utils.parseSize(sizeStr, null);
1423                 if (size == null || size.getWidth() * size.getHeight() <= 0) {
1424                     continue;
1425                 }
1426                 Range<Long> range = Utils.parseLongRange(map.get(key), null);
1427                 if (range == null || range.getLower() < 0 || range.getUpper() < 0) {
1428                     continue;
1429                 }
1430                 ret.put(size, range);
1431             }
1432             return ret;
1433         }
1434 
parseFromInfo(MediaFormat info)1435         private void parseFromInfo(MediaFormat info) {
1436             final Map<String, Object> map = info.getMap();
1437             Size blockSize = new Size(mBlockWidth, mBlockHeight);
1438             Size alignment = new Size(mWidthAlignment, mHeightAlignment);
1439             Range<Integer> counts = null, widths = null, heights = null;
1440             Range<Integer> frameRates = null, bitRates = null;
1441             Range<Long> blockRates = null;
1442             Range<Rational> ratios = null, blockRatios = null;
1443 
1444             blockSize = Utils.parseSize(map.get("block-size"), blockSize);
1445             alignment = Utils.parseSize(map.get("alignment"), alignment);
1446             counts = Utils.parseIntRange(map.get("block-count-range"), null);
1447             blockRates =
1448                 Utils.parseLongRange(map.get("blocks-per-second-range"), null);
1449             mMeasuredFrameRates = getMeasuredFrameRates(map);
1450             {
1451                 Object o = map.get("size-range");
1452                 Pair<Size, Size> sizeRange = Utils.parseSizeRange(o);
1453                 if (sizeRange != null) {
1454                     try {
1455                         widths = Range.create(
1456                                 sizeRange.first.getWidth(),
1457                                 sizeRange.second.getWidth());
1458                         heights = Range.create(
1459                                 sizeRange.first.getHeight(),
1460                                 sizeRange.second.getHeight());
1461                     } catch (IllegalArgumentException e) {
1462                         Log.w(TAG, "could not parse size range '" + o + "'");
1463                         widths = null;
1464                         heights = null;
1465                     }
1466                 }
1467             }
1468             // for now this just means using the smaller max size as 2nd
1469             // upper limit.
1470             // for now we are keeping the profile specific "width/height
1471             // in macroblocks" limits.
1472             if (map.containsKey("feature-can-swap-width-height")) {
1473                 if (widths != null) {
1474                     mSmallerDimensionUpperLimit =
1475                         Math.min(widths.getUpper(), heights.getUpper());
1476                     widths = heights = widths.extend(heights);
1477                 } else {
1478                     Log.w(TAG, "feature can-swap-width-height is best used with size-range");
1479                     mSmallerDimensionUpperLimit =
1480                         Math.min(mWidthRange.getUpper(), mHeightRange.getUpper());
1481                     mWidthRange = mHeightRange = mWidthRange.extend(mHeightRange);
1482                 }
1483             }
1484 
1485             ratios = Utils.parseRationalRange(
1486                     map.get("block-aspect-ratio-range"), null);
1487             blockRatios = Utils.parseRationalRange(
1488                     map.get("pixel-aspect-ratio-range"), null);
1489             frameRates = Utils.parseIntRange(map.get("frame-rate-range"), null);
1490             if (frameRates != null) {
1491                 try {
1492                     frameRates = frameRates.intersect(FRAME_RATE_RANGE);
1493                 } catch (IllegalArgumentException e) {
1494                     Log.w(TAG, "frame rate range (" + frameRates
1495                             + ") is out of limits: " + FRAME_RATE_RANGE);
1496                     frameRates = null;
1497                 }
1498             }
1499             bitRates = Utils.parseIntRange(map.get("bitrate-range"), null);
1500             if (bitRates != null) {
1501                 try {
1502                     bitRates = bitRates.intersect(BITRATE_RANGE);
1503                 } catch (IllegalArgumentException e) {
1504                     Log.w(TAG,  "bitrate range (" + bitRates
1505                             + ") is out of limits: " + BITRATE_RANGE);
1506                     bitRates = null;
1507                 }
1508             }
1509 
1510             checkPowerOfTwo(
1511                     blockSize.getWidth(), "block-size width must be power of two");
1512             checkPowerOfTwo(
1513                     blockSize.getHeight(), "block-size height must be power of two");
1514 
1515             checkPowerOfTwo(
1516                     alignment.getWidth(), "alignment width must be power of two");
1517             checkPowerOfTwo(
1518                     alignment.getHeight(), "alignment height must be power of two");
1519 
1520             // update block-size and alignment
1521             applyMacroBlockLimits(
1522                     Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE,
1523                     Long.MAX_VALUE, blockSize.getWidth(), blockSize.getHeight(),
1524                     alignment.getWidth(), alignment.getHeight());
1525 
1526             if ((mParent.mError & ERROR_UNSUPPORTED) != 0) {
1527                 // codec supports profiles that we don't know.
1528                 // Use supplied values clipped to platform limits
1529                 if (widths != null) {
1530                     mWidthRange = SIZE_RANGE.intersect(widths);
1531                 }
1532                 if (heights != null) {
1533                     mHeightRange = SIZE_RANGE.intersect(heights);
1534                 }
1535                 if (counts != null) {
1536                     mBlockCountRange = POSITIVE_INTEGERS.intersect(
1537                             Utils.factorRange(counts, mBlockWidth * mBlockHeight
1538                                     / blockSize.getWidth() / blockSize.getHeight()));
1539                 }
1540                 if (blockRates != null) {
1541                     mBlocksPerSecondRange = POSITIVE_LONGS.intersect(
1542                             Utils.factorRange(blockRates, mBlockWidth * mBlockHeight
1543                                     / blockSize.getWidth() / blockSize.getHeight()));
1544                 }
1545                 if (blockRatios != null) {
1546                     mBlockAspectRatioRange = POSITIVE_RATIONALS.intersect(
1547                             Utils.scaleRange(blockRatios,
1548                                     mBlockHeight / blockSize.getHeight(),
1549                                     mBlockWidth / blockSize.getWidth()));
1550                 }
1551                 if (ratios != null) {
1552                     mAspectRatioRange = POSITIVE_RATIONALS.intersect(ratios);
1553                 }
1554                 if (frameRates != null) {
1555                     mFrameRateRange = FRAME_RATE_RANGE.intersect(frameRates);
1556                 }
1557                 if (bitRates != null) {
1558                     mBitrateRange = BITRATE_RANGE.intersect(bitRates);
1559                 }
1560             } else {
1561                 // no unsupported profile/levels, so restrict values to known limits
1562                 if (widths != null) {
1563                     mWidthRange = mWidthRange.intersect(widths);
1564                 }
1565                 if (heights != null) {
1566                     mHeightRange = mHeightRange.intersect(heights);
1567                 }
1568                 if (counts != null) {
1569                     mBlockCountRange = mBlockCountRange.intersect(
1570                             Utils.factorRange(counts, mBlockWidth * mBlockHeight
1571                                     / blockSize.getWidth() / blockSize.getHeight()));
1572                 }
1573                 if (blockRates != null) {
1574                     mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(
1575                             Utils.factorRange(blockRates, mBlockWidth * mBlockHeight
1576                                     / blockSize.getWidth() / blockSize.getHeight()));
1577                 }
1578                 if (blockRatios != null) {
1579                     mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(
1580                             Utils.scaleRange(blockRatios,
1581                                     mBlockHeight / blockSize.getHeight(),
1582                                     mBlockWidth / blockSize.getWidth()));
1583                 }
1584                 if (ratios != null) {
1585                     mAspectRatioRange = mAspectRatioRange.intersect(ratios);
1586                 }
1587                 if (frameRates != null) {
1588                     mFrameRateRange = mFrameRateRange.intersect(frameRates);
1589                 }
1590                 if (bitRates != null) {
1591                     mBitrateRange = mBitrateRange.intersect(bitRates);
1592                 }
1593             }
1594             updateLimits();
1595         }
1596 
applyBlockLimits( int blockWidth, int blockHeight, Range<Integer> counts, Range<Long> rates, Range<Rational> ratios)1597         private void applyBlockLimits(
1598                 int blockWidth, int blockHeight,
1599                 Range<Integer> counts, Range<Long> rates, Range<Rational> ratios) {
1600             checkPowerOfTwo(blockWidth, "blockWidth must be a power of two");
1601             checkPowerOfTwo(blockHeight, "blockHeight must be a power of two");
1602 
1603             final int newBlockWidth = Math.max(blockWidth, mBlockWidth);
1604             final int newBlockHeight = Math.max(blockHeight, mBlockHeight);
1605 
1606             // factor will always be a power-of-2
1607             int factor =
1608                 newBlockWidth * newBlockHeight / mBlockWidth / mBlockHeight;
1609             if (factor != 1) {
1610                 mBlockCountRange = Utils.factorRange(mBlockCountRange, factor);
1611                 mBlocksPerSecondRange = Utils.factorRange(
1612                         mBlocksPerSecondRange, factor);
1613                 mBlockAspectRatioRange = Utils.scaleRange(
1614                         mBlockAspectRatioRange,
1615                         newBlockHeight / mBlockHeight,
1616                         newBlockWidth / mBlockWidth);
1617                 mHorizontalBlockRange = Utils.factorRange(
1618                         mHorizontalBlockRange, newBlockWidth / mBlockWidth);
1619                 mVerticalBlockRange = Utils.factorRange(
1620                         mVerticalBlockRange, newBlockHeight / mBlockHeight);
1621             }
1622             factor = newBlockWidth * newBlockHeight / blockWidth / blockHeight;
1623             if (factor != 1) {
1624                 counts = Utils.factorRange(counts, factor);
1625                 rates = Utils.factorRange(rates, factor);
1626                 ratios = Utils.scaleRange(
1627                         ratios, newBlockHeight / blockHeight,
1628                         newBlockWidth / blockWidth);
1629             }
1630             mBlockCountRange = mBlockCountRange.intersect(counts);
1631             mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(rates);
1632             mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(ratios);
1633             mBlockWidth = newBlockWidth;
1634             mBlockHeight = newBlockHeight;
1635         }
1636 
applyAlignment(int widthAlignment, int heightAlignment)1637         private void applyAlignment(int widthAlignment, int heightAlignment) {
1638             checkPowerOfTwo(widthAlignment, "widthAlignment must be a power of two");
1639             checkPowerOfTwo(heightAlignment, "heightAlignment must be a power of two");
1640 
1641             if (widthAlignment > mBlockWidth || heightAlignment > mBlockHeight) {
1642                 // maintain assumption that 0 < alignment <= block-size
1643                 applyBlockLimits(
1644                         Math.max(widthAlignment, mBlockWidth),
1645                         Math.max(heightAlignment, mBlockHeight),
1646                         POSITIVE_INTEGERS, POSITIVE_LONGS, POSITIVE_RATIONALS);
1647             }
1648 
1649             mWidthAlignment = Math.max(widthAlignment, mWidthAlignment);
1650             mHeightAlignment = Math.max(heightAlignment, mHeightAlignment);
1651 
1652             mWidthRange = Utils.alignRange(mWidthRange, mWidthAlignment);
1653             mHeightRange = Utils.alignRange(mHeightRange, mHeightAlignment);
1654         }
1655 
updateLimits()1656         private void updateLimits() {
1657             // pixels -> blocks <- counts
1658             mHorizontalBlockRange = mHorizontalBlockRange.intersect(
1659                     Utils.factorRange(mWidthRange, mBlockWidth));
1660             mHorizontalBlockRange = mHorizontalBlockRange.intersect(
1661                     Range.create(
1662                             mBlockCountRange.getLower() / mVerticalBlockRange.getUpper(),
1663                             mBlockCountRange.getUpper() / mVerticalBlockRange.getLower()));
1664             mVerticalBlockRange = mVerticalBlockRange.intersect(
1665                     Utils.factorRange(mHeightRange, mBlockHeight));
1666             mVerticalBlockRange = mVerticalBlockRange.intersect(
1667                     Range.create(
1668                             mBlockCountRange.getLower() / mHorizontalBlockRange.getUpper(),
1669                             mBlockCountRange.getUpper() / mHorizontalBlockRange.getLower()));
1670             mBlockCountRange = mBlockCountRange.intersect(
1671                     Range.create(
1672                             mHorizontalBlockRange.getLower()
1673                                     * mVerticalBlockRange.getLower(),
1674                             mHorizontalBlockRange.getUpper()
1675                                     * mVerticalBlockRange.getUpper()));
1676             mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(
1677                     new Rational(
1678                             mHorizontalBlockRange.getLower(), mVerticalBlockRange.getUpper()),
1679                     new Rational(
1680                             mHorizontalBlockRange.getUpper(), mVerticalBlockRange.getLower()));
1681 
1682             // blocks -> pixels
1683             mWidthRange = mWidthRange.intersect(
1684                     (mHorizontalBlockRange.getLower() - 1) * mBlockWidth + mWidthAlignment,
1685                     mHorizontalBlockRange.getUpper() * mBlockWidth);
1686             mHeightRange = mHeightRange.intersect(
1687                     (mVerticalBlockRange.getLower() - 1) * mBlockHeight + mHeightAlignment,
1688                     mVerticalBlockRange.getUpper() * mBlockHeight);
1689             mAspectRatioRange = mAspectRatioRange.intersect(
1690                     new Rational(mWidthRange.getLower(), mHeightRange.getUpper()),
1691                     new Rational(mWidthRange.getUpper(), mHeightRange.getLower()));
1692 
1693             mSmallerDimensionUpperLimit = Math.min(
1694                     mSmallerDimensionUpperLimit,
1695                     Math.min(mWidthRange.getUpper(), mHeightRange.getUpper()));
1696 
1697             // blocks -> rate
1698             mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(
1699                     mBlockCountRange.getLower() * (long)mFrameRateRange.getLower(),
1700                     mBlockCountRange.getUpper() * (long)mFrameRateRange.getUpper());
1701             mFrameRateRange = mFrameRateRange.intersect(
1702                     (int)(mBlocksPerSecondRange.getLower()
1703                             / mBlockCountRange.getUpper()),
1704                     (int)(mBlocksPerSecondRange.getUpper()
1705                             / (double)mBlockCountRange.getLower()));
1706         }
1707 
applyMacroBlockLimits( int maxHorizontalBlocks, int maxVerticalBlocks, int maxBlocks, long maxBlocksPerSecond, int blockWidth, int blockHeight, int widthAlignment, int heightAlignment)1708         private void applyMacroBlockLimits(
1709                 int maxHorizontalBlocks, int maxVerticalBlocks,
1710                 int maxBlocks, long maxBlocksPerSecond,
1711                 int blockWidth, int blockHeight,
1712                 int widthAlignment, int heightAlignment) {
1713             applyAlignment(widthAlignment, heightAlignment);
1714             applyBlockLimits(
1715                     blockWidth, blockHeight, Range.create(1, maxBlocks),
1716                     Range.create(1L, maxBlocksPerSecond),
1717                     Range.create(
1718                             new Rational(1, maxVerticalBlocks),
1719                             new Rational(maxHorizontalBlocks, 1)));
1720             mHorizontalBlockRange =
1721                     mHorizontalBlockRange.intersect(
1722                             1, maxHorizontalBlocks / (mBlockWidth / blockWidth));
1723             mVerticalBlockRange =
1724                     mVerticalBlockRange.intersect(
1725                             1, maxVerticalBlocks / (mBlockHeight / blockHeight));
1726         }
1727 
applyLevelLimits()1728         private void applyLevelLimits() {
1729             int maxBlocksPerSecond = 0;
1730             int maxBlocks = 0;
1731             int maxBps = 0;
1732             int maxDPBBlocks = 0;
1733 
1734             int errors = ERROR_NONE_SUPPORTED;
1735             CodecProfileLevel[] profileLevels = mParent.profileLevels;
1736             String mime = mParent.getMimeType();
1737 
1738             if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC)) {
1739                 maxBlocks = 99;
1740                 maxBlocksPerSecond = 1485;
1741                 maxBps = 64000;
1742                 maxDPBBlocks = 396;
1743                 for (CodecProfileLevel profileLevel: profileLevels) {
1744                     int MBPS = 0, FS = 0, BR = 0, DPB = 0;
1745                     boolean supported = true;
1746                     switch (profileLevel.level) {
1747                         case CodecProfileLevel.AVCLevel1:
1748                             MBPS =    1485; FS =    99; BR =     64; DPB =    396; break;
1749                         case CodecProfileLevel.AVCLevel1b:
1750                             MBPS =    1485; FS =    99; BR =    128; DPB =    396; break;
1751                         case CodecProfileLevel.AVCLevel11:
1752                             MBPS =    3000; FS =   396; BR =    192; DPB =    900; break;
1753                         case CodecProfileLevel.AVCLevel12:
1754                             MBPS =    6000; FS =   396; BR =    384; DPB =   2376; break;
1755                         case CodecProfileLevel.AVCLevel13:
1756                             MBPS =   11880; FS =   396; BR =    768; DPB =   2376; break;
1757                         case CodecProfileLevel.AVCLevel2:
1758                             MBPS =   11880; FS =   396; BR =   2000; DPB =   2376; break;
1759                         case CodecProfileLevel.AVCLevel21:
1760                             MBPS =   19800; FS =   792; BR =   4000; DPB =   4752; break;
1761                         case CodecProfileLevel.AVCLevel22:
1762                             MBPS =   20250; FS =  1620; BR =   4000; DPB =   8100; break;
1763                         case CodecProfileLevel.AVCLevel3:
1764                             MBPS =   40500; FS =  1620; BR =  10000; DPB =   8100; break;
1765                         case CodecProfileLevel.AVCLevel31:
1766                             MBPS =  108000; FS =  3600; BR =  14000; DPB =  18000; break;
1767                         case CodecProfileLevel.AVCLevel32:
1768                             MBPS =  216000; FS =  5120; BR =  20000; DPB =  20480; break;
1769                         case CodecProfileLevel.AVCLevel4:
1770                             MBPS =  245760; FS =  8192; BR =  20000; DPB =  32768; break;
1771                         case CodecProfileLevel.AVCLevel41:
1772                             MBPS =  245760; FS =  8192; BR =  50000; DPB =  32768; break;
1773                         case CodecProfileLevel.AVCLevel42:
1774                             MBPS =  522240; FS =  8704; BR =  50000; DPB =  34816; break;
1775                         case CodecProfileLevel.AVCLevel5:
1776                             MBPS =  589824; FS = 22080; BR = 135000; DPB = 110400; break;
1777                         case CodecProfileLevel.AVCLevel51:
1778                             MBPS =  983040; FS = 36864; BR = 240000; DPB = 184320; break;
1779                         case CodecProfileLevel.AVCLevel52:
1780                             MBPS = 2073600; FS = 36864; BR = 240000; DPB = 184320; break;
1781                         default:
1782                             Log.w(TAG, "Unrecognized level "
1783                                     + profileLevel.level + " for " + mime);
1784                             errors |= ERROR_UNRECOGNIZED;
1785                     }
1786                     switch (profileLevel.profile) {
1787                         case CodecProfileLevel.AVCProfileHigh:
1788                             BR *= 1250; break;
1789                         case CodecProfileLevel.AVCProfileHigh10:
1790                             BR *= 3000; break;
1791                         case CodecProfileLevel.AVCProfileExtended:
1792                         case CodecProfileLevel.AVCProfileHigh422:
1793                         case CodecProfileLevel.AVCProfileHigh444:
1794                             Log.w(TAG, "Unsupported profile "
1795                                     + profileLevel.profile + " for " + mime);
1796                             errors |= ERROR_UNSUPPORTED;
1797                             supported = false;
1798                             // fall through - treat as base profile
1799                         case CodecProfileLevel.AVCProfileBaseline:
1800                         case CodecProfileLevel.AVCProfileMain:
1801                             BR *= 1000; break;
1802                         default:
1803                             Log.w(TAG, "Unrecognized profile "
1804                                     + profileLevel.profile + " for " + mime);
1805                             errors |= ERROR_UNRECOGNIZED;
1806                             BR *= 1000;
1807                     }
1808                     if (supported) {
1809                         errors &= ~ERROR_NONE_SUPPORTED;
1810                     }
1811                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
1812                     maxBlocks = Math.max(FS, maxBlocks);
1813                     maxBps = Math.max(BR, maxBps);
1814                     maxDPBBlocks = Math.max(maxDPBBlocks, DPB);
1815                 }
1816 
1817                 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8));
1818                 applyMacroBlockLimits(
1819                         maxLengthInBlocks, maxLengthInBlocks,
1820                         maxBlocks, maxBlocksPerSecond,
1821                         16 /* blockWidth */, 16 /* blockHeight */,
1822                         1 /* widthAlignment */, 1 /* heightAlignment */);
1823             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG2)) {
1824                 int maxWidth = 11, maxHeight = 9, maxRate = 15;
1825                 maxBlocks = 99;
1826                 maxBlocksPerSecond = 1485;
1827                 maxBps = 64000;
1828                 for (CodecProfileLevel profileLevel: profileLevels) {
1829                     int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0;
1830                     boolean supported = true;
1831                     switch (profileLevel.profile) {
1832                         case CodecProfileLevel.MPEG2ProfileSimple:
1833                             switch (profileLevel.level) {
1834                                 case CodecProfileLevel.MPEG2LevelML:
1835                                     FR = 30; W = 45; H =  36; MBPS =  48600; FS =  1620; BR =  15000; break;
1836                                 default:
1837                                     Log.w(TAG, "Unrecognized profile/level "
1838                                             + profileLevel.profile + "/"
1839                                             + profileLevel.level + " for " + mime);
1840                                     errors |= ERROR_UNRECOGNIZED;
1841                             }
1842                             break;
1843                         case CodecProfileLevel.MPEG2ProfileMain:
1844                             switch (profileLevel.level) {
1845                                 case CodecProfileLevel.MPEG2LevelLL:
1846                                     FR = 30; W = 22; H =  18; MBPS =  11880; FS =  396; BR =  4000; break;
1847                                 case CodecProfileLevel.MPEG2LevelML:
1848                                     FR = 30; W = 45; H =  36; MBPS =  48600; FS =  1620; BR =  15000; break;
1849                                 case CodecProfileLevel.MPEG2LevelH14:
1850                                     FR = 60; W = 90; H =  68; MBPS =  367200; FS =  6120; BR = 60000; break;
1851                                 case CodecProfileLevel.MPEG2LevelHL:
1852                                     FR = 60; W = 120; H = 68; MBPS =  489600; FS =  8160; BR = 80000; break;
1853                                 default:
1854                                     Log.w(TAG, "Unrecognized profile/level "
1855                                             + profileLevel.profile + "/"
1856                                             + profileLevel.level + " for " + mime);
1857                                     errors |= ERROR_UNRECOGNIZED;
1858                             }
1859                             break;
1860                         case CodecProfileLevel.MPEG2Profile422:
1861                         case CodecProfileLevel.MPEG2ProfileSNR:
1862                         case CodecProfileLevel.MPEG2ProfileSpatial:
1863                         case CodecProfileLevel.MPEG2ProfileHigh:
1864                             Log.i(TAG, "Unsupported profile "
1865                                     + profileLevel.profile + " for " + mime);
1866                             errors |= ERROR_UNSUPPORTED;
1867                             supported = false;
1868                             break;
1869                         default:
1870                             Log.w(TAG, "Unrecognized profile "
1871                                     + profileLevel.profile + " for " + mime);
1872                             errors |= ERROR_UNRECOGNIZED;
1873                     }
1874                     if (supported) {
1875                         errors &= ~ERROR_NONE_SUPPORTED;
1876                     }
1877                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
1878                     maxBlocks = Math.max(FS, maxBlocks);
1879                     maxBps = Math.max(BR * 1000, maxBps);
1880                     maxWidth = Math.max(W, maxWidth);
1881                     maxHeight = Math.max(H, maxHeight);
1882                     maxRate = Math.max(FR, maxRate);
1883                 }
1884                 applyMacroBlockLimits(maxWidth, maxHeight,
1885                         maxBlocks, maxBlocksPerSecond,
1886                         16 /* blockWidth */, 16 /* blockHeight */,
1887                         1 /* widthAlignment */, 1 /* heightAlignment */);
1888                 mFrameRateRange = mFrameRateRange.intersect(12, maxRate);
1889             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) {
1890                 int maxWidth = 11, maxHeight = 9, maxRate = 15;
1891                 maxBlocks = 99;
1892                 maxBlocksPerSecond = 1485;
1893                 maxBps = 64000;
1894                 for (CodecProfileLevel profileLevel: profileLevels) {
1895                     int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0;
1896                     boolean supported = true;
1897                     switch (profileLevel.profile) {
1898                         case CodecProfileLevel.MPEG4ProfileSimple:
1899                             switch (profileLevel.level) {
1900                                 case CodecProfileLevel.MPEG4Level0:
1901                                     FR = 15; W = 11; H =  9; MBPS =  1485; FS =  99; BR =  64; break;
1902                                 case CodecProfileLevel.MPEG4Level1:
1903                                     FR = 30; W = 11; H =  9; MBPS =  1485; FS =  99; BR =  64; break;
1904                                 case CodecProfileLevel.MPEG4Level0b:
1905                                     FR = 30; W = 11; H =  9; MBPS =  1485; FS =  99; BR = 128; break;
1906                                 case CodecProfileLevel.MPEG4Level2:
1907                                     FR = 30; W = 22; H = 18; MBPS =  5940; FS = 396; BR = 128; break;
1908                                 case CodecProfileLevel.MPEG4Level3:
1909                                     FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384; break;
1910                                 case CodecProfileLevel.MPEG4Level4:
1911                                 case CodecProfileLevel.MPEG4Level4a:
1912                                 case CodecProfileLevel.MPEG4Level5:
1913                                     // While MPEG4 SP does not have level 4 or 5, some vendors
1914                                     // report it. Use the same limits as level 3, but mark as
1915                                     // unsupported.
1916                                     FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384;
1917                                     supported = false;
1918                                     break;
1919                                 default:
1920                                     Log.w(TAG, "Unrecognized profile/level "
1921                                             + profileLevel.profile + "/"
1922                                             + profileLevel.level + " for " + mime);
1923                                     errors |= ERROR_UNRECOGNIZED;
1924                             }
1925                             break;
1926                         case CodecProfileLevel.MPEG4ProfileAdvancedSimple:
1927                             switch (profileLevel.level) {
1928                                 case CodecProfileLevel.MPEG4Level0:
1929                                 case CodecProfileLevel.MPEG4Level1:
1930                                     FR = 30; W = 11; H =  9; MBPS =  2970; FS =   99; BR =  128; break;
1931                                 case CodecProfileLevel.MPEG4Level2:
1932                                     FR = 30; W = 22; H = 18; MBPS =  5940; FS =  396; BR =  384; break;
1933                                 case CodecProfileLevel.MPEG4Level3:
1934                                     FR = 30; W = 22; H = 18; MBPS = 11880; FS =  396; BR =  768; break;
1935                                 // case CodecProfileLevel.MPEG4Level3b:
1936                                 // TODO: MPEG4 level 3b is not defined in OMX
1937                                 //  MBPS = 11880; FS =  396; BR = 1500; break;
1938                                 case CodecProfileLevel.MPEG4Level4:
1939                                 case CodecProfileLevel.MPEG4Level4a:
1940                                     // TODO: MPEG4 level 4a is not defined in spec
1941                                     FR = 30; W = 44; H = 36; MBPS = 23760; FS =  792; BR = 3000; break;
1942                                 case CodecProfileLevel.MPEG4Level5:
1943                                     FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 8000; break;
1944                                 default:
1945                                     Log.w(TAG, "Unrecognized profile/level "
1946                                             + profileLevel.profile + "/"
1947                                             + profileLevel.level + " for " + mime);
1948                                     errors |= ERROR_UNRECOGNIZED;
1949                             }
1950                             break;
1951                         case CodecProfileLevel.MPEG4ProfileMain:             // 2-4
1952                         case CodecProfileLevel.MPEG4ProfileNbit:             // 2
1953                         case CodecProfileLevel.MPEG4ProfileAdvancedRealTime: // 1-4
1954                         case CodecProfileLevel.MPEG4ProfileCoreScalable:     // 1-3
1955                         case CodecProfileLevel.MPEG4ProfileAdvancedCoding:   // 1-4
1956                         case CodecProfileLevel.MPEG4ProfileCore:             // 1-2
1957                         case CodecProfileLevel.MPEG4ProfileAdvancedCore:     // 1-4
1958                         case CodecProfileLevel.MPEG4ProfileSimpleScalable:   // 0-2
1959                         case CodecProfileLevel.MPEG4ProfileAdvancedScalable: // 1-3
1960                         case CodecProfileLevel.MPEG4ProfileHybrid:           // 1-2
1961                         case CodecProfileLevel.MPEG4ProfileBasicAnimated:    // 1-2
1962                         case CodecProfileLevel.MPEG4ProfileScalableTexture:  // 1
1963                         case CodecProfileLevel.MPEG4ProfileSimpleFace:       // 1-2
1964                         case CodecProfileLevel.MPEG4ProfileSimpleFBA:        // 1-2
1965                             Log.i(TAG, "Unsupported profile "
1966                                     + profileLevel.profile + " for " + mime);
1967                             errors |= ERROR_UNSUPPORTED;
1968                             supported = false;
1969                             break;
1970                         default:
1971                             Log.w(TAG, "Unrecognized profile "
1972                                     + profileLevel.profile + " for " + mime);
1973                             errors |= ERROR_UNRECOGNIZED;
1974                     }
1975                     if (supported) {
1976                         errors &= ~ERROR_NONE_SUPPORTED;
1977                     }
1978                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
1979                     maxBlocks = Math.max(FS, maxBlocks);
1980                     maxBps = Math.max(BR * 1000, maxBps);
1981                     maxWidth = Math.max(W, maxWidth);
1982                     maxHeight = Math.max(H, maxHeight);
1983                     maxRate = Math.max(FR, maxRate);
1984                 }
1985                 applyMacroBlockLimits(maxWidth, maxHeight,
1986                         maxBlocks, maxBlocksPerSecond,
1987                         16 /* blockWidth */, 16 /* blockHeight */,
1988                         1 /* widthAlignment */, 1 /* heightAlignment */);
1989                 mFrameRateRange = mFrameRateRange.intersect(12, maxRate);
1990             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) {
1991                 int maxWidth = 11, maxHeight = 9, maxRate = 15;
1992                 maxBlocks = 99;
1993                 maxBlocksPerSecond = 1485;
1994                 maxBps = 64000;
1995                 for (CodecProfileLevel profileLevel: profileLevels) {
1996                     int MBPS = 0, BR = 0, FR = 0, W = 0, H = 0;
1997                     switch (profileLevel.level) {
1998                         case CodecProfileLevel.H263Level10:
1999                             FR = 15; W = 11; H =  9; BR =   1; MBPS =  W * H * FR; break;
2000                         case CodecProfileLevel.H263Level20:
2001                             // only supports CIF, 0..QCIF
2002                             FR = 30; W = 22; H = 18; BR =   2; MBPS =  W * H * FR; break;
2003                         case CodecProfileLevel.H263Level30:
2004                             // only supports CIF, 0..QCIF
2005                             FR = 30; W = 22; H = 18; BR =   6; MBPS =  W * H * FR; break;
2006                         case CodecProfileLevel.H263Level40:
2007                             // only supports CIF, 0..QCIF
2008                             FR = 30; W = 22; H = 18; BR =  32; MBPS =  W * H * FR; break;
2009                         case CodecProfileLevel.H263Level45:
2010                             // only implies level 10 support
2011                             FR = 30; W = 11; H =  9; BR =   2; MBPS =  W * H * FR; break;
2012                         case CodecProfileLevel.H263Level50:
2013                             // only supports 50fps for H > 15
2014                             FR = 60; W = 22; H = 18; BR =  64; MBPS =  W * H * 50; break;
2015                         case CodecProfileLevel.H263Level60:
2016                             // only supports 50fps for H > 15
2017                             FR = 60; W = 45; H = 18; BR = 128; MBPS =  W * H * 50; break;
2018                         case CodecProfileLevel.H263Level70:
2019                             // only supports 50fps for H > 30
2020                             FR = 60; W = 45; H = 36; BR = 256; MBPS =  W * H * 50; break;
2021                         default:
2022                             Log.w(TAG, "Unrecognized profile/level " + profileLevel.profile
2023                                     + "/" + profileLevel.level + " for " + mime);
2024                             errors |= ERROR_UNRECOGNIZED;
2025                     }
2026                     switch (profileLevel.profile) {
2027                         case CodecProfileLevel.H263ProfileBackwardCompatible:
2028                         case CodecProfileLevel.H263ProfileBaseline:
2029                         case CodecProfileLevel.H263ProfileH320Coding:
2030                         case CodecProfileLevel.H263ProfileHighCompression:
2031                         case CodecProfileLevel.H263ProfileHighLatency:
2032                         case CodecProfileLevel.H263ProfileInterlace:
2033                         case CodecProfileLevel.H263ProfileInternet:
2034                         case CodecProfileLevel.H263ProfileISWV2:
2035                         case CodecProfileLevel.H263ProfileISWV3:
2036                             break;
2037                         default:
2038                             Log.w(TAG, "Unrecognized profile "
2039                                     + profileLevel.profile + " for " + mime);
2040                             errors |= ERROR_UNRECOGNIZED;
2041                     }
2042                     errors &= ~ERROR_NONE_SUPPORTED;
2043                     maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
2044                     maxBlocks = Math.max(W * H, maxBlocks);
2045                     maxBps = Math.max(BR * 64000, maxBps);
2046                     maxWidth = Math.max(W, maxWidth);
2047                     maxHeight = Math.max(H, maxHeight);
2048                     maxRate = Math.max(FR, maxRate);
2049                 }
2050                 applyMacroBlockLimits(maxWidth, maxHeight,
2051                         maxBlocks, maxBlocksPerSecond,
2052                         16 /* blockWidth */, 16 /* blockHeight */,
2053                         1 /* widthAlignment */, 1 /* heightAlignment */);
2054                 mFrameRateRange = Range.create(1, maxRate);
2055             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8) ||
2056                     mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) {
2057                 maxBlocks = maxBlocksPerSecond = Integer.MAX_VALUE;
2058 
2059                 // TODO: set to 100Mbps for now, need a number for VPX
2060                 maxBps = 100000000;
2061 
2062                 // profile levels are not indicative for VPx, but verify
2063                 // them nonetheless
2064                 for (CodecProfileLevel profileLevel: profileLevels) {
2065                     switch (profileLevel.level) {
2066                         case CodecProfileLevel.VP8Level_Version0:
2067                         case CodecProfileLevel.VP8Level_Version1:
2068                         case CodecProfileLevel.VP8Level_Version2:
2069                         case CodecProfileLevel.VP8Level_Version3:
2070                             break;
2071                         default:
2072                             Log.w(TAG, "Unrecognized level "
2073                                     + profileLevel.level + " for " + mime);
2074                             errors |= ERROR_UNRECOGNIZED;
2075                     }
2076                     switch (profileLevel.profile) {
2077                         case CodecProfileLevel.VP8ProfileMain:
2078                             break;
2079                         default:
2080                             Log.w(TAG, "Unrecognized profile "
2081                                     + profileLevel.profile + " for " + mime);
2082                             errors |= ERROR_UNRECOGNIZED;
2083                     }
2084                     errors &= ~ERROR_NONE_SUPPORTED;
2085                 }
2086 
2087                 final int blockSize =
2088                     mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8) ? 16 : 8;
2089                 applyMacroBlockLimits(Short.MAX_VALUE, Short.MAX_VALUE,
2090                         maxBlocks, maxBlocksPerSecond, blockSize, blockSize,
2091                         1 /* widthAlignment */, 1 /* heightAlignment */);
2092             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
2093                 maxBlocks = 36864;
2094                 maxBlocksPerSecond = maxBlocks * 15;
2095                 maxBps = 128000;
2096                 for (CodecProfileLevel profileLevel: profileLevels) {
2097                     double FR = 0;
2098                     int FS = 0;
2099                     int BR = 0;
2100                     switch (profileLevel.level) {
2101                         case CodecProfileLevel.HEVCMainTierLevel1:
2102                         case CodecProfileLevel.HEVCHighTierLevel1:
2103                             FR =    15; FS =    36864; BR =    128; break;
2104                         case CodecProfileLevel.HEVCMainTierLevel2:
2105                         case CodecProfileLevel.HEVCHighTierLevel2:
2106                             FR =    30; FS =   122880; BR =   1500; break;
2107                         case CodecProfileLevel.HEVCMainTierLevel21:
2108                         case CodecProfileLevel.HEVCHighTierLevel21:
2109                             FR =    30; FS =   245760; BR =   3000; break;
2110                         case CodecProfileLevel.HEVCMainTierLevel3:
2111                         case CodecProfileLevel.HEVCHighTierLevel3:
2112                             FR =    30; FS =   552960; BR =   6000; break;
2113                         case CodecProfileLevel.HEVCMainTierLevel31:
2114                         case CodecProfileLevel.HEVCHighTierLevel31:
2115                             FR = 33.75; FS =   983040; BR =  10000; break;
2116                         case CodecProfileLevel.HEVCMainTierLevel4:
2117                             FR =    30; FS =  2228224; BR =  12000; break;
2118                         case CodecProfileLevel.HEVCHighTierLevel4:
2119                             FR =    30; FS =  2228224; BR =  30000; break;
2120                         case CodecProfileLevel.HEVCMainTierLevel41:
2121                             FR =    60; FS =  2228224; BR =  20000; break;
2122                         case CodecProfileLevel.HEVCHighTierLevel41:
2123                             FR =    60; FS =  2228224; BR =  50000; break;
2124                         case CodecProfileLevel.HEVCMainTierLevel5:
2125                             FR =    30; FS =  8912896; BR =  25000; break;
2126                         case CodecProfileLevel.HEVCHighTierLevel5:
2127                             FR =    30; FS =  8912896; BR = 100000; break;
2128                         case CodecProfileLevel.HEVCMainTierLevel51:
2129                             FR =    60; FS =  8912896; BR =  40000; break;
2130                         case CodecProfileLevel.HEVCHighTierLevel51:
2131                             FR =    60; FS =  8912896; BR = 160000; break;
2132                         case CodecProfileLevel.HEVCMainTierLevel52:
2133                             FR =   120; FS =  8912896; BR =  60000; break;
2134                         case CodecProfileLevel.HEVCHighTierLevel52:
2135                             FR =   120; FS =  8912896; BR = 240000; break;
2136                         case CodecProfileLevel.HEVCMainTierLevel6:
2137                             FR =    30; FS = 35651584; BR =  60000; break;
2138                         case CodecProfileLevel.HEVCHighTierLevel6:
2139                             FR =    30; FS = 35651584; BR = 240000; break;
2140                         case CodecProfileLevel.HEVCMainTierLevel61:
2141                             FR =    60; FS = 35651584; BR = 120000; break;
2142                         case CodecProfileLevel.HEVCHighTierLevel61:
2143                             FR =    60; FS = 35651584; BR = 480000; break;
2144                         case CodecProfileLevel.HEVCMainTierLevel62:
2145                             FR =   120; FS = 35651584; BR = 240000; break;
2146                         case CodecProfileLevel.HEVCHighTierLevel62:
2147                             FR =   120; FS = 35651584; BR = 800000; break;
2148                         default:
2149                             Log.w(TAG, "Unrecognized level "
2150                                     + profileLevel.level + " for " + mime);
2151                             errors |= ERROR_UNRECOGNIZED;
2152                     }
2153                     switch (profileLevel.profile) {
2154                         case CodecProfileLevel.HEVCProfileMain:
2155                         case CodecProfileLevel.HEVCProfileMain10:
2156                             break;
2157                         default:
2158                             Log.w(TAG, "Unrecognized profile "
2159                                     + profileLevel.profile + " for " + mime);
2160                             errors |= ERROR_UNRECOGNIZED;
2161                     }
2162 
2163                     /* DPB logic:
2164                     if      (width * height <= FS / 4)    DPB = 16;
2165                     else if (width * height <= FS / 2)    DPB = 12;
2166                     else if (width * height <= FS * 0.75) DPB = 8;
2167                     else                                  DPB = 6;
2168                     */
2169 
2170                     errors &= ~ERROR_NONE_SUPPORTED;
2171                     maxBlocksPerSecond = Math.max((int)(FR * FS), maxBlocksPerSecond);
2172                     maxBlocks = Math.max(FS, maxBlocks);
2173                     maxBps = Math.max(BR * 1000, maxBps);
2174                 }
2175 
2176                 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8));
2177                 // CTBs are at least 8x8
2178                 maxBlocks = Utils.divUp(maxBlocks, 8 * 8);
2179                 maxBlocksPerSecond = Utils.divUp(maxBlocksPerSecond, 8 * 8);
2180                 maxLengthInBlocks = Utils.divUp(maxLengthInBlocks, 8);
2181 
2182                 applyMacroBlockLimits(
2183                         maxLengthInBlocks, maxLengthInBlocks,
2184                         maxBlocks, maxBlocksPerSecond,
2185                         8 /* blockWidth */, 8 /* blockHeight */,
2186                         1 /* widthAlignment */, 1 /* heightAlignment */);
2187             } else {
2188                 Log.w(TAG, "Unsupported mime " + mime);
2189                 // using minimal bitrate here.  should be overriden by
2190                 // info from media_codecs.xml
2191                 maxBps = 64000;
2192                 errors |= ERROR_UNSUPPORTED;
2193             }
2194             mBitrateRange = Range.create(1, maxBps);
2195             mParent.mError |= errors;
2196         }
2197     }
2198 
2199     /**
2200      * A class that supports querying the encoding capabilities of a codec.
2201      */
2202     public static final class EncoderCapabilities {
2203         /**
2204          * Returns the supported range of quality values.
2205          *
2206          * @hide
2207          */
getQualityRange()2208         public Range<Integer> getQualityRange() {
2209             return mQualityRange;
2210         }
2211 
2212         /**
2213          * Returns the supported range of encoder complexity values.
2214          * <p>
2215          * Some codecs may support multiple complexity levels, where higher
2216          * complexity values use more encoder tools (e.g. perform more
2217          * intensive calculations) to improve the quality or the compression
2218          * ratio.  Use a lower value to save power and/or time.
2219          */
getComplexityRange()2220         public Range<Integer> getComplexityRange() {
2221             return mComplexityRange;
2222         }
2223 
2224         /** Constant quality mode */
2225         public static final int BITRATE_MODE_CQ = 0;
2226         /** Variable bitrate mode */
2227         public static final int BITRATE_MODE_VBR = 1;
2228         /** Constant bitrate mode */
2229         public static final int BITRATE_MODE_CBR = 2;
2230 
2231         private static final Feature[] bitrates = new Feature[] {
2232             new Feature("VBR", BITRATE_MODE_VBR, true),
2233             new Feature("CBR", BITRATE_MODE_CBR, false),
2234             new Feature("CQ",  BITRATE_MODE_CQ,  false)
2235         };
2236 
parseBitrateMode(String mode)2237         private static int parseBitrateMode(String mode) {
2238             for (Feature feat: bitrates) {
2239                 if (feat.mName.equalsIgnoreCase(mode)) {
2240                     return feat.mValue;
2241                 }
2242             }
2243             return 0;
2244         }
2245 
2246         /**
2247          * Query whether a bitrate mode is supported.
2248          */
isBitrateModeSupported(int mode)2249         public boolean isBitrateModeSupported(int mode) {
2250             for (Feature feat: bitrates) {
2251                 if (mode == feat.mValue) {
2252                     return (mBitControl & (1 << mode)) != 0;
2253                 }
2254             }
2255             return false;
2256         }
2257 
2258         private Range<Integer> mQualityRange;
2259         private Range<Integer> mComplexityRange;
2260         private CodecCapabilities mParent;
2261 
2262         /* no public constructor */
EncoderCapabilities()2263         private EncoderCapabilities() { }
2264 
2265         /** @hide */
create( MediaFormat info, CodecCapabilities parent)2266         public static EncoderCapabilities create(
2267                 MediaFormat info, CodecCapabilities parent) {
2268             EncoderCapabilities caps = new EncoderCapabilities();
2269             caps.init(info, parent);
2270             return caps;
2271         }
2272 
2273         /** @hide */
init(MediaFormat info, CodecCapabilities parent)2274         public void init(MediaFormat info, CodecCapabilities parent) {
2275             // no support for complexity or quality yet
2276             mParent = parent;
2277             mComplexityRange = Range.create(0, 0);
2278             mQualityRange = Range.create(0, 0);
2279             mBitControl = (1 << BITRATE_MODE_VBR);
2280 
2281             applyLevelLimits();
2282             parseFromInfo(info);
2283         }
2284 
applyLevelLimits()2285         private void applyLevelLimits() {
2286             String mime = mParent.getMimeType();
2287             if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
2288                 mComplexityRange = Range.create(0, 8);
2289                 mBitControl = (1 << BITRATE_MODE_CQ);
2290             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)
2291                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)
2292                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW)
2293                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)
2294                     || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) {
2295                 mBitControl = (1 << BITRATE_MODE_CBR);
2296             }
2297         }
2298 
2299         private int mBitControl;
2300         private Integer mDefaultComplexity;
2301         private Integer mDefaultQuality;
2302         private String mQualityScale;
2303 
parseFromInfo(MediaFormat info)2304         private void parseFromInfo(MediaFormat info) {
2305             Map<String, Object> map = info.getMap();
2306 
2307             if (info.containsKey("complexity-range")) {
2308                 mComplexityRange = Utils
2309                         .parseIntRange(info.getString("complexity-range"), mComplexityRange);
2310                 // TODO should we limit this to level limits?
2311             }
2312             if (info.containsKey("quality-range")) {
2313                 mQualityRange = Utils
2314                         .parseIntRange(info.getString("quality-range"), mQualityRange);
2315             }
2316             if (info.containsKey("feature-bitrate-control")) {
2317                 for (String mode: info.getString("feature-bitrate-control").split(",")) {
2318                     mBitControl |= parseBitrateMode(mode);
2319                 }
2320             }
2321 
2322             try {
2323                 mDefaultComplexity = Integer.parseInt((String)map.get("complexity-default"));
2324             } catch (NumberFormatException e) { }
2325 
2326             try {
2327                 mDefaultQuality = Integer.parseInt((String)map.get("quality-default"));
2328             } catch (NumberFormatException e) { }
2329 
2330             mQualityScale = (String)map.get("quality-scale");
2331         }
2332 
supports( Integer complexity, Integer quality, Integer profile)2333         private boolean supports(
2334                 Integer complexity, Integer quality, Integer profile) {
2335             boolean ok = true;
2336             if (ok && complexity != null) {
2337                 ok = mComplexityRange.contains(complexity);
2338             }
2339             if (ok && quality != null) {
2340                 ok = mQualityRange.contains(quality);
2341             }
2342             if (ok && profile != null) {
2343                 for (CodecProfileLevel pl: mParent.profileLevels) {
2344                     if (pl.profile == profile) {
2345                         profile = null;
2346                         break;
2347                     }
2348                 }
2349                 ok = profile == null;
2350             }
2351             return ok;
2352         }
2353 
2354         /** @hide */
setDefaultFormat(MediaFormat format)2355         public void setDefaultFormat(MediaFormat format) {
2356             // don't list trivial quality/complexity as default for now
2357             if (!mQualityRange.getUpper().equals(mQualityRange.getLower())
2358                     && mDefaultQuality != null) {
2359                 format.setInteger(MediaFormat.KEY_QUALITY, mDefaultQuality);
2360             }
2361             if (!mComplexityRange.getUpper().equals(mComplexityRange.getLower())
2362                     && mDefaultComplexity != null) {
2363                 format.setInteger(MediaFormat.KEY_COMPLEXITY, mDefaultComplexity);
2364             }
2365             // bitrates are listed in order of preference
2366             for (Feature feat: bitrates) {
2367                 if ((mBitControl & (1 << feat.mValue)) != 0) {
2368                     format.setInteger(MediaFormat.KEY_BITRATE_MODE, feat.mValue);
2369                     break;
2370                 }
2371             }
2372         }
2373 
2374         /** @hide */
supportsFormat(MediaFormat format)2375         public boolean supportsFormat(MediaFormat format) {
2376             final Map<String, Object> map = format.getMap();
2377             final String mime = mParent.getMimeType();
2378 
2379             Integer mode = (Integer)map.get(MediaFormat.KEY_BITRATE_MODE);
2380             if (mode != null && !isBitrateModeSupported(mode)) {
2381                 return false;
2382             }
2383 
2384             Integer complexity = (Integer)map.get(MediaFormat.KEY_COMPLEXITY);
2385             if (MediaFormat.MIMETYPE_AUDIO_FLAC.equalsIgnoreCase(mime)) {
2386                 Integer flacComplexity =
2387                     (Integer)map.get(MediaFormat.KEY_FLAC_COMPRESSION_LEVEL);
2388                 if (complexity == null) {
2389                     complexity = flacComplexity;
2390                 } else if (flacComplexity != null && !complexity.equals(flacComplexity)) {
2391                     throw new IllegalArgumentException(
2392                             "conflicting values for complexity and " +
2393                             "flac-compression-level");
2394                 }
2395             }
2396 
2397             // other audio parameters
2398             Integer profile = (Integer)map.get(MediaFormat.KEY_PROFILE);
2399             if (MediaFormat.MIMETYPE_AUDIO_AAC.equalsIgnoreCase(mime)) {
2400                 Integer aacProfile = (Integer)map.get(MediaFormat.KEY_AAC_PROFILE);
2401                 if (profile == null) {
2402                     profile = aacProfile;
2403                 } else if (aacProfile != null && !aacProfile.equals(profile)) {
2404                     throw new IllegalArgumentException(
2405                             "conflicting values for profile and aac-profile");
2406                 }
2407             }
2408 
2409             Integer quality = (Integer)map.get(MediaFormat.KEY_QUALITY);
2410 
2411             return supports(complexity, quality, profile);
2412         }
2413     };
2414 
2415     /**
2416      * Encapsulates the profiles available for a codec component.
2417      * <p>You can get a set of {@link MediaCodecInfo.CodecProfileLevel} objects for a given
2418      * {@link MediaCodecInfo} object from the
2419      * {@link MediaCodecInfo.CodecCapabilities#profileLevels} field.
2420      */
2421     public static final class CodecProfileLevel {
2422         // from OMX_VIDEO_AVCPROFILETYPE
2423         public static final int AVCProfileBaseline = 0x01;
2424         public static final int AVCProfileMain     = 0x02;
2425         public static final int AVCProfileExtended = 0x04;
2426         public static final int AVCProfileHigh     = 0x08;
2427         public static final int AVCProfileHigh10   = 0x10;
2428         public static final int AVCProfileHigh422  = 0x20;
2429         public static final int AVCProfileHigh444  = 0x40;
2430 
2431         // from OMX_VIDEO_AVCLEVELTYPE
2432         public static final int AVCLevel1       = 0x01;
2433         public static final int AVCLevel1b      = 0x02;
2434         public static final int AVCLevel11      = 0x04;
2435         public static final int AVCLevel12      = 0x08;
2436         public static final int AVCLevel13      = 0x10;
2437         public static final int AVCLevel2       = 0x20;
2438         public static final int AVCLevel21      = 0x40;
2439         public static final int AVCLevel22      = 0x80;
2440         public static final int AVCLevel3       = 0x100;
2441         public static final int AVCLevel31      = 0x200;
2442         public static final int AVCLevel32      = 0x400;
2443         public static final int AVCLevel4       = 0x800;
2444         public static final int AVCLevel41      = 0x1000;
2445         public static final int AVCLevel42      = 0x2000;
2446         public static final int AVCLevel5       = 0x4000;
2447         public static final int AVCLevel51      = 0x8000;
2448         public static final int AVCLevel52      = 0x10000;
2449 
2450         // from OMX_VIDEO_H263PROFILETYPE
2451         public static final int H263ProfileBaseline             = 0x01;
2452         public static final int H263ProfileH320Coding           = 0x02;
2453         public static final int H263ProfileBackwardCompatible   = 0x04;
2454         public static final int H263ProfileISWV2                = 0x08;
2455         public static final int H263ProfileISWV3                = 0x10;
2456         public static final int H263ProfileHighCompression      = 0x20;
2457         public static final int H263ProfileInternet             = 0x40;
2458         public static final int H263ProfileInterlace            = 0x80;
2459         public static final int H263ProfileHighLatency          = 0x100;
2460 
2461         // from OMX_VIDEO_H263LEVELTYPE
2462         public static final int H263Level10      = 0x01;
2463         public static final int H263Level20      = 0x02;
2464         public static final int H263Level30      = 0x04;
2465         public static final int H263Level40      = 0x08;
2466         public static final int H263Level45      = 0x10;
2467         public static final int H263Level50      = 0x20;
2468         public static final int H263Level60      = 0x40;
2469         public static final int H263Level70      = 0x80;
2470 
2471         // from OMX_VIDEO_MPEG4PROFILETYPE
2472         public static final int MPEG4ProfileSimple              = 0x01;
2473         public static final int MPEG4ProfileSimpleScalable      = 0x02;
2474         public static final int MPEG4ProfileCore                = 0x04;
2475         public static final int MPEG4ProfileMain                = 0x08;
2476         public static final int MPEG4ProfileNbit                = 0x10;
2477         public static final int MPEG4ProfileScalableTexture     = 0x20;
2478         public static final int MPEG4ProfileSimpleFace          = 0x40;
2479         public static final int MPEG4ProfileSimpleFBA           = 0x80;
2480         public static final int MPEG4ProfileBasicAnimated       = 0x100;
2481         public static final int MPEG4ProfileHybrid              = 0x200;
2482         public static final int MPEG4ProfileAdvancedRealTime    = 0x400;
2483         public static final int MPEG4ProfileCoreScalable        = 0x800;
2484         public static final int MPEG4ProfileAdvancedCoding      = 0x1000;
2485         public static final int MPEG4ProfileAdvancedCore        = 0x2000;
2486         public static final int MPEG4ProfileAdvancedScalable    = 0x4000;
2487         public static final int MPEG4ProfileAdvancedSimple      = 0x8000;
2488 
2489         // from OMX_VIDEO_MPEG4LEVELTYPE
2490         public static final int MPEG4Level0      = 0x01;
2491         public static final int MPEG4Level0b     = 0x02;
2492         public static final int MPEG4Level1      = 0x04;
2493         public static final int MPEG4Level2      = 0x08;
2494         public static final int MPEG4Level3      = 0x10;
2495         public static final int MPEG4Level4      = 0x20;
2496         public static final int MPEG4Level4a     = 0x40;
2497         public static final int MPEG4Level5      = 0x80;
2498 
2499         // from OMX_VIDEO_MPEG2PROFILETYPE
2500         public static final int MPEG2ProfileSimple              = 0x00;
2501         public static final int MPEG2ProfileMain                = 0x01;
2502         public static final int MPEG2Profile422                 = 0x02;
2503         public static final int MPEG2ProfileSNR                 = 0x03;
2504         public static final int MPEG2ProfileSpatial             = 0x04;
2505         public static final int MPEG2ProfileHigh                = 0x05;
2506 
2507         // from OMX_VIDEO_MPEG2LEVELTYPE
2508         public static final int MPEG2LevelLL     = 0x00;
2509         public static final int MPEG2LevelML     = 0x01;
2510         public static final int MPEG2LevelH14    = 0x02;
2511         public static final int MPEG2LevelHL     = 0x03;
2512 
2513         // from OMX_AUDIO_AACPROFILETYPE
2514         public static final int AACObjectMain       = 1;
2515         public static final int AACObjectLC         = 2;
2516         public static final int AACObjectSSR        = 3;
2517         public static final int AACObjectLTP        = 4;
2518         public static final int AACObjectHE         = 5;
2519         public static final int AACObjectScalable   = 6;
2520         public static final int AACObjectERLC       = 17;
2521         public static final int AACObjectLD         = 23;
2522         public static final int AACObjectHE_PS      = 29;
2523         public static final int AACObjectELD        = 39;
2524 
2525         // from OMX_VIDEO_VP8LEVELTYPE
2526         public static final int VP8Level_Version0 = 0x01;
2527         public static final int VP8Level_Version1 = 0x02;
2528         public static final int VP8Level_Version2 = 0x04;
2529         public static final int VP8Level_Version3 = 0x08;
2530 
2531         // from OMX_VIDEO_VP8PROFILETYPE
2532         public static final int VP8ProfileMain = 0x01;
2533 
2534         // from OMX_VIDEO_HEVCPROFILETYPE
2535         public static final int HEVCProfileMain   = 0x01;
2536         public static final int HEVCProfileMain10 = 0x02;
2537 
2538         // from OMX_VIDEO_HEVCLEVELTYPE
2539         public static final int HEVCMainTierLevel1  = 0x1;
2540         public static final int HEVCHighTierLevel1  = 0x2;
2541         public static final int HEVCMainTierLevel2  = 0x4;
2542         public static final int HEVCHighTierLevel2  = 0x8;
2543         public static final int HEVCMainTierLevel21 = 0x10;
2544         public static final int HEVCHighTierLevel21 = 0x20;
2545         public static final int HEVCMainTierLevel3  = 0x40;
2546         public static final int HEVCHighTierLevel3  = 0x80;
2547         public static final int HEVCMainTierLevel31 = 0x100;
2548         public static final int HEVCHighTierLevel31 = 0x200;
2549         public static final int HEVCMainTierLevel4  = 0x400;
2550         public static final int HEVCHighTierLevel4  = 0x800;
2551         public static final int HEVCMainTierLevel41 = 0x1000;
2552         public static final int HEVCHighTierLevel41 = 0x2000;
2553         public static final int HEVCMainTierLevel5  = 0x4000;
2554         public static final int HEVCHighTierLevel5  = 0x8000;
2555         public static final int HEVCMainTierLevel51 = 0x10000;
2556         public static final int HEVCHighTierLevel51 = 0x20000;
2557         public static final int HEVCMainTierLevel52 = 0x40000;
2558         public static final int HEVCHighTierLevel52 = 0x80000;
2559         public static final int HEVCMainTierLevel6  = 0x100000;
2560         public static final int HEVCHighTierLevel6  = 0x200000;
2561         public static final int HEVCMainTierLevel61 = 0x400000;
2562         public static final int HEVCHighTierLevel61 = 0x800000;
2563         public static final int HEVCMainTierLevel62 = 0x1000000;
2564         public static final int HEVCHighTierLevel62 = 0x2000000;
2565 
2566         /**
2567          * Defined in the OpenMAX IL specs, depending on the type of media
2568          * this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE,
2569          * OMX_VIDEO_MPEG4PROFILETYPE or OMX_VIDEO_VP8PROFILETYPE.
2570          */
2571         public int profile;
2572 
2573         /**
2574          * Defined in the OpenMAX IL specs, depending on the type of media
2575          * this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE
2576          * OMX_VIDEO_MPEG4LEVELTYPE or OMX_VIDEO_VP8LEVELTYPE.
2577          */
2578         public int level;
2579     };
2580 
2581     /**
2582      * Enumerates the capabilities of the codec component. Since a single
2583      * component can support data of a variety of types, the type has to be
2584      * specified to yield a meaningful result.
2585      * @param type The MIME type to query
2586      */
getCapabilitiesForType( String type)2587     public final CodecCapabilities getCapabilitiesForType(
2588             String type) {
2589         CodecCapabilities caps = mCaps.get(type);
2590         if (caps == null) {
2591             throw new IllegalArgumentException("codec does not support type");
2592         }
2593         // clone writable object
2594         return caps.dup();
2595     }
2596 
2597     /** @hide */
makeRegular()2598     public MediaCodecInfo makeRegular() {
2599         ArrayList<CodecCapabilities> caps = new ArrayList<CodecCapabilities>();
2600         for (CodecCapabilities c: mCaps.values()) {
2601             if (c.isRegular()) {
2602                 caps.add(c);
2603             }
2604         }
2605         if (caps.size() == 0) {
2606             return null;
2607         } else if (caps.size() == mCaps.size()) {
2608             return this;
2609         }
2610 
2611         return new MediaCodecInfo(
2612                 mName, mIsEncoder,
2613                 caps.toArray(new CodecCapabilities[caps.size()]));
2614     }
2615 }
2616