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