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 android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.util.Log; 22 import android.util.Pair; 23 import android.util.Range; 24 import android.util.Rational; 25 import android.util.Size; 26 27 import java.util.ArrayList; 28 import java.util.Arrays; 29 import java.util.HashMap; 30 import java.util.Map; 31 import java.util.Set; 32 33 import static android.media.Utils.intersectSortedDistinctRanges; 34 import static android.media.Utils.sortDistinctRanges; 35 36 /** 37 * Provides information about a given media codec available on the device. You can 38 * iterate through all codecs available by querying {@link MediaCodecList}. For example, 39 * here's how to find an encoder that supports a given MIME type: 40 * <pre> 41 * private static MediaCodecInfo selectCodec(String mimeType) { 42 * int numCodecs = MediaCodecList.getCodecCount(); 43 * for (int i = 0; i < numCodecs; i++) { 44 * MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i); 45 * 46 * if (!codecInfo.isEncoder()) { 47 * continue; 48 * } 49 * 50 * String[] types = codecInfo.getSupportedTypes(); 51 * for (int j = 0; j < types.length; j++) { 52 * if (types[j].equalsIgnoreCase(mimeType)) { 53 * return codecInfo; 54 * } 55 * } 56 * } 57 * return null; 58 * }</pre> 59 * 60 */ 61 public final class MediaCodecInfo { 62 private boolean mIsEncoder; 63 private String mName; 64 private Map<String, CodecCapabilities> mCaps; 65 MediaCodecInfo( String name, boolean isEncoder, CodecCapabilities[] caps)66 /* package private */ MediaCodecInfo( 67 String name, boolean isEncoder, CodecCapabilities[] caps) { 68 mName = name; 69 mIsEncoder = isEncoder; 70 mCaps = new HashMap<String, CodecCapabilities>(); 71 for (CodecCapabilities c: caps) { 72 mCaps.put(c.getMimeType(), c); 73 } 74 } 75 76 /** 77 * Retrieve the codec name. 78 */ getName()79 public final String getName() { 80 return mName; 81 } 82 83 /** 84 * Query if the codec is an encoder. 85 */ isEncoder()86 public final boolean isEncoder() { 87 return mIsEncoder; 88 } 89 90 /** 91 * Query the media types supported by the codec. 92 */ getSupportedTypes()93 public final String[] getSupportedTypes() { 94 Set<String> typeSet = mCaps.keySet(); 95 String[] types = typeSet.toArray(new String[typeSet.size()]); 96 Arrays.sort(types); 97 return types; 98 } 99 checkPowerOfTwo(int value, String message)100 private static int checkPowerOfTwo(int value, String message) { 101 if ((value & (value - 1)) != 0) { 102 throw new IllegalArgumentException(message); 103 } 104 return value; 105 } 106 107 private static class Feature { 108 public String mName; 109 public int mValue; 110 public boolean mDefault; Feature(String name, int value, boolean def)111 public Feature(String name, int value, boolean def) { 112 mName = name; 113 mValue = value; 114 mDefault = def; 115 } 116 } 117 118 // COMMON CONSTANTS 119 private static final Range<Integer> POSITIVE_INTEGERS = 120 Range.create(1, Integer.MAX_VALUE); 121 private static final Range<Long> POSITIVE_LONGS = 122 Range.create(1l, Long.MAX_VALUE); 123 private static final Range<Rational> POSITIVE_RATIONALS = 124 Range.create(new Rational(1, Integer.MAX_VALUE), 125 new Rational(Integer.MAX_VALUE, 1)); 126 private static final Range<Integer> SIZE_RANGE = Range.create(1, 32768); 127 private static final Range<Integer> FRAME_RATE_RANGE = Range.create(0, 960); 128 private static final Range<Integer> BITRATE_RANGE = Range.create(0, 500000000); 129 private static final int DEFAULT_MAX_SUPPORTED_INSTANCES = 32; 130 private static final int MAX_SUPPORTED_INSTANCES_LIMIT = 256; 131 132 // found stuff that is not supported by framework (=> this should not happen) 133 private static final int ERROR_UNRECOGNIZED = (1 << 0); 134 // found profile/level for which we don't have capability estimates 135 private static final int ERROR_UNSUPPORTED = (1 << 1); 136 // have not found any profile/level for which we don't have capability estimate 137 private static final int ERROR_NONE_SUPPORTED = (1 << 2); 138 139 140 /** 141 * Encapsulates the capabilities of a given codec component. 142 * For example, what profile/level combinations it supports and what colorspaces 143 * it is capable of providing the decoded data in, as well as some 144 * codec-type specific capability flags. 145 * <p>You can get an instance for a given {@link MediaCodecInfo} object with 146 * {@link MediaCodecInfo#getCapabilitiesForType getCapabilitiesForType()}, passing a MIME type. 147 */ 148 public static final class CodecCapabilities { CodecCapabilities()149 public CodecCapabilities() { 150 } 151 152 // CLASSIFICATION 153 private String mMime; 154 private int mMaxSupportedInstances; 155 156 // LEGACY FIELDS 157 158 // Enumerates supported profile/level combinations as defined 159 // by the type of encoded data. These combinations impose restrictions 160 // on video resolution, bitrate... and limit the available encoder tools 161 // such as B-frame support, arithmetic coding... 162 public CodecProfileLevel[] profileLevels; // NOTE this array is modifiable by user 163 164 // from OMX_COLOR_FORMATTYPE 165 /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */ 166 public static final int COLOR_FormatMonochrome = 1; 167 /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */ 168 public static final int COLOR_Format8bitRGB332 = 2; 169 /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */ 170 public static final int COLOR_Format12bitRGB444 = 3; 171 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 172 public static final int COLOR_Format16bitARGB4444 = 4; 173 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 174 public static final int COLOR_Format16bitARGB1555 = 5; 175 176 /** 177 * 16 bits per pixel RGB color format, with 5-bit red & blue and 6-bit green component. 178 * <p> 179 * Using 16-bit little-endian representation, colors stored as Red 15:11, Green 10:5, Blue 4:0. 180 * <pre> 181 * byte byte 182 * <--------- i --------> | <------ i + 1 ------> 183 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 184 * | BLUE | GREEN | RED | 185 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 186 * 0 4 5 7 0 2 3 7 187 * bit 188 * </pre> 189 * 190 * This format corresponds to {@link android.graphics.PixelFormat#RGB_565} and 191 * {@link android.graphics.ImageFormat#RGB_565}. 192 */ 193 public static final int COLOR_Format16bitRGB565 = 6; 194 /** @deprecated Use {@link #COLOR_Format16bitRGB565}. */ 195 public static final int COLOR_Format16bitBGR565 = 7; 196 /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */ 197 public static final int COLOR_Format18bitRGB666 = 8; 198 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 199 public static final int COLOR_Format18bitARGB1665 = 9; 200 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 201 public static final int COLOR_Format19bitARGB1666 = 10; 202 203 /** @deprecated Use {@link #COLOR_Format24bitBGR888} or {@link #COLOR_FormatRGBFlexible}. */ 204 public static final int COLOR_Format24bitRGB888 = 11; 205 206 /** 207 * 24 bits per pixel RGB color format, with 8-bit red, green & blue components. 208 * <p> 209 * Using 24-bit little-endian representation, colors stored as Red 7:0, Green 15:8, Blue 23:16. 210 * <pre> 211 * byte byte byte 212 * <------ i -----> | <---- i+1 ----> | <---- i+2 -----> 213 * +-----------------+-----------------+-----------------+ 214 * | RED | GREEN | BLUE | 215 * +-----------------+-----------------+-----------------+ 216 * </pre> 217 * 218 * This format corresponds to {@link android.graphics.PixelFormat#RGB_888}, and can also be 219 * represented as a flexible format by {@link #COLOR_FormatRGBFlexible}. 220 */ 221 public static final int COLOR_Format24bitBGR888 = 12; 222 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 223 public static final int COLOR_Format24bitARGB1887 = 13; 224 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 225 public static final int COLOR_Format25bitARGB1888 = 14; 226 227 /** 228 * @deprecated Use {@link #COLOR_Format32bitABGR8888} Or {@link #COLOR_FormatRGBAFlexible}. 229 */ 230 public static final int COLOR_Format32bitBGRA8888 = 15; 231 /** 232 * @deprecated Use {@link #COLOR_Format32bitABGR8888} Or {@link #COLOR_FormatRGBAFlexible}. 233 */ 234 public static final int COLOR_Format32bitARGB8888 = 16; 235 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 236 public static final int COLOR_FormatYUV411Planar = 17; 237 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 238 public static final int COLOR_FormatYUV411PackedPlanar = 18; 239 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 240 public static final int COLOR_FormatYUV420Planar = 19; 241 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 242 public static final int COLOR_FormatYUV420PackedPlanar = 20; 243 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 244 public static final int COLOR_FormatYUV420SemiPlanar = 21; 245 246 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 247 public static final int COLOR_FormatYUV422Planar = 22; 248 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 249 public static final int COLOR_FormatYUV422PackedPlanar = 23; 250 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 251 public static final int COLOR_FormatYUV422SemiPlanar = 24; 252 253 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 254 public static final int COLOR_FormatYCbYCr = 25; 255 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 256 public static final int COLOR_FormatYCrYCb = 26; 257 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 258 public static final int COLOR_FormatCbYCrY = 27; 259 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 260 public static final int COLOR_FormatCrYCbY = 28; 261 262 /** @deprecated Use {@link #COLOR_FormatYUV444Flexible}. */ 263 public static final int COLOR_FormatYUV444Interleaved = 29; 264 265 /** 266 * SMIA 8-bit Bayer format. 267 * Each byte represents the top 8-bits of a 10-bit signal. 268 */ 269 public static final int COLOR_FormatRawBayer8bit = 30; 270 /** 271 * SMIA 10-bit Bayer format. 272 */ 273 public static final int COLOR_FormatRawBayer10bit = 31; 274 275 /** 276 * SMIA 8-bit compressed Bayer format. 277 * Each byte represents a sample from the 10-bit signal that is compressed into 8-bits 278 * using DPCM/PCM compression, as defined by the SMIA Functional Specification. 279 */ 280 public static final int COLOR_FormatRawBayer8bitcompressed = 32; 281 282 /** @deprecated Use {@link #COLOR_FormatL8}. */ 283 public static final int COLOR_FormatL2 = 33; 284 /** @deprecated Use {@link #COLOR_FormatL8}. */ 285 public static final int COLOR_FormatL4 = 34; 286 287 /** 288 * 8 bits per pixel Y color format. 289 * <p> 290 * Each byte contains a single pixel. 291 * This format corresponds to {@link android.graphics.PixelFormat#L_8}. 292 */ 293 public static final int COLOR_FormatL8 = 35; 294 295 /** 296 * 16 bits per pixel, little-endian Y color format. 297 * <p> 298 * <pre> 299 * byte byte 300 * <--------- i --------> | <------ i + 1 ------> 301 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 302 * | Y | 303 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 304 * 0 7 0 7 305 * bit 306 * </pre> 307 */ 308 public static final int COLOR_FormatL16 = 36; 309 /** @deprecated Use {@link #COLOR_FormatL16}. */ 310 public static final int COLOR_FormatL24 = 37; 311 312 /** 313 * 32 bits per pixel, little-endian Y color format. 314 * <p> 315 * <pre> 316 * byte byte byte byte 317 * <------ i -----> | <---- i+1 ----> | <---- i+2 ----> | <---- i+3 -----> 318 * +-----------------+-----------------+-----------------+-----------------+ 319 * | Y | 320 * +-----------------+-----------------+-----------------+-----------------+ 321 * 0 7 0 7 0 7 0 7 322 * bit 323 * </pre> 324 * 325 * @deprecated Use {@link #COLOR_FormatL16}. 326 */ 327 public static final int COLOR_FormatL32 = 38; 328 329 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 330 public static final int COLOR_FormatYUV420PackedSemiPlanar = 39; 331 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 332 public static final int COLOR_FormatYUV422PackedSemiPlanar = 40; 333 334 /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */ 335 public static final int COLOR_Format18BitBGR666 = 41; 336 337 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 338 public static final int COLOR_Format24BitARGB6666 = 42; 339 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 340 public static final int COLOR_Format24BitABGR6666 = 43; 341 342 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 343 public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100; 344 // COLOR_FormatSurface indicates that the data will be a GraphicBuffer metadata reference. 345 // In OMX this is called OMX_COLOR_FormatAndroidOpaque. 346 public static final int COLOR_FormatSurface = 0x7F000789; 347 348 /** 349 * 32 bits per pixel RGBA color format, with 8-bit red, green, blue, and alpha components. 350 * <p> 351 * Using 32-bit little-endian representation, colors stored as Red 7:0, Green 15:8, 352 * Blue 23:16, and Alpha 31:24. 353 * <pre> 354 * byte byte byte byte 355 * <------ i -----> | <---- i+1 ----> | <---- i+2 ----> | <---- i+3 -----> 356 * +-----------------+-----------------+-----------------+-----------------+ 357 * | RED | GREEN | BLUE | ALPHA | 358 * +-----------------+-----------------+-----------------+-----------------+ 359 * </pre> 360 * 361 * This corresponds to {@link android.graphics.PixelFormat#RGBA_8888}. 362 */ 363 public static final int COLOR_Format32bitABGR8888 = 0x7F00A000; 364 365 /** 366 * Flexible 12 bits per pixel, subsampled YUV color format with 8-bit chroma and luma 367 * components. 368 * <p> 369 * Chroma planes are subsampled by 2 both horizontally and vertically. 370 * Use this format with {@link Image}. 371 * This format corresponds to {@link android.graphics.ImageFormat#YUV_420_888}, 372 * and can represent the {@link #COLOR_FormatYUV411Planar}, 373 * {@link #COLOR_FormatYUV411PackedPlanar}, {@link #COLOR_FormatYUV420Planar}, 374 * {@link #COLOR_FormatYUV420PackedPlanar}, {@link #COLOR_FormatYUV420SemiPlanar} 375 * and {@link #COLOR_FormatYUV420PackedSemiPlanar} formats. 376 * 377 * @see Image#getFormat 378 */ 379 public static final int COLOR_FormatYUV420Flexible = 0x7F420888; 380 381 /** 382 * Flexible 16 bits per pixel, subsampled YUV color format with 8-bit chroma and luma 383 * components. 384 * <p> 385 * Chroma planes are horizontally subsampled by 2. Use this format with {@link Image}. 386 * This format corresponds to {@link android.graphics.ImageFormat#YUV_422_888}, 387 * and can represent the {@link #COLOR_FormatYCbYCr}, {@link #COLOR_FormatYCrYCb}, 388 * {@link #COLOR_FormatCbYCrY}, {@link #COLOR_FormatCrYCbY}, 389 * {@link #COLOR_FormatYUV422Planar}, {@link #COLOR_FormatYUV422PackedPlanar}, 390 * {@link #COLOR_FormatYUV422SemiPlanar} and {@link #COLOR_FormatYUV422PackedSemiPlanar} 391 * formats. 392 * 393 * @see Image#getFormat 394 */ 395 public static final int COLOR_FormatYUV422Flexible = 0x7F422888; 396 397 /** 398 * Flexible 24 bits per pixel YUV color format with 8-bit chroma and luma 399 * components. 400 * <p> 401 * Chroma planes are not subsampled. Use this format with {@link Image}. 402 * This format corresponds to {@link android.graphics.ImageFormat#YUV_444_888}, 403 * and can represent the {@link #COLOR_FormatYUV444Interleaved} format. 404 * @see Image#getFormat 405 */ 406 public static final int COLOR_FormatYUV444Flexible = 0x7F444888; 407 408 /** 409 * Flexible 24 bits per pixel RGB color format with 8-bit red, green and blue 410 * components. 411 * <p> 412 * Use this format with {@link Image}. This format corresponds to 413 * {@link android.graphics.ImageFormat#FLEX_RGB_888}, and can represent 414 * {@link #COLOR_Format24bitBGR888} and {@link #COLOR_Format24bitRGB888} formats. 415 * @see Image#getFormat. 416 */ 417 public static final int COLOR_FormatRGBFlexible = 0x7F36B888; 418 419 /** 420 * Flexible 32 bits per pixel RGBA color format with 8-bit red, green, blue, and alpha 421 * components. 422 * <p> 423 * Use this format with {@link Image}. This format corresponds to 424 * {@link android.graphics.ImageFormat#FLEX_RGBA_8888}, and can represent 425 * {@link #COLOR_Format32bitBGRA8888}, {@link #COLOR_Format32bitABGR8888} and 426 * {@link #COLOR_Format32bitARGB8888} formats. 427 * 428 * @see Image#getFormat 429 */ 430 public static final int COLOR_FormatRGBAFlexible = 0x7F36A888; 431 432 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 433 public static final int COLOR_QCOM_FormatYUV420SemiPlanar = 0x7fa30c00; 434 435 /** 436 * Defined in the OpenMAX IL specs, color format values are drawn from 437 * OMX_COLOR_FORMATTYPE. 438 */ 439 public int[] colorFormats; // NOTE this array is modifiable by user 440 441 // FEATURES 442 443 private int mFlagsSupported; 444 private int mFlagsRequired; 445 private int mFlagsVerified; 446 447 /** 448 * <b>video decoder only</b>: codec supports seamless resolution changes. 449 */ 450 public static final String FEATURE_AdaptivePlayback = "adaptive-playback"; 451 452 /** 453 * <b>video decoder only</b>: codec supports secure decryption. 454 */ 455 public static final String FEATURE_SecurePlayback = "secure-playback"; 456 457 /** 458 * <b>video or audio decoder only</b>: codec supports tunneled playback. 459 */ 460 public static final String FEATURE_TunneledPlayback = "tunneled-playback"; 461 462 /** 463 * <b>video decoder only</b>: codec supports queuing partial frames. 464 */ 465 public static final String FEATURE_PartialFrame = "partial-frame"; 466 467 /** 468 * <b>video encoder only</b>: codec supports intra refresh. 469 */ 470 public static final String FEATURE_IntraRefresh = "intra-refresh"; 471 472 /** 473 * Query codec feature capabilities. 474 * <p> 475 * These features are supported to be used by the codec. These 476 * include optional features that can be turned on, as well as 477 * features that are always on. 478 */ isFeatureSupported(String name)479 public final boolean isFeatureSupported(String name) { 480 return checkFeature(name, mFlagsSupported); 481 } 482 483 /** 484 * Query codec feature requirements. 485 * <p> 486 * These features are required to be used by the codec, and as such, 487 * they are always turned on. 488 */ isFeatureRequired(String name)489 public final boolean isFeatureRequired(String name) { 490 return checkFeature(name, mFlagsRequired); 491 } 492 493 private static final Feature[] decoderFeatures = { 494 new Feature(FEATURE_AdaptivePlayback, (1 << 0), true), 495 new Feature(FEATURE_SecurePlayback, (1 << 1), false), 496 new Feature(FEATURE_TunneledPlayback, (1 << 2), false), 497 new Feature(FEATURE_PartialFrame, (1 << 3), false), 498 }; 499 500 private static final Feature[] encoderFeatures = { 501 new Feature(FEATURE_IntraRefresh, (1 << 0), false), 502 }; 503 504 /** @hide */ validFeatures()505 public String[] validFeatures() { 506 Feature[] features = getValidFeatures(); 507 String[] res = new String[features.length]; 508 for (int i = 0; i < res.length; i++) { 509 res[i] = features[i].mName; 510 } 511 return res; 512 } 513 getValidFeatures()514 private Feature[] getValidFeatures() { 515 if (!isEncoder()) { 516 return decoderFeatures; 517 } 518 return encoderFeatures; 519 } 520 checkFeature(String name, int flags)521 private boolean checkFeature(String name, int flags) { 522 for (Feature feat: getValidFeatures()) { 523 if (feat.mName.equals(name)) { 524 return (flags & feat.mValue) != 0; 525 } 526 } 527 return false; 528 } 529 530 /** @hide */ isRegular()531 public boolean isRegular() { 532 // regular codecs only require default features 533 for (Feature feat: getValidFeatures()) { 534 if (!feat.mDefault && isFeatureRequired(feat.mName)) { 535 return false; 536 } 537 } 538 return true; 539 } 540 541 /** 542 * Query whether codec supports a given {@link MediaFormat}. 543 * 544 * <p class=note> 545 * <strong>Note:</strong> On {@link android.os.Build.VERSION_CODES#LOLLIPOP}, 546 * {@code format} must not contain a {@linkplain MediaFormat#KEY_FRAME_RATE 547 * frame rate}. Use 548 * <code class=prettyprint>format.setString(MediaFormat.KEY_FRAME_RATE, null)</code> 549 * to clear any existing frame rate setting in the format. 550 * <p> 551 * 552 * The following table summarizes the format keys considered by this method. 553 * 554 * <table style="width: 0%"> 555 * <thead> 556 * <tr> 557 * <th rowspan=3>OS Version(s)</th> 558 * <td colspan=3>{@code MediaFormat} keys considered for</th> 559 * </tr><tr> 560 * <th>Audio Codecs</th> 561 * <th>Video Codecs</th> 562 * <th>Encoders</th> 563 * </tr> 564 * </thead> 565 * <tbody> 566 * <tr> 567 * <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP}</th> 568 * <td rowspan=3>{@link MediaFormat#KEY_MIME}<sup>*</sup>,<br> 569 * {@link MediaFormat#KEY_SAMPLE_RATE},<br> 570 * {@link MediaFormat#KEY_CHANNEL_COUNT},</td> 571 * <td>{@link MediaFormat#KEY_MIME}<sup>*</sup>,<br> 572 * {@link CodecCapabilities#FEATURE_AdaptivePlayback}<sup>D</sup>,<br> 573 * {@link CodecCapabilities#FEATURE_SecurePlayback}<sup>D</sup>,<br> 574 * {@link CodecCapabilities#FEATURE_TunneledPlayback}<sup>D</sup>,<br> 575 * {@link MediaFormat#KEY_WIDTH},<br> 576 * {@link MediaFormat#KEY_HEIGHT},<br> 577 * <strong>no</strong> {@code KEY_FRAME_RATE}</td> 578 * <td rowspan=4>{@link MediaFormat#KEY_BITRATE_MODE},<br> 579 * {@link MediaFormat#KEY_PROFILE} 580 * (and/or {@link MediaFormat#KEY_AAC_PROFILE}<sup>~</sup>),<br> 581 * <!-- {link MediaFormat#KEY_QUALITY},<br> --> 582 * {@link MediaFormat#KEY_COMPLEXITY} 583 * (and/or {@link MediaFormat#KEY_FLAC_COMPRESSION_LEVEL}<sup>~</sup>)</td> 584 * </tr><tr> 585 * <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}</th> 586 * <td rowspan=2>as above, plus<br> 587 * {@link MediaFormat#KEY_FRAME_RATE}</td> 588 * </tr><tr> 589 * <td>{@link android.os.Build.VERSION_CODES#M}</th> 590 * </tr><tr> 591 * <td>{@link android.os.Build.VERSION_CODES#N}</th> 592 * <td>as above, plus<br> 593 * {@link MediaFormat#KEY_PROFILE},<br> 594 * <!-- {link MediaFormat#KEY_MAX_BIT_RATE},<br> --> 595 * {@link MediaFormat#KEY_BIT_RATE}</td> 596 * <td>as above, plus<br> 597 * {@link MediaFormat#KEY_PROFILE},<br> 598 * {@link MediaFormat#KEY_LEVEL}<sup>+</sup>,<br> 599 * <!-- {link MediaFormat#KEY_MAX_BIT_RATE},<br> --> 600 * {@link MediaFormat#KEY_BIT_RATE},<br> 601 * {@link CodecCapabilities#FEATURE_IntraRefresh}<sup>E</sup></td> 602 * </tr> 603 * <tr> 604 * <td colspan=4> 605 * <p class=note><strong>Notes:</strong><br> 606 * *: must be specified; otherwise, method returns {@code false}.<br> 607 * +: method does not verify that the format parameters are supported 608 * by the specified level.<br> 609 * D: decoders only<br> 610 * E: encoders only<br> 611 * ~: if both keys are provided values must match 612 * </td> 613 * </tr> 614 * </tbody> 615 * </table> 616 * 617 * @param format media format with optional feature directives. 618 * @throws IllegalArgumentException if format is not a valid media format. 619 * @return whether the codec capabilities support the given format 620 * and feature requests. 621 */ isFormatSupported(MediaFormat format)622 public final boolean isFormatSupported(MediaFormat format) { 623 final Map<String, Object> map = format.getMap(); 624 final String mime = (String)map.get(MediaFormat.KEY_MIME); 625 626 // mime must match if present 627 if (mime != null && !mMime.equalsIgnoreCase(mime)) { 628 return false; 629 } 630 631 // check feature support 632 for (Feature feat: getValidFeatures()) { 633 Integer yesNo = (Integer)map.get(MediaFormat.KEY_FEATURE_ + feat.mName); 634 if (yesNo == null) { 635 continue; 636 } 637 if ((yesNo == 1 && !isFeatureSupported(feat.mName)) || 638 (yesNo == 0 && isFeatureRequired(feat.mName))) { 639 return false; 640 } 641 } 642 643 Integer profile = (Integer)map.get(MediaFormat.KEY_PROFILE); 644 Integer level = (Integer)map.get(MediaFormat.KEY_LEVEL); 645 646 if (profile != null) { 647 if (!supportsProfileLevel(profile, level)) { 648 return false; 649 } 650 651 // If we recognize this profile, check that this format is supported by the 652 // highest level supported by the codec for that profile. (Ignore specified 653 // level beyond the above profile/level check as level is only used as a 654 // guidance. E.g. AVC Level 1 CIF format is supported if codec supports level 1.1 655 // even though max size for Level 1 is QCIF. However, MPEG2 Simple Profile 656 // 1080p format is not supported even if codec supports Main Profile Level High, 657 // as Simple Profile does not support 1080p. 658 CodecCapabilities levelCaps = null; 659 int maxLevel = 0; 660 for (CodecProfileLevel pl : profileLevels) { 661 if (pl.profile == profile && pl.level > maxLevel) { 662 maxLevel = pl.level; 663 } 664 } 665 levelCaps = createFromProfileLevel(mMime, profile, maxLevel); 666 // remove profile from this format otherwise levelCaps.isFormatSupported will 667 // get into this same conditon and loop forever. 668 Map<String, Object> mapWithoutProfile = new HashMap<>(map); 669 mapWithoutProfile.remove(MediaFormat.KEY_PROFILE); 670 MediaFormat formatWithoutProfile = new MediaFormat(mapWithoutProfile); 671 if (levelCaps != null && !levelCaps.isFormatSupported(formatWithoutProfile)) { 672 return false; 673 } 674 } 675 if (mAudioCaps != null && !mAudioCaps.supportsFormat(format)) { 676 return false; 677 } 678 if (mVideoCaps != null && !mVideoCaps.supportsFormat(format)) { 679 return false; 680 } 681 if (mEncoderCaps != null && !mEncoderCaps.supportsFormat(format)) { 682 return false; 683 } 684 return true; 685 } 686 supportsBitrate( Range<Integer> bitrateRange, MediaFormat format)687 private static boolean supportsBitrate( 688 Range<Integer> bitrateRange, MediaFormat format) { 689 Map<String, Object> map = format.getMap(); 690 691 // consider max bitrate over average bitrate for support 692 Integer maxBitrate = (Integer)map.get(MediaFormat.KEY_MAX_BIT_RATE); 693 Integer bitrate = (Integer)map.get(MediaFormat.KEY_BIT_RATE); 694 if (bitrate == null) { 695 bitrate = maxBitrate; 696 } else if (maxBitrate != null) { 697 bitrate = Math.max(bitrate, maxBitrate); 698 } 699 700 if (bitrate != null && bitrate > 0) { 701 return bitrateRange.contains(bitrate); 702 } 703 704 return true; 705 } 706 supportsProfileLevel(int profile, Integer level)707 private boolean supportsProfileLevel(int profile, Integer level) { 708 for (CodecProfileLevel pl: profileLevels) { 709 if (pl.profile != profile) { 710 continue; 711 } 712 713 // AAC does not use levels 714 if (level == null || mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC)) { 715 return true; 716 } 717 718 // H.263 levels are not completely ordered: 719 // Level45 support only implies Level10 support 720 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) { 721 if (pl.level != level && pl.level == CodecProfileLevel.H263Level45 722 && level > CodecProfileLevel.H263Level10) { 723 continue; 724 } 725 } 726 727 // MPEG4 levels are not completely ordered: 728 // Level1 support only implies Level0 (and not Level0b) support 729 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) { 730 if (pl.level != level && pl.level == CodecProfileLevel.MPEG4Level1 731 && level > CodecProfileLevel.MPEG4Level0) { 732 continue; 733 } 734 } 735 736 // HEVC levels incorporate both tiers and levels. Verify tier support. 737 if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) { 738 boolean supportsHighTier = 739 (pl.level & CodecProfileLevel.HEVCHighTierLevels) != 0; 740 boolean checkingHighTier = (level & CodecProfileLevel.HEVCHighTierLevels) != 0; 741 // high tier levels are only supported by other high tier levels 742 if (checkingHighTier && !supportsHighTier) { 743 continue; 744 } 745 } 746 747 if (pl.level >= level) { 748 // if we recognize the listed profile/level, we must also recognize the 749 // profile/level arguments. 750 if (createFromProfileLevel(mMime, profile, pl.level) != null) { 751 return createFromProfileLevel(mMime, profile, level) != null; 752 } 753 return true; 754 } 755 } 756 return false; 757 } 758 759 // errors while reading profile levels - accessed from sister capabilities 760 int mError; 761 762 private static final String TAG = "CodecCapabilities"; 763 764 // NEW-STYLE CAPABILITIES 765 private AudioCapabilities mAudioCaps; 766 private VideoCapabilities mVideoCaps; 767 private EncoderCapabilities mEncoderCaps; 768 private MediaFormat mDefaultFormat; 769 770 /** 771 * Returns a MediaFormat object with default values for configurations that have 772 * defaults. 773 */ getDefaultFormat()774 public MediaFormat getDefaultFormat() { 775 return mDefaultFormat; 776 } 777 778 /** 779 * Returns the mime type for which this codec-capability object was created. 780 */ getMimeType()781 public String getMimeType() { 782 return mMime; 783 } 784 785 /** 786 * Returns the max number of the supported concurrent codec instances. 787 * <p> 788 * This is a hint for an upper bound. Applications should not expect to successfully 789 * operate more instances than the returned value, but the actual number of 790 * concurrently operable instances may be less as it depends on the available 791 * resources at time of use. 792 */ getMaxSupportedInstances()793 public int getMaxSupportedInstances() { 794 return mMaxSupportedInstances; 795 } 796 isAudio()797 private boolean isAudio() { 798 return mAudioCaps != null; 799 } 800 801 /** 802 * Returns the audio capabilities or {@code null} if this is not an audio codec. 803 */ getAudioCapabilities()804 public AudioCapabilities getAudioCapabilities() { 805 return mAudioCaps; 806 } 807 isEncoder()808 private boolean isEncoder() { 809 return mEncoderCaps != null; 810 } 811 812 /** 813 * Returns the encoding capabilities or {@code null} if this is not an encoder. 814 */ getEncoderCapabilities()815 public EncoderCapabilities getEncoderCapabilities() { 816 return mEncoderCaps; 817 } 818 isVideo()819 private boolean isVideo() { 820 return mVideoCaps != null; 821 } 822 823 /** 824 * Returns the video capabilities or {@code null} if this is not a video codec. 825 */ getVideoCapabilities()826 public VideoCapabilities getVideoCapabilities() { 827 return mVideoCaps; 828 } 829 830 /** @hide */ dup()831 public CodecCapabilities dup() { 832 return new CodecCapabilities( 833 // clone writable arrays 834 Arrays.copyOf(profileLevels, profileLevels.length), 835 Arrays.copyOf(colorFormats, colorFormats.length), 836 isEncoder(), 837 mFlagsVerified, 838 mDefaultFormat, 839 mCapabilitiesInfo); 840 } 841 842 /** 843 * Retrieve the codec capabilities for a certain {@code mime type}, {@code 844 * profile} and {@code level}. If the type, or profile-level combination 845 * is not understood by the framework, it returns null. 846 * <p class=note> In {@link android.os.Build.VERSION_CODES#M}, calling this 847 * method without calling any method of the {@link MediaCodecList} class beforehand 848 * results in a {@link NullPointerException}.</p> 849 */ createFromProfileLevel( String mime, int profile, int level)850 public static CodecCapabilities createFromProfileLevel( 851 String mime, int profile, int level) { 852 CodecProfileLevel pl = new CodecProfileLevel(); 853 pl.profile = profile; 854 pl.level = level; 855 MediaFormat defaultFormat = new MediaFormat(); 856 defaultFormat.setString(MediaFormat.KEY_MIME, mime); 857 858 CodecCapabilities ret = new CodecCapabilities( 859 new CodecProfileLevel[] { pl }, new int[0], true /* encoder */, 860 0 /* flags */, defaultFormat, new MediaFormat() /* info */); 861 if (ret.mError != 0) { 862 return null; 863 } 864 return ret; 865 } 866 CodecCapabilities( CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags, Map<String, Object>defaultFormatMap, Map<String, Object>capabilitiesMap)867 /* package private */ CodecCapabilities( 868 CodecProfileLevel[] profLevs, int[] colFmts, 869 boolean encoder, int flags, 870 Map<String, Object>defaultFormatMap, 871 Map<String, Object>capabilitiesMap) { 872 this(profLevs, colFmts, encoder, flags, 873 new MediaFormat(defaultFormatMap), 874 new MediaFormat(capabilitiesMap)); 875 } 876 877 private MediaFormat mCapabilitiesInfo; 878 CodecCapabilities( CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags, MediaFormat defaultFormat, MediaFormat info)879 /* package private */ CodecCapabilities( 880 CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags, 881 MediaFormat defaultFormat, MediaFormat info) { 882 final Map<String, Object> map = info.getMap(); 883 colorFormats = colFmts; 884 mFlagsVerified = flags; 885 mDefaultFormat = defaultFormat; 886 mCapabilitiesInfo = info; 887 mMime = mDefaultFormat.getString(MediaFormat.KEY_MIME); 888 889 /* VP9 introduced profiles around 2016, so some VP9 codecs may not advertise any 890 supported profiles. Determine the level for them using the info they provide. */ 891 if (profLevs.length == 0 && mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) { 892 CodecProfileLevel profLev = new CodecProfileLevel(); 893 profLev.profile = CodecProfileLevel.VP9Profile0; 894 profLev.level = VideoCapabilities.equivalentVP9Level(info); 895 profLevs = new CodecProfileLevel[] { profLev }; 896 } 897 profileLevels = profLevs; 898 899 if (mMime.toLowerCase().startsWith("audio/")) { 900 mAudioCaps = AudioCapabilities.create(info, this); 901 mAudioCaps.setDefaultFormat(mDefaultFormat); 902 } else if (mMime.toLowerCase().startsWith("video/")) { 903 mVideoCaps = VideoCapabilities.create(info, this); 904 } 905 if (encoder) { 906 mEncoderCaps = EncoderCapabilities.create(info, this); 907 mEncoderCaps.setDefaultFormat(mDefaultFormat); 908 } 909 910 final Map<String, Object> global = MediaCodecList.getGlobalSettings(); 911 mMaxSupportedInstances = Utils.parseIntSafely( 912 global.get("max-concurrent-instances"), DEFAULT_MAX_SUPPORTED_INSTANCES); 913 914 int maxInstances = Utils.parseIntSafely( 915 map.get("max-concurrent-instances"), mMaxSupportedInstances); 916 mMaxSupportedInstances = 917 Range.create(1, MAX_SUPPORTED_INSTANCES_LIMIT).clamp(maxInstances); 918 919 for (Feature feat: getValidFeatures()) { 920 String key = MediaFormat.KEY_FEATURE_ + feat.mName; 921 Integer yesNo = (Integer)map.get(key); 922 if (yesNo == null) { 923 continue; 924 } 925 if (yesNo > 0) { 926 mFlagsRequired |= feat.mValue; 927 } 928 mFlagsSupported |= feat.mValue; 929 mDefaultFormat.setInteger(key, 1); 930 // TODO restrict features by mFlagsVerified once all codecs reliably verify them 931 } 932 } 933 } 934 935 /** 936 * A class that supports querying the audio capabilities of a codec. 937 */ 938 public static final class AudioCapabilities { 939 private static final String TAG = "AudioCapabilities"; 940 private CodecCapabilities mParent; 941 private Range<Integer> mBitrateRange; 942 943 private int[] mSampleRates; 944 private Range<Integer>[] mSampleRateRanges; 945 private int mMaxInputChannelCount; 946 947 private static final int MAX_INPUT_CHANNEL_COUNT = 30; 948 949 /** 950 * Returns the range of supported bitrates in bits/second. 951 */ getBitrateRange()952 public Range<Integer> getBitrateRange() { 953 return mBitrateRange; 954 } 955 956 /** 957 * Returns the array of supported sample rates if the codec 958 * supports only discrete values. Otherwise, it returns 959 * {@code null}. The array is sorted in ascending order. 960 */ getSupportedSampleRates()961 public int[] getSupportedSampleRates() { 962 return Arrays.copyOf(mSampleRates, mSampleRates.length); 963 } 964 965 /** 966 * Returns the array of supported sample rate ranges. The 967 * array is sorted in ascending order, and the ranges are 968 * distinct. 969 */ getSupportedSampleRateRanges()970 public Range<Integer>[] getSupportedSampleRateRanges() { 971 return Arrays.copyOf(mSampleRateRanges, mSampleRateRanges.length); 972 } 973 974 /** 975 * Returns the maximum number of input channels supported. The codec 976 * supports any number of channels between 1 and this maximum value. 977 */ getMaxInputChannelCount()978 public int getMaxInputChannelCount() { 979 return mMaxInputChannelCount; 980 } 981 982 /* no public constructor */ AudioCapabilities()983 private AudioCapabilities() { } 984 985 /** @hide */ create( MediaFormat info, CodecCapabilities parent)986 public static AudioCapabilities create( 987 MediaFormat info, CodecCapabilities parent) { 988 AudioCapabilities caps = new AudioCapabilities(); 989 caps.init(info, parent); 990 return caps; 991 } 992 993 /** @hide */ init(MediaFormat info, CodecCapabilities parent)994 public void init(MediaFormat info, CodecCapabilities parent) { 995 mParent = parent; 996 initWithPlatformLimits(); 997 applyLevelLimits(); 998 parseFromInfo(info); 999 } 1000 initWithPlatformLimits()1001 private void initWithPlatformLimits() { 1002 mBitrateRange = Range.create(0, Integer.MAX_VALUE); 1003 mMaxInputChannelCount = MAX_INPUT_CHANNEL_COUNT; 1004 // mBitrateRange = Range.create(1, 320000); 1005 mSampleRateRanges = new Range[] { Range.create(8000, 96000) }; 1006 mSampleRates = null; 1007 } 1008 supports(Integer sampleRate, Integer inputChannels)1009 private boolean supports(Integer sampleRate, Integer inputChannels) { 1010 // channels and sample rates are checked orthogonally 1011 if (inputChannels != null && 1012 (inputChannels < 1 || inputChannels > mMaxInputChannelCount)) { 1013 return false; 1014 } 1015 if (sampleRate != null) { 1016 int ix = Utils.binarySearchDistinctRanges( 1017 mSampleRateRanges, sampleRate); 1018 if (ix < 0) { 1019 return false; 1020 } 1021 } 1022 return true; 1023 } 1024 1025 /** 1026 * Query whether the sample rate is supported by the codec. 1027 */ isSampleRateSupported(int sampleRate)1028 public boolean isSampleRateSupported(int sampleRate) { 1029 return supports(sampleRate, null); 1030 } 1031 1032 /** modifies rates */ limitSampleRates(int[] rates)1033 private void limitSampleRates(int[] rates) { 1034 Arrays.sort(rates); 1035 ArrayList<Range<Integer>> ranges = new ArrayList<Range<Integer>>(); 1036 for (int rate: rates) { 1037 if (supports(rate, null /* channels */)) { 1038 ranges.add(Range.create(rate, rate)); 1039 } 1040 } 1041 mSampleRateRanges = ranges.toArray(new Range[ranges.size()]); 1042 createDiscreteSampleRates(); 1043 } 1044 createDiscreteSampleRates()1045 private void createDiscreteSampleRates() { 1046 mSampleRates = new int[mSampleRateRanges.length]; 1047 for (int i = 0; i < mSampleRateRanges.length; i++) { 1048 mSampleRates[i] = mSampleRateRanges[i].getLower(); 1049 } 1050 } 1051 1052 /** modifies rateRanges */ limitSampleRates(Range<Integer>[] rateRanges)1053 private void limitSampleRates(Range<Integer>[] rateRanges) { 1054 sortDistinctRanges(rateRanges); 1055 mSampleRateRanges = intersectSortedDistinctRanges(mSampleRateRanges, rateRanges); 1056 1057 // check if all values are discrete 1058 for (Range<Integer> range: mSampleRateRanges) { 1059 if (!range.getLower().equals(range.getUpper())) { 1060 mSampleRates = null; 1061 return; 1062 } 1063 } 1064 createDiscreteSampleRates(); 1065 } 1066 applyLevelLimits()1067 private void applyLevelLimits() { 1068 int[] sampleRates = null; 1069 Range<Integer> sampleRateRange = null, bitRates = null; 1070 int maxChannels = MAX_INPUT_CHANNEL_COUNT; 1071 String mime = mParent.getMimeType(); 1072 1073 if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MPEG)) { 1074 sampleRates = new int[] { 1075 8000, 11025, 12000, 1076 16000, 22050, 24000, 1077 32000, 44100, 48000 }; 1078 bitRates = Range.create(8000, 320000); 1079 maxChannels = 2; 1080 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)) { 1081 sampleRates = new int[] { 8000 }; 1082 bitRates = Range.create(4750, 12200); 1083 maxChannels = 1; 1084 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)) { 1085 sampleRates = new int[] { 16000 }; 1086 bitRates = Range.create(6600, 23850); 1087 maxChannels = 1; 1088 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC)) { 1089 sampleRates = new int[] { 1090 7350, 8000, 1091 11025, 12000, 16000, 1092 22050, 24000, 32000, 1093 44100, 48000, 64000, 1094 88200, 96000 }; 1095 bitRates = Range.create(8000, 510000); 1096 maxChannels = 48; 1097 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_VORBIS)) { 1098 bitRates = Range.create(32000, 500000); 1099 sampleRateRange = Range.create(8000, 192000); 1100 maxChannels = 255; 1101 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_OPUS)) { 1102 bitRates = Range.create(6000, 510000); 1103 sampleRates = new int[] { 8000, 12000, 16000, 24000, 48000 }; 1104 maxChannels = 255; 1105 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW)) { 1106 sampleRateRange = Range.create(1, 96000); 1107 bitRates = Range.create(1, 10000000); 1108 maxChannels = AudioTrack.CHANNEL_COUNT_MAX; 1109 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) { 1110 sampleRateRange = Range.create(1, 655350); 1111 // lossless codec, so bitrate is ignored 1112 maxChannels = 255; 1113 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW) 1114 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)) { 1115 sampleRates = new int[] { 8000 }; 1116 bitRates = Range.create(64000, 64000); 1117 // platform allows multiple channels for this format 1118 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) { 1119 sampleRates = new int[] { 8000 }; 1120 bitRates = Range.create(13000, 13000); 1121 maxChannels = 1; 1122 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AC3)) { 1123 maxChannels = 6; 1124 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_EAC3)) { 1125 maxChannels = 16; 1126 } else { 1127 Log.w(TAG, "Unsupported mime " + mime); 1128 mParent.mError |= ERROR_UNSUPPORTED; 1129 } 1130 1131 // restrict ranges 1132 if (sampleRates != null) { 1133 limitSampleRates(sampleRates); 1134 } else if (sampleRateRange != null) { 1135 limitSampleRates(new Range[] { sampleRateRange }); 1136 } 1137 applyLimits(maxChannels, bitRates); 1138 } 1139 applyLimits(int maxInputChannels, Range<Integer> bitRates)1140 private void applyLimits(int maxInputChannels, Range<Integer> bitRates) { 1141 mMaxInputChannelCount = Range.create(1, mMaxInputChannelCount) 1142 .clamp(maxInputChannels); 1143 if (bitRates != null) { 1144 mBitrateRange = mBitrateRange.intersect(bitRates); 1145 } 1146 } 1147 parseFromInfo(MediaFormat info)1148 private void parseFromInfo(MediaFormat info) { 1149 int maxInputChannels = MAX_INPUT_CHANNEL_COUNT; 1150 Range<Integer> bitRates = POSITIVE_INTEGERS; 1151 1152 if (info.containsKey("sample-rate-ranges")) { 1153 String[] rateStrings = info.getString("sample-rate-ranges").split(","); 1154 Range<Integer>[] rateRanges = new Range[rateStrings.length]; 1155 for (int i = 0; i < rateStrings.length; i++) { 1156 rateRanges[i] = Utils.parseIntRange(rateStrings[i], null); 1157 } 1158 limitSampleRates(rateRanges); 1159 } 1160 if (info.containsKey("max-channel-count")) { 1161 maxInputChannels = Utils.parseIntSafely( 1162 info.getString("max-channel-count"), maxInputChannels); 1163 } else if ((mParent.mError & ERROR_UNSUPPORTED) != 0) { 1164 maxInputChannels = 0; 1165 } 1166 if (info.containsKey("bitrate-range")) { 1167 bitRates = bitRates.intersect( 1168 Utils.parseIntRange(info.getString("bitrate-range"), bitRates)); 1169 } 1170 applyLimits(maxInputChannels, bitRates); 1171 } 1172 1173 /** @hide */ setDefaultFormat(MediaFormat format)1174 public void setDefaultFormat(MediaFormat format) { 1175 // report settings that have only a single choice 1176 if (mBitrateRange.getLower().equals(mBitrateRange.getUpper())) { 1177 format.setInteger(MediaFormat.KEY_BIT_RATE, mBitrateRange.getLower()); 1178 } 1179 if (mMaxInputChannelCount == 1) { 1180 // mono-only format 1181 format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); 1182 } 1183 if (mSampleRates != null && mSampleRates.length == 1) { 1184 format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRates[0]); 1185 } 1186 } 1187 1188 /** @hide */ supportsFormat(MediaFormat format)1189 public boolean supportsFormat(MediaFormat format) { 1190 Map<String, Object> map = format.getMap(); 1191 Integer sampleRate = (Integer)map.get(MediaFormat.KEY_SAMPLE_RATE); 1192 Integer channels = (Integer)map.get(MediaFormat.KEY_CHANNEL_COUNT); 1193 1194 if (!supports(sampleRate, channels)) { 1195 return false; 1196 } 1197 1198 if (!CodecCapabilities.supportsBitrate(mBitrateRange, format)) { 1199 return false; 1200 } 1201 1202 // nothing to do for: 1203 // KEY_CHANNEL_MASK: codecs don't get this 1204 // KEY_IS_ADTS: required feature for all AAC decoders 1205 return true; 1206 } 1207 } 1208 1209 /** 1210 * A class that supports querying the video capabilities of a codec. 1211 */ 1212 public static final class VideoCapabilities { 1213 private static final String TAG = "VideoCapabilities"; 1214 private CodecCapabilities mParent; 1215 private Range<Integer> mBitrateRange; 1216 1217 private Range<Integer> mHeightRange; 1218 private Range<Integer> mWidthRange; 1219 private Range<Integer> mBlockCountRange; 1220 private Range<Integer> mHorizontalBlockRange; 1221 private Range<Integer> mVerticalBlockRange; 1222 private Range<Rational> mAspectRatioRange; 1223 private Range<Rational> mBlockAspectRatioRange; 1224 private Range<Long> mBlocksPerSecondRange; 1225 private Map<Size, Range<Long>> mMeasuredFrameRates; 1226 private Range<Integer> mFrameRateRange; 1227 1228 private int mBlockWidth; 1229 private int mBlockHeight; 1230 private int mWidthAlignment; 1231 private int mHeightAlignment; 1232 private int mSmallerDimensionUpperLimit; 1233 1234 private boolean mAllowMbOverride; // allow XML to override calculated limits 1235 1236 /** 1237 * Returns the range of supported bitrates in bits/second. 1238 */ getBitrateRange()1239 public Range<Integer> getBitrateRange() { 1240 return mBitrateRange; 1241 } 1242 1243 /** 1244 * Returns the range of supported video widths. 1245 */ getSupportedWidths()1246 public Range<Integer> getSupportedWidths() { 1247 return mWidthRange; 1248 } 1249 1250 /** 1251 * Returns the range of supported video heights. 1252 */ getSupportedHeights()1253 public Range<Integer> getSupportedHeights() { 1254 return mHeightRange; 1255 } 1256 1257 /** 1258 * Returns the alignment requirement for video width (in pixels). 1259 * 1260 * This is a power-of-2 value that video width must be a 1261 * multiple of. 1262 */ getWidthAlignment()1263 public int getWidthAlignment() { 1264 return mWidthAlignment; 1265 } 1266 1267 /** 1268 * Returns the alignment requirement for video height (in pixels). 1269 * 1270 * This is a power-of-2 value that video height must be a 1271 * multiple of. 1272 */ getHeightAlignment()1273 public int getHeightAlignment() { 1274 return mHeightAlignment; 1275 } 1276 1277 /** 1278 * Return the upper limit on the smaller dimension of width or height. 1279 * <p></p> 1280 * Some codecs have a limit on the smaller dimension, whether it be 1281 * the width or the height. E.g. a codec may only be able to handle 1282 * up to 1920x1080 both in landscape and portrait mode (1080x1920). 1283 * In this case the maximum width and height are both 1920, but the 1284 * smaller dimension limit will be 1080. For other codecs, this is 1285 * {@code Math.min(getSupportedWidths().getUpper(), 1286 * getSupportedHeights().getUpper())}. 1287 * 1288 * @hide 1289 */ getSmallerDimensionUpperLimit()1290 public int getSmallerDimensionUpperLimit() { 1291 return mSmallerDimensionUpperLimit; 1292 } 1293 1294 /** 1295 * Returns the range of supported frame rates. 1296 * <p> 1297 * This is not a performance indicator. Rather, it expresses the 1298 * limits specified in the coding standard, based on the complexities 1299 * of encoding material for later playback at a certain frame rate, 1300 * or the decoding of such material in non-realtime. 1301 */ getSupportedFrameRates()1302 public Range<Integer> getSupportedFrameRates() { 1303 return mFrameRateRange; 1304 } 1305 1306 /** 1307 * Returns the range of supported video widths for a video height. 1308 * @param height the height of the video 1309 */ getSupportedWidthsFor(int height)1310 public Range<Integer> getSupportedWidthsFor(int height) { 1311 try { 1312 Range<Integer> range = mWidthRange; 1313 if (!mHeightRange.contains(height) 1314 || (height % mHeightAlignment) != 0) { 1315 throw new IllegalArgumentException("unsupported height"); 1316 } 1317 final int heightInBlocks = Utils.divUp(height, mBlockHeight); 1318 1319 // constrain by block count and by block aspect ratio 1320 final int minWidthInBlocks = Math.max( 1321 Utils.divUp(mBlockCountRange.getLower(), heightInBlocks), 1322 (int)Math.ceil(mBlockAspectRatioRange.getLower().doubleValue() 1323 * heightInBlocks)); 1324 final int maxWidthInBlocks = Math.min( 1325 mBlockCountRange.getUpper() / heightInBlocks, 1326 (int)(mBlockAspectRatioRange.getUpper().doubleValue() 1327 * heightInBlocks)); 1328 range = range.intersect( 1329 (minWidthInBlocks - 1) * mBlockWidth + mWidthAlignment, 1330 maxWidthInBlocks * mBlockWidth); 1331 1332 // constrain by smaller dimension limit 1333 if (height > mSmallerDimensionUpperLimit) { 1334 range = range.intersect(1, mSmallerDimensionUpperLimit); 1335 } 1336 1337 // constrain by aspect ratio 1338 range = range.intersect( 1339 (int)Math.ceil(mAspectRatioRange.getLower().doubleValue() 1340 * height), 1341 (int)(mAspectRatioRange.getUpper().doubleValue() * height)); 1342 return range; 1343 } catch (IllegalArgumentException e) { 1344 // height is not supported because there are no suitable widths 1345 Log.v(TAG, "could not get supported widths for " + height); 1346 throw new IllegalArgumentException("unsupported height"); 1347 } 1348 } 1349 1350 /** 1351 * Returns the range of supported video heights for a video width 1352 * @param width the width of the video 1353 */ getSupportedHeightsFor(int width)1354 public Range<Integer> getSupportedHeightsFor(int width) { 1355 try { 1356 Range<Integer> range = mHeightRange; 1357 if (!mWidthRange.contains(width) 1358 || (width % mWidthAlignment) != 0) { 1359 throw new IllegalArgumentException("unsupported width"); 1360 } 1361 final int widthInBlocks = Utils.divUp(width, mBlockWidth); 1362 1363 // constrain by block count and by block aspect ratio 1364 final int minHeightInBlocks = Math.max( 1365 Utils.divUp(mBlockCountRange.getLower(), widthInBlocks), 1366 (int)Math.ceil(widthInBlocks / 1367 mBlockAspectRatioRange.getUpper().doubleValue())); 1368 final int maxHeightInBlocks = Math.min( 1369 mBlockCountRange.getUpper() / widthInBlocks, 1370 (int)(widthInBlocks / 1371 mBlockAspectRatioRange.getLower().doubleValue())); 1372 range = range.intersect( 1373 (minHeightInBlocks - 1) * mBlockHeight + mHeightAlignment, 1374 maxHeightInBlocks * mBlockHeight); 1375 1376 // constrain by smaller dimension limit 1377 if (width > mSmallerDimensionUpperLimit) { 1378 range = range.intersect(1, mSmallerDimensionUpperLimit); 1379 } 1380 1381 // constrain by aspect ratio 1382 range = range.intersect( 1383 (int)Math.ceil(width / 1384 mAspectRatioRange.getUpper().doubleValue()), 1385 (int)(width / mAspectRatioRange.getLower().doubleValue())); 1386 return range; 1387 } catch (IllegalArgumentException e) { 1388 // width is not supported because there are no suitable heights 1389 Log.v(TAG, "could not get supported heights for " + width); 1390 throw new IllegalArgumentException("unsupported width"); 1391 } 1392 } 1393 1394 /** 1395 * Returns the range of supported video frame rates for a video size. 1396 * <p> 1397 * This is not a performance indicator. Rather, it expresses the limits specified in 1398 * the coding standard, based on the complexities of encoding material of a given 1399 * size for later playback at a certain frame rate, or the decoding of such material 1400 * in non-realtime. 1401 1402 * @param width the width of the video 1403 * @param height the height of the video 1404 */ getSupportedFrameRatesFor(int width, int height)1405 public Range<Double> getSupportedFrameRatesFor(int width, int height) { 1406 Range<Integer> range = mHeightRange; 1407 if (!supports(width, height, null)) { 1408 throw new IllegalArgumentException("unsupported size"); 1409 } 1410 final int blockCount = 1411 Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight); 1412 1413 return Range.create( 1414 Math.max(mBlocksPerSecondRange.getLower() / (double) blockCount, 1415 (double) mFrameRateRange.getLower()), 1416 Math.min(mBlocksPerSecondRange.getUpper() / (double) blockCount, 1417 (double) mFrameRateRange.getUpper())); 1418 } 1419 getBlockCount(int width, int height)1420 private int getBlockCount(int width, int height) { 1421 return Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight); 1422 } 1423 1424 @NonNull findClosestSize(int width, int height)1425 private Size findClosestSize(int width, int height) { 1426 int targetBlockCount = getBlockCount(width, height); 1427 Size closestSize = null; 1428 int minDiff = Integer.MAX_VALUE; 1429 for (Size size : mMeasuredFrameRates.keySet()) { 1430 int diff = Math.abs(targetBlockCount - 1431 getBlockCount(size.getWidth(), size.getHeight())); 1432 if (diff < minDiff) { 1433 minDiff = diff; 1434 closestSize = size; 1435 } 1436 } 1437 return closestSize; 1438 } 1439 estimateFrameRatesFor(int width, int height)1440 private Range<Double> estimateFrameRatesFor(int width, int height) { 1441 Size size = findClosestSize(width, height); 1442 Range<Long> range = mMeasuredFrameRates.get(size); 1443 Double ratio = getBlockCount(size.getWidth(), size.getHeight()) 1444 / (double)Math.max(getBlockCount(width, height), 1); 1445 return Range.create(range.getLower() * ratio, range.getUpper() * ratio); 1446 } 1447 1448 /** 1449 * Returns the range of achievable video frame rates for a video size. 1450 * May return {@code null}, if the codec did not publish any measurement 1451 * data. 1452 * <p> 1453 * This is a performance estimate provided by the device manufacturer based on statistical 1454 * sampling of full-speed decoding and encoding measurements in various configurations 1455 * of common video sizes supported by the codec. As such it should only be used to 1456 * compare individual codecs on the device. The value is not suitable for comparing 1457 * different devices or even different android releases for the same device. 1458 * <p> 1459 * <em>On {@link android.os.Build.VERSION_CODES#M} release</em> the returned range 1460 * corresponds to the fastest frame rates achieved in the tested configurations. As 1461 * such, it should not be used to gauge guaranteed or even average codec performance 1462 * on the device. 1463 * <p> 1464 * <em>On {@link android.os.Build.VERSION_CODES#N} release</em> the returned range 1465 * corresponds closer to sustained performance <em>in tested configurations</em>. 1466 * One can expect to achieve sustained performance higher than the lower limit more than 1467 * 50% of the time, and higher than half of the lower limit at least 90% of the time 1468 * <em>in tested configurations</em>. 1469 * Conversely, one can expect performance lower than twice the upper limit at least 1470 * 90% of the time. 1471 * <p class=note> 1472 * Tested configurations use a single active codec. For use cases where multiple 1473 * codecs are active, applications can expect lower and in most cases significantly lower 1474 * performance. 1475 * <p class=note> 1476 * The returned range value is interpolated from the nearest frame size(s) tested. 1477 * Codec performance is severely impacted by other activity on the device as well 1478 * as environmental factors (such as battery level, temperature or power source), and can 1479 * vary significantly even in a steady environment. 1480 * <p class=note> 1481 * Use this method in cases where only codec performance matters, e.g. to evaluate if 1482 * a codec has any chance of meeting a performance target. Codecs are listed 1483 * in {@link MediaCodecList} in the preferred order as defined by the device 1484 * manufacturer. As such, applications should use the first suitable codec in the 1485 * list to achieve the best balance between power use and performance. 1486 * 1487 * @param width the width of the video 1488 * @param height the height of the video 1489 * 1490 * @throws IllegalArgumentException if the video size is not supported. 1491 */ 1492 @Nullable getAchievableFrameRatesFor(int width, int height)1493 public Range<Double> getAchievableFrameRatesFor(int width, int height) { 1494 if (!supports(width, height, null)) { 1495 throw new IllegalArgumentException("unsupported size"); 1496 } 1497 1498 if (mMeasuredFrameRates == null || mMeasuredFrameRates.size() <= 0) { 1499 Log.w(TAG, "Codec did not publish any measurement data."); 1500 return null; 1501 } 1502 1503 return estimateFrameRatesFor(width, height); 1504 } 1505 1506 /** 1507 * Returns whether a given video size ({@code width} and 1508 * {@code height}) and {@code frameRate} combination is supported. 1509 */ areSizeAndRateSupported( int width, int height, double frameRate)1510 public boolean areSizeAndRateSupported( 1511 int width, int height, double frameRate) { 1512 return supports(width, height, frameRate); 1513 } 1514 1515 /** 1516 * Returns whether a given video size ({@code width} and 1517 * {@code height}) is supported. 1518 */ isSizeSupported(int width, int height)1519 public boolean isSizeSupported(int width, int height) { 1520 return supports(width, height, null); 1521 } 1522 supports(Integer width, Integer height, Number rate)1523 private boolean supports(Integer width, Integer height, Number rate) { 1524 boolean ok = true; 1525 1526 if (ok && width != null) { 1527 ok = mWidthRange.contains(width) 1528 && (width % mWidthAlignment == 0); 1529 } 1530 if (ok && height != null) { 1531 ok = mHeightRange.contains(height) 1532 && (height % mHeightAlignment == 0); 1533 } 1534 if (ok && rate != null) { 1535 ok = mFrameRateRange.contains(Utils.intRangeFor(rate.doubleValue())); 1536 } 1537 if (ok && height != null && width != null) { 1538 ok = Math.min(height, width) <= mSmallerDimensionUpperLimit; 1539 1540 final int widthInBlocks = Utils.divUp(width, mBlockWidth); 1541 final int heightInBlocks = Utils.divUp(height, mBlockHeight); 1542 final int blockCount = widthInBlocks * heightInBlocks; 1543 ok = ok && mBlockCountRange.contains(blockCount) 1544 && mBlockAspectRatioRange.contains( 1545 new Rational(widthInBlocks, heightInBlocks)) 1546 && mAspectRatioRange.contains(new Rational(width, height)); 1547 if (ok && rate != null) { 1548 double blocksPerSec = blockCount * rate.doubleValue(); 1549 ok = mBlocksPerSecondRange.contains( 1550 Utils.longRangeFor(blocksPerSec)); 1551 } 1552 } 1553 return ok; 1554 } 1555 1556 /** 1557 * @hide 1558 * @throws java.lang.ClassCastException */ supportsFormat(MediaFormat format)1559 public boolean supportsFormat(MediaFormat format) { 1560 final Map<String, Object> map = format.getMap(); 1561 Integer width = (Integer)map.get(MediaFormat.KEY_WIDTH); 1562 Integer height = (Integer)map.get(MediaFormat.KEY_HEIGHT); 1563 Number rate = (Number)map.get(MediaFormat.KEY_FRAME_RATE); 1564 1565 if (!supports(width, height, rate)) { 1566 return false; 1567 } 1568 1569 if (!CodecCapabilities.supportsBitrate(mBitrateRange, format)) { 1570 return false; 1571 } 1572 1573 // we ignore color-format for now as it is not reliably reported by codec 1574 return true; 1575 } 1576 1577 /* no public constructor */ VideoCapabilities()1578 private VideoCapabilities() { } 1579 1580 /** @hide */ create( MediaFormat info, CodecCapabilities parent)1581 public static VideoCapabilities create( 1582 MediaFormat info, CodecCapabilities parent) { 1583 VideoCapabilities caps = new VideoCapabilities(); 1584 caps.init(info, parent); 1585 return caps; 1586 } 1587 1588 /** @hide */ init(MediaFormat info, CodecCapabilities parent)1589 public void init(MediaFormat info, CodecCapabilities parent) { 1590 mParent = parent; 1591 initWithPlatformLimits(); 1592 applyLevelLimits(); 1593 parseFromInfo(info); 1594 updateLimits(); 1595 } 1596 1597 /** @hide */ getBlockSize()1598 public Size getBlockSize() { 1599 return new Size(mBlockWidth, mBlockHeight); 1600 } 1601 1602 /** @hide */ getBlockCountRange()1603 public Range<Integer> getBlockCountRange() { 1604 return mBlockCountRange; 1605 } 1606 1607 /** @hide */ getBlocksPerSecondRange()1608 public Range<Long> getBlocksPerSecondRange() { 1609 return mBlocksPerSecondRange; 1610 } 1611 1612 /** @hide */ getAspectRatioRange(boolean blocks)1613 public Range<Rational> getAspectRatioRange(boolean blocks) { 1614 return blocks ? mBlockAspectRatioRange : mAspectRatioRange; 1615 } 1616 initWithPlatformLimits()1617 private void initWithPlatformLimits() { 1618 mBitrateRange = BITRATE_RANGE; 1619 1620 mWidthRange = SIZE_RANGE; 1621 mHeightRange = SIZE_RANGE; 1622 mFrameRateRange = FRAME_RATE_RANGE; 1623 1624 mHorizontalBlockRange = SIZE_RANGE; 1625 mVerticalBlockRange = SIZE_RANGE; 1626 1627 // full positive ranges are supported as these get calculated 1628 mBlockCountRange = POSITIVE_INTEGERS; 1629 mBlocksPerSecondRange = POSITIVE_LONGS; 1630 1631 mBlockAspectRatioRange = POSITIVE_RATIONALS; 1632 mAspectRatioRange = POSITIVE_RATIONALS; 1633 1634 // YUV 4:2:0 requires 2:2 alignment 1635 mWidthAlignment = 2; 1636 mHeightAlignment = 2; 1637 mBlockWidth = 2; 1638 mBlockHeight = 2; 1639 mSmallerDimensionUpperLimit = SIZE_RANGE.getUpper(); 1640 } 1641 getMeasuredFrameRates(Map<String, Object> map)1642 private Map<Size, Range<Long>> getMeasuredFrameRates(Map<String, Object> map) { 1643 Map<Size, Range<Long>> ret = new HashMap<Size, Range<Long>>(); 1644 final String prefix = "measured-frame-rate-"; 1645 Set<String> keys = map.keySet(); 1646 for (String key : keys) { 1647 // looking for: measured-frame-rate-WIDTHxHEIGHT-range 1648 if (!key.startsWith(prefix)) { 1649 continue; 1650 } 1651 String subKey = key.substring(prefix.length()); 1652 String[] temp = key.split("-"); 1653 if (temp.length != 5) { 1654 continue; 1655 } 1656 String sizeStr = temp[3]; 1657 Size size = Utils.parseSize(sizeStr, null); 1658 if (size == null || size.getWidth() * size.getHeight() <= 0) { 1659 continue; 1660 } 1661 Range<Long> range = Utils.parseLongRange(map.get(key), null); 1662 if (range == null || range.getLower() < 0 || range.getUpper() < 0) { 1663 continue; 1664 } 1665 ret.put(size, range); 1666 } 1667 return ret; 1668 } 1669 parseWidthHeightRanges(Object o)1670 private static Pair<Range<Integer>, Range<Integer>> parseWidthHeightRanges(Object o) { 1671 Pair<Size, Size> range = Utils.parseSizeRange(o); 1672 if (range != null) { 1673 try { 1674 return Pair.create( 1675 Range.create(range.first.getWidth(), range.second.getWidth()), 1676 Range.create(range.first.getHeight(), range.second.getHeight())); 1677 } catch (IllegalArgumentException e) { 1678 Log.w(TAG, "could not parse size range '" + o + "'"); 1679 } 1680 } 1681 return null; 1682 } 1683 1684 /** @hide */ equivalentVP9Level(MediaFormat info)1685 public static int equivalentVP9Level(MediaFormat info) { 1686 final Map<String, Object> map = info.getMap(); 1687 1688 Size blockSize = Utils.parseSize(map.get("block-size"), new Size(8, 8)); 1689 int BS = blockSize.getWidth() * blockSize.getHeight(); 1690 1691 Range<Integer> counts = Utils.parseIntRange(map.get("block-count-range"), null); 1692 int FS = counts == null ? 0 : BS * counts.getUpper(); 1693 1694 Range<Long> blockRates = 1695 Utils.parseLongRange(map.get("blocks-per-second-range"), null); 1696 long SR = blockRates == null ? 0 : BS * blockRates.getUpper(); 1697 1698 Pair<Range<Integer>, Range<Integer>> dimensionRanges = 1699 parseWidthHeightRanges(map.get("size-range")); 1700 int D = dimensionRanges == null ? 0 : Math.max( 1701 dimensionRanges.first.getUpper(), dimensionRanges.second.getUpper()); 1702 1703 Range<Integer> bitRates = Utils.parseIntRange(map.get("bitrate-range"), null); 1704 int BR = bitRates == null ? 0 : Utils.divUp(bitRates.getUpper(), 1000); 1705 1706 if (SR <= 829440 && FS <= 36864 && BR <= 200 && D <= 512) 1707 return CodecProfileLevel.VP9Level1; 1708 if (SR <= 2764800 && FS <= 73728 && BR <= 800 && D <= 768) 1709 return CodecProfileLevel.VP9Level11; 1710 if (SR <= 4608000 && FS <= 122880 && BR <= 1800 && D <= 960) 1711 return CodecProfileLevel.VP9Level2; 1712 if (SR <= 9216000 && FS <= 245760 && BR <= 3600 && D <= 1344) 1713 return CodecProfileLevel.VP9Level21; 1714 if (SR <= 20736000 && FS <= 552960 && BR <= 7200 && D <= 2048) 1715 return CodecProfileLevel.VP9Level3; 1716 if (SR <= 36864000 && FS <= 983040 && BR <= 12000 && D <= 2752) 1717 return CodecProfileLevel.VP9Level31; 1718 if (SR <= 83558400 && FS <= 2228224 && BR <= 18000 && D <= 4160) 1719 return CodecProfileLevel.VP9Level4; 1720 if (SR <= 160432128 && FS <= 2228224 && BR <= 30000 && D <= 4160) 1721 return CodecProfileLevel.VP9Level41; 1722 if (SR <= 311951360 && FS <= 8912896 && BR <= 60000 && D <= 8384) 1723 return CodecProfileLevel.VP9Level5; 1724 if (SR <= 588251136 && FS <= 8912896 && BR <= 120000 && D <= 8384) 1725 return CodecProfileLevel.VP9Level51; 1726 if (SR <= 1176502272 && FS <= 8912896 && BR <= 180000 && D <= 8384) 1727 return CodecProfileLevel.VP9Level52; 1728 if (SR <= 1176502272 && FS <= 35651584 && BR <= 180000 && D <= 16832) 1729 return CodecProfileLevel.VP9Level6; 1730 if (SR <= 2353004544L && FS <= 35651584 && BR <= 240000 && D <= 16832) 1731 return CodecProfileLevel.VP9Level61; 1732 if (SR <= 4706009088L && FS <= 35651584 && BR <= 480000 && D <= 16832) 1733 return CodecProfileLevel.VP9Level62; 1734 // returning largest level 1735 return CodecProfileLevel.VP9Level62; 1736 } 1737 parseFromInfo(MediaFormat info)1738 private void parseFromInfo(MediaFormat info) { 1739 final Map<String, Object> map = info.getMap(); 1740 Size blockSize = new Size(mBlockWidth, mBlockHeight); 1741 Size alignment = new Size(mWidthAlignment, mHeightAlignment); 1742 Range<Integer> counts = null, widths = null, heights = null; 1743 Range<Integer> frameRates = null, bitRates = null; 1744 Range<Long> blockRates = null; 1745 Range<Rational> ratios = null, blockRatios = null; 1746 1747 blockSize = Utils.parseSize(map.get("block-size"), blockSize); 1748 alignment = Utils.parseSize(map.get("alignment"), alignment); 1749 counts = Utils.parseIntRange(map.get("block-count-range"), null); 1750 blockRates = 1751 Utils.parseLongRange(map.get("blocks-per-second-range"), null); 1752 mMeasuredFrameRates = getMeasuredFrameRates(map); 1753 Pair<Range<Integer>, Range<Integer>> sizeRanges = 1754 parseWidthHeightRanges(map.get("size-range")); 1755 if (sizeRanges != null) { 1756 widths = sizeRanges.first; 1757 heights = sizeRanges.second; 1758 } 1759 // for now this just means using the smaller max size as 2nd 1760 // upper limit. 1761 // for now we are keeping the profile specific "width/height 1762 // in macroblocks" limits. 1763 if (map.containsKey("feature-can-swap-width-height")) { 1764 if (widths != null) { 1765 mSmallerDimensionUpperLimit = 1766 Math.min(widths.getUpper(), heights.getUpper()); 1767 widths = heights = widths.extend(heights); 1768 } else { 1769 Log.w(TAG, "feature can-swap-width-height is best used with size-range"); 1770 mSmallerDimensionUpperLimit = 1771 Math.min(mWidthRange.getUpper(), mHeightRange.getUpper()); 1772 mWidthRange = mHeightRange = mWidthRange.extend(mHeightRange); 1773 } 1774 } 1775 1776 ratios = Utils.parseRationalRange( 1777 map.get("block-aspect-ratio-range"), null); 1778 blockRatios = Utils.parseRationalRange( 1779 map.get("pixel-aspect-ratio-range"), null); 1780 frameRates = Utils.parseIntRange(map.get("frame-rate-range"), null); 1781 if (frameRates != null) { 1782 try { 1783 frameRates = frameRates.intersect(FRAME_RATE_RANGE); 1784 } catch (IllegalArgumentException e) { 1785 Log.w(TAG, "frame rate range (" + frameRates 1786 + ") is out of limits: " + FRAME_RATE_RANGE); 1787 frameRates = null; 1788 } 1789 } 1790 bitRates = Utils.parseIntRange(map.get("bitrate-range"), null); 1791 if (bitRates != null) { 1792 try { 1793 bitRates = bitRates.intersect(BITRATE_RANGE); 1794 } catch (IllegalArgumentException e) { 1795 Log.w(TAG, "bitrate range (" + bitRates 1796 + ") is out of limits: " + BITRATE_RANGE); 1797 bitRates = null; 1798 } 1799 } 1800 1801 checkPowerOfTwo( 1802 blockSize.getWidth(), "block-size width must be power of two"); 1803 checkPowerOfTwo( 1804 blockSize.getHeight(), "block-size height must be power of two"); 1805 1806 checkPowerOfTwo( 1807 alignment.getWidth(), "alignment width must be power of two"); 1808 checkPowerOfTwo( 1809 alignment.getHeight(), "alignment height must be power of two"); 1810 1811 // update block-size and alignment 1812 applyMacroBlockLimits( 1813 Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, 1814 Long.MAX_VALUE, blockSize.getWidth(), blockSize.getHeight(), 1815 alignment.getWidth(), alignment.getHeight()); 1816 1817 if ((mParent.mError & ERROR_UNSUPPORTED) != 0 || mAllowMbOverride) { 1818 // codec supports profiles that we don't know. 1819 // Use supplied values clipped to platform limits 1820 if (widths != null) { 1821 mWidthRange = SIZE_RANGE.intersect(widths); 1822 } 1823 if (heights != null) { 1824 mHeightRange = SIZE_RANGE.intersect(heights); 1825 } 1826 if (counts != null) { 1827 mBlockCountRange = POSITIVE_INTEGERS.intersect( 1828 Utils.factorRange(counts, mBlockWidth * mBlockHeight 1829 / blockSize.getWidth() / blockSize.getHeight())); 1830 } 1831 if (blockRates != null) { 1832 mBlocksPerSecondRange = POSITIVE_LONGS.intersect( 1833 Utils.factorRange(blockRates, mBlockWidth * mBlockHeight 1834 / blockSize.getWidth() / blockSize.getHeight())); 1835 } 1836 if (blockRatios != null) { 1837 mBlockAspectRatioRange = POSITIVE_RATIONALS.intersect( 1838 Utils.scaleRange(blockRatios, 1839 mBlockHeight / blockSize.getHeight(), 1840 mBlockWidth / blockSize.getWidth())); 1841 } 1842 if (ratios != null) { 1843 mAspectRatioRange = POSITIVE_RATIONALS.intersect(ratios); 1844 } 1845 if (frameRates != null) { 1846 mFrameRateRange = FRAME_RATE_RANGE.intersect(frameRates); 1847 } 1848 if (bitRates != null) { 1849 // only allow bitrate override if unsupported profiles were encountered 1850 if ((mParent.mError & ERROR_UNSUPPORTED) != 0) { 1851 mBitrateRange = BITRATE_RANGE.intersect(bitRates); 1852 } else { 1853 mBitrateRange = mBitrateRange.intersect(bitRates); 1854 } 1855 } 1856 } else { 1857 // no unsupported profile/levels, so restrict values to known limits 1858 if (widths != null) { 1859 mWidthRange = mWidthRange.intersect(widths); 1860 } 1861 if (heights != null) { 1862 mHeightRange = mHeightRange.intersect(heights); 1863 } 1864 if (counts != null) { 1865 mBlockCountRange = mBlockCountRange.intersect( 1866 Utils.factorRange(counts, mBlockWidth * mBlockHeight 1867 / blockSize.getWidth() / blockSize.getHeight())); 1868 } 1869 if (blockRates != null) { 1870 mBlocksPerSecondRange = mBlocksPerSecondRange.intersect( 1871 Utils.factorRange(blockRates, mBlockWidth * mBlockHeight 1872 / blockSize.getWidth() / blockSize.getHeight())); 1873 } 1874 if (blockRatios != null) { 1875 mBlockAspectRatioRange = mBlockAspectRatioRange.intersect( 1876 Utils.scaleRange(blockRatios, 1877 mBlockHeight / blockSize.getHeight(), 1878 mBlockWidth / blockSize.getWidth())); 1879 } 1880 if (ratios != null) { 1881 mAspectRatioRange = mAspectRatioRange.intersect(ratios); 1882 } 1883 if (frameRates != null) { 1884 mFrameRateRange = mFrameRateRange.intersect(frameRates); 1885 } 1886 if (bitRates != null) { 1887 mBitrateRange = mBitrateRange.intersect(bitRates); 1888 } 1889 } 1890 updateLimits(); 1891 } 1892 applyBlockLimits( int blockWidth, int blockHeight, Range<Integer> counts, Range<Long> rates, Range<Rational> ratios)1893 private void applyBlockLimits( 1894 int blockWidth, int blockHeight, 1895 Range<Integer> counts, Range<Long> rates, Range<Rational> ratios) { 1896 checkPowerOfTwo(blockWidth, "blockWidth must be a power of two"); 1897 checkPowerOfTwo(blockHeight, "blockHeight must be a power of two"); 1898 1899 final int newBlockWidth = Math.max(blockWidth, mBlockWidth); 1900 final int newBlockHeight = Math.max(blockHeight, mBlockHeight); 1901 1902 // factor will always be a power-of-2 1903 int factor = 1904 newBlockWidth * newBlockHeight / mBlockWidth / mBlockHeight; 1905 if (factor != 1) { 1906 mBlockCountRange = Utils.factorRange(mBlockCountRange, factor); 1907 mBlocksPerSecondRange = Utils.factorRange( 1908 mBlocksPerSecondRange, factor); 1909 mBlockAspectRatioRange = Utils.scaleRange( 1910 mBlockAspectRatioRange, 1911 newBlockHeight / mBlockHeight, 1912 newBlockWidth / mBlockWidth); 1913 mHorizontalBlockRange = Utils.factorRange( 1914 mHorizontalBlockRange, newBlockWidth / mBlockWidth); 1915 mVerticalBlockRange = Utils.factorRange( 1916 mVerticalBlockRange, newBlockHeight / mBlockHeight); 1917 } 1918 factor = newBlockWidth * newBlockHeight / blockWidth / blockHeight; 1919 if (factor != 1) { 1920 counts = Utils.factorRange(counts, factor); 1921 rates = Utils.factorRange(rates, factor); 1922 ratios = Utils.scaleRange( 1923 ratios, newBlockHeight / blockHeight, 1924 newBlockWidth / blockWidth); 1925 } 1926 mBlockCountRange = mBlockCountRange.intersect(counts); 1927 mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(rates); 1928 mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(ratios); 1929 mBlockWidth = newBlockWidth; 1930 mBlockHeight = newBlockHeight; 1931 } 1932 applyAlignment(int widthAlignment, int heightAlignment)1933 private void applyAlignment(int widthAlignment, int heightAlignment) { 1934 checkPowerOfTwo(widthAlignment, "widthAlignment must be a power of two"); 1935 checkPowerOfTwo(heightAlignment, "heightAlignment must be a power of two"); 1936 1937 if (widthAlignment > mBlockWidth || heightAlignment > mBlockHeight) { 1938 // maintain assumption that 0 < alignment <= block-size 1939 applyBlockLimits( 1940 Math.max(widthAlignment, mBlockWidth), 1941 Math.max(heightAlignment, mBlockHeight), 1942 POSITIVE_INTEGERS, POSITIVE_LONGS, POSITIVE_RATIONALS); 1943 } 1944 1945 mWidthAlignment = Math.max(widthAlignment, mWidthAlignment); 1946 mHeightAlignment = Math.max(heightAlignment, mHeightAlignment); 1947 1948 mWidthRange = Utils.alignRange(mWidthRange, mWidthAlignment); 1949 mHeightRange = Utils.alignRange(mHeightRange, mHeightAlignment); 1950 } 1951 updateLimits()1952 private void updateLimits() { 1953 // pixels -> blocks <- counts 1954 mHorizontalBlockRange = mHorizontalBlockRange.intersect( 1955 Utils.factorRange(mWidthRange, mBlockWidth)); 1956 mHorizontalBlockRange = mHorizontalBlockRange.intersect( 1957 Range.create( 1958 mBlockCountRange.getLower() / mVerticalBlockRange.getUpper(), 1959 mBlockCountRange.getUpper() / mVerticalBlockRange.getLower())); 1960 mVerticalBlockRange = mVerticalBlockRange.intersect( 1961 Utils.factorRange(mHeightRange, mBlockHeight)); 1962 mVerticalBlockRange = mVerticalBlockRange.intersect( 1963 Range.create( 1964 mBlockCountRange.getLower() / mHorizontalBlockRange.getUpper(), 1965 mBlockCountRange.getUpper() / mHorizontalBlockRange.getLower())); 1966 mBlockCountRange = mBlockCountRange.intersect( 1967 Range.create( 1968 mHorizontalBlockRange.getLower() 1969 * mVerticalBlockRange.getLower(), 1970 mHorizontalBlockRange.getUpper() 1971 * mVerticalBlockRange.getUpper())); 1972 mBlockAspectRatioRange = mBlockAspectRatioRange.intersect( 1973 new Rational( 1974 mHorizontalBlockRange.getLower(), mVerticalBlockRange.getUpper()), 1975 new Rational( 1976 mHorizontalBlockRange.getUpper(), mVerticalBlockRange.getLower())); 1977 1978 // blocks -> pixels 1979 mWidthRange = mWidthRange.intersect( 1980 (mHorizontalBlockRange.getLower() - 1) * mBlockWidth + mWidthAlignment, 1981 mHorizontalBlockRange.getUpper() * mBlockWidth); 1982 mHeightRange = mHeightRange.intersect( 1983 (mVerticalBlockRange.getLower() - 1) * mBlockHeight + mHeightAlignment, 1984 mVerticalBlockRange.getUpper() * mBlockHeight); 1985 mAspectRatioRange = mAspectRatioRange.intersect( 1986 new Rational(mWidthRange.getLower(), mHeightRange.getUpper()), 1987 new Rational(mWidthRange.getUpper(), mHeightRange.getLower())); 1988 1989 mSmallerDimensionUpperLimit = Math.min( 1990 mSmallerDimensionUpperLimit, 1991 Math.min(mWidthRange.getUpper(), mHeightRange.getUpper())); 1992 1993 // blocks -> rate 1994 mBlocksPerSecondRange = mBlocksPerSecondRange.intersect( 1995 mBlockCountRange.getLower() * (long)mFrameRateRange.getLower(), 1996 mBlockCountRange.getUpper() * (long)mFrameRateRange.getUpper()); 1997 mFrameRateRange = mFrameRateRange.intersect( 1998 (int)(mBlocksPerSecondRange.getLower() 1999 / mBlockCountRange.getUpper()), 2000 (int)(mBlocksPerSecondRange.getUpper() 2001 / (double)mBlockCountRange.getLower())); 2002 } 2003 applyMacroBlockLimits( int maxHorizontalBlocks, int maxVerticalBlocks, int maxBlocks, long maxBlocksPerSecond, int blockWidth, int blockHeight, int widthAlignment, int heightAlignment)2004 private void applyMacroBlockLimits( 2005 int maxHorizontalBlocks, int maxVerticalBlocks, 2006 int maxBlocks, long maxBlocksPerSecond, 2007 int blockWidth, int blockHeight, 2008 int widthAlignment, int heightAlignment) { 2009 applyMacroBlockLimits( 2010 1 /* minHorizontalBlocks */, 1 /* minVerticalBlocks */, 2011 maxHorizontalBlocks, maxVerticalBlocks, 2012 maxBlocks, maxBlocksPerSecond, 2013 blockWidth, blockHeight, widthAlignment, heightAlignment); 2014 } 2015 applyMacroBlockLimits( int minHorizontalBlocks, int minVerticalBlocks, int maxHorizontalBlocks, int maxVerticalBlocks, int maxBlocks, long maxBlocksPerSecond, int blockWidth, int blockHeight, int widthAlignment, int heightAlignment)2016 private void applyMacroBlockLimits( 2017 int minHorizontalBlocks, int minVerticalBlocks, 2018 int maxHorizontalBlocks, int maxVerticalBlocks, 2019 int maxBlocks, long maxBlocksPerSecond, 2020 int blockWidth, int blockHeight, 2021 int widthAlignment, int heightAlignment) { 2022 applyAlignment(widthAlignment, heightAlignment); 2023 applyBlockLimits( 2024 blockWidth, blockHeight, Range.create(1, maxBlocks), 2025 Range.create(1L, maxBlocksPerSecond), 2026 Range.create( 2027 new Rational(1, maxVerticalBlocks), 2028 new Rational(maxHorizontalBlocks, 1))); 2029 mHorizontalBlockRange = 2030 mHorizontalBlockRange.intersect( 2031 Utils.divUp(minHorizontalBlocks, (mBlockWidth / blockWidth)), 2032 maxHorizontalBlocks / (mBlockWidth / blockWidth)); 2033 mVerticalBlockRange = 2034 mVerticalBlockRange.intersect( 2035 Utils.divUp(minVerticalBlocks, (mBlockHeight / blockHeight)), 2036 maxVerticalBlocks / (mBlockHeight / blockHeight)); 2037 } 2038 applyLevelLimits()2039 private void applyLevelLimits() { 2040 long maxBlocksPerSecond = 0; 2041 int maxBlocks = 0; 2042 int maxBps = 0; 2043 int maxDPBBlocks = 0; 2044 2045 int errors = ERROR_NONE_SUPPORTED; 2046 CodecProfileLevel[] profileLevels = mParent.profileLevels; 2047 String mime = mParent.getMimeType(); 2048 2049 if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC)) { 2050 maxBlocks = 99; 2051 maxBlocksPerSecond = 1485; 2052 maxBps = 64000; 2053 maxDPBBlocks = 396; 2054 for (CodecProfileLevel profileLevel: profileLevels) { 2055 int MBPS = 0, FS = 0, BR = 0, DPB = 0; 2056 boolean supported = true; 2057 switch (profileLevel.level) { 2058 case CodecProfileLevel.AVCLevel1: 2059 MBPS = 1485; FS = 99; BR = 64; DPB = 396; break; 2060 case CodecProfileLevel.AVCLevel1b: 2061 MBPS = 1485; FS = 99; BR = 128; DPB = 396; break; 2062 case CodecProfileLevel.AVCLevel11: 2063 MBPS = 3000; FS = 396; BR = 192; DPB = 900; break; 2064 case CodecProfileLevel.AVCLevel12: 2065 MBPS = 6000; FS = 396; BR = 384; DPB = 2376; break; 2066 case CodecProfileLevel.AVCLevel13: 2067 MBPS = 11880; FS = 396; BR = 768; DPB = 2376; break; 2068 case CodecProfileLevel.AVCLevel2: 2069 MBPS = 11880; FS = 396; BR = 2000; DPB = 2376; break; 2070 case CodecProfileLevel.AVCLevel21: 2071 MBPS = 19800; FS = 792; BR = 4000; DPB = 4752; break; 2072 case CodecProfileLevel.AVCLevel22: 2073 MBPS = 20250; FS = 1620; BR = 4000; DPB = 8100; break; 2074 case CodecProfileLevel.AVCLevel3: 2075 MBPS = 40500; FS = 1620; BR = 10000; DPB = 8100; break; 2076 case CodecProfileLevel.AVCLevel31: 2077 MBPS = 108000; FS = 3600; BR = 14000; DPB = 18000; break; 2078 case CodecProfileLevel.AVCLevel32: 2079 MBPS = 216000; FS = 5120; BR = 20000; DPB = 20480; break; 2080 case CodecProfileLevel.AVCLevel4: 2081 MBPS = 245760; FS = 8192; BR = 20000; DPB = 32768; break; 2082 case CodecProfileLevel.AVCLevel41: 2083 MBPS = 245760; FS = 8192; BR = 50000; DPB = 32768; break; 2084 case CodecProfileLevel.AVCLevel42: 2085 MBPS = 522240; FS = 8704; BR = 50000; DPB = 34816; break; 2086 case CodecProfileLevel.AVCLevel5: 2087 MBPS = 589824; FS = 22080; BR = 135000; DPB = 110400; break; 2088 case CodecProfileLevel.AVCLevel51: 2089 MBPS = 983040; FS = 36864; BR = 240000; DPB = 184320; break; 2090 case CodecProfileLevel.AVCLevel52: 2091 MBPS = 2073600; FS = 36864; BR = 240000; DPB = 184320; break; 2092 default: 2093 Log.w(TAG, "Unrecognized level " 2094 + profileLevel.level + " for " + mime); 2095 errors |= ERROR_UNRECOGNIZED; 2096 } 2097 switch (profileLevel.profile) { 2098 case CodecProfileLevel.AVCProfileHigh: 2099 BR *= 1250; break; 2100 case CodecProfileLevel.AVCProfileHigh10: 2101 BR *= 3000; break; 2102 case CodecProfileLevel.AVCProfileExtended: 2103 case CodecProfileLevel.AVCProfileHigh422: 2104 case CodecProfileLevel.AVCProfileHigh444: 2105 Log.w(TAG, "Unsupported profile " 2106 + profileLevel.profile + " for " + mime); 2107 errors |= ERROR_UNSUPPORTED; 2108 supported = false; 2109 // fall through - treat as base profile 2110 case CodecProfileLevel.AVCProfileBaseline: 2111 case CodecProfileLevel.AVCProfileMain: 2112 BR *= 1000; break; 2113 default: 2114 Log.w(TAG, "Unrecognized profile " 2115 + profileLevel.profile + " for " + mime); 2116 errors |= ERROR_UNRECOGNIZED; 2117 BR *= 1000; 2118 } 2119 if (supported) { 2120 errors &= ~ERROR_NONE_SUPPORTED; 2121 } 2122 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); 2123 maxBlocks = Math.max(FS, maxBlocks); 2124 maxBps = Math.max(BR, maxBps); 2125 maxDPBBlocks = Math.max(maxDPBBlocks, DPB); 2126 } 2127 2128 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8)); 2129 applyMacroBlockLimits( 2130 maxLengthInBlocks, maxLengthInBlocks, 2131 maxBlocks, maxBlocksPerSecond, 2132 16 /* blockWidth */, 16 /* blockHeight */, 2133 1 /* widthAlignment */, 1 /* heightAlignment */); 2134 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG2)) { 2135 int maxWidth = 11, maxHeight = 9, maxRate = 15; 2136 maxBlocks = 99; 2137 maxBlocksPerSecond = 1485; 2138 maxBps = 64000; 2139 for (CodecProfileLevel profileLevel: profileLevels) { 2140 int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0; 2141 boolean supported = true; 2142 switch (profileLevel.profile) { 2143 case CodecProfileLevel.MPEG2ProfileSimple: 2144 switch (profileLevel.level) { 2145 case CodecProfileLevel.MPEG2LevelML: 2146 FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 15000; break; 2147 default: 2148 Log.w(TAG, "Unrecognized profile/level " 2149 + profileLevel.profile + "/" 2150 + profileLevel.level + " for " + mime); 2151 errors |= ERROR_UNRECOGNIZED; 2152 } 2153 break; 2154 case CodecProfileLevel.MPEG2ProfileMain: 2155 switch (profileLevel.level) { 2156 case CodecProfileLevel.MPEG2LevelLL: 2157 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 4000; break; 2158 case CodecProfileLevel.MPEG2LevelML: 2159 FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 15000; break; 2160 case CodecProfileLevel.MPEG2LevelH14: 2161 FR = 60; W = 90; H = 68; MBPS = 183600; FS = 6120; BR = 60000; break; 2162 case CodecProfileLevel.MPEG2LevelHL: 2163 FR = 60; W = 120; H = 68; MBPS = 244800; FS = 8160; BR = 80000; break; 2164 case CodecProfileLevel.MPEG2LevelHP: 2165 FR = 60; W = 120; H = 68; MBPS = 489600; FS = 8160; BR = 80000; break; 2166 default: 2167 Log.w(TAG, "Unrecognized profile/level " 2168 + profileLevel.profile + "/" 2169 + profileLevel.level + " for " + mime); 2170 errors |= ERROR_UNRECOGNIZED; 2171 } 2172 break; 2173 case CodecProfileLevel.MPEG2Profile422: 2174 case CodecProfileLevel.MPEG2ProfileSNR: 2175 case CodecProfileLevel.MPEG2ProfileSpatial: 2176 case CodecProfileLevel.MPEG2ProfileHigh: 2177 Log.i(TAG, "Unsupported profile " 2178 + profileLevel.profile + " for " + mime); 2179 errors |= ERROR_UNSUPPORTED; 2180 supported = false; 2181 break; 2182 default: 2183 Log.w(TAG, "Unrecognized profile " 2184 + profileLevel.profile + " for " + mime); 2185 errors |= ERROR_UNRECOGNIZED; 2186 } 2187 if (supported) { 2188 errors &= ~ERROR_NONE_SUPPORTED; 2189 } 2190 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); 2191 maxBlocks = Math.max(FS, maxBlocks); 2192 maxBps = Math.max(BR * 1000, maxBps); 2193 maxWidth = Math.max(W, maxWidth); 2194 maxHeight = Math.max(H, maxHeight); 2195 maxRate = Math.max(FR, maxRate); 2196 } 2197 applyMacroBlockLimits(maxWidth, maxHeight, 2198 maxBlocks, maxBlocksPerSecond, 2199 16 /* blockWidth */, 16 /* blockHeight */, 2200 1 /* widthAlignment */, 1 /* heightAlignment */); 2201 mFrameRateRange = mFrameRateRange.intersect(12, maxRate); 2202 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) { 2203 int maxWidth = 11, maxHeight = 9, maxRate = 15; 2204 maxBlocks = 99; 2205 maxBlocksPerSecond = 1485; 2206 maxBps = 64000; 2207 for (CodecProfileLevel profileLevel: profileLevels) { 2208 int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0; 2209 boolean strict = false; // true: W, H and FR are individual max limits 2210 boolean supported = true; 2211 switch (profileLevel.profile) { 2212 case CodecProfileLevel.MPEG4ProfileSimple: 2213 switch (profileLevel.level) { 2214 case CodecProfileLevel.MPEG4Level0: 2215 strict = true; 2216 FR = 15; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 64; break; 2217 case CodecProfileLevel.MPEG4Level1: 2218 FR = 30; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 64; break; 2219 case CodecProfileLevel.MPEG4Level0b: 2220 strict = true; 2221 FR = 15; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 128; break; 2222 case CodecProfileLevel.MPEG4Level2: 2223 FR = 30; W = 22; H = 18; MBPS = 5940; FS = 396; BR = 128; break; 2224 case CodecProfileLevel.MPEG4Level3: 2225 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384; break; 2226 case CodecProfileLevel.MPEG4Level4a: 2227 FR = 30; W = 40; H = 30; MBPS = 36000; FS = 1200; BR = 4000; break; 2228 case CodecProfileLevel.MPEG4Level5: 2229 FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 8000; break; 2230 case CodecProfileLevel.MPEG4Level6: 2231 FR = 30; W = 80; H = 45; MBPS = 108000; FS = 3600; BR = 12000; break; 2232 default: 2233 Log.w(TAG, "Unrecognized profile/level " 2234 + profileLevel.profile + "/" 2235 + profileLevel.level + " for " + mime); 2236 errors |= ERROR_UNRECOGNIZED; 2237 } 2238 break; 2239 case CodecProfileLevel.MPEG4ProfileAdvancedSimple: 2240 switch (profileLevel.level) { 2241 case CodecProfileLevel.MPEG4Level0: 2242 case CodecProfileLevel.MPEG4Level1: 2243 FR = 30; W = 11; H = 9; MBPS = 2970; FS = 99; BR = 128; break; 2244 case CodecProfileLevel.MPEG4Level2: 2245 FR = 30; W = 22; H = 18; MBPS = 5940; FS = 396; BR = 384; break; 2246 case CodecProfileLevel.MPEG4Level3: 2247 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 768; break; 2248 case CodecProfileLevel.MPEG4Level3b: 2249 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 1500; break; 2250 case CodecProfileLevel.MPEG4Level4: 2251 FR = 30; W = 44; H = 36; MBPS = 23760; FS = 792; BR = 3000; break; 2252 case CodecProfileLevel.MPEG4Level5: 2253 FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 8000; break; 2254 default: 2255 Log.w(TAG, "Unrecognized profile/level " 2256 + profileLevel.profile + "/" 2257 + profileLevel.level + " for " + mime); 2258 errors |= ERROR_UNRECOGNIZED; 2259 } 2260 break; 2261 case CodecProfileLevel.MPEG4ProfileMain: // 2-4 2262 case CodecProfileLevel.MPEG4ProfileNbit: // 2 2263 case CodecProfileLevel.MPEG4ProfileAdvancedRealTime: // 1-4 2264 case CodecProfileLevel.MPEG4ProfileCoreScalable: // 1-3 2265 case CodecProfileLevel.MPEG4ProfileAdvancedCoding: // 1-4 2266 case CodecProfileLevel.MPEG4ProfileCore: // 1-2 2267 case CodecProfileLevel.MPEG4ProfileAdvancedCore: // 1-4 2268 case CodecProfileLevel.MPEG4ProfileSimpleScalable: // 0-2 2269 case CodecProfileLevel.MPEG4ProfileHybrid: // 1-2 2270 2271 // Studio profiles are not supported by our codecs. 2272 2273 // Only profiles that can decode simple object types are considered. 2274 // The following profiles are not able to. 2275 case CodecProfileLevel.MPEG4ProfileBasicAnimated: // 1-2 2276 case CodecProfileLevel.MPEG4ProfileScalableTexture: // 1 2277 case CodecProfileLevel.MPEG4ProfileSimpleFace: // 1-2 2278 case CodecProfileLevel.MPEG4ProfileAdvancedScalable: // 1-3 2279 case CodecProfileLevel.MPEG4ProfileSimpleFBA: // 1-2 2280 Log.i(TAG, "Unsupported profile " 2281 + profileLevel.profile + " for " + mime); 2282 errors |= ERROR_UNSUPPORTED; 2283 supported = false; 2284 break; 2285 default: 2286 Log.w(TAG, "Unrecognized profile " 2287 + profileLevel.profile + " for " + mime); 2288 errors |= ERROR_UNRECOGNIZED; 2289 } 2290 if (supported) { 2291 errors &= ~ERROR_NONE_SUPPORTED; 2292 } 2293 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); 2294 maxBlocks = Math.max(FS, maxBlocks); 2295 maxBps = Math.max(BR * 1000, maxBps); 2296 if (strict) { 2297 maxWidth = Math.max(W, maxWidth); 2298 maxHeight = Math.max(H, maxHeight); 2299 maxRate = Math.max(FR, maxRate); 2300 } else { 2301 // assuming max 60 fps frame rate and 1:2 aspect ratio 2302 int maxDim = (int)Math.sqrt(FS * 2); 2303 maxWidth = Math.max(maxDim, maxWidth); 2304 maxHeight = Math.max(maxDim, maxHeight); 2305 maxRate = Math.max(Math.max(FR, 60), maxRate); 2306 } 2307 } 2308 applyMacroBlockLimits(maxWidth, maxHeight, 2309 maxBlocks, maxBlocksPerSecond, 2310 16 /* blockWidth */, 16 /* blockHeight */, 2311 1 /* widthAlignment */, 1 /* heightAlignment */); 2312 mFrameRateRange = mFrameRateRange.intersect(12, maxRate); 2313 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) { 2314 int maxWidth = 11, maxHeight = 9, maxRate = 15; 2315 int minWidth = maxWidth, minHeight = maxHeight; 2316 int minAlignment = 16; 2317 maxBlocks = 99; 2318 maxBlocksPerSecond = 1485; 2319 maxBps = 64000; 2320 for (CodecProfileLevel profileLevel: profileLevels) { 2321 int MBPS = 0, BR = 0, FR = 0, W = 0, H = 0, minW = minWidth, minH = minHeight; 2322 boolean strict = false; // true: support only sQCIF, QCIF (maybe CIF) 2323 switch (profileLevel.level) { 2324 case CodecProfileLevel.H263Level10: 2325 strict = true; // only supports sQCIF & QCIF 2326 FR = 15; W = 11; H = 9; BR = 1; MBPS = W * H * FR; break; 2327 case CodecProfileLevel.H263Level20: 2328 strict = true; // only supports sQCIF, QCIF & CIF 2329 FR = 30; W = 22; H = 18; BR = 2; MBPS = W * H * 15; break; 2330 case CodecProfileLevel.H263Level30: 2331 strict = true; // only supports sQCIF, QCIF & CIF 2332 FR = 30; W = 22; H = 18; BR = 6; MBPS = W * H * FR; break; 2333 case CodecProfileLevel.H263Level40: 2334 strict = true; // only supports sQCIF, QCIF & CIF 2335 FR = 30; W = 22; H = 18; BR = 32; MBPS = W * H * FR; break; 2336 case CodecProfileLevel.H263Level45: 2337 // only implies level 10 support 2338 strict = profileLevel.profile == CodecProfileLevel.H263ProfileBaseline 2339 || profileLevel.profile == 2340 CodecProfileLevel.H263ProfileBackwardCompatible; 2341 if (!strict) { 2342 minW = 1; minH = 1; minAlignment = 4; 2343 } 2344 FR = 15; W = 11; H = 9; BR = 2; MBPS = W * H * FR; break; 2345 case CodecProfileLevel.H263Level50: 2346 // only supports 50fps for H > 15 2347 minW = 1; minH = 1; minAlignment = 4; 2348 FR = 60; W = 22; H = 18; BR = 64; MBPS = W * H * 50; break; 2349 case CodecProfileLevel.H263Level60: 2350 // only supports 50fps for H > 15 2351 minW = 1; minH = 1; minAlignment = 4; 2352 FR = 60; W = 45; H = 18; BR = 128; MBPS = W * H * 50; break; 2353 case CodecProfileLevel.H263Level70: 2354 // only supports 50fps for H > 30 2355 minW = 1; minH = 1; minAlignment = 4; 2356 FR = 60; W = 45; H = 36; BR = 256; MBPS = W * H * 50; break; 2357 default: 2358 Log.w(TAG, "Unrecognized profile/level " + profileLevel.profile 2359 + "/" + profileLevel.level + " for " + mime); 2360 errors |= ERROR_UNRECOGNIZED; 2361 } 2362 switch (profileLevel.profile) { 2363 case CodecProfileLevel.H263ProfileBackwardCompatible: 2364 case CodecProfileLevel.H263ProfileBaseline: 2365 case CodecProfileLevel.H263ProfileH320Coding: 2366 case CodecProfileLevel.H263ProfileHighCompression: 2367 case CodecProfileLevel.H263ProfileHighLatency: 2368 case CodecProfileLevel.H263ProfileInterlace: 2369 case CodecProfileLevel.H263ProfileInternet: 2370 case CodecProfileLevel.H263ProfileISWV2: 2371 case CodecProfileLevel.H263ProfileISWV3: 2372 break; 2373 default: 2374 Log.w(TAG, "Unrecognized profile " 2375 + profileLevel.profile + " for " + mime); 2376 errors |= ERROR_UNRECOGNIZED; 2377 } 2378 if (strict) { 2379 // Strict levels define sub-QCIF min size and enumerated sizes. We cannot 2380 // express support for "only sQCIF & QCIF (& CIF)" using VideoCapabilities 2381 // but we can express "only QCIF (& CIF)", so set minimume size at QCIF. 2382 // minW = 8; minH = 6; 2383 minW = 11; minH = 9; 2384 } else { 2385 // any support for non-strict levels (including unrecognized profiles or 2386 // levels) allow custom frame size support beyond supported limits 2387 // (other than bitrate) 2388 mAllowMbOverride = true; 2389 } 2390 errors &= ~ERROR_NONE_SUPPORTED; 2391 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); 2392 maxBlocks = Math.max(W * H, maxBlocks); 2393 maxBps = Math.max(BR * 64000, maxBps); 2394 maxWidth = Math.max(W, maxWidth); 2395 maxHeight = Math.max(H, maxHeight); 2396 maxRate = Math.max(FR, maxRate); 2397 minWidth = Math.min(minW, minWidth); 2398 minHeight = Math.min(minH, minHeight); 2399 } 2400 // unless we encountered custom frame size support, limit size to QCIF and CIF 2401 // using aspect ratio. 2402 if (!mAllowMbOverride) { 2403 mBlockAspectRatioRange = 2404 Range.create(new Rational(11, 9), new Rational(11, 9)); 2405 } 2406 applyMacroBlockLimits( 2407 minWidth, minHeight, 2408 maxWidth, maxHeight, 2409 maxBlocks, maxBlocksPerSecond, 2410 16 /* blockWidth */, 16 /* blockHeight */, 2411 minAlignment /* widthAlignment */, minAlignment /* heightAlignment */); 2412 mFrameRateRange = Range.create(1, maxRate); 2413 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8)) { 2414 maxBlocks = Integer.MAX_VALUE; 2415 maxBlocksPerSecond = Integer.MAX_VALUE; 2416 2417 // TODO: set to 100Mbps for now, need a number for VP8 2418 maxBps = 100000000; 2419 2420 // profile levels are not indicative for VPx, but verify 2421 // them nonetheless 2422 for (CodecProfileLevel profileLevel: profileLevels) { 2423 switch (profileLevel.level) { 2424 case CodecProfileLevel.VP8Level_Version0: 2425 case CodecProfileLevel.VP8Level_Version1: 2426 case CodecProfileLevel.VP8Level_Version2: 2427 case CodecProfileLevel.VP8Level_Version3: 2428 break; 2429 default: 2430 Log.w(TAG, "Unrecognized level " 2431 + profileLevel.level + " for " + mime); 2432 errors |= ERROR_UNRECOGNIZED; 2433 } 2434 switch (profileLevel.profile) { 2435 case CodecProfileLevel.VP8ProfileMain: 2436 break; 2437 default: 2438 Log.w(TAG, "Unrecognized profile " 2439 + profileLevel.profile + " for " + mime); 2440 errors |= ERROR_UNRECOGNIZED; 2441 } 2442 errors &= ~ERROR_NONE_SUPPORTED; 2443 } 2444 2445 final int blockSize = 16; 2446 applyMacroBlockLimits(Short.MAX_VALUE, Short.MAX_VALUE, 2447 maxBlocks, maxBlocksPerSecond, blockSize, blockSize, 2448 1 /* widthAlignment */, 1 /* heightAlignment */); 2449 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) { 2450 maxBlocksPerSecond = 829440; 2451 maxBlocks = 36864; 2452 maxBps = 200000; 2453 int maxDim = 512; 2454 2455 for (CodecProfileLevel profileLevel: profileLevels) { 2456 long SR = 0; // luma sample rate 2457 int FS = 0; // luma picture size 2458 int BR = 0; // bit rate kbps 2459 int D = 0; // luma dimension 2460 switch (profileLevel.level) { 2461 case CodecProfileLevel.VP9Level1: 2462 SR = 829440; FS = 36864; BR = 200; D = 512; break; 2463 case CodecProfileLevel.VP9Level11: 2464 SR = 2764800; FS = 73728; BR = 800; D = 768; break; 2465 case CodecProfileLevel.VP9Level2: 2466 SR = 4608000; FS = 122880; BR = 1800; D = 960; break; 2467 case CodecProfileLevel.VP9Level21: 2468 SR = 9216000; FS = 245760; BR = 3600; D = 1344; break; 2469 case CodecProfileLevel.VP9Level3: 2470 SR = 20736000; FS = 552960; BR = 7200; D = 2048; break; 2471 case CodecProfileLevel.VP9Level31: 2472 SR = 36864000; FS = 983040; BR = 12000; D = 2752; break; 2473 case CodecProfileLevel.VP9Level4: 2474 SR = 83558400; FS = 2228224; BR = 18000; D = 4160; break; 2475 case CodecProfileLevel.VP9Level41: 2476 SR = 160432128; FS = 2228224; BR = 30000; D = 4160; break; 2477 case CodecProfileLevel.VP9Level5: 2478 SR = 311951360; FS = 8912896; BR = 60000; D = 8384; break; 2479 case CodecProfileLevel.VP9Level51: 2480 SR = 588251136; FS = 8912896; BR = 120000; D = 8384; break; 2481 case CodecProfileLevel.VP9Level52: 2482 SR = 1176502272; FS = 8912896; BR = 180000; D = 8384; break; 2483 case CodecProfileLevel.VP9Level6: 2484 SR = 1176502272; FS = 35651584; BR = 180000; D = 16832; break; 2485 case CodecProfileLevel.VP9Level61: 2486 SR = 2353004544L; FS = 35651584; BR = 240000; D = 16832; break; 2487 case CodecProfileLevel.VP9Level62: 2488 SR = 4706009088L; FS = 35651584; BR = 480000; D = 16832; break; 2489 default: 2490 Log.w(TAG, "Unrecognized level " 2491 + profileLevel.level + " for " + mime); 2492 errors |= ERROR_UNRECOGNIZED; 2493 } 2494 switch (profileLevel.profile) { 2495 case CodecProfileLevel.VP9Profile0: 2496 case CodecProfileLevel.VP9Profile1: 2497 case CodecProfileLevel.VP9Profile2: 2498 case CodecProfileLevel.VP9Profile3: 2499 case CodecProfileLevel.VP9Profile2HDR: 2500 case CodecProfileLevel.VP9Profile3HDR: 2501 break; 2502 default: 2503 Log.w(TAG, "Unrecognized profile " 2504 + profileLevel.profile + " for " + mime); 2505 errors |= ERROR_UNRECOGNIZED; 2506 } 2507 errors &= ~ERROR_NONE_SUPPORTED; 2508 maxBlocksPerSecond = Math.max(SR, maxBlocksPerSecond); 2509 maxBlocks = Math.max(FS, maxBlocks); 2510 maxBps = Math.max(BR * 1000, maxBps); 2511 maxDim = Math.max(D, maxDim); 2512 } 2513 2514 final int blockSize = 8; 2515 int maxLengthInBlocks = Utils.divUp(maxDim, blockSize); 2516 maxBlocks = Utils.divUp(maxBlocks, blockSize * blockSize); 2517 maxBlocksPerSecond = Utils.divUp(maxBlocksPerSecond, blockSize * blockSize); 2518 2519 applyMacroBlockLimits( 2520 maxLengthInBlocks, maxLengthInBlocks, 2521 maxBlocks, maxBlocksPerSecond, 2522 blockSize, blockSize, 2523 1 /* widthAlignment */, 1 /* heightAlignment */); 2524 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) { 2525 // CTBs are at least 8x8 so use 8x8 block size 2526 maxBlocks = 36864 >> 6; // 192x192 pixels == 576 8x8 blocks 2527 maxBlocksPerSecond = maxBlocks * 15; 2528 maxBps = 128000; 2529 for (CodecProfileLevel profileLevel: profileLevels) { 2530 double FR = 0; 2531 int FS = 0; 2532 int BR = 0; 2533 switch (profileLevel.level) { 2534 /* The HEVC spec talks only in a very convoluted manner about the 2535 existence of levels 1-3.1 for High tier, which could also be 2536 understood as 'decoders and encoders should treat these levels 2537 as if they were Main tier', so we do that. */ 2538 case CodecProfileLevel.HEVCMainTierLevel1: 2539 case CodecProfileLevel.HEVCHighTierLevel1: 2540 FR = 15; FS = 36864; BR = 128; break; 2541 case CodecProfileLevel.HEVCMainTierLevel2: 2542 case CodecProfileLevel.HEVCHighTierLevel2: 2543 FR = 30; FS = 122880; BR = 1500; break; 2544 case CodecProfileLevel.HEVCMainTierLevel21: 2545 case CodecProfileLevel.HEVCHighTierLevel21: 2546 FR = 30; FS = 245760; BR = 3000; break; 2547 case CodecProfileLevel.HEVCMainTierLevel3: 2548 case CodecProfileLevel.HEVCHighTierLevel3: 2549 FR = 30; FS = 552960; BR = 6000; break; 2550 case CodecProfileLevel.HEVCMainTierLevel31: 2551 case CodecProfileLevel.HEVCHighTierLevel31: 2552 FR = 33.75; FS = 983040; BR = 10000; break; 2553 case CodecProfileLevel.HEVCMainTierLevel4: 2554 FR = 30; FS = 2228224; BR = 12000; break; 2555 case CodecProfileLevel.HEVCHighTierLevel4: 2556 FR = 30; FS = 2228224; BR = 30000; break; 2557 case CodecProfileLevel.HEVCMainTierLevel41: 2558 FR = 60; FS = 2228224; BR = 20000; break; 2559 case CodecProfileLevel.HEVCHighTierLevel41: 2560 FR = 60; FS = 2228224; BR = 50000; break; 2561 case CodecProfileLevel.HEVCMainTierLevel5: 2562 FR = 30; FS = 8912896; BR = 25000; break; 2563 case CodecProfileLevel.HEVCHighTierLevel5: 2564 FR = 30; FS = 8912896; BR = 100000; break; 2565 case CodecProfileLevel.HEVCMainTierLevel51: 2566 FR = 60; FS = 8912896; BR = 40000; break; 2567 case CodecProfileLevel.HEVCHighTierLevel51: 2568 FR = 60; FS = 8912896; BR = 160000; break; 2569 case CodecProfileLevel.HEVCMainTierLevel52: 2570 FR = 120; FS = 8912896; BR = 60000; break; 2571 case CodecProfileLevel.HEVCHighTierLevel52: 2572 FR = 120; FS = 8912896; BR = 240000; break; 2573 case CodecProfileLevel.HEVCMainTierLevel6: 2574 FR = 30; FS = 35651584; BR = 60000; break; 2575 case CodecProfileLevel.HEVCHighTierLevel6: 2576 FR = 30; FS = 35651584; BR = 240000; break; 2577 case CodecProfileLevel.HEVCMainTierLevel61: 2578 FR = 60; FS = 35651584; BR = 120000; break; 2579 case CodecProfileLevel.HEVCHighTierLevel61: 2580 FR = 60; FS = 35651584; BR = 480000; break; 2581 case CodecProfileLevel.HEVCMainTierLevel62: 2582 FR = 120; FS = 35651584; BR = 240000; break; 2583 case CodecProfileLevel.HEVCHighTierLevel62: 2584 FR = 120; FS = 35651584; BR = 800000; break; 2585 default: 2586 Log.w(TAG, "Unrecognized level " 2587 + profileLevel.level + " for " + mime); 2588 errors |= ERROR_UNRECOGNIZED; 2589 } 2590 switch (profileLevel.profile) { 2591 case CodecProfileLevel.HEVCProfileMain: 2592 case CodecProfileLevel.HEVCProfileMain10: 2593 case CodecProfileLevel.HEVCProfileMain10HDR10: 2594 break; 2595 default: 2596 Log.w(TAG, "Unrecognized profile " 2597 + profileLevel.profile + " for " + mime); 2598 errors |= ERROR_UNRECOGNIZED; 2599 } 2600 2601 /* DPB logic: 2602 if (width * height <= FS / 4) DPB = 16; 2603 else if (width * height <= FS / 2) DPB = 12; 2604 else if (width * height <= FS * 0.75) DPB = 8; 2605 else DPB = 6; 2606 */ 2607 2608 FS >>= 6; // convert pixels to blocks 2609 errors &= ~ERROR_NONE_SUPPORTED; 2610 maxBlocksPerSecond = Math.max((int)(FR * FS), maxBlocksPerSecond); 2611 maxBlocks = Math.max(FS, maxBlocks); 2612 maxBps = Math.max(BR * 1000, maxBps); 2613 } 2614 2615 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8)); 2616 applyMacroBlockLimits( 2617 maxLengthInBlocks, maxLengthInBlocks, 2618 maxBlocks, maxBlocksPerSecond, 2619 8 /* blockWidth */, 8 /* blockHeight */, 2620 1 /* widthAlignment */, 1 /* heightAlignment */); 2621 } else { 2622 Log.w(TAG, "Unsupported mime " + mime); 2623 // using minimal bitrate here. should be overriden by 2624 // info from media_codecs.xml 2625 maxBps = 64000; 2626 errors |= ERROR_UNSUPPORTED; 2627 } 2628 mBitrateRange = Range.create(1, maxBps); 2629 mParent.mError |= errors; 2630 } 2631 } 2632 2633 /** 2634 * A class that supports querying the encoding capabilities of a codec. 2635 */ 2636 public static final class EncoderCapabilities { 2637 /** 2638 * Returns the supported range of quality values. 2639 * 2640 * @hide 2641 */ getQualityRange()2642 public Range<Integer> getQualityRange() { 2643 return mQualityRange; 2644 } 2645 2646 /** 2647 * Returns the supported range of encoder complexity values. 2648 * <p> 2649 * Some codecs may support multiple complexity levels, where higher 2650 * complexity values use more encoder tools (e.g. perform more 2651 * intensive calculations) to improve the quality or the compression 2652 * ratio. Use a lower value to save power and/or time. 2653 */ getComplexityRange()2654 public Range<Integer> getComplexityRange() { 2655 return mComplexityRange; 2656 } 2657 2658 /** Constant quality mode */ 2659 public static final int BITRATE_MODE_CQ = 0; 2660 /** Variable bitrate mode */ 2661 public static final int BITRATE_MODE_VBR = 1; 2662 /** Constant bitrate mode */ 2663 public static final int BITRATE_MODE_CBR = 2; 2664 2665 private static final Feature[] bitrates = new Feature[] { 2666 new Feature("VBR", BITRATE_MODE_VBR, true), 2667 new Feature("CBR", BITRATE_MODE_CBR, false), 2668 new Feature("CQ", BITRATE_MODE_CQ, false) 2669 }; 2670 parseBitrateMode(String mode)2671 private static int parseBitrateMode(String mode) { 2672 for (Feature feat: bitrates) { 2673 if (feat.mName.equalsIgnoreCase(mode)) { 2674 return feat.mValue; 2675 } 2676 } 2677 return 0; 2678 } 2679 2680 /** 2681 * Query whether a bitrate mode is supported. 2682 */ isBitrateModeSupported(int mode)2683 public boolean isBitrateModeSupported(int mode) { 2684 for (Feature feat: bitrates) { 2685 if (mode == feat.mValue) { 2686 return (mBitControl & (1 << mode)) != 0; 2687 } 2688 } 2689 return false; 2690 } 2691 2692 private Range<Integer> mQualityRange; 2693 private Range<Integer> mComplexityRange; 2694 private CodecCapabilities mParent; 2695 2696 /* no public constructor */ EncoderCapabilities()2697 private EncoderCapabilities() { } 2698 2699 /** @hide */ create( MediaFormat info, CodecCapabilities parent)2700 public static EncoderCapabilities create( 2701 MediaFormat info, CodecCapabilities parent) { 2702 EncoderCapabilities caps = new EncoderCapabilities(); 2703 caps.init(info, parent); 2704 return caps; 2705 } 2706 2707 /** @hide */ init(MediaFormat info, CodecCapabilities parent)2708 public void init(MediaFormat info, CodecCapabilities parent) { 2709 // no support for complexity or quality yet 2710 mParent = parent; 2711 mComplexityRange = Range.create(0, 0); 2712 mQualityRange = Range.create(0, 0); 2713 mBitControl = (1 << BITRATE_MODE_VBR); 2714 2715 applyLevelLimits(); 2716 parseFromInfo(info); 2717 } 2718 applyLevelLimits()2719 private void applyLevelLimits() { 2720 String mime = mParent.getMimeType(); 2721 if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) { 2722 mComplexityRange = Range.create(0, 8); 2723 mBitControl = (1 << BITRATE_MODE_CQ); 2724 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB) 2725 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB) 2726 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW) 2727 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW) 2728 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) { 2729 mBitControl = (1 << BITRATE_MODE_CBR); 2730 } 2731 } 2732 2733 private int mBitControl; 2734 private Integer mDefaultComplexity; 2735 private Integer mDefaultQuality; 2736 private String mQualityScale; 2737 parseFromInfo(MediaFormat info)2738 private void parseFromInfo(MediaFormat info) { 2739 Map<String, Object> map = info.getMap(); 2740 2741 if (info.containsKey("complexity-range")) { 2742 mComplexityRange = Utils 2743 .parseIntRange(info.getString("complexity-range"), mComplexityRange); 2744 // TODO should we limit this to level limits? 2745 } 2746 if (info.containsKey("quality-range")) { 2747 mQualityRange = Utils 2748 .parseIntRange(info.getString("quality-range"), mQualityRange); 2749 } 2750 if (info.containsKey("feature-bitrate-control")) { 2751 for (String mode: info.getString("feature-bitrate-control").split(",")) { 2752 mBitControl |= parseBitrateMode(mode); 2753 } 2754 } 2755 2756 try { 2757 mDefaultComplexity = Integer.parseInt((String)map.get("complexity-default")); 2758 } catch (NumberFormatException e) { } 2759 2760 try { 2761 mDefaultQuality = Integer.parseInt((String)map.get("quality-default")); 2762 } catch (NumberFormatException e) { } 2763 2764 mQualityScale = (String)map.get("quality-scale"); 2765 } 2766 supports( Integer complexity, Integer quality, Integer profile)2767 private boolean supports( 2768 Integer complexity, Integer quality, Integer profile) { 2769 boolean ok = true; 2770 if (ok && complexity != null) { 2771 ok = mComplexityRange.contains(complexity); 2772 } 2773 if (ok && quality != null) { 2774 ok = mQualityRange.contains(quality); 2775 } 2776 if (ok && profile != null) { 2777 for (CodecProfileLevel pl: mParent.profileLevels) { 2778 if (pl.profile == profile) { 2779 profile = null; 2780 break; 2781 } 2782 } 2783 ok = profile == null; 2784 } 2785 return ok; 2786 } 2787 2788 /** @hide */ setDefaultFormat(MediaFormat format)2789 public void setDefaultFormat(MediaFormat format) { 2790 // don't list trivial quality/complexity as default for now 2791 if (!mQualityRange.getUpper().equals(mQualityRange.getLower()) 2792 && mDefaultQuality != null) { 2793 format.setInteger(MediaFormat.KEY_QUALITY, mDefaultQuality); 2794 } 2795 if (!mComplexityRange.getUpper().equals(mComplexityRange.getLower()) 2796 && mDefaultComplexity != null) { 2797 format.setInteger(MediaFormat.KEY_COMPLEXITY, mDefaultComplexity); 2798 } 2799 // bitrates are listed in order of preference 2800 for (Feature feat: bitrates) { 2801 if ((mBitControl & (1 << feat.mValue)) != 0) { 2802 format.setInteger(MediaFormat.KEY_BITRATE_MODE, feat.mValue); 2803 break; 2804 } 2805 } 2806 } 2807 2808 /** @hide */ supportsFormat(MediaFormat format)2809 public boolean supportsFormat(MediaFormat format) { 2810 final Map<String, Object> map = format.getMap(); 2811 final String mime = mParent.getMimeType(); 2812 2813 Integer mode = (Integer)map.get(MediaFormat.KEY_BITRATE_MODE); 2814 if (mode != null && !isBitrateModeSupported(mode)) { 2815 return false; 2816 } 2817 2818 Integer complexity = (Integer)map.get(MediaFormat.KEY_COMPLEXITY); 2819 if (MediaFormat.MIMETYPE_AUDIO_FLAC.equalsIgnoreCase(mime)) { 2820 Integer flacComplexity = 2821 (Integer)map.get(MediaFormat.KEY_FLAC_COMPRESSION_LEVEL); 2822 if (complexity == null) { 2823 complexity = flacComplexity; 2824 } else if (flacComplexity != null && !complexity.equals(flacComplexity)) { 2825 throw new IllegalArgumentException( 2826 "conflicting values for complexity and " + 2827 "flac-compression-level"); 2828 } 2829 } 2830 2831 // other audio parameters 2832 Integer profile = (Integer)map.get(MediaFormat.KEY_PROFILE); 2833 if (MediaFormat.MIMETYPE_AUDIO_AAC.equalsIgnoreCase(mime)) { 2834 Integer aacProfile = (Integer)map.get(MediaFormat.KEY_AAC_PROFILE); 2835 if (profile == null) { 2836 profile = aacProfile; 2837 } else if (aacProfile != null && !aacProfile.equals(profile)) { 2838 throw new IllegalArgumentException( 2839 "conflicting values for profile and aac-profile"); 2840 } 2841 } 2842 2843 Integer quality = (Integer)map.get(MediaFormat.KEY_QUALITY); 2844 2845 return supports(complexity, quality, profile); 2846 } 2847 }; 2848 2849 /** 2850 * Encapsulates the profiles available for a codec component. 2851 * <p>You can get a set of {@link MediaCodecInfo.CodecProfileLevel} objects for a given 2852 * {@link MediaCodecInfo} object from the 2853 * {@link MediaCodecInfo.CodecCapabilities#profileLevels} field. 2854 */ 2855 public static final class CodecProfileLevel { 2856 // from OMX_VIDEO_AVCPROFILETYPE 2857 public static final int AVCProfileBaseline = 0x01; 2858 public static final int AVCProfileMain = 0x02; 2859 public static final int AVCProfileExtended = 0x04; 2860 public static final int AVCProfileHigh = 0x08; 2861 public static final int AVCProfileHigh10 = 0x10; 2862 public static final int AVCProfileHigh422 = 0x20; 2863 public static final int AVCProfileHigh444 = 0x40; 2864 2865 // from OMX_VIDEO_AVCLEVELTYPE 2866 public static final int AVCLevel1 = 0x01; 2867 public static final int AVCLevel1b = 0x02; 2868 public static final int AVCLevel11 = 0x04; 2869 public static final int AVCLevel12 = 0x08; 2870 public static final int AVCLevel13 = 0x10; 2871 public static final int AVCLevel2 = 0x20; 2872 public static final int AVCLevel21 = 0x40; 2873 public static final int AVCLevel22 = 0x80; 2874 public static final int AVCLevel3 = 0x100; 2875 public static final int AVCLevel31 = 0x200; 2876 public static final int AVCLevel32 = 0x400; 2877 public static final int AVCLevel4 = 0x800; 2878 public static final int AVCLevel41 = 0x1000; 2879 public static final int AVCLevel42 = 0x2000; 2880 public static final int AVCLevel5 = 0x4000; 2881 public static final int AVCLevel51 = 0x8000; 2882 public static final int AVCLevel52 = 0x10000; 2883 2884 // from OMX_VIDEO_H263PROFILETYPE 2885 public static final int H263ProfileBaseline = 0x01; 2886 public static final int H263ProfileH320Coding = 0x02; 2887 public static final int H263ProfileBackwardCompatible = 0x04; 2888 public static final int H263ProfileISWV2 = 0x08; 2889 public static final int H263ProfileISWV3 = 0x10; 2890 public static final int H263ProfileHighCompression = 0x20; 2891 public static final int H263ProfileInternet = 0x40; 2892 public static final int H263ProfileInterlace = 0x80; 2893 public static final int H263ProfileHighLatency = 0x100; 2894 2895 // from OMX_VIDEO_H263LEVELTYPE 2896 public static final int H263Level10 = 0x01; 2897 public static final int H263Level20 = 0x02; 2898 public static final int H263Level30 = 0x04; 2899 public static final int H263Level40 = 0x08; 2900 public static final int H263Level45 = 0x10; 2901 public static final int H263Level50 = 0x20; 2902 public static final int H263Level60 = 0x40; 2903 public static final int H263Level70 = 0x80; 2904 2905 // from OMX_VIDEO_MPEG4PROFILETYPE 2906 public static final int MPEG4ProfileSimple = 0x01; 2907 public static final int MPEG4ProfileSimpleScalable = 0x02; 2908 public static final int MPEG4ProfileCore = 0x04; 2909 public static final int MPEG4ProfileMain = 0x08; 2910 public static final int MPEG4ProfileNbit = 0x10; 2911 public static final int MPEG4ProfileScalableTexture = 0x20; 2912 public static final int MPEG4ProfileSimpleFace = 0x40; 2913 public static final int MPEG4ProfileSimpleFBA = 0x80; 2914 public static final int MPEG4ProfileBasicAnimated = 0x100; 2915 public static final int MPEG4ProfileHybrid = 0x200; 2916 public static final int MPEG4ProfileAdvancedRealTime = 0x400; 2917 public static final int MPEG4ProfileCoreScalable = 0x800; 2918 public static final int MPEG4ProfileAdvancedCoding = 0x1000; 2919 public static final int MPEG4ProfileAdvancedCore = 0x2000; 2920 public static final int MPEG4ProfileAdvancedScalable = 0x4000; 2921 public static final int MPEG4ProfileAdvancedSimple = 0x8000; 2922 2923 // from OMX_VIDEO_MPEG4LEVELTYPE 2924 public static final int MPEG4Level0 = 0x01; 2925 public static final int MPEG4Level0b = 0x02; 2926 public static final int MPEG4Level1 = 0x04; 2927 public static final int MPEG4Level2 = 0x08; 2928 public static final int MPEG4Level3 = 0x10; 2929 public static final int MPEG4Level3b = 0x18; 2930 public static final int MPEG4Level4 = 0x20; 2931 public static final int MPEG4Level4a = 0x40; 2932 public static final int MPEG4Level5 = 0x80; 2933 public static final int MPEG4Level6 = 0x100; 2934 2935 // from OMX_VIDEO_MPEG2PROFILETYPE 2936 public static final int MPEG2ProfileSimple = 0x00; 2937 public static final int MPEG2ProfileMain = 0x01; 2938 public static final int MPEG2Profile422 = 0x02; 2939 public static final int MPEG2ProfileSNR = 0x03; 2940 public static final int MPEG2ProfileSpatial = 0x04; 2941 public static final int MPEG2ProfileHigh = 0x05; 2942 2943 // from OMX_VIDEO_MPEG2LEVELTYPE 2944 public static final int MPEG2LevelLL = 0x00; 2945 public static final int MPEG2LevelML = 0x01; 2946 public static final int MPEG2LevelH14 = 0x02; 2947 public static final int MPEG2LevelHL = 0x03; 2948 public static final int MPEG2LevelHP = 0x04; 2949 2950 // from OMX_AUDIO_AACPROFILETYPE 2951 public static final int AACObjectMain = 1; 2952 public static final int AACObjectLC = 2; 2953 public static final int AACObjectSSR = 3; 2954 public static final int AACObjectLTP = 4; 2955 public static final int AACObjectHE = 5; 2956 public static final int AACObjectScalable = 6; 2957 public static final int AACObjectERLC = 17; 2958 public static final int AACObjectERScalable = 20; 2959 public static final int AACObjectLD = 23; 2960 public static final int AACObjectHE_PS = 29; 2961 public static final int AACObjectELD = 39; 2962 2963 // from OMX_VIDEO_VP8LEVELTYPE 2964 public static final int VP8Level_Version0 = 0x01; 2965 public static final int VP8Level_Version1 = 0x02; 2966 public static final int VP8Level_Version2 = 0x04; 2967 public static final int VP8Level_Version3 = 0x08; 2968 2969 // from OMX_VIDEO_VP8PROFILETYPE 2970 public static final int VP8ProfileMain = 0x01; 2971 2972 // from OMX_VIDEO_VP9PROFILETYPE 2973 public static final int VP9Profile0 = 0x01; 2974 public static final int VP9Profile1 = 0x02; 2975 public static final int VP9Profile2 = 0x04; 2976 public static final int VP9Profile3 = 0x08; 2977 // HDR profiles also support passing HDR metadata 2978 public static final int VP9Profile2HDR = 0x1000; 2979 public static final int VP9Profile3HDR = 0x2000; 2980 2981 // from OMX_VIDEO_VP9LEVELTYPE 2982 public static final int VP9Level1 = 0x1; 2983 public static final int VP9Level11 = 0x2; 2984 public static final int VP9Level2 = 0x4; 2985 public static final int VP9Level21 = 0x8; 2986 public static final int VP9Level3 = 0x10; 2987 public static final int VP9Level31 = 0x20; 2988 public static final int VP9Level4 = 0x40; 2989 public static final int VP9Level41 = 0x80; 2990 public static final int VP9Level5 = 0x100; 2991 public static final int VP9Level51 = 0x200; 2992 public static final int VP9Level52 = 0x400; 2993 public static final int VP9Level6 = 0x800; 2994 public static final int VP9Level61 = 0x1000; 2995 public static final int VP9Level62 = 0x2000; 2996 2997 // from OMX_VIDEO_HEVCPROFILETYPE 2998 public static final int HEVCProfileMain = 0x01; 2999 public static final int HEVCProfileMain10 = 0x02; 3000 public static final int HEVCProfileMain10HDR10 = 0x1000; 3001 3002 // from OMX_VIDEO_HEVCLEVELTYPE 3003 public static final int HEVCMainTierLevel1 = 0x1; 3004 public static final int HEVCHighTierLevel1 = 0x2; 3005 public static final int HEVCMainTierLevel2 = 0x4; 3006 public static final int HEVCHighTierLevel2 = 0x8; 3007 public static final int HEVCMainTierLevel21 = 0x10; 3008 public static final int HEVCHighTierLevel21 = 0x20; 3009 public static final int HEVCMainTierLevel3 = 0x40; 3010 public static final int HEVCHighTierLevel3 = 0x80; 3011 public static final int HEVCMainTierLevel31 = 0x100; 3012 public static final int HEVCHighTierLevel31 = 0x200; 3013 public static final int HEVCMainTierLevel4 = 0x400; 3014 public static final int HEVCHighTierLevel4 = 0x800; 3015 public static final int HEVCMainTierLevel41 = 0x1000; 3016 public static final int HEVCHighTierLevel41 = 0x2000; 3017 public static final int HEVCMainTierLevel5 = 0x4000; 3018 public static final int HEVCHighTierLevel5 = 0x8000; 3019 public static final int HEVCMainTierLevel51 = 0x10000; 3020 public static final int HEVCHighTierLevel51 = 0x20000; 3021 public static final int HEVCMainTierLevel52 = 0x40000; 3022 public static final int HEVCHighTierLevel52 = 0x80000; 3023 public static final int HEVCMainTierLevel6 = 0x100000; 3024 public static final int HEVCHighTierLevel6 = 0x200000; 3025 public static final int HEVCMainTierLevel61 = 0x400000; 3026 public static final int HEVCHighTierLevel61 = 0x800000; 3027 public static final int HEVCMainTierLevel62 = 0x1000000; 3028 public static final int HEVCHighTierLevel62 = 0x2000000; 3029 3030 private static final int HEVCHighTierLevels = 3031 HEVCHighTierLevel1 | HEVCHighTierLevel2 | HEVCHighTierLevel21 | HEVCHighTierLevel3 | 3032 HEVCHighTierLevel31 | HEVCHighTierLevel4 | HEVCHighTierLevel41 | HEVCHighTierLevel5 | 3033 HEVCHighTierLevel51 | HEVCHighTierLevel52 | HEVCHighTierLevel6 | HEVCHighTierLevel61 | 3034 HEVCHighTierLevel62; 3035 3036 // from OMX_VIDEO_DOLBYVISIONPROFILETYPE 3037 public static final int DolbyVisionProfileDvavPer = 0x1; 3038 public static final int DolbyVisionProfileDvavPen = 0x2; 3039 public static final int DolbyVisionProfileDvheDer = 0x4; 3040 public static final int DolbyVisionProfileDvheDen = 0x8; 3041 public static final int DolbyVisionProfileDvheDtr = 0x10; 3042 public static final int DolbyVisionProfileDvheStn = 0x20; 3043 public static final int DolbyVisionProfileDvheDth = 0x40; 3044 public static final int DolbyVisionProfileDvheDtb = 0x80; 3045 3046 // from OMX_VIDEO_DOLBYVISIONLEVELTYPE 3047 public static final int DolbyVisionLevelHd24 = 0x1; 3048 public static final int DolbyVisionLevelHd30 = 0x2; 3049 public static final int DolbyVisionLevelFhd24 = 0x4; 3050 public static final int DolbyVisionLevelFhd30 = 0x8; 3051 public static final int DolbyVisionLevelFhd60 = 0x10; 3052 public static final int DolbyVisionLevelUhd24 = 0x20; 3053 public static final int DolbyVisionLevelUhd30 = 0x40; 3054 public static final int DolbyVisionLevelUhd48 = 0x80; 3055 public static final int DolbyVisionLevelUhd60 = 0x100; 3056 3057 /** 3058 * Defined in the OpenMAX IL specs, depending on the type of media 3059 * this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE, 3060 * OMX_VIDEO_MPEG4PROFILETYPE, OMX_VIDEO_VP8PROFILETYPE or OMX_VIDEO_VP9PROFILETYPE. 3061 */ 3062 public int profile; 3063 3064 /** 3065 * Defined in the OpenMAX IL specs, depending on the type of media 3066 * this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE 3067 * OMX_VIDEO_MPEG4LEVELTYPE, OMX_VIDEO_VP8LEVELTYPE or OMX_VIDEO_VP9LEVELTYPE. 3068 * 3069 * Note that VP9 decoder on platforms before {@link android.os.Build.VERSION_CODES#N} may 3070 * not advertise a profile level support. For those VP9 decoders, please use 3071 * {@link VideoCapabilities} to determine the codec capabilities. 3072 */ 3073 public int level; 3074 }; 3075 3076 /** 3077 * Enumerates the capabilities of the codec component. Since a single 3078 * component can support data of a variety of types, the type has to be 3079 * specified to yield a meaningful result. 3080 * @param type The MIME type to query 3081 */ getCapabilitiesForType( String type)3082 public final CodecCapabilities getCapabilitiesForType( 3083 String type) { 3084 CodecCapabilities caps = mCaps.get(type); 3085 if (caps == null) { 3086 throw new IllegalArgumentException("codec does not support type"); 3087 } 3088 // clone writable object 3089 return caps.dup(); 3090 } 3091 3092 /** @hide */ makeRegular()3093 public MediaCodecInfo makeRegular() { 3094 ArrayList<CodecCapabilities> caps = new ArrayList<CodecCapabilities>(); 3095 for (CodecCapabilities c: mCaps.values()) { 3096 if (c.isRegular()) { 3097 caps.add(c); 3098 } 3099 } 3100 if (caps.size() == 0) { 3101 return null; 3102 } else if (caps.size() == mCaps.size()) { 3103 return this; 3104 } 3105 3106 return new MediaCodecInfo( 3107 mName, mIsEncoder, 3108 caps.toArray(new CodecCapabilities[caps.size()])); 3109 } 3110 } 3111