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