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 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 */ 79 public final String getName() { 80 return mName; 81 } 82 83 /** 84 * Query if the codec is an encoder. 85 */ 86 public final boolean isEncoder() { 87 return mIsEncoder; 88 } 89 90 /** 91 * Query the media types supported by the codec. 92 */ 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 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; 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 { 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 * Query codec feature capabilities. 464 * <p> 465 * These features are supported to be used by the codec. These 466 * include optional features that can be turned on, as well as 467 * features that are always on. 468 */ 469 public final boolean isFeatureSupported(String name) { 470 return checkFeature(name, mFlagsSupported); 471 } 472 473 /** 474 * Query codec feature requirements. 475 * <p> 476 * These features are required to be used by the codec, and as such, 477 * they are always turned on. 478 */ 479 public final boolean isFeatureRequired(String name) { 480 return checkFeature(name, mFlagsRequired); 481 } 482 483 private static final Feature[] decoderFeatures = { 484 new Feature(FEATURE_AdaptivePlayback, (1 << 0), true), 485 new Feature(FEATURE_SecurePlayback, (1 << 1), false), 486 new Feature(FEATURE_TunneledPlayback, (1 << 2), false), 487 }; 488 489 /** @hide */ 490 public String[] validFeatures() { 491 Feature[] features = getValidFeatures(); 492 String[] res = new String[features.length]; 493 for (int i = 0; i < res.length; i++) { 494 res[i] = features[i].mName; 495 } 496 return res; 497 } 498 499 private Feature[] getValidFeatures() { 500 if (!isEncoder()) { 501 return decoderFeatures; 502 } 503 return new Feature[] {}; 504 } 505 506 private boolean checkFeature(String name, int flags) { 507 for (Feature feat: getValidFeatures()) { 508 if (feat.mName.equals(name)) { 509 return (flags & feat.mValue) != 0; 510 } 511 } 512 return false; 513 } 514 515 /** @hide */ 516 public boolean isRegular() { 517 // regular codecs only require default features 518 for (Feature feat: getValidFeatures()) { 519 if (!feat.mDefault && isFeatureRequired(feat.mName)) { 520 return false; 521 } 522 } 523 return true; 524 } 525 526 /** 527 * Query whether codec supports a given {@link MediaFormat}. 528 * 529 * <p class=note> 530 * <strong>Note:</strong> On {@link android.os.Build.VERSION_CODES#LOLLIPOP}, 531 * {@code format} must not contain a {@linkplain MediaFormat#KEY_FRAME_RATE 532 * frame rate}. Use 533 * <code class=prettyprint>format.setString(MediaFormat.KEY_FRAME_RATE, null)</code> 534 * to clear any existing frame rate setting in the format. 535 * 536 * @param format media format with optional feature directives. 537 * @throws IllegalArgumentException if format is not a valid media format. 538 * @return whether the codec capabilities support the given format 539 * and feature requests. 540 */ 541 public final boolean isFormatSupported(MediaFormat format) { 542 final Map<String, Object> map = format.getMap(); 543 final String mime = (String)map.get(MediaFormat.KEY_MIME); 544 545 // mime must match if present 546 if (mime != null && !mMime.equalsIgnoreCase(mime)) { 547 return false; 548 } 549 550 // check feature support 551 for (Feature feat: getValidFeatures()) { 552 Integer yesNo = (Integer)map.get(MediaFormat.KEY_FEATURE_ + feat.mName); 553 if (yesNo == null) { 554 continue; 555 } 556 if ((yesNo == 1 && !isFeatureSupported(feat.mName)) || 557 (yesNo == 0 && isFeatureRequired(feat.mName))) { 558 return false; 559 } 560 } 561 if (mAudioCaps != null && !mAudioCaps.supportsFormat(format)) { 562 return false; 563 } 564 if (mVideoCaps != null && !mVideoCaps.supportsFormat(format)) { 565 return false; 566 } 567 if (mEncoderCaps != null && !mEncoderCaps.supportsFormat(format)) { 568 return false; 569 } 570 return true; 571 } 572 573 // errors while reading profile levels - accessed from sister capabilities 574 int mError; 575 576 private static final String TAG = "CodecCapabilities"; 577 578 // NEW-STYLE CAPABILITIES 579 private AudioCapabilities mAudioCaps; 580 private VideoCapabilities mVideoCaps; 581 private EncoderCapabilities mEncoderCaps; 582 private MediaFormat mDefaultFormat; 583 584 /** 585 * Returns a MediaFormat object with default values for configurations that have 586 * defaults. 587 */ 588 public MediaFormat getDefaultFormat() { 589 return mDefaultFormat; 590 } 591 592 /** 593 * Returns the mime type for which this codec-capability object was created. 594 */ 595 public String getMimeType() { 596 return mMime; 597 } 598 599 /** 600 * Returns the max number of the supported concurrent codec instances. 601 * <p> 602 * This is a hint for an upper bound. Applications should not expect to successfully 603 * operate more instances than the returned value, but the actual number of 604 * concurrently operable instances may be less as it depends on the available 605 * resources at time of use. 606 */ 607 public int getMaxSupportedInstances() { 608 return mMaxSupportedInstances; 609 } 610 611 private boolean isAudio() { 612 return mAudioCaps != null; 613 } 614 615 /** 616 * Returns the audio capabilities or {@code null} if this is not an audio codec. 617 */ 618 public AudioCapabilities getAudioCapabilities() { 619 return mAudioCaps; 620 } 621 622 private boolean isEncoder() { 623 return mEncoderCaps != null; 624 } 625 626 /** 627 * Returns the encoding capabilities or {@code null} if this is not an encoder. 628 */ 629 public EncoderCapabilities getEncoderCapabilities() { 630 return mEncoderCaps; 631 } 632 633 private boolean isVideo() { 634 return mVideoCaps != null; 635 } 636 637 /** 638 * Returns the video capabilities or {@code null} if this is not a video codec. 639 */ 640 public VideoCapabilities getVideoCapabilities() { 641 return mVideoCaps; 642 } 643 644 /** @hide */ 645 public CodecCapabilities dup() { 646 return new CodecCapabilities( 647 // clone writable arrays 648 Arrays.copyOf(profileLevels, profileLevels.length), 649 Arrays.copyOf(colorFormats, colorFormats.length), 650 isEncoder(), 651 mFlagsVerified, 652 mDefaultFormat, 653 mCapabilitiesInfo); 654 } 655 656 /** 657 * Retrieve the codec capabilities for a certain {@code mime type}, {@code 658 * profile} and {@code level}. If the type, or profile-level combination 659 * is not understood by the framework, it returns null. 660 */ 661 public static CodecCapabilities createFromProfileLevel( 662 String mime, int profile, int level) { 663 CodecProfileLevel pl = new CodecProfileLevel(); 664 pl.profile = profile; 665 pl.level = level; 666 MediaFormat defaultFormat = new MediaFormat(); 667 defaultFormat.setString(MediaFormat.KEY_MIME, mime); 668 669 CodecCapabilities ret = new CodecCapabilities( 670 new CodecProfileLevel[] { pl }, new int[0], true /* encoder */, 671 0 /* flags */, defaultFormat, new MediaFormat() /* info */); 672 if (ret.mError != 0) { 673 return null; 674 } 675 return ret; 676 } 677 678 /* package private */ CodecCapabilities( 679 CodecProfileLevel[] profLevs, int[] colFmts, 680 boolean encoder, int flags, 681 Map<String, Object>defaultFormatMap, 682 Map<String, Object>capabilitiesMap) { 683 this(profLevs, colFmts, encoder, flags, 684 new MediaFormat(defaultFormatMap), 685 new MediaFormat(capabilitiesMap)); 686 } 687 688 private MediaFormat mCapabilitiesInfo; 689 690 /* package private */ CodecCapabilities( 691 CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags, 692 MediaFormat defaultFormat, MediaFormat info) { 693 final Map<String, Object> map = info.getMap(); 694 profileLevels = profLevs; 695 colorFormats = colFmts; 696 mFlagsVerified = flags; 697 mDefaultFormat = defaultFormat; 698 mCapabilitiesInfo = info; 699 mMime = mDefaultFormat.getString(MediaFormat.KEY_MIME); 700 701 if (mMime.toLowerCase().startsWith("audio/")) { 702 mAudioCaps = AudioCapabilities.create(info, this); 703 mAudioCaps.setDefaultFormat(mDefaultFormat); 704 } else if (mMime.toLowerCase().startsWith("video/")) { 705 mVideoCaps = VideoCapabilities.create(info, this); 706 } 707 if (encoder) { 708 mEncoderCaps = EncoderCapabilities.create(info, this); 709 mEncoderCaps.setDefaultFormat(mDefaultFormat); 710 } 711 712 final Map<String, Object> global = MediaCodecList.getGlobalSettings(); 713 mMaxSupportedInstances = Utils.parseIntSafely( 714 global.get("max-concurrent-instances"), DEFAULT_MAX_SUPPORTED_INSTANCES); 715 716 int maxInstances = Utils.parseIntSafely( 717 map.get("max-concurrent-instances"), mMaxSupportedInstances); 718 mMaxSupportedInstances = 719 Range.create(1, MAX_SUPPORTED_INSTANCES_LIMIT).clamp(maxInstances); 720 721 for (Feature feat: getValidFeatures()) { 722 String key = MediaFormat.KEY_FEATURE_ + feat.mName; 723 Integer yesNo = (Integer)map.get(key); 724 if (yesNo == null) { 725 continue; 726 } 727 if (yesNo > 0) { 728 mFlagsRequired |= feat.mValue; 729 } 730 mFlagsSupported |= feat.mValue; 731 mDefaultFormat.setInteger(key, 1); 732 // TODO restrict features by mFlagsVerified once all codecs reliably verify them 733 } 734 } 735 } 736 737 /** 738 * A class that supports querying the audio capabilities of a codec. 739 */ 740 public static final class AudioCapabilities { 741 private static final String TAG = "AudioCapabilities"; 742 private CodecCapabilities mParent; 743 private Range<Integer> mBitrateRange; 744 745 private int[] mSampleRates; 746 private Range<Integer>[] mSampleRateRanges; 747 private int mMaxInputChannelCount; 748 749 private static final int MAX_INPUT_CHANNEL_COUNT = 30; 750 751 /** 752 * Returns the range of supported bitrates in bits/second. 753 */ 754 public Range<Integer> getBitrateRange() { 755 return mBitrateRange; 756 } 757 758 /** 759 * Returns the array of supported sample rates if the codec 760 * supports only discrete values. Otherwise, it returns 761 * {@code null}. The array is sorted in ascending order. 762 */ 763 public int[] getSupportedSampleRates() { 764 return Arrays.copyOf(mSampleRates, mSampleRates.length); 765 } 766 767 /** 768 * Returns the array of supported sample rate ranges. The 769 * array is sorted in ascending order, and the ranges are 770 * distinct. 771 */ 772 public Range<Integer>[] getSupportedSampleRateRanges() { 773 return Arrays.copyOf(mSampleRateRanges, mSampleRateRanges.length); 774 } 775 776 /** 777 * Returns the maximum number of input channels supported. The codec 778 * supports any number of channels between 1 and this maximum value. 779 */ 780 public int getMaxInputChannelCount() { 781 return mMaxInputChannelCount; 782 } 783 784 /* no public constructor */ 785 private AudioCapabilities() { } 786 787 /** @hide */ 788 public static AudioCapabilities create( 789 MediaFormat info, CodecCapabilities parent) { 790 AudioCapabilities caps = new AudioCapabilities(); 791 caps.init(info, parent); 792 return caps; 793 } 794 795 /** @hide */ 796 public void init(MediaFormat info, CodecCapabilities parent) { 797 mParent = parent; 798 initWithPlatformLimits(); 799 applyLevelLimits(); 800 parseFromInfo(info); 801 } 802 803 private void initWithPlatformLimits() { 804 mBitrateRange = Range.create(0, Integer.MAX_VALUE); 805 mMaxInputChannelCount = MAX_INPUT_CHANNEL_COUNT; 806 // mBitrateRange = Range.create(1, 320000); 807 mSampleRateRanges = new Range[] { Range.create(8000, 96000) }; 808 mSampleRates = null; 809 } 810 811 private boolean supports(Integer sampleRate, Integer inputChannels) { 812 // channels and sample rates are checked orthogonally 813 if (inputChannels != null && 814 (inputChannels < 1 || inputChannels > mMaxInputChannelCount)) { 815 return false; 816 } 817 if (sampleRate != null) { 818 int ix = Utils.binarySearchDistinctRanges( 819 mSampleRateRanges, sampleRate); 820 if (ix < 0) { 821 return false; 822 } 823 } 824 return true; 825 } 826 827 /** 828 * Query whether the sample rate is supported by the codec. 829 */ 830 public boolean isSampleRateSupported(int sampleRate) { 831 return supports(sampleRate, null); 832 } 833 834 /** modifies rates */ 835 private void limitSampleRates(int[] rates) { 836 Arrays.sort(rates); 837 ArrayList<Range<Integer>> ranges = new ArrayList<Range<Integer>>(); 838 for (int rate: rates) { 839 if (supports(rate, null /* channels */)) { 840 ranges.add(Range.create(rate, rate)); 841 } 842 } 843 mSampleRateRanges = ranges.toArray(new Range[ranges.size()]); 844 createDiscreteSampleRates(); 845 } 846 847 private void createDiscreteSampleRates() { 848 mSampleRates = new int[mSampleRateRanges.length]; 849 for (int i = 0; i < mSampleRateRanges.length; i++) { 850 mSampleRates[i] = mSampleRateRanges[i].getLower(); 851 } 852 } 853 854 /** modifies rateRanges */ 855 private void limitSampleRates(Range<Integer>[] rateRanges) { 856 sortDistinctRanges(rateRanges); 857 mSampleRateRanges = intersectSortedDistinctRanges(mSampleRateRanges, rateRanges); 858 859 // check if all values are discrete 860 for (Range<Integer> range: mSampleRateRanges) { 861 if (!range.getLower().equals(range.getUpper())) { 862 mSampleRates = null; 863 return; 864 } 865 } 866 createDiscreteSampleRates(); 867 } 868 869 private void applyLevelLimits() { 870 int[] sampleRates = null; 871 Range<Integer> sampleRateRange = null, bitRates = null; 872 int maxChannels = 0; 873 String mime = mParent.getMimeType(); 874 875 if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MPEG)) { 876 sampleRates = new int[] { 877 8000, 11025, 12000, 878 16000, 22050, 24000, 879 32000, 44100, 48000 }; 880 bitRates = Range.create(8000, 320000); 881 maxChannels = 2; 882 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)) { 883 sampleRates = new int[] { 8000 }; 884 bitRates = Range.create(4750, 12200); 885 maxChannels = 1; 886 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)) { 887 sampleRates = new int[] { 16000 }; 888 bitRates = Range.create(6600, 23850); 889 maxChannels = 1; 890 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC)) { 891 sampleRates = new int[] { 892 7350, 8000, 893 11025, 12000, 16000, 894 22050, 24000, 32000, 895 44100, 48000, 64000, 896 88200, 96000 }; 897 bitRates = Range.create(8000, 510000); 898 maxChannels = 48; 899 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_VORBIS)) { 900 bitRates = Range.create(32000, 500000); 901 sampleRateRange = Range.create(8000, 192000); 902 maxChannels = 255; 903 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_OPUS)) { 904 bitRates = Range.create(6000, 510000); 905 sampleRates = new int[] { 8000, 12000, 16000, 24000, 48000 }; 906 maxChannels = 255; 907 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW)) { 908 sampleRateRange = Range.create(1, 96000); 909 bitRates = Range.create(1, 10000000); 910 maxChannels = 8; 911 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) { 912 sampleRateRange = Range.create(1, 655350); 913 // lossless codec, so bitrate is ignored 914 maxChannels = 255; 915 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW) 916 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)) { 917 sampleRates = new int[] { 8000 }; 918 bitRates = Range.create(64000, 64000); 919 // platform allows multiple channels for this format 920 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) { 921 sampleRates = new int[] { 8000 }; 922 bitRates = Range.create(13000, 13000); 923 maxChannels = 1; 924 } else { 925 Log.w(TAG, "Unsupported mime " + mime); 926 mParent.mError |= ERROR_UNSUPPORTED; 927 } 928 929 // restrict ranges 930 if (sampleRates != null) { 931 limitSampleRates(sampleRates); 932 } else if (sampleRateRange != null) { 933 limitSampleRates(new Range[] { sampleRateRange }); 934 } 935 applyLimits(maxChannels, bitRates); 936 } 937 938 private void applyLimits(int maxInputChannels, Range<Integer> bitRates) { 939 mMaxInputChannelCount = Range.create(1, mMaxInputChannelCount) 940 .clamp(maxInputChannels); 941 if (bitRates != null) { 942 mBitrateRange = mBitrateRange.intersect(bitRates); 943 } 944 } 945 946 private void parseFromInfo(MediaFormat info) { 947 int maxInputChannels = MAX_INPUT_CHANNEL_COUNT; 948 Range<Integer> bitRates = POSITIVE_INTEGERS; 949 950 if (info.containsKey("sample-rate-ranges")) { 951 String[] rateStrings = info.getString("sample-rate-ranges").split(","); 952 Range<Integer>[] rateRanges = new Range[rateStrings.length]; 953 for (int i = 0; i < rateStrings.length; i++) { 954 rateRanges[i] = Utils.parseIntRange(rateStrings[i], null); 955 } 956 limitSampleRates(rateRanges); 957 } 958 if (info.containsKey("max-channel-count")) { 959 maxInputChannels = Utils.parseIntSafely( 960 info.getString("max-channel-count"), maxInputChannels); 961 } 962 if (info.containsKey("bitrate-range")) { 963 bitRates = bitRates.intersect( 964 Utils.parseIntRange(info.getString("bitrate-range"), bitRates)); 965 } 966 applyLimits(maxInputChannels, bitRates); 967 } 968 969 /** @hide */ 970 public void setDefaultFormat(MediaFormat format) { 971 // report settings that have only a single choice 972 if (mBitrateRange.getLower().equals(mBitrateRange.getUpper())) { 973 format.setInteger(MediaFormat.KEY_BIT_RATE, mBitrateRange.getLower()); 974 } 975 if (mMaxInputChannelCount == 1) { 976 // mono-only format 977 format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); 978 } 979 if (mSampleRates != null && mSampleRates.length == 1) { 980 format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRates[0]); 981 } 982 } 983 984 /** @hide */ 985 public boolean supportsFormat(MediaFormat format) { 986 Map<String, Object> map = format.getMap(); 987 Integer sampleRate = (Integer)map.get(MediaFormat.KEY_SAMPLE_RATE); 988 Integer channels = (Integer)map.get(MediaFormat.KEY_CHANNEL_COUNT); 989 if (!supports(sampleRate, channels)) { 990 return false; 991 } 992 993 // nothing to do for: 994 // KEY_CHANNEL_MASK: codecs don't get this 995 // KEY_IS_ADTS: required feature for all AAC decoders 996 return true; 997 } 998 } 999 1000 /** 1001 * A class that supports querying the video capabilities of a codec. 1002 */ 1003 public static final class VideoCapabilities { 1004 private static final String TAG = "VideoCapabilities"; 1005 private CodecCapabilities mParent; 1006 private Range<Integer> mBitrateRange; 1007 1008 private Range<Integer> mHeightRange; 1009 private Range<Integer> mWidthRange; 1010 private Range<Integer> mBlockCountRange; 1011 private Range<Integer> mHorizontalBlockRange; 1012 private Range<Integer> mVerticalBlockRange; 1013 private Range<Rational> mAspectRatioRange; 1014 private Range<Rational> mBlockAspectRatioRange; 1015 private Range<Long> mBlocksPerSecondRange; 1016 private Map<Size, Range<Long>> mMeasuredFrameRates; 1017 private Range<Integer> mFrameRateRange; 1018 1019 private int mBlockWidth; 1020 private int mBlockHeight; 1021 private int mWidthAlignment; 1022 private int mHeightAlignment; 1023 private int mSmallerDimensionUpperLimit; 1024 1025 /** 1026 * Returns the range of supported bitrates in bits/second. 1027 */ 1028 public Range<Integer> getBitrateRange() { 1029 return mBitrateRange; 1030 } 1031 1032 /** 1033 * Returns the range of supported video widths. 1034 */ 1035 public Range<Integer> getSupportedWidths() { 1036 return mWidthRange; 1037 } 1038 1039 /** 1040 * Returns the range of supported video heights. 1041 */ 1042 public Range<Integer> getSupportedHeights() { 1043 return mHeightRange; 1044 } 1045 1046 /** 1047 * Returns the alignment requirement for video width (in pixels). 1048 * 1049 * This is a power-of-2 value that video width must be a 1050 * multiple of. 1051 */ 1052 public int getWidthAlignment() { 1053 return mWidthAlignment; 1054 } 1055 1056 /** 1057 * Returns the alignment requirement for video height (in pixels). 1058 * 1059 * This is a power-of-2 value that video height must be a 1060 * multiple of. 1061 */ 1062 public int getHeightAlignment() { 1063 return mHeightAlignment; 1064 } 1065 1066 /** 1067 * Return the upper limit on the smaller dimension of width or height. 1068 * <p></p> 1069 * Some codecs have a limit on the smaller dimension, whether it be 1070 * the width or the height. E.g. a codec may only be able to handle 1071 * up to 1920x1080 both in landscape and portrait mode (1080x1920). 1072 * In this case the maximum width and height are both 1920, but the 1073 * smaller dimension limit will be 1080. For other codecs, this is 1074 * {@code Math.min(getSupportedWidths().getUpper(), 1075 * getSupportedHeights().getUpper())}. 1076 * 1077 * @hide 1078 */ 1079 public int getSmallerDimensionUpperLimit() { 1080 return mSmallerDimensionUpperLimit; 1081 } 1082 1083 /** 1084 * Returns the range of supported frame rates. 1085 * <p> 1086 * This is not a performance indicator. Rather, it expresses the 1087 * limits specified in the coding standard, based on the complexities 1088 * of encoding material for later playback at a certain frame rate, 1089 * or the decoding of such material in non-realtime. 1090 */ 1091 public Range<Integer> getSupportedFrameRates() { 1092 return mFrameRateRange; 1093 } 1094 1095 /** 1096 * Returns the range of supported video widths for a video height. 1097 * @param height the height of the video 1098 */ 1099 public Range<Integer> getSupportedWidthsFor(int height) { 1100 try { 1101 Range<Integer> range = mWidthRange; 1102 if (!mHeightRange.contains(height) 1103 || (height % mHeightAlignment) != 0) { 1104 throw new IllegalArgumentException("unsupported height"); 1105 } 1106 final int heightInBlocks = Utils.divUp(height, mBlockHeight); 1107 1108 // constrain by block count and by block aspect ratio 1109 final int minWidthInBlocks = Math.max( 1110 Utils.divUp(mBlockCountRange.getLower(), heightInBlocks), 1111 (int)Math.ceil(mBlockAspectRatioRange.getLower().doubleValue() 1112 * heightInBlocks)); 1113 final int maxWidthInBlocks = Math.min( 1114 mBlockCountRange.getUpper() / heightInBlocks, 1115 (int)(mBlockAspectRatioRange.getUpper().doubleValue() 1116 * heightInBlocks)); 1117 range = range.intersect( 1118 (minWidthInBlocks - 1) * mBlockWidth + mWidthAlignment, 1119 maxWidthInBlocks * mBlockWidth); 1120 1121 // constrain by smaller dimension limit 1122 if (height > mSmallerDimensionUpperLimit) { 1123 range = range.intersect(1, mSmallerDimensionUpperLimit); 1124 } 1125 1126 // constrain by aspect ratio 1127 range = range.intersect( 1128 (int)Math.ceil(mAspectRatioRange.getLower().doubleValue() 1129 * height), 1130 (int)(mAspectRatioRange.getUpper().doubleValue() * height)); 1131 return range; 1132 } catch (IllegalArgumentException e) { 1133 // height is not supported because there are no suitable widths 1134 Log.v(TAG, "could not get supported widths for " + height); 1135 throw new IllegalArgumentException("unsupported height"); 1136 } 1137 } 1138 1139 /** 1140 * Returns the range of supported video heights for a video width 1141 * @param width the width of the video 1142 */ 1143 public Range<Integer> getSupportedHeightsFor(int width) { 1144 try { 1145 Range<Integer> range = mHeightRange; 1146 if (!mWidthRange.contains(width) 1147 || (width % mWidthAlignment) != 0) { 1148 throw new IllegalArgumentException("unsupported width"); 1149 } 1150 final int widthInBlocks = Utils.divUp(width, mBlockWidth); 1151 1152 // constrain by block count and by block aspect ratio 1153 final int minHeightInBlocks = Math.max( 1154 Utils.divUp(mBlockCountRange.getLower(), widthInBlocks), 1155 (int)Math.ceil(widthInBlocks / 1156 mBlockAspectRatioRange.getUpper().doubleValue())); 1157 final int maxHeightInBlocks = Math.min( 1158 mBlockCountRange.getUpper() / widthInBlocks, 1159 (int)(widthInBlocks / 1160 mBlockAspectRatioRange.getLower().doubleValue())); 1161 range = range.intersect( 1162 (minHeightInBlocks - 1) * mBlockHeight + mHeightAlignment, 1163 maxHeightInBlocks * mBlockHeight); 1164 1165 // constrain by smaller dimension limit 1166 if (width > mSmallerDimensionUpperLimit) { 1167 range = range.intersect(1, mSmallerDimensionUpperLimit); 1168 } 1169 1170 // constrain by aspect ratio 1171 range = range.intersect( 1172 (int)Math.ceil(width / 1173 mAspectRatioRange.getUpper().doubleValue()), 1174 (int)(width / mAspectRatioRange.getLower().doubleValue())); 1175 return range; 1176 } catch (IllegalArgumentException e) { 1177 // width is not supported because there are no suitable heights 1178 Log.v(TAG, "could not get supported heights for " + width); 1179 throw new IllegalArgumentException("unsupported width"); 1180 } 1181 } 1182 1183 /** 1184 * Returns the range of supported video frame rates for a video size. 1185 * <p> 1186 * This is not a performance indicator. Rather, it expresses the limits specified in 1187 * the coding standard, based on the complexities of encoding material of a given 1188 * size for later playback at a certain frame rate, or the decoding of such material 1189 * in non-realtime. 1190 1191 * @param width the width of the video 1192 * @param height the height of the video 1193 */ 1194 public Range<Double> getSupportedFrameRatesFor(int width, int height) { 1195 Range<Integer> range = mHeightRange; 1196 if (!supports(width, height, null)) { 1197 throw new IllegalArgumentException("unsupported size"); 1198 } 1199 final int blockCount = 1200 Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight); 1201 1202 return Range.create( 1203 Math.max(mBlocksPerSecondRange.getLower() / (double) blockCount, 1204 (double) mFrameRateRange.getLower()), 1205 Math.min(mBlocksPerSecondRange.getUpper() / (double) blockCount, 1206 (double) mFrameRateRange.getUpper())); 1207 } 1208 1209 private int getBlockCount(int width, int height) { 1210 return Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight); 1211 } 1212 1213 @NonNull 1214 private Size findClosestSize(int width, int height) { 1215 int targetBlockCount = getBlockCount(width, height); 1216 Size closestSize = null; 1217 int minDiff = Integer.MAX_VALUE; 1218 for (Size size : mMeasuredFrameRates.keySet()) { 1219 int diff = Math.abs(targetBlockCount - 1220 getBlockCount(size.getWidth(), size.getHeight())); 1221 if (diff < minDiff) { 1222 minDiff = diff; 1223 closestSize = size; 1224 } 1225 } 1226 return closestSize; 1227 } 1228 1229 private Range<Double> estimateFrameRatesFor(int width, int height) { 1230 Size size = findClosestSize(width, height); 1231 Range<Long> range = mMeasuredFrameRates.get(size); 1232 Double ratio = (double)(size.getWidth() * size.getHeight()) / (width * height); 1233 return Range.create(range.getLower() * ratio, range.getUpper() * ratio); 1234 } 1235 1236 /** 1237 * Returns the range of achievable video frame rates for a video size. 1238 * May return {@code null}, if the codec did not publish any measurement 1239 * data. 1240 * <p> 1241 * This is a performance estimate provided by the device manufacturer 1242 * based on full-speed decoding and encoding measurements in various configurations 1243 * of common video sizes supported by the codec. As such it should only be used to 1244 * compare individual codecs on the device. The value is not suitable for comparing 1245 * different devices or even different android releases for the same device. 1246 * <p> 1247 * The returned range corresponds to the fastest frame rates achieved in the tested 1248 * configurations. It is interpolated from the nearest frame size(s) tested. Codec 1249 * performance is severely impacted by other activity on the device, and can vary 1250 * significantly. 1251 * <p class=note> 1252 * Use this method in cases where only codec performance matters, e.g. to evaluate if 1253 * a codec has any chance of meeting a performance target. Codecs are listed 1254 * in {@link MediaCodecList} in the preferred order as defined by the device 1255 * manufacturer. As such, applications should use the first suitable codec in the 1256 * list to achieve the best balance between power use and performance. 1257 * 1258 * @param width the width of the video 1259 * @param height the height of the video 1260 * 1261 * @throws IllegalArgumentException if the video size is not supported. 1262 */ 1263 @Nullable 1264 public Range<Double> getAchievableFrameRatesFor(int width, int height) { 1265 if (!supports(width, height, null)) { 1266 throw new IllegalArgumentException("unsupported size"); 1267 } 1268 1269 if (mMeasuredFrameRates == null || mMeasuredFrameRates.size() <= 0) { 1270 Log.w(TAG, "Codec did not publish any measurement data."); 1271 return null; 1272 } 1273 1274 return estimateFrameRatesFor(width, height); 1275 } 1276 1277 /** 1278 * Returns whether a given video size ({@code width} and 1279 * {@code height}) and {@code frameRate} combination is supported. 1280 */ 1281 public boolean areSizeAndRateSupported( 1282 int width, int height, double frameRate) { 1283 return supports(width, height, frameRate); 1284 } 1285 1286 /** 1287 * Returns whether a given video size ({@code width} and 1288 * {@code height}) is supported. 1289 */ 1290 public boolean isSizeSupported(int width, int height) { 1291 return supports(width, height, null); 1292 } 1293 1294 private boolean supports( 1295 Integer width, Integer height, Number rate) { 1296 boolean ok = true; 1297 1298 if (ok && width != null) { 1299 ok = mWidthRange.contains(width) 1300 && (width % mWidthAlignment == 0); 1301 } 1302 if (ok && height != null) { 1303 ok = mHeightRange.contains(height) 1304 && (height % mHeightAlignment == 0); 1305 } 1306 if (ok && rate != null) { 1307 ok = mFrameRateRange.contains(Utils.intRangeFor(rate.doubleValue())); 1308 } 1309 if (ok && height != null && width != null) { 1310 ok = Math.min(height, width) <= mSmallerDimensionUpperLimit; 1311 1312 final int widthInBlocks = Utils.divUp(width, mBlockWidth); 1313 final int heightInBlocks = Utils.divUp(height, mBlockHeight); 1314 final int blockCount = widthInBlocks * heightInBlocks; 1315 ok = ok && mBlockCountRange.contains(blockCount) 1316 && mBlockAspectRatioRange.contains( 1317 new Rational(widthInBlocks, heightInBlocks)) 1318 && mAspectRatioRange.contains(new Rational(width, height)); 1319 if (ok && rate != null) { 1320 double blocksPerSec = blockCount * rate.doubleValue(); 1321 ok = mBlocksPerSecondRange.contains( 1322 Utils.longRangeFor(blocksPerSec)); 1323 } 1324 } 1325 return ok; 1326 } 1327 1328 /** 1329 * @hide 1330 * @throws java.lang.ClassCastException */ 1331 public boolean supportsFormat(MediaFormat format) { 1332 final Map<String, Object> map = format.getMap(); 1333 Integer width = (Integer)map.get(MediaFormat.KEY_WIDTH); 1334 Integer height = (Integer)map.get(MediaFormat.KEY_HEIGHT); 1335 Number rate = (Number)map.get(MediaFormat.KEY_FRAME_RATE); 1336 1337 // we ignore color-format for now as it is not reliably reported by codec 1338 1339 return supports(width, height, rate); 1340 } 1341 1342 /* no public constructor */ 1343 private VideoCapabilities() { } 1344 1345 /** @hide */ 1346 public static VideoCapabilities create( 1347 MediaFormat info, CodecCapabilities parent) { 1348 VideoCapabilities caps = new VideoCapabilities(); 1349 caps.init(info, parent); 1350 return caps; 1351 } 1352 1353 /** @hide */ 1354 public void init(MediaFormat info, CodecCapabilities parent) { 1355 mParent = parent; 1356 initWithPlatformLimits(); 1357 applyLevelLimits(); 1358 parseFromInfo(info); 1359 updateLimits(); 1360 } 1361 1362 /** @hide */ 1363 public Size getBlockSize() { 1364 return new Size(mBlockWidth, mBlockHeight); 1365 } 1366 1367 /** @hide */ 1368 public Range<Integer> getBlockCountRange() { 1369 return mBlockCountRange; 1370 } 1371 1372 /** @hide */ 1373 public Range<Long> getBlocksPerSecondRange() { 1374 return mBlocksPerSecondRange; 1375 } 1376 1377 /** @hide */ 1378 public Range<Rational> getAspectRatioRange(boolean blocks) { 1379 return blocks ? mBlockAspectRatioRange : mAspectRatioRange; 1380 } 1381 1382 private void initWithPlatformLimits() { 1383 mBitrateRange = BITRATE_RANGE; 1384 1385 mWidthRange = SIZE_RANGE; 1386 mHeightRange = SIZE_RANGE; 1387 mFrameRateRange = FRAME_RATE_RANGE; 1388 1389 mHorizontalBlockRange = SIZE_RANGE; 1390 mVerticalBlockRange = SIZE_RANGE; 1391 1392 // full positive ranges are supported as these get calculated 1393 mBlockCountRange = POSITIVE_INTEGERS; 1394 mBlocksPerSecondRange = POSITIVE_LONGS; 1395 1396 mBlockAspectRatioRange = POSITIVE_RATIONALS; 1397 mAspectRatioRange = POSITIVE_RATIONALS; 1398 1399 // YUV 4:2:0 requires 2:2 alignment 1400 mWidthAlignment = 2; 1401 mHeightAlignment = 2; 1402 mBlockWidth = 2; 1403 mBlockHeight = 2; 1404 mSmallerDimensionUpperLimit = SIZE_RANGE.getUpper(); 1405 } 1406 1407 private Map<Size, Range<Long>> getMeasuredFrameRates(Map<String, Object> map) { 1408 Map<Size, Range<Long>> ret = new HashMap<Size, Range<Long>>(); 1409 final String prefix = "measured-frame-rate-"; 1410 Set<String> keys = map.keySet(); 1411 for (String key : keys) { 1412 // looking for: measured-frame-rate-WIDTHxHEIGHT-range 1413 if (!key.startsWith(prefix)) { 1414 continue; 1415 } 1416 String subKey = key.substring(prefix.length()); 1417 String[] temp = key.split("-"); 1418 if (temp.length != 5) { 1419 continue; 1420 } 1421 String sizeStr = temp[3]; 1422 Size size = Utils.parseSize(sizeStr, null); 1423 if (size == null || size.getWidth() * size.getHeight() <= 0) { 1424 continue; 1425 } 1426 Range<Long> range = Utils.parseLongRange(map.get(key), null); 1427 if (range == null || range.getLower() < 0 || range.getUpper() < 0) { 1428 continue; 1429 } 1430 ret.put(size, range); 1431 } 1432 return ret; 1433 } 1434 1435 private void parseFromInfo(MediaFormat info) { 1436 final Map<String, Object> map = info.getMap(); 1437 Size blockSize = new Size(mBlockWidth, mBlockHeight); 1438 Size alignment = new Size(mWidthAlignment, mHeightAlignment); 1439 Range<Integer> counts = null, widths = null, heights = null; 1440 Range<Integer> frameRates = null, bitRates = null; 1441 Range<Long> blockRates = null; 1442 Range<Rational> ratios = null, blockRatios = null; 1443 1444 blockSize = Utils.parseSize(map.get("block-size"), blockSize); 1445 alignment = Utils.parseSize(map.get("alignment"), alignment); 1446 counts = Utils.parseIntRange(map.get("block-count-range"), null); 1447 blockRates = 1448 Utils.parseLongRange(map.get("blocks-per-second-range"), null); 1449 mMeasuredFrameRates = getMeasuredFrameRates(map); 1450 { 1451 Object o = map.get("size-range"); 1452 Pair<Size, Size> sizeRange = Utils.parseSizeRange(o); 1453 if (sizeRange != null) { 1454 try { 1455 widths = Range.create( 1456 sizeRange.first.getWidth(), 1457 sizeRange.second.getWidth()); 1458 heights = Range.create( 1459 sizeRange.first.getHeight(), 1460 sizeRange.second.getHeight()); 1461 } catch (IllegalArgumentException e) { 1462 Log.w(TAG, "could not parse size range '" + o + "'"); 1463 widths = null; 1464 heights = null; 1465 } 1466 } 1467 } 1468 // for now this just means using the smaller max size as 2nd 1469 // upper limit. 1470 // for now we are keeping the profile specific "width/height 1471 // in macroblocks" limits. 1472 if (map.containsKey("feature-can-swap-width-height")) { 1473 if (widths != null) { 1474 mSmallerDimensionUpperLimit = 1475 Math.min(widths.getUpper(), heights.getUpper()); 1476 widths = heights = widths.extend(heights); 1477 } else { 1478 Log.w(TAG, "feature can-swap-width-height is best used with size-range"); 1479 mSmallerDimensionUpperLimit = 1480 Math.min(mWidthRange.getUpper(), mHeightRange.getUpper()); 1481 mWidthRange = mHeightRange = mWidthRange.extend(mHeightRange); 1482 } 1483 } 1484 1485 ratios = Utils.parseRationalRange( 1486 map.get("block-aspect-ratio-range"), null); 1487 blockRatios = Utils.parseRationalRange( 1488 map.get("pixel-aspect-ratio-range"), null); 1489 frameRates = Utils.parseIntRange(map.get("frame-rate-range"), null); 1490 if (frameRates != null) { 1491 try { 1492 frameRates = frameRates.intersect(FRAME_RATE_RANGE); 1493 } catch (IllegalArgumentException e) { 1494 Log.w(TAG, "frame rate range (" + frameRates 1495 + ") is out of limits: " + FRAME_RATE_RANGE); 1496 frameRates = null; 1497 } 1498 } 1499 bitRates = Utils.parseIntRange(map.get("bitrate-range"), null); 1500 if (bitRates != null) { 1501 try { 1502 bitRates = bitRates.intersect(BITRATE_RANGE); 1503 } catch (IllegalArgumentException e) { 1504 Log.w(TAG, "bitrate range (" + bitRates 1505 + ") is out of limits: " + BITRATE_RANGE); 1506 bitRates = null; 1507 } 1508 } 1509 1510 checkPowerOfTwo( 1511 blockSize.getWidth(), "block-size width must be power of two"); 1512 checkPowerOfTwo( 1513 blockSize.getHeight(), "block-size height must be power of two"); 1514 1515 checkPowerOfTwo( 1516 alignment.getWidth(), "alignment width must be power of two"); 1517 checkPowerOfTwo( 1518 alignment.getHeight(), "alignment height must be power of two"); 1519 1520 // update block-size and alignment 1521 applyMacroBlockLimits( 1522 Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, 1523 Long.MAX_VALUE, blockSize.getWidth(), blockSize.getHeight(), 1524 alignment.getWidth(), alignment.getHeight()); 1525 1526 if ((mParent.mError & ERROR_UNSUPPORTED) != 0) { 1527 // codec supports profiles that we don't know. 1528 // Use supplied values clipped to platform limits 1529 if (widths != null) { 1530 mWidthRange = SIZE_RANGE.intersect(widths); 1531 } 1532 if (heights != null) { 1533 mHeightRange = SIZE_RANGE.intersect(heights); 1534 } 1535 if (counts != null) { 1536 mBlockCountRange = POSITIVE_INTEGERS.intersect( 1537 Utils.factorRange(counts, mBlockWidth * mBlockHeight 1538 / blockSize.getWidth() / blockSize.getHeight())); 1539 } 1540 if (blockRates != null) { 1541 mBlocksPerSecondRange = POSITIVE_LONGS.intersect( 1542 Utils.factorRange(blockRates, mBlockWidth * mBlockHeight 1543 / blockSize.getWidth() / blockSize.getHeight())); 1544 } 1545 if (blockRatios != null) { 1546 mBlockAspectRatioRange = POSITIVE_RATIONALS.intersect( 1547 Utils.scaleRange(blockRatios, 1548 mBlockHeight / blockSize.getHeight(), 1549 mBlockWidth / blockSize.getWidth())); 1550 } 1551 if (ratios != null) { 1552 mAspectRatioRange = POSITIVE_RATIONALS.intersect(ratios); 1553 } 1554 if (frameRates != null) { 1555 mFrameRateRange = FRAME_RATE_RANGE.intersect(frameRates); 1556 } 1557 if (bitRates != null) { 1558 mBitrateRange = BITRATE_RANGE.intersect(bitRates); 1559 } 1560 } else { 1561 // no unsupported profile/levels, so restrict values to known limits 1562 if (widths != null) { 1563 mWidthRange = mWidthRange.intersect(widths); 1564 } 1565 if (heights != null) { 1566 mHeightRange = mHeightRange.intersect(heights); 1567 } 1568 if (counts != null) { 1569 mBlockCountRange = mBlockCountRange.intersect( 1570 Utils.factorRange(counts, mBlockWidth * mBlockHeight 1571 / blockSize.getWidth() / blockSize.getHeight())); 1572 } 1573 if (blockRates != null) { 1574 mBlocksPerSecondRange = mBlocksPerSecondRange.intersect( 1575 Utils.factorRange(blockRates, mBlockWidth * mBlockHeight 1576 / blockSize.getWidth() / blockSize.getHeight())); 1577 } 1578 if (blockRatios != null) { 1579 mBlockAspectRatioRange = mBlockAspectRatioRange.intersect( 1580 Utils.scaleRange(blockRatios, 1581 mBlockHeight / blockSize.getHeight(), 1582 mBlockWidth / blockSize.getWidth())); 1583 } 1584 if (ratios != null) { 1585 mAspectRatioRange = mAspectRatioRange.intersect(ratios); 1586 } 1587 if (frameRates != null) { 1588 mFrameRateRange = mFrameRateRange.intersect(frameRates); 1589 } 1590 if (bitRates != null) { 1591 mBitrateRange = mBitrateRange.intersect(bitRates); 1592 } 1593 } 1594 updateLimits(); 1595 } 1596 1597 private void applyBlockLimits( 1598 int blockWidth, int blockHeight, 1599 Range<Integer> counts, Range<Long> rates, Range<Rational> ratios) { 1600 checkPowerOfTwo(blockWidth, "blockWidth must be a power of two"); 1601 checkPowerOfTwo(blockHeight, "blockHeight must be a power of two"); 1602 1603 final int newBlockWidth = Math.max(blockWidth, mBlockWidth); 1604 final int newBlockHeight = Math.max(blockHeight, mBlockHeight); 1605 1606 // factor will always be a power-of-2 1607 int factor = 1608 newBlockWidth * newBlockHeight / mBlockWidth / mBlockHeight; 1609 if (factor != 1) { 1610 mBlockCountRange = Utils.factorRange(mBlockCountRange, factor); 1611 mBlocksPerSecondRange = Utils.factorRange( 1612 mBlocksPerSecondRange, factor); 1613 mBlockAspectRatioRange = Utils.scaleRange( 1614 mBlockAspectRatioRange, 1615 newBlockHeight / mBlockHeight, 1616 newBlockWidth / mBlockWidth); 1617 mHorizontalBlockRange = Utils.factorRange( 1618 mHorizontalBlockRange, newBlockWidth / mBlockWidth); 1619 mVerticalBlockRange = Utils.factorRange( 1620 mVerticalBlockRange, newBlockHeight / mBlockHeight); 1621 } 1622 factor = newBlockWidth * newBlockHeight / blockWidth / blockHeight; 1623 if (factor != 1) { 1624 counts = Utils.factorRange(counts, factor); 1625 rates = Utils.factorRange(rates, factor); 1626 ratios = Utils.scaleRange( 1627 ratios, newBlockHeight / blockHeight, 1628 newBlockWidth / blockWidth); 1629 } 1630 mBlockCountRange = mBlockCountRange.intersect(counts); 1631 mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(rates); 1632 mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(ratios); 1633 mBlockWidth = newBlockWidth; 1634 mBlockHeight = newBlockHeight; 1635 } 1636 1637 private void applyAlignment(int widthAlignment, int heightAlignment) { 1638 checkPowerOfTwo(widthAlignment, "widthAlignment must be a power of two"); 1639 checkPowerOfTwo(heightAlignment, "heightAlignment must be a power of two"); 1640 1641 if (widthAlignment > mBlockWidth || heightAlignment > mBlockHeight) { 1642 // maintain assumption that 0 < alignment <= block-size 1643 applyBlockLimits( 1644 Math.max(widthAlignment, mBlockWidth), 1645 Math.max(heightAlignment, mBlockHeight), 1646 POSITIVE_INTEGERS, POSITIVE_LONGS, POSITIVE_RATIONALS); 1647 } 1648 1649 mWidthAlignment = Math.max(widthAlignment, mWidthAlignment); 1650 mHeightAlignment = Math.max(heightAlignment, mHeightAlignment); 1651 1652 mWidthRange = Utils.alignRange(mWidthRange, mWidthAlignment); 1653 mHeightRange = Utils.alignRange(mHeightRange, mHeightAlignment); 1654 } 1655 1656 private void updateLimits() { 1657 // pixels -> blocks <- counts 1658 mHorizontalBlockRange = mHorizontalBlockRange.intersect( 1659 Utils.factorRange(mWidthRange, mBlockWidth)); 1660 mHorizontalBlockRange = mHorizontalBlockRange.intersect( 1661 Range.create( 1662 mBlockCountRange.getLower() / mVerticalBlockRange.getUpper(), 1663 mBlockCountRange.getUpper() / mVerticalBlockRange.getLower())); 1664 mVerticalBlockRange = mVerticalBlockRange.intersect( 1665 Utils.factorRange(mHeightRange, mBlockHeight)); 1666 mVerticalBlockRange = mVerticalBlockRange.intersect( 1667 Range.create( 1668 mBlockCountRange.getLower() / mHorizontalBlockRange.getUpper(), 1669 mBlockCountRange.getUpper() / mHorizontalBlockRange.getLower())); 1670 mBlockCountRange = mBlockCountRange.intersect( 1671 Range.create( 1672 mHorizontalBlockRange.getLower() 1673 * mVerticalBlockRange.getLower(), 1674 mHorizontalBlockRange.getUpper() 1675 * mVerticalBlockRange.getUpper())); 1676 mBlockAspectRatioRange = mBlockAspectRatioRange.intersect( 1677 new Rational( 1678 mHorizontalBlockRange.getLower(), mVerticalBlockRange.getUpper()), 1679 new Rational( 1680 mHorizontalBlockRange.getUpper(), mVerticalBlockRange.getLower())); 1681 1682 // blocks -> pixels 1683 mWidthRange = mWidthRange.intersect( 1684 (mHorizontalBlockRange.getLower() - 1) * mBlockWidth + mWidthAlignment, 1685 mHorizontalBlockRange.getUpper() * mBlockWidth); 1686 mHeightRange = mHeightRange.intersect( 1687 (mVerticalBlockRange.getLower() - 1) * mBlockHeight + mHeightAlignment, 1688 mVerticalBlockRange.getUpper() * mBlockHeight); 1689 mAspectRatioRange = mAspectRatioRange.intersect( 1690 new Rational(mWidthRange.getLower(), mHeightRange.getUpper()), 1691 new Rational(mWidthRange.getUpper(), mHeightRange.getLower())); 1692 1693 mSmallerDimensionUpperLimit = Math.min( 1694 mSmallerDimensionUpperLimit, 1695 Math.min(mWidthRange.getUpper(), mHeightRange.getUpper())); 1696 1697 // blocks -> rate 1698 mBlocksPerSecondRange = mBlocksPerSecondRange.intersect( 1699 mBlockCountRange.getLower() * (long)mFrameRateRange.getLower(), 1700 mBlockCountRange.getUpper() * (long)mFrameRateRange.getUpper()); 1701 mFrameRateRange = mFrameRateRange.intersect( 1702 (int)(mBlocksPerSecondRange.getLower() 1703 / mBlockCountRange.getUpper()), 1704 (int)(mBlocksPerSecondRange.getUpper() 1705 / (double)mBlockCountRange.getLower())); 1706 } 1707 1708 private void applyMacroBlockLimits( 1709 int maxHorizontalBlocks, int maxVerticalBlocks, 1710 int maxBlocks, long maxBlocksPerSecond, 1711 int blockWidth, int blockHeight, 1712 int widthAlignment, int heightAlignment) { 1713 applyAlignment(widthAlignment, heightAlignment); 1714 applyBlockLimits( 1715 blockWidth, blockHeight, Range.create(1, maxBlocks), 1716 Range.create(1L, maxBlocksPerSecond), 1717 Range.create( 1718 new Rational(1, maxVerticalBlocks), 1719 new Rational(maxHorizontalBlocks, 1))); 1720 mHorizontalBlockRange = 1721 mHorizontalBlockRange.intersect( 1722 1, maxHorizontalBlocks / (mBlockWidth / blockWidth)); 1723 mVerticalBlockRange = 1724 mVerticalBlockRange.intersect( 1725 1, maxVerticalBlocks / (mBlockHeight / blockHeight)); 1726 } 1727 1728 private void applyLevelLimits() { 1729 int maxBlocksPerSecond = 0; 1730 int maxBlocks = 0; 1731 int maxBps = 0; 1732 int maxDPBBlocks = 0; 1733 1734 int errors = ERROR_NONE_SUPPORTED; 1735 CodecProfileLevel[] profileLevels = mParent.profileLevels; 1736 String mime = mParent.getMimeType(); 1737 1738 if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC)) { 1739 maxBlocks = 99; 1740 maxBlocksPerSecond = 1485; 1741 maxBps = 64000; 1742 maxDPBBlocks = 396; 1743 for (CodecProfileLevel profileLevel: profileLevels) { 1744 int MBPS = 0, FS = 0, BR = 0, DPB = 0; 1745 boolean supported = true; 1746 switch (profileLevel.level) { 1747 case CodecProfileLevel.AVCLevel1: 1748 MBPS = 1485; FS = 99; BR = 64; DPB = 396; break; 1749 case CodecProfileLevel.AVCLevel1b: 1750 MBPS = 1485; FS = 99; BR = 128; DPB = 396; break; 1751 case CodecProfileLevel.AVCLevel11: 1752 MBPS = 3000; FS = 396; BR = 192; DPB = 900; break; 1753 case CodecProfileLevel.AVCLevel12: 1754 MBPS = 6000; FS = 396; BR = 384; DPB = 2376; break; 1755 case CodecProfileLevel.AVCLevel13: 1756 MBPS = 11880; FS = 396; BR = 768; DPB = 2376; break; 1757 case CodecProfileLevel.AVCLevel2: 1758 MBPS = 11880; FS = 396; BR = 2000; DPB = 2376; break; 1759 case CodecProfileLevel.AVCLevel21: 1760 MBPS = 19800; FS = 792; BR = 4000; DPB = 4752; break; 1761 case CodecProfileLevel.AVCLevel22: 1762 MBPS = 20250; FS = 1620; BR = 4000; DPB = 8100; break; 1763 case CodecProfileLevel.AVCLevel3: 1764 MBPS = 40500; FS = 1620; BR = 10000; DPB = 8100; break; 1765 case CodecProfileLevel.AVCLevel31: 1766 MBPS = 108000; FS = 3600; BR = 14000; DPB = 18000; break; 1767 case CodecProfileLevel.AVCLevel32: 1768 MBPS = 216000; FS = 5120; BR = 20000; DPB = 20480; break; 1769 case CodecProfileLevel.AVCLevel4: 1770 MBPS = 245760; FS = 8192; BR = 20000; DPB = 32768; break; 1771 case CodecProfileLevel.AVCLevel41: 1772 MBPS = 245760; FS = 8192; BR = 50000; DPB = 32768; break; 1773 case CodecProfileLevel.AVCLevel42: 1774 MBPS = 522240; FS = 8704; BR = 50000; DPB = 34816; break; 1775 case CodecProfileLevel.AVCLevel5: 1776 MBPS = 589824; FS = 22080; BR = 135000; DPB = 110400; break; 1777 case CodecProfileLevel.AVCLevel51: 1778 MBPS = 983040; FS = 36864; BR = 240000; DPB = 184320; break; 1779 case CodecProfileLevel.AVCLevel52: 1780 MBPS = 2073600; FS = 36864; BR = 240000; DPB = 184320; break; 1781 default: 1782 Log.w(TAG, "Unrecognized level " 1783 + profileLevel.level + " for " + mime); 1784 errors |= ERROR_UNRECOGNIZED; 1785 } 1786 switch (profileLevel.profile) { 1787 case CodecProfileLevel.AVCProfileHigh: 1788 BR *= 1250; break; 1789 case CodecProfileLevel.AVCProfileHigh10: 1790 BR *= 3000; break; 1791 case CodecProfileLevel.AVCProfileExtended: 1792 case CodecProfileLevel.AVCProfileHigh422: 1793 case CodecProfileLevel.AVCProfileHigh444: 1794 Log.w(TAG, "Unsupported profile " 1795 + profileLevel.profile + " for " + mime); 1796 errors |= ERROR_UNSUPPORTED; 1797 supported = false; 1798 // fall through - treat as base profile 1799 case CodecProfileLevel.AVCProfileBaseline: 1800 case CodecProfileLevel.AVCProfileMain: 1801 BR *= 1000; break; 1802 default: 1803 Log.w(TAG, "Unrecognized profile " 1804 + profileLevel.profile + " for " + mime); 1805 errors |= ERROR_UNRECOGNIZED; 1806 BR *= 1000; 1807 } 1808 if (supported) { 1809 errors &= ~ERROR_NONE_SUPPORTED; 1810 } 1811 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); 1812 maxBlocks = Math.max(FS, maxBlocks); 1813 maxBps = Math.max(BR, maxBps); 1814 maxDPBBlocks = Math.max(maxDPBBlocks, DPB); 1815 } 1816 1817 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8)); 1818 applyMacroBlockLimits( 1819 maxLengthInBlocks, maxLengthInBlocks, 1820 maxBlocks, maxBlocksPerSecond, 1821 16 /* blockWidth */, 16 /* blockHeight */, 1822 1 /* widthAlignment */, 1 /* heightAlignment */); 1823 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG2)) { 1824 int maxWidth = 11, maxHeight = 9, maxRate = 15; 1825 maxBlocks = 99; 1826 maxBlocksPerSecond = 1485; 1827 maxBps = 64000; 1828 for (CodecProfileLevel profileLevel: profileLevels) { 1829 int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0; 1830 boolean supported = true; 1831 switch (profileLevel.profile) { 1832 case CodecProfileLevel.MPEG2ProfileSimple: 1833 switch (profileLevel.level) { 1834 case CodecProfileLevel.MPEG2LevelML: 1835 FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 15000; break; 1836 default: 1837 Log.w(TAG, "Unrecognized profile/level " 1838 + profileLevel.profile + "/" 1839 + profileLevel.level + " for " + mime); 1840 errors |= ERROR_UNRECOGNIZED; 1841 } 1842 break; 1843 case CodecProfileLevel.MPEG2ProfileMain: 1844 switch (profileLevel.level) { 1845 case CodecProfileLevel.MPEG2LevelLL: 1846 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 4000; break; 1847 case CodecProfileLevel.MPEG2LevelML: 1848 FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 15000; break; 1849 case CodecProfileLevel.MPEG2LevelH14: 1850 FR = 60; W = 90; H = 68; MBPS = 367200; FS = 6120; BR = 60000; break; 1851 case CodecProfileLevel.MPEG2LevelHL: 1852 FR = 60; W = 120; H = 68; MBPS = 489600; FS = 8160; BR = 80000; break; 1853 default: 1854 Log.w(TAG, "Unrecognized profile/level " 1855 + profileLevel.profile + "/" 1856 + profileLevel.level + " for " + mime); 1857 errors |= ERROR_UNRECOGNIZED; 1858 } 1859 break; 1860 case CodecProfileLevel.MPEG2Profile422: 1861 case CodecProfileLevel.MPEG2ProfileSNR: 1862 case CodecProfileLevel.MPEG2ProfileSpatial: 1863 case CodecProfileLevel.MPEG2ProfileHigh: 1864 Log.i(TAG, "Unsupported profile " 1865 + profileLevel.profile + " for " + mime); 1866 errors |= ERROR_UNSUPPORTED; 1867 supported = false; 1868 break; 1869 default: 1870 Log.w(TAG, "Unrecognized profile " 1871 + profileLevel.profile + " for " + mime); 1872 errors |= ERROR_UNRECOGNIZED; 1873 } 1874 if (supported) { 1875 errors &= ~ERROR_NONE_SUPPORTED; 1876 } 1877 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); 1878 maxBlocks = Math.max(FS, maxBlocks); 1879 maxBps = Math.max(BR * 1000, maxBps); 1880 maxWidth = Math.max(W, maxWidth); 1881 maxHeight = Math.max(H, maxHeight); 1882 maxRate = Math.max(FR, maxRate); 1883 } 1884 applyMacroBlockLimits(maxWidth, maxHeight, 1885 maxBlocks, maxBlocksPerSecond, 1886 16 /* blockWidth */, 16 /* blockHeight */, 1887 1 /* widthAlignment */, 1 /* heightAlignment */); 1888 mFrameRateRange = mFrameRateRange.intersect(12, maxRate); 1889 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) { 1890 int maxWidth = 11, maxHeight = 9, maxRate = 15; 1891 maxBlocks = 99; 1892 maxBlocksPerSecond = 1485; 1893 maxBps = 64000; 1894 for (CodecProfileLevel profileLevel: profileLevels) { 1895 int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0; 1896 boolean supported = true; 1897 switch (profileLevel.profile) { 1898 case CodecProfileLevel.MPEG4ProfileSimple: 1899 switch (profileLevel.level) { 1900 case CodecProfileLevel.MPEG4Level0: 1901 FR = 15; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 64; break; 1902 case CodecProfileLevel.MPEG4Level1: 1903 FR = 30; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 64; break; 1904 case CodecProfileLevel.MPEG4Level0b: 1905 FR = 30; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 128; break; 1906 case CodecProfileLevel.MPEG4Level2: 1907 FR = 30; W = 22; H = 18; MBPS = 5940; FS = 396; BR = 128; break; 1908 case CodecProfileLevel.MPEG4Level3: 1909 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384; break; 1910 case CodecProfileLevel.MPEG4Level4: 1911 case CodecProfileLevel.MPEG4Level4a: 1912 case CodecProfileLevel.MPEG4Level5: 1913 // While MPEG4 SP does not have level 4 or 5, some vendors 1914 // report it. Use the same limits as level 3, but mark as 1915 // unsupported. 1916 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384; 1917 supported = false; 1918 break; 1919 default: 1920 Log.w(TAG, "Unrecognized profile/level " 1921 + profileLevel.profile + "/" 1922 + profileLevel.level + " for " + mime); 1923 errors |= ERROR_UNRECOGNIZED; 1924 } 1925 break; 1926 case CodecProfileLevel.MPEG4ProfileAdvancedSimple: 1927 switch (profileLevel.level) { 1928 case CodecProfileLevel.MPEG4Level0: 1929 case CodecProfileLevel.MPEG4Level1: 1930 FR = 30; W = 11; H = 9; MBPS = 2970; FS = 99; BR = 128; break; 1931 case CodecProfileLevel.MPEG4Level2: 1932 FR = 30; W = 22; H = 18; MBPS = 5940; FS = 396; BR = 384; break; 1933 case CodecProfileLevel.MPEG4Level3: 1934 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 768; break; 1935 // case CodecProfileLevel.MPEG4Level3b: 1936 // TODO: MPEG4 level 3b is not defined in OMX 1937 // MBPS = 11880; FS = 396; BR = 1500; break; 1938 case CodecProfileLevel.MPEG4Level4: 1939 case CodecProfileLevel.MPEG4Level4a: 1940 // TODO: MPEG4 level 4a is not defined in spec 1941 FR = 30; W = 44; H = 36; MBPS = 23760; FS = 792; BR = 3000; break; 1942 case CodecProfileLevel.MPEG4Level5: 1943 FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 8000; break; 1944 default: 1945 Log.w(TAG, "Unrecognized profile/level " 1946 + profileLevel.profile + "/" 1947 + profileLevel.level + " for " + mime); 1948 errors |= ERROR_UNRECOGNIZED; 1949 } 1950 break; 1951 case CodecProfileLevel.MPEG4ProfileMain: // 2-4 1952 case CodecProfileLevel.MPEG4ProfileNbit: // 2 1953 case CodecProfileLevel.MPEG4ProfileAdvancedRealTime: // 1-4 1954 case CodecProfileLevel.MPEG4ProfileCoreScalable: // 1-3 1955 case CodecProfileLevel.MPEG4ProfileAdvancedCoding: // 1-4 1956 case CodecProfileLevel.MPEG4ProfileCore: // 1-2 1957 case CodecProfileLevel.MPEG4ProfileAdvancedCore: // 1-4 1958 case CodecProfileLevel.MPEG4ProfileSimpleScalable: // 0-2 1959 case CodecProfileLevel.MPEG4ProfileAdvancedScalable: // 1-3 1960 case CodecProfileLevel.MPEG4ProfileHybrid: // 1-2 1961 case CodecProfileLevel.MPEG4ProfileBasicAnimated: // 1-2 1962 case CodecProfileLevel.MPEG4ProfileScalableTexture: // 1 1963 case CodecProfileLevel.MPEG4ProfileSimpleFace: // 1-2 1964 case CodecProfileLevel.MPEG4ProfileSimpleFBA: // 1-2 1965 Log.i(TAG, "Unsupported profile " 1966 + profileLevel.profile + " for " + mime); 1967 errors |= ERROR_UNSUPPORTED; 1968 supported = false; 1969 break; 1970 default: 1971 Log.w(TAG, "Unrecognized profile " 1972 + profileLevel.profile + " for " + mime); 1973 errors |= ERROR_UNRECOGNIZED; 1974 } 1975 if (supported) { 1976 errors &= ~ERROR_NONE_SUPPORTED; 1977 } 1978 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); 1979 maxBlocks = Math.max(FS, maxBlocks); 1980 maxBps = Math.max(BR * 1000, maxBps); 1981 maxWidth = Math.max(W, maxWidth); 1982 maxHeight = Math.max(H, maxHeight); 1983 maxRate = Math.max(FR, maxRate); 1984 } 1985 applyMacroBlockLimits(maxWidth, maxHeight, 1986 maxBlocks, maxBlocksPerSecond, 1987 16 /* blockWidth */, 16 /* blockHeight */, 1988 1 /* widthAlignment */, 1 /* heightAlignment */); 1989 mFrameRateRange = mFrameRateRange.intersect(12, maxRate); 1990 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) { 1991 int maxWidth = 11, maxHeight = 9, maxRate = 15; 1992 maxBlocks = 99; 1993 maxBlocksPerSecond = 1485; 1994 maxBps = 64000; 1995 for (CodecProfileLevel profileLevel: profileLevels) { 1996 int MBPS = 0, BR = 0, FR = 0, W = 0, H = 0; 1997 switch (profileLevel.level) { 1998 case CodecProfileLevel.H263Level10: 1999 FR = 15; W = 11; H = 9; BR = 1; MBPS = W * H * FR; break; 2000 case CodecProfileLevel.H263Level20: 2001 // only supports CIF, 0..QCIF 2002 FR = 30; W = 22; H = 18; BR = 2; MBPS = W * H * FR; break; 2003 case CodecProfileLevel.H263Level30: 2004 // only supports CIF, 0..QCIF 2005 FR = 30; W = 22; H = 18; BR = 6; MBPS = W * H * FR; break; 2006 case CodecProfileLevel.H263Level40: 2007 // only supports CIF, 0..QCIF 2008 FR = 30; W = 22; H = 18; BR = 32; MBPS = W * H * FR; break; 2009 case CodecProfileLevel.H263Level45: 2010 // only implies level 10 support 2011 FR = 30; W = 11; H = 9; BR = 2; MBPS = W * H * FR; break; 2012 case CodecProfileLevel.H263Level50: 2013 // only supports 50fps for H > 15 2014 FR = 60; W = 22; H = 18; BR = 64; MBPS = W * H * 50; break; 2015 case CodecProfileLevel.H263Level60: 2016 // only supports 50fps for H > 15 2017 FR = 60; W = 45; H = 18; BR = 128; MBPS = W * H * 50; break; 2018 case CodecProfileLevel.H263Level70: 2019 // only supports 50fps for H > 30 2020 FR = 60; W = 45; H = 36; BR = 256; MBPS = W * H * 50; break; 2021 default: 2022 Log.w(TAG, "Unrecognized profile/level " + profileLevel.profile 2023 + "/" + profileLevel.level + " for " + mime); 2024 errors |= ERROR_UNRECOGNIZED; 2025 } 2026 switch (profileLevel.profile) { 2027 case CodecProfileLevel.H263ProfileBackwardCompatible: 2028 case CodecProfileLevel.H263ProfileBaseline: 2029 case CodecProfileLevel.H263ProfileH320Coding: 2030 case CodecProfileLevel.H263ProfileHighCompression: 2031 case CodecProfileLevel.H263ProfileHighLatency: 2032 case CodecProfileLevel.H263ProfileInterlace: 2033 case CodecProfileLevel.H263ProfileInternet: 2034 case CodecProfileLevel.H263ProfileISWV2: 2035 case CodecProfileLevel.H263ProfileISWV3: 2036 break; 2037 default: 2038 Log.w(TAG, "Unrecognized profile " 2039 + profileLevel.profile + " for " + mime); 2040 errors |= ERROR_UNRECOGNIZED; 2041 } 2042 errors &= ~ERROR_NONE_SUPPORTED; 2043 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); 2044 maxBlocks = Math.max(W * H, maxBlocks); 2045 maxBps = Math.max(BR * 64000, maxBps); 2046 maxWidth = Math.max(W, maxWidth); 2047 maxHeight = Math.max(H, maxHeight); 2048 maxRate = Math.max(FR, maxRate); 2049 } 2050 applyMacroBlockLimits(maxWidth, maxHeight, 2051 maxBlocks, maxBlocksPerSecond, 2052 16 /* blockWidth */, 16 /* blockHeight */, 2053 1 /* widthAlignment */, 1 /* heightAlignment */); 2054 mFrameRateRange = Range.create(1, maxRate); 2055 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8) || 2056 mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) { 2057 maxBlocks = maxBlocksPerSecond = Integer.MAX_VALUE; 2058 2059 // TODO: set to 100Mbps for now, need a number for VPX 2060 maxBps = 100000000; 2061 2062 // profile levels are not indicative for VPx, but verify 2063 // them nonetheless 2064 for (CodecProfileLevel profileLevel: profileLevels) { 2065 switch (profileLevel.level) { 2066 case CodecProfileLevel.VP8Level_Version0: 2067 case CodecProfileLevel.VP8Level_Version1: 2068 case CodecProfileLevel.VP8Level_Version2: 2069 case CodecProfileLevel.VP8Level_Version3: 2070 break; 2071 default: 2072 Log.w(TAG, "Unrecognized level " 2073 + profileLevel.level + " for " + mime); 2074 errors |= ERROR_UNRECOGNIZED; 2075 } 2076 switch (profileLevel.profile) { 2077 case CodecProfileLevel.VP8ProfileMain: 2078 break; 2079 default: 2080 Log.w(TAG, "Unrecognized profile " 2081 + profileLevel.profile + " for " + mime); 2082 errors |= ERROR_UNRECOGNIZED; 2083 } 2084 errors &= ~ERROR_NONE_SUPPORTED; 2085 } 2086 2087 final int blockSize = 2088 mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8) ? 16 : 8; 2089 applyMacroBlockLimits(Short.MAX_VALUE, Short.MAX_VALUE, 2090 maxBlocks, maxBlocksPerSecond, blockSize, blockSize, 2091 1 /* widthAlignment */, 1 /* heightAlignment */); 2092 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) { 2093 maxBlocks = 36864; 2094 maxBlocksPerSecond = maxBlocks * 15; 2095 maxBps = 128000; 2096 for (CodecProfileLevel profileLevel: profileLevels) { 2097 double FR = 0; 2098 int FS = 0; 2099 int BR = 0; 2100 switch (profileLevel.level) { 2101 case CodecProfileLevel.HEVCMainTierLevel1: 2102 case CodecProfileLevel.HEVCHighTierLevel1: 2103 FR = 15; FS = 36864; BR = 128; break; 2104 case CodecProfileLevel.HEVCMainTierLevel2: 2105 case CodecProfileLevel.HEVCHighTierLevel2: 2106 FR = 30; FS = 122880; BR = 1500; break; 2107 case CodecProfileLevel.HEVCMainTierLevel21: 2108 case CodecProfileLevel.HEVCHighTierLevel21: 2109 FR = 30; FS = 245760; BR = 3000; break; 2110 case CodecProfileLevel.HEVCMainTierLevel3: 2111 case CodecProfileLevel.HEVCHighTierLevel3: 2112 FR = 30; FS = 552960; BR = 6000; break; 2113 case CodecProfileLevel.HEVCMainTierLevel31: 2114 case CodecProfileLevel.HEVCHighTierLevel31: 2115 FR = 33.75; FS = 983040; BR = 10000; break; 2116 case CodecProfileLevel.HEVCMainTierLevel4: 2117 FR = 30; FS = 2228224; BR = 12000; break; 2118 case CodecProfileLevel.HEVCHighTierLevel4: 2119 FR = 30; FS = 2228224; BR = 30000; break; 2120 case CodecProfileLevel.HEVCMainTierLevel41: 2121 FR = 60; FS = 2228224; BR = 20000; break; 2122 case CodecProfileLevel.HEVCHighTierLevel41: 2123 FR = 60; FS = 2228224; BR = 50000; break; 2124 case CodecProfileLevel.HEVCMainTierLevel5: 2125 FR = 30; FS = 8912896; BR = 25000; break; 2126 case CodecProfileLevel.HEVCHighTierLevel5: 2127 FR = 30; FS = 8912896; BR = 100000; break; 2128 case CodecProfileLevel.HEVCMainTierLevel51: 2129 FR = 60; FS = 8912896; BR = 40000; break; 2130 case CodecProfileLevel.HEVCHighTierLevel51: 2131 FR = 60; FS = 8912896; BR = 160000; break; 2132 case CodecProfileLevel.HEVCMainTierLevel52: 2133 FR = 120; FS = 8912896; BR = 60000; break; 2134 case CodecProfileLevel.HEVCHighTierLevel52: 2135 FR = 120; FS = 8912896; BR = 240000; break; 2136 case CodecProfileLevel.HEVCMainTierLevel6: 2137 FR = 30; FS = 35651584; BR = 60000; break; 2138 case CodecProfileLevel.HEVCHighTierLevel6: 2139 FR = 30; FS = 35651584; BR = 240000; break; 2140 case CodecProfileLevel.HEVCMainTierLevel61: 2141 FR = 60; FS = 35651584; BR = 120000; break; 2142 case CodecProfileLevel.HEVCHighTierLevel61: 2143 FR = 60; FS = 35651584; BR = 480000; break; 2144 case CodecProfileLevel.HEVCMainTierLevel62: 2145 FR = 120; FS = 35651584; BR = 240000; break; 2146 case CodecProfileLevel.HEVCHighTierLevel62: 2147 FR = 120; FS = 35651584; BR = 800000; break; 2148 default: 2149 Log.w(TAG, "Unrecognized level " 2150 + profileLevel.level + " for " + mime); 2151 errors |= ERROR_UNRECOGNIZED; 2152 } 2153 switch (profileLevel.profile) { 2154 case CodecProfileLevel.HEVCProfileMain: 2155 case CodecProfileLevel.HEVCProfileMain10: 2156 break; 2157 default: 2158 Log.w(TAG, "Unrecognized profile " 2159 + profileLevel.profile + " for " + mime); 2160 errors |= ERROR_UNRECOGNIZED; 2161 } 2162 2163 /* DPB logic: 2164 if (width * height <= FS / 4) DPB = 16; 2165 else if (width * height <= FS / 2) DPB = 12; 2166 else if (width * height <= FS * 0.75) DPB = 8; 2167 else DPB = 6; 2168 */ 2169 2170 errors &= ~ERROR_NONE_SUPPORTED; 2171 maxBlocksPerSecond = Math.max((int)(FR * FS), maxBlocksPerSecond); 2172 maxBlocks = Math.max(FS, maxBlocks); 2173 maxBps = Math.max(BR * 1000, maxBps); 2174 } 2175 2176 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8)); 2177 // CTBs are at least 8x8 2178 maxBlocks = Utils.divUp(maxBlocks, 8 * 8); 2179 maxBlocksPerSecond = Utils.divUp(maxBlocksPerSecond, 8 * 8); 2180 maxLengthInBlocks = Utils.divUp(maxLengthInBlocks, 8); 2181 2182 applyMacroBlockLimits( 2183 maxLengthInBlocks, maxLengthInBlocks, 2184 maxBlocks, maxBlocksPerSecond, 2185 8 /* blockWidth */, 8 /* blockHeight */, 2186 1 /* widthAlignment */, 1 /* heightAlignment */); 2187 } else { 2188 Log.w(TAG, "Unsupported mime " + mime); 2189 // using minimal bitrate here. should be overriden by 2190 // info from media_codecs.xml 2191 maxBps = 64000; 2192 errors |= ERROR_UNSUPPORTED; 2193 } 2194 mBitrateRange = Range.create(1, maxBps); 2195 mParent.mError |= errors; 2196 } 2197 } 2198 2199 /** 2200 * A class that supports querying the encoding capabilities of a codec. 2201 */ 2202 public static final class EncoderCapabilities { 2203 /** 2204 * Returns the supported range of quality values. 2205 * 2206 * @hide 2207 */ 2208 public Range<Integer> getQualityRange() { 2209 return mQualityRange; 2210 } 2211 2212 /** 2213 * Returns the supported range of encoder complexity values. 2214 * <p> 2215 * Some codecs may support multiple complexity levels, where higher 2216 * complexity values use more encoder tools (e.g. perform more 2217 * intensive calculations) to improve the quality or the compression 2218 * ratio. Use a lower value to save power and/or time. 2219 */ 2220 public Range<Integer> getComplexityRange() { 2221 return mComplexityRange; 2222 } 2223 2224 /** Constant quality mode */ 2225 public static final int BITRATE_MODE_CQ = 0; 2226 /** Variable bitrate mode */ 2227 public static final int BITRATE_MODE_VBR = 1; 2228 /** Constant bitrate mode */ 2229 public static final int BITRATE_MODE_CBR = 2; 2230 2231 private static final Feature[] bitrates = new Feature[] { 2232 new Feature("VBR", BITRATE_MODE_VBR, true), 2233 new Feature("CBR", BITRATE_MODE_CBR, false), 2234 new Feature("CQ", BITRATE_MODE_CQ, false) 2235 }; 2236 2237 private static int parseBitrateMode(String mode) { 2238 for (Feature feat: bitrates) { 2239 if (feat.mName.equalsIgnoreCase(mode)) { 2240 return feat.mValue; 2241 } 2242 } 2243 return 0; 2244 } 2245 2246 /** 2247 * Query whether a bitrate mode is supported. 2248 */ 2249 public boolean isBitrateModeSupported(int mode) { 2250 for (Feature feat: bitrates) { 2251 if (mode == feat.mValue) { 2252 return (mBitControl & (1 << mode)) != 0; 2253 } 2254 } 2255 return false; 2256 } 2257 2258 private Range<Integer> mQualityRange; 2259 private Range<Integer> mComplexityRange; 2260 private CodecCapabilities mParent; 2261 2262 /* no public constructor */ 2263 private EncoderCapabilities() { } 2264 2265 /** @hide */ 2266 public static EncoderCapabilities create( 2267 MediaFormat info, CodecCapabilities parent) { 2268 EncoderCapabilities caps = new EncoderCapabilities(); 2269 caps.init(info, parent); 2270 return caps; 2271 } 2272 2273 /** @hide */ 2274 public void init(MediaFormat info, CodecCapabilities parent) { 2275 // no support for complexity or quality yet 2276 mParent = parent; 2277 mComplexityRange = Range.create(0, 0); 2278 mQualityRange = Range.create(0, 0); 2279 mBitControl = (1 << BITRATE_MODE_VBR); 2280 2281 applyLevelLimits(); 2282 parseFromInfo(info); 2283 } 2284 2285 private void applyLevelLimits() { 2286 String mime = mParent.getMimeType(); 2287 if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) { 2288 mComplexityRange = Range.create(0, 8); 2289 mBitControl = (1 << BITRATE_MODE_CQ); 2290 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB) 2291 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB) 2292 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW) 2293 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW) 2294 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) { 2295 mBitControl = (1 << BITRATE_MODE_CBR); 2296 } 2297 } 2298 2299 private int mBitControl; 2300 private Integer mDefaultComplexity; 2301 private Integer mDefaultQuality; 2302 private String mQualityScale; 2303 2304 private void parseFromInfo(MediaFormat info) { 2305 Map<String, Object> map = info.getMap(); 2306 2307 if (info.containsKey("complexity-range")) { 2308 mComplexityRange = Utils 2309 .parseIntRange(info.getString("complexity-range"), mComplexityRange); 2310 // TODO should we limit this to level limits? 2311 } 2312 if (info.containsKey("quality-range")) { 2313 mQualityRange = Utils 2314 .parseIntRange(info.getString("quality-range"), mQualityRange); 2315 } 2316 if (info.containsKey("feature-bitrate-control")) { 2317 for (String mode: info.getString("feature-bitrate-control").split(",")) { 2318 mBitControl |= parseBitrateMode(mode); 2319 } 2320 } 2321 2322 try { 2323 mDefaultComplexity = Integer.parseInt((String)map.get("complexity-default")); 2324 } catch (NumberFormatException e) { } 2325 2326 try { 2327 mDefaultQuality = Integer.parseInt((String)map.get("quality-default")); 2328 } catch (NumberFormatException e) { } 2329 2330 mQualityScale = (String)map.get("quality-scale"); 2331 } 2332 2333 private boolean supports( 2334 Integer complexity, Integer quality, Integer profile) { 2335 boolean ok = true; 2336 if (ok && complexity != null) { 2337 ok = mComplexityRange.contains(complexity); 2338 } 2339 if (ok && quality != null) { 2340 ok = mQualityRange.contains(quality); 2341 } 2342 if (ok && profile != null) { 2343 for (CodecProfileLevel pl: mParent.profileLevels) { 2344 if (pl.profile == profile) { 2345 profile = null; 2346 break; 2347 } 2348 } 2349 ok = profile == null; 2350 } 2351 return ok; 2352 } 2353 2354 /** @hide */ 2355 public void setDefaultFormat(MediaFormat format) { 2356 // don't list trivial quality/complexity as default for now 2357 if (!mQualityRange.getUpper().equals(mQualityRange.getLower()) 2358 && mDefaultQuality != null) { 2359 format.setInteger(MediaFormat.KEY_QUALITY, mDefaultQuality); 2360 } 2361 if (!mComplexityRange.getUpper().equals(mComplexityRange.getLower()) 2362 && mDefaultComplexity != null) { 2363 format.setInteger(MediaFormat.KEY_COMPLEXITY, mDefaultComplexity); 2364 } 2365 // bitrates are listed in order of preference 2366 for (Feature feat: bitrates) { 2367 if ((mBitControl & (1 << feat.mValue)) != 0) { 2368 format.setInteger(MediaFormat.KEY_BITRATE_MODE, feat.mValue); 2369 break; 2370 } 2371 } 2372 } 2373 2374 /** @hide */ 2375 public boolean supportsFormat(MediaFormat format) { 2376 final Map<String, Object> map = format.getMap(); 2377 final String mime = mParent.getMimeType(); 2378 2379 Integer mode = (Integer)map.get(MediaFormat.KEY_BITRATE_MODE); 2380 if (mode != null && !isBitrateModeSupported(mode)) { 2381 return false; 2382 } 2383 2384 Integer complexity = (Integer)map.get(MediaFormat.KEY_COMPLEXITY); 2385 if (MediaFormat.MIMETYPE_AUDIO_FLAC.equalsIgnoreCase(mime)) { 2386 Integer flacComplexity = 2387 (Integer)map.get(MediaFormat.KEY_FLAC_COMPRESSION_LEVEL); 2388 if (complexity == null) { 2389 complexity = flacComplexity; 2390 } else if (flacComplexity != null && !complexity.equals(flacComplexity)) { 2391 throw new IllegalArgumentException( 2392 "conflicting values for complexity and " + 2393 "flac-compression-level"); 2394 } 2395 } 2396 2397 // other audio parameters 2398 Integer profile = (Integer)map.get(MediaFormat.KEY_PROFILE); 2399 if (MediaFormat.MIMETYPE_AUDIO_AAC.equalsIgnoreCase(mime)) { 2400 Integer aacProfile = (Integer)map.get(MediaFormat.KEY_AAC_PROFILE); 2401 if (profile == null) { 2402 profile = aacProfile; 2403 } else if (aacProfile != null && !aacProfile.equals(profile)) { 2404 throw new IllegalArgumentException( 2405 "conflicting values for profile and aac-profile"); 2406 } 2407 } 2408 2409 Integer quality = (Integer)map.get(MediaFormat.KEY_QUALITY); 2410 2411 return supports(complexity, quality, profile); 2412 } 2413 }; 2414 2415 /** 2416 * Encapsulates the profiles available for a codec component. 2417 * <p>You can get a set of {@link MediaCodecInfo.CodecProfileLevel} objects for a given 2418 * {@link MediaCodecInfo} object from the 2419 * {@link MediaCodecInfo.CodecCapabilities#profileLevels} field. 2420 */ 2421 public static final class CodecProfileLevel { 2422 // from OMX_VIDEO_AVCPROFILETYPE 2423 public static final int AVCProfileBaseline = 0x01; 2424 public static final int AVCProfileMain = 0x02; 2425 public static final int AVCProfileExtended = 0x04; 2426 public static final int AVCProfileHigh = 0x08; 2427 public static final int AVCProfileHigh10 = 0x10; 2428 public static final int AVCProfileHigh422 = 0x20; 2429 public static final int AVCProfileHigh444 = 0x40; 2430 2431 // from OMX_VIDEO_AVCLEVELTYPE 2432 public static final int AVCLevel1 = 0x01; 2433 public static final int AVCLevel1b = 0x02; 2434 public static final int AVCLevel11 = 0x04; 2435 public static final int AVCLevel12 = 0x08; 2436 public static final int AVCLevel13 = 0x10; 2437 public static final int AVCLevel2 = 0x20; 2438 public static final int AVCLevel21 = 0x40; 2439 public static final int AVCLevel22 = 0x80; 2440 public static final int AVCLevel3 = 0x100; 2441 public static final int AVCLevel31 = 0x200; 2442 public static final int AVCLevel32 = 0x400; 2443 public static final int AVCLevel4 = 0x800; 2444 public static final int AVCLevel41 = 0x1000; 2445 public static final int AVCLevel42 = 0x2000; 2446 public static final int AVCLevel5 = 0x4000; 2447 public static final int AVCLevel51 = 0x8000; 2448 public static final int AVCLevel52 = 0x10000; 2449 2450 // from OMX_VIDEO_H263PROFILETYPE 2451 public static final int H263ProfileBaseline = 0x01; 2452 public static final int H263ProfileH320Coding = 0x02; 2453 public static final int H263ProfileBackwardCompatible = 0x04; 2454 public static final int H263ProfileISWV2 = 0x08; 2455 public static final int H263ProfileISWV3 = 0x10; 2456 public static final int H263ProfileHighCompression = 0x20; 2457 public static final int H263ProfileInternet = 0x40; 2458 public static final int H263ProfileInterlace = 0x80; 2459 public static final int H263ProfileHighLatency = 0x100; 2460 2461 // from OMX_VIDEO_H263LEVELTYPE 2462 public static final int H263Level10 = 0x01; 2463 public static final int H263Level20 = 0x02; 2464 public static final int H263Level30 = 0x04; 2465 public static final int H263Level40 = 0x08; 2466 public static final int H263Level45 = 0x10; 2467 public static final int H263Level50 = 0x20; 2468 public static final int H263Level60 = 0x40; 2469 public static final int H263Level70 = 0x80; 2470 2471 // from OMX_VIDEO_MPEG4PROFILETYPE 2472 public static final int MPEG4ProfileSimple = 0x01; 2473 public static final int MPEG4ProfileSimpleScalable = 0x02; 2474 public static final int MPEG4ProfileCore = 0x04; 2475 public static final int MPEG4ProfileMain = 0x08; 2476 public static final int MPEG4ProfileNbit = 0x10; 2477 public static final int MPEG4ProfileScalableTexture = 0x20; 2478 public static final int MPEG4ProfileSimpleFace = 0x40; 2479 public static final int MPEG4ProfileSimpleFBA = 0x80; 2480 public static final int MPEG4ProfileBasicAnimated = 0x100; 2481 public static final int MPEG4ProfileHybrid = 0x200; 2482 public static final int MPEG4ProfileAdvancedRealTime = 0x400; 2483 public static final int MPEG4ProfileCoreScalable = 0x800; 2484 public static final int MPEG4ProfileAdvancedCoding = 0x1000; 2485 public static final int MPEG4ProfileAdvancedCore = 0x2000; 2486 public static final int MPEG4ProfileAdvancedScalable = 0x4000; 2487 public static final int MPEG4ProfileAdvancedSimple = 0x8000; 2488 2489 // from OMX_VIDEO_MPEG4LEVELTYPE 2490 public static final int MPEG4Level0 = 0x01; 2491 public static final int MPEG4Level0b = 0x02; 2492 public static final int MPEG4Level1 = 0x04; 2493 public static final int MPEG4Level2 = 0x08; 2494 public static final int MPEG4Level3 = 0x10; 2495 public static final int MPEG4Level4 = 0x20; 2496 public static final int MPEG4Level4a = 0x40; 2497 public static final int MPEG4Level5 = 0x80; 2498 2499 // from OMX_VIDEO_MPEG2PROFILETYPE 2500 public static final int MPEG2ProfileSimple = 0x00; 2501 public static final int MPEG2ProfileMain = 0x01; 2502 public static final int MPEG2Profile422 = 0x02; 2503 public static final int MPEG2ProfileSNR = 0x03; 2504 public static final int MPEG2ProfileSpatial = 0x04; 2505 public static final int MPEG2ProfileHigh = 0x05; 2506 2507 // from OMX_VIDEO_MPEG2LEVELTYPE 2508 public static final int MPEG2LevelLL = 0x00; 2509 public static final int MPEG2LevelML = 0x01; 2510 public static final int MPEG2LevelH14 = 0x02; 2511 public static final int MPEG2LevelHL = 0x03; 2512 2513 // from OMX_AUDIO_AACPROFILETYPE 2514 public static final int AACObjectMain = 1; 2515 public static final int AACObjectLC = 2; 2516 public static final int AACObjectSSR = 3; 2517 public static final int AACObjectLTP = 4; 2518 public static final int AACObjectHE = 5; 2519 public static final int AACObjectScalable = 6; 2520 public static final int AACObjectERLC = 17; 2521 public static final int AACObjectLD = 23; 2522 public static final int AACObjectHE_PS = 29; 2523 public static final int AACObjectELD = 39; 2524 2525 // from OMX_VIDEO_VP8LEVELTYPE 2526 public static final int VP8Level_Version0 = 0x01; 2527 public static final int VP8Level_Version1 = 0x02; 2528 public static final int VP8Level_Version2 = 0x04; 2529 public static final int VP8Level_Version3 = 0x08; 2530 2531 // from OMX_VIDEO_VP8PROFILETYPE 2532 public static final int VP8ProfileMain = 0x01; 2533 2534 // from OMX_VIDEO_HEVCPROFILETYPE 2535 public static final int HEVCProfileMain = 0x01; 2536 public static final int HEVCProfileMain10 = 0x02; 2537 2538 // from OMX_VIDEO_HEVCLEVELTYPE 2539 public static final int HEVCMainTierLevel1 = 0x1; 2540 public static final int HEVCHighTierLevel1 = 0x2; 2541 public static final int HEVCMainTierLevel2 = 0x4; 2542 public static final int HEVCHighTierLevel2 = 0x8; 2543 public static final int HEVCMainTierLevel21 = 0x10; 2544 public static final int HEVCHighTierLevel21 = 0x20; 2545 public static final int HEVCMainTierLevel3 = 0x40; 2546 public static final int HEVCHighTierLevel3 = 0x80; 2547 public static final int HEVCMainTierLevel31 = 0x100; 2548 public static final int HEVCHighTierLevel31 = 0x200; 2549 public static final int HEVCMainTierLevel4 = 0x400; 2550 public static final int HEVCHighTierLevel4 = 0x800; 2551 public static final int HEVCMainTierLevel41 = 0x1000; 2552 public static final int HEVCHighTierLevel41 = 0x2000; 2553 public static final int HEVCMainTierLevel5 = 0x4000; 2554 public static final int HEVCHighTierLevel5 = 0x8000; 2555 public static final int HEVCMainTierLevel51 = 0x10000; 2556 public static final int HEVCHighTierLevel51 = 0x20000; 2557 public static final int HEVCMainTierLevel52 = 0x40000; 2558 public static final int HEVCHighTierLevel52 = 0x80000; 2559 public static final int HEVCMainTierLevel6 = 0x100000; 2560 public static final int HEVCHighTierLevel6 = 0x200000; 2561 public static final int HEVCMainTierLevel61 = 0x400000; 2562 public static final int HEVCHighTierLevel61 = 0x800000; 2563 public static final int HEVCMainTierLevel62 = 0x1000000; 2564 public static final int HEVCHighTierLevel62 = 0x2000000; 2565 2566 /** 2567 * Defined in the OpenMAX IL specs, depending on the type of media 2568 * this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE, 2569 * OMX_VIDEO_MPEG4PROFILETYPE or OMX_VIDEO_VP8PROFILETYPE. 2570 */ 2571 public int profile; 2572 2573 /** 2574 * Defined in the OpenMAX IL specs, depending on the type of media 2575 * this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE 2576 * OMX_VIDEO_MPEG4LEVELTYPE or OMX_VIDEO_VP8LEVELTYPE. 2577 */ 2578 public int level; 2579 }; 2580 2581 /** 2582 * Enumerates the capabilities of the codec component. Since a single 2583 * component can support data of a variety of types, the type has to be 2584 * specified to yield a meaningful result. 2585 * @param type The MIME type to query 2586 */ 2587 public final CodecCapabilities getCapabilitiesForType( 2588 String type) { 2589 CodecCapabilities caps = mCaps.get(type); 2590 if (caps == null) { 2591 throw new IllegalArgumentException("codec does not support type"); 2592 } 2593 // clone writable object 2594 return caps.dup(); 2595 } 2596 2597 /** @hide */ 2598 public MediaCodecInfo makeRegular() { 2599 ArrayList<CodecCapabilities> caps = new ArrayList<CodecCapabilities>(); 2600 for (CodecCapabilities c: mCaps.values()) { 2601 if (c.isRegular()) { 2602 caps.add(c); 2603 } 2604 } 2605 if (caps.size() == 0) { 2606 return null; 2607 } else if (caps.size() == mCaps.size()) { 2608 return this; 2609 } 2610 2611 return new MediaCodecInfo( 2612 mName, mIsEncoder, 2613 caps.toArray(new CodecCapabilities[caps.size()])); 2614 } 2615 } 2616