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 // We must remove the profile from this format otherwise levelCaps.isFormatSupported 938 // will get into this same condition and loop forever. Furthermore, since levelCaps 939 // does not contain features and bitrate specific keys, keep only keys relevant for 940 // a level check. 941 Map<String, Object> levelCriticalFormatMap = new HashMap<>(map); 942 final Set<String> criticalKeys = 943 isVideo() ? VideoCapabilities.VIDEO_LEVEL_CRITICAL_FORMAT_KEYS : 944 isAudio() ? AudioCapabilities.AUDIO_LEVEL_CRITICAL_FORMAT_KEYS : 945 null; 946 947 // critical keys will always contain KEY_MIME, but should also contain others to be 948 // meaningful 949 if (criticalKeys != null && criticalKeys.size() > 1 && levelCaps != null) { 950 levelCriticalFormatMap.keySet().retainAll(criticalKeys); 951 952 MediaFormat levelCriticalFormat = new MediaFormat(levelCriticalFormatMap); 953 if (!levelCaps.isFormatSupported(levelCriticalFormat)) { 954 return false; 955 } 956 } 957 } 958 if (mAudioCaps != null && !mAudioCaps.supportsFormat(format)) { 959 return false; 960 } 961 if (mVideoCaps != null && !mVideoCaps.supportsFormat(format)) { 962 return false; 963 } 964 if (mEncoderCaps != null && !mEncoderCaps.supportsFormat(format)) { 965 return false; 966 } 967 return true; 968 } 969 supportsBitrate( Range<Integer> bitrateRange, MediaFormat format)970 private static boolean supportsBitrate( 971 Range<Integer> bitrateRange, MediaFormat format) { 972 Map<String, Object> map = format.getMap(); 973 974 // consider max bitrate over average bitrate for support 975 Integer maxBitrate = (Integer)map.get(MediaFormat.KEY_MAX_BIT_RATE); 976 Integer bitrate = (Integer)map.get(MediaFormat.KEY_BIT_RATE); 977 if (bitrate == null) { 978 bitrate = maxBitrate; 979 } else if (maxBitrate != null) { 980 bitrate = Math.max(bitrate, maxBitrate); 981 } 982 983 if (bitrate != null && bitrate > 0) { 984 return bitrateRange.contains(bitrate); 985 } 986 987 return true; 988 } 989 supportsProfileLevel(int profile, Integer level)990 private boolean supportsProfileLevel(int profile, Integer level) { 991 for (CodecProfileLevel pl: profileLevels) { 992 if (pl.profile != profile) { 993 continue; 994 } 995 996 // No specific level requested 997 if (level == null) { 998 return true; 999 } 1000 1001 // AAC doesn't use levels 1002 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC)) { 1003 return true; 1004 } 1005 1006 // DTS doesn't use levels 1007 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_DTS) 1008 || mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_DTS_HD) 1009 || mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_DTS_UHD)) { 1010 return true; 1011 } 1012 1013 // H.263 levels are not completely ordered: 1014 // Level45 support only implies Level10 support 1015 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) { 1016 if (pl.level != level && pl.level == CodecProfileLevel.H263Level45 1017 && level > CodecProfileLevel.H263Level10) { 1018 continue; 1019 } 1020 } 1021 1022 // MPEG4 levels are not completely ordered: 1023 // Level1 support only implies Level0 (and not Level0b) support 1024 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) { 1025 if (pl.level != level && pl.level == CodecProfileLevel.MPEG4Level1 1026 && level > CodecProfileLevel.MPEG4Level0) { 1027 continue; 1028 } 1029 } 1030 1031 // HEVC levels incorporate both tiers and levels. Verify tier support. 1032 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) { 1033 boolean supportsHighTier = 1034 (pl.level & CodecProfileLevel.HEVCHighTierLevels) != 0; 1035 boolean checkingHighTier = (level & CodecProfileLevel.HEVCHighTierLevels) != 0; 1036 // high tier levels are only supported by other high tier levels 1037 if (checkingHighTier && !supportsHighTier) { 1038 continue; 1039 } 1040 } 1041 1042 if (pl.level >= level) { 1043 // if we recognize the listed profile/level, we must also recognize the 1044 // profile/level arguments. 1045 if (createFromProfileLevel(mMime, profile, pl.level) != null) { 1046 return createFromProfileLevel(mMime, profile, level) != null; 1047 } 1048 return true; 1049 } 1050 } 1051 return false; 1052 } 1053 1054 // errors while reading profile levels - accessed from sister capabilities 1055 int mError; 1056 1057 private static final String TAG = "CodecCapabilities"; 1058 1059 // NEW-STYLE CAPABILITIES 1060 private AudioCapabilities mAudioCaps; 1061 private VideoCapabilities mVideoCaps; 1062 private EncoderCapabilities mEncoderCaps; 1063 private MediaFormat mDefaultFormat; 1064 1065 /** 1066 * Returns a MediaFormat object with default values for configurations that have 1067 * defaults. 1068 */ getDefaultFormat()1069 public MediaFormat getDefaultFormat() { 1070 return mDefaultFormat; 1071 } 1072 1073 /** 1074 * Returns the mime type for which this codec-capability object was created. 1075 */ getMimeType()1076 public String getMimeType() { 1077 return mMime; 1078 } 1079 1080 /** 1081 * Returns the max number of the supported concurrent codec instances. 1082 * <p> 1083 * This is a hint for an upper bound. Applications should not expect to successfully 1084 * operate more instances than the returned value, but the actual number of 1085 * concurrently operable instances may be less as it depends on the available 1086 * resources at time of use. 1087 */ getMaxSupportedInstances()1088 public int getMaxSupportedInstances() { 1089 return mMaxSupportedInstances; 1090 } 1091 isAudio()1092 private boolean isAudio() { 1093 return mAudioCaps != null; 1094 } 1095 1096 /** 1097 * Returns the audio capabilities or {@code null} if this is not an audio codec. 1098 */ getAudioCapabilities()1099 public AudioCapabilities getAudioCapabilities() { 1100 return mAudioCaps; 1101 } 1102 isEncoder()1103 private boolean isEncoder() { 1104 return mEncoderCaps != null; 1105 } 1106 1107 /** 1108 * Returns the encoding capabilities or {@code null} if this is not an encoder. 1109 */ getEncoderCapabilities()1110 public EncoderCapabilities getEncoderCapabilities() { 1111 return mEncoderCaps; 1112 } 1113 isVideo()1114 private boolean isVideo() { 1115 return mVideoCaps != null; 1116 } 1117 1118 /** 1119 * Returns the video capabilities or {@code null} if this is not a video codec. 1120 */ getVideoCapabilities()1121 public VideoCapabilities getVideoCapabilities() { 1122 return mVideoCaps; 1123 } 1124 1125 /** @hide */ dup()1126 public CodecCapabilities dup() { 1127 CodecCapabilities caps = new CodecCapabilities(); 1128 1129 // profileLevels and colorFormats may be modified by client. 1130 caps.profileLevels = Arrays.copyOf(profileLevels, profileLevels.length); 1131 caps.colorFormats = Arrays.copyOf(colorFormats, colorFormats.length); 1132 1133 caps.mMime = mMime; 1134 caps.mMaxSupportedInstances = mMaxSupportedInstances; 1135 caps.mFlagsRequired = mFlagsRequired; 1136 caps.mFlagsSupported = mFlagsSupported; 1137 caps.mFlagsVerified = mFlagsVerified; 1138 caps.mAudioCaps = mAudioCaps; 1139 caps.mVideoCaps = mVideoCaps; 1140 caps.mEncoderCaps = mEncoderCaps; 1141 caps.mDefaultFormat = mDefaultFormat; 1142 caps.mCapabilitiesInfo = mCapabilitiesInfo; 1143 1144 return caps; 1145 } 1146 1147 /** 1148 * Retrieve the codec capabilities for a certain {@code mime type}, {@code 1149 * profile} and {@code level}. If the type, or profile-level combination 1150 * is not understood by the framework, it returns null. 1151 * <p class=note> In {@link android.os.Build.VERSION_CODES#M}, calling this 1152 * method without calling any method of the {@link MediaCodecList} class beforehand 1153 * results in a {@link NullPointerException}.</p> 1154 */ createFromProfileLevel( String mime, int profile, int level)1155 public static CodecCapabilities createFromProfileLevel( 1156 String mime, int profile, int level) { 1157 CodecProfileLevel pl = new CodecProfileLevel(); 1158 pl.profile = profile; 1159 pl.level = level; 1160 MediaFormat defaultFormat = new MediaFormat(); 1161 defaultFormat.setString(MediaFormat.KEY_MIME, mime); 1162 1163 CodecCapabilities ret = new CodecCapabilities( 1164 new CodecProfileLevel[] { pl }, new int[0], true /* encoder */, 1165 defaultFormat, new MediaFormat() /* info */); 1166 if (ret.mError != 0) { 1167 return null; 1168 } 1169 return ret; 1170 } 1171 CodecCapabilities( CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, Map<String, Object>defaultFormatMap, Map<String, Object>capabilitiesMap)1172 /* package private */ CodecCapabilities( 1173 CodecProfileLevel[] profLevs, int[] colFmts, 1174 boolean encoder, 1175 Map<String, Object>defaultFormatMap, 1176 Map<String, Object>capabilitiesMap) { 1177 this(profLevs, colFmts, encoder, 1178 new MediaFormat(defaultFormatMap), 1179 new MediaFormat(capabilitiesMap)); 1180 } 1181 1182 private MediaFormat mCapabilitiesInfo; 1183 CodecCapabilities( CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, MediaFormat defaultFormat, MediaFormat info)1184 /* package private */ CodecCapabilities( 1185 CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, 1186 MediaFormat defaultFormat, MediaFormat info) { 1187 final Map<String, Object> map = info.getMap(); 1188 colorFormats = colFmts; 1189 mFlagsVerified = 0; // TODO: remove as it is unused 1190 mDefaultFormat = defaultFormat; 1191 mCapabilitiesInfo = info; 1192 mMime = mDefaultFormat.getString(MediaFormat.KEY_MIME); 1193 1194 /* VP9 introduced profiles around 2016, so some VP9 codecs may not advertise any 1195 supported profiles. Determine the level for them using the info they provide. */ 1196 if (profLevs.length == 0 && mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) { 1197 CodecProfileLevel profLev = new CodecProfileLevel(); 1198 profLev.profile = CodecProfileLevel.VP9Profile0; 1199 profLev.level = VideoCapabilities.equivalentVP9Level(info); 1200 profLevs = new CodecProfileLevel[] { profLev }; 1201 } 1202 profileLevels = profLevs; 1203 1204 if (mMime.toLowerCase().startsWith("audio/")) { 1205 mAudioCaps = AudioCapabilities.create(info, this); 1206 mAudioCaps.getDefaultFormat(mDefaultFormat); 1207 } else if (mMime.toLowerCase().startsWith("video/") 1208 || mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC)) { 1209 mVideoCaps = VideoCapabilities.create(info, this); 1210 } 1211 if (encoder) { 1212 mEncoderCaps = EncoderCapabilities.create(info, this); 1213 mEncoderCaps.getDefaultFormat(mDefaultFormat); 1214 } 1215 1216 final Map<String, Object> global = MediaCodecList.getGlobalSettings(); 1217 mMaxSupportedInstances = Utils.parseIntSafely( 1218 global.get("max-concurrent-instances"), DEFAULT_MAX_SUPPORTED_INSTANCES); 1219 1220 int maxInstances = Utils.parseIntSafely( 1221 map.get("max-concurrent-instances"), mMaxSupportedInstances); 1222 mMaxSupportedInstances = 1223 Range.create(1, MAX_SUPPORTED_INSTANCES_LIMIT).clamp(maxInstances); 1224 1225 for (Feature feat: getValidFeatures()) { 1226 String key = MediaFormat.KEY_FEATURE_ + feat.mName; 1227 Integer yesNo = (Integer)map.get(key); 1228 if (yesNo == null) { 1229 continue; 1230 } 1231 if (yesNo > 0) { 1232 mFlagsRequired |= feat.mValue; 1233 } 1234 mFlagsSupported |= feat.mValue; 1235 if (!feat.mInternal) { 1236 mDefaultFormat.setInteger(key, 1); 1237 } 1238 // TODO restrict features by mFlagsVerified once all codecs reliably verify them 1239 } 1240 } 1241 } 1242 1243 /** 1244 * A class that supports querying the audio capabilities of a codec. 1245 */ 1246 public static final class AudioCapabilities { 1247 private static final String TAG = "AudioCapabilities"; 1248 private CodecCapabilities mParent; 1249 private Range<Integer> mBitrateRange; 1250 1251 private int[] mSampleRates; 1252 private Range<Integer>[] mSampleRateRanges; 1253 private Range<Integer>[] mInputChannelRanges; 1254 1255 private static final int MAX_INPUT_CHANNEL_COUNT = 30; 1256 1257 /** 1258 * Returns the range of supported bitrates in bits/second. 1259 */ getBitrateRange()1260 public Range<Integer> getBitrateRange() { 1261 return mBitrateRange; 1262 } 1263 1264 /** 1265 * Returns the array of supported sample rates if the codec 1266 * supports only discrete values. Otherwise, it returns 1267 * {@code null}. The array is sorted in ascending order. 1268 */ getSupportedSampleRates()1269 public int[] getSupportedSampleRates() { 1270 return mSampleRates != null ? Arrays.copyOf(mSampleRates, mSampleRates.length) : null; 1271 } 1272 1273 /** 1274 * Returns the array of supported sample rate ranges. The 1275 * array is sorted in ascending order, and the ranges are 1276 * distinct. 1277 */ getSupportedSampleRateRanges()1278 public Range<Integer>[] getSupportedSampleRateRanges() { 1279 return Arrays.copyOf(mSampleRateRanges, mSampleRateRanges.length); 1280 } 1281 1282 /** 1283 * Returns the maximum number of input channels supported. 1284 * 1285 * Through {@link android.os.Build.VERSION_CODES#R}, this method indicated support 1286 * for any number of input channels between 1 and this maximum value. 1287 * 1288 * As of {@link android.os.Build.VERSION_CODES#S}, 1289 * the implied lower limit of 1 channel is no longer valid. 1290 * As of {@link android.os.Build.VERSION_CODES#S}, {@link #getMaxInputChannelCount} is 1291 * superseded by {@link #getInputChannelCountRanges}, 1292 * which returns an array of ranges of channels. 1293 * The {@link #getMaxInputChannelCount} method will return the highest value 1294 * in the ranges returned by {@link #getInputChannelCountRanges} 1295 * 1296 */ 1297 @IntRange(from = 1, to = 255) getMaxInputChannelCount()1298 public int getMaxInputChannelCount() { 1299 int overall_max = 0; 1300 for (int i = mInputChannelRanges.length - 1; i >= 0; i--) { 1301 int lmax = mInputChannelRanges[i].getUpper(); 1302 if (lmax > overall_max) { 1303 overall_max = lmax; 1304 } 1305 } 1306 return overall_max; 1307 } 1308 1309 /** 1310 * Returns the minimum number of input channels supported. 1311 * This is often 1, but does vary for certain mime types. 1312 * 1313 * This returns the lowest channel count in the ranges returned by 1314 * {@link #getInputChannelCountRanges}. 1315 */ 1316 @IntRange(from = 1, to = 255) getMinInputChannelCount()1317 public int getMinInputChannelCount() { 1318 int overall_min = MAX_INPUT_CHANNEL_COUNT; 1319 for (int i = mInputChannelRanges.length - 1; i >= 0; i--) { 1320 int lmin = mInputChannelRanges[i].getLower(); 1321 if (lmin < overall_min) { 1322 overall_min = lmin; 1323 } 1324 } 1325 return overall_min; 1326 } 1327 1328 /* 1329 * Returns an array of ranges representing the number of input channels supported. 1330 * The codec supports any number of input channels within this range. 1331 * 1332 * This supersedes the {@link #getMaxInputChannelCount} method. 1333 * 1334 * For many codecs, this will be a single range [1..N], for some N. 1335 */ 1336 @SuppressLint("ArrayReturn") 1337 @NonNull getInputChannelCountRanges()1338 public Range<Integer>[] getInputChannelCountRanges() { 1339 return Arrays.copyOf(mInputChannelRanges, mInputChannelRanges.length); 1340 } 1341 1342 /* no public constructor */ AudioCapabilities()1343 private AudioCapabilities() { } 1344 1345 /** @hide */ create( MediaFormat info, CodecCapabilities parent)1346 public static AudioCapabilities create( 1347 MediaFormat info, CodecCapabilities parent) { 1348 AudioCapabilities caps = new AudioCapabilities(); 1349 caps.init(info, parent); 1350 return caps; 1351 } 1352 init(MediaFormat info, CodecCapabilities parent)1353 private void init(MediaFormat info, CodecCapabilities parent) { 1354 mParent = parent; 1355 initWithPlatformLimits(); 1356 applyLevelLimits(); 1357 parseFromInfo(info); 1358 } 1359 initWithPlatformLimits()1360 private void initWithPlatformLimits() { 1361 mBitrateRange = Range.create(0, Integer.MAX_VALUE); 1362 mInputChannelRanges = new Range[] {Range.create(1, MAX_INPUT_CHANNEL_COUNT)}; 1363 // mBitrateRange = Range.create(1, 320000); 1364 final int minSampleRate = SystemProperties. 1365 getInt("ro.mediacodec.min_sample_rate", 7350); 1366 final int maxSampleRate = SystemProperties. 1367 getInt("ro.mediacodec.max_sample_rate", 192000); 1368 mSampleRateRanges = new Range[] { Range.create(minSampleRate, maxSampleRate) }; 1369 mSampleRates = null; 1370 } 1371 supports(Integer sampleRate, Integer inputChannels)1372 private boolean supports(Integer sampleRate, Integer inputChannels) { 1373 // channels and sample rates are checked orthogonally 1374 if (inputChannels != null) { 1375 int ix = Utils.binarySearchDistinctRanges( 1376 mInputChannelRanges, inputChannels); 1377 if (ix < 0) { 1378 return false; 1379 } 1380 } 1381 if (sampleRate != null) { 1382 int ix = Utils.binarySearchDistinctRanges( 1383 mSampleRateRanges, sampleRate); 1384 if (ix < 0) { 1385 return false; 1386 } 1387 } 1388 return true; 1389 } 1390 1391 /** 1392 * Query whether the sample rate is supported by the codec. 1393 */ isSampleRateSupported(int sampleRate)1394 public boolean isSampleRateSupported(int sampleRate) { 1395 return supports(sampleRate, null); 1396 } 1397 1398 /** modifies rates */ limitSampleRates(int[] rates)1399 private void limitSampleRates(int[] rates) { 1400 Arrays.sort(rates); 1401 ArrayList<Range<Integer>> ranges = new ArrayList<Range<Integer>>(); 1402 for (int rate: rates) { 1403 if (supports(rate, null /* channels */)) { 1404 ranges.add(Range.create(rate, rate)); 1405 } 1406 } 1407 mSampleRateRanges = ranges.toArray(new Range[ranges.size()]); 1408 createDiscreteSampleRates(); 1409 } 1410 createDiscreteSampleRates()1411 private void createDiscreteSampleRates() { 1412 mSampleRates = new int[mSampleRateRanges.length]; 1413 for (int i = 0; i < mSampleRateRanges.length; i++) { 1414 mSampleRates[i] = mSampleRateRanges[i].getLower(); 1415 } 1416 } 1417 1418 /** modifies rateRanges */ limitSampleRates(Range<Integer>[] rateRanges)1419 private void limitSampleRates(Range<Integer>[] rateRanges) { 1420 sortDistinctRanges(rateRanges); 1421 mSampleRateRanges = intersectSortedDistinctRanges(mSampleRateRanges, rateRanges); 1422 1423 // check if all values are discrete 1424 for (Range<Integer> range: mSampleRateRanges) { 1425 if (!range.getLower().equals(range.getUpper())) { 1426 mSampleRates = null; 1427 return; 1428 } 1429 } 1430 createDiscreteSampleRates(); 1431 } 1432 applyLevelLimits()1433 private void applyLevelLimits() { 1434 int[] sampleRates = null; 1435 Range<Integer> sampleRateRange = null, bitRates = null; 1436 int maxChannels = MAX_INPUT_CHANNEL_COUNT; 1437 CodecProfileLevel[] profileLevels = mParent.profileLevels; 1438 String mime = mParent.getMimeType(); 1439 1440 if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MPEG)) { 1441 sampleRates = new int[] { 1442 8000, 11025, 12000, 1443 16000, 22050, 24000, 1444 32000, 44100, 48000 }; 1445 bitRates = Range.create(8000, 320000); 1446 maxChannels = 2; 1447 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)) { 1448 sampleRates = new int[] { 8000 }; 1449 bitRates = Range.create(4750, 12200); 1450 maxChannels = 1; 1451 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)) { 1452 sampleRates = new int[] { 16000 }; 1453 bitRates = Range.create(6600, 23850); 1454 maxChannels = 1; 1455 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC)) { 1456 sampleRates = new int[] { 1457 7350, 8000, 1458 11025, 12000, 16000, 1459 22050, 24000, 32000, 1460 44100, 48000, 64000, 1461 88200, 96000 }; 1462 bitRates = Range.create(8000, 510000); 1463 maxChannels = 48; 1464 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_VORBIS)) { 1465 bitRates = Range.create(32000, 500000); 1466 sampleRateRange = Range.create(8000, 192000); 1467 maxChannels = 255; 1468 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_OPUS)) { 1469 bitRates = Range.create(6000, 510000); 1470 sampleRates = new int[] { 8000, 12000, 16000, 24000, 48000 }; 1471 maxChannels = 255; 1472 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW)) { 1473 sampleRateRange = Range.create(1, 192000); 1474 bitRates = Range.create(1, 10000000); 1475 maxChannels = AudioSystem.OUT_CHANNEL_COUNT_MAX; 1476 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) { 1477 sampleRateRange = Range.create(1, 655350); 1478 // lossless codec, so bitrate is ignored 1479 maxChannels = 255; 1480 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW) 1481 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)) { 1482 sampleRates = new int[] { 8000 }; 1483 bitRates = Range.create(64000, 64000); 1484 // platform allows multiple channels for this format 1485 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) { 1486 sampleRates = new int[] { 8000 }; 1487 bitRates = Range.create(13000, 13000); 1488 maxChannels = 1; 1489 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AC3)) { 1490 maxChannels = 6; 1491 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_EAC3)) { 1492 maxChannels = 16; 1493 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_EAC3_JOC)) { 1494 sampleRates = new int[] { 48000 }; 1495 bitRates = Range.create(32000, 6144000); 1496 maxChannels = 16; 1497 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AC4)) { 1498 sampleRates = new int[] { 44100, 48000, 96000, 192000 }; 1499 bitRates = Range.create(16000, 2688000); 1500 maxChannels = 24; 1501 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_DTS)) { 1502 sampleRates = new int[] { 44100, 48000 }; 1503 bitRates = Range.create(96000, 1524000); 1504 maxChannels = 6; 1505 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_DTS_HD)) { 1506 for (CodecProfileLevel profileLevel: profileLevels) { 1507 switch (profileLevel.profile) { 1508 case CodecProfileLevel.DTS_HDProfileLBR: 1509 sampleRates = new int[]{ 22050, 24000, 44100, 48000 }; 1510 bitRates = Range.create(32000, 768000); 1511 break; 1512 case CodecProfileLevel.DTS_HDProfileHRA: 1513 case CodecProfileLevel.DTS_HDProfileMA: 1514 sampleRates = new int[]{ 44100, 48000, 88200, 96000, 176400, 192000 }; 1515 bitRates = Range.create(96000, 24500000); 1516 break; 1517 default: 1518 Log.w(TAG, "Unrecognized profile " 1519 + profileLevel.profile + " for " + mime); 1520 mParent.mError |= ERROR_UNRECOGNIZED; 1521 sampleRates = new int[]{ 44100, 48000, 88200, 96000, 176400, 192000 }; 1522 bitRates = Range.create(96000, 24500000); 1523 } 1524 } 1525 maxChannels = 8; 1526 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_DTS_UHD)) { 1527 for (CodecProfileLevel profileLevel: profileLevels) { 1528 switch (profileLevel.profile) { 1529 case CodecProfileLevel.DTS_UHDProfileP2: 1530 sampleRates = new int[]{ 48000 }; 1531 bitRates = Range.create(96000, 768000); 1532 maxChannels = 10; 1533 break; 1534 case CodecProfileLevel.DTS_UHDProfileP1: 1535 sampleRates = new int[]{ 44100, 48000, 88200, 96000, 176400, 192000 }; 1536 bitRates = Range.create(96000, 24500000); 1537 maxChannels = 32; 1538 break; 1539 default: 1540 Log.w(TAG, "Unrecognized profile " 1541 + profileLevel.profile + " for " + mime); 1542 mParent.mError |= ERROR_UNRECOGNIZED; 1543 sampleRates = new int[]{ 44100, 48000, 88200, 96000, 176400, 192000 }; 1544 bitRates = Range.create(96000, 24500000); 1545 maxChannels = 32; 1546 } 1547 } 1548 } else { 1549 Log.w(TAG, "Unsupported mime " + mime); 1550 mParent.mError |= ERROR_UNSUPPORTED; 1551 } 1552 1553 // restrict ranges 1554 if (sampleRates != null) { 1555 limitSampleRates(sampleRates); 1556 } else if (sampleRateRange != null) { 1557 limitSampleRates(new Range[] { sampleRateRange }); 1558 } 1559 1560 Range<Integer> channelRange = Range.create(1, maxChannels); 1561 1562 applyLimits(new Range[] { channelRange }, bitRates); 1563 } 1564 applyLimits(Range<Integer>[] inputChannels, Range<Integer> bitRates)1565 private void applyLimits(Range<Integer>[] inputChannels, Range<Integer> bitRates) { 1566 1567 // clamp & make a local copy 1568 Range<Integer>[] myInputChannels = new Range[inputChannels.length]; 1569 for (int i = 0; i < inputChannels.length; i++) { 1570 int lower = inputChannels[i].clamp(1); 1571 int upper = inputChannels[i].clamp(MAX_INPUT_CHANNEL_COUNT); 1572 myInputChannels[i] = Range.create(lower, upper); 1573 } 1574 1575 // sort, intersect with existing, & save channel list 1576 sortDistinctRanges(myInputChannels); 1577 Range<Integer>[] joinedChannelList = 1578 intersectSortedDistinctRanges(myInputChannels, mInputChannelRanges); 1579 mInputChannelRanges = joinedChannelList; 1580 1581 if (bitRates != null) { 1582 mBitrateRange = mBitrateRange.intersect(bitRates); 1583 } 1584 } 1585 parseFromInfo(MediaFormat info)1586 private void parseFromInfo(MediaFormat info) { 1587 int maxInputChannels = MAX_INPUT_CHANNEL_COUNT; 1588 Range<Integer>[] channels = new Range[] { Range.create(1, maxInputChannels)}; 1589 Range<Integer> bitRates = POSITIVE_INTEGERS; 1590 1591 if (info.containsKey("sample-rate-ranges")) { 1592 String[] rateStrings = info.getString("sample-rate-ranges").split(","); 1593 Range<Integer>[] rateRanges = new Range[rateStrings.length]; 1594 for (int i = 0; i < rateStrings.length; i++) { 1595 rateRanges[i] = Utils.parseIntRange(rateStrings[i], null); 1596 } 1597 limitSampleRates(rateRanges); 1598 } 1599 1600 // we will prefer channel-ranges over max-channel-count 1601 if (info.containsKey("channel-ranges")) { 1602 String[] channelStrings = info.getString("channel-ranges").split(","); 1603 Range<Integer>[] channelRanges = new Range[channelStrings.length]; 1604 for (int i = 0; i < channelStrings.length; i++) { 1605 channelRanges[i] = Utils.parseIntRange(channelStrings[i], null); 1606 } 1607 channels = channelRanges; 1608 } else if (info.containsKey("channel-range")) { 1609 Range<Integer> oneRange = Utils.parseIntRange(info.getString("channel-range"), 1610 null); 1611 channels = new Range[] { oneRange }; 1612 } else if (info.containsKey("max-channel-count")) { 1613 maxInputChannels = Utils.parseIntSafely( 1614 info.getString("max-channel-count"), maxInputChannels); 1615 if (maxInputChannels == 0) { 1616 channels = new Range[] {Range.create(0, 0)}; 1617 } else { 1618 channels = new Range[] {Range.create(1, maxInputChannels)}; 1619 } 1620 } else if ((mParent.mError & ERROR_UNSUPPORTED) != 0) { 1621 maxInputChannels = 0; 1622 channels = new Range[] {Range.create(0, 0)}; 1623 } 1624 1625 if (info.containsKey("bitrate-range")) { 1626 bitRates = bitRates.intersect( 1627 Utils.parseIntRange(info.getString("bitrate-range"), bitRates)); 1628 } 1629 1630 applyLimits(channels, bitRates); 1631 } 1632 1633 /** @hide */ getDefaultFormat(MediaFormat format)1634 public void getDefaultFormat(MediaFormat format) { 1635 // report settings that have only a single choice 1636 if (mBitrateRange.getLower().equals(mBitrateRange.getUpper())) { 1637 format.setInteger(MediaFormat.KEY_BIT_RATE, mBitrateRange.getLower()); 1638 } 1639 if (getMaxInputChannelCount() == 1) { 1640 // mono-only format 1641 format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); 1642 } 1643 if (mSampleRates != null && mSampleRates.length == 1) { 1644 format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRates[0]); 1645 } 1646 } 1647 1648 /* package private */ 1649 // must not contain KEY_PROFILE 1650 static final Set<String> AUDIO_LEVEL_CRITICAL_FORMAT_KEYS = Set.of( 1651 // We don't set level-specific limits for audio codecs today. Key candidates would 1652 // be sample rate, bit rate or channel count. 1653 // MediaFormat.KEY_SAMPLE_RATE, 1654 // MediaFormat.KEY_CHANNEL_COUNT, 1655 // MediaFormat.KEY_BIT_RATE, 1656 MediaFormat.KEY_MIME); 1657 1658 /** @hide */ supportsFormat(MediaFormat format)1659 public boolean supportsFormat(MediaFormat format) { 1660 Map<String, Object> map = format.getMap(); 1661 Integer sampleRate = (Integer)map.get(MediaFormat.KEY_SAMPLE_RATE); 1662 Integer channels = (Integer)map.get(MediaFormat.KEY_CHANNEL_COUNT); 1663 1664 if (!supports(sampleRate, channels)) { 1665 return false; 1666 } 1667 1668 if (!CodecCapabilities.supportsBitrate(mBitrateRange, format)) { 1669 return false; 1670 } 1671 1672 // nothing to do for: 1673 // KEY_CHANNEL_MASK: codecs don't get this 1674 // KEY_IS_ADTS: required feature for all AAC decoders 1675 return true; 1676 } 1677 } 1678 1679 /** 1680 * A class that supports querying the video capabilities of a codec. 1681 */ 1682 public static final class VideoCapabilities { 1683 private static final String TAG = "VideoCapabilities"; 1684 private CodecCapabilities mParent; 1685 private Range<Integer> mBitrateRange; 1686 1687 private Range<Integer> mHeightRange; 1688 private Range<Integer> mWidthRange; 1689 private Range<Integer> mBlockCountRange; 1690 private Range<Integer> mHorizontalBlockRange; 1691 private Range<Integer> mVerticalBlockRange; 1692 private Range<Rational> mAspectRatioRange; 1693 private Range<Rational> mBlockAspectRatioRange; 1694 private Range<Long> mBlocksPerSecondRange; 1695 private Map<Size, Range<Long>> mMeasuredFrameRates; 1696 private List<PerformancePoint> mPerformancePoints; 1697 private Range<Integer> mFrameRateRange; 1698 1699 private int mBlockWidth; 1700 private int mBlockHeight; 1701 private int mWidthAlignment; 1702 private int mHeightAlignment; 1703 private int mSmallerDimensionUpperLimit; 1704 1705 private boolean mAllowMbOverride; // allow XML to override calculated limits 1706 1707 /** 1708 * Returns the range of supported bitrates in bits/second. 1709 */ getBitrateRange()1710 public Range<Integer> getBitrateRange() { 1711 return mBitrateRange; 1712 } 1713 1714 /** 1715 * Returns the range of supported video widths. 1716 * <p class=note> 1717 * 32-bit processes will not support resolutions larger than 4096x4096 due to 1718 * the limited address space. 1719 */ getSupportedWidths()1720 public Range<Integer> getSupportedWidths() { 1721 return mWidthRange; 1722 } 1723 1724 /** 1725 * Returns the range of supported video heights. 1726 * <p class=note> 1727 * 32-bit processes will not support resolutions larger than 4096x4096 due to 1728 * the limited address space. 1729 */ getSupportedHeights()1730 public Range<Integer> getSupportedHeights() { 1731 return mHeightRange; 1732 } 1733 1734 /** 1735 * Returns the alignment requirement for video width (in pixels). 1736 * 1737 * This is a power-of-2 value that video width must be a 1738 * multiple of. 1739 */ getWidthAlignment()1740 public int getWidthAlignment() { 1741 return mWidthAlignment; 1742 } 1743 1744 /** 1745 * Returns the alignment requirement for video height (in pixels). 1746 * 1747 * This is a power-of-2 value that video height must be a 1748 * multiple of. 1749 */ getHeightAlignment()1750 public int getHeightAlignment() { 1751 return mHeightAlignment; 1752 } 1753 1754 /** 1755 * Return the upper limit on the smaller dimension of width or height. 1756 * <p></p> 1757 * Some codecs have a limit on the smaller dimension, whether it be 1758 * the width or the height. E.g. a codec may only be able to handle 1759 * up to 1920x1080 both in landscape and portrait mode (1080x1920). 1760 * In this case the maximum width and height are both 1920, but the 1761 * smaller dimension limit will be 1080. For other codecs, this is 1762 * {@code Math.min(getSupportedWidths().getUpper(), 1763 * getSupportedHeights().getUpper())}. 1764 * 1765 * @hide 1766 */ getSmallerDimensionUpperLimit()1767 public int getSmallerDimensionUpperLimit() { 1768 return mSmallerDimensionUpperLimit; 1769 } 1770 1771 /** 1772 * Returns the range of supported frame rates. 1773 * <p> 1774 * This is not a performance indicator. Rather, it expresses the 1775 * limits specified in the coding standard, based on the complexities 1776 * of encoding material for later playback at a certain frame rate, 1777 * or the decoding of such material in non-realtime. 1778 */ getSupportedFrameRates()1779 public Range<Integer> getSupportedFrameRates() { 1780 return mFrameRateRange; 1781 } 1782 1783 /** 1784 * Returns the range of supported video widths for a video height. 1785 * @param height the height of the video 1786 */ getSupportedWidthsFor(int height)1787 public Range<Integer> getSupportedWidthsFor(int height) { 1788 try { 1789 Range<Integer> range = mWidthRange; 1790 if (!mHeightRange.contains(height) 1791 || (height % mHeightAlignment) != 0) { 1792 throw new IllegalArgumentException("unsupported height"); 1793 } 1794 final int heightInBlocks = Utils.divUp(height, mBlockHeight); 1795 1796 // constrain by block count and by block aspect ratio 1797 final int minWidthInBlocks = Math.max( 1798 Utils.divUp(mBlockCountRange.getLower(), heightInBlocks), 1799 (int)Math.ceil(mBlockAspectRatioRange.getLower().doubleValue() 1800 * heightInBlocks)); 1801 final int maxWidthInBlocks = Math.min( 1802 mBlockCountRange.getUpper() / heightInBlocks, 1803 (int)(mBlockAspectRatioRange.getUpper().doubleValue() 1804 * heightInBlocks)); 1805 range = range.intersect( 1806 (minWidthInBlocks - 1) * mBlockWidth + mWidthAlignment, 1807 maxWidthInBlocks * mBlockWidth); 1808 1809 // constrain by smaller dimension limit 1810 if (height > mSmallerDimensionUpperLimit) { 1811 range = range.intersect(1, mSmallerDimensionUpperLimit); 1812 } 1813 1814 // constrain by aspect ratio 1815 range = range.intersect( 1816 (int)Math.ceil(mAspectRatioRange.getLower().doubleValue() 1817 * height), 1818 (int)(mAspectRatioRange.getUpper().doubleValue() * height)); 1819 return range; 1820 } catch (IllegalArgumentException e) { 1821 // height is not supported because there are no suitable widths 1822 Log.v(TAG, "could not get supported widths for " + height); 1823 throw new IllegalArgumentException("unsupported height"); 1824 } 1825 } 1826 1827 /** 1828 * Returns the range of supported video heights for a video width 1829 * @param width the width of the video 1830 */ getSupportedHeightsFor(int width)1831 public Range<Integer> getSupportedHeightsFor(int width) { 1832 try { 1833 Range<Integer> range = mHeightRange; 1834 if (!mWidthRange.contains(width) 1835 || (width % mWidthAlignment) != 0) { 1836 throw new IllegalArgumentException("unsupported width"); 1837 } 1838 final int widthInBlocks = Utils.divUp(width, mBlockWidth); 1839 1840 // constrain by block count and by block aspect ratio 1841 final int minHeightInBlocks = Math.max( 1842 Utils.divUp(mBlockCountRange.getLower(), widthInBlocks), 1843 (int)Math.ceil(widthInBlocks / 1844 mBlockAspectRatioRange.getUpper().doubleValue())); 1845 final int maxHeightInBlocks = Math.min( 1846 mBlockCountRange.getUpper() / widthInBlocks, 1847 (int)(widthInBlocks / 1848 mBlockAspectRatioRange.getLower().doubleValue())); 1849 range = range.intersect( 1850 (minHeightInBlocks - 1) * mBlockHeight + mHeightAlignment, 1851 maxHeightInBlocks * mBlockHeight); 1852 1853 // constrain by smaller dimension limit 1854 if (width > mSmallerDimensionUpperLimit) { 1855 range = range.intersect(1, mSmallerDimensionUpperLimit); 1856 } 1857 1858 // constrain by aspect ratio 1859 range = range.intersect( 1860 (int)Math.ceil(width / 1861 mAspectRatioRange.getUpper().doubleValue()), 1862 (int)(width / mAspectRatioRange.getLower().doubleValue())); 1863 return range; 1864 } catch (IllegalArgumentException e) { 1865 // width is not supported because there are no suitable heights 1866 Log.v(TAG, "could not get supported heights for " + width); 1867 throw new IllegalArgumentException("unsupported width"); 1868 } 1869 } 1870 1871 /** 1872 * Returns the range of supported video frame rates for a video size. 1873 * <p> 1874 * This is not a performance indicator. Rather, it expresses the limits specified in 1875 * the coding standard, based on the complexities of encoding material of a given 1876 * size for later playback at a certain frame rate, or the decoding of such material 1877 * in non-realtime. 1878 1879 * @param width the width of the video 1880 * @param height the height of the video 1881 */ getSupportedFrameRatesFor(int width, int height)1882 public Range<Double> getSupportedFrameRatesFor(int width, int height) { 1883 Range<Integer> range = mHeightRange; 1884 if (!supports(width, height, null)) { 1885 throw new IllegalArgumentException("unsupported size"); 1886 } 1887 final int blockCount = 1888 Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight); 1889 1890 return Range.create( 1891 Math.max(mBlocksPerSecondRange.getLower() / (double) blockCount, 1892 (double) mFrameRateRange.getLower()), 1893 Math.min(mBlocksPerSecondRange.getUpper() / (double) blockCount, 1894 (double) mFrameRateRange.getUpper())); 1895 } 1896 getBlockCount(int width, int height)1897 private int getBlockCount(int width, int height) { 1898 return Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight); 1899 } 1900 1901 @NonNull findClosestSize(int width, int height)1902 private Size findClosestSize(int width, int height) { 1903 int targetBlockCount = getBlockCount(width, height); 1904 Size closestSize = null; 1905 int minDiff = Integer.MAX_VALUE; 1906 for (Size size : mMeasuredFrameRates.keySet()) { 1907 int diff = Math.abs(targetBlockCount - 1908 getBlockCount(size.getWidth(), size.getHeight())); 1909 if (diff < minDiff) { 1910 minDiff = diff; 1911 closestSize = size; 1912 } 1913 } 1914 return closestSize; 1915 } 1916 estimateFrameRatesFor(int width, int height)1917 private Range<Double> estimateFrameRatesFor(int width, int height) { 1918 Size size = findClosestSize(width, height); 1919 Range<Long> range = mMeasuredFrameRates.get(size); 1920 Double ratio = getBlockCount(size.getWidth(), size.getHeight()) 1921 / (double)Math.max(getBlockCount(width, height), 1); 1922 return Range.create(range.getLower() * ratio, range.getUpper() * ratio); 1923 } 1924 1925 /** 1926 * Returns the range of achievable video frame rates for a video size. 1927 * May return {@code null}, if the codec did not publish any measurement 1928 * data. 1929 * <p> 1930 * This is a performance estimate provided by the device manufacturer based on statistical 1931 * sampling of full-speed decoding and encoding measurements in various configurations 1932 * of common video sizes supported by the codec. As such it should only be used to 1933 * compare individual codecs on the device. The value is not suitable for comparing 1934 * different devices or even different android releases for the same device. 1935 * <p> 1936 * <em>On {@link android.os.Build.VERSION_CODES#M} release</em> the returned range 1937 * corresponds to the fastest frame rates achieved in the tested configurations. As 1938 * such, it should not be used to gauge guaranteed or even average codec performance 1939 * on the device. 1940 * <p> 1941 * <em>On {@link android.os.Build.VERSION_CODES#N} release</em> the returned range 1942 * corresponds closer to sustained performance <em>in tested configurations</em>. 1943 * One can expect to achieve sustained performance higher than the lower limit more than 1944 * 50% of the time, and higher than half of the lower limit at least 90% of the time 1945 * <em>in tested configurations</em>. 1946 * Conversely, one can expect performance lower than twice the upper limit at least 1947 * 90% of the time. 1948 * <p class=note> 1949 * Tested configurations use a single active codec. For use cases where multiple 1950 * codecs are active, applications can expect lower and in most cases significantly lower 1951 * performance. 1952 * <p class=note> 1953 * The returned range value is interpolated from the nearest frame size(s) tested. 1954 * Codec performance is severely impacted by other activity on the device as well 1955 * as environmental factors (such as battery level, temperature or power source), and can 1956 * vary significantly even in a steady environment. 1957 * <p class=note> 1958 * Use this method in cases where only codec performance matters, e.g. to evaluate if 1959 * a codec has any chance of meeting a performance target. Codecs are listed 1960 * in {@link MediaCodecList} in the preferred order as defined by the device 1961 * manufacturer. As such, applications should use the first suitable codec in the 1962 * list to achieve the best balance between power use and performance. 1963 * 1964 * @param width the width of the video 1965 * @param height the height of the video 1966 * 1967 * @throws IllegalArgumentException if the video size is not supported. 1968 */ 1969 @Nullable getAchievableFrameRatesFor(int width, int height)1970 public Range<Double> getAchievableFrameRatesFor(int width, int height) { 1971 if (!supports(width, height, null)) { 1972 throw new IllegalArgumentException("unsupported size"); 1973 } 1974 1975 if (mMeasuredFrameRates == null || mMeasuredFrameRates.size() <= 0) { 1976 Log.w(TAG, "Codec did not publish any measurement data."); 1977 return null; 1978 } 1979 1980 return estimateFrameRatesFor(width, height); 1981 } 1982 1983 /** 1984 * Video performance points are a set of standard performance points defined by number of 1985 * pixels, pixel rate and frame rate. Performance point represents an upper bound. This 1986 * means that it covers all performance points with fewer pixels, pixel rate and frame 1987 * rate. 1988 */ 1989 public static final class PerformancePoint { 1990 private Size mBlockSize; // codec block size in macroblocks 1991 private int mWidth; // width in macroblocks 1992 private int mHeight; // height in macroblocks 1993 private int mMaxFrameRate; // max frames per second 1994 private long mMaxMacroBlockRate; // max macro block rate 1995 1996 /** 1997 * Maximum number of macroblocks in the frame. 1998 * 1999 * Video frames are conceptually divided into 16-by-16 pixel blocks called macroblocks. 2000 * Most coding standards operate on these 16-by-16 pixel blocks; thus, codec performance 2001 * is characterized using such blocks. 2002 * 2003 * @hide 2004 */ 2005 @TestApi getMaxMacroBlocks()2006 public int getMaxMacroBlocks() { 2007 return saturateLongToInt(mWidth * (long)mHeight); 2008 } 2009 2010 /** 2011 * Maximum frame rate in frames per second. 2012 * 2013 * @hide 2014 */ 2015 @TestApi getMaxFrameRate()2016 public int getMaxFrameRate() { 2017 return mMaxFrameRate; 2018 } 2019 2020 /** 2021 * Maximum number of macroblocks processed per second. 2022 * 2023 * @hide 2024 */ 2025 @TestApi getMaxMacroBlockRate()2026 public long getMaxMacroBlockRate() { 2027 return mMaxMacroBlockRate; 2028 } 2029 2030 /** Convert to a debug string */ toString()2031 public String toString() { 2032 int blockWidth = 16 * mBlockSize.getWidth(); 2033 int blockHeight = 16 * mBlockSize.getHeight(); 2034 int origRate = (int)Utils.divUp(mMaxMacroBlockRate, getMaxMacroBlocks()); 2035 String info = (mWidth * 16) + "x" + (mHeight * 16) + "@" + origRate; 2036 if (origRate < mMaxFrameRate) { 2037 info += ", max " + mMaxFrameRate + "fps"; 2038 } 2039 if (blockWidth > 16 || blockHeight > 16) { 2040 info += ", " + blockWidth + "x" + blockHeight + " blocks"; 2041 } 2042 return "PerformancePoint(" + info + ")"; 2043 } 2044 2045 @Override hashCode()2046 public int hashCode() { 2047 // only max frame rate must equal between performance points that equal to one 2048 // another 2049 return mMaxFrameRate; 2050 } 2051 2052 /** 2053 * Create a detailed performance point with custom max frame rate and macroblock size. 2054 * 2055 * @param width frame width in pixels 2056 * @param height frame height in pixels 2057 * @param frameRate frames per second for frame width and height 2058 * @param maxFrameRate maximum frames per second for any frame size 2059 * @param blockSize block size for codec implementation. Must be powers of two in both 2060 * width and height. 2061 * 2062 * @throws IllegalArgumentException if the blockSize dimensions are not powers of two. 2063 * 2064 * @hide 2065 */ 2066 @TestApi PerformancePoint( int width, int height, int frameRate, int maxFrameRate, @NonNull Size blockSize)2067 public PerformancePoint( 2068 int width, int height, int frameRate, int maxFrameRate, 2069 @NonNull Size blockSize) { 2070 checkPowerOfTwo(blockSize.getWidth(), "block width"); 2071 checkPowerOfTwo(blockSize.getHeight(), "block height"); 2072 2073 mBlockSize = new Size(Utils.divUp(blockSize.getWidth(), 16), 2074 Utils.divUp(blockSize.getHeight(), 16)); 2075 // these are guaranteed not to overflow as we decimate by 16 2076 mWidth = (int)(Utils.divUp(Math.max(1L, width), 2077 Math.max(blockSize.getWidth(), 16)) 2078 * mBlockSize.getWidth()); 2079 mHeight = (int)(Utils.divUp(Math.max(1L, height), 2080 Math.max(blockSize.getHeight(), 16)) 2081 * mBlockSize.getHeight()); 2082 mMaxFrameRate = Math.max(1, Math.max(frameRate, maxFrameRate)); 2083 mMaxMacroBlockRate = Math.max(1, frameRate) * getMaxMacroBlocks(); 2084 } 2085 2086 /** 2087 * Convert a performance point to a larger blocksize. 2088 * 2089 * @param pp performance point 2090 * @param blockSize block size for codec implementation 2091 * 2092 * @hide 2093 */ 2094 @TestApi PerformancePoint(@onNull PerformancePoint pp, @NonNull Size newBlockSize)2095 public PerformancePoint(@NonNull PerformancePoint pp, @NonNull Size newBlockSize) { 2096 this( 2097 pp.mWidth * 16, pp.mHeight * 16, 2098 // guaranteed not to overflow as these were multiplied at construction 2099 (int)Utils.divUp(pp.mMaxMacroBlockRate, pp.getMaxMacroBlocks()), 2100 pp.mMaxFrameRate, 2101 new Size(Math.max(newBlockSize.getWidth(), pp.mBlockSize.getWidth() * 16), 2102 Math.max(newBlockSize.getHeight(), pp.mBlockSize.getHeight() * 16)) 2103 ); 2104 } 2105 2106 /** 2107 * Create a performance point for a given frame size and frame rate. 2108 * 2109 * @param width width of the frame in pixels 2110 * @param height height of the frame in pixels 2111 * @param frameRate frame rate in frames per second 2112 */ PerformancePoint(int width, int height, int frameRate)2113 public PerformancePoint(int width, int height, int frameRate) { 2114 this(width, height, frameRate, frameRate /* maxFrameRate */, new Size(16, 16)); 2115 } 2116 2117 /** Saturates a long value to int */ saturateLongToInt(long value)2118 private int saturateLongToInt(long value) { 2119 if (value < Integer.MIN_VALUE) { 2120 return Integer.MIN_VALUE; 2121 } else if (value > Integer.MAX_VALUE) { 2122 return Integer.MAX_VALUE; 2123 } else { 2124 return (int)value; 2125 } 2126 } 2127 2128 /* This method may overflow */ align(int value, int alignment)2129 private int align(int value, int alignment) { 2130 return Utils.divUp(value, alignment) * alignment; 2131 } 2132 2133 /** Checks that value is a power of two. */ checkPowerOfTwo2(int value, @NonNull String description)2134 private void checkPowerOfTwo2(int value, @NonNull String description) { 2135 if (value == 0 || (value & (value - 1)) != 0) { 2136 throw new IllegalArgumentException( 2137 description + " (" + value + ") must be a power of 2"); 2138 } 2139 } 2140 2141 /** 2142 * Checks whether the performance point covers a media format. 2143 * 2144 * @param format Stream format considered 2145 * 2146 * @return {@code true} if the performance point covers the format. 2147 */ covers(@onNull MediaFormat format)2148 public boolean covers(@NonNull MediaFormat format) { 2149 PerformancePoint other = new PerformancePoint( 2150 format.getInteger(MediaFormat.KEY_WIDTH, 0), 2151 format.getInteger(MediaFormat.KEY_HEIGHT, 0), 2152 // safely convert ceil(double) to int through float cast and Math.round 2153 Math.round((float)( 2154 Math.ceil(format.getNumber(MediaFormat.KEY_FRAME_RATE, 0) 2155 .doubleValue())))); 2156 return covers(other); 2157 } 2158 2159 /** 2160 * Checks whether the performance point covers another performance point. Use this 2161 * method to determine if a performance point advertised by a codec covers the 2162 * performance point required. This method can also be used for loose ordering as this 2163 * method is transitive. 2164 * 2165 * @param other other performance point considered 2166 * 2167 * @return {@code true} if the performance point covers the other. 2168 */ covers(@onNull PerformancePoint other)2169 public boolean covers(@NonNull PerformancePoint other) { 2170 // convert performance points to common block size 2171 Size commonSize = getCommonBlockSize(other); 2172 PerformancePoint aligned = new PerformancePoint(this, commonSize); 2173 PerformancePoint otherAligned = new PerformancePoint(other, commonSize); 2174 2175 return (aligned.getMaxMacroBlocks() >= otherAligned.getMaxMacroBlocks() 2176 && aligned.mMaxFrameRate >= otherAligned.mMaxFrameRate 2177 && aligned.mMaxMacroBlockRate >= otherAligned.mMaxMacroBlockRate); 2178 } 2179 getCommonBlockSize(@onNull PerformancePoint other)2180 private @NonNull Size getCommonBlockSize(@NonNull PerformancePoint other) { 2181 return new Size( 2182 Math.max(mBlockSize.getWidth(), other.mBlockSize.getWidth()) * 16, 2183 Math.max(mBlockSize.getHeight(), other.mBlockSize.getHeight()) * 16); 2184 } 2185 2186 @Override equals(Object o)2187 public boolean equals(Object o) { 2188 if (o instanceof PerformancePoint) { 2189 // convert performance points to common block size 2190 PerformancePoint other = (PerformancePoint)o; 2191 Size commonSize = getCommonBlockSize(other); 2192 PerformancePoint aligned = new PerformancePoint(this, commonSize); 2193 PerformancePoint otherAligned = new PerformancePoint(other, commonSize); 2194 2195 return (aligned.getMaxMacroBlocks() == otherAligned.getMaxMacroBlocks() 2196 && aligned.mMaxFrameRate == otherAligned.mMaxFrameRate 2197 && aligned.mMaxMacroBlockRate == otherAligned.mMaxMacroBlockRate); 2198 } 2199 return false; 2200 } 2201 2202 /** 480p 24fps */ 2203 @NonNull 2204 public static final PerformancePoint SD_24 = new PerformancePoint(720, 480, 24); 2205 /** 576p 25fps */ 2206 @NonNull 2207 public static final PerformancePoint SD_25 = new PerformancePoint(720, 576, 25); 2208 /** 480p 30fps */ 2209 @NonNull 2210 public static final PerformancePoint SD_30 = new PerformancePoint(720, 480, 30); 2211 /** 480p 48fps */ 2212 @NonNull 2213 public static final PerformancePoint SD_48 = new PerformancePoint(720, 480, 48); 2214 /** 576p 50fps */ 2215 @NonNull 2216 public static final PerformancePoint SD_50 = new PerformancePoint(720, 576, 50); 2217 /** 480p 60fps */ 2218 @NonNull 2219 public static final PerformancePoint SD_60 = new PerformancePoint(720, 480, 60); 2220 2221 /** 720p 24fps */ 2222 @NonNull 2223 public static final PerformancePoint HD_24 = new PerformancePoint(1280, 720, 24); 2224 /** 720p 25fps */ 2225 @NonNull 2226 public static final PerformancePoint HD_25 = new PerformancePoint(1280, 720, 25); 2227 /** 720p 30fps */ 2228 @NonNull 2229 public static final PerformancePoint HD_30 = new PerformancePoint(1280, 720, 30); 2230 /** 720p 50fps */ 2231 @NonNull 2232 public static final PerformancePoint HD_50 = new PerformancePoint(1280, 720, 50); 2233 /** 720p 60fps */ 2234 @NonNull 2235 public static final PerformancePoint HD_60 = new PerformancePoint(1280, 720, 60); 2236 /** 720p 100fps */ 2237 @NonNull 2238 public static final PerformancePoint HD_100 = new PerformancePoint(1280, 720, 100); 2239 /** 720p 120fps */ 2240 @NonNull 2241 public static final PerformancePoint HD_120 = new PerformancePoint(1280, 720, 120); 2242 /** 720p 200fps */ 2243 @NonNull 2244 public static final PerformancePoint HD_200 = new PerformancePoint(1280, 720, 200); 2245 /** 720p 240fps */ 2246 @NonNull 2247 public static final PerformancePoint HD_240 = new PerformancePoint(1280, 720, 240); 2248 2249 /** 1080p 24fps */ 2250 @NonNull 2251 public static final PerformancePoint FHD_24 = new PerformancePoint(1920, 1080, 24); 2252 /** 1080p 25fps */ 2253 @NonNull 2254 public static final PerformancePoint FHD_25 = new PerformancePoint(1920, 1080, 25); 2255 /** 1080p 30fps */ 2256 @NonNull 2257 public static final PerformancePoint FHD_30 = new PerformancePoint(1920, 1080, 30); 2258 /** 1080p 50fps */ 2259 @NonNull 2260 public static final PerformancePoint FHD_50 = new PerformancePoint(1920, 1080, 50); 2261 /** 1080p 60fps */ 2262 @NonNull 2263 public static final PerformancePoint FHD_60 = new PerformancePoint(1920, 1080, 60); 2264 /** 1080p 100fps */ 2265 @NonNull 2266 public static final PerformancePoint FHD_100 = new PerformancePoint(1920, 1080, 100); 2267 /** 1080p 120fps */ 2268 @NonNull 2269 public static final PerformancePoint FHD_120 = new PerformancePoint(1920, 1080, 120); 2270 /** 1080p 200fps */ 2271 @NonNull 2272 public static final PerformancePoint FHD_200 = new PerformancePoint(1920, 1080, 200); 2273 /** 1080p 240fps */ 2274 @NonNull 2275 public static final PerformancePoint FHD_240 = new PerformancePoint(1920, 1080, 240); 2276 2277 /** 2160p 24fps */ 2278 @NonNull 2279 public static final PerformancePoint UHD_24 = new PerformancePoint(3840, 2160, 24); 2280 /** 2160p 25fps */ 2281 @NonNull 2282 public static final PerformancePoint UHD_25 = new PerformancePoint(3840, 2160, 25); 2283 /** 2160p 30fps */ 2284 @NonNull 2285 public static final PerformancePoint UHD_30 = new PerformancePoint(3840, 2160, 30); 2286 /** 2160p 50fps */ 2287 @NonNull 2288 public static final PerformancePoint UHD_50 = new PerformancePoint(3840, 2160, 50); 2289 /** 2160p 60fps */ 2290 @NonNull 2291 public static final PerformancePoint UHD_60 = new PerformancePoint(3840, 2160, 60); 2292 /** 2160p 100fps */ 2293 @NonNull 2294 public static final PerformancePoint UHD_100 = new PerformancePoint(3840, 2160, 100); 2295 /** 2160p 120fps */ 2296 @NonNull 2297 public static final PerformancePoint UHD_120 = new PerformancePoint(3840, 2160, 120); 2298 /** 2160p 200fps */ 2299 @NonNull 2300 public static final PerformancePoint UHD_200 = new PerformancePoint(3840, 2160, 200); 2301 /** 2160p 240fps */ 2302 @NonNull 2303 public static final PerformancePoint UHD_240 = new PerformancePoint(3840, 2160, 240); 2304 } 2305 2306 /** 2307 * Returns the supported performance points. May return {@code null} if the codec did not 2308 * publish any performance point information (e.g. the vendor codecs have not been updated 2309 * to the latest android release). May return an empty list if the codec published that 2310 * if does not guarantee any performance points. 2311 * <p> 2312 * This is a performance guarantee provided by the device manufacturer for hardware codecs 2313 * based on hardware capabilities of the device. 2314 * <p> 2315 * The returned list is sorted first by decreasing number of pixels, then by decreasing 2316 * width, and finally by decreasing frame rate. 2317 * Performance points assume a single active codec. For use cases where multiple 2318 * codecs are active, should use that highest pixel count, and add the frame rates of 2319 * each individual codec. 2320 * <p class=note> 2321 * 32-bit processes will not support resolutions larger than 4096x4096 due to 2322 * the limited address space, but performance points will be presented as is. 2323 * In other words, even though a component publishes a performance point for 2324 * a resolution higher than 4096x4096, it does not mean that the resolution is supported 2325 * for 32-bit processes. 2326 */ 2327 @Nullable getSupportedPerformancePoints()2328 public List<PerformancePoint> getSupportedPerformancePoints() { 2329 return mPerformancePoints; 2330 } 2331 2332 /** 2333 * Returns whether a given video size ({@code width} and 2334 * {@code height}) and {@code frameRate} combination is supported. 2335 */ areSizeAndRateSupported( int width, int height, double frameRate)2336 public boolean areSizeAndRateSupported( 2337 int width, int height, double frameRate) { 2338 return supports(width, height, frameRate); 2339 } 2340 2341 /** 2342 * Returns whether a given video size ({@code width} and 2343 * {@code height}) is supported. 2344 */ isSizeSupported(int width, int height)2345 public boolean isSizeSupported(int width, int height) { 2346 return supports(width, height, null); 2347 } 2348 supports(Integer width, Integer height, Number rate)2349 private boolean supports(Integer width, Integer height, Number rate) { 2350 boolean ok = true; 2351 2352 if (ok && width != null) { 2353 ok = mWidthRange.contains(width) 2354 && (width % mWidthAlignment == 0); 2355 } 2356 if (ok && height != null) { 2357 ok = mHeightRange.contains(height) 2358 && (height % mHeightAlignment == 0); 2359 } 2360 if (ok && rate != null) { 2361 ok = mFrameRateRange.contains(Utils.intRangeFor(rate.doubleValue())); 2362 } 2363 if (ok && height != null && width != null) { 2364 ok = Math.min(height, width) <= mSmallerDimensionUpperLimit; 2365 2366 final int widthInBlocks = Utils.divUp(width, mBlockWidth); 2367 final int heightInBlocks = Utils.divUp(height, mBlockHeight); 2368 final int blockCount = widthInBlocks * heightInBlocks; 2369 ok = ok && mBlockCountRange.contains(blockCount) 2370 && mBlockAspectRatioRange.contains( 2371 new Rational(widthInBlocks, heightInBlocks)) 2372 && mAspectRatioRange.contains(new Rational(width, height)); 2373 if (ok && rate != null) { 2374 double blocksPerSec = blockCount * rate.doubleValue(); 2375 ok = mBlocksPerSecondRange.contains( 2376 Utils.longRangeFor(blocksPerSec)); 2377 } 2378 } 2379 return ok; 2380 } 2381 2382 /* package private */ 2383 // must not contain KEY_PROFILE 2384 static final Set<String> VIDEO_LEVEL_CRITICAL_FORMAT_KEYS = Set.of( 2385 MediaFormat.KEY_WIDTH, 2386 MediaFormat.KEY_HEIGHT, 2387 MediaFormat.KEY_FRAME_RATE, 2388 MediaFormat.KEY_BIT_RATE, 2389 MediaFormat.KEY_MIME); 2390 2391 /** 2392 * @hide 2393 * @throws java.lang.ClassCastException */ supportsFormat(MediaFormat format)2394 public boolean supportsFormat(MediaFormat format) { 2395 final Map<String, Object> map = format.getMap(); 2396 Integer width = (Integer)map.get(MediaFormat.KEY_WIDTH); 2397 Integer height = (Integer)map.get(MediaFormat.KEY_HEIGHT); 2398 Number rate = (Number)map.get(MediaFormat.KEY_FRAME_RATE); 2399 2400 if (!supports(width, height, rate)) { 2401 return false; 2402 } 2403 2404 if (!CodecCapabilities.supportsBitrate(mBitrateRange, format)) { 2405 return false; 2406 } 2407 2408 // we ignore color-format for now as it is not reliably reported by codec 2409 return true; 2410 } 2411 2412 /* no public constructor */ VideoCapabilities()2413 private VideoCapabilities() { } 2414 2415 /** @hide */ 2416 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) create( MediaFormat info, CodecCapabilities parent)2417 public static VideoCapabilities create( 2418 MediaFormat info, CodecCapabilities parent) { 2419 VideoCapabilities caps = new VideoCapabilities(); 2420 caps.init(info, parent); 2421 return caps; 2422 } 2423 init(MediaFormat info, CodecCapabilities parent)2424 private void init(MediaFormat info, CodecCapabilities parent) { 2425 mParent = parent; 2426 initWithPlatformLimits(); 2427 applyLevelLimits(); 2428 parseFromInfo(info); 2429 updateLimits(); 2430 } 2431 2432 /** @hide */ getBlockSize()2433 public Size getBlockSize() { 2434 return new Size(mBlockWidth, mBlockHeight); 2435 } 2436 2437 /** @hide */ getBlockCountRange()2438 public Range<Integer> getBlockCountRange() { 2439 return mBlockCountRange; 2440 } 2441 2442 /** @hide */ getBlocksPerSecondRange()2443 public Range<Long> getBlocksPerSecondRange() { 2444 return mBlocksPerSecondRange; 2445 } 2446 2447 /** @hide */ getAspectRatioRange(boolean blocks)2448 public Range<Rational> getAspectRatioRange(boolean blocks) { 2449 return blocks ? mBlockAspectRatioRange : mAspectRatioRange; 2450 } 2451 initWithPlatformLimits()2452 private void initWithPlatformLimits() { 2453 mBitrateRange = BITRATE_RANGE; 2454 2455 mWidthRange = getSizeRange(); 2456 mHeightRange = getSizeRange(); 2457 mFrameRateRange = FRAME_RATE_RANGE; 2458 2459 mHorizontalBlockRange = getSizeRange(); 2460 mVerticalBlockRange = getSizeRange(); 2461 2462 // full positive ranges are supported as these get calculated 2463 mBlockCountRange = POSITIVE_INTEGERS; 2464 mBlocksPerSecondRange = POSITIVE_LONGS; 2465 2466 mBlockAspectRatioRange = POSITIVE_RATIONALS; 2467 mAspectRatioRange = POSITIVE_RATIONALS; 2468 2469 // YUV 4:2:0 requires 2:2 alignment 2470 mWidthAlignment = 2; 2471 mHeightAlignment = 2; 2472 mBlockWidth = 2; 2473 mBlockHeight = 2; 2474 mSmallerDimensionUpperLimit = getSizeRange().getUpper(); 2475 } 2476 getPerformancePoints(Map<String, Object> map)2477 private @Nullable List<PerformancePoint> getPerformancePoints(Map<String, Object> map) { 2478 Vector<PerformancePoint> ret = new Vector<>(); 2479 final String prefix = "performance-point-"; 2480 Set<String> keys = map.keySet(); 2481 for (String key : keys) { 2482 // looking for: performance-point-WIDTHxHEIGHT-range 2483 if (!key.startsWith(prefix)) { 2484 continue; 2485 } 2486 String subKey = key.substring(prefix.length()); 2487 if (subKey.equals("none") && ret.size() == 0) { 2488 // This means that component knowingly did not publish performance points. 2489 // This is different from when the component forgot to publish performance 2490 // points. 2491 return Collections.unmodifiableList(ret); 2492 } 2493 String[] temp = key.split("-"); 2494 if (temp.length != 4) { 2495 continue; 2496 } 2497 String sizeStr = temp[2]; 2498 Size size = Utils.parseSize(sizeStr, null); 2499 if (size == null || size.getWidth() * size.getHeight() <= 0) { 2500 continue; 2501 } 2502 Range<Long> range = Utils.parseLongRange(map.get(key), null); 2503 if (range == null || range.getLower() < 0 || range.getUpper() < 0) { 2504 continue; 2505 } 2506 PerformancePoint given = new PerformancePoint( 2507 size.getWidth(), size.getHeight(), range.getLower().intValue(), 2508 range.getUpper().intValue(), new Size(mBlockWidth, mBlockHeight)); 2509 PerformancePoint rotated = new PerformancePoint( 2510 size.getHeight(), size.getWidth(), range.getLower().intValue(), 2511 range.getUpper().intValue(), new Size(mBlockWidth, mBlockHeight)); 2512 ret.add(given); 2513 if (!given.covers(rotated)) { 2514 ret.add(rotated); 2515 } 2516 } 2517 2518 // check if the component specified no performance point indication 2519 if (ret.size() == 0) { 2520 return null; 2521 } 2522 2523 // sort reversed by area first, then by frame rate 2524 ret.sort((a, b) -> 2525 -((a.getMaxMacroBlocks() != b.getMaxMacroBlocks()) ? 2526 (a.getMaxMacroBlocks() < b.getMaxMacroBlocks() ? -1 : 1) : 2527 (a.getMaxMacroBlockRate() != b.getMaxMacroBlockRate()) ? 2528 (a.getMaxMacroBlockRate() < b.getMaxMacroBlockRate() ? -1 : 1) : 2529 (a.getMaxFrameRate() != b.getMaxFrameRate()) ? 2530 (a.getMaxFrameRate() < b.getMaxFrameRate() ? -1 : 1) : 0)); 2531 2532 return Collections.unmodifiableList(ret); 2533 } 2534 2535 private Map<Size, Range<Long>> getMeasuredFrameRates(Map<String, Object> map) { 2536 Map<Size, Range<Long>> ret = new HashMap<Size, Range<Long>>(); 2537 final String prefix = "measured-frame-rate-"; 2538 Set<String> keys = map.keySet(); 2539 for (String key : keys) { 2540 // looking for: measured-frame-rate-WIDTHxHEIGHT-range 2541 if (!key.startsWith(prefix)) { 2542 continue; 2543 } 2544 String subKey = key.substring(prefix.length()); 2545 String[] temp = key.split("-"); 2546 if (temp.length != 5) { 2547 continue; 2548 } 2549 String sizeStr = temp[3]; 2550 Size size = Utils.parseSize(sizeStr, null); 2551 if (size == null || size.getWidth() * size.getHeight() <= 0) { 2552 continue; 2553 } 2554 Range<Long> range = Utils.parseLongRange(map.get(key), null); 2555 if (range == null || range.getLower() < 0 || range.getUpper() < 0) { 2556 continue; 2557 } 2558 ret.put(size, range); 2559 } 2560 return ret; 2561 } 2562 2563 private static Pair<Range<Integer>, Range<Integer>> parseWidthHeightRanges(Object o) { 2564 Pair<Size, Size> range = Utils.parseSizeRange(o); 2565 if (range != null) { 2566 try { 2567 return Pair.create( 2568 Range.create(range.first.getWidth(), range.second.getWidth()), 2569 Range.create(range.first.getHeight(), range.second.getHeight())); 2570 } catch (IllegalArgumentException e) { 2571 Log.w(TAG, "could not parse size range '" + o + "'"); 2572 } 2573 } 2574 return null; 2575 } 2576 2577 /** @hide */ 2578 public static int equivalentVP9Level(MediaFormat info) { 2579 final Map<String, Object> map = info.getMap(); 2580 2581 Size blockSize = Utils.parseSize(map.get("block-size"), new Size(8, 8)); 2582 int BS = blockSize.getWidth() * blockSize.getHeight(); 2583 2584 Range<Integer> counts = Utils.parseIntRange(map.get("block-count-range"), null); 2585 int FS = counts == null ? 0 : BS * counts.getUpper(); 2586 2587 Range<Long> blockRates = 2588 Utils.parseLongRange(map.get("blocks-per-second-range"), null); 2589 long SR = blockRates == null ? 0 : BS * blockRates.getUpper(); 2590 2591 Pair<Range<Integer>, Range<Integer>> dimensionRanges = 2592 parseWidthHeightRanges(map.get("size-range")); 2593 int D = dimensionRanges == null ? 0 : Math.max( 2594 dimensionRanges.first.getUpper(), dimensionRanges.second.getUpper()); 2595 2596 Range<Integer> bitRates = Utils.parseIntRange(map.get("bitrate-range"), null); 2597 int BR = bitRates == null ? 0 : Utils.divUp(bitRates.getUpper(), 1000); 2598 2599 if (SR <= 829440 && FS <= 36864 && BR <= 200 && D <= 512) 2600 return CodecProfileLevel.VP9Level1; 2601 if (SR <= 2764800 && FS <= 73728 && BR <= 800 && D <= 768) 2602 return CodecProfileLevel.VP9Level11; 2603 if (SR <= 4608000 && FS <= 122880 && BR <= 1800 && D <= 960) 2604 return CodecProfileLevel.VP9Level2; 2605 if (SR <= 9216000 && FS <= 245760 && BR <= 3600 && D <= 1344) 2606 return CodecProfileLevel.VP9Level21; 2607 if (SR <= 20736000 && FS <= 552960 && BR <= 7200 && D <= 2048) 2608 return CodecProfileLevel.VP9Level3; 2609 if (SR <= 36864000 && FS <= 983040 && BR <= 12000 && D <= 2752) 2610 return CodecProfileLevel.VP9Level31; 2611 if (SR <= 83558400 && FS <= 2228224 && BR <= 18000 && D <= 4160) 2612 return CodecProfileLevel.VP9Level4; 2613 if (SR <= 160432128 && FS <= 2228224 && BR <= 30000 && D <= 4160) 2614 return CodecProfileLevel.VP9Level41; 2615 if (SR <= 311951360 && FS <= 8912896 && BR <= 60000 && D <= 8384) 2616 return CodecProfileLevel.VP9Level5; 2617 if (SR <= 588251136 && FS <= 8912896 && BR <= 120000 && D <= 8384) 2618 return CodecProfileLevel.VP9Level51; 2619 if (SR <= 1176502272 && FS <= 8912896 && BR <= 180000 && D <= 8384) 2620 return CodecProfileLevel.VP9Level52; 2621 if (SR <= 1176502272 && FS <= 35651584 && BR <= 180000 && D <= 16832) 2622 return CodecProfileLevel.VP9Level6; 2623 if (SR <= 2353004544L && FS <= 35651584 && BR <= 240000 && D <= 16832) 2624 return CodecProfileLevel.VP9Level61; 2625 if (SR <= 4706009088L && FS <= 35651584 && BR <= 480000 && D <= 16832) 2626 return CodecProfileLevel.VP9Level62; 2627 // returning largest level 2628 return CodecProfileLevel.VP9Level62; 2629 } 2630 2631 private void parseFromInfo(MediaFormat info) { 2632 final Map<String, Object> map = info.getMap(); 2633 Size blockSize = new Size(mBlockWidth, mBlockHeight); 2634 Size alignment = new Size(mWidthAlignment, mHeightAlignment); 2635 Range<Integer> counts = null, widths = null, heights = null; 2636 Range<Integer> frameRates = null, bitRates = null; 2637 Range<Long> blockRates = null; 2638 Range<Rational> ratios = null, blockRatios = null; 2639 2640 blockSize = Utils.parseSize(map.get("block-size"), blockSize); 2641 alignment = Utils.parseSize(map.get("alignment"), alignment); 2642 counts = Utils.parseIntRange(map.get("block-count-range"), null); 2643 blockRates = 2644 Utils.parseLongRange(map.get("blocks-per-second-range"), null); 2645 mMeasuredFrameRates = getMeasuredFrameRates(map); 2646 mPerformancePoints = getPerformancePoints(map); 2647 Pair<Range<Integer>, Range<Integer>> sizeRanges = 2648 parseWidthHeightRanges(map.get("size-range")); 2649 if (sizeRanges != null) { 2650 widths = sizeRanges.first; 2651 heights = sizeRanges.second; 2652 } 2653 // for now this just means using the smaller max size as 2nd 2654 // upper limit. 2655 // for now we are keeping the profile specific "width/height 2656 // in macroblocks" limits. 2657 if (map.containsKey("feature-can-swap-width-height")) { 2658 if (widths != null) { 2659 mSmallerDimensionUpperLimit = 2660 Math.min(widths.getUpper(), heights.getUpper()); 2661 widths = heights = widths.extend(heights); 2662 } else { 2663 Log.w(TAG, "feature can-swap-width-height is best used with size-range"); 2664 mSmallerDimensionUpperLimit = 2665 Math.min(mWidthRange.getUpper(), mHeightRange.getUpper()); 2666 mWidthRange = mHeightRange = mWidthRange.extend(mHeightRange); 2667 } 2668 } 2669 2670 ratios = Utils.parseRationalRange( 2671 map.get("block-aspect-ratio-range"), null); 2672 blockRatios = Utils.parseRationalRange( 2673 map.get("pixel-aspect-ratio-range"), null); 2674 frameRates = Utils.parseIntRange(map.get("frame-rate-range"), null); 2675 if (frameRates != null) { 2676 try { 2677 frameRates = frameRates.intersect(FRAME_RATE_RANGE); 2678 } catch (IllegalArgumentException e) { 2679 Log.w(TAG, "frame rate range (" + frameRates 2680 + ") is out of limits: " + FRAME_RATE_RANGE); 2681 frameRates = null; 2682 } 2683 } 2684 bitRates = Utils.parseIntRange(map.get("bitrate-range"), null); 2685 if (bitRates != null) { 2686 try { 2687 bitRates = bitRates.intersect(BITRATE_RANGE); 2688 } catch (IllegalArgumentException e) { 2689 Log.w(TAG, "bitrate range (" + bitRates 2690 + ") is out of limits: " + BITRATE_RANGE); 2691 bitRates = null; 2692 } 2693 } 2694 2695 checkPowerOfTwo( 2696 blockSize.getWidth(), "block-size width must be power of two"); 2697 checkPowerOfTwo( 2698 blockSize.getHeight(), "block-size height must be power of two"); 2699 2700 checkPowerOfTwo( 2701 alignment.getWidth(), "alignment width must be power of two"); 2702 checkPowerOfTwo( 2703 alignment.getHeight(), "alignment height must be power of two"); 2704 2705 // update block-size and alignment 2706 applyMacroBlockLimits( 2707 Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, 2708 Long.MAX_VALUE, blockSize.getWidth(), blockSize.getHeight(), 2709 alignment.getWidth(), alignment.getHeight()); 2710 2711 if ((mParent.mError & ERROR_UNSUPPORTED) != 0 || mAllowMbOverride) { 2712 // codec supports profiles that we don't know. 2713 // Use supplied values clipped to platform limits 2714 if (widths != null) { 2715 mWidthRange = getSizeRange().intersect(widths); 2716 } 2717 if (heights != null) { 2718 mHeightRange = getSizeRange().intersect(heights); 2719 } 2720 if (counts != null) { 2721 mBlockCountRange = POSITIVE_INTEGERS.intersect( 2722 Utils.factorRange(counts, mBlockWidth * mBlockHeight 2723 / blockSize.getWidth() / blockSize.getHeight())); 2724 } 2725 if (blockRates != null) { 2726 mBlocksPerSecondRange = POSITIVE_LONGS.intersect( 2727 Utils.factorRange(blockRates, mBlockWidth * mBlockHeight 2728 / blockSize.getWidth() / blockSize.getHeight())); 2729 } 2730 if (blockRatios != null) { 2731 mBlockAspectRatioRange = POSITIVE_RATIONALS.intersect( 2732 Utils.scaleRange(blockRatios, 2733 mBlockHeight / blockSize.getHeight(), 2734 mBlockWidth / blockSize.getWidth())); 2735 } 2736 if (ratios != null) { 2737 mAspectRatioRange = POSITIVE_RATIONALS.intersect(ratios); 2738 } 2739 if (frameRates != null) { 2740 mFrameRateRange = FRAME_RATE_RANGE.intersect(frameRates); 2741 } 2742 if (bitRates != null) { 2743 // only allow bitrate override if unsupported profiles were encountered 2744 if ((mParent.mError & ERROR_UNSUPPORTED) != 0) { 2745 mBitrateRange = BITRATE_RANGE.intersect(bitRates); 2746 } else { 2747 mBitrateRange = mBitrateRange.intersect(bitRates); 2748 } 2749 } 2750 } else { 2751 // no unsupported profile/levels, so restrict values to known limits 2752 if (widths != null) { 2753 mWidthRange = mWidthRange.intersect(widths); 2754 } 2755 if (heights != null) { 2756 mHeightRange = mHeightRange.intersect(heights); 2757 } 2758 if (counts != null) { 2759 mBlockCountRange = mBlockCountRange.intersect( 2760 Utils.factorRange(counts, mBlockWidth * mBlockHeight 2761 / blockSize.getWidth() / blockSize.getHeight())); 2762 } 2763 if (blockRates != null) { 2764 mBlocksPerSecondRange = mBlocksPerSecondRange.intersect( 2765 Utils.factorRange(blockRates, mBlockWidth * mBlockHeight 2766 / blockSize.getWidth() / blockSize.getHeight())); 2767 } 2768 if (blockRatios != null) { 2769 mBlockAspectRatioRange = mBlockAspectRatioRange.intersect( 2770 Utils.scaleRange(blockRatios, 2771 mBlockHeight / blockSize.getHeight(), 2772 mBlockWidth / blockSize.getWidth())); 2773 } 2774 if (ratios != null) { 2775 mAspectRatioRange = mAspectRatioRange.intersect(ratios); 2776 } 2777 if (frameRates != null) { 2778 mFrameRateRange = mFrameRateRange.intersect(frameRates); 2779 } 2780 if (bitRates != null) { 2781 mBitrateRange = mBitrateRange.intersect(bitRates); 2782 } 2783 } 2784 updateLimits(); 2785 } 2786 2787 private void applyBlockLimits( 2788 int blockWidth, int blockHeight, 2789 Range<Integer> counts, Range<Long> rates, Range<Rational> ratios) { 2790 checkPowerOfTwo(blockWidth, "blockWidth must be a power of two"); 2791 checkPowerOfTwo(blockHeight, "blockHeight must be a power of two"); 2792 2793 final int newBlockWidth = Math.max(blockWidth, mBlockWidth); 2794 final int newBlockHeight = Math.max(blockHeight, mBlockHeight); 2795 2796 // factor will always be a power-of-2 2797 int factor = 2798 newBlockWidth * newBlockHeight / mBlockWidth / mBlockHeight; 2799 if (factor != 1) { 2800 mBlockCountRange = Utils.factorRange(mBlockCountRange, factor); 2801 mBlocksPerSecondRange = Utils.factorRange( 2802 mBlocksPerSecondRange, factor); 2803 mBlockAspectRatioRange = Utils.scaleRange( 2804 mBlockAspectRatioRange, 2805 newBlockHeight / mBlockHeight, 2806 newBlockWidth / mBlockWidth); 2807 mHorizontalBlockRange = Utils.factorRange( 2808 mHorizontalBlockRange, newBlockWidth / mBlockWidth); 2809 mVerticalBlockRange = Utils.factorRange( 2810 mVerticalBlockRange, newBlockHeight / mBlockHeight); 2811 } 2812 factor = newBlockWidth * newBlockHeight / blockWidth / blockHeight; 2813 if (factor != 1) { 2814 counts = Utils.factorRange(counts, factor); 2815 rates = Utils.factorRange(rates, factor); 2816 ratios = Utils.scaleRange( 2817 ratios, newBlockHeight / blockHeight, 2818 newBlockWidth / blockWidth); 2819 } 2820 mBlockCountRange = mBlockCountRange.intersect(counts); 2821 mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(rates); 2822 mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(ratios); 2823 mBlockWidth = newBlockWidth; 2824 mBlockHeight = newBlockHeight; 2825 } 2826 2827 private void applyAlignment(int widthAlignment, int heightAlignment) { 2828 checkPowerOfTwo(widthAlignment, "widthAlignment must be a power of two"); 2829 checkPowerOfTwo(heightAlignment, "heightAlignment must be a power of two"); 2830 2831 if (widthAlignment > mBlockWidth || heightAlignment > mBlockHeight) { 2832 // maintain assumption that 0 < alignment <= block-size 2833 applyBlockLimits( 2834 Math.max(widthAlignment, mBlockWidth), 2835 Math.max(heightAlignment, mBlockHeight), 2836 POSITIVE_INTEGERS, POSITIVE_LONGS, POSITIVE_RATIONALS); 2837 } 2838 2839 mWidthAlignment = Math.max(widthAlignment, mWidthAlignment); 2840 mHeightAlignment = Math.max(heightAlignment, mHeightAlignment); 2841 2842 mWidthRange = Utils.alignRange(mWidthRange, mWidthAlignment); 2843 mHeightRange = Utils.alignRange(mHeightRange, mHeightAlignment); 2844 } 2845 2846 private void updateLimits() { 2847 // pixels -> blocks <- counts 2848 mHorizontalBlockRange = mHorizontalBlockRange.intersect( 2849 Utils.factorRange(mWidthRange, mBlockWidth)); 2850 mHorizontalBlockRange = mHorizontalBlockRange.intersect( 2851 Range.create( 2852 mBlockCountRange.getLower() / mVerticalBlockRange.getUpper(), 2853 mBlockCountRange.getUpper() / mVerticalBlockRange.getLower())); 2854 mVerticalBlockRange = mVerticalBlockRange.intersect( 2855 Utils.factorRange(mHeightRange, mBlockHeight)); 2856 mVerticalBlockRange = mVerticalBlockRange.intersect( 2857 Range.create( 2858 mBlockCountRange.getLower() / mHorizontalBlockRange.getUpper(), 2859 mBlockCountRange.getUpper() / mHorizontalBlockRange.getLower())); 2860 mBlockCountRange = mBlockCountRange.intersect( 2861 Range.create( 2862 mHorizontalBlockRange.getLower() 2863 * mVerticalBlockRange.getLower(), 2864 mHorizontalBlockRange.getUpper() 2865 * mVerticalBlockRange.getUpper())); 2866 mBlockAspectRatioRange = mBlockAspectRatioRange.intersect( 2867 new Rational( 2868 mHorizontalBlockRange.getLower(), mVerticalBlockRange.getUpper()), 2869 new Rational( 2870 mHorizontalBlockRange.getUpper(), mVerticalBlockRange.getLower())); 2871 2872 // blocks -> pixels 2873 mWidthRange = mWidthRange.intersect( 2874 (mHorizontalBlockRange.getLower() - 1) * mBlockWidth + mWidthAlignment, 2875 mHorizontalBlockRange.getUpper() * mBlockWidth); 2876 mHeightRange = mHeightRange.intersect( 2877 (mVerticalBlockRange.getLower() - 1) * mBlockHeight + mHeightAlignment, 2878 mVerticalBlockRange.getUpper() * mBlockHeight); 2879 mAspectRatioRange = mAspectRatioRange.intersect( 2880 new Rational(mWidthRange.getLower(), mHeightRange.getUpper()), 2881 new Rational(mWidthRange.getUpper(), mHeightRange.getLower())); 2882 2883 mSmallerDimensionUpperLimit = Math.min( 2884 mSmallerDimensionUpperLimit, 2885 Math.min(mWidthRange.getUpper(), mHeightRange.getUpper())); 2886 2887 // blocks -> rate 2888 mBlocksPerSecondRange = mBlocksPerSecondRange.intersect( 2889 mBlockCountRange.getLower() * (long)mFrameRateRange.getLower(), 2890 mBlockCountRange.getUpper() * (long)mFrameRateRange.getUpper()); 2891 mFrameRateRange = mFrameRateRange.intersect( 2892 (int)(mBlocksPerSecondRange.getLower() 2893 / mBlockCountRange.getUpper()), 2894 (int)(mBlocksPerSecondRange.getUpper() 2895 / (double)mBlockCountRange.getLower())); 2896 } 2897 2898 private void applyMacroBlockLimits( 2899 int maxHorizontalBlocks, int maxVerticalBlocks, 2900 int maxBlocks, long maxBlocksPerSecond, 2901 int blockWidth, int blockHeight, 2902 int widthAlignment, int heightAlignment) { 2903 applyMacroBlockLimits( 2904 1 /* minHorizontalBlocks */, 1 /* minVerticalBlocks */, 2905 maxHorizontalBlocks, maxVerticalBlocks, 2906 maxBlocks, maxBlocksPerSecond, 2907 blockWidth, blockHeight, widthAlignment, heightAlignment); 2908 } 2909 2910 private void applyMacroBlockLimits( 2911 int minHorizontalBlocks, int minVerticalBlocks, 2912 int maxHorizontalBlocks, int maxVerticalBlocks, 2913 int maxBlocks, long maxBlocksPerSecond, 2914 int blockWidth, int blockHeight, 2915 int widthAlignment, int heightAlignment) { 2916 applyAlignment(widthAlignment, heightAlignment); 2917 applyBlockLimits( 2918 blockWidth, blockHeight, Range.create(1, maxBlocks), 2919 Range.create(1L, maxBlocksPerSecond), 2920 Range.create( 2921 new Rational(1, maxVerticalBlocks), 2922 new Rational(maxHorizontalBlocks, 1))); 2923 mHorizontalBlockRange = 2924 mHorizontalBlockRange.intersect( 2925 Utils.divUp(minHorizontalBlocks, (mBlockWidth / blockWidth)), 2926 maxHorizontalBlocks / (mBlockWidth / blockWidth)); 2927 mVerticalBlockRange = 2928 mVerticalBlockRange.intersect( 2929 Utils.divUp(minVerticalBlocks, (mBlockHeight / blockHeight)), 2930 maxVerticalBlocks / (mBlockHeight / blockHeight)); 2931 } 2932 2933 private void applyLevelLimits() { 2934 long maxBlocksPerSecond = 0; 2935 int maxBlocks = 0; 2936 int maxBps = 0; 2937 int maxDPBBlocks = 0; 2938 2939 int errors = ERROR_NONE_SUPPORTED; 2940 CodecProfileLevel[] profileLevels = mParent.profileLevels; 2941 String mime = mParent.getMimeType(); 2942 2943 if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC)) { 2944 maxBlocks = 99; 2945 maxBlocksPerSecond = 1485; 2946 maxBps = 64000; 2947 maxDPBBlocks = 396; 2948 for (CodecProfileLevel profileLevel: profileLevels) { 2949 int MBPS = 0, FS = 0, BR = 0, DPB = 0; 2950 boolean supported = true; 2951 switch (profileLevel.level) { 2952 case CodecProfileLevel.AVCLevel1: 2953 MBPS = 1485; FS = 99; BR = 64; DPB = 396; break; 2954 case CodecProfileLevel.AVCLevel1b: 2955 MBPS = 1485; FS = 99; BR = 128; DPB = 396; break; 2956 case CodecProfileLevel.AVCLevel11: 2957 MBPS = 3000; FS = 396; BR = 192; DPB = 900; break; 2958 case CodecProfileLevel.AVCLevel12: 2959 MBPS = 6000; FS = 396; BR = 384; DPB = 2376; break; 2960 case CodecProfileLevel.AVCLevel13: 2961 MBPS = 11880; FS = 396; BR = 768; DPB = 2376; break; 2962 case CodecProfileLevel.AVCLevel2: 2963 MBPS = 11880; FS = 396; BR = 2000; DPB = 2376; break; 2964 case CodecProfileLevel.AVCLevel21: 2965 MBPS = 19800; FS = 792; BR = 4000; DPB = 4752; break; 2966 case CodecProfileLevel.AVCLevel22: 2967 MBPS = 20250; FS = 1620; BR = 4000; DPB = 8100; break; 2968 case CodecProfileLevel.AVCLevel3: 2969 MBPS = 40500; FS = 1620; BR = 10000; DPB = 8100; break; 2970 case CodecProfileLevel.AVCLevel31: 2971 MBPS = 108000; FS = 3600; BR = 14000; DPB = 18000; break; 2972 case CodecProfileLevel.AVCLevel32: 2973 MBPS = 216000; FS = 5120; BR = 20000; DPB = 20480; break; 2974 case CodecProfileLevel.AVCLevel4: 2975 MBPS = 245760; FS = 8192; BR = 20000; DPB = 32768; break; 2976 case CodecProfileLevel.AVCLevel41: 2977 MBPS = 245760; FS = 8192; BR = 50000; DPB = 32768; break; 2978 case CodecProfileLevel.AVCLevel42: 2979 MBPS = 522240; FS = 8704; BR = 50000; DPB = 34816; break; 2980 case CodecProfileLevel.AVCLevel5: 2981 MBPS = 589824; FS = 22080; BR = 135000; DPB = 110400; break; 2982 case CodecProfileLevel.AVCLevel51: 2983 MBPS = 983040; FS = 36864; BR = 240000; DPB = 184320; break; 2984 case CodecProfileLevel.AVCLevel52: 2985 MBPS = 2073600; FS = 36864; BR = 240000; DPB = 184320; break; 2986 case CodecProfileLevel.AVCLevel6: 2987 MBPS = 4177920; FS = 139264; BR = 240000; DPB = 696320; break; 2988 case CodecProfileLevel.AVCLevel61: 2989 MBPS = 8355840; FS = 139264; BR = 480000; DPB = 696320; break; 2990 case CodecProfileLevel.AVCLevel62: 2991 MBPS = 16711680; FS = 139264; BR = 800000; DPB = 696320; break; 2992 default: 2993 Log.w(TAG, "Unrecognized level " 2994 + profileLevel.level + " for " + mime); 2995 errors |= ERROR_UNRECOGNIZED; 2996 } 2997 switch (profileLevel.profile) { 2998 case CodecProfileLevel.AVCProfileConstrainedHigh: 2999 case CodecProfileLevel.AVCProfileHigh: 3000 BR *= 1250; break; 3001 case CodecProfileLevel.AVCProfileHigh10: 3002 BR *= 3000; break; 3003 case CodecProfileLevel.AVCProfileExtended: 3004 case CodecProfileLevel.AVCProfileHigh422: 3005 case CodecProfileLevel.AVCProfileHigh444: 3006 Log.w(TAG, "Unsupported profile " 3007 + profileLevel.profile + " for " + mime); 3008 errors |= ERROR_UNSUPPORTED; 3009 supported = false; 3010 // fall through - treat as base profile 3011 case CodecProfileLevel.AVCProfileConstrainedBaseline: 3012 case CodecProfileLevel.AVCProfileBaseline: 3013 case CodecProfileLevel.AVCProfileMain: 3014 BR *= 1000; break; 3015 default: 3016 Log.w(TAG, "Unrecognized profile " 3017 + profileLevel.profile + " for " + mime); 3018 errors |= ERROR_UNRECOGNIZED; 3019 BR *= 1000; 3020 } 3021 if (supported) { 3022 errors &= ~ERROR_NONE_SUPPORTED; 3023 } 3024 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); 3025 maxBlocks = Math.max(FS, maxBlocks); 3026 maxBps = Math.max(BR, maxBps); 3027 maxDPBBlocks = Math.max(maxDPBBlocks, DPB); 3028 } 3029 3030 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8)); 3031 applyMacroBlockLimits( 3032 maxLengthInBlocks, maxLengthInBlocks, 3033 maxBlocks, maxBlocksPerSecond, 3034 16 /* blockWidth */, 16 /* blockHeight */, 3035 1 /* widthAlignment */, 1 /* heightAlignment */); 3036 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG2)) { 3037 int maxWidth = 11, maxHeight = 9, maxRate = 15; 3038 maxBlocks = 99; 3039 maxBlocksPerSecond = 1485; 3040 maxBps = 64000; 3041 for (CodecProfileLevel profileLevel: profileLevels) { 3042 int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0; 3043 boolean supported = true; 3044 switch (profileLevel.profile) { 3045 case CodecProfileLevel.MPEG2ProfileSimple: 3046 switch (profileLevel.level) { 3047 case CodecProfileLevel.MPEG2LevelML: 3048 FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 15000; break; 3049 default: 3050 Log.w(TAG, "Unrecognized profile/level " 3051 + profileLevel.profile + "/" 3052 + profileLevel.level + " for " + mime); 3053 errors |= ERROR_UNRECOGNIZED; 3054 } 3055 break; 3056 case CodecProfileLevel.MPEG2ProfileMain: 3057 switch (profileLevel.level) { 3058 case CodecProfileLevel.MPEG2LevelLL: 3059 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 4000; break; 3060 case CodecProfileLevel.MPEG2LevelML: 3061 FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 15000; break; 3062 case CodecProfileLevel.MPEG2LevelH14: 3063 FR = 60; W = 90; H = 68; MBPS = 183600; FS = 6120; BR = 60000; break; 3064 case CodecProfileLevel.MPEG2LevelHL: 3065 FR = 60; W = 120; H = 68; MBPS = 244800; FS = 8160; BR = 80000; break; 3066 case CodecProfileLevel.MPEG2LevelHP: 3067 FR = 60; W = 120; H = 68; MBPS = 489600; FS = 8160; BR = 80000; break; 3068 default: 3069 Log.w(TAG, "Unrecognized profile/level " 3070 + profileLevel.profile + "/" 3071 + profileLevel.level + " for " + mime); 3072 errors |= ERROR_UNRECOGNIZED; 3073 } 3074 break; 3075 case CodecProfileLevel.MPEG2Profile422: 3076 case CodecProfileLevel.MPEG2ProfileSNR: 3077 case CodecProfileLevel.MPEG2ProfileSpatial: 3078 case CodecProfileLevel.MPEG2ProfileHigh: 3079 Log.i(TAG, "Unsupported profile " 3080 + profileLevel.profile + " for " + mime); 3081 errors |= ERROR_UNSUPPORTED; 3082 supported = false; 3083 break; 3084 default: 3085 Log.w(TAG, "Unrecognized profile " 3086 + profileLevel.profile + " for " + mime); 3087 errors |= ERROR_UNRECOGNIZED; 3088 } 3089 if (supported) { 3090 errors &= ~ERROR_NONE_SUPPORTED; 3091 } 3092 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); 3093 maxBlocks = Math.max(FS, maxBlocks); 3094 maxBps = Math.max(BR * 1000, maxBps); 3095 maxWidth = Math.max(W, maxWidth); 3096 maxHeight = Math.max(H, maxHeight); 3097 maxRate = Math.max(FR, maxRate); 3098 } 3099 applyMacroBlockLimits(maxWidth, maxHeight, 3100 maxBlocks, maxBlocksPerSecond, 3101 16 /* blockWidth */, 16 /* blockHeight */, 3102 1 /* widthAlignment */, 1 /* heightAlignment */); 3103 mFrameRateRange = mFrameRateRange.intersect(12, maxRate); 3104 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) { 3105 int maxWidth = 11, maxHeight = 9, maxRate = 15; 3106 maxBlocks = 99; 3107 maxBlocksPerSecond = 1485; 3108 maxBps = 64000; 3109 for (CodecProfileLevel profileLevel: profileLevels) { 3110 int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0; 3111 boolean strict = false; // true: W, H and FR are individual max limits 3112 boolean supported = true; 3113 switch (profileLevel.profile) { 3114 case CodecProfileLevel.MPEG4ProfileSimple: 3115 switch (profileLevel.level) { 3116 case CodecProfileLevel.MPEG4Level0: 3117 strict = true; 3118 FR = 15; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 64; break; 3119 case CodecProfileLevel.MPEG4Level1: 3120 FR = 30; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 64; break; 3121 case CodecProfileLevel.MPEG4Level0b: 3122 strict = true; 3123 FR = 15; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 128; break; 3124 case CodecProfileLevel.MPEG4Level2: 3125 FR = 30; W = 22; H = 18; MBPS = 5940; FS = 396; BR = 128; break; 3126 case CodecProfileLevel.MPEG4Level3: 3127 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384; break; 3128 case CodecProfileLevel.MPEG4Level4a: 3129 FR = 30; W = 40; H = 30; MBPS = 36000; FS = 1200; BR = 4000; break; 3130 case CodecProfileLevel.MPEG4Level5: 3131 FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 8000; break; 3132 case CodecProfileLevel.MPEG4Level6: 3133 FR = 30; W = 80; H = 45; MBPS = 108000; FS = 3600; BR = 12000; break; 3134 default: 3135 Log.w(TAG, "Unrecognized profile/level " 3136 + profileLevel.profile + "/" 3137 + profileLevel.level + " for " + mime); 3138 errors |= ERROR_UNRECOGNIZED; 3139 } 3140 break; 3141 case CodecProfileLevel.MPEG4ProfileAdvancedSimple: 3142 switch (profileLevel.level) { 3143 case CodecProfileLevel.MPEG4Level0: 3144 case CodecProfileLevel.MPEG4Level1: 3145 FR = 30; W = 11; H = 9; MBPS = 2970; FS = 99; BR = 128; break; 3146 case CodecProfileLevel.MPEG4Level2: 3147 FR = 30; W = 22; H = 18; MBPS = 5940; FS = 396; BR = 384; break; 3148 case CodecProfileLevel.MPEG4Level3: 3149 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 768; break; 3150 case CodecProfileLevel.MPEG4Level3b: 3151 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 1500; break; 3152 case CodecProfileLevel.MPEG4Level4: 3153 FR = 30; W = 44; H = 36; MBPS = 23760; FS = 792; BR = 3000; break; 3154 case CodecProfileLevel.MPEG4Level5: 3155 FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 8000; break; 3156 default: 3157 Log.w(TAG, "Unrecognized profile/level " 3158 + profileLevel.profile + "/" 3159 + profileLevel.level + " for " + mime); 3160 errors |= ERROR_UNRECOGNIZED; 3161 } 3162 break; 3163 case CodecProfileLevel.MPEG4ProfileMain: // 2-4 3164 case CodecProfileLevel.MPEG4ProfileNbit: // 2 3165 case CodecProfileLevel.MPEG4ProfileAdvancedRealTime: // 1-4 3166 case CodecProfileLevel.MPEG4ProfileCoreScalable: // 1-3 3167 case CodecProfileLevel.MPEG4ProfileAdvancedCoding: // 1-4 3168 case CodecProfileLevel.MPEG4ProfileCore: // 1-2 3169 case CodecProfileLevel.MPEG4ProfileAdvancedCore: // 1-4 3170 case CodecProfileLevel.MPEG4ProfileSimpleScalable: // 0-2 3171 case CodecProfileLevel.MPEG4ProfileHybrid: // 1-2 3172 3173 // Studio profiles are not supported by our codecs. 3174 3175 // Only profiles that can decode simple object types are considered. 3176 // The following profiles are not able to. 3177 case CodecProfileLevel.MPEG4ProfileBasicAnimated: // 1-2 3178 case CodecProfileLevel.MPEG4ProfileScalableTexture: // 1 3179 case CodecProfileLevel.MPEG4ProfileSimpleFace: // 1-2 3180 case CodecProfileLevel.MPEG4ProfileAdvancedScalable: // 1-3 3181 case CodecProfileLevel.MPEG4ProfileSimpleFBA: // 1-2 3182 Log.i(TAG, "Unsupported profile " 3183 + profileLevel.profile + " for " + mime); 3184 errors |= ERROR_UNSUPPORTED; 3185 supported = false; 3186 break; 3187 default: 3188 Log.w(TAG, "Unrecognized profile " 3189 + profileLevel.profile + " for " + mime); 3190 errors |= ERROR_UNRECOGNIZED; 3191 } 3192 if (supported) { 3193 errors &= ~ERROR_NONE_SUPPORTED; 3194 } 3195 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); 3196 maxBlocks = Math.max(FS, maxBlocks); 3197 maxBps = Math.max(BR * 1000, maxBps); 3198 if (strict) { 3199 maxWidth = Math.max(W, maxWidth); 3200 maxHeight = Math.max(H, maxHeight); 3201 maxRate = Math.max(FR, maxRate); 3202 } else { 3203 // assuming max 60 fps frame rate and 1:2 aspect ratio 3204 int maxDim = (int)Math.sqrt(FS * 2); 3205 maxWidth = Math.max(maxDim, maxWidth); 3206 maxHeight = Math.max(maxDim, maxHeight); 3207 maxRate = Math.max(Math.max(FR, 60), maxRate); 3208 } 3209 } 3210 applyMacroBlockLimits(maxWidth, maxHeight, 3211 maxBlocks, maxBlocksPerSecond, 3212 16 /* blockWidth */, 16 /* blockHeight */, 3213 1 /* widthAlignment */, 1 /* heightAlignment */); 3214 mFrameRateRange = mFrameRateRange.intersect(12, maxRate); 3215 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) { 3216 int maxWidth = 11, maxHeight = 9, maxRate = 15; 3217 int minWidth = maxWidth, minHeight = maxHeight; 3218 int minAlignment = 16; 3219 maxBlocks = 99; 3220 maxBlocksPerSecond = 1485; 3221 maxBps = 64000; 3222 for (CodecProfileLevel profileLevel: profileLevels) { 3223 int MBPS = 0, BR = 0, FR = 0, W = 0, H = 0, minW = minWidth, minH = minHeight; 3224 boolean strict = false; // true: support only sQCIF, QCIF (maybe CIF) 3225 switch (profileLevel.level) { 3226 case CodecProfileLevel.H263Level10: 3227 strict = true; // only supports sQCIF & QCIF 3228 FR = 15; W = 11; H = 9; BR = 1; MBPS = W * H * FR; break; 3229 case CodecProfileLevel.H263Level20: 3230 strict = true; // only supports sQCIF, QCIF & CIF 3231 FR = 30; W = 22; H = 18; BR = 2; MBPS = W * H * 15; break; 3232 case CodecProfileLevel.H263Level30: 3233 strict = true; // only supports sQCIF, QCIF & CIF 3234 FR = 30; W = 22; H = 18; BR = 6; MBPS = W * H * FR; break; 3235 case CodecProfileLevel.H263Level40: 3236 strict = true; // only supports sQCIF, QCIF & CIF 3237 FR = 30; W = 22; H = 18; BR = 32; MBPS = W * H * FR; break; 3238 case CodecProfileLevel.H263Level45: 3239 // only implies level 10 support 3240 strict = profileLevel.profile == CodecProfileLevel.H263ProfileBaseline 3241 || profileLevel.profile == 3242 CodecProfileLevel.H263ProfileBackwardCompatible; 3243 if (!strict) { 3244 minW = 1; minH = 1; minAlignment = 4; 3245 } 3246 FR = 15; W = 11; H = 9; BR = 2; MBPS = W * H * FR; break; 3247 case CodecProfileLevel.H263Level50: 3248 // only supports 50fps for H > 15 3249 minW = 1; minH = 1; minAlignment = 4; 3250 FR = 60; W = 22; H = 18; BR = 64; MBPS = W * H * 50; break; 3251 case CodecProfileLevel.H263Level60: 3252 // only supports 50fps for H > 15 3253 minW = 1; minH = 1; minAlignment = 4; 3254 FR = 60; W = 45; H = 18; BR = 128; MBPS = W * H * 50; break; 3255 case CodecProfileLevel.H263Level70: 3256 // only supports 50fps for H > 30 3257 minW = 1; minH = 1; minAlignment = 4; 3258 FR = 60; W = 45; H = 36; BR = 256; MBPS = W * H * 50; break; 3259 default: 3260 Log.w(TAG, "Unrecognized profile/level " + profileLevel.profile 3261 + "/" + profileLevel.level + " for " + mime); 3262 errors |= ERROR_UNRECOGNIZED; 3263 } 3264 switch (profileLevel.profile) { 3265 case CodecProfileLevel.H263ProfileBackwardCompatible: 3266 case CodecProfileLevel.H263ProfileBaseline: 3267 case CodecProfileLevel.H263ProfileH320Coding: 3268 case CodecProfileLevel.H263ProfileHighCompression: 3269 case CodecProfileLevel.H263ProfileHighLatency: 3270 case CodecProfileLevel.H263ProfileInterlace: 3271 case CodecProfileLevel.H263ProfileInternet: 3272 case CodecProfileLevel.H263ProfileISWV2: 3273 case CodecProfileLevel.H263ProfileISWV3: 3274 break; 3275 default: 3276 Log.w(TAG, "Unrecognized profile " 3277 + profileLevel.profile + " for " + mime); 3278 errors |= ERROR_UNRECOGNIZED; 3279 } 3280 if (strict) { 3281 // Strict levels define sub-QCIF min size and enumerated sizes. We cannot 3282 // express support for "only sQCIF & QCIF (& CIF)" using VideoCapabilities 3283 // but we can express "only QCIF (& CIF)", so set minimume size at QCIF. 3284 // minW = 8; minH = 6; 3285 minW = 11; minH = 9; 3286 } else { 3287 // any support for non-strict levels (including unrecognized profiles or 3288 // levels) allow custom frame size support beyond supported limits 3289 // (other than bitrate) 3290 mAllowMbOverride = true; 3291 } 3292 errors &= ~ERROR_NONE_SUPPORTED; 3293 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); 3294 maxBlocks = Math.max(W * H, maxBlocks); 3295 maxBps = Math.max(BR * 64000, maxBps); 3296 maxWidth = Math.max(W, maxWidth); 3297 maxHeight = Math.max(H, maxHeight); 3298 maxRate = Math.max(FR, maxRate); 3299 minWidth = Math.min(minW, minWidth); 3300 minHeight = Math.min(minH, minHeight); 3301 } 3302 // unless we encountered custom frame size support, limit size to QCIF and CIF 3303 // using aspect ratio. 3304 if (!mAllowMbOverride) { 3305 mBlockAspectRatioRange = 3306 Range.create(new Rational(11, 9), new Rational(11, 9)); 3307 } 3308 applyMacroBlockLimits( 3309 minWidth, minHeight, 3310 maxWidth, maxHeight, 3311 maxBlocks, maxBlocksPerSecond, 3312 16 /* blockWidth */, 16 /* blockHeight */, 3313 minAlignment /* widthAlignment */, minAlignment /* heightAlignment */); 3314 mFrameRateRange = Range.create(1, maxRate); 3315 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8)) { 3316 maxBlocks = Integer.MAX_VALUE; 3317 maxBlocksPerSecond = Integer.MAX_VALUE; 3318 3319 // TODO: set to 100Mbps for now, need a number for VP8 3320 maxBps = 100000000; 3321 3322 // profile levels are not indicative for VPx, but verify 3323 // them nonetheless 3324 for (CodecProfileLevel profileLevel: profileLevels) { 3325 switch (profileLevel.level) { 3326 case CodecProfileLevel.VP8Level_Version0: 3327 case CodecProfileLevel.VP8Level_Version1: 3328 case CodecProfileLevel.VP8Level_Version2: 3329 case CodecProfileLevel.VP8Level_Version3: 3330 break; 3331 default: 3332 Log.w(TAG, "Unrecognized level " 3333 + profileLevel.level + " for " + mime); 3334 errors |= ERROR_UNRECOGNIZED; 3335 } 3336 switch (profileLevel.profile) { 3337 case CodecProfileLevel.VP8ProfileMain: 3338 break; 3339 default: 3340 Log.w(TAG, "Unrecognized profile " 3341 + profileLevel.profile + " for " + mime); 3342 errors |= ERROR_UNRECOGNIZED; 3343 } 3344 errors &= ~ERROR_NONE_SUPPORTED; 3345 } 3346 3347 final int blockSize = 16; 3348 applyMacroBlockLimits(Short.MAX_VALUE, Short.MAX_VALUE, 3349 maxBlocks, maxBlocksPerSecond, blockSize, blockSize, 3350 1 /* widthAlignment */, 1 /* heightAlignment */); 3351 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) { 3352 maxBlocksPerSecond = 829440; 3353 maxBlocks = 36864; 3354 maxBps = 200000; 3355 int maxDim = 512; 3356 3357 for (CodecProfileLevel profileLevel: profileLevels) { 3358 long SR = 0; // luma sample rate 3359 int FS = 0; // luma picture size 3360 int BR = 0; // bit rate kbps 3361 int D = 0; // luma dimension 3362 switch (profileLevel.level) { 3363 case CodecProfileLevel.VP9Level1: 3364 SR = 829440; FS = 36864; BR = 200; D = 512; break; 3365 case CodecProfileLevel.VP9Level11: 3366 SR = 2764800; FS = 73728; BR = 800; D = 768; break; 3367 case CodecProfileLevel.VP9Level2: 3368 SR = 4608000; FS = 122880; BR = 1800; D = 960; break; 3369 case CodecProfileLevel.VP9Level21: 3370 SR = 9216000; FS = 245760; BR = 3600; D = 1344; break; 3371 case CodecProfileLevel.VP9Level3: 3372 SR = 20736000; FS = 552960; BR = 7200; D = 2048; break; 3373 case CodecProfileLevel.VP9Level31: 3374 SR = 36864000; FS = 983040; BR = 12000; D = 2752; break; 3375 case CodecProfileLevel.VP9Level4: 3376 SR = 83558400; FS = 2228224; BR = 18000; D = 4160; break; 3377 case CodecProfileLevel.VP9Level41: 3378 SR = 160432128; FS = 2228224; BR = 30000; D = 4160; break; 3379 case CodecProfileLevel.VP9Level5: 3380 SR = 311951360; FS = 8912896; BR = 60000; D = 8384; break; 3381 case CodecProfileLevel.VP9Level51: 3382 SR = 588251136; FS = 8912896; BR = 120000; D = 8384; break; 3383 case CodecProfileLevel.VP9Level52: 3384 SR = 1176502272; FS = 8912896; BR = 180000; D = 8384; break; 3385 case CodecProfileLevel.VP9Level6: 3386 SR = 1176502272; FS = 35651584; BR = 180000; D = 16832; break; 3387 case CodecProfileLevel.VP9Level61: 3388 SR = 2353004544L; FS = 35651584; BR = 240000; D = 16832; break; 3389 case CodecProfileLevel.VP9Level62: 3390 SR = 4706009088L; FS = 35651584; BR = 480000; D = 16832; break; 3391 default: 3392 Log.w(TAG, "Unrecognized level " 3393 + profileLevel.level + " for " + mime); 3394 errors |= ERROR_UNRECOGNIZED; 3395 } 3396 switch (profileLevel.profile) { 3397 case CodecProfileLevel.VP9Profile0: 3398 case CodecProfileLevel.VP9Profile1: 3399 case CodecProfileLevel.VP9Profile2: 3400 case CodecProfileLevel.VP9Profile3: 3401 case CodecProfileLevel.VP9Profile2HDR: 3402 case CodecProfileLevel.VP9Profile3HDR: 3403 case CodecProfileLevel.VP9Profile2HDR10Plus: 3404 case CodecProfileLevel.VP9Profile3HDR10Plus: 3405 break; 3406 default: 3407 Log.w(TAG, "Unrecognized profile " 3408 + profileLevel.profile + " for " + mime); 3409 errors |= ERROR_UNRECOGNIZED; 3410 } 3411 errors &= ~ERROR_NONE_SUPPORTED; 3412 maxBlocksPerSecond = Math.max(SR, maxBlocksPerSecond); 3413 maxBlocks = Math.max(FS, maxBlocks); 3414 maxBps = Math.max(BR * 1000, maxBps); 3415 maxDim = Math.max(D, maxDim); 3416 } 3417 3418 final int blockSize = 8; 3419 int maxLengthInBlocks = Utils.divUp(maxDim, blockSize); 3420 maxBlocks = Utils.divUp(maxBlocks, blockSize * blockSize); 3421 maxBlocksPerSecond = Utils.divUp(maxBlocksPerSecond, blockSize * blockSize); 3422 3423 applyMacroBlockLimits( 3424 maxLengthInBlocks, maxLengthInBlocks, 3425 maxBlocks, maxBlocksPerSecond, 3426 blockSize, blockSize, 3427 1 /* widthAlignment */, 1 /* heightAlignment */); 3428 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) { 3429 // CTBs are at least 8x8 so use 8x8 block size 3430 maxBlocks = 36864 >> 6; // 192x192 pixels == 576 8x8 blocks 3431 maxBlocksPerSecond = maxBlocks * 15; 3432 maxBps = 128000; 3433 for (CodecProfileLevel profileLevel: profileLevels) { 3434 double FR = 0; 3435 int FS = 0; 3436 int BR = 0; 3437 switch (profileLevel.level) { 3438 /* The HEVC spec talks only in a very convoluted manner about the 3439 existence of levels 1-3.1 for High tier, which could also be 3440 understood as 'decoders and encoders should treat these levels 3441 as if they were Main tier', so we do that. */ 3442 case CodecProfileLevel.HEVCMainTierLevel1: 3443 case CodecProfileLevel.HEVCHighTierLevel1: 3444 FR = 15; FS = 36864; BR = 128; break; 3445 case CodecProfileLevel.HEVCMainTierLevel2: 3446 case CodecProfileLevel.HEVCHighTierLevel2: 3447 FR = 30; FS = 122880; BR = 1500; break; 3448 case CodecProfileLevel.HEVCMainTierLevel21: 3449 case CodecProfileLevel.HEVCHighTierLevel21: 3450 FR = 30; FS = 245760; BR = 3000; break; 3451 case CodecProfileLevel.HEVCMainTierLevel3: 3452 case CodecProfileLevel.HEVCHighTierLevel3: 3453 FR = 30; FS = 552960; BR = 6000; break; 3454 case CodecProfileLevel.HEVCMainTierLevel31: 3455 case CodecProfileLevel.HEVCHighTierLevel31: 3456 FR = 33.75; FS = 983040; BR = 10000; break; 3457 case CodecProfileLevel.HEVCMainTierLevel4: 3458 FR = 30; FS = 2228224; BR = 12000; break; 3459 case CodecProfileLevel.HEVCHighTierLevel4: 3460 FR = 30; FS = 2228224; BR = 30000; break; 3461 case CodecProfileLevel.HEVCMainTierLevel41: 3462 FR = 60; FS = 2228224; BR = 20000; break; 3463 case CodecProfileLevel.HEVCHighTierLevel41: 3464 FR = 60; FS = 2228224; BR = 50000; break; 3465 case CodecProfileLevel.HEVCMainTierLevel5: 3466 FR = 30; FS = 8912896; BR = 25000; break; 3467 case CodecProfileLevel.HEVCHighTierLevel5: 3468 FR = 30; FS = 8912896; BR = 100000; break; 3469 case CodecProfileLevel.HEVCMainTierLevel51: 3470 FR = 60; FS = 8912896; BR = 40000; break; 3471 case CodecProfileLevel.HEVCHighTierLevel51: 3472 FR = 60; FS = 8912896; BR = 160000; break; 3473 case CodecProfileLevel.HEVCMainTierLevel52: 3474 FR = 120; FS = 8912896; BR = 60000; break; 3475 case CodecProfileLevel.HEVCHighTierLevel52: 3476 FR = 120; FS = 8912896; BR = 240000; break; 3477 case CodecProfileLevel.HEVCMainTierLevel6: 3478 FR = 30; FS = 35651584; BR = 60000; break; 3479 case CodecProfileLevel.HEVCHighTierLevel6: 3480 FR = 30; FS = 35651584; BR = 240000; break; 3481 case CodecProfileLevel.HEVCMainTierLevel61: 3482 FR = 60; FS = 35651584; BR = 120000; break; 3483 case CodecProfileLevel.HEVCHighTierLevel61: 3484 FR = 60; FS = 35651584; BR = 480000; break; 3485 case CodecProfileLevel.HEVCMainTierLevel62: 3486 FR = 120; FS = 35651584; BR = 240000; break; 3487 case CodecProfileLevel.HEVCHighTierLevel62: 3488 FR = 120; FS = 35651584; BR = 800000; break; 3489 default: 3490 Log.w(TAG, "Unrecognized level " 3491 + profileLevel.level + " for " + mime); 3492 errors |= ERROR_UNRECOGNIZED; 3493 } 3494 switch (profileLevel.profile) { 3495 case CodecProfileLevel.HEVCProfileMain: 3496 case CodecProfileLevel.HEVCProfileMain10: 3497 case CodecProfileLevel.HEVCProfileMainStill: 3498 case CodecProfileLevel.HEVCProfileMain10HDR10: 3499 case CodecProfileLevel.HEVCProfileMain10HDR10Plus: 3500 break; 3501 default: 3502 Log.w(TAG, "Unrecognized profile " 3503 + profileLevel.profile + " for " + mime); 3504 errors |= ERROR_UNRECOGNIZED; 3505 } 3506 3507 /* DPB logic: 3508 if (width * height <= FS / 4) DPB = 16; 3509 else if (width * height <= FS / 2) DPB = 12; 3510 else if (width * height <= FS * 0.75) DPB = 8; 3511 else DPB = 6; 3512 */ 3513 3514 FS >>= 6; // convert pixels to blocks 3515 errors &= ~ERROR_NONE_SUPPORTED; 3516 maxBlocksPerSecond = Math.max((int)(FR * FS), maxBlocksPerSecond); 3517 maxBlocks = Math.max(FS, maxBlocks); 3518 maxBps = Math.max(BR * 1000, maxBps); 3519 } 3520 3521 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8)); 3522 applyMacroBlockLimits( 3523 maxLengthInBlocks, maxLengthInBlocks, 3524 maxBlocks, maxBlocksPerSecond, 3525 8 /* blockWidth */, 8 /* blockHeight */, 3526 1 /* widthAlignment */, 1 /* heightAlignment */); 3527 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AV1)) { 3528 maxBlocksPerSecond = 829440; 3529 maxBlocks = 36864; 3530 maxBps = 200000; 3531 int maxDim = 512; 3532 3533 // Sample rate, Picture Size, Bit rate and luma dimension for AV1 Codec, 3534 // corresponding to the definitions in 3535 // "AV1 Bitstream & Decoding Process Specification", Annex A 3536 // found at https://aomedia.org/av1-bitstream-and-decoding-process-specification/ 3537 for (CodecProfileLevel profileLevel: profileLevels) { 3538 long SR = 0; // luma sample rate 3539 int FS = 0; // luma picture size 3540 int BR = 0; // bit rate kbps 3541 int D = 0; // luma D 3542 switch (profileLevel.level) { 3543 case CodecProfileLevel.AV1Level2: 3544 SR = 5529600; FS = 147456; BR = 1500; D = 2048; break; 3545 case CodecProfileLevel.AV1Level21: 3546 case CodecProfileLevel.AV1Level22: 3547 case CodecProfileLevel.AV1Level23: 3548 SR = 10454400; FS = 278784; BR = 3000; D = 2816; break; 3549 3550 case CodecProfileLevel.AV1Level3: 3551 SR = 24969600; FS = 665856; BR = 6000; D = 4352; break; 3552 case CodecProfileLevel.AV1Level31: 3553 case CodecProfileLevel.AV1Level32: 3554 case CodecProfileLevel.AV1Level33: 3555 SR = 39938400; FS = 1065024; BR = 10000; D = 5504; break; 3556 3557 case CodecProfileLevel.AV1Level4: 3558 SR = 77856768; FS = 2359296; BR = 12000; D = 6144; break; 3559 case CodecProfileLevel.AV1Level41: 3560 case CodecProfileLevel.AV1Level42: 3561 case CodecProfileLevel.AV1Level43: 3562 SR = 155713536; FS = 2359296; BR = 20000; D = 6144; break; 3563 3564 case CodecProfileLevel.AV1Level5: 3565 SR = 273715200; FS = 8912896; BR = 30000; D = 8192; break; 3566 case CodecProfileLevel.AV1Level51: 3567 SR = 547430400; FS = 8912896; BR = 40000; D = 8192; break; 3568 case CodecProfileLevel.AV1Level52: 3569 SR = 1094860800; FS = 8912896; BR = 60000; D = 8192; break; 3570 case CodecProfileLevel.AV1Level53: 3571 SR = 1176502272; FS = 8912896; BR = 60000; D = 8192; break; 3572 3573 case CodecProfileLevel.AV1Level6: 3574 SR = 1176502272; FS = 35651584; BR = 60000; D = 16384; break; 3575 case CodecProfileLevel.AV1Level61: 3576 SR = 2189721600L; FS = 35651584; BR = 100000; D = 16384; break; 3577 case CodecProfileLevel.AV1Level62: 3578 SR = 4379443200L; FS = 35651584; BR = 160000; D = 16384; break; 3579 case CodecProfileLevel.AV1Level63: 3580 SR = 4706009088L; FS = 35651584; BR = 160000; D = 16384; break; 3581 3582 default: 3583 Log.w(TAG, "Unrecognized level " 3584 + profileLevel.level + " for " + mime); 3585 errors |= ERROR_UNRECOGNIZED; 3586 } 3587 switch (profileLevel.profile) { 3588 case CodecProfileLevel.AV1ProfileMain8: 3589 case CodecProfileLevel.AV1ProfileMain10: 3590 case CodecProfileLevel.AV1ProfileMain10HDR10: 3591 case CodecProfileLevel.AV1ProfileMain10HDR10Plus: 3592 break; 3593 default: 3594 Log.w(TAG, "Unrecognized profile " 3595 + profileLevel.profile + " for " + mime); 3596 errors |= ERROR_UNRECOGNIZED; 3597 } 3598 errors &= ~ERROR_NONE_SUPPORTED; 3599 maxBlocksPerSecond = Math.max(SR, maxBlocksPerSecond); 3600 maxBlocks = Math.max(FS, maxBlocks); 3601 maxBps = Math.max(BR * 1000, maxBps); 3602 maxDim = Math.max(D, maxDim); 3603 } 3604 3605 final int blockSize = 8; 3606 int maxLengthInBlocks = Utils.divUp(maxDim, blockSize); 3607 maxBlocks = Utils.divUp(maxBlocks, blockSize * blockSize); 3608 maxBlocksPerSecond = Utils.divUp(maxBlocksPerSecond, blockSize * blockSize); 3609 applyMacroBlockLimits( 3610 maxLengthInBlocks, maxLengthInBlocks, 3611 maxBlocks, maxBlocksPerSecond, 3612 blockSize, blockSize, 3613 1 /* widthAlignment */, 1 /* heightAlignment */); 3614 } else { 3615 Log.w(TAG, "Unsupported mime " + mime); 3616 // using minimal bitrate here. should be overriden by 3617 // info from media_codecs.xml 3618 maxBps = 64000; 3619 errors |= ERROR_UNSUPPORTED; 3620 } 3621 mBitrateRange = Range.create(1, maxBps); 3622 mParent.mError |= errors; 3623 } 3624 } 3625 3626 /** 3627 * A class that supports querying the encoding capabilities of a codec. 3628 */ 3629 public static final class EncoderCapabilities { 3630 /** 3631 * Returns the supported range of quality values. 3632 * 3633 * Quality is implementation-specific. As a general rule, a higher quality 3634 * setting results in a better image quality and a lower compression ratio. 3635 */ 3636 public Range<Integer> getQualityRange() { 3637 return mQualityRange; 3638 } 3639 3640 /** 3641 * Returns the supported range of encoder complexity values. 3642 * <p> 3643 * Some codecs may support multiple complexity levels, where higher 3644 * complexity values use more encoder tools (e.g. perform more 3645 * intensive calculations) to improve the quality or the compression 3646 * ratio. Use a lower value to save power and/or time. 3647 */ 3648 public Range<Integer> getComplexityRange() { 3649 return mComplexityRange; 3650 } 3651 3652 /** Constant quality mode */ 3653 public static final int BITRATE_MODE_CQ = 0; 3654 /** Variable bitrate mode */ 3655 public static final int BITRATE_MODE_VBR = 1; 3656 /** Constant bitrate mode */ 3657 public static final int BITRATE_MODE_CBR = 2; 3658 /** Constant bitrate mode with frame drops */ 3659 public static final int BITRATE_MODE_CBR_FD = 3; 3660 3661 private static final Feature[] bitrates = new Feature[] { 3662 new Feature("VBR", BITRATE_MODE_VBR, true), 3663 new Feature("CBR", BITRATE_MODE_CBR, false), 3664 new Feature("CQ", BITRATE_MODE_CQ, false), 3665 new Feature("CBR-FD", BITRATE_MODE_CBR_FD, false) 3666 }; 3667 3668 private static int parseBitrateMode(String mode) { 3669 for (Feature feat: bitrates) { 3670 if (feat.mName.equalsIgnoreCase(mode)) { 3671 return feat.mValue; 3672 } 3673 } 3674 return 0; 3675 } 3676 3677 /** 3678 * Query whether a bitrate mode is supported. 3679 */ 3680 public boolean isBitrateModeSupported(int mode) { 3681 for (Feature feat: bitrates) { 3682 if (mode == feat.mValue) { 3683 return (mBitControl & (1 << mode)) != 0; 3684 } 3685 } 3686 return false; 3687 } 3688 3689 private Range<Integer> mQualityRange; 3690 private Range<Integer> mComplexityRange; 3691 private CodecCapabilities mParent; 3692 3693 /* no public constructor */ 3694 private EncoderCapabilities() { } 3695 3696 /** @hide */ 3697 public static EncoderCapabilities create( 3698 MediaFormat info, CodecCapabilities parent) { 3699 EncoderCapabilities caps = new EncoderCapabilities(); 3700 caps.init(info, parent); 3701 return caps; 3702 } 3703 3704 private void init(MediaFormat info, CodecCapabilities parent) { 3705 // no support for complexity or quality yet 3706 mParent = parent; 3707 mComplexityRange = Range.create(0, 0); 3708 mQualityRange = Range.create(0, 0); 3709 mBitControl = (1 << BITRATE_MODE_VBR); 3710 3711 applyLevelLimits(); 3712 parseFromInfo(info); 3713 } 3714 3715 private void applyLevelLimits() { 3716 String mime = mParent.getMimeType(); 3717 if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) { 3718 mComplexityRange = Range.create(0, 8); 3719 mBitControl = (1 << BITRATE_MODE_CQ); 3720 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB) 3721 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB) 3722 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW) 3723 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW) 3724 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) { 3725 mBitControl = (1 << BITRATE_MODE_CBR); 3726 } 3727 } 3728 3729 private int mBitControl; 3730 private Integer mDefaultComplexity; 3731 private Integer mDefaultQuality; 3732 private String mQualityScale; 3733 3734 private void parseFromInfo(MediaFormat info) { 3735 Map<String, Object> map = info.getMap(); 3736 3737 if (info.containsKey("complexity-range")) { 3738 mComplexityRange = Utils 3739 .parseIntRange(info.getString("complexity-range"), mComplexityRange); 3740 // TODO should we limit this to level limits? 3741 } 3742 if (info.containsKey("quality-range")) { 3743 mQualityRange = Utils 3744 .parseIntRange(info.getString("quality-range"), mQualityRange); 3745 } 3746 if (info.containsKey("feature-bitrate-modes")) { 3747 mBitControl = 0; 3748 for (String mode: info.getString("feature-bitrate-modes").split(",")) { 3749 mBitControl |= (1 << parseBitrateMode(mode)); 3750 } 3751 } 3752 3753 try { 3754 mDefaultComplexity = Integer.parseInt((String)map.get("complexity-default")); 3755 } catch (NumberFormatException e) { } 3756 3757 try { 3758 mDefaultQuality = Integer.parseInt((String)map.get("quality-default")); 3759 } catch (NumberFormatException e) { } 3760 3761 mQualityScale = (String)map.get("quality-scale"); 3762 } 3763 3764 private boolean supports( 3765 Integer complexity, Integer quality, Integer profile) { 3766 boolean ok = true; 3767 if (ok && complexity != null) { 3768 ok = mComplexityRange.contains(complexity); 3769 } 3770 if (ok && quality != null) { 3771 ok = mQualityRange.contains(quality); 3772 } 3773 if (ok && profile != null) { 3774 for (CodecProfileLevel pl: mParent.profileLevels) { 3775 if (pl.profile == profile) { 3776 profile = null; 3777 break; 3778 } 3779 } 3780 ok = profile == null; 3781 } 3782 return ok; 3783 } 3784 3785 /** @hide */ 3786 public void getDefaultFormat(MediaFormat format) { 3787 // don't list trivial quality/complexity as default for now 3788 if (!mQualityRange.getUpper().equals(mQualityRange.getLower()) 3789 && mDefaultQuality != null) { 3790 format.setInteger(MediaFormat.KEY_QUALITY, mDefaultQuality); 3791 } 3792 if (!mComplexityRange.getUpper().equals(mComplexityRange.getLower()) 3793 && mDefaultComplexity != null) { 3794 format.setInteger(MediaFormat.KEY_COMPLEXITY, mDefaultComplexity); 3795 } 3796 // bitrates are listed in order of preference 3797 for (Feature feat: bitrates) { 3798 if ((mBitControl & (1 << feat.mValue)) != 0) { 3799 format.setInteger(MediaFormat.KEY_BITRATE_MODE, feat.mValue); 3800 break; 3801 } 3802 } 3803 } 3804 3805 /** @hide */ 3806 public boolean supportsFormat(MediaFormat format) { 3807 final Map<String, Object> map = format.getMap(); 3808 final String mime = mParent.getMimeType(); 3809 3810 Integer mode = (Integer)map.get(MediaFormat.KEY_BITRATE_MODE); 3811 if (mode != null && !isBitrateModeSupported(mode)) { 3812 return false; 3813 } 3814 3815 Integer complexity = (Integer)map.get(MediaFormat.KEY_COMPLEXITY); 3816 if (MediaFormat.MIMETYPE_AUDIO_FLAC.equalsIgnoreCase(mime)) { 3817 Integer flacComplexity = 3818 (Integer)map.get(MediaFormat.KEY_FLAC_COMPRESSION_LEVEL); 3819 if (complexity == null) { 3820 complexity = flacComplexity; 3821 } else if (flacComplexity != null && !complexity.equals(flacComplexity)) { 3822 throw new IllegalArgumentException( 3823 "conflicting values for complexity and " + 3824 "flac-compression-level"); 3825 } 3826 } 3827 3828 // other audio parameters 3829 Integer profile = (Integer)map.get(MediaFormat.KEY_PROFILE); 3830 if (MediaFormat.MIMETYPE_AUDIO_AAC.equalsIgnoreCase(mime)) { 3831 Integer aacProfile = (Integer)map.get(MediaFormat.KEY_AAC_PROFILE); 3832 if (profile == null) { 3833 profile = aacProfile; 3834 } else if (aacProfile != null && !aacProfile.equals(profile)) { 3835 throw new IllegalArgumentException( 3836 "conflicting values for profile and aac-profile"); 3837 } 3838 } 3839 3840 Integer quality = (Integer)map.get(MediaFormat.KEY_QUALITY); 3841 3842 return supports(complexity, quality, profile); 3843 } 3844 }; 3845 3846 /** 3847 * Encapsulates the profiles available for a codec component. 3848 * <p>You can get a set of {@link MediaCodecInfo.CodecProfileLevel} objects for a given 3849 * {@link MediaCodecInfo} object from the 3850 * {@link MediaCodecInfo.CodecCapabilities#profileLevels} field. 3851 */ 3852 public static final class CodecProfileLevel { 3853 // These constants were originally in-line with OMX values, but this 3854 // correspondence is no longer maintained. 3855 3856 // Profiles and levels for AVC Codec, corresponding to the definitions in 3857 // "SERIES H: AUDIOVISUAL AND MULTIMEDIA SYSTEMS, 3858 // Infrastructure of audiovisual services – Coding of moving video 3859 // Advanced video coding for generic audiovisual services" 3860 // found at 3861 // https://www.itu.int/rec/T-REC-H.264-201704-I 3862 3863 /** 3864 * AVC Baseline profile. 3865 * See definition in 3866 * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>, 3867 * Annex A. 3868 */ 3869 public static final int AVCProfileBaseline = 0x01; 3870 3871 /** 3872 * AVC Main profile. 3873 * See definition in 3874 * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>, 3875 * Annex A. 3876 */ 3877 public static final int AVCProfileMain = 0x02; 3878 3879 /** 3880 * AVC Extended profile. 3881 * See definition in 3882 * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>, 3883 * Annex A. 3884 */ 3885 public static final int AVCProfileExtended = 0x04; 3886 3887 /** 3888 * AVC High profile. 3889 * See definition in 3890 * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>, 3891 * Annex A. 3892 */ 3893 public static final int AVCProfileHigh = 0x08; 3894 3895 /** 3896 * AVC High 10 profile. 3897 * See definition in 3898 * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>, 3899 * Annex A. 3900 */ 3901 public static final int AVCProfileHigh10 = 0x10; 3902 3903 /** 3904 * AVC High 4:2:2 profile. 3905 * See definition in 3906 * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>, 3907 * Annex A. 3908 */ 3909 public static final int AVCProfileHigh422 = 0x20; 3910 3911 /** 3912 * AVC High 4:4:4 profile. 3913 * See definition in 3914 * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>, 3915 * Annex A. 3916 */ 3917 public static final int AVCProfileHigh444 = 0x40; 3918 3919 /** 3920 * AVC Constrained Baseline profile. 3921 * See definition in 3922 * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>, 3923 * Annex A. 3924 */ 3925 public static final int AVCProfileConstrainedBaseline = 0x10000; 3926 3927 /** 3928 * AVC Constrained High profile. 3929 * See definition in 3930 * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>, 3931 * Annex A. 3932 */ 3933 public static final int AVCProfileConstrainedHigh = 0x80000; 3934 3935 public static final int AVCLevel1 = 0x01; 3936 public static final int AVCLevel1b = 0x02; 3937 public static final int AVCLevel11 = 0x04; 3938 public static final int AVCLevel12 = 0x08; 3939 public static final int AVCLevel13 = 0x10; 3940 public static final int AVCLevel2 = 0x20; 3941 public static final int AVCLevel21 = 0x40; 3942 public static final int AVCLevel22 = 0x80; 3943 public static final int AVCLevel3 = 0x100; 3944 public static final int AVCLevel31 = 0x200; 3945 public static final int AVCLevel32 = 0x400; 3946 public static final int AVCLevel4 = 0x800; 3947 public static final int AVCLevel41 = 0x1000; 3948 public static final int AVCLevel42 = 0x2000; 3949 public static final int AVCLevel5 = 0x4000; 3950 public static final int AVCLevel51 = 0x8000; 3951 public static final int AVCLevel52 = 0x10000; 3952 public static final int AVCLevel6 = 0x20000; 3953 public static final int AVCLevel61 = 0x40000; 3954 public static final int AVCLevel62 = 0x80000; 3955 3956 public static final int H263ProfileBaseline = 0x01; 3957 public static final int H263ProfileH320Coding = 0x02; 3958 public static final int H263ProfileBackwardCompatible = 0x04; 3959 public static final int H263ProfileISWV2 = 0x08; 3960 public static final int H263ProfileISWV3 = 0x10; 3961 public static final int H263ProfileHighCompression = 0x20; 3962 public static final int H263ProfileInternet = 0x40; 3963 public static final int H263ProfileInterlace = 0x80; 3964 public static final int H263ProfileHighLatency = 0x100; 3965 3966 public static final int H263Level10 = 0x01; 3967 public static final int H263Level20 = 0x02; 3968 public static final int H263Level30 = 0x04; 3969 public static final int H263Level40 = 0x08; 3970 public static final int H263Level45 = 0x10; 3971 public static final int H263Level50 = 0x20; 3972 public static final int H263Level60 = 0x40; 3973 public static final int H263Level70 = 0x80; 3974 3975 public static final int MPEG4ProfileSimple = 0x01; 3976 public static final int MPEG4ProfileSimpleScalable = 0x02; 3977 public static final int MPEG4ProfileCore = 0x04; 3978 public static final int MPEG4ProfileMain = 0x08; 3979 public static final int MPEG4ProfileNbit = 0x10; 3980 public static final int MPEG4ProfileScalableTexture = 0x20; 3981 public static final int MPEG4ProfileSimpleFace = 0x40; 3982 public static final int MPEG4ProfileSimpleFBA = 0x80; 3983 public static final int MPEG4ProfileBasicAnimated = 0x100; 3984 public static final int MPEG4ProfileHybrid = 0x200; 3985 public static final int MPEG4ProfileAdvancedRealTime = 0x400; 3986 public static final int MPEG4ProfileCoreScalable = 0x800; 3987 public static final int MPEG4ProfileAdvancedCoding = 0x1000; 3988 public static final int MPEG4ProfileAdvancedCore = 0x2000; 3989 public static final int MPEG4ProfileAdvancedScalable = 0x4000; 3990 public static final int MPEG4ProfileAdvancedSimple = 0x8000; 3991 3992 public static final int MPEG4Level0 = 0x01; 3993 public static final int MPEG4Level0b = 0x02; 3994 public static final int MPEG4Level1 = 0x04; 3995 public static final int MPEG4Level2 = 0x08; 3996 public static final int MPEG4Level3 = 0x10; 3997 public static final int MPEG4Level3b = 0x18; 3998 public static final int MPEG4Level4 = 0x20; 3999 public static final int MPEG4Level4a = 0x40; 4000 public static final int MPEG4Level5 = 0x80; 4001 public static final int MPEG4Level6 = 0x100; 4002 4003 public static final int MPEG2ProfileSimple = 0x00; 4004 public static final int MPEG2ProfileMain = 0x01; 4005 public static final int MPEG2Profile422 = 0x02; 4006 public static final int MPEG2ProfileSNR = 0x03; 4007 public static final int MPEG2ProfileSpatial = 0x04; 4008 public static final int MPEG2ProfileHigh = 0x05; 4009 4010 public static final int MPEG2LevelLL = 0x00; 4011 public static final int MPEG2LevelML = 0x01; 4012 public static final int MPEG2LevelH14 = 0x02; 4013 public static final int MPEG2LevelHL = 0x03; 4014 public static final int MPEG2LevelHP = 0x04; 4015 4016 public static final int AACObjectMain = 1; 4017 public static final int AACObjectLC = 2; 4018 public static final int AACObjectSSR = 3; 4019 public static final int AACObjectLTP = 4; 4020 public static final int AACObjectHE = 5; 4021 public static final int AACObjectScalable = 6; 4022 public static final int AACObjectERLC = 17; 4023 public static final int AACObjectERScalable = 20; 4024 public static final int AACObjectLD = 23; 4025 public static final int AACObjectHE_PS = 29; 4026 public static final int AACObjectELD = 39; 4027 /** xHE-AAC (includes USAC) */ 4028 public static final int AACObjectXHE = 42; 4029 4030 public static final int VP8Level_Version0 = 0x01; 4031 public static final int VP8Level_Version1 = 0x02; 4032 public static final int VP8Level_Version2 = 0x04; 4033 public static final int VP8Level_Version3 = 0x08; 4034 4035 public static final int VP8ProfileMain = 0x01; 4036 4037 /** VP9 Profile 0 4:2:0 8-bit */ 4038 public static final int VP9Profile0 = 0x01; 4039 4040 /** VP9 Profile 1 4:2:2 8-bit */ 4041 public static final int VP9Profile1 = 0x02; 4042 4043 /** VP9 Profile 2 4:2:0 10-bit */ 4044 public static final int VP9Profile2 = 0x04; 4045 4046 /** VP9 Profile 3 4:2:2 10-bit */ 4047 public static final int VP9Profile3 = 0x08; 4048 4049 // HDR profiles also support passing HDR metadata 4050 /** VP9 Profile 2 4:2:0 10-bit HDR */ 4051 public static final int VP9Profile2HDR = 0x1000; 4052 4053 /** VP9 Profile 3 4:2:2 10-bit HDR */ 4054 public static final int VP9Profile3HDR = 0x2000; 4055 4056 /** VP9 Profile 2 4:2:0 10-bit HDR10Plus */ 4057 public static final int VP9Profile2HDR10Plus = 0x4000; 4058 4059 /** VP9 Profile 3 4:2:2 10-bit HDR10Plus */ 4060 public static final int VP9Profile3HDR10Plus = 0x8000; 4061 4062 public static final int VP9Level1 = 0x1; 4063 public static final int VP9Level11 = 0x2; 4064 public static final int VP9Level2 = 0x4; 4065 public static final int VP9Level21 = 0x8; 4066 public static final int VP9Level3 = 0x10; 4067 public static final int VP9Level31 = 0x20; 4068 public static final int VP9Level4 = 0x40; 4069 public static final int VP9Level41 = 0x80; 4070 public static final int VP9Level5 = 0x100; 4071 public static final int VP9Level51 = 0x200; 4072 public static final int VP9Level52 = 0x400; 4073 public static final int VP9Level6 = 0x800; 4074 public static final int VP9Level61 = 0x1000; 4075 public static final int VP9Level62 = 0x2000; 4076 4077 public static final int HEVCProfileMain = 0x01; 4078 public static final int HEVCProfileMain10 = 0x02; 4079 public static final int HEVCProfileMainStill = 0x04; 4080 public static final int HEVCProfileMain10HDR10 = 0x1000; 4081 public static final int HEVCProfileMain10HDR10Plus = 0x2000; 4082 4083 public static final int HEVCMainTierLevel1 = 0x1; 4084 public static final int HEVCHighTierLevel1 = 0x2; 4085 public static final int HEVCMainTierLevel2 = 0x4; 4086 public static final int HEVCHighTierLevel2 = 0x8; 4087 public static final int HEVCMainTierLevel21 = 0x10; 4088 public static final int HEVCHighTierLevel21 = 0x20; 4089 public static final int HEVCMainTierLevel3 = 0x40; 4090 public static final int HEVCHighTierLevel3 = 0x80; 4091 public static final int HEVCMainTierLevel31 = 0x100; 4092 public static final int HEVCHighTierLevel31 = 0x200; 4093 public static final int HEVCMainTierLevel4 = 0x400; 4094 public static final int HEVCHighTierLevel4 = 0x800; 4095 public static final int HEVCMainTierLevel41 = 0x1000; 4096 public static final int HEVCHighTierLevel41 = 0x2000; 4097 public static final int HEVCMainTierLevel5 = 0x4000; 4098 public static final int HEVCHighTierLevel5 = 0x8000; 4099 public static final int HEVCMainTierLevel51 = 0x10000; 4100 public static final int HEVCHighTierLevel51 = 0x20000; 4101 public static final int HEVCMainTierLevel52 = 0x40000; 4102 public static final int HEVCHighTierLevel52 = 0x80000; 4103 public static final int HEVCMainTierLevel6 = 0x100000; 4104 public static final int HEVCHighTierLevel6 = 0x200000; 4105 public static final int HEVCMainTierLevel61 = 0x400000; 4106 public static final int HEVCHighTierLevel61 = 0x800000; 4107 public static final int HEVCMainTierLevel62 = 0x1000000; 4108 public static final int HEVCHighTierLevel62 = 0x2000000; 4109 4110 private static final int HEVCHighTierLevels = 4111 HEVCHighTierLevel1 | HEVCHighTierLevel2 | HEVCHighTierLevel21 | HEVCHighTierLevel3 | 4112 HEVCHighTierLevel31 | HEVCHighTierLevel4 | HEVCHighTierLevel41 | HEVCHighTierLevel5 | 4113 HEVCHighTierLevel51 | HEVCHighTierLevel52 | HEVCHighTierLevel6 | HEVCHighTierLevel61 | 4114 HEVCHighTierLevel62; 4115 4116 public static final int DolbyVisionProfileDvavPer = 0x1; 4117 public static final int DolbyVisionProfileDvavPen = 0x2; 4118 public static final int DolbyVisionProfileDvheDer = 0x4; 4119 public static final int DolbyVisionProfileDvheDen = 0x8; 4120 public static final int DolbyVisionProfileDvheDtr = 0x10; 4121 public static final int DolbyVisionProfileDvheStn = 0x20; 4122 public static final int DolbyVisionProfileDvheDth = 0x40; 4123 public static final int DolbyVisionProfileDvheDtb = 0x80; 4124 public static final int DolbyVisionProfileDvheSt = 0x100; 4125 public static final int DolbyVisionProfileDvavSe = 0x200; 4126 /** Dolby Vision AV1 profile */ 4127 @SuppressLint("AllUpper") 4128 public static final int DolbyVisionProfileDvav110 = 0x400; 4129 4130 public static final int DolbyVisionLevelHd24 = 0x1; 4131 public static final int DolbyVisionLevelHd30 = 0x2; 4132 public static final int DolbyVisionLevelFhd24 = 0x4; 4133 public static final int DolbyVisionLevelFhd30 = 0x8; 4134 public static final int DolbyVisionLevelFhd60 = 0x10; 4135 public static final int DolbyVisionLevelUhd24 = 0x20; 4136 public static final int DolbyVisionLevelUhd30 = 0x40; 4137 public static final int DolbyVisionLevelUhd48 = 0x80; 4138 public static final int DolbyVisionLevelUhd60 = 0x100; 4139 @SuppressLint("AllUpper") 4140 public static final int DolbyVisionLevelUhd120 = 0x200; 4141 @SuppressLint("AllUpper") 4142 public static final int DolbyVisionLevel8k30 = 0x400; 4143 @SuppressLint("AllUpper") 4144 public static final int DolbyVisionLevel8k60 = 0x800; 4145 4146 // Profiles and levels for AV1 Codec, corresponding to the definitions in 4147 // "AV1 Bitstream & Decoding Process Specification", Annex A 4148 // found at https://aomedia.org/av1-bitstream-and-decoding-process-specification/ 4149 4150 /** 4151 * AV1 Main profile 4:2:0 8-bit 4152 * 4153 * See definition in 4154 * <a href="https://aomedia.org/av1-bitstream-and-decoding-process-specification/">AV1 Specification</a> 4155 * Annex A. 4156 */ 4157 public static final int AV1ProfileMain8 = 0x1; 4158 4159 /** 4160 * AV1 Main profile 4:2:0 10-bit 4161 * 4162 * See definition in 4163 * <a href="https://aomedia.org/av1-bitstream-and-decoding-process-specification/">AV1 Specification</a> 4164 * Annex A. 4165 */ 4166 public static final int AV1ProfileMain10 = 0x2; 4167 4168 4169 /** AV1 Main profile 4:2:0 10-bit with HDR10. */ 4170 public static final int AV1ProfileMain10HDR10 = 0x1000; 4171 4172 /** AV1 Main profile 4:2:0 10-bit with HDR10Plus. */ 4173 public static final int AV1ProfileMain10HDR10Plus = 0x2000; 4174 4175 public static final int AV1Level2 = 0x1; 4176 public static final int AV1Level21 = 0x2; 4177 public static final int AV1Level22 = 0x4; 4178 public static final int AV1Level23 = 0x8; 4179 public static final int AV1Level3 = 0x10; 4180 public static final int AV1Level31 = 0x20; 4181 public static final int AV1Level32 = 0x40; 4182 public static final int AV1Level33 = 0x80; 4183 public static final int AV1Level4 = 0x100; 4184 public static final int AV1Level41 = 0x200; 4185 public static final int AV1Level42 = 0x400; 4186 public static final int AV1Level43 = 0x800; 4187 public static final int AV1Level5 = 0x1000; 4188 public static final int AV1Level51 = 0x2000; 4189 public static final int AV1Level52 = 0x4000; 4190 public static final int AV1Level53 = 0x8000; 4191 public static final int AV1Level6 = 0x10000; 4192 public static final int AV1Level61 = 0x20000; 4193 public static final int AV1Level62 = 0x40000; 4194 public static final int AV1Level63 = 0x80000; 4195 public static final int AV1Level7 = 0x100000; 4196 public static final int AV1Level71 = 0x200000; 4197 public static final int AV1Level72 = 0x400000; 4198 public static final int AV1Level73 = 0x800000; 4199 4200 /** DTS codec profile for DTS HRA. */ 4201 @SuppressLint("AllUpper") 4202 public static final int DTS_HDProfileHRA = 0x1; 4203 /** DTS codec profile for DTS Express. */ 4204 @SuppressLint("AllUpper") 4205 public static final int DTS_HDProfileLBR = 0x2; 4206 /** DTS codec profile for DTS-HD Master Audio */ 4207 @SuppressLint("AllUpper") 4208 public static final int DTS_HDProfileMA = 0x4; 4209 /** DTS codec profile for DTS:X Profile 1 */ 4210 @SuppressLint("AllUpper") 4211 public static final int DTS_UHDProfileP1 = 0x1; 4212 /** DTS codec profile for DTS:X Profile 2 */ 4213 @SuppressLint("AllUpper") 4214 public static final int DTS_UHDProfileP2 = 0x2; 4215 4216 // Profiles and levels for AC-4 Codec, corresponding to the definitions in 4217 // "The MIME codecs parameter", Annex E.13 4218 // found at https://www.etsi.org/deliver/etsi_ts/103100_103199/10319002/01.02.01_60/ts_10319002v010201p.pdf 4219 // profile = ((1 << bitstream_version) << 8) | (1 << presentation_version); 4220 // level = 1 << mdcompat; 4221 4222 @SuppressLint("AllUpper") 4223 private static final int AC4BitstreamVersion0 = 0x01; 4224 @SuppressLint("AllUpper") 4225 private static final int AC4BitstreamVersion1 = 0x02; 4226 @SuppressLint("AllUpper") 4227 private static final int AC4BitstreamVersion2 = 0x04; 4228 4229 @SuppressLint("AllUpper") 4230 private static final int AC4PresentationVersion0 = 0x01; 4231 @SuppressLint("AllUpper") 4232 private static final int AC4PresentationVersion1 = 0x02; 4233 @SuppressLint("AllUpper") 4234 private static final int AC4PresentationVersion2 = 0x04; 4235 4236 /** 4237 * AC-4 codec profile with bitstream_version 0 and presentation_version 0 4238 * as per ETSI TS 103 190-2 v1.2.1 4239 */ 4240 @SuppressLint("AllUpper") 4241 public static final int AC4Profile00 = AC4BitstreamVersion0 << 8 | AC4PresentationVersion0; 4242 4243 /** 4244 * AC-4 codec profile with bitstream_version 1 and presentation_version 0 4245 * as per ETSI TS 103 190-2 v1.2.1 4246 */ 4247 @SuppressLint("AllUpper") 4248 public static final int AC4Profile10 = AC4BitstreamVersion1 << 8 | AC4PresentationVersion0; 4249 4250 /** 4251 * AC-4 codec profile with bitstream_version 1 and presentation_version 1 4252 * as per ETSI TS 103 190-2 v1.2.1 4253 */ 4254 @SuppressLint("AllUpper") 4255 public static final int AC4Profile11 = AC4BitstreamVersion1 << 8 | AC4PresentationVersion1; 4256 4257 /** 4258 * AC-4 codec profile with bitstream_version 2 and presentation_version 1 4259 * as per ETSI TS 103 190-2 v1.2.1 4260 */ 4261 @SuppressLint("AllUpper") 4262 public static final int AC4Profile21 = AC4BitstreamVersion2 << 8 | AC4PresentationVersion1; 4263 4264 /** 4265 * AC-4 codec profile with bitstream_version 2 and presentation_version 2 4266 * as per ETSI TS 103 190-2 v1.2.1 4267 */ 4268 @SuppressLint("AllUpper") 4269 public static final int AC4Profile22 = AC4BitstreamVersion2 << 8 | AC4PresentationVersion2; 4270 4271 /** AC-4 codec level corresponding to mdcompat 0 as per ETSI TS 103 190-2 v1.2.1 */ 4272 @SuppressLint("AllUpper") 4273 public static final int AC4Level0 = 0x01; 4274 /** AC-4 codec level corresponding to mdcompat 1 as per ETSI TS 103 190-2 v1.2.1 */ 4275 @SuppressLint("AllUpper") 4276 public static final int AC4Level1 = 0x02; 4277 /** AC-4 codec level corresponding to mdcompat 2 as per ETSI TS 103 190-2 v1.2.1 */ 4278 @SuppressLint("AllUpper") 4279 public static final int AC4Level2 = 0x04; 4280 /** AC-4 codec level corresponding to mdcompat 3 as per ETSI TS 103 190-2 v1.2.1 */ 4281 @SuppressLint("AllUpper") 4282 public static final int AC4Level3 = 0x08; 4283 /** AC-4 codec level corresponding to mdcompat 4 as per ETSI TS 103 190-2 v1.2.1 */ 4284 @SuppressLint("AllUpper") 4285 public static final int AC4Level4 = 0x10; 4286 4287 /** 4288 * The profile of the media content. Depending on the type of media this can be 4289 * one of the profile values defined in this class. 4290 */ 4291 public int profile; 4292 4293 /** 4294 * The level of the media content. Depending on the type of media this can be 4295 * one of the level values defined in this class. 4296 * 4297 * Note that VP9 decoder on platforms before {@link android.os.Build.VERSION_CODES#N} may 4298 * not advertise a profile level support. For those VP9 decoders, please use 4299 * {@link VideoCapabilities} to determine the codec capabilities. 4300 */ 4301 public int level; 4302 4303 @Override 4304 public boolean equals(Object obj) { 4305 if (obj == null) { 4306 return false; 4307 } 4308 if (obj instanceof CodecProfileLevel) { 4309 CodecProfileLevel other = (CodecProfileLevel)obj; 4310 return other.profile == profile && other.level == level; 4311 } 4312 return false; 4313 } 4314 4315 @Override 4316 public int hashCode() { 4317 return Long.hashCode(((long)profile << Integer.SIZE) | level); 4318 } 4319 }; 4320 4321 /** 4322 * Enumerates the capabilities of the codec component. Since a single 4323 * component can support data of a variety of types, the type has to be 4324 * specified to yield a meaningful result. 4325 * @param type The MIME type to query 4326 */ 4327 public final CodecCapabilities getCapabilitiesForType( 4328 String type) { 4329 CodecCapabilities caps = mCaps.get(type); 4330 if (caps == null) { 4331 throw new IllegalArgumentException("codec does not support type"); 4332 } 4333 // clone writable object 4334 return caps.dup(); 4335 } 4336 4337 /** @hide */ 4338 public MediaCodecInfo makeRegular() { 4339 ArrayList<CodecCapabilities> caps = new ArrayList<CodecCapabilities>(); 4340 for (CodecCapabilities c: mCaps.values()) { 4341 if (c.isRegular()) { 4342 caps.add(c); 4343 } 4344 } 4345 if (caps.size() == 0) { 4346 return null; 4347 } else if (caps.size() == mCaps.size()) { 4348 return this; 4349 } 4350 4351 return new MediaCodecInfo( 4352 mName, mCanonicalName, mFlags, 4353 caps.toArray(new CodecCapabilities[caps.size()])); 4354 } 4355 } 4356