1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.media; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.util.Log; 22 import android.util.Pair; 23 import android.util.Range; 24 import android.util.Rational; 25 import android.util.Size; 26 27 import java.util.ArrayList; 28 import java.util.Arrays; 29 import java.util.HashMap; 30 import java.util.Map; 31 import java.util.Set; 32 33 import static android.media.Utils.intersectSortedDistinctRanges; 34 import static android.media.Utils.sortDistinctRanges; 35 36 /** 37 * Provides information about a given media codec available on the device. You can 38 * iterate through all codecs available by querying {@link MediaCodecList}. For example, 39 * here's how to find an encoder that supports a given MIME type: 40 * <pre> 41 * private static MediaCodecInfo selectCodec(String mimeType) { 42 * int numCodecs = MediaCodecList.getCodecCount(); 43 * for (int i = 0; i < 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 < types.length; j++) { 52 * if (types[j].equalsIgnoreCase(mimeType)) { 53 * return codecInfo; 54 * } 55 * } 56 * } 57 * return null; 58 * }</pre> 59 * 60 */ 61 public final class MediaCodecInfo { 62 private boolean mIsEncoder; 63 private String mName; 64 private Map<String, CodecCapabilities> mCaps; 65 MediaCodecInfo( String name, boolean isEncoder, CodecCapabilities[] caps)66 /* package private */ MediaCodecInfo( 67 String name, boolean isEncoder, CodecCapabilities[] caps) { 68 mName = name; 69 mIsEncoder = isEncoder; 70 mCaps = new HashMap<String, CodecCapabilities>(); 71 for (CodecCapabilities c: caps) { 72 mCaps.put(c.getMimeType(), c); 73 } 74 } 75 76 /** 77 * Retrieve the codec name. 78 */ getName()79 public final String getName() { 80 return mName; 81 } 82 83 /** 84 * Query if the codec is an encoder. 85 */ isEncoder()86 public final boolean isEncoder() { 87 return mIsEncoder; 88 } 89 90 /** 91 * Query the media types supported by the codec. 92 */ getSupportedTypes()93 public final String[] getSupportedTypes() { 94 Set<String> typeSet = mCaps.keySet(); 95 String[] types = typeSet.toArray(new String[typeSet.size()]); 96 Arrays.sort(types); 97 return types; 98 } 99 checkPowerOfTwo(int value, String message)100 private static int checkPowerOfTwo(int value, String message) { 101 if ((value & (value - 1)) != 0) { 102 throw new IllegalArgumentException(message); 103 } 104 return value; 105 } 106 107 private static class Feature { 108 public String mName; 109 public int mValue; 110 public boolean mDefault; Feature(String name, int value, boolean def)111 public Feature(String name, int value, boolean def) { 112 mName = name; 113 mValue = value; 114 mDefault = def; 115 } 116 } 117 118 // COMMON CONSTANTS 119 private static final Range<Integer> POSITIVE_INTEGERS = 120 Range.create(1, Integer.MAX_VALUE); 121 private static final Range<Long> POSITIVE_LONGS = 122 Range.create(1l, Long.MAX_VALUE); 123 private static final Range<Rational> POSITIVE_RATIONALS = 124 Range.create(new Rational(1, Integer.MAX_VALUE), 125 new Rational(Integer.MAX_VALUE, 1)); 126 private static final Range<Integer> SIZE_RANGE = Range.create(1, 32768); 127 private static final Range<Integer> FRAME_RATE_RANGE = Range.create(0, 960); 128 private static final Range<Integer> BITRATE_RANGE = Range.create(0, 500000000); 129 private static final int DEFAULT_MAX_SUPPORTED_INSTANCES = 32; 130 private static final int MAX_SUPPORTED_INSTANCES_LIMIT = 256; 131 132 // found stuff that is not supported by framework (=> this should not happen) 133 private static final int ERROR_UNRECOGNIZED = (1 << 0); 134 // found profile/level for which we don't have capability estimates 135 private static final int ERROR_UNSUPPORTED = (1 << 1); 136 // have not found any profile/level for which we don't have capability estimate 137 private static final int ERROR_NONE_SUPPORTED = (1 << 2); 138 139 140 /** 141 * Encapsulates the capabilities of a given codec component. 142 * For example, what profile/level combinations it supports and what colorspaces 143 * it is capable of providing the decoded data in, as well as some 144 * codec-type specific capability flags. 145 * <p>You can get an instance for a given {@link MediaCodecInfo} object with 146 * {@link MediaCodecInfo#getCapabilitiesForType getCapabilitiesForType()}, passing a MIME type. 147 */ 148 public static final class CodecCapabilities { CodecCapabilities()149 public CodecCapabilities() { 150 } 151 152 // CLASSIFICATION 153 private String mMime; 154 private int mMaxSupportedInstances; 155 156 // LEGACY FIELDS 157 158 // Enumerates supported profile/level combinations as defined 159 // by the type of encoded data. These combinations impose restrictions 160 // on video resolution, bitrate... and limit the available encoder tools 161 // such as B-frame support, arithmetic coding... 162 public CodecProfileLevel[] profileLevels; // NOTE this array is modifiable by user 163 164 // from OMX_COLOR_FORMATTYPE 165 /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */ 166 public static final int COLOR_FormatMonochrome = 1; 167 /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */ 168 public static final int COLOR_Format8bitRGB332 = 2; 169 /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */ 170 public static final int COLOR_Format12bitRGB444 = 3; 171 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 172 public static final int COLOR_Format16bitARGB4444 = 4; 173 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 174 public static final int COLOR_Format16bitARGB1555 = 5; 175 176 /** 177 * 16 bits per pixel RGB color format, with 5-bit red & blue and 6-bit green component. 178 * <p> 179 * Using 16-bit little-endian representation, colors stored as Red 15:11, Green 10:5, Blue 4:0. 180 * <pre> 181 * byte byte 182 * <--------- i --------> | <------ i + 1 ------> 183 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 184 * | BLUE | GREEN | RED | 185 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 186 * 0 4 5 7 0 2 3 7 187 * bit 188 * </pre> 189 * 190 * This format corresponds to {@link android.graphics.PixelFormat#RGB_565} and 191 * {@link android.graphics.ImageFormat#RGB_565}. 192 */ 193 public static final int COLOR_Format16bitRGB565 = 6; 194 /** @deprecated Use {@link #COLOR_Format16bitRGB565}. */ 195 public static final int COLOR_Format16bitBGR565 = 7; 196 /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */ 197 public static final int COLOR_Format18bitRGB666 = 8; 198 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 199 public static final int COLOR_Format18bitARGB1665 = 9; 200 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 201 public static final int COLOR_Format19bitARGB1666 = 10; 202 203 /** @deprecated Use {@link #COLOR_Format24bitBGR888} or {@link #COLOR_FormatRGBFlexible}. */ 204 public static final int COLOR_Format24bitRGB888 = 11; 205 206 /** 207 * 24 bits per pixel RGB color format, with 8-bit red, green & blue components. 208 * <p> 209 * Using 24-bit little-endian representation, colors stored as Red 7:0, Green 15:8, Blue 23:16. 210 * <pre> 211 * byte byte byte 212 * <------ i -----> | <---- i+1 ----> | <---- i+2 -----> 213 * +-----------------+-----------------+-----------------+ 214 * | RED | GREEN | BLUE | 215 * +-----------------+-----------------+-----------------+ 216 * </pre> 217 * 218 * This format corresponds to {@link android.graphics.PixelFormat#RGB_888}, and can also be 219 * represented as a flexible format by {@link #COLOR_FormatRGBFlexible}. 220 */ 221 public static final int COLOR_Format24bitBGR888 = 12; 222 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 223 public static final int COLOR_Format24bitARGB1887 = 13; 224 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 225 public static final int COLOR_Format25bitARGB1888 = 14; 226 227 /** 228 * @deprecated Use {@link #COLOR_Format32bitABGR8888} Or {@link #COLOR_FormatRGBAFlexible}. 229 */ 230 public static final int COLOR_Format32bitBGRA8888 = 15; 231 /** 232 * @deprecated Use {@link #COLOR_Format32bitABGR8888} Or {@link #COLOR_FormatRGBAFlexible}. 233 */ 234 public static final int COLOR_Format32bitARGB8888 = 16; 235 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 236 public static final int COLOR_FormatYUV411Planar = 17; 237 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 238 public static final int COLOR_FormatYUV411PackedPlanar = 18; 239 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 240 public static final int COLOR_FormatYUV420Planar = 19; 241 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 242 public static final int COLOR_FormatYUV420PackedPlanar = 20; 243 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 244 public static final int COLOR_FormatYUV420SemiPlanar = 21; 245 246 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 247 public static final int COLOR_FormatYUV422Planar = 22; 248 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 249 public static final int COLOR_FormatYUV422PackedPlanar = 23; 250 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 251 public static final int COLOR_FormatYUV422SemiPlanar = 24; 252 253 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 254 public static final int COLOR_FormatYCbYCr = 25; 255 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 256 public static final int COLOR_FormatYCrYCb = 26; 257 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 258 public static final int COLOR_FormatCbYCrY = 27; 259 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 260 public static final int COLOR_FormatCrYCbY = 28; 261 262 /** @deprecated Use {@link #COLOR_FormatYUV444Flexible}. */ 263 public static final int COLOR_FormatYUV444Interleaved = 29; 264 265 /** 266 * SMIA 8-bit Bayer format. 267 * Each byte represents the top 8-bits of a 10-bit signal. 268 */ 269 public static final int COLOR_FormatRawBayer8bit = 30; 270 /** 271 * SMIA 10-bit Bayer format. 272 */ 273 public static final int COLOR_FormatRawBayer10bit = 31; 274 275 /** 276 * SMIA 8-bit compressed Bayer format. 277 * Each byte represents a sample from the 10-bit signal that is compressed into 8-bits 278 * using DPCM/PCM compression, as defined by the SMIA Functional Specification. 279 */ 280 public static final int COLOR_FormatRawBayer8bitcompressed = 32; 281 282 /** @deprecated Use {@link #COLOR_FormatL8}. */ 283 public static final int COLOR_FormatL2 = 33; 284 /** @deprecated Use {@link #COLOR_FormatL8}. */ 285 public static final int COLOR_FormatL4 = 34; 286 287 /** 288 * 8 bits per pixel Y color format. 289 * <p> 290 * Each byte contains a single pixel. 291 * This format corresponds to {@link android.graphics.PixelFormat#L_8}. 292 */ 293 public static final int COLOR_FormatL8 = 35; 294 295 /** 296 * 16 bits per pixel, little-endian Y color format. 297 * <p> 298 * <pre> 299 * byte byte 300 * <--------- i --------> | <------ i + 1 ------> 301 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 302 * | Y | 303 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 304 * 0 7 0 7 305 * bit 306 * </pre> 307 */ 308 public static final int COLOR_FormatL16 = 36; 309 /** @deprecated Use {@link #COLOR_FormatL16}. */ 310 public static final int COLOR_FormatL24 = 37; 311 312 /** 313 * 32 bits per pixel, little-endian Y color format. 314 * <p> 315 * <pre> 316 * byte byte byte byte 317 * <------ i -----> | <---- i+1 ----> | <---- i+2 ----> | <---- i+3 -----> 318 * +-----------------+-----------------+-----------------+-----------------+ 319 * | Y | 320 * +-----------------+-----------------+-----------------+-----------------+ 321 * 0 7 0 7 0 7 0 7 322 * bit 323 * </pre> 324 * 325 * @deprecated Use {@link #COLOR_FormatL16}. 326 */ 327 public static final int COLOR_FormatL32 = 38; 328 329 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 330 public static final int COLOR_FormatYUV420PackedSemiPlanar = 39; 331 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 332 public static final int COLOR_FormatYUV422PackedSemiPlanar = 40; 333 334 /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */ 335 public static final int COLOR_Format18BitBGR666 = 41; 336 337 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 338 public static final int COLOR_Format24BitARGB6666 = 42; 339 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 340 public static final int COLOR_Format24BitABGR6666 = 43; 341 342 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 343 public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100; 344 // COLOR_FormatSurface indicates that the data will be a GraphicBuffer metadata reference. 345 // In OMX this is called OMX_COLOR_FormatAndroidOpaque. 346 public static final int COLOR_FormatSurface = 0x7F000789; 347 348 /** 349 * 32 bits per pixel RGBA color format, with 8-bit red, green, blue, and alpha components. 350 * <p> 351 * Using 32-bit little-endian representation, colors stored as Red 7:0, Green 15:8, 352 * Blue 23:16, and Alpha 31:24. 353 * <pre> 354 * byte byte byte byte 355 * <------ i -----> | <---- i+1 ----> | <---- i+2 ----> | <---- i+3 -----> 356 * +-----------------+-----------------+-----------------+-----------------+ 357 * | RED | GREEN | BLUE | ALPHA | 358 * +-----------------+-----------------+-----------------+-----------------+ 359 * </pre> 360 * 361 * This corresponds to {@link android.graphics.PixelFormat#RGBA_8888}. 362 */ 363 public static final int COLOR_Format32bitABGR8888 = 0x7F00A000; 364 365 /** 366 * Flexible 12 bits per pixel, subsampled YUV color format with 8-bit chroma and luma 367 * components. 368 * <p> 369 * Chroma planes are subsampled by 2 both horizontally and vertically. 370 * Use this format with {@link Image}. 371 * This format corresponds to {@link android.graphics.ImageFormat#YUV_420_888}, 372 * and can represent the {@link #COLOR_FormatYUV411Planar}, 373 * {@link #COLOR_FormatYUV411PackedPlanar}, {@link #COLOR_FormatYUV420Planar}, 374 * {@link #COLOR_FormatYUV420PackedPlanar}, {@link #COLOR_FormatYUV420SemiPlanar} 375 * and {@link #COLOR_FormatYUV420PackedSemiPlanar} formats. 376 * 377 * @see Image#getFormat 378 */ 379 public static final int COLOR_FormatYUV420Flexible = 0x7F420888; 380 381 /** 382 * Flexible 16 bits per pixel, subsampled YUV color format with 8-bit chroma and luma 383 * components. 384 * <p> 385 * Chroma planes are horizontally subsampled by 2. Use this format with {@link Image}. 386 * This format corresponds to {@link android.graphics.ImageFormat#YUV_422_888}, 387 * and can represent the {@link #COLOR_FormatYCbYCr}, {@link #COLOR_FormatYCrYCb}, 388 * {@link #COLOR_FormatCbYCrY}, {@link #COLOR_FormatCrYCbY}, 389 * {@link #COLOR_FormatYUV422Planar}, {@link #COLOR_FormatYUV422PackedPlanar}, 390 * {@link #COLOR_FormatYUV422SemiPlanar} and {@link #COLOR_FormatYUV422PackedSemiPlanar} 391 * formats. 392 * 393 * @see Image#getFormat 394 */ 395 public static final int COLOR_FormatYUV422Flexible = 0x7F422888; 396 397 /** 398 * Flexible 24 bits per pixel YUV color format with 8-bit chroma and luma 399 * components. 400 * <p> 401 * Chroma planes are not subsampled. Use this format with {@link Image}. 402 * This format corresponds to {@link android.graphics.ImageFormat#YUV_444_888}, 403 * and can represent the {@link #COLOR_FormatYUV444Interleaved} format. 404 * @see Image#getFormat 405 */ 406 public static final int COLOR_FormatYUV444Flexible = 0x7F444888; 407 408 /** 409 * Flexible 24 bits per pixel RGB color format with 8-bit red, green and blue 410 * components. 411 * <p> 412 * Use this format with {@link Image}. This format corresponds to 413 * {@link android.graphics.ImageFormat#FLEX_RGB_888}, and can represent 414 * {@link #COLOR_Format24bitBGR888} and {@link #COLOR_Format24bitRGB888} formats. 415 * @see Image#getFormat. 416 */ 417 public static final int COLOR_FormatRGBFlexible = 0x7F36B888; 418 419 /** 420 * Flexible 32 bits per pixel RGBA color format with 8-bit red, green, blue, and alpha 421 * components. 422 * <p> 423 * Use this format with {@link Image}. This format corresponds to 424 * {@link android.graphics.ImageFormat#FLEX_RGBA_8888}, and can represent 425 * {@link #COLOR_Format32bitBGRA8888}, {@link #COLOR_Format32bitABGR8888} and 426 * {@link #COLOR_Format32bitARGB8888} formats. 427 * 428 * @see Image#getFormat 429 */ 430 public static final int COLOR_FormatRGBAFlexible = 0x7F36A888; 431 432 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 433 public static final int COLOR_QCOM_FormatYUV420SemiPlanar = 0x7fa30c00; 434 435 /** 436 * Defined in the OpenMAX IL specs, color format values are drawn from 437 * OMX_COLOR_FORMATTYPE. 438 */ 439 public int[] colorFormats; // NOTE this array is modifiable by user 440 441 // FEATURES 442 443 private int mFlagsSupported; 444 private int mFlagsRequired; 445 private int mFlagsVerified; 446 447 /** 448 * <b>video decoder only</b>: codec supports seamless resolution changes. 449 */ 450 public static final String FEATURE_AdaptivePlayback = "adaptive-playback"; 451 452 /** 453 * <b>video decoder only</b>: codec supports secure decryption. 454 */ 455 public static final String FEATURE_SecurePlayback = "secure-playback"; 456 457 /** 458 * <b>video or audio decoder only</b>: codec supports tunneled playback. 459 */ 460 public static final String FEATURE_TunneledPlayback = "tunneled-playback"; 461 462 /** 463 * <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 */ isFeatureSupported(String name)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 */ isFeatureRequired(String name)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 */ validFeatures()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 getValidFeatures()514 private Feature[] getValidFeatures() { 515 if (!isEncoder()) { 516 return decoderFeatures; 517 } 518 return encoderFeatures; 519 } 520 checkFeature(String name, int flags)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 */ isRegular()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 */ isFormatSupported(MediaFormat format)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 supportsBitrate( Range<Integer> bitrateRange, MediaFormat format)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 supportsProfileLevel(int profile, Integer level)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 */ getDefaultFormat()774 public MediaFormat getDefaultFormat() { 775 return mDefaultFormat; 776 } 777 778 /** 779 * Returns the mime type for which this codec-capability object was created. 780 */ getMimeType()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 */ getMaxSupportedInstances()793 public int getMaxSupportedInstances() { 794 return mMaxSupportedInstances; 795 } 796 isAudio()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 */ getAudioCapabilities()804 public AudioCapabilities getAudioCapabilities() { 805 return mAudioCaps; 806 } 807 isEncoder()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 */ getEncoderCapabilities()815 public EncoderCapabilities getEncoderCapabilities() { 816 return mEncoderCaps; 817 } 818 isVideo()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 */ getVideoCapabilities()826 public VideoCapabilities getVideoCapabilities() { 827 return mVideoCaps; 828 } 829 830 /** @hide */ dup()831 public CodecCapabilities dup() { 832 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; 850 } 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 */ createFromProfileLevel( String mime, int profile, int level)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 CodecCapabilities( CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags, Map<String, Object>defaultFormatMap, Map<String, Object>capabilitiesMap)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 CodecCapabilities( CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags, MediaFormat defaultFormat, MediaFormat info)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); 911 mAudioCaps.getDefaultFormat(mDefaultFormat); 912 } else if (mMime.toLowerCase().startsWith("video/") 913 || mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC)) { 914 mVideoCaps = VideoCapabilities.create(info, this); 915 } 916 if (encoder) { 917 mEncoderCaps = EncoderCapabilities.create(info, this); 918 mEncoderCaps.getDefaultFormat(mDefaultFormat); 919 } 920 921 final Map<String, Object> global = MediaCodecList.getGlobalSettings(); 922 mMaxSupportedInstances = Utils.parseIntSafely( 923 global.get("max-concurrent-instances"), DEFAULT_MAX_SUPPORTED_INSTANCES); 924 925 int maxInstances = Utils.parseIntSafely( 926 map.get("max-concurrent-instances"), mMaxSupportedInstances); 927 mMaxSupportedInstances = 928 Range.create(1, MAX_SUPPORTED_INSTANCES_LIMIT).clamp(maxInstances); 929 930 for (Feature feat: getValidFeatures()) { 931 String key = MediaFormat.KEY_FEATURE_ + feat.mName; 932 Integer yesNo = (Integer)map.get(key); 933 if (yesNo == null) { 934 continue; 935 } 936 if (yesNo > 0) { 937 mFlagsRequired |= feat.mValue; 938 } 939 mFlagsSupported |= feat.mValue; 940 mDefaultFormat.setInteger(key, 1); 941 // TODO restrict features by mFlagsVerified once all codecs reliably verify them 942 } 943 } 944 } 945 946 /** 947 * A class that supports querying the audio capabilities of a codec. 948 */ 949 public static final class AudioCapabilities { 950 private static final String TAG = "AudioCapabilities"; 951 private CodecCapabilities mParent; 952 private Range<Integer> mBitrateRange; 953 954 private int[] mSampleRates; 955 private Range<Integer>[] mSampleRateRanges; 956 private int mMaxInputChannelCount; 957 958 private static final int MAX_INPUT_CHANNEL_COUNT = 30; 959 960 /** 961 * Returns the range of supported bitrates in bits/second. 962 */ getBitrateRange()963 public Range<Integer> getBitrateRange() { 964 return mBitrateRange; 965 } 966 967 /** 968 * Returns the array of supported sample rates if the codec 969 * supports only discrete values. Otherwise, it returns 970 * {@code null}. The array is sorted in ascending order. 971 */ getSupportedSampleRates()972 public int[] getSupportedSampleRates() { 973 return Arrays.copyOf(mSampleRates, mSampleRates.length); 974 } 975 976 /** 977 * Returns the array of supported sample rate ranges. The 978 * array is sorted in ascending order, and the ranges are 979 * distinct. 980 */ getSupportedSampleRateRanges()981 public Range<Integer>[] getSupportedSampleRateRanges() { 982 return Arrays.copyOf(mSampleRateRanges, mSampleRateRanges.length); 983 } 984 985 /** 986 * Returns the maximum number of input channels supported. The codec 987 * supports any number of channels between 1 and this maximum value. 988 */ getMaxInputChannelCount()989 public int getMaxInputChannelCount() { 990 return mMaxInputChannelCount; 991 } 992 993 /* no public constructor */ AudioCapabilities()994 private AudioCapabilities() { } 995 996 /** @hide */ create( MediaFormat info, CodecCapabilities parent)997 public static AudioCapabilities create( 998 MediaFormat info, CodecCapabilities parent) { 999 AudioCapabilities caps = new AudioCapabilities(); 1000 caps.init(info, parent); 1001 return caps; 1002 } 1003 init(MediaFormat info, CodecCapabilities parent)1004 private void init(MediaFormat info, CodecCapabilities parent) { 1005 mParent = parent; 1006 initWithPlatformLimits(); 1007 applyLevelLimits(); 1008 parseFromInfo(info); 1009 } 1010 initWithPlatformLimits()1011 private void initWithPlatformLimits() { 1012 mBitrateRange = Range.create(0, Integer.MAX_VALUE); 1013 mMaxInputChannelCount = MAX_INPUT_CHANNEL_COUNT; 1014 // mBitrateRange = Range.create(1, 320000); 1015 mSampleRateRanges = new Range[] { Range.create(8000, 96000) }; 1016 mSampleRates = null; 1017 } 1018 supports(Integer sampleRate, Integer inputChannels)1019 private boolean supports(Integer sampleRate, Integer inputChannels) { 1020 // channels and sample rates are checked orthogonally 1021 if (inputChannels != null && 1022 (inputChannels < 1 || inputChannels > mMaxInputChannelCount)) { 1023 return false; 1024 } 1025 if (sampleRate != null) { 1026 int ix = Utils.binarySearchDistinctRanges( 1027 mSampleRateRanges, sampleRate); 1028 if (ix < 0) { 1029 return false; 1030 } 1031 } 1032 return true; 1033 } 1034 1035 /** 1036 * Query whether the sample rate is supported by the codec. 1037 */ isSampleRateSupported(int sampleRate)1038 public boolean isSampleRateSupported(int sampleRate) { 1039 return supports(sampleRate, null); 1040 } 1041 1042 /** modifies rates */ limitSampleRates(int[] rates)1043 private void limitSampleRates(int[] rates) { 1044 Arrays.sort(rates); 1045 ArrayList<Range<Integer>> ranges = new ArrayList<Range<Integer>>(); 1046 for (int rate: rates) { 1047 if (supports(rate, null /* channels */)) { 1048 ranges.add(Range.create(rate, rate)); 1049 } 1050 } 1051 mSampleRateRanges = ranges.toArray(new Range[ranges.size()]); 1052 createDiscreteSampleRates(); 1053 } 1054 createDiscreteSampleRates()1055 private void createDiscreteSampleRates() { 1056 mSampleRates = new int[mSampleRateRanges.length]; 1057 for (int i = 0; i < mSampleRateRanges.length; i++) { 1058 mSampleRates[i] = mSampleRateRanges[i].getLower(); 1059 } 1060 } 1061 1062 /** modifies rateRanges */ limitSampleRates(Range<Integer>[] rateRanges)1063 private void limitSampleRates(Range<Integer>[] rateRanges) { 1064 sortDistinctRanges(rateRanges); 1065 mSampleRateRanges = intersectSortedDistinctRanges(mSampleRateRanges, rateRanges); 1066 1067 // check if all values are discrete 1068 for (Range<Integer> range: mSampleRateRanges) { 1069 if (!range.getLower().equals(range.getUpper())) { 1070 mSampleRates = null; 1071 return; 1072 } 1073 } 1074 createDiscreteSampleRates(); 1075 } 1076 applyLevelLimits()1077 private void applyLevelLimits() { 1078 int[] sampleRates = null; 1079 Range<Integer> sampleRateRange = null, bitRates = null; 1080 int maxChannels = MAX_INPUT_CHANNEL_COUNT; 1081 String mime = mParent.getMimeType(); 1082 1083 if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MPEG)) { 1084 sampleRates = new int[] { 1085 8000, 11025, 12000, 1086 16000, 22050, 24000, 1087 32000, 44100, 48000 }; 1088 bitRates = Range.create(8000, 320000); 1089 maxChannels = 2; 1090 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)) { 1091 sampleRates = new int[] { 8000 }; 1092 bitRates = Range.create(4750, 12200); 1093 maxChannels = 1; 1094 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)) { 1095 sampleRates = new int[] { 16000 }; 1096 bitRates = Range.create(6600, 23850); 1097 maxChannels = 1; 1098 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC)) { 1099 sampleRates = new int[] { 1100 7350, 8000, 1101 11025, 12000, 16000, 1102 22050, 24000, 32000, 1103 44100, 48000, 64000, 1104 88200, 96000 }; 1105 bitRates = Range.create(8000, 510000); 1106 maxChannels = 48; 1107 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_VORBIS)) { 1108 bitRates = Range.create(32000, 500000); 1109 sampleRateRange = Range.create(8000, 192000); 1110 maxChannels = 255; 1111 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_OPUS)) { 1112 bitRates = Range.create(6000, 510000); 1113 sampleRates = new int[] { 8000, 12000, 16000, 24000, 48000 }; 1114 maxChannels = 255; 1115 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW)) { 1116 sampleRateRange = Range.create(1, 96000); 1117 bitRates = Range.create(1, 10000000); 1118 maxChannels = AudioTrack.CHANNEL_COUNT_MAX; 1119 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) { 1120 sampleRateRange = Range.create(1, 655350); 1121 // lossless codec, so bitrate is ignored 1122 maxChannels = 255; 1123 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW) 1124 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)) { 1125 sampleRates = new int[] { 8000 }; 1126 bitRates = Range.create(64000, 64000); 1127 // platform allows multiple channels for this format 1128 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) { 1129 sampleRates = new int[] { 8000 }; 1130 bitRates = Range.create(13000, 13000); 1131 maxChannels = 1; 1132 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AC3)) { 1133 maxChannels = 6; 1134 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_EAC3)) { 1135 maxChannels = 16; 1136 } else { 1137 Log.w(TAG, "Unsupported mime " + mime); 1138 mParent.mError |= ERROR_UNSUPPORTED; 1139 } 1140 1141 // restrict ranges 1142 if (sampleRates != null) { 1143 limitSampleRates(sampleRates); 1144 } else if (sampleRateRange != null) { 1145 limitSampleRates(new Range[] { sampleRateRange }); 1146 } 1147 applyLimits(maxChannels, bitRates); 1148 } 1149 applyLimits(int maxInputChannels, Range<Integer> bitRates)1150 private void applyLimits(int maxInputChannels, Range<Integer> bitRates) { 1151 mMaxInputChannelCount = Range.create(1, mMaxInputChannelCount) 1152 .clamp(maxInputChannels); 1153 if (bitRates != null) { 1154 mBitrateRange = mBitrateRange.intersect(bitRates); 1155 } 1156 } 1157 parseFromInfo(MediaFormat info)1158 private void parseFromInfo(MediaFormat info) { 1159 int maxInputChannels = MAX_INPUT_CHANNEL_COUNT; 1160 Range<Integer> bitRates = POSITIVE_INTEGERS; 1161 1162 if (info.containsKey("sample-rate-ranges")) { 1163 String[] rateStrings = info.getString("sample-rate-ranges").split(","); 1164 Range<Integer>[] rateRanges = new Range[rateStrings.length]; 1165 for (int i = 0; i < rateStrings.length; i++) { 1166 rateRanges[i] = Utils.parseIntRange(rateStrings[i], null); 1167 } 1168 limitSampleRates(rateRanges); 1169 } 1170 if (info.containsKey("max-channel-count")) { 1171 maxInputChannels = Utils.parseIntSafely( 1172 info.getString("max-channel-count"), maxInputChannels); 1173 } else if ((mParent.mError & ERROR_UNSUPPORTED) != 0) { 1174 maxInputChannels = 0; 1175 } 1176 if (info.containsKey("bitrate-range")) { 1177 bitRates = bitRates.intersect( 1178 Utils.parseIntRange(info.getString("bitrate-range"), bitRates)); 1179 } 1180 applyLimits(maxInputChannels, bitRates); 1181 } 1182 1183 /** @hide */ getDefaultFormat(MediaFormat format)1184 public void getDefaultFormat(MediaFormat format) { 1185 // report settings that have only a single choice 1186 if (mBitrateRange.getLower().equals(mBitrateRange.getUpper())) { 1187 format.setInteger(MediaFormat.KEY_BIT_RATE, mBitrateRange.getLower()); 1188 } 1189 if (mMaxInputChannelCount == 1) { 1190 // mono-only format 1191 format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); 1192 } 1193 if (mSampleRates != null && mSampleRates.length == 1) { 1194 format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRates[0]); 1195 } 1196 } 1197 1198 /** @hide */ supportsFormat(MediaFormat format)1199 public boolean supportsFormat(MediaFormat format) { 1200 Map<String, Object> map = format.getMap(); 1201 Integer sampleRate = (Integer)map.get(MediaFormat.KEY_SAMPLE_RATE); 1202 Integer channels = (Integer)map.get(MediaFormat.KEY_CHANNEL_COUNT); 1203 1204 if (!supports(sampleRate, channels)) { 1205 return false; 1206 } 1207 1208 if (!CodecCapabilities.supportsBitrate(mBitrateRange, format)) { 1209 return false; 1210 } 1211 1212 // nothing to do for: 1213 // KEY_CHANNEL_MASK: codecs don't get this 1214 // KEY_IS_ADTS: required feature for all AAC decoders 1215 return true; 1216 } 1217 } 1218 1219 /** 1220 * A class that supports querying the video capabilities of a codec. 1221 */ 1222 public static final class VideoCapabilities { 1223 private static final String TAG = "VideoCapabilities"; 1224 private CodecCapabilities mParent; 1225 private Range<Integer> mBitrateRange; 1226 1227 private Range<Integer> mHeightRange; 1228 private Range<Integer> mWidthRange; 1229 private Range<Integer> mBlockCountRange; 1230 private Range<Integer> mHorizontalBlockRange; 1231 private Range<Integer> mVerticalBlockRange; 1232 private Range<Rational> mAspectRatioRange; 1233 private Range<Rational> mBlockAspectRatioRange; 1234 private Range<Long> mBlocksPerSecondRange; 1235 private Map<Size, Range<Long>> mMeasuredFrameRates; 1236 private Range<Integer> mFrameRateRange; 1237 1238 private int mBlockWidth; 1239 private int mBlockHeight; 1240 private int mWidthAlignment; 1241 private int mHeightAlignment; 1242 private int mSmallerDimensionUpperLimit; 1243 1244 private boolean mAllowMbOverride; // allow XML to override calculated limits 1245 1246 /** 1247 * Returns the range of supported bitrates in bits/second. 1248 */ getBitrateRange()1249 public Range<Integer> getBitrateRange() { 1250 return mBitrateRange; 1251 } 1252 1253 /** 1254 * Returns the range of supported video widths. 1255 */ getSupportedWidths()1256 public Range<Integer> getSupportedWidths() { 1257 return mWidthRange; 1258 } 1259 1260 /** 1261 * Returns the range of supported video heights. 1262 */ getSupportedHeights()1263 public Range<Integer> getSupportedHeights() { 1264 return mHeightRange; 1265 } 1266 1267 /** 1268 * Returns the alignment requirement for video width (in pixels). 1269 * 1270 * This is a power-of-2 value that video width must be a 1271 * multiple of. 1272 */ getWidthAlignment()1273 public int getWidthAlignment() { 1274 return mWidthAlignment; 1275 } 1276 1277 /** 1278 * Returns the alignment requirement for video height (in pixels). 1279 * 1280 * This is a power-of-2 value that video height must be a 1281 * multiple of. 1282 */ getHeightAlignment()1283 public int getHeightAlignment() { 1284 return mHeightAlignment; 1285 } 1286 1287 /** 1288 * Return the upper limit on the smaller dimension of width or height. 1289 * <p></p> 1290 * Some codecs have a limit on the smaller dimension, whether it be 1291 * the width or the height. E.g. a codec may only be able to handle 1292 * up to 1920x1080 both in landscape and portrait mode (1080x1920). 1293 * In this case the maximum width and height are both 1920, but the 1294 * smaller dimension limit will be 1080. For other codecs, this is 1295 * {@code Math.min(getSupportedWidths().getUpper(), 1296 * getSupportedHeights().getUpper())}. 1297 * 1298 * @hide 1299 */ getSmallerDimensionUpperLimit()1300 public int getSmallerDimensionUpperLimit() { 1301 return mSmallerDimensionUpperLimit; 1302 } 1303 1304 /** 1305 * Returns the range of supported frame rates. 1306 * <p> 1307 * This is not a performance indicator. Rather, it expresses the 1308 * limits specified in the coding standard, based on the complexities 1309 * of encoding material for later playback at a certain frame rate, 1310 * or the decoding of such material in non-realtime. 1311 */ getSupportedFrameRates()1312 public Range<Integer> getSupportedFrameRates() { 1313 return mFrameRateRange; 1314 } 1315 1316 /** 1317 * Returns the range of supported video widths for a video height. 1318 * @param height the height of the video 1319 */ getSupportedWidthsFor(int height)1320 public Range<Integer> getSupportedWidthsFor(int height) { 1321 try { 1322 Range<Integer> range = mWidthRange; 1323 if (!mHeightRange.contains(height) 1324 || (height % mHeightAlignment) != 0) { 1325 throw new IllegalArgumentException("unsupported height"); 1326 } 1327 final int heightInBlocks = Utils.divUp(height, mBlockHeight); 1328 1329 // constrain by block count and by block aspect ratio 1330 final int minWidthInBlocks = Math.max( 1331 Utils.divUp(mBlockCountRange.getLower(), heightInBlocks), 1332 (int)Math.ceil(mBlockAspectRatioRange.getLower().doubleValue() 1333 * heightInBlocks)); 1334 final int maxWidthInBlocks = Math.min( 1335 mBlockCountRange.getUpper() / heightInBlocks, 1336 (int)(mBlockAspectRatioRange.getUpper().doubleValue() 1337 * heightInBlocks)); 1338 range = range.intersect( 1339 (minWidthInBlocks - 1) * mBlockWidth + mWidthAlignment, 1340 maxWidthInBlocks * mBlockWidth); 1341 1342 // constrain by smaller dimension limit 1343 if (height > mSmallerDimensionUpperLimit) { 1344 range = range.intersect(1, mSmallerDimensionUpperLimit); 1345 } 1346 1347 // constrain by aspect ratio 1348 range = range.intersect( 1349 (int)Math.ceil(mAspectRatioRange.getLower().doubleValue() 1350 * height), 1351 (int)(mAspectRatioRange.getUpper().doubleValue() * height)); 1352 return range; 1353 } catch (IllegalArgumentException e) { 1354 // height is not supported because there are no suitable widths 1355 Log.v(TAG, "could not get supported widths for " + height); 1356 throw new IllegalArgumentException("unsupported height"); 1357 } 1358 } 1359 1360 /** 1361 * Returns the range of supported video heights for a video width 1362 * @param width the width of the video 1363 */ getSupportedHeightsFor(int width)1364 public Range<Integer> getSupportedHeightsFor(int width) { 1365 try { 1366 Range<Integer> range = mHeightRange; 1367 if (!mWidthRange.contains(width) 1368 || (width % mWidthAlignment) != 0) { 1369 throw new IllegalArgumentException("unsupported width"); 1370 } 1371 final int widthInBlocks = Utils.divUp(width, mBlockWidth); 1372 1373 // constrain by block count and by block aspect ratio 1374 final int minHeightInBlocks = Math.max( 1375 Utils.divUp(mBlockCountRange.getLower(), widthInBlocks), 1376 (int)Math.ceil(widthInBlocks / 1377 mBlockAspectRatioRange.getUpper().doubleValue())); 1378 final int maxHeightInBlocks = Math.min( 1379 mBlockCountRange.getUpper() / widthInBlocks, 1380 (int)(widthInBlocks / 1381 mBlockAspectRatioRange.getLower().doubleValue())); 1382 range = range.intersect( 1383 (minHeightInBlocks - 1) * mBlockHeight + mHeightAlignment, 1384 maxHeightInBlocks * mBlockHeight); 1385 1386 // constrain by smaller dimension limit 1387 if (width > mSmallerDimensionUpperLimit) { 1388 range = range.intersect(1, mSmallerDimensionUpperLimit); 1389 } 1390 1391 // constrain by aspect ratio 1392 range = range.intersect( 1393 (int)Math.ceil(width / 1394 mAspectRatioRange.getUpper().doubleValue()), 1395 (int)(width / mAspectRatioRange.getLower().doubleValue())); 1396 return range; 1397 } catch (IllegalArgumentException e) { 1398 // width is not supported because there are no suitable heights 1399 Log.v(TAG, "could not get supported heights for " + width); 1400 throw new IllegalArgumentException("unsupported width"); 1401 } 1402 } 1403 1404 /** 1405 * Returns the range of supported video frame rates for a video size. 1406 * <p> 1407 * This is not a performance indicator. Rather, it expresses the limits specified in 1408 * the coding standard, based on the complexities of encoding material of a given 1409 * size for later playback at a certain frame rate, or the decoding of such material 1410 * in non-realtime. 1411 1412 * @param width the width of the video 1413 * @param height the height of the video 1414 */ getSupportedFrameRatesFor(int width, int height)1415 public Range<Double> getSupportedFrameRatesFor(int width, int height) { 1416 Range<Integer> range = mHeightRange; 1417 if (!supports(width, height, null)) { 1418 throw new IllegalArgumentException("unsupported size"); 1419 } 1420 final int blockCount = 1421 Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight); 1422 1423 return Range.create( 1424 Math.max(mBlocksPerSecondRange.getLower() / (double) blockCount, 1425 (double) mFrameRateRange.getLower()), 1426 Math.min(mBlocksPerSecondRange.getUpper() / (double) blockCount, 1427 (double) mFrameRateRange.getUpper())); 1428 } 1429 getBlockCount(int width, int height)1430 private int getBlockCount(int width, int height) { 1431 return Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight); 1432 } 1433 1434 @NonNull findClosestSize(int width, int height)1435 private Size findClosestSize(int width, int height) { 1436 int targetBlockCount = getBlockCount(width, height); 1437 Size closestSize = null; 1438 int minDiff = Integer.MAX_VALUE; 1439 for (Size size : mMeasuredFrameRates.keySet()) { 1440 int diff = Math.abs(targetBlockCount - 1441 getBlockCount(size.getWidth(), size.getHeight())); 1442 if (diff < minDiff) { 1443 minDiff = diff; 1444 closestSize = size; 1445 } 1446 } 1447 return closestSize; 1448 } 1449 estimateFrameRatesFor(int width, int height)1450 private Range<Double> estimateFrameRatesFor(int width, int height) { 1451 Size size = findClosestSize(width, height); 1452 Range<Long> range = mMeasuredFrameRates.get(size); 1453 Double ratio = getBlockCount(size.getWidth(), size.getHeight()) 1454 / (double)Math.max(getBlockCount(width, height), 1); 1455 return Range.create(range.getLower() * ratio, range.getUpper() * ratio); 1456 } 1457 1458 /** 1459 * Returns the range of achievable video frame rates for a video size. 1460 * May return {@code null}, if the codec did not publish any measurement 1461 * data. 1462 * <p> 1463 * This is a performance estimate provided by the device manufacturer based on statistical 1464 * sampling of full-speed decoding and encoding measurements in various configurations 1465 * of common video sizes supported by the codec. As such it should only be used to 1466 * compare individual codecs on the device. The value is not suitable for comparing 1467 * different devices or even different android releases for the same device. 1468 * <p> 1469 * <em>On {@link android.os.Build.VERSION_CODES#M} release</em> the returned range 1470 * corresponds to the fastest frame rates achieved in the tested configurations. As 1471 * such, it should not be used to gauge guaranteed or even average codec performance 1472 * on the device. 1473 * <p> 1474 * <em>On {@link android.os.Build.VERSION_CODES#N} release</em> the returned range 1475 * corresponds closer to sustained performance <em>in tested configurations</em>. 1476 * One can expect to achieve sustained performance higher than the lower limit more than 1477 * 50% of the time, and higher than half of the lower limit at least 90% of the time 1478 * <em>in tested configurations</em>. 1479 * Conversely, one can expect performance lower than twice the upper limit at least 1480 * 90% of the time. 1481 * <p class=note> 1482 * Tested configurations use a single active codec. For use cases where multiple 1483 * codecs are active, applications can expect lower and in most cases significantly lower 1484 * performance. 1485 * <p class=note> 1486 * The returned range value is interpolated from the nearest frame size(s) tested. 1487 * Codec performance is severely impacted by other activity on the device as well 1488 * as environmental factors (such as battery level, temperature or power source), and can 1489 * vary significantly even in a steady environment. 1490 * <p class=note> 1491 * Use this method in cases where only codec performance matters, e.g. to evaluate if 1492 * a codec has any chance of meeting a performance target. Codecs are listed 1493 * in {@link MediaCodecList} in the preferred order as defined by the device 1494 * manufacturer. As such, applications should use the first suitable codec in the 1495 * list to achieve the best balance between power use and performance. 1496 * 1497 * @param width the width of the video 1498 * @param height the height of the video 1499 * 1500 * @throws IllegalArgumentException if the video size is not supported. 1501 */ 1502 @Nullable getAchievableFrameRatesFor(int width, int height)1503 public Range<Double> getAchievableFrameRatesFor(int width, int height) { 1504 if (!supports(width, height, null)) { 1505 throw new IllegalArgumentException("unsupported size"); 1506 } 1507 1508 if (mMeasuredFrameRates == null || mMeasuredFrameRates.size() <= 0) { 1509 Log.w(TAG, "Codec did not publish any measurement data."); 1510 return null; 1511 } 1512 1513 return estimateFrameRatesFor(width, height); 1514 } 1515 1516 /** 1517 * Returns whether a given video size ({@code width} and 1518 * {@code height}) and {@code frameRate} combination is supported. 1519 */ areSizeAndRateSupported( int width, int height, double frameRate)1520 public boolean areSizeAndRateSupported( 1521 int width, int height, double frameRate) { 1522 return supports(width, height, frameRate); 1523 } 1524 1525 /** 1526 * Returns whether a given video size ({@code width} and 1527 * {@code height}) is supported. 1528 */ isSizeSupported(int width, int height)1529 public boolean isSizeSupported(int width, int height) { 1530 return supports(width, height, null); 1531 } 1532 supports(Integer width, Integer height, Number rate)1533 private boolean supports(Integer width, Integer height, Number rate) { 1534 boolean ok = true; 1535 1536 if (ok && width != null) { 1537 ok = mWidthRange.contains(width) 1538 && (width % mWidthAlignment == 0); 1539 } 1540 if (ok && height != null) { 1541 ok = mHeightRange.contains(height) 1542 && (height % mHeightAlignment == 0); 1543 } 1544 if (ok && rate != null) { 1545 ok = mFrameRateRange.contains(Utils.intRangeFor(rate.doubleValue())); 1546 } 1547 if (ok && height != null && width != null) { 1548 ok = Math.min(height, width) <= mSmallerDimensionUpperLimit; 1549 1550 final int widthInBlocks = Utils.divUp(width, mBlockWidth); 1551 final int heightInBlocks = Utils.divUp(height, mBlockHeight); 1552 final int blockCount = widthInBlocks * heightInBlocks; 1553 ok = ok && mBlockCountRange.contains(blockCount) 1554 && mBlockAspectRatioRange.contains( 1555 new Rational(widthInBlocks, heightInBlocks)) 1556 && mAspectRatioRange.contains(new Rational(width, height)); 1557 if (ok && rate != null) { 1558 double blocksPerSec = blockCount * rate.doubleValue(); 1559 ok = mBlocksPerSecondRange.contains( 1560 Utils.longRangeFor(blocksPerSec)); 1561 } 1562 } 1563 return ok; 1564 } 1565 1566 /** 1567 * @hide 1568 * @throws java.lang.ClassCastException */ supportsFormat(MediaFormat format)1569 public boolean supportsFormat(MediaFormat format) { 1570 final Map<String, Object> map = format.getMap(); 1571 Integer width = (Integer)map.get(MediaFormat.KEY_WIDTH); 1572 Integer height = (Integer)map.get(MediaFormat.KEY_HEIGHT); 1573 Number rate = (Number)map.get(MediaFormat.KEY_FRAME_RATE); 1574 1575 if (!supports(width, height, rate)) { 1576 return false; 1577 } 1578 1579 if (!CodecCapabilities.supportsBitrate(mBitrateRange, format)) { 1580 return false; 1581 } 1582 1583 // we ignore color-format for now as it is not reliably reported by codec 1584 return true; 1585 } 1586 1587 /* no public constructor */ VideoCapabilities()1588 private VideoCapabilities() { } 1589 1590 /** @hide */ create( MediaFormat info, CodecCapabilities parent)1591 public static VideoCapabilities create( 1592 MediaFormat info, CodecCapabilities parent) { 1593 VideoCapabilities caps = new VideoCapabilities(); 1594 caps.init(info, parent); 1595 return caps; 1596 } 1597 init(MediaFormat info, CodecCapabilities parent)1598 private void init(MediaFormat info, CodecCapabilities parent) { 1599 mParent = parent; 1600 initWithPlatformLimits(); 1601 applyLevelLimits(); 1602 parseFromInfo(info); 1603 updateLimits(); 1604 } 1605 1606 /** @hide */ getBlockSize()1607 public Size getBlockSize() { 1608 return new Size(mBlockWidth, mBlockHeight); 1609 } 1610 1611 /** @hide */ getBlockCountRange()1612 public Range<Integer> getBlockCountRange() { 1613 return mBlockCountRange; 1614 } 1615 1616 /** @hide */ getBlocksPerSecondRange()1617 public Range<Long> getBlocksPerSecondRange() { 1618 return mBlocksPerSecondRange; 1619 } 1620 1621 /** @hide */ getAspectRatioRange(boolean blocks)1622 public Range<Rational> getAspectRatioRange(boolean blocks) { 1623 return blocks ? mBlockAspectRatioRange : mAspectRatioRange; 1624 } 1625 initWithPlatformLimits()1626 private void initWithPlatformLimits() { 1627 mBitrateRange = BITRATE_RANGE; 1628 1629 mWidthRange = SIZE_RANGE; 1630 mHeightRange = SIZE_RANGE; 1631 mFrameRateRange = FRAME_RATE_RANGE; 1632 1633 mHorizontalBlockRange = SIZE_RANGE; 1634 mVerticalBlockRange = SIZE_RANGE; 1635 1636 // full positive ranges are supported as these get calculated 1637 mBlockCountRange = POSITIVE_INTEGERS; 1638 mBlocksPerSecondRange = POSITIVE_LONGS; 1639 1640 mBlockAspectRatioRange = POSITIVE_RATIONALS; 1641 mAspectRatioRange = POSITIVE_RATIONALS; 1642 1643 // YUV 4:2:0 requires 2:2 alignment 1644 mWidthAlignment = 2; 1645 mHeightAlignment = 2; 1646 mBlockWidth = 2; 1647 mBlockHeight = 2; 1648 mSmallerDimensionUpperLimit = SIZE_RANGE.getUpper(); 1649 } 1650 getMeasuredFrameRates(Map<String, Object> map)1651 private Map<Size, Range<Long>> getMeasuredFrameRates(Map<String, Object> map) { 1652 Map<Size, Range<Long>> ret = new HashMap<Size, Range<Long>>(); 1653 final String prefix = "measured-frame-rate-"; 1654 Set<String> keys = map.keySet(); 1655 for (String key : keys) { 1656 // looking for: measured-frame-rate-WIDTHxHEIGHT-range 1657 if (!key.startsWith(prefix)) { 1658 continue; 1659 } 1660 String subKey = key.substring(prefix.length()); 1661 String[] temp = key.split("-"); 1662 if (temp.length != 5) { 1663 continue; 1664 } 1665 String sizeStr = temp[3]; 1666 Size size = Utils.parseSize(sizeStr, null); 1667 if (size == null || size.getWidth() * size.getHeight() <= 0) { 1668 continue; 1669 } 1670 Range<Long> range = Utils.parseLongRange(map.get(key), null); 1671 if (range == null || range.getLower() < 0 || range.getUpper() < 0) { 1672 continue; 1673 } 1674 ret.put(size, range); 1675 } 1676 return ret; 1677 } 1678 parseWidthHeightRanges(Object o)1679 private static Pair<Range<Integer>, Range<Integer>> parseWidthHeightRanges(Object o) { 1680 Pair<Size, Size> range = Utils.parseSizeRange(o); 1681 if (range != null) { 1682 try { 1683 return Pair.create( 1684 Range.create(range.first.getWidth(), range.second.getWidth()), 1685 Range.create(range.first.getHeight(), range.second.getHeight())); 1686 } catch (IllegalArgumentException e) { 1687 Log.w(TAG, "could not parse size range '" + o + "'"); 1688 } 1689 } 1690 return null; 1691 } 1692 1693 /** @hide */ equivalentVP9Level(MediaFormat info)1694 public static int equivalentVP9Level(MediaFormat info) { 1695 final Map<String, Object> map = info.getMap(); 1696 1697 Size blockSize = Utils.parseSize(map.get("block-size"), new Size(8, 8)); 1698 int BS = blockSize.getWidth() * blockSize.getHeight(); 1699 1700 Range<Integer> counts = Utils.parseIntRange(map.get("block-count-range"), null); 1701 int FS = counts == null ? 0 : BS * counts.getUpper(); 1702 1703 Range<Long> blockRates = 1704 Utils.parseLongRange(map.get("blocks-per-second-range"), null); 1705 long SR = blockRates == null ? 0 : BS * blockRates.getUpper(); 1706 1707 Pair<Range<Integer>, Range<Integer>> dimensionRanges = 1708 parseWidthHeightRanges(map.get("size-range")); 1709 int D = dimensionRanges == null ? 0 : Math.max( 1710 dimensionRanges.first.getUpper(), dimensionRanges.second.getUpper()); 1711 1712 Range<Integer> bitRates = Utils.parseIntRange(map.get("bitrate-range"), null); 1713 int BR = bitRates == null ? 0 : Utils.divUp(bitRates.getUpper(), 1000); 1714 1715 if (SR <= 829440 && FS <= 36864 && BR <= 200 && D <= 512) 1716 return CodecProfileLevel.VP9Level1; 1717 if (SR <= 2764800 && FS <= 73728 && BR <= 800 && D <= 768) 1718 return CodecProfileLevel.VP9Level11; 1719 if (SR <= 4608000 && FS <= 122880 && BR <= 1800 && D <= 960) 1720 return CodecProfileLevel.VP9Level2; 1721 if (SR <= 9216000 && FS <= 245760 && BR <= 3600 && D <= 1344) 1722 return CodecProfileLevel.VP9Level21; 1723 if (SR <= 20736000 && FS <= 552960 && BR <= 7200 && D <= 2048) 1724 return CodecProfileLevel.VP9Level3; 1725 if (SR <= 36864000 && FS <= 983040 && BR <= 12000 && D <= 2752) 1726 return CodecProfileLevel.VP9Level31; 1727 if (SR <= 83558400 && FS <= 2228224 && BR <= 18000 && D <= 4160) 1728 return CodecProfileLevel.VP9Level4; 1729 if (SR <= 160432128 && FS <= 2228224 && BR <= 30000 && D <= 4160) 1730 return CodecProfileLevel.VP9Level41; 1731 if (SR <= 311951360 && FS <= 8912896 && BR <= 60000 && D <= 8384) 1732 return CodecProfileLevel.VP9Level5; 1733 if (SR <= 588251136 && FS <= 8912896 && BR <= 120000 && D <= 8384) 1734 return CodecProfileLevel.VP9Level51; 1735 if (SR <= 1176502272 && FS <= 8912896 && BR <= 180000 && D <= 8384) 1736 return CodecProfileLevel.VP9Level52; 1737 if (SR <= 1176502272 && FS <= 35651584 && BR <= 180000 && D <= 16832) 1738 return CodecProfileLevel.VP9Level6; 1739 if (SR <= 2353004544L && FS <= 35651584 && BR <= 240000 && D <= 16832) 1740 return CodecProfileLevel.VP9Level61; 1741 if (SR <= 4706009088L && FS <= 35651584 && BR <= 480000 && D <= 16832) 1742 return CodecProfileLevel.VP9Level62; 1743 // returning largest level 1744 return CodecProfileLevel.VP9Level62; 1745 } 1746 parseFromInfo(MediaFormat info)1747 private void parseFromInfo(MediaFormat info) { 1748 final Map<String, Object> map = info.getMap(); 1749 Size blockSize = new Size(mBlockWidth, mBlockHeight); 1750 Size alignment = new Size(mWidthAlignment, mHeightAlignment); 1751 Range<Integer> counts = null, widths = null, heights = null; 1752 Range<Integer> frameRates = null, bitRates = null; 1753 Range<Long> blockRates = null; 1754 Range<Rational> ratios = null, blockRatios = null; 1755 1756 blockSize = Utils.parseSize(map.get("block-size"), blockSize); 1757 alignment = Utils.parseSize(map.get("alignment"), alignment); 1758 counts = Utils.parseIntRange(map.get("block-count-range"), null); 1759 blockRates = 1760 Utils.parseLongRange(map.get("blocks-per-second-range"), null); 1761 mMeasuredFrameRates = getMeasuredFrameRates(map); 1762 Pair<Range<Integer>, Range<Integer>> sizeRanges = 1763 parseWidthHeightRanges(map.get("size-range")); 1764 if (sizeRanges != null) { 1765 widths = sizeRanges.first; 1766 heights = sizeRanges.second; 1767 } 1768 // for now this just means using the smaller max size as 2nd 1769 // upper limit. 1770 // for now we are keeping the profile specific "width/height 1771 // in macroblocks" limits. 1772 if (map.containsKey("feature-can-swap-width-height")) { 1773 if (widths != null) { 1774 mSmallerDimensionUpperLimit = 1775 Math.min(widths.getUpper(), heights.getUpper()); 1776 widths = heights = widths.extend(heights); 1777 } else { 1778 Log.w(TAG, "feature can-swap-width-height is best used with size-range"); 1779 mSmallerDimensionUpperLimit = 1780 Math.min(mWidthRange.getUpper(), mHeightRange.getUpper()); 1781 mWidthRange = mHeightRange = mWidthRange.extend(mHeightRange); 1782 } 1783 } 1784 1785 ratios = Utils.parseRationalRange( 1786 map.get("block-aspect-ratio-range"), null); 1787 blockRatios = Utils.parseRationalRange( 1788 map.get("pixel-aspect-ratio-range"), null); 1789 frameRates = Utils.parseIntRange(map.get("frame-rate-range"), null); 1790 if (frameRates != null) { 1791 try { 1792 frameRates = frameRates.intersect(FRAME_RATE_RANGE); 1793 } catch (IllegalArgumentException e) { 1794 Log.w(TAG, "frame rate range (" + frameRates 1795 + ") is out of limits: " + FRAME_RATE_RANGE); 1796 frameRates = null; 1797 } 1798 } 1799 bitRates = Utils.parseIntRange(map.get("bitrate-range"), null); 1800 if (bitRates != null) { 1801 try { 1802 bitRates = bitRates.intersect(BITRATE_RANGE); 1803 } catch (IllegalArgumentException e) { 1804 Log.w(TAG, "bitrate range (" + bitRates 1805 + ") is out of limits: " + BITRATE_RANGE); 1806 bitRates = null; 1807 } 1808 } 1809 1810 checkPowerOfTwo( 1811 blockSize.getWidth(), "block-size width must be power of two"); 1812 checkPowerOfTwo( 1813 blockSize.getHeight(), "block-size height must be power of two"); 1814 1815 checkPowerOfTwo( 1816 alignment.getWidth(), "alignment width must be power of two"); 1817 checkPowerOfTwo( 1818 alignment.getHeight(), "alignment height must be power of two"); 1819 1820 // update block-size and alignment 1821 applyMacroBlockLimits( 1822 Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, 1823 Long.MAX_VALUE, blockSize.getWidth(), blockSize.getHeight(), 1824 alignment.getWidth(), alignment.getHeight()); 1825 1826 if ((mParent.mError & ERROR_UNSUPPORTED) != 0 || mAllowMbOverride) { 1827 // codec supports profiles that we don't know. 1828 // Use supplied values clipped to platform limits 1829 if (widths != null) { 1830 mWidthRange = SIZE_RANGE.intersect(widths); 1831 } 1832 if (heights != null) { 1833 mHeightRange = SIZE_RANGE.intersect(heights); 1834 } 1835 if (counts != null) { 1836 mBlockCountRange = POSITIVE_INTEGERS.intersect( 1837 Utils.factorRange(counts, mBlockWidth * mBlockHeight 1838 / blockSize.getWidth() / blockSize.getHeight())); 1839 } 1840 if (blockRates != null) { 1841 mBlocksPerSecondRange = POSITIVE_LONGS.intersect( 1842 Utils.factorRange(blockRates, mBlockWidth * mBlockHeight 1843 / blockSize.getWidth() / blockSize.getHeight())); 1844 } 1845 if (blockRatios != null) { 1846 mBlockAspectRatioRange = POSITIVE_RATIONALS.intersect( 1847 Utils.scaleRange(blockRatios, 1848 mBlockHeight / blockSize.getHeight(), 1849 mBlockWidth / blockSize.getWidth())); 1850 } 1851 if (ratios != null) { 1852 mAspectRatioRange = POSITIVE_RATIONALS.intersect(ratios); 1853 } 1854 if (frameRates != null) { 1855 mFrameRateRange = FRAME_RATE_RANGE.intersect(frameRates); 1856 } 1857 if (bitRates != null) { 1858 // only allow bitrate override if unsupported profiles were encountered 1859 if ((mParent.mError & ERROR_UNSUPPORTED) != 0) { 1860 mBitrateRange = BITRATE_RANGE.intersect(bitRates); 1861 } else { 1862 mBitrateRange = mBitrateRange.intersect(bitRates); 1863 } 1864 } 1865 } else { 1866 // no unsupported profile/levels, so restrict values to known limits 1867 if (widths != null) { 1868 mWidthRange = mWidthRange.intersect(widths); 1869 } 1870 if (heights != null) { 1871 mHeightRange = mHeightRange.intersect(heights); 1872 } 1873 if (counts != null) { 1874 mBlockCountRange = mBlockCountRange.intersect( 1875 Utils.factorRange(counts, mBlockWidth * mBlockHeight 1876 / blockSize.getWidth() / blockSize.getHeight())); 1877 } 1878 if (blockRates != null) { 1879 mBlocksPerSecondRange = mBlocksPerSecondRange.intersect( 1880 Utils.factorRange(blockRates, mBlockWidth * mBlockHeight 1881 / blockSize.getWidth() / blockSize.getHeight())); 1882 } 1883 if (blockRatios != null) { 1884 mBlockAspectRatioRange = mBlockAspectRatioRange.intersect( 1885 Utils.scaleRange(blockRatios, 1886 mBlockHeight / blockSize.getHeight(), 1887 mBlockWidth / blockSize.getWidth())); 1888 } 1889 if (ratios != null) { 1890 mAspectRatioRange = mAspectRatioRange.intersect(ratios); 1891 } 1892 if (frameRates != null) { 1893 mFrameRateRange = mFrameRateRange.intersect(frameRates); 1894 } 1895 if (bitRates != null) { 1896 mBitrateRange = mBitrateRange.intersect(bitRates); 1897 } 1898 } 1899 updateLimits(); 1900 } 1901 applyBlockLimits( int blockWidth, int blockHeight, Range<Integer> counts, Range<Long> rates, Range<Rational> ratios)1902 private void applyBlockLimits( 1903 int blockWidth, int blockHeight, 1904 Range<Integer> counts, Range<Long> rates, Range<Rational> ratios) { 1905 checkPowerOfTwo(blockWidth, "blockWidth must be a power of two"); 1906 checkPowerOfTwo(blockHeight, "blockHeight must be a power of two"); 1907 1908 final int newBlockWidth = Math.max(blockWidth, mBlockWidth); 1909 final int newBlockHeight = Math.max(blockHeight, mBlockHeight); 1910 1911 // factor will always be a power-of-2 1912 int factor = 1913 newBlockWidth * newBlockHeight / mBlockWidth / mBlockHeight; 1914 if (factor != 1) { 1915 mBlockCountRange = Utils.factorRange(mBlockCountRange, factor); 1916 mBlocksPerSecondRange = Utils.factorRange( 1917 mBlocksPerSecondRange, factor); 1918 mBlockAspectRatioRange = Utils.scaleRange( 1919 mBlockAspectRatioRange, 1920 newBlockHeight / mBlockHeight, 1921 newBlockWidth / mBlockWidth); 1922 mHorizontalBlockRange = Utils.factorRange( 1923 mHorizontalBlockRange, newBlockWidth / mBlockWidth); 1924 mVerticalBlockRange = Utils.factorRange( 1925 mVerticalBlockRange, newBlockHeight / mBlockHeight); 1926 } 1927 factor = newBlockWidth * newBlockHeight / blockWidth / blockHeight; 1928 if (factor != 1) { 1929 counts = Utils.factorRange(counts, factor); 1930 rates = Utils.factorRange(rates, factor); 1931 ratios = Utils.scaleRange( 1932 ratios, newBlockHeight / blockHeight, 1933 newBlockWidth / blockWidth); 1934 } 1935 mBlockCountRange = mBlockCountRange.intersect(counts); 1936 mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(rates); 1937 mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(ratios); 1938 mBlockWidth = newBlockWidth; 1939 mBlockHeight = newBlockHeight; 1940 } 1941 applyAlignment(int widthAlignment, int heightAlignment)1942 private void applyAlignment(int widthAlignment, int heightAlignment) { 1943 checkPowerOfTwo(widthAlignment, "widthAlignment must be a power of two"); 1944 checkPowerOfTwo(heightAlignment, "heightAlignment must be a power of two"); 1945 1946 if (widthAlignment > mBlockWidth || heightAlignment > mBlockHeight) { 1947 // maintain assumption that 0 < alignment <= block-size 1948 applyBlockLimits( 1949 Math.max(widthAlignment, mBlockWidth), 1950 Math.max(heightAlignment, mBlockHeight), 1951 POSITIVE_INTEGERS, POSITIVE_LONGS, POSITIVE_RATIONALS); 1952 } 1953 1954 mWidthAlignment = Math.max(widthAlignment, mWidthAlignment); 1955 mHeightAlignment = Math.max(heightAlignment, mHeightAlignment); 1956 1957 mWidthRange = Utils.alignRange(mWidthRange, mWidthAlignment); 1958 mHeightRange = Utils.alignRange(mHeightRange, mHeightAlignment); 1959 } 1960 updateLimits()1961 private void updateLimits() { 1962 // pixels -> blocks <- counts 1963 mHorizontalBlockRange = mHorizontalBlockRange.intersect( 1964 Utils.factorRange(mWidthRange, mBlockWidth)); 1965 mHorizontalBlockRange = mHorizontalBlockRange.intersect( 1966 Range.create( 1967 mBlockCountRange.getLower() / mVerticalBlockRange.getUpper(), 1968 mBlockCountRange.getUpper() / mVerticalBlockRange.getLower())); 1969 mVerticalBlockRange = mVerticalBlockRange.intersect( 1970 Utils.factorRange(mHeightRange, mBlockHeight)); 1971 mVerticalBlockRange = mVerticalBlockRange.intersect( 1972 Range.create( 1973 mBlockCountRange.getLower() / mHorizontalBlockRange.getUpper(), 1974 mBlockCountRange.getUpper() / mHorizontalBlockRange.getLower())); 1975 mBlockCountRange = mBlockCountRange.intersect( 1976 Range.create( 1977 mHorizontalBlockRange.getLower() 1978 * mVerticalBlockRange.getLower(), 1979 mHorizontalBlockRange.getUpper() 1980 * mVerticalBlockRange.getUpper())); 1981 mBlockAspectRatioRange = mBlockAspectRatioRange.intersect( 1982 new Rational( 1983 mHorizontalBlockRange.getLower(), mVerticalBlockRange.getUpper()), 1984 new Rational( 1985 mHorizontalBlockRange.getUpper(), mVerticalBlockRange.getLower())); 1986 1987 // blocks -> pixels 1988 mWidthRange = mWidthRange.intersect( 1989 (mHorizontalBlockRange.getLower() - 1) * mBlockWidth + mWidthAlignment, 1990 mHorizontalBlockRange.getUpper() * mBlockWidth); 1991 mHeightRange = mHeightRange.intersect( 1992 (mVerticalBlockRange.getLower() - 1) * mBlockHeight + mHeightAlignment, 1993 mVerticalBlockRange.getUpper() * mBlockHeight); 1994 mAspectRatioRange = mAspectRatioRange.intersect( 1995 new Rational(mWidthRange.getLower(), mHeightRange.getUpper()), 1996 new Rational(mWidthRange.getUpper(), mHeightRange.getLower())); 1997 1998 mSmallerDimensionUpperLimit = Math.min( 1999 mSmallerDimensionUpperLimit, 2000 Math.min(mWidthRange.getUpper(), mHeightRange.getUpper())); 2001 2002 // blocks -> rate 2003 mBlocksPerSecondRange = mBlocksPerSecondRange.intersect( 2004 mBlockCountRange.getLower() * (long)mFrameRateRange.getLower(), 2005 mBlockCountRange.getUpper() * (long)mFrameRateRange.getUpper()); 2006 mFrameRateRange = mFrameRateRange.intersect( 2007 (int)(mBlocksPerSecondRange.getLower() 2008 / mBlockCountRange.getUpper()), 2009 (int)(mBlocksPerSecondRange.getUpper() 2010 / (double)mBlockCountRange.getLower())); 2011 } 2012 applyMacroBlockLimits( int maxHorizontalBlocks, int maxVerticalBlocks, int maxBlocks, long maxBlocksPerSecond, int blockWidth, int blockHeight, int widthAlignment, int heightAlignment)2013 private void applyMacroBlockLimits( 2014 int maxHorizontalBlocks, int maxVerticalBlocks, 2015 int maxBlocks, long maxBlocksPerSecond, 2016 int blockWidth, int blockHeight, 2017 int widthAlignment, int heightAlignment) { 2018 applyMacroBlockLimits( 2019 1 /* minHorizontalBlocks */, 1 /* minVerticalBlocks */, 2020 maxHorizontalBlocks, maxVerticalBlocks, 2021 maxBlocks, maxBlocksPerSecond, 2022 blockWidth, blockHeight, widthAlignment, heightAlignment); 2023 } 2024 applyMacroBlockLimits( int minHorizontalBlocks, int minVerticalBlocks, int maxHorizontalBlocks, int maxVerticalBlocks, int maxBlocks, long maxBlocksPerSecond, int blockWidth, int blockHeight, int widthAlignment, int heightAlignment)2025 private void applyMacroBlockLimits( 2026 int minHorizontalBlocks, int minVerticalBlocks, 2027 int maxHorizontalBlocks, int maxVerticalBlocks, 2028 int maxBlocks, long maxBlocksPerSecond, 2029 int blockWidth, int blockHeight, 2030 int widthAlignment, int heightAlignment) { 2031 applyAlignment(widthAlignment, heightAlignment); 2032 applyBlockLimits( 2033 blockWidth, blockHeight, Range.create(1, maxBlocks), 2034 Range.create(1L, maxBlocksPerSecond), 2035 Range.create( 2036 new Rational(1, maxVerticalBlocks), 2037 new Rational(maxHorizontalBlocks, 1))); 2038 mHorizontalBlockRange = 2039 mHorizontalBlockRange.intersect( 2040 Utils.divUp(minHorizontalBlocks, (mBlockWidth / blockWidth)), 2041 maxHorizontalBlocks / (mBlockWidth / blockWidth)); 2042 mVerticalBlockRange = 2043 mVerticalBlockRange.intersect( 2044 Utils.divUp(minVerticalBlocks, (mBlockHeight / blockHeight)), 2045 maxVerticalBlocks / (mBlockHeight / blockHeight)); 2046 } 2047 applyLevelLimits()2048 private void applyLevelLimits() { 2049 long maxBlocksPerSecond = 0; 2050 int maxBlocks = 0; 2051 int maxBps = 0; 2052 int maxDPBBlocks = 0; 2053 2054 int errors = ERROR_NONE_SUPPORTED; 2055 CodecProfileLevel[] profileLevels = mParent.profileLevels; 2056 String mime = mParent.getMimeType(); 2057 2058 if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC)) { 2059 maxBlocks = 99; 2060 maxBlocksPerSecond = 1485; 2061 maxBps = 64000; 2062 maxDPBBlocks = 396; 2063 for (CodecProfileLevel profileLevel: profileLevels) { 2064 int MBPS = 0, FS = 0, BR = 0, DPB = 0; 2065 boolean supported = true; 2066 switch (profileLevel.level) { 2067 case CodecProfileLevel.AVCLevel1: 2068 MBPS = 1485; FS = 99; BR = 64; DPB = 396; break; 2069 case CodecProfileLevel.AVCLevel1b: 2070 MBPS = 1485; FS = 99; BR = 128; DPB = 396; break; 2071 case CodecProfileLevel.AVCLevel11: 2072 MBPS = 3000; FS = 396; BR = 192; DPB = 900; break; 2073 case CodecProfileLevel.AVCLevel12: 2074 MBPS = 6000; FS = 396; BR = 384; DPB = 2376; break; 2075 case CodecProfileLevel.AVCLevel13: 2076 MBPS = 11880; FS = 396; BR = 768; DPB = 2376; break; 2077 case CodecProfileLevel.AVCLevel2: 2078 MBPS = 11880; FS = 396; BR = 2000; DPB = 2376; break; 2079 case CodecProfileLevel.AVCLevel21: 2080 MBPS = 19800; FS = 792; BR = 4000; DPB = 4752; break; 2081 case CodecProfileLevel.AVCLevel22: 2082 MBPS = 20250; FS = 1620; BR = 4000; DPB = 8100; break; 2083 case CodecProfileLevel.AVCLevel3: 2084 MBPS = 40500; FS = 1620; BR = 10000; DPB = 8100; break; 2085 case CodecProfileLevel.AVCLevel31: 2086 MBPS = 108000; FS = 3600; BR = 14000; DPB = 18000; break; 2087 case CodecProfileLevel.AVCLevel32: 2088 MBPS = 216000; FS = 5120; BR = 20000; DPB = 20480; break; 2089 case CodecProfileLevel.AVCLevel4: 2090 MBPS = 245760; FS = 8192; BR = 20000; DPB = 32768; break; 2091 case CodecProfileLevel.AVCLevel41: 2092 MBPS = 245760; FS = 8192; BR = 50000; DPB = 32768; break; 2093 case CodecProfileLevel.AVCLevel42: 2094 MBPS = 522240; FS = 8704; BR = 50000; DPB = 34816; break; 2095 case CodecProfileLevel.AVCLevel5: 2096 MBPS = 589824; FS = 22080; BR = 135000; DPB = 110400; break; 2097 case CodecProfileLevel.AVCLevel51: 2098 MBPS = 983040; FS = 36864; BR = 240000; DPB = 184320; break; 2099 case CodecProfileLevel.AVCLevel52: 2100 MBPS = 2073600; FS = 36864; BR = 240000; DPB = 184320; break; 2101 default: 2102 Log.w(TAG, "Unrecognized level " 2103 + profileLevel.level + " for " + mime); 2104 errors |= ERROR_UNRECOGNIZED; 2105 } 2106 switch (profileLevel.profile) { 2107 case CodecProfileLevel.AVCProfileConstrainedHigh: 2108 case CodecProfileLevel.AVCProfileHigh: 2109 BR *= 1250; break; 2110 case CodecProfileLevel.AVCProfileHigh10: 2111 BR *= 3000; break; 2112 case CodecProfileLevel.AVCProfileExtended: 2113 case CodecProfileLevel.AVCProfileHigh422: 2114 case CodecProfileLevel.AVCProfileHigh444: 2115 Log.w(TAG, "Unsupported profile " 2116 + profileLevel.profile + " for " + mime); 2117 errors |= ERROR_UNSUPPORTED; 2118 supported = false; 2119 // fall through - treat as base profile 2120 case CodecProfileLevel.AVCProfileConstrainedBaseline: 2121 case CodecProfileLevel.AVCProfileBaseline: 2122 case CodecProfileLevel.AVCProfileMain: 2123 BR *= 1000; break; 2124 default: 2125 Log.w(TAG, "Unrecognized profile " 2126 + profileLevel.profile + " for " + mime); 2127 errors |= ERROR_UNRECOGNIZED; 2128 BR *= 1000; 2129 } 2130 if (supported) { 2131 errors &= ~ERROR_NONE_SUPPORTED; 2132 } 2133 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); 2134 maxBlocks = Math.max(FS, maxBlocks); 2135 maxBps = Math.max(BR, maxBps); 2136 maxDPBBlocks = Math.max(maxDPBBlocks, DPB); 2137 } 2138 2139 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8)); 2140 applyMacroBlockLimits( 2141 maxLengthInBlocks, maxLengthInBlocks, 2142 maxBlocks, maxBlocksPerSecond, 2143 16 /* blockWidth */, 16 /* blockHeight */, 2144 1 /* widthAlignment */, 1 /* heightAlignment */); 2145 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG2)) { 2146 int maxWidth = 11, maxHeight = 9, maxRate = 15; 2147 maxBlocks = 99; 2148 maxBlocksPerSecond = 1485; 2149 maxBps = 64000; 2150 for (CodecProfileLevel profileLevel: profileLevels) { 2151 int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0; 2152 boolean supported = true; 2153 switch (profileLevel.profile) { 2154 case CodecProfileLevel.MPEG2ProfileSimple: 2155 switch (profileLevel.level) { 2156 case CodecProfileLevel.MPEG2LevelML: 2157 FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 15000; break; 2158 default: 2159 Log.w(TAG, "Unrecognized profile/level " 2160 + profileLevel.profile + "/" 2161 + profileLevel.level + " for " + mime); 2162 errors |= ERROR_UNRECOGNIZED; 2163 } 2164 break; 2165 case CodecProfileLevel.MPEG2ProfileMain: 2166 switch (profileLevel.level) { 2167 case CodecProfileLevel.MPEG2LevelLL: 2168 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 4000; break; 2169 case CodecProfileLevel.MPEG2LevelML: 2170 FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 15000; break; 2171 case CodecProfileLevel.MPEG2LevelH14: 2172 FR = 60; W = 90; H = 68; MBPS = 183600; FS = 6120; BR = 60000; break; 2173 case CodecProfileLevel.MPEG2LevelHL: 2174 FR = 60; W = 120; H = 68; MBPS = 244800; FS = 8160; BR = 80000; break; 2175 case CodecProfileLevel.MPEG2LevelHP: 2176 FR = 60; W = 120; H = 68; MBPS = 489600; FS = 8160; BR = 80000; break; 2177 default: 2178 Log.w(TAG, "Unrecognized profile/level " 2179 + profileLevel.profile + "/" 2180 + profileLevel.level + " for " + mime); 2181 errors |= ERROR_UNRECOGNIZED; 2182 } 2183 break; 2184 case CodecProfileLevel.MPEG2Profile422: 2185 case CodecProfileLevel.MPEG2ProfileSNR: 2186 case CodecProfileLevel.MPEG2ProfileSpatial: 2187 case CodecProfileLevel.MPEG2ProfileHigh: 2188 Log.i(TAG, "Unsupported profile " 2189 + profileLevel.profile + " for " + mime); 2190 errors |= ERROR_UNSUPPORTED; 2191 supported = false; 2192 break; 2193 default: 2194 Log.w(TAG, "Unrecognized profile " 2195 + profileLevel.profile + " for " + mime); 2196 errors |= ERROR_UNRECOGNIZED; 2197 } 2198 if (supported) { 2199 errors &= ~ERROR_NONE_SUPPORTED; 2200 } 2201 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); 2202 maxBlocks = Math.max(FS, maxBlocks); 2203 maxBps = Math.max(BR * 1000, maxBps); 2204 maxWidth = Math.max(W, maxWidth); 2205 maxHeight = Math.max(H, maxHeight); 2206 maxRate = Math.max(FR, maxRate); 2207 } 2208 applyMacroBlockLimits(maxWidth, maxHeight, 2209 maxBlocks, maxBlocksPerSecond, 2210 16 /* blockWidth */, 16 /* blockHeight */, 2211 1 /* widthAlignment */, 1 /* heightAlignment */); 2212 mFrameRateRange = mFrameRateRange.intersect(12, maxRate); 2213 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) { 2214 int maxWidth = 11, maxHeight = 9, maxRate = 15; 2215 maxBlocks = 99; 2216 maxBlocksPerSecond = 1485; 2217 maxBps = 64000; 2218 for (CodecProfileLevel profileLevel: profileLevels) { 2219 int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0; 2220 boolean strict = false; // true: W, H and FR are individual max limits 2221 boolean supported = true; 2222 switch (profileLevel.profile) { 2223 case CodecProfileLevel.MPEG4ProfileSimple: 2224 switch (profileLevel.level) { 2225 case CodecProfileLevel.MPEG4Level0: 2226 strict = true; 2227 FR = 15; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 64; break; 2228 case CodecProfileLevel.MPEG4Level1: 2229 FR = 30; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 64; break; 2230 case CodecProfileLevel.MPEG4Level0b: 2231 strict = true; 2232 FR = 15; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 128; break; 2233 case CodecProfileLevel.MPEG4Level2: 2234 FR = 30; W = 22; H = 18; MBPS = 5940; FS = 396; BR = 128; break; 2235 case CodecProfileLevel.MPEG4Level3: 2236 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384; break; 2237 case CodecProfileLevel.MPEG4Level4a: 2238 FR = 30; W = 40; H = 30; MBPS = 36000; FS = 1200; BR = 4000; break; 2239 case CodecProfileLevel.MPEG4Level5: 2240 FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 8000; break; 2241 case CodecProfileLevel.MPEG4Level6: 2242 FR = 30; W = 80; H = 45; MBPS = 108000; FS = 3600; BR = 12000; break; 2243 default: 2244 Log.w(TAG, "Unrecognized profile/level " 2245 + profileLevel.profile + "/" 2246 + profileLevel.level + " for " + mime); 2247 errors |= ERROR_UNRECOGNIZED; 2248 } 2249 break; 2250 case CodecProfileLevel.MPEG4ProfileAdvancedSimple: 2251 switch (profileLevel.level) { 2252 case CodecProfileLevel.MPEG4Level0: 2253 case CodecProfileLevel.MPEG4Level1: 2254 FR = 30; W = 11; H = 9; MBPS = 2970; FS = 99; BR = 128; break; 2255 case CodecProfileLevel.MPEG4Level2: 2256 FR = 30; W = 22; H = 18; MBPS = 5940; FS = 396; BR = 384; break; 2257 case CodecProfileLevel.MPEG4Level3: 2258 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 768; break; 2259 case CodecProfileLevel.MPEG4Level3b: 2260 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 1500; break; 2261 case CodecProfileLevel.MPEG4Level4: 2262 FR = 30; W = 44; H = 36; MBPS = 23760; FS = 792; BR = 3000; break; 2263 case CodecProfileLevel.MPEG4Level5: 2264 FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 8000; break; 2265 default: 2266 Log.w(TAG, "Unrecognized profile/level " 2267 + profileLevel.profile + "/" 2268 + profileLevel.level + " for " + mime); 2269 errors |= ERROR_UNRECOGNIZED; 2270 } 2271 break; 2272 case CodecProfileLevel.MPEG4ProfileMain: // 2-4 2273 case CodecProfileLevel.MPEG4ProfileNbit: // 2 2274 case CodecProfileLevel.MPEG4ProfileAdvancedRealTime: // 1-4 2275 case CodecProfileLevel.MPEG4ProfileCoreScalable: // 1-3 2276 case CodecProfileLevel.MPEG4ProfileAdvancedCoding: // 1-4 2277 case CodecProfileLevel.MPEG4ProfileCore: // 1-2 2278 case CodecProfileLevel.MPEG4ProfileAdvancedCore: // 1-4 2279 case CodecProfileLevel.MPEG4ProfileSimpleScalable: // 0-2 2280 case CodecProfileLevel.MPEG4ProfileHybrid: // 1-2 2281 2282 // Studio profiles are not supported by our codecs. 2283 2284 // Only profiles that can decode simple object types are considered. 2285 // The following profiles are not able to. 2286 case CodecProfileLevel.MPEG4ProfileBasicAnimated: // 1-2 2287 case CodecProfileLevel.MPEG4ProfileScalableTexture: // 1 2288 case CodecProfileLevel.MPEG4ProfileSimpleFace: // 1-2 2289 case CodecProfileLevel.MPEG4ProfileAdvancedScalable: // 1-3 2290 case CodecProfileLevel.MPEG4ProfileSimpleFBA: // 1-2 2291 Log.i(TAG, "Unsupported profile " 2292 + profileLevel.profile + " for " + mime); 2293 errors |= ERROR_UNSUPPORTED; 2294 supported = false; 2295 break; 2296 default: 2297 Log.w(TAG, "Unrecognized profile " 2298 + profileLevel.profile + " for " + mime); 2299 errors |= ERROR_UNRECOGNIZED; 2300 } 2301 if (supported) { 2302 errors &= ~ERROR_NONE_SUPPORTED; 2303 } 2304 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); 2305 maxBlocks = Math.max(FS, maxBlocks); 2306 maxBps = Math.max(BR * 1000, maxBps); 2307 if (strict) { 2308 maxWidth = Math.max(W, maxWidth); 2309 maxHeight = Math.max(H, maxHeight); 2310 maxRate = Math.max(FR, maxRate); 2311 } else { 2312 // assuming max 60 fps frame rate and 1:2 aspect ratio 2313 int maxDim = (int)Math.sqrt(FS * 2); 2314 maxWidth = Math.max(maxDim, maxWidth); 2315 maxHeight = Math.max(maxDim, maxHeight); 2316 maxRate = Math.max(Math.max(FR, 60), maxRate); 2317 } 2318 } 2319 applyMacroBlockLimits(maxWidth, maxHeight, 2320 maxBlocks, maxBlocksPerSecond, 2321 16 /* blockWidth */, 16 /* blockHeight */, 2322 1 /* widthAlignment */, 1 /* heightAlignment */); 2323 mFrameRateRange = mFrameRateRange.intersect(12, maxRate); 2324 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) { 2325 int maxWidth = 11, maxHeight = 9, maxRate = 15; 2326 int minWidth = maxWidth, minHeight = maxHeight; 2327 int minAlignment = 16; 2328 maxBlocks = 99; 2329 maxBlocksPerSecond = 1485; 2330 maxBps = 64000; 2331 for (CodecProfileLevel profileLevel: profileLevels) { 2332 int MBPS = 0, BR = 0, FR = 0, W = 0, H = 0, minW = minWidth, minH = minHeight; 2333 boolean strict = false; // true: support only sQCIF, QCIF (maybe CIF) 2334 switch (profileLevel.level) { 2335 case CodecProfileLevel.H263Level10: 2336 strict = true; // only supports sQCIF & QCIF 2337 FR = 15; W = 11; H = 9; BR = 1; MBPS = W * H * FR; break; 2338 case CodecProfileLevel.H263Level20: 2339 strict = true; // only supports sQCIF, QCIF & CIF 2340 FR = 30; W = 22; H = 18; BR = 2; MBPS = W * H * 15; break; 2341 case CodecProfileLevel.H263Level30: 2342 strict = true; // only supports sQCIF, QCIF & CIF 2343 FR = 30; W = 22; H = 18; BR = 6; MBPS = W * H * FR; break; 2344 case CodecProfileLevel.H263Level40: 2345 strict = true; // only supports sQCIF, QCIF & CIF 2346 FR = 30; W = 22; H = 18; BR = 32; MBPS = W * H * FR; break; 2347 case CodecProfileLevel.H263Level45: 2348 // only implies level 10 support 2349 strict = profileLevel.profile == CodecProfileLevel.H263ProfileBaseline 2350 || profileLevel.profile == 2351 CodecProfileLevel.H263ProfileBackwardCompatible; 2352 if (!strict) { 2353 minW = 1; minH = 1; minAlignment = 4; 2354 } 2355 FR = 15; W = 11; H = 9; BR = 2; MBPS = W * H * FR; break; 2356 case CodecProfileLevel.H263Level50: 2357 // only supports 50fps for H > 15 2358 minW = 1; minH = 1; minAlignment = 4; 2359 FR = 60; W = 22; H = 18; BR = 64; MBPS = W * H * 50; break; 2360 case CodecProfileLevel.H263Level60: 2361 // only supports 50fps for H > 15 2362 minW = 1; minH = 1; minAlignment = 4; 2363 FR = 60; W = 45; H = 18; BR = 128; MBPS = W * H * 50; break; 2364 case CodecProfileLevel.H263Level70: 2365 // only supports 50fps for H > 30 2366 minW = 1; minH = 1; minAlignment = 4; 2367 FR = 60; W = 45; H = 36; BR = 256; MBPS = W * H * 50; break; 2368 default: 2369 Log.w(TAG, "Unrecognized profile/level " + profileLevel.profile 2370 + "/" + profileLevel.level + " for " + mime); 2371 errors |= ERROR_UNRECOGNIZED; 2372 } 2373 switch (profileLevel.profile) { 2374 case CodecProfileLevel.H263ProfileBackwardCompatible: 2375 case CodecProfileLevel.H263ProfileBaseline: 2376 case CodecProfileLevel.H263ProfileH320Coding: 2377 case CodecProfileLevel.H263ProfileHighCompression: 2378 case CodecProfileLevel.H263ProfileHighLatency: 2379 case CodecProfileLevel.H263ProfileInterlace: 2380 case CodecProfileLevel.H263ProfileInternet: 2381 case CodecProfileLevel.H263ProfileISWV2: 2382 case CodecProfileLevel.H263ProfileISWV3: 2383 break; 2384 default: 2385 Log.w(TAG, "Unrecognized profile " 2386 + profileLevel.profile + " for " + mime); 2387 errors |= ERROR_UNRECOGNIZED; 2388 } 2389 if (strict) { 2390 // Strict levels define sub-QCIF min size and enumerated sizes. We cannot 2391 // express support for "only sQCIF & QCIF (& CIF)" using VideoCapabilities 2392 // but we can express "only QCIF (& CIF)", so set minimume size at QCIF. 2393 // minW = 8; minH = 6; 2394 minW = 11; minH = 9; 2395 } else { 2396 // any support for non-strict levels (including unrecognized profiles or 2397 // levels) allow custom frame size support beyond supported limits 2398 // (other than bitrate) 2399 mAllowMbOverride = true; 2400 } 2401 errors &= ~ERROR_NONE_SUPPORTED; 2402 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); 2403 maxBlocks = Math.max(W * H, maxBlocks); 2404 maxBps = Math.max(BR * 64000, maxBps); 2405 maxWidth = Math.max(W, maxWidth); 2406 maxHeight = Math.max(H, maxHeight); 2407 maxRate = Math.max(FR, maxRate); 2408 minWidth = Math.min(minW, minWidth); 2409 minHeight = Math.min(minH, minHeight); 2410 } 2411 // unless we encountered custom frame size support, limit size to QCIF and CIF 2412 // using aspect ratio. 2413 if (!mAllowMbOverride) { 2414 mBlockAspectRatioRange = 2415 Range.create(new Rational(11, 9), new Rational(11, 9)); 2416 } 2417 applyMacroBlockLimits( 2418 minWidth, minHeight, 2419 maxWidth, maxHeight, 2420 maxBlocks, maxBlocksPerSecond, 2421 16 /* blockWidth */, 16 /* blockHeight */, 2422 minAlignment /* widthAlignment */, minAlignment /* heightAlignment */); 2423 mFrameRateRange = Range.create(1, maxRate); 2424 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8)) { 2425 maxBlocks = Integer.MAX_VALUE; 2426 maxBlocksPerSecond = Integer.MAX_VALUE; 2427 2428 // TODO: set to 100Mbps for now, need a number for VP8 2429 maxBps = 100000000; 2430 2431 // profile levels are not indicative for VPx, but verify 2432 // them nonetheless 2433 for (CodecProfileLevel profileLevel: profileLevels) { 2434 switch (profileLevel.level) { 2435 case CodecProfileLevel.VP8Level_Version0: 2436 case CodecProfileLevel.VP8Level_Version1: 2437 case CodecProfileLevel.VP8Level_Version2: 2438 case CodecProfileLevel.VP8Level_Version3: 2439 break; 2440 default: 2441 Log.w(TAG, "Unrecognized level " 2442 + profileLevel.level + " for " + mime); 2443 errors |= ERROR_UNRECOGNIZED; 2444 } 2445 switch (profileLevel.profile) { 2446 case CodecProfileLevel.VP8ProfileMain: 2447 break; 2448 default: 2449 Log.w(TAG, "Unrecognized profile " 2450 + profileLevel.profile + " for " + mime); 2451 errors |= ERROR_UNRECOGNIZED; 2452 } 2453 errors &= ~ERROR_NONE_SUPPORTED; 2454 } 2455 2456 final int blockSize = 16; 2457 applyMacroBlockLimits(Short.MAX_VALUE, Short.MAX_VALUE, 2458 maxBlocks, maxBlocksPerSecond, blockSize, blockSize, 2459 1 /* widthAlignment */, 1 /* heightAlignment */); 2460 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) { 2461 maxBlocksPerSecond = 829440; 2462 maxBlocks = 36864; 2463 maxBps = 200000; 2464 int maxDim = 512; 2465 2466 for (CodecProfileLevel profileLevel: profileLevels) { 2467 long SR = 0; // luma sample rate 2468 int FS = 0; // luma picture size 2469 int BR = 0; // bit rate kbps 2470 int D = 0; // luma dimension 2471 switch (profileLevel.level) { 2472 case CodecProfileLevel.VP9Level1: 2473 SR = 829440; FS = 36864; BR = 200; D = 512; break; 2474 case CodecProfileLevel.VP9Level11: 2475 SR = 2764800; FS = 73728; BR = 800; D = 768; break; 2476 case CodecProfileLevel.VP9Level2: 2477 SR = 4608000; FS = 122880; BR = 1800; D = 960; break; 2478 case CodecProfileLevel.VP9Level21: 2479 SR = 9216000; FS = 245760; BR = 3600; D = 1344; break; 2480 case CodecProfileLevel.VP9Level3: 2481 SR = 20736000; FS = 552960; BR = 7200; D = 2048; break; 2482 case CodecProfileLevel.VP9Level31: 2483 SR = 36864000; FS = 983040; BR = 12000; D = 2752; break; 2484 case CodecProfileLevel.VP9Level4: 2485 SR = 83558400; FS = 2228224; BR = 18000; D = 4160; break; 2486 case CodecProfileLevel.VP9Level41: 2487 SR = 160432128; FS = 2228224; BR = 30000; D = 4160; break; 2488 case CodecProfileLevel.VP9Level5: 2489 SR = 311951360; FS = 8912896; BR = 60000; D = 8384; break; 2490 case CodecProfileLevel.VP9Level51: 2491 SR = 588251136; FS = 8912896; BR = 120000; D = 8384; break; 2492 case CodecProfileLevel.VP9Level52: 2493 SR = 1176502272; FS = 8912896; BR = 180000; D = 8384; break; 2494 case CodecProfileLevel.VP9Level6: 2495 SR = 1176502272; FS = 35651584; BR = 180000; D = 16832; break; 2496 case CodecProfileLevel.VP9Level61: 2497 SR = 2353004544L; FS = 35651584; BR = 240000; D = 16832; break; 2498 case CodecProfileLevel.VP9Level62: 2499 SR = 4706009088L; FS = 35651584; BR = 480000; D = 16832; break; 2500 default: 2501 Log.w(TAG, "Unrecognized level " 2502 + profileLevel.level + " for " + mime); 2503 errors |= ERROR_UNRECOGNIZED; 2504 } 2505 switch (profileLevel.profile) { 2506 case CodecProfileLevel.VP9Profile0: 2507 case CodecProfileLevel.VP9Profile1: 2508 case CodecProfileLevel.VP9Profile2: 2509 case CodecProfileLevel.VP9Profile3: 2510 case CodecProfileLevel.VP9Profile2HDR: 2511 case CodecProfileLevel.VP9Profile3HDR: 2512 break; 2513 default: 2514 Log.w(TAG, "Unrecognized profile " 2515 + profileLevel.profile + " for " + mime); 2516 errors |= ERROR_UNRECOGNIZED; 2517 } 2518 errors &= ~ERROR_NONE_SUPPORTED; 2519 maxBlocksPerSecond = Math.max(SR, maxBlocksPerSecond); 2520 maxBlocks = Math.max(FS, maxBlocks); 2521 maxBps = Math.max(BR * 1000, maxBps); 2522 maxDim = Math.max(D, maxDim); 2523 } 2524 2525 final int blockSize = 8; 2526 int maxLengthInBlocks = Utils.divUp(maxDim, blockSize); 2527 maxBlocks = Utils.divUp(maxBlocks, blockSize * blockSize); 2528 maxBlocksPerSecond = Utils.divUp(maxBlocksPerSecond, blockSize * blockSize); 2529 2530 applyMacroBlockLimits( 2531 maxLengthInBlocks, maxLengthInBlocks, 2532 maxBlocks, maxBlocksPerSecond, 2533 blockSize, blockSize, 2534 1 /* widthAlignment */, 1 /* heightAlignment */); 2535 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) { 2536 // CTBs are at least 8x8 so use 8x8 block size 2537 maxBlocks = 36864 >> 6; // 192x192 pixels == 576 8x8 blocks 2538 maxBlocksPerSecond = maxBlocks * 15; 2539 maxBps = 128000; 2540 for (CodecProfileLevel profileLevel: profileLevels) { 2541 double FR = 0; 2542 int FS = 0; 2543 int BR = 0; 2544 switch (profileLevel.level) { 2545 /* The HEVC spec talks only in a very convoluted manner about the 2546 existence of levels 1-3.1 for High tier, which could also be 2547 understood as 'decoders and encoders should treat these levels 2548 as if they were Main tier', so we do that. */ 2549 case CodecProfileLevel.HEVCMainTierLevel1: 2550 case CodecProfileLevel.HEVCHighTierLevel1: 2551 FR = 15; FS = 36864; BR = 128; break; 2552 case CodecProfileLevel.HEVCMainTierLevel2: 2553 case CodecProfileLevel.HEVCHighTierLevel2: 2554 FR = 30; FS = 122880; BR = 1500; break; 2555 case CodecProfileLevel.HEVCMainTierLevel21: 2556 case CodecProfileLevel.HEVCHighTierLevel21: 2557 FR = 30; FS = 245760; BR = 3000; break; 2558 case CodecProfileLevel.HEVCMainTierLevel3: 2559 case CodecProfileLevel.HEVCHighTierLevel3: 2560 FR = 30; FS = 552960; BR = 6000; break; 2561 case CodecProfileLevel.HEVCMainTierLevel31: 2562 case CodecProfileLevel.HEVCHighTierLevel31: 2563 FR = 33.75; FS = 983040; BR = 10000; break; 2564 case CodecProfileLevel.HEVCMainTierLevel4: 2565 FR = 30; FS = 2228224; BR = 12000; break; 2566 case CodecProfileLevel.HEVCHighTierLevel4: 2567 FR = 30; FS = 2228224; BR = 30000; break; 2568 case CodecProfileLevel.HEVCMainTierLevel41: 2569 FR = 60; FS = 2228224; BR = 20000; break; 2570 case CodecProfileLevel.HEVCHighTierLevel41: 2571 FR = 60; FS = 2228224; BR = 50000; break; 2572 case CodecProfileLevel.HEVCMainTierLevel5: 2573 FR = 30; FS = 8912896; BR = 25000; break; 2574 case CodecProfileLevel.HEVCHighTierLevel5: 2575 FR = 30; FS = 8912896; BR = 100000; break; 2576 case CodecProfileLevel.HEVCMainTierLevel51: 2577 FR = 60; FS = 8912896; BR = 40000; break; 2578 case CodecProfileLevel.HEVCHighTierLevel51: 2579 FR = 60; FS = 8912896; BR = 160000; break; 2580 case CodecProfileLevel.HEVCMainTierLevel52: 2581 FR = 120; FS = 8912896; BR = 60000; break; 2582 case CodecProfileLevel.HEVCHighTierLevel52: 2583 FR = 120; FS = 8912896; BR = 240000; break; 2584 case CodecProfileLevel.HEVCMainTierLevel6: 2585 FR = 30; FS = 35651584; BR = 60000; break; 2586 case CodecProfileLevel.HEVCHighTierLevel6: 2587 FR = 30; FS = 35651584; BR = 240000; break; 2588 case CodecProfileLevel.HEVCMainTierLevel61: 2589 FR = 60; FS = 35651584; BR = 120000; break; 2590 case CodecProfileLevel.HEVCHighTierLevel61: 2591 FR = 60; FS = 35651584; BR = 480000; break; 2592 case CodecProfileLevel.HEVCMainTierLevel62: 2593 FR = 120; FS = 35651584; BR = 240000; break; 2594 case CodecProfileLevel.HEVCHighTierLevel62: 2595 FR = 120; FS = 35651584; BR = 800000; break; 2596 default: 2597 Log.w(TAG, "Unrecognized level " 2598 + profileLevel.level + " for " + mime); 2599 errors |= ERROR_UNRECOGNIZED; 2600 } 2601 switch (profileLevel.profile) { 2602 case CodecProfileLevel.HEVCProfileMain: 2603 case CodecProfileLevel.HEVCProfileMain10: 2604 case CodecProfileLevel.HEVCProfileMain10HDR10: 2605 break; 2606 default: 2607 Log.w(TAG, "Unrecognized profile " 2608 + profileLevel.profile + " for " + mime); 2609 errors |= ERROR_UNRECOGNIZED; 2610 } 2611 2612 /* DPB logic: 2613 if (width * height <= FS / 4) DPB = 16; 2614 else if (width * height <= FS / 2) DPB = 12; 2615 else if (width * height <= FS * 0.75) DPB = 8; 2616 else DPB = 6; 2617 */ 2618 2619 FS >>= 6; // convert pixels to blocks 2620 errors &= ~ERROR_NONE_SUPPORTED; 2621 maxBlocksPerSecond = Math.max((int)(FR * FS), maxBlocksPerSecond); 2622 maxBlocks = Math.max(FS, maxBlocks); 2623 maxBps = Math.max(BR * 1000, maxBps); 2624 } 2625 2626 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8)); 2627 applyMacroBlockLimits( 2628 maxLengthInBlocks, maxLengthInBlocks, 2629 maxBlocks, maxBlocksPerSecond, 2630 8 /* blockWidth */, 8 /* blockHeight */, 2631 1 /* widthAlignment */, 1 /* heightAlignment */); 2632 } else { 2633 Log.w(TAG, "Unsupported mime " + mime); 2634 // using minimal bitrate here. should be overriden by 2635 // info from media_codecs.xml 2636 maxBps = 64000; 2637 errors |= ERROR_UNSUPPORTED; 2638 } 2639 mBitrateRange = Range.create(1, maxBps); 2640 mParent.mError |= errors; 2641 } 2642 } 2643 2644 /** 2645 * A class that supports querying the encoding capabilities of a codec. 2646 */ 2647 public static final class EncoderCapabilities { 2648 /** 2649 * Returns the supported range of quality values. 2650 * 2651 * Quality is implementation-specific. As a general rule, a higher quality 2652 * setting results in a better image quality and a lower compression ratio. 2653 */ getQualityRange()2654 public Range<Integer> getQualityRange() { 2655 return mQualityRange; 2656 } 2657 2658 /** 2659 * Returns the supported range of encoder complexity values. 2660 * <p> 2661 * Some codecs may support multiple complexity levels, where higher 2662 * complexity values use more encoder tools (e.g. perform more 2663 * intensive calculations) to improve the quality or the compression 2664 * ratio. Use a lower value to save power and/or time. 2665 */ getComplexityRange()2666 public Range<Integer> getComplexityRange() { 2667 return mComplexityRange; 2668 } 2669 2670 /** Constant quality mode */ 2671 public static final int BITRATE_MODE_CQ = 0; 2672 /** Variable bitrate mode */ 2673 public static final int BITRATE_MODE_VBR = 1; 2674 /** Constant bitrate mode */ 2675 public static final int BITRATE_MODE_CBR = 2; 2676 2677 private static final Feature[] bitrates = new Feature[] { 2678 new Feature("VBR", BITRATE_MODE_VBR, true), 2679 new Feature("CBR", BITRATE_MODE_CBR, false), 2680 new Feature("CQ", BITRATE_MODE_CQ, false) 2681 }; 2682 parseBitrateMode(String mode)2683 private static int parseBitrateMode(String mode) { 2684 for (Feature feat: bitrates) { 2685 if (feat.mName.equalsIgnoreCase(mode)) { 2686 return feat.mValue; 2687 } 2688 } 2689 return 0; 2690 } 2691 2692 /** 2693 * Query whether a bitrate mode is supported. 2694 */ isBitrateModeSupported(int mode)2695 public boolean isBitrateModeSupported(int mode) { 2696 for (Feature feat: bitrates) { 2697 if (mode == feat.mValue) { 2698 return (mBitControl & (1 << mode)) != 0; 2699 } 2700 } 2701 return false; 2702 } 2703 2704 private Range<Integer> mQualityRange; 2705 private Range<Integer> mComplexityRange; 2706 private CodecCapabilities mParent; 2707 2708 /* no public constructor */ EncoderCapabilities()2709 private EncoderCapabilities() { } 2710 2711 /** @hide */ create( MediaFormat info, CodecCapabilities parent)2712 public static EncoderCapabilities create( 2713 MediaFormat info, CodecCapabilities parent) { 2714 EncoderCapabilities caps = new EncoderCapabilities(); 2715 caps.init(info, parent); 2716 return caps; 2717 } 2718 init(MediaFormat info, CodecCapabilities parent)2719 private void init(MediaFormat info, CodecCapabilities parent) { 2720 // no support for complexity or quality yet 2721 mParent = parent; 2722 mComplexityRange = Range.create(0, 0); 2723 mQualityRange = Range.create(0, 0); 2724 mBitControl = (1 << BITRATE_MODE_VBR); 2725 2726 applyLevelLimits(); 2727 parseFromInfo(info); 2728 } 2729 applyLevelLimits()2730 private void applyLevelLimits() { 2731 String mime = mParent.getMimeType(); 2732 if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) { 2733 mComplexityRange = Range.create(0, 8); 2734 mBitControl = (1 << BITRATE_MODE_CQ); 2735 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB) 2736 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB) 2737 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW) 2738 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW) 2739 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) { 2740 mBitControl = (1 << BITRATE_MODE_CBR); 2741 } 2742 } 2743 2744 private int mBitControl; 2745 private Integer mDefaultComplexity; 2746 private Integer mDefaultQuality; 2747 private String mQualityScale; 2748 parseFromInfo(MediaFormat info)2749 private void parseFromInfo(MediaFormat info) { 2750 Map<String, Object> map = info.getMap(); 2751 2752 if (info.containsKey("complexity-range")) { 2753 mComplexityRange = Utils 2754 .parseIntRange(info.getString("complexity-range"), mComplexityRange); 2755 // TODO should we limit this to level limits? 2756 } 2757 if (info.containsKey("quality-range")) { 2758 mQualityRange = Utils 2759 .parseIntRange(info.getString("quality-range"), mQualityRange); 2760 } 2761 if (info.containsKey("feature-bitrate-modes")) { 2762 for (String mode: info.getString("feature-bitrate-modes").split(",")) { 2763 mBitControl |= (1 << parseBitrateMode(mode)); 2764 } 2765 } 2766 2767 try { 2768 mDefaultComplexity = Integer.parseInt((String)map.get("complexity-default")); 2769 } catch (NumberFormatException e) { } 2770 2771 try { 2772 mDefaultQuality = Integer.parseInt((String)map.get("quality-default")); 2773 } catch (NumberFormatException e) { } 2774 2775 mQualityScale = (String)map.get("quality-scale"); 2776 } 2777 supports( Integer complexity, Integer quality, Integer profile)2778 private boolean supports( 2779 Integer complexity, Integer quality, Integer profile) { 2780 boolean ok = true; 2781 if (ok && complexity != null) { 2782 ok = mComplexityRange.contains(complexity); 2783 } 2784 if (ok && quality != null) { 2785 ok = mQualityRange.contains(quality); 2786 } 2787 if (ok && profile != null) { 2788 for (CodecProfileLevel pl: mParent.profileLevels) { 2789 if (pl.profile == profile) { 2790 profile = null; 2791 break; 2792 } 2793 } 2794 ok = profile == null; 2795 } 2796 return ok; 2797 } 2798 2799 /** @hide */ getDefaultFormat(MediaFormat format)2800 public void getDefaultFormat(MediaFormat format) { 2801 // don't list trivial quality/complexity as default for now 2802 if (!mQualityRange.getUpper().equals(mQualityRange.getLower()) 2803 && mDefaultQuality != null) { 2804 format.setInteger(MediaFormat.KEY_QUALITY, mDefaultQuality); 2805 } 2806 if (!mComplexityRange.getUpper().equals(mComplexityRange.getLower()) 2807 && mDefaultComplexity != null) { 2808 format.setInteger(MediaFormat.KEY_COMPLEXITY, mDefaultComplexity); 2809 } 2810 // bitrates are listed in order of preference 2811 for (Feature feat: bitrates) { 2812 if ((mBitControl & (1 << feat.mValue)) != 0) { 2813 format.setInteger(MediaFormat.KEY_BITRATE_MODE, feat.mValue); 2814 break; 2815 } 2816 } 2817 } 2818 2819 /** @hide */ supportsFormat(MediaFormat format)2820 public boolean supportsFormat(MediaFormat format) { 2821 final Map<String, Object> map = format.getMap(); 2822 final String mime = mParent.getMimeType(); 2823 2824 Integer mode = (Integer)map.get(MediaFormat.KEY_BITRATE_MODE); 2825 if (mode != null && !isBitrateModeSupported(mode)) { 2826 return false; 2827 } 2828 2829 Integer complexity = (Integer)map.get(MediaFormat.KEY_COMPLEXITY); 2830 if (MediaFormat.MIMETYPE_AUDIO_FLAC.equalsIgnoreCase(mime)) { 2831 Integer flacComplexity = 2832 (Integer)map.get(MediaFormat.KEY_FLAC_COMPRESSION_LEVEL); 2833 if (complexity == null) { 2834 complexity = flacComplexity; 2835 } else if (flacComplexity != null && !complexity.equals(flacComplexity)) { 2836 throw new IllegalArgumentException( 2837 "conflicting values for complexity and " + 2838 "flac-compression-level"); 2839 } 2840 } 2841 2842 // other audio parameters 2843 Integer profile = (Integer)map.get(MediaFormat.KEY_PROFILE); 2844 if (MediaFormat.MIMETYPE_AUDIO_AAC.equalsIgnoreCase(mime)) { 2845 Integer aacProfile = (Integer)map.get(MediaFormat.KEY_AAC_PROFILE); 2846 if (profile == null) { 2847 profile = aacProfile; 2848 } else if (aacProfile != null && !aacProfile.equals(profile)) { 2849 throw new IllegalArgumentException( 2850 "conflicting values for profile and aac-profile"); 2851 } 2852 } 2853 2854 Integer quality = (Integer)map.get(MediaFormat.KEY_QUALITY); 2855 2856 return supports(complexity, quality, profile); 2857 } 2858 }; 2859 2860 /** 2861 * Encapsulates the profiles available for a codec component. 2862 * <p>You can get a set of {@link MediaCodecInfo.CodecProfileLevel} objects for a given 2863 * {@link MediaCodecInfo} object from the 2864 * {@link MediaCodecInfo.CodecCapabilities#profileLevels} field. 2865 */ 2866 public static final class CodecProfileLevel { 2867 // from OMX_VIDEO_AVCPROFILETYPE 2868 public static final int AVCProfileBaseline = 0x01; 2869 public static final int AVCProfileMain = 0x02; 2870 public static final int AVCProfileExtended = 0x04; 2871 public static final int AVCProfileHigh = 0x08; 2872 public static final int AVCProfileHigh10 = 0x10; 2873 public static final int AVCProfileHigh422 = 0x20; 2874 public static final int AVCProfileHigh444 = 0x40; 2875 public static final int AVCProfileConstrainedBaseline = 0x10000; 2876 public static final int AVCProfileConstrainedHigh = 0x80000; 2877 2878 // from OMX_VIDEO_AVCLEVELTYPE 2879 public static final int AVCLevel1 = 0x01; 2880 public static final int AVCLevel1b = 0x02; 2881 public static final int AVCLevel11 = 0x04; 2882 public static final int AVCLevel12 = 0x08; 2883 public static final int AVCLevel13 = 0x10; 2884 public static final int AVCLevel2 = 0x20; 2885 public static final int AVCLevel21 = 0x40; 2886 public static final int AVCLevel22 = 0x80; 2887 public static final int AVCLevel3 = 0x100; 2888 public static final int AVCLevel31 = 0x200; 2889 public static final int AVCLevel32 = 0x400; 2890 public static final int AVCLevel4 = 0x800; 2891 public static final int AVCLevel41 = 0x1000; 2892 public static final int AVCLevel42 = 0x2000; 2893 public static final int AVCLevel5 = 0x4000; 2894 public static final int AVCLevel51 = 0x8000; 2895 public static final int AVCLevel52 = 0x10000; 2896 2897 // from OMX_VIDEO_H263PROFILETYPE 2898 public static final int H263ProfileBaseline = 0x01; 2899 public static final int H263ProfileH320Coding = 0x02; 2900 public static final int H263ProfileBackwardCompatible = 0x04; 2901 public static final int H263ProfileISWV2 = 0x08; 2902 public static final int H263ProfileISWV3 = 0x10; 2903 public static final int H263ProfileHighCompression = 0x20; 2904 public static final int H263ProfileInternet = 0x40; 2905 public static final int H263ProfileInterlace = 0x80; 2906 public static final int H263ProfileHighLatency = 0x100; 2907 2908 // from OMX_VIDEO_H263LEVELTYPE 2909 public static final int H263Level10 = 0x01; 2910 public static final int H263Level20 = 0x02; 2911 public static final int H263Level30 = 0x04; 2912 public static final int H263Level40 = 0x08; 2913 public static final int H263Level45 = 0x10; 2914 public static final int H263Level50 = 0x20; 2915 public static final int H263Level60 = 0x40; 2916 public static final int H263Level70 = 0x80; 2917 2918 // from OMX_VIDEO_MPEG4PROFILETYPE 2919 public static final int MPEG4ProfileSimple = 0x01; 2920 public static final int MPEG4ProfileSimpleScalable = 0x02; 2921 public static final int MPEG4ProfileCore = 0x04; 2922 public static final int MPEG4ProfileMain = 0x08; 2923 public static final int MPEG4ProfileNbit = 0x10; 2924 public static final int MPEG4ProfileScalableTexture = 0x20; 2925 public static final int MPEG4ProfileSimpleFace = 0x40; 2926 public static final int MPEG4ProfileSimpleFBA = 0x80; 2927 public static final int MPEG4ProfileBasicAnimated = 0x100; 2928 public static final int MPEG4ProfileHybrid = 0x200; 2929 public static final int MPEG4ProfileAdvancedRealTime = 0x400; 2930 public static final int MPEG4ProfileCoreScalable = 0x800; 2931 public static final int MPEG4ProfileAdvancedCoding = 0x1000; 2932 public static final int MPEG4ProfileAdvancedCore = 0x2000; 2933 public static final int MPEG4ProfileAdvancedScalable = 0x4000; 2934 public static final int MPEG4ProfileAdvancedSimple = 0x8000; 2935 2936 // from OMX_VIDEO_MPEG4LEVELTYPE 2937 public static final int MPEG4Level0 = 0x01; 2938 public static final int MPEG4Level0b = 0x02; 2939 public static final int MPEG4Level1 = 0x04; 2940 public static final int MPEG4Level2 = 0x08; 2941 public static final int MPEG4Level3 = 0x10; 2942 public static final int MPEG4Level3b = 0x18; 2943 public static final int MPEG4Level4 = 0x20; 2944 public static final int MPEG4Level4a = 0x40; 2945 public static final int MPEG4Level5 = 0x80; 2946 public static final int MPEG4Level6 = 0x100; 2947 2948 // from OMX_VIDEO_MPEG2PROFILETYPE 2949 public static final int MPEG2ProfileSimple = 0x00; 2950 public static final int MPEG2ProfileMain = 0x01; 2951 public static final int MPEG2Profile422 = 0x02; 2952 public static final int MPEG2ProfileSNR = 0x03; 2953 public static final int MPEG2ProfileSpatial = 0x04; 2954 public static final int MPEG2ProfileHigh = 0x05; 2955 2956 // from OMX_VIDEO_MPEG2LEVELTYPE 2957 public static final int MPEG2LevelLL = 0x00; 2958 public static final int MPEG2LevelML = 0x01; 2959 public static final int MPEG2LevelH14 = 0x02; 2960 public static final int MPEG2LevelHL = 0x03; 2961 public static final int MPEG2LevelHP = 0x04; 2962 2963 // from OMX_AUDIO_AACPROFILETYPE 2964 public static final int AACObjectMain = 1; 2965 public static final int AACObjectLC = 2; 2966 public static final int AACObjectSSR = 3; 2967 public static final int AACObjectLTP = 4; 2968 public static final int AACObjectHE = 5; 2969 public static final int AACObjectScalable = 6; 2970 public static final int AACObjectERLC = 17; 2971 public static final int AACObjectERScalable = 20; 2972 public static final int AACObjectLD = 23; 2973 public static final int AACObjectHE_PS = 29; 2974 public static final int AACObjectELD = 39; 2975 /** xHE-AAC (includes USAC) */ 2976 public static final int AACObjectXHE = 42; 2977 2978 // from OMX_VIDEO_VP8LEVELTYPE 2979 public static final int VP8Level_Version0 = 0x01; 2980 public static final int VP8Level_Version1 = 0x02; 2981 public static final int VP8Level_Version2 = 0x04; 2982 public static final int VP8Level_Version3 = 0x08; 2983 2984 // from OMX_VIDEO_VP8PROFILETYPE 2985 public static final int VP8ProfileMain = 0x01; 2986 2987 // from OMX_VIDEO_VP9PROFILETYPE 2988 public static final int VP9Profile0 = 0x01; 2989 public static final int VP9Profile1 = 0x02; 2990 public static final int VP9Profile2 = 0x04; 2991 public static final int VP9Profile3 = 0x08; 2992 // HDR profiles also support passing HDR metadata 2993 public static final int VP9Profile2HDR = 0x1000; 2994 public static final int VP9Profile3HDR = 0x2000; 2995 2996 // from OMX_VIDEO_VP9LEVELTYPE 2997 public static final int VP9Level1 = 0x1; 2998 public static final int VP9Level11 = 0x2; 2999 public static final int VP9Level2 = 0x4; 3000 public static final int VP9Level21 = 0x8; 3001 public static final int VP9Level3 = 0x10; 3002 public static final int VP9Level31 = 0x20; 3003 public static final int VP9Level4 = 0x40; 3004 public static final int VP9Level41 = 0x80; 3005 public static final int VP9Level5 = 0x100; 3006 public static final int VP9Level51 = 0x200; 3007 public static final int VP9Level52 = 0x400; 3008 public static final int VP9Level6 = 0x800; 3009 public static final int VP9Level61 = 0x1000; 3010 public static final int VP9Level62 = 0x2000; 3011 3012 // from OMX_VIDEO_HEVCPROFILETYPE 3013 public static final int HEVCProfileMain = 0x01; 3014 public static final int HEVCProfileMain10 = 0x02; 3015 public static final int HEVCProfileMainStill = 0x04; 3016 public static final int HEVCProfileMain10HDR10 = 0x1000; 3017 3018 // from OMX_VIDEO_HEVCLEVELTYPE 3019 public static final int HEVCMainTierLevel1 = 0x1; 3020 public static final int HEVCHighTierLevel1 = 0x2; 3021 public static final int HEVCMainTierLevel2 = 0x4; 3022 public static final int HEVCHighTierLevel2 = 0x8; 3023 public static final int HEVCMainTierLevel21 = 0x10; 3024 public static final int HEVCHighTierLevel21 = 0x20; 3025 public static final int HEVCMainTierLevel3 = 0x40; 3026 public static final int HEVCHighTierLevel3 = 0x80; 3027 public static final int HEVCMainTierLevel31 = 0x100; 3028 public static final int HEVCHighTierLevel31 = 0x200; 3029 public static final int HEVCMainTierLevel4 = 0x400; 3030 public static final int HEVCHighTierLevel4 = 0x800; 3031 public static final int HEVCMainTierLevel41 = 0x1000; 3032 public static final int HEVCHighTierLevel41 = 0x2000; 3033 public static final int HEVCMainTierLevel5 = 0x4000; 3034 public static final int HEVCHighTierLevel5 = 0x8000; 3035 public static final int HEVCMainTierLevel51 = 0x10000; 3036 public static final int HEVCHighTierLevel51 = 0x20000; 3037 public static final int HEVCMainTierLevel52 = 0x40000; 3038 public static final int HEVCHighTierLevel52 = 0x80000; 3039 public static final int HEVCMainTierLevel6 = 0x100000; 3040 public static final int HEVCHighTierLevel6 = 0x200000; 3041 public static final int HEVCMainTierLevel61 = 0x400000; 3042 public static final int HEVCHighTierLevel61 = 0x800000; 3043 public static final int HEVCMainTierLevel62 = 0x1000000; 3044 public static final int HEVCHighTierLevel62 = 0x2000000; 3045 3046 private static final int HEVCHighTierLevels = 3047 HEVCHighTierLevel1 | HEVCHighTierLevel2 | HEVCHighTierLevel21 | HEVCHighTierLevel3 | 3048 HEVCHighTierLevel31 | HEVCHighTierLevel4 | HEVCHighTierLevel41 | HEVCHighTierLevel5 | 3049 HEVCHighTierLevel51 | HEVCHighTierLevel52 | HEVCHighTierLevel6 | HEVCHighTierLevel61 | 3050 HEVCHighTierLevel62; 3051 3052 // from OMX_VIDEO_DOLBYVISIONPROFILETYPE 3053 public static final int DolbyVisionProfileDvavPer = 0x1; 3054 public static final int DolbyVisionProfileDvavPen = 0x2; 3055 public static final int DolbyVisionProfileDvheDer = 0x4; 3056 public static final int DolbyVisionProfileDvheDen = 0x8; 3057 public static final int DolbyVisionProfileDvheDtr = 0x10; 3058 public static final int DolbyVisionProfileDvheStn = 0x20; 3059 public static final int DolbyVisionProfileDvheDth = 0x40; 3060 public static final int DolbyVisionProfileDvheDtb = 0x80; 3061 public static final int DolbyVisionProfileDvheSt = 0x100; 3062 public static final int DolbyVisionProfileDvavSe = 0x200; 3063 3064 // from OMX_VIDEO_DOLBYVISIONLEVELTYPE 3065 public static final int DolbyVisionLevelHd24 = 0x1; 3066 public static final int DolbyVisionLevelHd30 = 0x2; 3067 public static final int DolbyVisionLevelFhd24 = 0x4; 3068 public static final int DolbyVisionLevelFhd30 = 0x8; 3069 public static final int DolbyVisionLevelFhd60 = 0x10; 3070 public static final int DolbyVisionLevelUhd24 = 0x20; 3071 public static final int DolbyVisionLevelUhd30 = 0x40; 3072 public static final int DolbyVisionLevelUhd48 = 0x80; 3073 public static final int DolbyVisionLevelUhd60 = 0x100; 3074 3075 /** 3076 * Defined in the OpenMAX IL specs, depending on the type of media 3077 * this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE, 3078 * OMX_VIDEO_MPEG4PROFILETYPE, OMX_VIDEO_VP8PROFILETYPE or OMX_VIDEO_VP9PROFILETYPE. 3079 */ 3080 public int profile; 3081 3082 /** 3083 * Defined in the OpenMAX IL specs, depending on the type of media 3084 * this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE 3085 * OMX_VIDEO_MPEG4LEVELTYPE, OMX_VIDEO_VP8LEVELTYPE or OMX_VIDEO_VP9LEVELTYPE. 3086 * 3087 * Note that VP9 decoder on platforms before {@link android.os.Build.VERSION_CODES#N} may 3088 * not advertise a profile level support. For those VP9 decoders, please use 3089 * {@link VideoCapabilities} to determine the codec capabilities. 3090 */ 3091 public int level; 3092 3093 @Override equals(Object obj)3094 public boolean equals(Object obj) { 3095 if (obj == null) { 3096 return false; 3097 } 3098 if (obj instanceof CodecProfileLevel) { 3099 CodecProfileLevel other = (CodecProfileLevel)obj; 3100 return other.profile == profile && other.level == level; 3101 } 3102 return false; 3103 } 3104 3105 @Override hashCode()3106 public int hashCode() { 3107 return Long.hashCode(((long)profile << Integer.SIZE) | level); 3108 } 3109 }; 3110 3111 /** 3112 * Enumerates the capabilities of the codec component. Since a single 3113 * component can support data of a variety of types, the type has to be 3114 * specified to yield a meaningful result. 3115 * @param type The MIME type to query 3116 */ getCapabilitiesForType( String type)3117 public final CodecCapabilities getCapabilitiesForType( 3118 String type) { 3119 CodecCapabilities caps = mCaps.get(type); 3120 if (caps == null) { 3121 throw new IllegalArgumentException("codec does not support type"); 3122 } 3123 // clone writable object 3124 return caps.dup(); 3125 } 3126 3127 /** @hide */ makeRegular()3128 public MediaCodecInfo makeRegular() { 3129 ArrayList<CodecCapabilities> caps = new ArrayList<CodecCapabilities>(); 3130 for (CodecCapabilities c: mCaps.values()) { 3131 if (c.isRegular()) { 3132 caps.add(c); 3133 } 3134 } 3135 if (caps.size() == 0) { 3136 return null; 3137 } else if (caps.size() == mCaps.size()) { 3138 return this; 3139 } 3140 3141 return new MediaCodecInfo( 3142 mName, mIsEncoder, 3143 caps.toArray(new CodecCapabilities[caps.size()])); 3144 } 3145 } 3146