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