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 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 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 */ 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 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 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 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 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 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 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 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 */ 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 */ 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 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 */ 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 */ 3482 private EncoderCapabilities() { } 3483 3484 /** @hide */ 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 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 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 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 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 */ 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 */ 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 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 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 */ 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 */ 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