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