blob: c29300d146b2adcc535e73498f18395386af4691 [file] [log] [blame]
Justin Klaassen10d07c82017-09-15 17:58:39 -04001/*
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
17package android.media;
18
19import android.annotation.NonNull;
20import android.annotation.Nullable;
21import android.util.Log;
22import android.util.Pair;
23import android.util.Range;
24import android.util.Rational;
25import android.util.Size;
26
27import java.util.ArrayList;
28import java.util.Arrays;
29import java.util.HashMap;
30import java.util.Map;
31import java.util.Set;
32
33import static android.media.Utils.intersectSortedDistinctRanges;
34import 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 */
61public final class MediaCodecInfo {
62 private boolean mIsEncoder;
63 private String mName;
64 private Map<String, CodecCapabilities> mCaps;
65
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 */
79 public final String getName() {
80 return mName;
81 }
82
83 /**
84 * Query if the codec is an encoder.
85 */
86 public final boolean isEncoder() {
87 return mIsEncoder;
88 }
89
90 /**
91 * Query the media types supported by the codec.
92 */
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
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;
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 {
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 * <b>video decoder only</b>: codec supports queuing partial frames.
464 */
465 public static final String FEATURE_PartialFrame = "partial-frame";
466
467 /**
468 * <b>video encoder only</b>: codec supports intra refresh.
469 */
470 public static final String FEATURE_IntraRefresh = "intra-refresh";
471
472 /**
473 * Query codec feature capabilities.
474 * <p>
475 * These features are supported to be used by the codec. These
476 * include optional features that can be turned on, as well as
477 * features that are always on.
478 */
479 public final boolean isFeatureSupported(String name) {
480 return checkFeature(name, mFlagsSupported);
481 }
482
483 /**
484 * Query codec feature requirements.
485 * <p>
486 * These features are required to be used by the codec, and as such,
487 * they are always turned on.
488 */
489 public final boolean isFeatureRequired(String name) {
490 return checkFeature(name, mFlagsRequired);
491 }
492
493 private static final Feature[] decoderFeatures = {
494 new Feature(FEATURE_AdaptivePlayback, (1 << 0), true),
495 new Feature(FEATURE_SecurePlayback, (1 << 1), false),
496 new Feature(FEATURE_TunneledPlayback, (1 << 2), false),
497 new Feature(FEATURE_PartialFrame, (1 << 3), false),
498 };
499
500 private static final Feature[] encoderFeatures = {
501 new Feature(FEATURE_IntraRefresh, (1 << 0), false),
502 };
503
504 /** @hide */
505 public String[] validFeatures() {
506 Feature[] features = getValidFeatures();
507 String[] res = new String[features.length];
508 for (int i = 0; i < res.length; i++) {
509 res[i] = features[i].mName;
510 }
511 return res;
512 }
513
514 private Feature[] getValidFeatures() {
515 if (!isEncoder()) {
516 return decoderFeatures;
517 }
518 return encoderFeatures;
519 }
520
521 private boolean checkFeature(String name, int flags) {
522 for (Feature feat: getValidFeatures()) {
523 if (feat.mName.equals(name)) {
524 return (flags & feat.mValue) != 0;
525 }
526 }
527 return false;
528 }
529
530 /** @hide */
531 public boolean isRegular() {
532 // regular codecs only require default features
533 for (Feature feat: getValidFeatures()) {
534 if (!feat.mDefault && isFeatureRequired(feat.mName)) {
535 return false;
536 }
537 }
538 return true;
539 }
540
541 /**
542 * Query whether codec supports a given {@link MediaFormat}.
543 *
544 * <p class=note>
545 * <strong>Note:</strong> On {@link android.os.Build.VERSION_CODES#LOLLIPOP},
546 * {@code format} must not contain a {@linkplain MediaFormat#KEY_FRAME_RATE
547 * frame rate}. Use
548 * <code class=prettyprint>format.setString(MediaFormat.KEY_FRAME_RATE, null)</code>
549 * to clear any existing frame rate setting in the format.
550 * <p>
551 *
552 * The following table summarizes the format keys considered by this method.
553 *
554 * <table style="width: 0%">
555 * <thead>
556 * <tr>
557 * <th rowspan=3>OS Version(s)</th>
558 * <td colspan=3>{@code MediaFormat} keys considered for</th>
559 * </tr><tr>
560 * <th>Audio Codecs</th>
561 * <th>Video Codecs</th>
562 * <th>Encoders</th>
563 * </tr>
564 * </thead>
565 * <tbody>
566 * <tr>
567 * <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP}</th>
568 * <td rowspan=3>{@link MediaFormat#KEY_MIME}<sup>*</sup>,<br>
569 * {@link MediaFormat#KEY_SAMPLE_RATE},<br>
570 * {@link MediaFormat#KEY_CHANNEL_COUNT},</td>
571 * <td>{@link MediaFormat#KEY_MIME}<sup>*</sup>,<br>
572 * {@link CodecCapabilities#FEATURE_AdaptivePlayback}<sup>D</sup>,<br>
573 * {@link CodecCapabilities#FEATURE_SecurePlayback}<sup>D</sup>,<br>
574 * {@link CodecCapabilities#FEATURE_TunneledPlayback}<sup>D</sup>,<br>
575 * {@link MediaFormat#KEY_WIDTH},<br>
576 * {@link MediaFormat#KEY_HEIGHT},<br>
577 * <strong>no</strong> {@code KEY_FRAME_RATE}</td>
578 * <td rowspan=4>{@link MediaFormat#KEY_BITRATE_MODE},<br>
579 * {@link MediaFormat#KEY_PROFILE}
580 * (and/or {@link MediaFormat#KEY_AAC_PROFILE}<sup>~</sup>),<br>
581 * <!-- {link MediaFormat#KEY_QUALITY},<br> -->
582 * {@link MediaFormat#KEY_COMPLEXITY}
583 * (and/or {@link MediaFormat#KEY_FLAC_COMPRESSION_LEVEL}<sup>~</sup>)</td>
584 * </tr><tr>
585 * <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}</th>
586 * <td rowspan=2>as above, plus<br>
587 * {@link MediaFormat#KEY_FRAME_RATE}</td>
588 * </tr><tr>
589 * <td>{@link android.os.Build.VERSION_CODES#M}</th>
590 * </tr><tr>
591 * <td>{@link android.os.Build.VERSION_CODES#N}</th>
592 * <td>as above, plus<br>
593 * {@link MediaFormat#KEY_PROFILE},<br>
594 * <!-- {link MediaFormat#KEY_MAX_BIT_RATE},<br> -->
595 * {@link MediaFormat#KEY_BIT_RATE}</td>
596 * <td>as above, plus<br>
597 * {@link MediaFormat#KEY_PROFILE},<br>
598 * {@link MediaFormat#KEY_LEVEL}<sup>+</sup>,<br>
599 * <!-- {link MediaFormat#KEY_MAX_BIT_RATE},<br> -->
600 * {@link MediaFormat#KEY_BIT_RATE},<br>
601 * {@link CodecCapabilities#FEATURE_IntraRefresh}<sup>E</sup></td>
602 * </tr>
603 * <tr>
604 * <td colspan=4>
605 * <p class=note><strong>Notes:</strong><br>
606 * *: must be specified; otherwise, method returns {@code false}.<br>
607 * +: method does not verify that the format parameters are supported
608 * by the specified level.<br>
609 * D: decoders only<br>
610 * E: encoders only<br>
611 * ~: if both keys are provided values must match
612 * </td>
613 * </tr>
614 * </tbody>
615 * </table>
616 *
617 * @param format media format with optional feature directives.
618 * @throws IllegalArgumentException if format is not a valid media format.
619 * @return whether the codec capabilities support the given format
620 * and feature requests.
621 */
622 public final boolean isFormatSupported(MediaFormat format) {
623 final Map<String, Object> map = format.getMap();
624 final String mime = (String)map.get(MediaFormat.KEY_MIME);
625
626 // mime must match if present
627 if (mime != null && !mMime.equalsIgnoreCase(mime)) {
628 return false;
629 }
630
631 // check feature support
632 for (Feature feat: getValidFeatures()) {
633 Integer yesNo = (Integer)map.get(MediaFormat.KEY_FEATURE_ + feat.mName);
634 if (yesNo == null) {
635 continue;
636 }
637 if ((yesNo == 1 && !isFeatureSupported(feat.mName)) ||
638 (yesNo == 0 && isFeatureRequired(feat.mName))) {
639 return false;
640 }
641 }
642
643 Integer profile = (Integer)map.get(MediaFormat.KEY_PROFILE);
644 Integer level = (Integer)map.get(MediaFormat.KEY_LEVEL);
645
646 if (profile != null) {
647 if (!supportsProfileLevel(profile, level)) {
648 return false;
649 }
650
651 // If we recognize this profile, check that this format is supported by the
652 // highest level supported by the codec for that profile. (Ignore specified
653 // level beyond the above profile/level check as level is only used as a
654 // guidance. E.g. AVC Level 1 CIF format is supported if codec supports level 1.1
655 // even though max size for Level 1 is QCIF. However, MPEG2 Simple Profile
656 // 1080p format is not supported even if codec supports Main Profile Level High,
657 // as Simple Profile does not support 1080p.
658 CodecCapabilities levelCaps = null;
659 int maxLevel = 0;
660 for (CodecProfileLevel pl : profileLevels) {
661 if (pl.profile == profile && pl.level > maxLevel) {
662 maxLevel = pl.level;
663 }
664 }
665 levelCaps = createFromProfileLevel(mMime, profile, maxLevel);
666 // remove profile from this format otherwise levelCaps.isFormatSupported will
667 // get into this same conditon and loop forever.
668 Map<String, Object> mapWithoutProfile = new HashMap<>(map);
669 mapWithoutProfile.remove(MediaFormat.KEY_PROFILE);
670 MediaFormat formatWithoutProfile = new MediaFormat(mapWithoutProfile);
671 if (levelCaps != null && !levelCaps.isFormatSupported(formatWithoutProfile)) {
672 return false;
673 }
674 }
675 if (mAudioCaps != null && !mAudioCaps.supportsFormat(format)) {
676 return false;
677 }
678 if (mVideoCaps != null && !mVideoCaps.supportsFormat(format)) {
679 return false;
680 }
681 if (mEncoderCaps != null && !mEncoderCaps.supportsFormat(format)) {
682 return false;
683 }
684 return true;
685 }
686
687 private static boolean supportsBitrate(
688 Range<Integer> bitrateRange, MediaFormat format) {
689 Map<String, Object> map = format.getMap();
690
691 // consider max bitrate over average bitrate for support
692 Integer maxBitrate = (Integer)map.get(MediaFormat.KEY_MAX_BIT_RATE);
693 Integer bitrate = (Integer)map.get(MediaFormat.KEY_BIT_RATE);
694 if (bitrate == null) {
695 bitrate = maxBitrate;
696 } else if (maxBitrate != null) {
697 bitrate = Math.max(bitrate, maxBitrate);
698 }
699
700 if (bitrate != null && bitrate > 0) {
701 return bitrateRange.contains(bitrate);
702 }
703
704 return true;
705 }
706
707 private boolean supportsProfileLevel(int profile, Integer level) {
708 for (CodecProfileLevel pl: profileLevels) {
709 if (pl.profile != profile) {
710 continue;
711 }
712
713 // AAC does not use levels
714 if (level == null || mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC)) {
715 return true;
716 }
717
718 // H.263 levels are not completely ordered:
719 // Level45 support only implies Level10 support
720 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) {
721 if (pl.level != level && pl.level == CodecProfileLevel.H263Level45
722 && level > CodecProfileLevel.H263Level10) {
723 continue;
724 }
725 }
726
727 // MPEG4 levels are not completely ordered:
728 // Level1 support only implies Level0 (and not Level0b) support
729 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) {
730 if (pl.level != level && pl.level == CodecProfileLevel.MPEG4Level1
731 && level > CodecProfileLevel.MPEG4Level0) {
732 continue;
733 }
734 }
735
736 // HEVC levels incorporate both tiers and levels. Verify tier support.
737 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
738 boolean supportsHighTier =
739 (pl.level & CodecProfileLevel.HEVCHighTierLevels) != 0;
740 boolean checkingHighTier = (level & CodecProfileLevel.HEVCHighTierLevels) != 0;
741 // high tier levels are only supported by other high tier levels
742 if (checkingHighTier && !supportsHighTier) {
743 continue;
744 }
745 }
746
747 if (pl.level >= level) {
748 // if we recognize the listed profile/level, we must also recognize the
749 // profile/level arguments.
750 if (createFromProfileLevel(mMime, profile, pl.level) != null) {
751 return createFromProfileLevel(mMime, profile, level) != null;
752 }
753 return true;
754 }
755 }
756 return false;
757 }
758
759 // errors while reading profile levels - accessed from sister capabilities
760 int mError;
761
762 private static final String TAG = "CodecCapabilities";
763
764 // NEW-STYLE CAPABILITIES
765 private AudioCapabilities mAudioCaps;
766 private VideoCapabilities mVideoCaps;
767 private EncoderCapabilities mEncoderCaps;
768 private MediaFormat mDefaultFormat;
769
770 /**
771 * Returns a MediaFormat object with default values for configurations that have
772 * defaults.
773 */
774 public MediaFormat getDefaultFormat() {
775 return mDefaultFormat;
776 }
777
778 /**
779 * Returns the mime type for which this codec-capability object was created.
780 */
781 public String getMimeType() {
782 return mMime;
783 }
784
785 /**
786 * Returns the max number of the supported concurrent codec instances.
787 * <p>
788 * This is a hint for an upper bound. Applications should not expect to successfully
789 * operate more instances than the returned value, but the actual number of
790 * concurrently operable instances may be less as it depends on the available
791 * resources at time of use.
792 */
793 public int getMaxSupportedInstances() {
794 return mMaxSupportedInstances;
795 }
796
797 private boolean isAudio() {
798 return mAudioCaps != null;
799 }
800
801 /**
802 * Returns the audio capabilities or {@code null} if this is not an audio codec.
803 */
804 public AudioCapabilities getAudioCapabilities() {
805 return mAudioCaps;
806 }
807
808 private boolean isEncoder() {
809 return mEncoderCaps != null;
810 }
811
812 /**
813 * Returns the encoding capabilities or {@code null} if this is not an encoder.
814 */
815 public EncoderCapabilities getEncoderCapabilities() {
816 return mEncoderCaps;
817 }
818
819 private boolean isVideo() {
820 return mVideoCaps != null;
821 }
822
823 /**
824 * Returns the video capabilities or {@code null} if this is not a video codec.
825 */
826 public VideoCapabilities getVideoCapabilities() {
827 return mVideoCaps;
828 }
829
830 /** @hide */
831 public CodecCapabilities dup() {
Justin Klaassen4d01eea2018-04-03 23:21:57 -0400832 CodecCapabilities caps = new CodecCapabilities();
833
834 // profileLevels and colorFormats may be modified by client.
835 caps.profileLevels = Arrays.copyOf(profileLevels, profileLevels.length);
836 caps.colorFormats = Arrays.copyOf(colorFormats, colorFormats.length);
837
838 caps.mMime = mMime;
839 caps.mMaxSupportedInstances = mMaxSupportedInstances;
840 caps.mFlagsRequired = mFlagsRequired;
841 caps.mFlagsSupported = mFlagsSupported;
842 caps.mFlagsVerified = mFlagsVerified;
843 caps.mAudioCaps = mAudioCaps;
844 caps.mVideoCaps = mVideoCaps;
845 caps.mEncoderCaps = mEncoderCaps;
846 caps.mDefaultFormat = mDefaultFormat;
847 caps.mCapabilitiesInfo = mCapabilitiesInfo;
848
849 return caps;
Justin Klaassen10d07c82017-09-15 17:58:39 -0400850 }
851
852 /**
853 * Retrieve the codec capabilities for a certain {@code mime type}, {@code
854 * profile} and {@code level}. If the type, or profile-level combination
855 * is not understood by the framework, it returns null.
856 * <p class=note> In {@link android.os.Build.VERSION_CODES#M}, calling this
857 * method without calling any method of the {@link MediaCodecList} class beforehand
858 * results in a {@link NullPointerException}.</p>
859 */
860 public static CodecCapabilities createFromProfileLevel(
861 String mime, int profile, int level) {
862 CodecProfileLevel pl = new CodecProfileLevel();
863 pl.profile = profile;
864 pl.level = level;
865 MediaFormat defaultFormat = new MediaFormat();
866 defaultFormat.setString(MediaFormat.KEY_MIME, mime);
867
868 CodecCapabilities ret = new CodecCapabilities(
869 new CodecProfileLevel[] { pl }, new int[0], true /* encoder */,
870 0 /* flags */, defaultFormat, new MediaFormat() /* info */);
871 if (ret.mError != 0) {
872 return null;
873 }
874 return ret;
875 }
876
877 /* package private */ CodecCapabilities(
878 CodecProfileLevel[] profLevs, int[] colFmts,
879 boolean encoder, int flags,
880 Map<String, Object>defaultFormatMap,
881 Map<String, Object>capabilitiesMap) {
882 this(profLevs, colFmts, encoder, flags,
883 new MediaFormat(defaultFormatMap),
884 new MediaFormat(capabilitiesMap));
885 }
886
887 private MediaFormat mCapabilitiesInfo;
888
889 /* package private */ CodecCapabilities(
890 CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags,
891 MediaFormat defaultFormat, MediaFormat info) {
892 final Map<String, Object> map = info.getMap();
893 colorFormats = colFmts;
894 mFlagsVerified = flags;
895 mDefaultFormat = defaultFormat;
896 mCapabilitiesInfo = info;
897 mMime = mDefaultFormat.getString(MediaFormat.KEY_MIME);
898
899 /* VP9 introduced profiles around 2016, so some VP9 codecs may not advertise any
900 supported profiles. Determine the level for them using the info they provide. */
901 if (profLevs.length == 0 && mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) {
902 CodecProfileLevel profLev = new CodecProfileLevel();
903 profLev.profile = CodecProfileLevel.VP9Profile0;
904 profLev.level = VideoCapabilities.equivalentVP9Level(info);
905 profLevs = new CodecProfileLevel[] { profLev };
906 }
907 profileLevels = profLevs;
908
909 if (mMime.toLowerCase().startsWith("audio/")) {
910 mAudioCaps = AudioCapabilities.create(info, this);
Justin Klaassen4d01eea2018-04-03 23:21:57 -0400911 mAudioCaps.getDefaultFormat(mDefaultFormat);
Justin Klaassen10d07c82017-09-15 17:58:39 -0400912 } else if (mMime.toLowerCase().startsWith("video/")) {
913 mVideoCaps = VideoCapabilities.create(info, this);
914 }
915 if (encoder) {
916 mEncoderCaps = EncoderCapabilities.create(info, this);
Justin Klaassen4d01eea2018-04-03 23:21:57 -0400917 mEncoderCaps.getDefaultFormat(mDefaultFormat);
Justin Klaassen10d07c82017-09-15 17:58:39 -0400918 }
919
920 final Map<String, Object> global = MediaCodecList.getGlobalSettings();
921 mMaxSupportedInstances = Utils.parseIntSafely(
922 global.get("max-concurrent-instances"), DEFAULT_MAX_SUPPORTED_INSTANCES);
923
924 int maxInstances = Utils.parseIntSafely(
925 map.get("max-concurrent-instances"), mMaxSupportedInstances);
926 mMaxSupportedInstances =
927 Range.create(1, MAX_SUPPORTED_INSTANCES_LIMIT).clamp(maxInstances);
928
929 for (Feature feat: getValidFeatures()) {
930 String key = MediaFormat.KEY_FEATURE_ + feat.mName;
931 Integer yesNo = (Integer)map.get(key);
932 if (yesNo == null) {
933 continue;
934 }
935 if (yesNo > 0) {
936 mFlagsRequired |= feat.mValue;
937 }
938 mFlagsSupported |= feat.mValue;
939 mDefaultFormat.setInteger(key, 1);
940 // TODO restrict features by mFlagsVerified once all codecs reliably verify them
941 }
942 }
943 }
944
945 /**
946 * A class that supports querying the audio capabilities of a codec.
947 */
948 public static final class AudioCapabilities {
949 private static final String TAG = "AudioCapabilities";
950 private CodecCapabilities mParent;
951 private Range<Integer> mBitrateRange;
952
953 private int[] mSampleRates;
954 private Range<Integer>[] mSampleRateRanges;
955 private int mMaxInputChannelCount;
956
957 private static final int MAX_INPUT_CHANNEL_COUNT = 30;
958
959 /**
960 * Returns the range of supported bitrates in bits/second.
961 */
962 public Range<Integer> getBitrateRange() {
963 return mBitrateRange;
964 }
965
966 /**
967 * Returns the array of supported sample rates if the codec
968 * supports only discrete values. Otherwise, it returns
969 * {@code null}. The array is sorted in ascending order.
970 */
971 public int[] getSupportedSampleRates() {
972 return Arrays.copyOf(mSampleRates, mSampleRates.length);
973 }
974
975 /**
976 * Returns the array of supported sample rate ranges. The
977 * array is sorted in ascending order, and the ranges are
978 * distinct.
979 */
980 public Range<Integer>[] getSupportedSampleRateRanges() {
981 return Arrays.copyOf(mSampleRateRanges, mSampleRateRanges.length);
982 }
983
984 /**
985 * Returns the maximum number of input channels supported. The codec
986 * supports any number of channels between 1 and this maximum value.
987 */
988 public int getMaxInputChannelCount() {
989 return mMaxInputChannelCount;
990 }
991
992 /* no public constructor */
993 private AudioCapabilities() { }
994
995 /** @hide */
996 public static AudioCapabilities create(
997 MediaFormat info, CodecCapabilities parent) {
998 AudioCapabilities caps = new AudioCapabilities();
999 caps.init(info, parent);
1000 return caps;
1001 }
1002
Justin Klaassen4d01eea2018-04-03 23:21:57 -04001003 private void init(MediaFormat info, CodecCapabilities parent) {
Justin Klaassen10d07c82017-09-15 17:58:39 -04001004 mParent = parent;
1005 initWithPlatformLimits();
1006 applyLevelLimits();
1007 parseFromInfo(info);
1008 }
1009
1010 private void initWithPlatformLimits() {
1011 mBitrateRange = Range.create(0, Integer.MAX_VALUE);
1012 mMaxInputChannelCount = MAX_INPUT_CHANNEL_COUNT;
1013 // mBitrateRange = Range.create(1, 320000);
1014 mSampleRateRanges = new Range[] { Range.create(8000, 96000) };
1015 mSampleRates = null;
1016 }
1017
1018 private boolean supports(Integer sampleRate, Integer inputChannels) {
1019 // channels and sample rates are checked orthogonally
1020 if (inputChannels != null &&
1021 (inputChannels < 1 || inputChannels > mMaxInputChannelCount)) {
1022 return false;
1023 }
1024 if (sampleRate != null) {
1025 int ix = Utils.binarySearchDistinctRanges(
1026 mSampleRateRanges, sampleRate);
1027 if (ix < 0) {
1028 return false;
1029 }
1030 }
1031 return true;
1032 }
1033
1034 /**
1035 * Query whether the sample rate is supported by the codec.
1036 */
1037 public boolean isSampleRateSupported(int sampleRate) {
1038 return supports(sampleRate, null);
1039 }
1040
1041 /** modifies rates */
1042 private void limitSampleRates(int[] rates) {
1043 Arrays.sort(rates);
1044 ArrayList<Range<Integer>> ranges = new ArrayList<Range<Integer>>();
1045 for (int rate: rates) {
1046 if (supports(rate, null /* channels */)) {
1047 ranges.add(Range.create(rate, rate));
1048 }
1049 }
1050 mSampleRateRanges = ranges.toArray(new Range[ranges.size()]);
1051 createDiscreteSampleRates();
1052 }
1053
1054 private void createDiscreteSampleRates() {
1055 mSampleRates = new int[mSampleRateRanges.length];
1056 for (int i = 0; i < mSampleRateRanges.length; i++) {
1057 mSampleRates[i] = mSampleRateRanges[i].getLower();
1058 }
1059 }
1060
1061 /** modifies rateRanges */
1062 private void limitSampleRates(Range<Integer>[] rateRanges) {
1063 sortDistinctRanges(rateRanges);
1064 mSampleRateRanges = intersectSortedDistinctRanges(mSampleRateRanges, rateRanges);
1065
1066 // check if all values are discrete
1067 for (Range<Integer> range: mSampleRateRanges) {
1068 if (!range.getLower().equals(range.getUpper())) {
1069 mSampleRates = null;
1070 return;
1071 }
1072 }
1073 createDiscreteSampleRates();
1074 }
1075
1076 private void applyLevelLimits() {
1077 int[] sampleRates = null;
1078 Range<Integer> sampleRateRange = null, bitRates = null;
1079 int maxChannels = MAX_INPUT_CHANNEL_COUNT;
1080 String mime = mParent.getMimeType();
1081
1082 if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MPEG)) {
1083 sampleRates = new int[] {
1084 8000, 11025, 12000,
1085 16000, 22050, 24000,
1086 32000, 44100, 48000 };
1087 bitRates = Range.create(8000, 320000);
1088 maxChannels = 2;
1089 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)) {
1090 sampleRates = new int[] { 8000 };
1091 bitRates = Range.create(4750, 12200);
1092 maxChannels = 1;
1093 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)) {
1094 sampleRates = new int[] { 16000 };
1095 bitRates = Range.create(6600, 23850);
1096 maxChannels = 1;
1097 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC)) {
1098 sampleRates = new int[] {
1099 7350, 8000,
1100 11025, 12000, 16000,
1101 22050, 24000, 32000,
1102 44100, 48000, 64000,
1103 88200, 96000 };
1104 bitRates = Range.create(8000, 510000);
1105 maxChannels = 48;
1106 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_VORBIS)) {
1107 bitRates = Range.create(32000, 500000);
1108 sampleRateRange = Range.create(8000, 192000);
1109 maxChannels = 255;
1110 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_OPUS)) {
1111 bitRates = Range.create(6000, 510000);
1112 sampleRates = new int[] { 8000, 12000, 16000, 24000, 48000 };
1113 maxChannels = 255;
1114 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW)) {
1115 sampleRateRange = Range.create(1, 96000);
1116 bitRates = Range.create(1, 10000000);
1117 maxChannels = AudioTrack.CHANNEL_COUNT_MAX;
1118 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
1119 sampleRateRange = Range.create(1, 655350);
1120 // lossless codec, so bitrate is ignored
1121 maxChannels = 255;
1122 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW)
1123 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)) {
1124 sampleRates = new int[] { 8000 };
1125 bitRates = Range.create(64000, 64000);
1126 // platform allows multiple channels for this format
1127 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) {
1128 sampleRates = new int[] { 8000 };
1129 bitRates = Range.create(13000, 13000);
1130 maxChannels = 1;
1131 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AC3)) {
1132 maxChannels = 6;
1133 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_EAC3)) {
1134 maxChannels = 16;
1135 } else {
1136 Log.w(TAG, "Unsupported mime " + mime);
1137 mParent.mError |= ERROR_UNSUPPORTED;
1138 }
1139
1140 // restrict ranges
1141 if (sampleRates != null) {
1142 limitSampleRates(sampleRates);
1143 } else if (sampleRateRange != null) {
1144 limitSampleRates(new Range[] { sampleRateRange });
1145 }
1146 applyLimits(maxChannels, bitRates);
1147 }
1148
1149 private void applyLimits(int maxInputChannels, Range<Integer> bitRates) {
1150 mMaxInputChannelCount = Range.create(1, mMaxInputChannelCount)
1151 .clamp(maxInputChannels);
1152 if (bitRates != null) {
1153 mBitrateRange = mBitrateRange.intersect(bitRates);
1154 }
1155 }
1156
1157 private void parseFromInfo(MediaFormat info) {
1158 int maxInputChannels = MAX_INPUT_CHANNEL_COUNT;
1159 Range<Integer> bitRates = POSITIVE_INTEGERS;
1160
1161 if (info.containsKey("sample-rate-ranges")) {
1162 String[] rateStrings = info.getString("sample-rate-ranges").split(",");
1163 Range<Integer>[] rateRanges = new Range[rateStrings.length];
1164 for (int i = 0; i < rateStrings.length; i++) {
1165 rateRanges[i] = Utils.parseIntRange(rateStrings[i], null);
1166 }
1167 limitSampleRates(rateRanges);
1168 }
1169 if (info.containsKey("max-channel-count")) {
1170 maxInputChannels = Utils.parseIntSafely(
1171 info.getString("max-channel-count"), maxInputChannels);
1172 } else if ((mParent.mError & ERROR_UNSUPPORTED) != 0) {
1173 maxInputChannels = 0;
1174 }
1175 if (info.containsKey("bitrate-range")) {
1176 bitRates = bitRates.intersect(
1177 Utils.parseIntRange(info.getString("bitrate-range"), bitRates));
1178 }
1179 applyLimits(maxInputChannels, bitRates);
1180 }
1181
1182 /** @hide */
Justin Klaassen4d01eea2018-04-03 23:21:57 -04001183 public void getDefaultFormat(MediaFormat format) {
Justin Klaassen10d07c82017-09-15 17:58:39 -04001184 // report settings that have only a single choice
1185 if (mBitrateRange.getLower().equals(mBitrateRange.getUpper())) {
1186 format.setInteger(MediaFormat.KEY_BIT_RATE, mBitrateRange.getLower());
1187 }
1188 if (mMaxInputChannelCount == 1) {
1189 // mono-only format
1190 format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
1191 }
1192 if (mSampleRates != null && mSampleRates.length == 1) {
1193 format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRates[0]);
1194 }
1195 }
1196
1197 /** @hide */
1198 public boolean supportsFormat(MediaFormat format) {
1199 Map<String, Object> map = format.getMap();
1200 Integer sampleRate = (Integer)map.get(MediaFormat.KEY_SAMPLE_RATE);
1201 Integer channels = (Integer)map.get(MediaFormat.KEY_CHANNEL_COUNT);
1202
1203 if (!supports(sampleRate, channels)) {
1204 return false;
1205 }
1206
1207 if (!CodecCapabilities.supportsBitrate(mBitrateRange, format)) {
1208 return false;
1209 }
1210
1211 // nothing to do for:
1212 // KEY_CHANNEL_MASK: codecs don't get this
1213 // KEY_IS_ADTS: required feature for all AAC decoders
1214 return true;
1215 }
1216 }
1217
1218 /**
1219 * A class that supports querying the video capabilities of a codec.
1220 */
1221 public static final class VideoCapabilities {
1222 private static final String TAG = "VideoCapabilities";
1223 private CodecCapabilities mParent;
1224 private Range<Integer> mBitrateRange;
1225
1226 private Range<Integer> mHeightRange;
1227 private Range<Integer> mWidthRange;
1228 private Range<Integer> mBlockCountRange;
1229 private Range<Integer> mHorizontalBlockRange;
1230 private Range<Integer> mVerticalBlockRange;
1231 private Range<Rational> mAspectRatioRange;
1232 private Range<Rational> mBlockAspectRatioRange;
1233 private Range<Long> mBlocksPerSecondRange;
1234 private Map<Size, Range<Long>> mMeasuredFrameRates;
1235 private Range<Integer> mFrameRateRange;
1236
1237 private int mBlockWidth;
1238 private int mBlockHeight;
1239 private int mWidthAlignment;
1240 private int mHeightAlignment;
1241 private int mSmallerDimensionUpperLimit;
1242
1243 private boolean mAllowMbOverride; // allow XML to override calculated limits
1244
1245 /**
1246 * Returns the range of supported bitrates in bits/second.
1247 */
1248 public Range<Integer> getBitrateRange() {
1249 return mBitrateRange;
1250 }
1251
1252 /**
1253 * Returns the range of supported video widths.
1254 */
1255 public Range<Integer> getSupportedWidths() {
1256 return mWidthRange;
1257 }
1258
1259 /**
1260 * Returns the range of supported video heights.
1261 */
1262 public Range<Integer> getSupportedHeights() {
1263 return mHeightRange;
1264 }
1265
1266 /**
1267 * Returns the alignment requirement for video width (in pixels).
1268 *
1269 * This is a power-of-2 value that video width must be a
1270 * multiple of.
1271 */
1272 public int getWidthAlignment() {
1273 return mWidthAlignment;
1274 }
1275
1276 /**
1277 * Returns the alignment requirement for video height (in pixels).
1278 *
1279 * This is a power-of-2 value that video height must be a
1280 * multiple of.
1281 */
1282 public int getHeightAlignment() {
1283 return mHeightAlignment;
1284 }
1285
1286 /**
1287 * Return the upper limit on the smaller dimension of width or height.
1288 * <p></p>
1289 * Some codecs have a limit on the smaller dimension, whether it be
1290 * the width or the height. E.g. a codec may only be able to handle
1291 * up to 1920x1080 both in landscape and portrait mode (1080x1920).
1292 * In this case the maximum width and height are both 1920, but the
1293 * smaller dimension limit will be 1080. For other codecs, this is
1294 * {@code Math.min(getSupportedWidths().getUpper(),
1295 * getSupportedHeights().getUpper())}.
1296 *
1297 * @hide
1298 */
1299 public int getSmallerDimensionUpperLimit() {
1300 return mSmallerDimensionUpperLimit;
1301 }
1302
1303 /**
1304 * Returns the range of supported frame rates.
1305 * <p>
1306 * This is not a performance indicator. Rather, it expresses the
1307 * limits specified in the coding standard, based on the complexities
1308 * of encoding material for later playback at a certain frame rate,
1309 * or the decoding of such material in non-realtime.
1310 */
1311 public Range<Integer> getSupportedFrameRates() {
1312 return mFrameRateRange;
1313 }
1314
1315 /**
1316 * Returns the range of supported video widths for a video height.
1317 * @param height the height of the video
1318 */
1319 public Range<Integer> getSupportedWidthsFor(int height) {
1320 try {
1321 Range<Integer> range = mWidthRange;
1322 if (!mHeightRange.contains(height)
1323 || (height % mHeightAlignment) != 0) {
1324 throw new IllegalArgumentException("unsupported height");
1325 }
1326 final int heightInBlocks = Utils.divUp(height, mBlockHeight);
1327
1328 // constrain by block count and by block aspect ratio
1329 final int minWidthInBlocks = Math.max(
1330 Utils.divUp(mBlockCountRange.getLower(), heightInBlocks),
1331 (int)Math.ceil(mBlockAspectRatioRange.getLower().doubleValue()
1332 * heightInBlocks));
1333 final int maxWidthInBlocks = Math.min(
1334 mBlockCountRange.getUpper() / heightInBlocks,
1335 (int)(mBlockAspectRatioRange.getUpper().doubleValue()
1336 * heightInBlocks));
1337 range = range.intersect(
1338 (minWidthInBlocks - 1) * mBlockWidth + mWidthAlignment,
1339 maxWidthInBlocks * mBlockWidth);
1340
1341 // constrain by smaller dimension limit
1342 if (height > mSmallerDimensionUpperLimit) {
1343 range = range.intersect(1, mSmallerDimensionUpperLimit);
1344 }
1345
1346 // constrain by aspect ratio
1347 range = range.intersect(
1348 (int)Math.ceil(mAspectRatioRange.getLower().doubleValue()
1349 * height),
1350 (int)(mAspectRatioRange.getUpper().doubleValue() * height));
1351 return range;
1352 } catch (IllegalArgumentException e) {
1353 // height is not supported because there are no suitable widths
1354 Log.v(TAG, "could not get supported widths for " + height);
1355 throw new IllegalArgumentException("unsupported height");
1356 }
1357 }
1358
1359 /**
1360 * Returns the range of supported video heights for a video width
1361 * @param width the width of the video
1362 */
1363 public Range<Integer> getSupportedHeightsFor(int width) {
1364 try {
1365 Range<Integer> range = mHeightRange;
1366 if (!mWidthRange.contains(width)
1367 || (width % mWidthAlignment) != 0) {
1368 throw new IllegalArgumentException("unsupported width");
1369 }
1370 final int widthInBlocks = Utils.divUp(width, mBlockWidth);
1371
1372 // constrain by block count and by block aspect ratio
1373 final int minHeightInBlocks = Math.max(
1374 Utils.divUp(mBlockCountRange.getLower(), widthInBlocks),
1375 (int)Math.ceil(widthInBlocks /
1376 mBlockAspectRatioRange.getUpper().doubleValue()));
1377 final int maxHeightInBlocks = Math.min(
1378 mBlockCountRange.getUpper() / widthInBlocks,
1379 (int)(widthInBlocks /
1380 mBlockAspectRatioRange.getLower().doubleValue()));
1381 range = range.intersect(
1382 (minHeightInBlocks - 1) * mBlockHeight + mHeightAlignment,
1383 maxHeightInBlocks * mBlockHeight);
1384
1385 // constrain by smaller dimension limit
1386 if (width > mSmallerDimensionUpperLimit) {
1387 range = range.intersect(1, mSmallerDimensionUpperLimit);
1388 }
1389
1390 // constrain by aspect ratio
1391 range = range.intersect(
1392 (int)Math.ceil(width /
1393 mAspectRatioRange.getUpper().doubleValue()),
1394 (int)(width / mAspectRatioRange.getLower().doubleValue()));
1395 return range;
1396 } catch (IllegalArgumentException e) {
1397 // width is not supported because there are no suitable heights
1398 Log.v(TAG, "could not get supported heights for " + width);
1399 throw new IllegalArgumentException("unsupported width");
1400 }
1401 }
1402
1403 /**
1404 * Returns the range of supported video frame rates for a video size.
1405 * <p>
1406 * This is not a performance indicator. Rather, it expresses the limits specified in
1407 * the coding standard, based on the complexities of encoding material of a given
1408 * size for later playback at a certain frame rate, or the decoding of such material
1409 * in non-realtime.
1410
1411 * @param width the width of the video
1412 * @param height the height of the video
1413 */
1414 public Range<Double> getSupportedFrameRatesFor(int width, int height) {
1415 Range<Integer> range = mHeightRange;
1416 if (!supports(width, height, null)) {
1417 throw new IllegalArgumentException("unsupported size");
1418 }
1419 final int blockCount =
1420 Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight);
1421
1422 return Range.create(
1423 Math.max(mBlocksPerSecondRange.getLower() / (double) blockCount,
1424 (double) mFrameRateRange.getLower()),
1425 Math.min(mBlocksPerSecondRange.getUpper() / (double) blockCount,
1426 (double) mFrameRateRange.getUpper()));
1427 }
1428
1429 private int getBlockCount(int width, int height) {
1430 return Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight);
1431 }
1432
1433 @NonNull
1434 private Size findClosestSize(int width, int height) {
1435 int targetBlockCount = getBlockCount(width, height);
1436 Size closestSize = null;
1437 int minDiff = Integer.MAX_VALUE;
1438 for (Size size : mMeasuredFrameRates.keySet()) {
1439 int diff = Math.abs(targetBlockCount -
1440 getBlockCount(size.getWidth(), size.getHeight()));
1441 if (diff < minDiff) {
1442 minDiff = diff;
1443 closestSize = size;
1444 }
1445 }
1446 return closestSize;
1447 }
1448
1449 private Range<Double> estimateFrameRatesFor(int width, int height) {
1450 Size size = findClosestSize(width, height);
1451 Range<Long> range = mMeasuredFrameRates.get(size);
1452 Double ratio = getBlockCount(size.getWidth(), size.getHeight())
1453 / (double)Math.max(getBlockCount(width, height), 1);
1454 return Range.create(range.getLower() * ratio, range.getUpper() * ratio);
1455 }
1456
1457 /**
1458 * Returns the range of achievable video frame rates for a video size.
1459 * May return {@code null}, if the codec did not publish any measurement
1460 * data.
1461 * <p>
1462 * This is a performance estimate provided by the device manufacturer based on statistical
1463 * sampling of full-speed decoding and encoding measurements in various configurations
1464 * of common video sizes supported by the codec. As such it should only be used to
1465 * compare individual codecs on the device. The value is not suitable for comparing
1466 * different devices or even different android releases for the same device.
1467 * <p>
1468 * <em>On {@link android.os.Build.VERSION_CODES#M} release</em> the returned range
1469 * corresponds to the fastest frame rates achieved in the tested configurations. As
1470 * such, it should not be used to gauge guaranteed or even average codec performance
1471 * on the device.
1472 * <p>
1473 * <em>On {@link android.os.Build.VERSION_CODES#N} release</em> the returned range
1474 * corresponds closer to sustained performance <em>in tested configurations</em>.
1475 * One can expect to achieve sustained performance higher than the lower limit more than
1476 * 50% of the time, and higher than half of the lower limit at least 90% of the time
1477 * <em>in tested configurations</em>.
1478 * Conversely, one can expect performance lower than twice the upper limit at least
1479 * 90% of the time.
1480 * <p class=note>
1481 * Tested configurations use a single active codec. For use cases where multiple
1482 * codecs are active, applications can expect lower and in most cases significantly lower
1483 * performance.
1484 * <p class=note>
1485 * The returned range value is interpolated from the nearest frame size(s) tested.
1486 * Codec performance is severely impacted by other activity on the device as well
1487 * as environmental factors (such as battery level, temperature or power source), and can
1488 * vary significantly even in a steady environment.
1489 * <p class=note>
1490 * Use this method in cases where only codec performance matters, e.g. to evaluate if
1491 * a codec has any chance of meeting a performance target. Codecs are listed
1492 * in {@link MediaCodecList} in the preferred order as defined by the device
1493 * manufacturer. As such, applications should use the first suitable codec in the
1494 * list to achieve the best balance between power use and performance.
1495 *
1496 * @param width the width of the video
1497 * @param height the height of the video
1498 *
1499 * @throws IllegalArgumentException if the video size is not supported.
1500 */
1501 @Nullable
1502 public Range<Double> getAchievableFrameRatesFor(int width, int height) {
1503 if (!supports(width, height, null)) {
1504 throw new IllegalArgumentException("unsupported size");
1505 }
1506
1507 if (mMeasuredFrameRates == null || mMeasuredFrameRates.size() <= 0) {
1508 Log.w(TAG, "Codec did not publish any measurement data.");
1509 return null;
1510 }
1511
1512 return estimateFrameRatesFor(width, height);
1513 }
1514
1515 /**
1516 * Returns whether a given video size ({@code width} and
1517 * {@code height}) and {@code frameRate} combination is supported.
1518 */
1519 public boolean areSizeAndRateSupported(
1520 int width, int height, double frameRate) {
1521 return supports(width, height, frameRate);
1522 }
1523
1524 /**
1525 * Returns whether a given video size ({@code width} and
1526 * {@code height}) is supported.
1527 */
1528 public boolean isSizeSupported(int width, int height) {
1529 return supports(width, height, null);
1530 }
1531
1532 private boolean supports(Integer width, Integer height, Number rate) {
1533 boolean ok = true;
1534
1535 if (ok && width != null) {
1536 ok = mWidthRange.contains(width)
1537 && (width % mWidthAlignment == 0);
1538 }
1539 if (ok && height != null) {
1540 ok = mHeightRange.contains(height)
1541 && (height % mHeightAlignment == 0);
1542 }
1543 if (ok && rate != null) {
1544 ok = mFrameRateRange.contains(Utils.intRangeFor(rate.doubleValue()));
1545 }
1546 if (ok && height != null && width != null) {
1547 ok = Math.min(height, width) <= mSmallerDimensionUpperLimit;
1548
1549 final int widthInBlocks = Utils.divUp(width, mBlockWidth);
1550 final int heightInBlocks = Utils.divUp(height, mBlockHeight);
1551 final int blockCount = widthInBlocks * heightInBlocks;
1552 ok = ok && mBlockCountRange.contains(blockCount)
1553 && mBlockAspectRatioRange.contains(
1554 new Rational(widthInBlocks, heightInBlocks))
1555 && mAspectRatioRange.contains(new Rational(width, height));
1556 if (ok && rate != null) {
1557 double blocksPerSec = blockCount * rate.doubleValue();
1558 ok = mBlocksPerSecondRange.contains(
1559 Utils.longRangeFor(blocksPerSec));
1560 }
1561 }
1562 return ok;
1563 }
1564
1565 /**
1566 * @hide
1567 * @throws java.lang.ClassCastException */
1568 public boolean supportsFormat(MediaFormat format) {
1569 final Map<String, Object> map = format.getMap();
1570 Integer width = (Integer)map.get(MediaFormat.KEY_WIDTH);
1571 Integer height = (Integer)map.get(MediaFormat.KEY_HEIGHT);
1572 Number rate = (Number)map.get(MediaFormat.KEY_FRAME_RATE);
1573
1574 if (!supports(width, height, rate)) {
1575 return false;
1576 }
1577
1578 if (!CodecCapabilities.supportsBitrate(mBitrateRange, format)) {
1579 return false;
1580 }
1581
1582 // we ignore color-format for now as it is not reliably reported by codec
1583 return true;
1584 }
1585
1586 /* no public constructor */
1587 private VideoCapabilities() { }
1588
1589 /** @hide */
1590 public static VideoCapabilities create(
1591 MediaFormat info, CodecCapabilities parent) {
1592 VideoCapabilities caps = new VideoCapabilities();
1593 caps.init(info, parent);
1594 return caps;
1595 }
1596
Justin Klaassen4d01eea2018-04-03 23:21:57 -04001597 private void init(MediaFormat info, CodecCapabilities parent) {
Justin Klaassen10d07c82017-09-15 17:58:39 -04001598 mParent = parent;
1599 initWithPlatformLimits();
1600 applyLevelLimits();
1601 parseFromInfo(info);
1602 updateLimits();
1603 }
1604
1605 /** @hide */
1606 public Size getBlockSize() {
1607 return new Size(mBlockWidth, mBlockHeight);
1608 }
1609
1610 /** @hide */
1611 public Range<Integer> getBlockCountRange() {
1612 return mBlockCountRange;
1613 }
1614
1615 /** @hide */
1616 public Range<Long> getBlocksPerSecondRange() {
1617 return mBlocksPerSecondRange;
1618 }
1619
1620 /** @hide */
1621 public Range<Rational> getAspectRatioRange(boolean blocks) {
1622 return blocks ? mBlockAspectRatioRange : mAspectRatioRange;
1623 }
1624
1625 private void initWithPlatformLimits() {
1626 mBitrateRange = BITRATE_RANGE;
1627
1628 mWidthRange = SIZE_RANGE;
1629 mHeightRange = SIZE_RANGE;
1630 mFrameRateRange = FRAME_RATE_RANGE;
1631
1632 mHorizontalBlockRange = SIZE_RANGE;
1633 mVerticalBlockRange = SIZE_RANGE;
1634
1635 // full positive ranges are supported as these get calculated
1636 mBlockCountRange = POSITIVE_INTEGERS;
1637 mBlocksPerSecondRange = POSITIVE_LONGS;
1638
1639 mBlockAspectRatioRange = POSITIVE_RATIONALS;
1640 mAspectRatioRange = POSITIVE_RATIONALS;
1641
1642 // YUV 4:2:0 requires 2:2 alignment
1643 mWidthAlignment = 2;
1644 mHeightAlignment = 2;
1645 mBlockWidth = 2;
1646 mBlockHeight = 2;
1647 mSmallerDimensionUpperLimit = SIZE_RANGE.getUpper();
1648 }
1649
1650 private Map<Size, Range<Long>> getMeasuredFrameRates(Map<String, Object> map) {
1651 Map<Size, Range<Long>> ret = new HashMap<Size, Range<Long>>();
1652 final String prefix = "measured-frame-rate-";
1653 Set<String> keys = map.keySet();
1654 for (String key : keys) {
1655 // looking for: measured-frame-rate-WIDTHxHEIGHT-range
1656 if (!key.startsWith(prefix)) {
1657 continue;
1658 }
1659 String subKey = key.substring(prefix.length());
1660 String[] temp = key.split("-");
1661 if (temp.length != 5) {
1662 continue;
1663 }
1664 String sizeStr = temp[3];
1665 Size size = Utils.parseSize(sizeStr, null);
1666 if (size == null || size.getWidth() * size.getHeight() <= 0) {
1667 continue;
1668 }
1669 Range<Long> range = Utils.parseLongRange(map.get(key), null);
1670 if (range == null || range.getLower() < 0 || range.getUpper() < 0) {
1671 continue;
1672 }
1673 ret.put(size, range);
1674 }
1675 return ret;
1676 }
1677
1678 private static Pair<Range<Integer>, Range<Integer>> parseWidthHeightRanges(Object o) {
1679 Pair<Size, Size> range = Utils.parseSizeRange(o);
1680 if (range != null) {
1681 try {
1682 return Pair.create(
1683 Range.create(range.first.getWidth(), range.second.getWidth()),
1684 Range.create(range.first.getHeight(), range.second.getHeight()));
1685 } catch (IllegalArgumentException e) {
1686 Log.w(TAG, "could not parse size range '" + o + "'");
1687 }
1688 }
1689 return null;
1690 }
1691
1692 /** @hide */
1693 public static int equivalentVP9Level(MediaFormat info) {
1694 final Map<String, Object> map = info.getMap();
1695
1696 Size blockSize = Utils.parseSize(map.get("block-size"), new Size(8, 8));
1697 int BS = blockSize.getWidth() * blockSize.getHeight();
1698
1699 Range<Integer> counts = Utils.parseIntRange(map.get("block-count-range"), null);
1700 int FS = counts == null ? 0 : BS * counts.getUpper();
1701
1702 Range<Long> blockRates =
1703 Utils.parseLongRange(map.get("blocks-per-second-range"), null);
1704 long SR = blockRates == null ? 0 : BS * blockRates.getUpper();
1705
1706 Pair<Range<Integer>, Range<Integer>> dimensionRanges =
1707 parseWidthHeightRanges(map.get("size-range"));
1708 int D = dimensionRanges == null ? 0 : Math.max(
1709 dimensionRanges.first.getUpper(), dimensionRanges.second.getUpper());
1710
1711 Range<Integer> bitRates = Utils.parseIntRange(map.get("bitrate-range"), null);
1712 int BR = bitRates == null ? 0 : Utils.divUp(bitRates.getUpper(), 1000);
1713
1714 if (SR <= 829440 && FS <= 36864 && BR <= 200 && D <= 512)
1715 return CodecProfileLevel.VP9Level1;
1716 if (SR <= 2764800 && FS <= 73728 && BR <= 800 && D <= 768)
1717 return CodecProfileLevel.VP9Level11;
1718 if (SR <= 4608000 && FS <= 122880 && BR <= 1800 && D <= 960)
1719 return CodecProfileLevel.VP9Level2;
1720 if (SR <= 9216000 && FS <= 245760 && BR <= 3600 && D <= 1344)
1721 return CodecProfileLevel.VP9Level21;
1722 if (SR <= 20736000 && FS <= 552960 && BR <= 7200 && D <= 2048)
1723 return CodecProfileLevel.VP9Level3;
1724 if (SR <= 36864000 && FS <= 983040 && BR <= 12000 && D <= 2752)
1725 return CodecProfileLevel.VP9Level31;
1726 if (SR <= 83558400 && FS <= 2228224 && BR <= 18000 && D <= 4160)
1727 return CodecProfileLevel.VP9Level4;
1728 if (SR <= 160432128 && FS <= 2228224 && BR <= 30000 && D <= 4160)
1729 return CodecProfileLevel.VP9Level41;
1730 if (SR <= 311951360 && FS <= 8912896 && BR <= 60000 && D <= 8384)
1731 return CodecProfileLevel.VP9Level5;
1732 if (SR <= 588251136 && FS <= 8912896 && BR <= 120000 && D <= 8384)
1733 return CodecProfileLevel.VP9Level51;
1734 if (SR <= 1176502272 && FS <= 8912896 && BR <= 180000 && D <= 8384)
1735 return CodecProfileLevel.VP9Level52;
1736 if (SR <= 1176502272 && FS <= 35651584 && BR <= 180000 && D <= 16832)
1737 return CodecProfileLevel.VP9Level6;
1738 if (SR <= 2353004544L && FS <= 35651584 && BR <= 240000 && D <= 16832)
1739 return CodecProfileLevel.VP9Level61;
1740 if (SR <= 4706009088L && FS <= 35651584 && BR <= 480000 && D <= 16832)
1741 return CodecProfileLevel.VP9Level62;
1742 // returning largest level
1743 return CodecProfileLevel.VP9Level62;
1744 }
1745
1746 private void parseFromInfo(MediaFormat info) {
1747 final Map<String, Object> map = info.getMap();
1748 Size blockSize = new Size(mBlockWidth, mBlockHeight);
1749 Size alignment = new Size(mWidthAlignment, mHeightAlignment);
1750 Range<Integer> counts = null, widths = null, heights = null;
1751 Range<Integer> frameRates = null, bitRates = null;
1752 Range<Long> blockRates = null;
1753 Range<Rational> ratios = null, blockRatios = null;
1754
1755 blockSize = Utils.parseSize(map.get("block-size"), blockSize);
1756 alignment = Utils.parseSize(map.get("alignment"), alignment);
1757 counts = Utils.parseIntRange(map.get("block-count-range"), null);
1758 blockRates =
1759 Utils.parseLongRange(map.get("blocks-per-second-range"), null);
1760 mMeasuredFrameRates = getMeasuredFrameRates(map);
1761 Pair<Range<Integer>, Range<Integer>> sizeRanges =
1762 parseWidthHeightRanges(map.get("size-range"));
1763 if (sizeRanges != null) {
1764 widths = sizeRanges.first;
1765 heights = sizeRanges.second;
1766 }
1767 // for now this just means using the smaller max size as 2nd
1768 // upper limit.
1769 // for now we are keeping the profile specific "width/height
1770 // in macroblocks" limits.
1771 if (map.containsKey("feature-can-swap-width-height")) {
1772 if (widths != null) {
1773 mSmallerDimensionUpperLimit =
1774 Math.min(widths.getUpper(), heights.getUpper());
1775 widths = heights = widths.extend(heights);
1776 } else {
1777 Log.w(TAG, "feature can-swap-width-height is best used with size-range");
1778 mSmallerDimensionUpperLimit =
1779 Math.min(mWidthRange.getUpper(), mHeightRange.getUpper());
1780 mWidthRange = mHeightRange = mWidthRange.extend(mHeightRange);
1781 }
1782 }
1783
1784 ratios = Utils.parseRationalRange(
1785 map.get("block-aspect-ratio-range"), null);
1786 blockRatios = Utils.parseRationalRange(
1787 map.get("pixel-aspect-ratio-range"), null);
1788 frameRates = Utils.parseIntRange(map.get("frame-rate-range"), null);
1789 if (frameRates != null) {
1790 try {
1791 frameRates = frameRates.intersect(FRAME_RATE_RANGE);
1792 } catch (IllegalArgumentException e) {
1793 Log.w(TAG, "frame rate range (" + frameRates
1794 + ") is out of limits: " + FRAME_RATE_RANGE);
1795 frameRates = null;
1796 }
1797 }
1798 bitRates = Utils.parseIntRange(map.get("bitrate-range"), null);
1799 if (bitRates != null) {
1800 try {
1801 bitRates = bitRates.intersect(BITRATE_RANGE);
1802 } catch (IllegalArgumentException e) {
1803 Log.w(TAG, "bitrate range (" + bitRates
1804 + ") is out of limits: " + BITRATE_RANGE);
1805 bitRates = null;
1806 }
1807 }
1808
1809 checkPowerOfTwo(
1810 blockSize.getWidth(), "block-size width must be power of two");
1811 checkPowerOfTwo(
1812 blockSize.getHeight(), "block-size height must be power of two");
1813
1814 checkPowerOfTwo(
1815 alignment.getWidth(), "alignment width must be power of two");
1816 checkPowerOfTwo(
1817 alignment.getHeight(), "alignment height must be power of two");
1818
1819 // update block-size and alignment
1820 applyMacroBlockLimits(
1821 Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE,
1822 Long.MAX_VALUE, blockSize.getWidth(), blockSize.getHeight(),
1823 alignment.getWidth(), alignment.getHeight());
1824
1825 if ((mParent.mError & ERROR_UNSUPPORTED) != 0 || mAllowMbOverride) {
1826 // codec supports profiles that we don't know.
1827 // Use supplied values clipped to platform limits
1828 if (widths != null) {
1829 mWidthRange = SIZE_RANGE.intersect(widths);
1830 }
1831 if (heights != null) {
1832 mHeightRange = SIZE_RANGE.intersect(heights);
1833 }
1834 if (counts != null) {
1835 mBlockCountRange = POSITIVE_INTEGERS.intersect(
1836 Utils.factorRange(counts, mBlockWidth * mBlockHeight
1837 / blockSize.getWidth() / blockSize.getHeight()));
1838 }
1839 if (blockRates != null) {
1840 mBlocksPerSecondRange = POSITIVE_LONGS.intersect(
1841 Utils.factorRange(blockRates, mBlockWidth * mBlockHeight
1842 / blockSize.getWidth() / blockSize.getHeight()));
1843 }
1844 if (blockRatios != null) {
1845 mBlockAspectRatioRange = POSITIVE_RATIONALS.intersect(
1846 Utils.scaleRange(blockRatios,
1847 mBlockHeight / blockSize.getHeight(),
1848 mBlockWidth / blockSize.getWidth()));
1849 }
1850 if (ratios != null) {
1851 mAspectRatioRange = POSITIVE_RATIONALS.intersect(ratios);
1852 }
1853 if (frameRates != null) {
1854 mFrameRateRange = FRAME_RATE_RANGE.intersect(frameRates);
1855 }
1856 if (bitRates != null) {
1857 // only allow bitrate override if unsupported profiles were encountered
1858 if ((mParent.mError & ERROR_UNSUPPORTED) != 0) {
1859 mBitrateRange = BITRATE_RANGE.intersect(bitRates);
1860 } else {
1861 mBitrateRange = mBitrateRange.intersect(bitRates);
1862 }
1863 }
1864 } else {
1865 // no unsupported profile/levels, so restrict values to known limits
1866 if (widths != null) {
1867 mWidthRange = mWidthRange.intersect(widths);
1868 }
1869 if (heights != null) {
1870 mHeightRange = mHeightRange.intersect(heights);
1871 }
1872 if (counts != null) {
1873 mBlockCountRange = mBlockCountRange.intersect(
1874 Utils.factorRange(counts, mBlockWidth * mBlockHeight
1875 / blockSize.getWidth() / blockSize.getHeight()));
1876 }
1877 if (blockRates != null) {
1878 mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(
1879 Utils.factorRange(blockRates, mBlockWidth * mBlockHeight
1880 / blockSize.getWidth() / blockSize.getHeight()));
1881 }
1882 if (blockRatios != null) {
1883 mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(
1884 Utils.scaleRange(blockRatios,
1885 mBlockHeight / blockSize.getHeight(),
1886 mBlockWidth / blockSize.getWidth()));
1887 }
1888 if (ratios != null) {
1889 mAspectRatioRange = mAspectRatioRange.intersect(ratios);
1890 }
1891 if (frameRates != null) {
1892 mFrameRateRange = mFrameRateRange.intersect(frameRates);
1893 }
1894 if (bitRates != null) {
1895 mBitrateRange = mBitrateRange.intersect(bitRates);
1896 }
1897 }
1898 updateLimits();
1899 }
1900
1901 private void applyBlockLimits(
1902 int blockWidth, int blockHeight,
1903 Range<Integer> counts, Range<Long> rates, Range<Rational> ratios) {
1904 checkPowerOfTwo(blockWidth, "blockWidth must be a power of two");
1905 checkPowerOfTwo(blockHeight, "blockHeight must be a power of two");
1906
1907 final int newBlockWidth = Math.max(blockWidth, mBlockWidth);
1908 final int newBlockHeight = Math.max(blockHeight, mBlockHeight);
1909
1910 // factor will always be a power-of-2
1911 int factor =
1912 newBlockWidth * newBlockHeight / mBlockWidth / mBlockHeight;
1913 if (factor != 1) {
1914 mBlockCountRange = Utils.factorRange(mBlockCountRange, factor);
1915 mBlocksPerSecondRange = Utils.factorRange(
1916 mBlocksPerSecondRange, factor);
1917 mBlockAspectRatioRange = Utils.scaleRange(
1918 mBlockAspectRatioRange,
1919 newBlockHeight / mBlockHeight,
1920 newBlockWidth / mBlockWidth);
1921 mHorizontalBlockRange = Utils.factorRange(
1922 mHorizontalBlockRange, newBlockWidth / mBlockWidth);
1923 mVerticalBlockRange = Utils.factorRange(
1924 mVerticalBlockRange, newBlockHeight / mBlockHeight);
1925 }
1926 factor = newBlockWidth * newBlockHeight / blockWidth / blockHeight;
1927 if (factor != 1) {
1928 counts = Utils.factorRange(counts, factor);
1929 rates = Utils.factorRange(rates, factor);
1930 ratios = Utils.scaleRange(
1931 ratios, newBlockHeight / blockHeight,
1932 newBlockWidth / blockWidth);
1933 }
1934 mBlockCountRange = mBlockCountRange.intersect(counts);
1935 mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(rates);
1936 mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(ratios);
1937 mBlockWidth = newBlockWidth;
1938 mBlockHeight = newBlockHeight;
1939 }
1940
1941 private void applyAlignment(int widthAlignment, int heightAlignment) {
1942 checkPowerOfTwo(widthAlignment, "widthAlignment must be a power of two");
1943 checkPowerOfTwo(heightAlignment, "heightAlignment must be a power of two");
1944
1945 if (widthAlignment > mBlockWidth || heightAlignment > mBlockHeight) {
1946 // maintain assumption that 0 < alignment <= block-size
1947 applyBlockLimits(
1948 Math.max(widthAlignment, mBlockWidth),
1949 Math.max(heightAlignment, mBlockHeight),
1950 POSITIVE_INTEGERS, POSITIVE_LONGS, POSITIVE_RATIONALS);
1951 }
1952
1953 mWidthAlignment = Math.max(widthAlignment, mWidthAlignment);
1954 mHeightAlignment = Math.max(heightAlignment, mHeightAlignment);
1955
1956 mWidthRange = Utils.alignRange(mWidthRange, mWidthAlignment);
1957 mHeightRange = Utils.alignRange(mHeightRange, mHeightAlignment);
1958 }
1959
1960 private void updateLimits() {
1961 // pixels -> blocks <- counts
1962 mHorizontalBlockRange = mHorizontalBlockRange.intersect(
1963 Utils.factorRange(mWidthRange, mBlockWidth));
1964 mHorizontalBlockRange = mHorizontalBlockRange.intersect(
1965 Range.create(
1966 mBlockCountRange.getLower() / mVerticalBlockRange.getUpper(),
1967 mBlockCountRange.getUpper() / mVerticalBlockRange.getLower()));
1968 mVerticalBlockRange = mVerticalBlockRange.intersect(
1969 Utils.factorRange(mHeightRange, mBlockHeight));
1970 mVerticalBlockRange = mVerticalBlockRange.intersect(
1971 Range.create(
1972 mBlockCountRange.getLower() / mHorizontalBlockRange.getUpper(),
1973 mBlockCountRange.getUpper() / mHorizontalBlockRange.getLower()));
1974 mBlockCountRange = mBlockCountRange.intersect(
1975 Range.create(
1976 mHorizontalBlockRange.getLower()
1977 * mVerticalBlockRange.getLower(),
1978 mHorizontalBlockRange.getUpper()
1979 * mVerticalBlockRange.getUpper()));
1980 mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(
1981 new Rational(
1982 mHorizontalBlockRange.getLower(), mVerticalBlockRange.getUpper()),
1983 new Rational(
1984 mHorizontalBlockRange.getUpper(), mVerticalBlockRange.getLower()));
1985
1986 // blocks -> pixels
1987 mWidthRange = mWidthRange.intersect(
1988 (mHorizontalBlockRange.getLower() - 1) * mBlockWidth + mWidthAlignment,
1989 mHorizontalBlockRange.getUpper() * mBlockWidth);
1990 mHeightRange = mHeightRange.intersect(
1991 (mVerticalBlockRange.getLower() - 1) * mBlockHeight + mHeightAlignment,
1992 mVerticalBlockRange.getUpper() * mBlockHeight);
1993 mAspectRatioRange = mAspectRatioRange.intersect(
1994 new Rational(mWidthRange.getLower(), mHeightRange.getUpper()),
1995 new Rational(mWidthRange.getUpper(), mHeightRange.getLower()));
1996
1997 mSmallerDimensionUpperLimit = Math.min(
1998 mSmallerDimensionUpperLimit,
1999 Math.min(mWidthRange.getUpper(), mHeightRange.getUpper()));
2000
2001 // blocks -> rate
2002 mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(
2003 mBlockCountRange.getLower() * (long)mFrameRateRange.getLower(),
2004 mBlockCountRange.getUpper() * (long)mFrameRateRange.getUpper());
2005 mFrameRateRange = mFrameRateRange.intersect(
2006 (int)(mBlocksPerSecondRange.getLower()
2007 / mBlockCountRange.getUpper()),
2008 (int)(mBlocksPerSecondRange.getUpper()
2009 / (double)mBlockCountRange.getLower()));
2010 }
2011
2012 private void applyMacroBlockLimits(
2013 int maxHorizontalBlocks, int maxVerticalBlocks,
2014 int maxBlocks, long maxBlocksPerSecond,
2015 int blockWidth, int blockHeight,
2016 int widthAlignment, int heightAlignment) {
2017 applyMacroBlockLimits(
2018 1 /* minHorizontalBlocks */, 1 /* minVerticalBlocks */,
2019 maxHorizontalBlocks, maxVerticalBlocks,
2020 maxBlocks, maxBlocksPerSecond,
2021 blockWidth, blockHeight, widthAlignment, heightAlignment);
2022 }
2023
2024 private void applyMacroBlockLimits(
2025 int minHorizontalBlocks, int minVerticalBlocks,
2026 int maxHorizontalBlocks, int maxVerticalBlocks,
2027 int maxBlocks, long maxBlocksPerSecond,
2028 int blockWidth, int blockHeight,
2029 int widthAlignment, int heightAlignment) {
2030 applyAlignment(widthAlignment, heightAlignment);
2031 applyBlockLimits(
2032 blockWidth, blockHeight, Range.create(1, maxBlocks),
2033 Range.create(1L, maxBlocksPerSecond),
2034 Range.create(
2035 new Rational(1, maxVerticalBlocks),
2036 new Rational(maxHorizontalBlocks, 1)));
2037 mHorizontalBlockRange =
2038 mHorizontalBlockRange.intersect(
2039 Utils.divUp(minHorizontalBlocks, (mBlockWidth / blockWidth)),
2040 maxHorizontalBlocks / (mBlockWidth / blockWidth));
2041 mVerticalBlockRange =
2042 mVerticalBlockRange.intersect(
2043 Utils.divUp(minVerticalBlocks, (mBlockHeight / blockHeight)),
2044 maxVerticalBlocks / (mBlockHeight / blockHeight));
2045 }
2046
2047 private void applyLevelLimits() {
2048 long maxBlocksPerSecond = 0;
2049 int maxBlocks = 0;
2050 int maxBps = 0;
2051 int maxDPBBlocks = 0;
2052
2053 int errors = ERROR_NONE_SUPPORTED;
2054 CodecProfileLevel[] profileLevels = mParent.profileLevels;
2055 String mime = mParent.getMimeType();
2056
2057 if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC)) {
2058 maxBlocks = 99;
2059 maxBlocksPerSecond = 1485;
2060 maxBps = 64000;
2061 maxDPBBlocks = 396;
2062 for (CodecProfileLevel profileLevel: profileLevels) {
2063 int MBPS = 0, FS = 0, BR = 0, DPB = 0;
2064 boolean supported = true;
2065 switch (profileLevel.level) {
2066 case CodecProfileLevel.AVCLevel1:
2067 MBPS = 1485; FS = 99; BR = 64; DPB = 396; break;
2068 case CodecProfileLevel.AVCLevel1b:
2069 MBPS = 1485; FS = 99; BR = 128; DPB = 396; break;
2070 case CodecProfileLevel.AVCLevel11:
2071 MBPS = 3000; FS = 396; BR = 192; DPB = 900; break;
2072 case CodecProfileLevel.AVCLevel12:
2073 MBPS = 6000; FS = 396; BR = 384; DPB = 2376; break;
2074 case CodecProfileLevel.AVCLevel13:
2075 MBPS = 11880; FS = 396; BR = 768; DPB = 2376; break;
2076 case CodecProfileLevel.AVCLevel2:
2077 MBPS = 11880; FS = 396; BR = 2000; DPB = 2376; break;
2078 case CodecProfileLevel.AVCLevel21:
2079 MBPS = 19800; FS = 792; BR = 4000; DPB = 4752; break;
2080 case CodecProfileLevel.AVCLevel22:
2081 MBPS = 20250; FS = 1620; BR = 4000; DPB = 8100; break;
2082 case CodecProfileLevel.AVCLevel3:
2083 MBPS = 40500; FS = 1620; BR = 10000; DPB = 8100; break;
2084 case CodecProfileLevel.AVCLevel31:
2085 MBPS = 108000; FS = 3600; BR = 14000; DPB = 18000; break;
2086 case CodecProfileLevel.AVCLevel32:
2087 MBPS = 216000; FS = 5120; BR = 20000; DPB = 20480; break;
2088 case CodecProfileLevel.AVCLevel4:
2089 MBPS = 245760; FS = 8192; BR = 20000; DPB = 32768; break;
2090 case CodecProfileLevel.AVCLevel41:
2091 MBPS = 245760; FS = 8192; BR = 50000; DPB = 32768; break;
2092 case CodecProfileLevel.AVCLevel42:
2093 MBPS = 522240; FS = 8704; BR = 50000; DPB = 34816; break;
2094 case CodecProfileLevel.AVCLevel5:
2095 MBPS = 589824; FS = 22080; BR = 135000; DPB = 110400; break;
2096 case CodecProfileLevel.AVCLevel51:
2097 MBPS = 983040; FS = 36864; BR = 240000; DPB = 184320; break;
2098 case CodecProfileLevel.AVCLevel52:
2099 MBPS = 2073600; FS = 36864; BR = 240000; DPB = 184320; break;
2100 default:
2101 Log.w(TAG, "Unrecognized level "
2102 + profileLevel.level + " for " + mime);
2103 errors |= ERROR_UNRECOGNIZED;
2104 }
2105 switch (profileLevel.profile) {
2106 case CodecProfileLevel.AVCProfileConstrainedHigh:
2107 case CodecProfileLevel.AVCProfileHigh:
2108 BR *= 1250; break;
2109 case CodecProfileLevel.AVCProfileHigh10:
2110 BR *= 3000; break;
2111 case CodecProfileLevel.AVCProfileExtended:
2112 case CodecProfileLevel.AVCProfileHigh422:
2113 case CodecProfileLevel.AVCProfileHigh444:
2114 Log.w(TAG, "Unsupported profile "
2115 + profileLevel.profile + " for " + mime);
2116 errors |= ERROR_UNSUPPORTED;
2117 supported = false;
2118 // fall through - treat as base profile
2119 case CodecProfileLevel.AVCProfileConstrainedBaseline:
2120 case CodecProfileLevel.AVCProfileBaseline:
2121 case CodecProfileLevel.AVCProfileMain:
2122 BR *= 1000; break;
2123 default:
2124 Log.w(TAG, "Unrecognized profile "
2125 + profileLevel.profile + " for " + mime);
2126 errors |= ERROR_UNRECOGNIZED;
2127 BR *= 1000;
2128 }
2129 if (supported) {
2130 errors &= ~ERROR_NONE_SUPPORTED;
2131 }
2132 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
2133 maxBlocks = Math.max(FS, maxBlocks);
2134 maxBps = Math.max(BR, maxBps);
2135 maxDPBBlocks = Math.max(maxDPBBlocks, DPB);
2136 }
2137
2138 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8));
2139 applyMacroBlockLimits(
2140 maxLengthInBlocks, maxLengthInBlocks,
2141 maxBlocks, maxBlocksPerSecond,
2142 16 /* blockWidth */, 16 /* blockHeight */,
2143 1 /* widthAlignment */, 1 /* heightAlignment */);
2144 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG2)) {
2145 int maxWidth = 11, maxHeight = 9, maxRate = 15;
2146 maxBlocks = 99;
2147 maxBlocksPerSecond = 1485;
2148 maxBps = 64000;
2149 for (CodecProfileLevel profileLevel: profileLevels) {
2150 int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0;
2151 boolean supported = true;
2152 switch (profileLevel.profile) {
2153 case CodecProfileLevel.MPEG2ProfileSimple:
2154 switch (profileLevel.level) {
2155 case CodecProfileLevel.MPEG2LevelML:
2156 FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 15000; break;
2157 default:
2158 Log.w(TAG, "Unrecognized profile/level "
2159 + profileLevel.profile + "/"
2160 + profileLevel.level + " for " + mime);
2161 errors |= ERROR_UNRECOGNIZED;
2162 }
2163 break;
2164 case CodecProfileLevel.MPEG2ProfileMain:
2165 switch (profileLevel.level) {
2166 case CodecProfileLevel.MPEG2LevelLL:
2167 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 4000; break;
2168 case CodecProfileLevel.MPEG2LevelML:
2169 FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 15000; break;
2170 case CodecProfileLevel.MPEG2LevelH14:
2171 FR = 60; W = 90; H = 68; MBPS = 183600; FS = 6120; BR = 60000; break;
2172 case CodecProfileLevel.MPEG2LevelHL:
2173 FR = 60; W = 120; H = 68; MBPS = 244800; FS = 8160; BR = 80000; break;
2174 case CodecProfileLevel.MPEG2LevelHP:
2175 FR = 60; W = 120; H = 68; MBPS = 489600; FS = 8160; BR = 80000; break;
2176 default:
2177 Log.w(TAG, "Unrecognized profile/level "
2178 + profileLevel.profile + "/"
2179 + profileLevel.level + " for " + mime);
2180 errors |= ERROR_UNRECOGNIZED;
2181 }
2182 break;
2183 case CodecProfileLevel.MPEG2Profile422:
2184 case CodecProfileLevel.MPEG2ProfileSNR:
2185 case CodecProfileLevel.MPEG2ProfileSpatial:
2186 case CodecProfileLevel.MPEG2ProfileHigh:
2187 Log.i(TAG, "Unsupported profile "
2188 + profileLevel.profile + " for " + mime);
2189 errors |= ERROR_UNSUPPORTED;
2190 supported = false;
2191 break;
2192 default:
2193 Log.w(TAG, "Unrecognized profile "
2194 + profileLevel.profile + " for " + mime);
2195 errors |= ERROR_UNRECOGNIZED;
2196 }
2197 if (supported) {
2198 errors &= ~ERROR_NONE_SUPPORTED;
2199 }
2200 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
2201 maxBlocks = Math.max(FS, maxBlocks);
2202 maxBps = Math.max(BR * 1000, maxBps);
2203 maxWidth = Math.max(W, maxWidth);
2204 maxHeight = Math.max(H, maxHeight);
2205 maxRate = Math.max(FR, maxRate);
2206 }
2207 applyMacroBlockLimits(maxWidth, maxHeight,
2208 maxBlocks, maxBlocksPerSecond,
2209 16 /* blockWidth */, 16 /* blockHeight */,
2210 1 /* widthAlignment */, 1 /* heightAlignment */);
2211 mFrameRateRange = mFrameRateRange.intersect(12, maxRate);
2212 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) {
2213 int maxWidth = 11, maxHeight = 9, maxRate = 15;
2214 maxBlocks = 99;
2215 maxBlocksPerSecond = 1485;
2216 maxBps = 64000;
2217 for (CodecProfileLevel profileLevel: profileLevels) {
2218 int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0;
2219 boolean strict = false; // true: W, H and FR are individual max limits
2220 boolean supported = true;
2221 switch (profileLevel.profile) {
2222 case CodecProfileLevel.MPEG4ProfileSimple:
2223 switch (profileLevel.level) {
2224 case CodecProfileLevel.MPEG4Level0:
2225 strict = true;
2226 FR = 15; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 64; break;
2227 case CodecProfileLevel.MPEG4Level1:
2228 FR = 30; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 64; break;
2229 case CodecProfileLevel.MPEG4Level0b:
2230 strict = true;
2231 FR = 15; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 128; break;
2232 case CodecProfileLevel.MPEG4Level2:
2233 FR = 30; W = 22; H = 18; MBPS = 5940; FS = 396; BR = 128; break;
2234 case CodecProfileLevel.MPEG4Level3:
2235 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384; break;
2236 case CodecProfileLevel.MPEG4Level4a:
2237 FR = 30; W = 40; H = 30; MBPS = 36000; FS = 1200; BR = 4000; break;
2238 case CodecProfileLevel.MPEG4Level5:
2239 FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 8000; break;
2240 case CodecProfileLevel.MPEG4Level6:
2241 FR = 30; W = 80; H = 45; MBPS = 108000; FS = 3600; BR = 12000; break;
2242 default:
2243 Log.w(TAG, "Unrecognized profile/level "
2244 + profileLevel.profile + "/"
2245 + profileLevel.level + " for " + mime);
2246 errors |= ERROR_UNRECOGNIZED;
2247 }
2248 break;
2249 case CodecProfileLevel.MPEG4ProfileAdvancedSimple:
2250 switch (profileLevel.level) {
2251 case CodecProfileLevel.MPEG4Level0:
2252 case CodecProfileLevel.MPEG4Level1:
2253 FR = 30; W = 11; H = 9; MBPS = 2970; FS = 99; BR = 128; break;
2254 case CodecProfileLevel.MPEG4Level2:
2255 FR = 30; W = 22; H = 18; MBPS = 5940; FS = 396; BR = 384; break;
2256 case CodecProfileLevel.MPEG4Level3:
2257 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 768; break;
2258 case CodecProfileLevel.MPEG4Level3b:
2259 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 1500; break;
2260 case CodecProfileLevel.MPEG4Level4:
2261 FR = 30; W = 44; H = 36; MBPS = 23760; FS = 792; BR = 3000; break;
2262 case CodecProfileLevel.MPEG4Level5:
2263 FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 8000; break;
2264 default:
2265 Log.w(TAG, "Unrecognized profile/level "
2266 + profileLevel.profile + "/"
2267 + profileLevel.level + " for " + mime);
2268 errors |= ERROR_UNRECOGNIZED;
2269 }
2270 break;
2271 case CodecProfileLevel.MPEG4ProfileMain: // 2-4
2272 case CodecProfileLevel.MPEG4ProfileNbit: // 2
2273 case CodecProfileLevel.MPEG4ProfileAdvancedRealTime: // 1-4
2274 case CodecProfileLevel.MPEG4ProfileCoreScalable: // 1-3
2275 case CodecProfileLevel.MPEG4ProfileAdvancedCoding: // 1-4
2276 case CodecProfileLevel.MPEG4ProfileCore: // 1-2
2277 case CodecProfileLevel.MPEG4ProfileAdvancedCore: // 1-4
2278 case CodecProfileLevel.MPEG4ProfileSimpleScalable: // 0-2
2279 case CodecProfileLevel.MPEG4ProfileHybrid: // 1-2
2280
2281 // Studio profiles are not supported by our codecs.
2282
2283 // Only profiles that can decode simple object types are considered.
2284 // The following profiles are not able to.
2285 case CodecProfileLevel.MPEG4ProfileBasicAnimated: // 1-2
2286 case CodecProfileLevel.MPEG4ProfileScalableTexture: // 1
2287 case CodecProfileLevel.MPEG4ProfileSimpleFace: // 1-2
2288 case CodecProfileLevel.MPEG4ProfileAdvancedScalable: // 1-3
2289 case CodecProfileLevel.MPEG4ProfileSimpleFBA: // 1-2
2290 Log.i(TAG, "Unsupported profile "
2291 + profileLevel.profile + " for " + mime);
2292 errors |= ERROR_UNSUPPORTED;
2293 supported = false;
2294 break;
2295 default:
2296 Log.w(TAG, "Unrecognized profile "
2297 + profileLevel.profile + " for " + mime);
2298 errors |= ERROR_UNRECOGNIZED;
2299 }
2300 if (supported) {
2301 errors &= ~ERROR_NONE_SUPPORTED;
2302 }
2303 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
2304 maxBlocks = Math.max(FS, maxBlocks);
2305 maxBps = Math.max(BR * 1000, maxBps);
2306 if (strict) {
2307 maxWidth = Math.max(W, maxWidth);
2308 maxHeight = Math.max(H, maxHeight);
2309 maxRate = Math.max(FR, maxRate);
2310 } else {
2311 // assuming max 60 fps frame rate and 1:2 aspect ratio
2312 int maxDim = (int)Math.sqrt(FS * 2);
2313 maxWidth = Math.max(maxDim, maxWidth);
2314 maxHeight = Math.max(maxDim, maxHeight);
2315 maxRate = Math.max(Math.max(FR, 60), maxRate);
2316 }
2317 }
2318 applyMacroBlockLimits(maxWidth, maxHeight,
2319 maxBlocks, maxBlocksPerSecond,
2320 16 /* blockWidth */, 16 /* blockHeight */,
2321 1 /* widthAlignment */, 1 /* heightAlignment */);
2322 mFrameRateRange = mFrameRateRange.intersect(12, maxRate);
2323 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) {
2324 int maxWidth = 11, maxHeight = 9, maxRate = 15;
2325 int minWidth = maxWidth, minHeight = maxHeight;
2326 int minAlignment = 16;
2327 maxBlocks = 99;
2328 maxBlocksPerSecond = 1485;
2329 maxBps = 64000;
2330 for (CodecProfileLevel profileLevel: profileLevels) {
2331 int MBPS = 0, BR = 0, FR = 0, W = 0, H = 0, minW = minWidth, minH = minHeight;
2332 boolean strict = false; // true: support only sQCIF, QCIF (maybe CIF)
2333 switch (profileLevel.level) {
2334 case CodecProfileLevel.H263Level10:
2335 strict = true; // only supports sQCIF & QCIF
2336 FR = 15; W = 11; H = 9; BR = 1; MBPS = W * H * FR; break;
2337 case CodecProfileLevel.H263Level20:
2338 strict = true; // only supports sQCIF, QCIF & CIF
2339 FR = 30; W = 22; H = 18; BR = 2; MBPS = W * H * 15; break;
2340 case CodecProfileLevel.H263Level30:
2341 strict = true; // only supports sQCIF, QCIF & CIF
2342 FR = 30; W = 22; H = 18; BR = 6; MBPS = W * H * FR; break;
2343 case CodecProfileLevel.H263Level40:
2344 strict = true; // only supports sQCIF, QCIF & CIF
2345 FR = 30; W = 22; H = 18; BR = 32; MBPS = W * H * FR; break;
2346 case CodecProfileLevel.H263Level45:
2347 // only implies level 10 support
2348 strict = profileLevel.profile == CodecProfileLevel.H263ProfileBaseline
2349 || profileLevel.profile ==
2350 CodecProfileLevel.H263ProfileBackwardCompatible;
2351 if (!strict) {
2352 minW = 1; minH = 1; minAlignment = 4;
2353 }
2354 FR = 15; W = 11; H = 9; BR = 2; MBPS = W * H * FR; break;
2355 case CodecProfileLevel.H263Level50:
2356 // only supports 50fps for H > 15
2357 minW = 1; minH = 1; minAlignment = 4;
2358 FR = 60; W = 22; H = 18; BR = 64; MBPS = W * H * 50; break;
2359 case CodecProfileLevel.H263Level60:
2360 // only supports 50fps for H > 15
2361 minW = 1; minH = 1; minAlignment = 4;
2362 FR = 60; W = 45; H = 18; BR = 128; MBPS = W * H * 50; break;
2363 case CodecProfileLevel.H263Level70:
2364 // only supports 50fps for H > 30
2365 minW = 1; minH = 1; minAlignment = 4;
2366 FR = 60; W = 45; H = 36; BR = 256; MBPS = W * H * 50; break;
2367 default:
2368 Log.w(TAG, "Unrecognized profile/level " + profileLevel.profile
2369 + "/" + profileLevel.level + " for " + mime);
2370 errors |= ERROR_UNRECOGNIZED;
2371 }
2372 switch (profileLevel.profile) {
2373 case CodecProfileLevel.H263ProfileBackwardCompatible:
2374 case CodecProfileLevel.H263ProfileBaseline:
2375 case CodecProfileLevel.H263ProfileH320Coding:
2376 case CodecProfileLevel.H263ProfileHighCompression:
2377 case CodecProfileLevel.H263ProfileHighLatency:
2378 case CodecProfileLevel.H263ProfileInterlace:
2379 case CodecProfileLevel.H263ProfileInternet:
2380 case CodecProfileLevel.H263ProfileISWV2:
2381 case CodecProfileLevel.H263ProfileISWV3:
2382 break;
2383 default:
2384 Log.w(TAG, "Unrecognized profile "
2385 + profileLevel.profile + " for " + mime);
2386 errors |= ERROR_UNRECOGNIZED;
2387 }
2388 if (strict) {
2389 // Strict levels define sub-QCIF min size and enumerated sizes. We cannot
2390 // express support for "only sQCIF & QCIF (& CIF)" using VideoCapabilities
2391 // but we can express "only QCIF (& CIF)", so set minimume size at QCIF.
2392 // minW = 8; minH = 6;
2393 minW = 11; minH = 9;
2394 } else {
2395 // any support for non-strict levels (including unrecognized profiles or
2396 // levels) allow custom frame size support beyond supported limits
2397 // (other than bitrate)
2398 mAllowMbOverride = true;
2399 }
2400 errors &= ~ERROR_NONE_SUPPORTED;
2401 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond);
2402 maxBlocks = Math.max(W * H, maxBlocks);
2403 maxBps = Math.max(BR * 64000, maxBps);
2404 maxWidth = Math.max(W, maxWidth);
2405 maxHeight = Math.max(H, maxHeight);
2406 maxRate = Math.max(FR, maxRate);
2407 minWidth = Math.min(minW, minWidth);
2408 minHeight = Math.min(minH, minHeight);
2409 }
2410 // unless we encountered custom frame size support, limit size to QCIF and CIF
2411 // using aspect ratio.
2412 if (!mAllowMbOverride) {
2413 mBlockAspectRatioRange =
2414 Range.create(new Rational(11, 9), new Rational(11, 9));
2415 }
2416 applyMacroBlockLimits(
2417 minWidth, minHeight,
2418 maxWidth, maxHeight,
2419 maxBlocks, maxBlocksPerSecond,
2420 16 /* blockWidth */, 16 /* blockHeight */,
2421 minAlignment /* widthAlignment */, minAlignment /* heightAlignment */);
2422 mFrameRateRange = Range.create(1, maxRate);
2423 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8)) {
2424 maxBlocks = Integer.MAX_VALUE;
2425 maxBlocksPerSecond = Integer.MAX_VALUE;
2426
2427 // TODO: set to 100Mbps for now, need a number for VP8
2428 maxBps = 100000000;
2429
2430 // profile levels are not indicative for VPx, but verify
2431 // them nonetheless
2432 for (CodecProfileLevel profileLevel: profileLevels) {
2433 switch (profileLevel.level) {
2434 case CodecProfileLevel.VP8Level_Version0:
2435 case CodecProfileLevel.VP8Level_Version1:
2436 case CodecProfileLevel.VP8Level_Version2:
2437 case CodecProfileLevel.VP8Level_Version3:
2438 break;
2439 default:
2440 Log.w(TAG, "Unrecognized level "
2441 + profileLevel.level + " for " + mime);
2442 errors |= ERROR_UNRECOGNIZED;
2443 }
2444 switch (profileLevel.profile) {
2445 case CodecProfileLevel.VP8ProfileMain:
2446 break;
2447 default:
2448 Log.w(TAG, "Unrecognized profile "
2449 + profileLevel.profile + " for " + mime);
2450 errors |= ERROR_UNRECOGNIZED;
2451 }
2452 errors &= ~ERROR_NONE_SUPPORTED;
2453 }
2454
2455 final int blockSize = 16;
2456 applyMacroBlockLimits(Short.MAX_VALUE, Short.MAX_VALUE,
2457 maxBlocks, maxBlocksPerSecond, blockSize, blockSize,
2458 1 /* widthAlignment */, 1 /* heightAlignment */);
2459 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) {
2460 maxBlocksPerSecond = 829440;
2461 maxBlocks = 36864;
2462 maxBps = 200000;
2463 int maxDim = 512;
2464
2465 for (CodecProfileLevel profileLevel: profileLevels) {
2466 long SR = 0; // luma sample rate
2467 int FS = 0; // luma picture size
2468 int BR = 0; // bit rate kbps
2469 int D = 0; // luma dimension
2470 switch (profileLevel.level) {
2471 case CodecProfileLevel.VP9Level1:
2472 SR = 829440; FS = 36864; BR = 200; D = 512; break;
2473 case CodecProfileLevel.VP9Level11:
2474 SR = 2764800; FS = 73728; BR = 800; D = 768; break;
2475 case CodecProfileLevel.VP9Level2:
2476 SR = 4608000; FS = 122880; BR = 1800; D = 960; break;
2477 case CodecProfileLevel.VP9Level21:
2478 SR = 9216000; FS = 245760; BR = 3600; D = 1344; break;
2479 case CodecProfileLevel.VP9Level3:
2480 SR = 20736000; FS = 552960; BR = 7200; D = 2048; break;
2481 case CodecProfileLevel.VP9Level31:
2482 SR = 36864000; FS = 983040; BR = 12000; D = 2752; break;
2483 case CodecProfileLevel.VP9Level4:
2484 SR = 83558400; FS = 2228224; BR = 18000; D = 4160; break;
2485 case CodecProfileLevel.VP9Level41:
2486 SR = 160432128; FS = 2228224; BR = 30000; D = 4160; break;
2487 case CodecProfileLevel.VP9Level5:
2488 SR = 311951360; FS = 8912896; BR = 60000; D = 8384; break;
2489 case CodecProfileLevel.VP9Level51:
2490 SR = 588251136; FS = 8912896; BR = 120000; D = 8384; break;
2491 case CodecProfileLevel.VP9Level52:
2492 SR = 1176502272; FS = 8912896; BR = 180000; D = 8384; break;
2493 case CodecProfileLevel.VP9Level6:
2494 SR = 1176502272; FS = 35651584; BR = 180000; D = 16832; break;
2495 case CodecProfileLevel.VP9Level61:
2496 SR = 2353004544L; FS = 35651584; BR = 240000; D = 16832; break;
2497 case CodecProfileLevel.VP9Level62:
2498 SR = 4706009088L; FS = 35651584; BR = 480000; D = 16832; break;
2499 default:
2500 Log.w(TAG, "Unrecognized level "
2501 + profileLevel.level + " for " + mime);
2502 errors |= ERROR_UNRECOGNIZED;
2503 }
2504 switch (profileLevel.profile) {
2505 case CodecProfileLevel.VP9Profile0:
2506 case CodecProfileLevel.VP9Profile1:
2507 case CodecProfileLevel.VP9Profile2:
2508 case CodecProfileLevel.VP9Profile3:
2509 case CodecProfileLevel.VP9Profile2HDR:
2510 case CodecProfileLevel.VP9Profile3HDR:
2511 break;
2512 default:
2513 Log.w(TAG, "Unrecognized profile "
2514 + profileLevel.profile + " for " + mime);
2515 errors |= ERROR_UNRECOGNIZED;
2516 }
2517 errors &= ~ERROR_NONE_SUPPORTED;
2518 maxBlocksPerSecond = Math.max(SR, maxBlocksPerSecond);
2519 maxBlocks = Math.max(FS, maxBlocks);
2520 maxBps = Math.max(BR * 1000, maxBps);
2521 maxDim = Math.max(D, maxDim);
2522 }
2523
2524 final int blockSize = 8;
2525 int maxLengthInBlocks = Utils.divUp(maxDim, blockSize);
2526 maxBlocks = Utils.divUp(maxBlocks, blockSize * blockSize);
2527 maxBlocksPerSecond = Utils.divUp(maxBlocksPerSecond, blockSize * blockSize);
2528
2529 applyMacroBlockLimits(
2530 maxLengthInBlocks, maxLengthInBlocks,
2531 maxBlocks, maxBlocksPerSecond,
2532 blockSize, blockSize,
2533 1 /* widthAlignment */, 1 /* heightAlignment */);
2534 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
2535 // CTBs are at least 8x8 so use 8x8 block size
2536 maxBlocks = 36864 >> 6; // 192x192 pixels == 576 8x8 blocks
2537 maxBlocksPerSecond = maxBlocks * 15;
2538 maxBps = 128000;
2539 for (CodecProfileLevel profileLevel: profileLevels) {
2540 double FR = 0;
2541 int FS = 0;
2542 int BR = 0;
2543 switch (profileLevel.level) {
2544 /* The HEVC spec talks only in a very convoluted manner about the
2545 existence of levels 1-3.1 for High tier, which could also be
2546 understood as 'decoders and encoders should treat these levels
2547 as if they were Main tier', so we do that. */
2548 case CodecProfileLevel.HEVCMainTierLevel1:
2549 case CodecProfileLevel.HEVCHighTierLevel1:
2550 FR = 15; FS = 36864; BR = 128; break;
2551 case CodecProfileLevel.HEVCMainTierLevel2:
2552 case CodecProfileLevel.HEVCHighTierLevel2:
2553 FR = 30; FS = 122880; BR = 1500; break;
2554 case CodecProfileLevel.HEVCMainTierLevel21:
2555 case CodecProfileLevel.HEVCHighTierLevel21:
2556 FR = 30; FS = 245760; BR = 3000; break;
2557 case CodecProfileLevel.HEVCMainTierLevel3:
2558 case CodecProfileLevel.HEVCHighTierLevel3:
2559 FR = 30; FS = 552960; BR = 6000; break;
2560 case CodecProfileLevel.HEVCMainTierLevel31:
2561 case CodecProfileLevel.HEVCHighTierLevel31:
2562 FR = 33.75; FS = 983040; BR = 10000; break;
2563 case CodecProfileLevel.HEVCMainTierLevel4:
2564 FR = 30; FS = 2228224; BR = 12000; break;
2565 case CodecProfileLevel.HEVCHighTierLevel4:
2566 FR = 30; FS = 2228224; BR = 30000; break;
2567 case CodecProfileLevel.HEVCMainTierLevel41:
2568 FR = 60; FS = 2228224; BR = 20000; break;
2569 case CodecProfileLevel.HEVCHighTierLevel41:
2570 FR = 60; FS = 2228224; BR = 50000; break;
2571 case CodecProfileLevel.HEVCMainTierLevel5:
2572 FR = 30; FS = 8912896; BR = 25000; break;
2573 case CodecProfileLevel.HEVCHighTierLevel5:
2574 FR = 30; FS = 8912896; BR = 100000; break;
2575 case CodecProfileLevel.HEVCMainTierLevel51:
2576 FR = 60; FS = 8912896; BR = 40000; break;
2577 case CodecProfileLevel.HEVCHighTierLevel51:
2578 FR = 60; FS = 8912896; BR = 160000; break;
2579 case CodecProfileLevel.HEVCMainTierLevel52:
2580 FR = 120; FS = 8912896; BR = 60000; break;
2581 case CodecProfileLevel.HEVCHighTierLevel52:
2582 FR = 120; FS = 8912896; BR = 240000; break;
2583 case CodecProfileLevel.HEVCMainTierLevel6:
2584 FR = 30; FS = 35651584; BR = 60000; break;
2585 case CodecProfileLevel.HEVCHighTierLevel6:
2586 FR = 30; FS = 35651584; BR = 240000; break;
2587 case CodecProfileLevel.HEVCMainTierLevel61:
2588 FR = 60; FS = 35651584; BR = 120000; break;
2589 case CodecProfileLevel.HEVCHighTierLevel61:
2590 FR = 60; FS = 35651584; BR = 480000; break;
2591 case CodecProfileLevel.HEVCMainTierLevel62:
2592 FR = 120; FS = 35651584; BR = 240000; break;
2593 case CodecProfileLevel.HEVCHighTierLevel62:
2594 FR = 120; FS = 35651584; BR = 800000; break;
2595 default:
2596 Log.w(TAG, "Unrecognized level "
2597 + profileLevel.level + " for " + mime);
2598 errors |= ERROR_UNRECOGNIZED;
2599 }
2600 switch (profileLevel.profile) {
2601 case CodecProfileLevel.HEVCProfileMain:
2602 case CodecProfileLevel.HEVCProfileMain10:
2603 case CodecProfileLevel.HEVCProfileMain10HDR10:
2604 break;
2605 default:
2606 Log.w(TAG, "Unrecognized profile "
2607 + profileLevel.profile + " for " + mime);
2608 errors |= ERROR_UNRECOGNIZED;
2609 }
2610
2611 /* DPB logic:
2612 if (width * height <= FS / 4) DPB = 16;
2613 else if (width * height <= FS / 2) DPB = 12;
2614 else if (width * height <= FS * 0.75) DPB = 8;
2615 else DPB = 6;
2616 */
2617
2618 FS >>= 6; // convert pixels to blocks
2619 errors &= ~ERROR_NONE_SUPPORTED;
2620 maxBlocksPerSecond = Math.max((int)(FR * FS), maxBlocksPerSecond);
2621 maxBlocks = Math.max(FS, maxBlocks);
2622 maxBps = Math.max(BR * 1000, maxBps);
2623 }
2624
2625 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8));
2626 applyMacroBlockLimits(
2627 maxLengthInBlocks, maxLengthInBlocks,
2628 maxBlocks, maxBlocksPerSecond,
2629 8 /* blockWidth */, 8 /* blockHeight */,
2630 1 /* widthAlignment */, 1 /* heightAlignment */);
2631 } else {
2632 Log.w(TAG, "Unsupported mime " + mime);
2633 // using minimal bitrate here. should be overriden by
2634 // info from media_codecs.xml
2635 maxBps = 64000;
2636 errors |= ERROR_UNSUPPORTED;
2637 }
2638 mBitrateRange = Range.create(1, maxBps);
2639 mParent.mError |= errors;
2640 }
2641 }
2642
2643 /**
2644 * A class that supports querying the encoding capabilities of a codec.
2645 */
2646 public static final class EncoderCapabilities {
2647 /**
2648 * Returns the supported range of quality values.
2649 *
Jeff Davidsona192cc22018-02-08 15:30:06 -08002650 * Quality is implementation-specific. As a general rule, a higher quality
2651 * setting results in a better image quality and a lower compression ratio.
Justin Klaassen10d07c82017-09-15 17:58:39 -04002652 */
2653 public Range<Integer> getQualityRange() {
2654 return mQualityRange;
2655 }
2656
2657 /**
2658 * Returns the supported range of encoder complexity values.
2659 * <p>
2660 * Some codecs may support multiple complexity levels, where higher
2661 * complexity values use more encoder tools (e.g. perform more
2662 * intensive calculations) to improve the quality or the compression
2663 * ratio. Use a lower value to save power and/or time.
2664 */
2665 public Range<Integer> getComplexityRange() {
2666 return mComplexityRange;
2667 }
2668
2669 /** Constant quality mode */
2670 public static final int BITRATE_MODE_CQ = 0;
2671 /** Variable bitrate mode */
2672 public static final int BITRATE_MODE_VBR = 1;
2673 /** Constant bitrate mode */
2674 public static final int BITRATE_MODE_CBR = 2;
2675
2676 private static final Feature[] bitrates = new Feature[] {
2677 new Feature("VBR", BITRATE_MODE_VBR, true),
2678 new Feature("CBR", BITRATE_MODE_CBR, false),
2679 new Feature("CQ", BITRATE_MODE_CQ, false)
2680 };
2681
2682 private static int parseBitrateMode(String mode) {
2683 for (Feature feat: bitrates) {
2684 if (feat.mName.equalsIgnoreCase(mode)) {
2685 return feat.mValue;
2686 }
2687 }
2688 return 0;
2689 }
2690
2691 /**
2692 * Query whether a bitrate mode is supported.
2693 */
2694 public boolean isBitrateModeSupported(int mode) {
2695 for (Feature feat: bitrates) {
2696 if (mode == feat.mValue) {
2697 return (mBitControl & (1 << mode)) != 0;
2698 }
2699 }
2700 return false;
2701 }
2702
2703 private Range<Integer> mQualityRange;
2704 private Range<Integer> mComplexityRange;
2705 private CodecCapabilities mParent;
2706
2707 /* no public constructor */
2708 private EncoderCapabilities() { }
2709
2710 /** @hide */
2711 public static EncoderCapabilities create(
2712 MediaFormat info, CodecCapabilities parent) {
2713 EncoderCapabilities caps = new EncoderCapabilities();
2714 caps.init(info, parent);
2715 return caps;
2716 }
2717
Justin Klaassen4d01eea2018-04-03 23:21:57 -04002718 private void init(MediaFormat info, CodecCapabilities parent) {
Justin Klaassen10d07c82017-09-15 17:58:39 -04002719 // no support for complexity or quality yet
2720 mParent = parent;
2721 mComplexityRange = Range.create(0, 0);
2722 mQualityRange = Range.create(0, 0);
2723 mBitControl = (1 << BITRATE_MODE_VBR);
2724
2725 applyLevelLimits();
2726 parseFromInfo(info);
2727 }
2728
2729 private void applyLevelLimits() {
2730 String mime = mParent.getMimeType();
2731 if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
2732 mComplexityRange = Range.create(0, 8);
2733 mBitControl = (1 << BITRATE_MODE_CQ);
2734 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)
2735 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)
2736 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW)
2737 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)
2738 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) {
2739 mBitControl = (1 << BITRATE_MODE_CBR);
2740 }
2741 }
2742
2743 private int mBitControl;
2744 private Integer mDefaultComplexity;
2745 private Integer mDefaultQuality;
2746 private String mQualityScale;
2747
2748 private void parseFromInfo(MediaFormat info) {
2749 Map<String, Object> map = info.getMap();
2750
2751 if (info.containsKey("complexity-range")) {
2752 mComplexityRange = Utils
2753 .parseIntRange(info.getString("complexity-range"), mComplexityRange);
2754 // TODO should we limit this to level limits?
2755 }
2756 if (info.containsKey("quality-range")) {
2757 mQualityRange = Utils
2758 .parseIntRange(info.getString("quality-range"), mQualityRange);
2759 }
Justin Klaassen93b7ee42017-10-10 15:20:13 -04002760 if (info.containsKey("feature-bitrate-modes")) {
2761 for (String mode: info.getString("feature-bitrate-modes").split(",")) {
Jeff Davidsona192cc22018-02-08 15:30:06 -08002762 mBitControl |= (1 << parseBitrateMode(mode));
Justin Klaassen10d07c82017-09-15 17:58:39 -04002763 }
2764 }
2765
2766 try {
2767 mDefaultComplexity = Integer.parseInt((String)map.get("complexity-default"));
2768 } catch (NumberFormatException e) { }
2769
2770 try {
2771 mDefaultQuality = Integer.parseInt((String)map.get("quality-default"));
2772 } catch (NumberFormatException e) { }
2773
2774 mQualityScale = (String)map.get("quality-scale");
2775 }
2776
2777 private boolean supports(
2778 Integer complexity, Integer quality, Integer profile) {
2779 boolean ok = true;
2780 if (ok && complexity != null) {
2781 ok = mComplexityRange.contains(complexity);
2782 }
2783 if (ok && quality != null) {
2784 ok = mQualityRange.contains(quality);
2785 }
2786 if (ok && profile != null) {
2787 for (CodecProfileLevel pl: mParent.profileLevels) {
2788 if (pl.profile == profile) {
2789 profile = null;
2790 break;
2791 }
2792 }
2793 ok = profile == null;
2794 }
2795 return ok;
2796 }
2797
2798 /** @hide */
Justin Klaassen4d01eea2018-04-03 23:21:57 -04002799 public void getDefaultFormat(MediaFormat format) {
Justin Klaassen10d07c82017-09-15 17:58:39 -04002800 // don't list trivial quality/complexity as default for now
2801 if (!mQualityRange.getUpper().equals(mQualityRange.getLower())
2802 && mDefaultQuality != null) {
2803 format.setInteger(MediaFormat.KEY_QUALITY, mDefaultQuality);
2804 }
2805 if (!mComplexityRange.getUpper().equals(mComplexityRange.getLower())
2806 && mDefaultComplexity != null) {
2807 format.setInteger(MediaFormat.KEY_COMPLEXITY, mDefaultComplexity);
2808 }
2809 // bitrates are listed in order of preference
2810 for (Feature feat: bitrates) {
2811 if ((mBitControl & (1 << feat.mValue)) != 0) {
2812 format.setInteger(MediaFormat.KEY_BITRATE_MODE, feat.mValue);
2813 break;
2814 }
2815 }
2816 }
2817
2818 /** @hide */
2819 public boolean supportsFormat(MediaFormat format) {
2820 final Map<String, Object> map = format.getMap();
2821 final String mime = mParent.getMimeType();
2822
2823 Integer mode = (Integer)map.get(MediaFormat.KEY_BITRATE_MODE);
2824 if (mode != null && !isBitrateModeSupported(mode)) {
2825 return false;
2826 }
2827
2828 Integer complexity = (Integer)map.get(MediaFormat.KEY_COMPLEXITY);
2829 if (MediaFormat.MIMETYPE_AUDIO_FLAC.equalsIgnoreCase(mime)) {
2830 Integer flacComplexity =
2831 (Integer)map.get(MediaFormat.KEY_FLAC_COMPRESSION_LEVEL);
2832 if (complexity == null) {
2833 complexity = flacComplexity;
2834 } else if (flacComplexity != null && !complexity.equals(flacComplexity)) {
2835 throw new IllegalArgumentException(
2836 "conflicting values for complexity and " +
2837 "flac-compression-level");
2838 }
2839 }
2840
2841 // other audio parameters
2842 Integer profile = (Integer)map.get(MediaFormat.KEY_PROFILE);
2843 if (MediaFormat.MIMETYPE_AUDIO_AAC.equalsIgnoreCase(mime)) {
2844 Integer aacProfile = (Integer)map.get(MediaFormat.KEY_AAC_PROFILE);
2845 if (profile == null) {
2846 profile = aacProfile;
2847 } else if (aacProfile != null && !aacProfile.equals(profile)) {
2848 throw new IllegalArgumentException(
2849 "conflicting values for profile and aac-profile");
2850 }
2851 }
2852
2853 Integer quality = (Integer)map.get(MediaFormat.KEY_QUALITY);
2854
2855 return supports(complexity, quality, profile);
2856 }
2857 };
2858
2859 /**
2860 * Encapsulates the profiles available for a codec component.
2861 * <p>You can get a set of {@link MediaCodecInfo.CodecProfileLevel} objects for a given
2862 * {@link MediaCodecInfo} object from the
2863 * {@link MediaCodecInfo.CodecCapabilities#profileLevels} field.
2864 */
2865 public static final class CodecProfileLevel {
2866 // from OMX_VIDEO_AVCPROFILETYPE
2867 public static final int AVCProfileBaseline = 0x01;
2868 public static final int AVCProfileMain = 0x02;
2869 public static final int AVCProfileExtended = 0x04;
2870 public static final int AVCProfileHigh = 0x08;
2871 public static final int AVCProfileHigh10 = 0x10;
2872 public static final int AVCProfileHigh422 = 0x20;
2873 public static final int AVCProfileHigh444 = 0x40;
2874 public static final int AVCProfileConstrainedBaseline = 0x10000;
2875 public static final int AVCProfileConstrainedHigh = 0x80000;
2876
2877 // from OMX_VIDEO_AVCLEVELTYPE
2878 public static final int AVCLevel1 = 0x01;
2879 public static final int AVCLevel1b = 0x02;
2880 public static final int AVCLevel11 = 0x04;
2881 public static final int AVCLevel12 = 0x08;
2882 public static final int AVCLevel13 = 0x10;
2883 public static final int AVCLevel2 = 0x20;
2884 public static final int AVCLevel21 = 0x40;
2885 public static final int AVCLevel22 = 0x80;
2886 public static final int AVCLevel3 = 0x100;
2887 public static final int AVCLevel31 = 0x200;
2888 public static final int AVCLevel32 = 0x400;
2889 public static final int AVCLevel4 = 0x800;
2890 public static final int AVCLevel41 = 0x1000;
2891 public static final int AVCLevel42 = 0x2000;
2892 public static final int AVCLevel5 = 0x4000;
2893 public static final int AVCLevel51 = 0x8000;
2894 public static final int AVCLevel52 = 0x10000;
2895
2896 // from OMX_VIDEO_H263PROFILETYPE
2897 public static final int H263ProfileBaseline = 0x01;
2898 public static final int H263ProfileH320Coding = 0x02;
2899 public static final int H263ProfileBackwardCompatible = 0x04;
2900 public static final int H263ProfileISWV2 = 0x08;
2901 public static final int H263ProfileISWV3 = 0x10;
2902 public static final int H263ProfileHighCompression = 0x20;
2903 public static final int H263ProfileInternet = 0x40;
2904 public static final int H263ProfileInterlace = 0x80;
2905 public static final int H263ProfileHighLatency = 0x100;
2906
2907 // from OMX_VIDEO_H263LEVELTYPE
2908 public static final int H263Level10 = 0x01;
2909 public static final int H263Level20 = 0x02;
2910 public static final int H263Level30 = 0x04;
2911 public static final int H263Level40 = 0x08;
2912 public static final int H263Level45 = 0x10;
2913 public static final int H263Level50 = 0x20;
2914 public static final int H263Level60 = 0x40;
2915 public static final int H263Level70 = 0x80;
2916
2917 // from OMX_VIDEO_MPEG4PROFILETYPE
2918 public static final int MPEG4ProfileSimple = 0x01;
2919 public static final int MPEG4ProfileSimpleScalable = 0x02;
2920 public static final int MPEG4ProfileCore = 0x04;
2921 public static final int MPEG4ProfileMain = 0x08;
2922 public static final int MPEG4ProfileNbit = 0x10;
2923 public static final int MPEG4ProfileScalableTexture = 0x20;
2924 public static final int MPEG4ProfileSimpleFace = 0x40;
2925 public static final int MPEG4ProfileSimpleFBA = 0x80;
2926 public static final int MPEG4ProfileBasicAnimated = 0x100;
2927 public static final int MPEG4ProfileHybrid = 0x200;
2928 public static final int MPEG4ProfileAdvancedRealTime = 0x400;
2929 public static final int MPEG4ProfileCoreScalable = 0x800;
2930 public static final int MPEG4ProfileAdvancedCoding = 0x1000;
2931 public static final int MPEG4ProfileAdvancedCore = 0x2000;
2932 public static final int MPEG4ProfileAdvancedScalable = 0x4000;
2933 public static final int MPEG4ProfileAdvancedSimple = 0x8000;
2934
2935 // from OMX_VIDEO_MPEG4LEVELTYPE
2936 public static final int MPEG4Level0 = 0x01;
2937 public static final int MPEG4Level0b = 0x02;
2938 public static final int MPEG4Level1 = 0x04;
2939 public static final int MPEG4Level2 = 0x08;
2940 public static final int MPEG4Level3 = 0x10;
2941 public static final int MPEG4Level3b = 0x18;
2942 public static final int MPEG4Level4 = 0x20;
2943 public static final int MPEG4Level4a = 0x40;
2944 public static final int MPEG4Level5 = 0x80;
2945 public static final int MPEG4Level6 = 0x100;
2946
2947 // from OMX_VIDEO_MPEG2PROFILETYPE
2948 public static final int MPEG2ProfileSimple = 0x00;
2949 public static final int MPEG2ProfileMain = 0x01;
2950 public static final int MPEG2Profile422 = 0x02;
2951 public static final int MPEG2ProfileSNR = 0x03;
2952 public static final int MPEG2ProfileSpatial = 0x04;
2953 public static final int MPEG2ProfileHigh = 0x05;
2954
2955 // from OMX_VIDEO_MPEG2LEVELTYPE
2956 public static final int MPEG2LevelLL = 0x00;
2957 public static final int MPEG2LevelML = 0x01;
2958 public static final int MPEG2LevelH14 = 0x02;
2959 public static final int MPEG2LevelHL = 0x03;
2960 public static final int MPEG2LevelHP = 0x04;
2961
2962 // from OMX_AUDIO_AACPROFILETYPE
2963 public static final int AACObjectMain = 1;
2964 public static final int AACObjectLC = 2;
2965 public static final int AACObjectSSR = 3;
2966 public static final int AACObjectLTP = 4;
2967 public static final int AACObjectHE = 5;
2968 public static final int AACObjectScalable = 6;
2969 public static final int AACObjectERLC = 17;
2970 public static final int AACObjectERScalable = 20;
2971 public static final int AACObjectLD = 23;
2972 public static final int AACObjectHE_PS = 29;
2973 public static final int AACObjectELD = 39;
Justin Klaassenb8042fc2018-04-15 00:41:15 -04002974 /** xHE-AAC (includes USAC) */
2975 public static final int AACObjectXHE = 42;
Justin Klaassen10d07c82017-09-15 17:58:39 -04002976
2977 // from OMX_VIDEO_VP8LEVELTYPE
2978 public static final int VP8Level_Version0 = 0x01;
2979 public static final int VP8Level_Version1 = 0x02;
2980 public static final int VP8Level_Version2 = 0x04;
2981 public static final int VP8Level_Version3 = 0x08;
2982
2983 // from OMX_VIDEO_VP8PROFILETYPE
2984 public static final int VP8ProfileMain = 0x01;
2985
2986 // from OMX_VIDEO_VP9PROFILETYPE
2987 public static final int VP9Profile0 = 0x01;
2988 public static final int VP9Profile1 = 0x02;
2989 public static final int VP9Profile2 = 0x04;
2990 public static final int VP9Profile3 = 0x08;
2991 // HDR profiles also support passing HDR metadata
2992 public static final int VP9Profile2HDR = 0x1000;
2993 public static final int VP9Profile3HDR = 0x2000;
2994
2995 // from OMX_VIDEO_VP9LEVELTYPE
2996 public static final int VP9Level1 = 0x1;
2997 public static final int VP9Level11 = 0x2;
2998 public static final int VP9Level2 = 0x4;
2999 public static final int VP9Level21 = 0x8;
3000 public static final int VP9Level3 = 0x10;
3001 public static final int VP9Level31 = 0x20;
3002 public static final int VP9Level4 = 0x40;
3003 public static final int VP9Level41 = 0x80;
3004 public static final int VP9Level5 = 0x100;
3005 public static final int VP9Level51 = 0x200;
3006 public static final int VP9Level52 = 0x400;
3007 public static final int VP9Level6 = 0x800;
3008 public static final int VP9Level61 = 0x1000;
3009 public static final int VP9Level62 = 0x2000;
3010
3011 // from OMX_VIDEO_HEVCPROFILETYPE
3012 public static final int HEVCProfileMain = 0x01;
3013 public static final int HEVCProfileMain10 = 0x02;
Justin Klaassen4d01eea2018-04-03 23:21:57 -04003014 public static final int HEVCProfileMainStill = 0x04;
Justin Klaassen10d07c82017-09-15 17:58:39 -04003015 public static final int HEVCProfileMain10HDR10 = 0x1000;
3016
3017 // from OMX_VIDEO_HEVCLEVELTYPE
3018 public static final int HEVCMainTierLevel1 = 0x1;
3019 public static final int HEVCHighTierLevel1 = 0x2;
3020 public static final int HEVCMainTierLevel2 = 0x4;
3021 public static final int HEVCHighTierLevel2 = 0x8;
3022 public static final int HEVCMainTierLevel21 = 0x10;
3023 public static final int HEVCHighTierLevel21 = 0x20;
3024 public static final int HEVCMainTierLevel3 = 0x40;
3025 public static final int HEVCHighTierLevel3 = 0x80;
3026 public static final int HEVCMainTierLevel31 = 0x100;
3027 public static final int HEVCHighTierLevel31 = 0x200;
3028 public static final int HEVCMainTierLevel4 = 0x400;
3029 public static final int HEVCHighTierLevel4 = 0x800;
3030 public static final int HEVCMainTierLevel41 = 0x1000;
3031 public static final int HEVCHighTierLevel41 = 0x2000;
3032 public static final int HEVCMainTierLevel5 = 0x4000;
3033 public static final int HEVCHighTierLevel5 = 0x8000;
3034 public static final int HEVCMainTierLevel51 = 0x10000;
3035 public static final int HEVCHighTierLevel51 = 0x20000;
3036 public static final int HEVCMainTierLevel52 = 0x40000;
3037 public static final int HEVCHighTierLevel52 = 0x80000;
3038 public static final int HEVCMainTierLevel6 = 0x100000;
3039 public static final int HEVCHighTierLevel6 = 0x200000;
3040 public static final int HEVCMainTierLevel61 = 0x400000;
3041 public static final int HEVCHighTierLevel61 = 0x800000;
3042 public static final int HEVCMainTierLevel62 = 0x1000000;
3043 public static final int HEVCHighTierLevel62 = 0x2000000;
3044
3045 private static final int HEVCHighTierLevels =
3046 HEVCHighTierLevel1 | HEVCHighTierLevel2 | HEVCHighTierLevel21 | HEVCHighTierLevel3 |
3047 HEVCHighTierLevel31 | HEVCHighTierLevel4 | HEVCHighTierLevel41 | HEVCHighTierLevel5 |
3048 HEVCHighTierLevel51 | HEVCHighTierLevel52 | HEVCHighTierLevel6 | HEVCHighTierLevel61 |
3049 HEVCHighTierLevel62;
3050
3051 // from OMX_VIDEO_DOLBYVISIONPROFILETYPE
3052 public static final int DolbyVisionProfileDvavPer = 0x1;
3053 public static final int DolbyVisionProfileDvavPen = 0x2;
3054 public static final int DolbyVisionProfileDvheDer = 0x4;
3055 public static final int DolbyVisionProfileDvheDen = 0x8;
3056 public static final int DolbyVisionProfileDvheDtr = 0x10;
3057 public static final int DolbyVisionProfileDvheStn = 0x20;
3058 public static final int DolbyVisionProfileDvheDth = 0x40;
3059 public static final int DolbyVisionProfileDvheDtb = 0x80;
3060 public static final int DolbyVisionProfileDvheSt = 0x100;
3061 public static final int DolbyVisionProfileDvavSe = 0x200;
3062
3063 // from OMX_VIDEO_DOLBYVISIONLEVELTYPE
3064 public static final int DolbyVisionLevelHd24 = 0x1;
3065 public static final int DolbyVisionLevelHd30 = 0x2;
3066 public static final int DolbyVisionLevelFhd24 = 0x4;
3067 public static final int DolbyVisionLevelFhd30 = 0x8;
3068 public static final int DolbyVisionLevelFhd60 = 0x10;
3069 public static final int DolbyVisionLevelUhd24 = 0x20;
3070 public static final int DolbyVisionLevelUhd30 = 0x40;
3071 public static final int DolbyVisionLevelUhd48 = 0x80;
3072 public static final int DolbyVisionLevelUhd60 = 0x100;
3073
3074 /**
3075 * Defined in the OpenMAX IL specs, depending on the type of media
3076 * this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE,
3077 * OMX_VIDEO_MPEG4PROFILETYPE, OMX_VIDEO_VP8PROFILETYPE or OMX_VIDEO_VP9PROFILETYPE.
3078 */
3079 public int profile;
3080
3081 /**
3082 * Defined in the OpenMAX IL specs, depending on the type of media
3083 * this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE
3084 * OMX_VIDEO_MPEG4LEVELTYPE, OMX_VIDEO_VP8LEVELTYPE or OMX_VIDEO_VP9LEVELTYPE.
3085 *
3086 * Note that VP9 decoder on platforms before {@link android.os.Build.VERSION_CODES#N} may
3087 * not advertise a profile level support. For those VP9 decoders, please use
3088 * {@link VideoCapabilities} to determine the codec capabilities.
3089 */
3090 public int level;
Justin Klaassen4d01eea2018-04-03 23:21:57 -04003091
3092 @Override
3093 public boolean equals(Object obj) {
3094 if (obj == null) {
3095 return false;
3096 }
3097 if (obj instanceof CodecProfileLevel) {
3098 CodecProfileLevel other = (CodecProfileLevel)obj;
3099 return other.profile == profile && other.level == level;
3100 }
3101 return false;
3102 }
3103
3104 @Override
3105 public int hashCode() {
3106 return Long.hashCode(((long)profile << Integer.SIZE) | level);
3107 }
Justin Klaassen10d07c82017-09-15 17:58:39 -04003108 };
3109
3110 /**
3111 * Enumerates the capabilities of the codec component. Since a single
3112 * component can support data of a variety of types, the type has to be
3113 * specified to yield a meaningful result.
3114 * @param type The MIME type to query
3115 */
3116 public final CodecCapabilities getCapabilitiesForType(
3117 String type) {
3118 CodecCapabilities caps = mCaps.get(type);
3119 if (caps == null) {
3120 throw new IllegalArgumentException("codec does not support type");
3121 }
3122 // clone writable object
3123 return caps.dup();
3124 }
3125
3126 /** @hide */
3127 public MediaCodecInfo makeRegular() {
3128 ArrayList<CodecCapabilities> caps = new ArrayList<CodecCapabilities>();
3129 for (CodecCapabilities c: mCaps.values()) {
3130 if (c.isRegular()) {
3131 caps.add(c);
3132 }
3133 }
3134 if (caps.size() == 0) {
3135 return null;
3136 } else if (caps.size() == mCaps.size()) {
3137 return this;
3138 }
3139
3140 return new MediaCodecInfo(
3141 mName, mIsEncoder,
3142 caps.toArray(new CodecCapabilities[caps.size()]));
3143 }
3144}