1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.media; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.util.Log; 22 import android.util.Pair; 23 import android.util.Range; 24 import android.util.Rational; 25 import android.util.Size; 26 27 import java.util.ArrayList; 28 import java.util.Arrays; 29 import java.util.HashMap; 30 import java.util.Map; 31 import java.util.Set; 32 33 import static android.media.Utils.intersectSortedDistinctRanges; 34 import static android.media.Utils.sortDistinctRanges; 35 36 /** 37 * Provides information about a given media codec available on the device. You can 38 * iterate through all codecs available by querying {@link MediaCodecList}. For example, 39 * here's how to find an encoder that supports a given MIME type: 40 * <pre> 41 * private static MediaCodecInfo selectCodec(String mimeType) { 42 * int numCodecs = MediaCodecList.getCodecCount(); 43 * for (int i = 0; i < numCodecs; i++) { 44 * MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i); 45 * 46 * if (!codecInfo.isEncoder()) { 47 * continue; 48 * } 49 * 50 * String[] types = codecInfo.getSupportedTypes(); 51 * for (int j = 0; j < types.length; j++) { 52 * if (types[j].equalsIgnoreCase(mimeType)) { 53 * return codecInfo; 54 * } 55 * } 56 * } 57 * return null; 58 * }</pre> 59 * 60 */ 61 public final class MediaCodecInfo { 62 private boolean mIsEncoder; 63 private String mName; 64 private Map<String, CodecCapabilities> mCaps; 65 MediaCodecInfo( String name, boolean isEncoder, CodecCapabilities[] caps)66 /* package private */ MediaCodecInfo( 67 String name, boolean isEncoder, CodecCapabilities[] caps) { 68 mName = name; 69 mIsEncoder = isEncoder; 70 mCaps = new HashMap<String, CodecCapabilities>(); 71 for (CodecCapabilities c: caps) { 72 mCaps.put(c.getMimeType(), c); 73 } 74 } 75 76 /** 77 * Retrieve the codec name. 78 */ getName()79 public final String getName() { 80 return mName; 81 } 82 83 /** 84 * Query if the codec is an encoder. 85 */ isEncoder()86 public final boolean isEncoder() { 87 return mIsEncoder; 88 } 89 90 /** 91 * Query the media types supported by the codec. 92 */ getSupportedTypes()93 public final String[] getSupportedTypes() { 94 Set<String> typeSet = mCaps.keySet(); 95 String[] types = typeSet.toArray(new String[typeSet.size()]); 96 Arrays.sort(types); 97 return types; 98 } 99 checkPowerOfTwo(int value, String message)100 private static int checkPowerOfTwo(int value, String message) { 101 if ((value & (value - 1)) != 0) { 102 throw new IllegalArgumentException(message); 103 } 104 return value; 105 } 106 107 private static class Feature { 108 public String mName; 109 public int mValue; 110 public boolean mDefault; Feature(String name, int value, boolean def)111 public Feature(String name, int value, boolean def) { 112 mName = name; 113 mValue = value; 114 mDefault = def; 115 } 116 } 117 118 // COMMON CONSTANTS 119 private static final Range<Integer> POSITIVE_INTEGERS = 120 Range.create(1, Integer.MAX_VALUE); 121 private static final Range<Long> POSITIVE_LONGS = 122 Range.create(1l, Long.MAX_VALUE); 123 private static final Range<Rational> POSITIVE_RATIONALS = 124 Range.create(new Rational(1, Integer.MAX_VALUE), 125 new Rational(Integer.MAX_VALUE, 1)); 126 private static final Range<Integer> SIZE_RANGE = Range.create(1, 32768); 127 private static final Range<Integer> FRAME_RATE_RANGE = Range.create(0, 960); 128 private static final Range<Integer> BITRATE_RANGE = Range.create(0, 500000000); 129 private static final int DEFAULT_MAX_SUPPORTED_INSTANCES = 32; 130 private static final int MAX_SUPPORTED_INSTANCES_LIMIT = 256; 131 132 // found stuff that is not supported by framework (=> this should not happen) 133 private static final int ERROR_UNRECOGNIZED = (1 << 0); 134 // found profile/level for which we don't have capability estimates 135 private static final int ERROR_UNSUPPORTED = (1 << 1); 136 // have not found any profile/level for which we don't have capability estimate 137 private static final int ERROR_NONE_SUPPORTED = (1 << 2); 138 139 140 /** 141 * Encapsulates the capabilities of a given codec component. 142 * For example, what profile/level combinations it supports and what colorspaces 143 * it is capable of providing the decoded data in, as well as some 144 * codec-type specific capability flags. 145 * <p>You can get an instance for a given {@link MediaCodecInfo} object with 146 * {@link MediaCodecInfo#getCapabilitiesForType getCapabilitiesForType()}, passing a MIME type. 147 */ 148 public static final class CodecCapabilities { CodecCapabilities()149 public CodecCapabilities() { 150 } 151 152 // CLASSIFICATION 153 private String mMime; 154 private int mMaxSupportedInstances; 155 156 // LEGACY FIELDS 157 158 // Enumerates supported profile/level combinations as defined 159 // by the type of encoded data. These combinations impose restrictions 160 // on video resolution, bitrate... and limit the available encoder tools 161 // such as B-frame support, arithmetic coding... 162 public CodecProfileLevel[] profileLevels; // NOTE this array is modifiable by user 163 164 // from OMX_COLOR_FORMATTYPE 165 /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */ 166 public static final int COLOR_FormatMonochrome = 1; 167 /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */ 168 public static final int COLOR_Format8bitRGB332 = 2; 169 /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */ 170 public static final int COLOR_Format12bitRGB444 = 3; 171 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 172 public static final int COLOR_Format16bitARGB4444 = 4; 173 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 174 public static final int COLOR_Format16bitARGB1555 = 5; 175 176 /** 177 * 16 bits per pixel RGB color format, with 5-bit red & blue and 6-bit green component. 178 * <p> 179 * Using 16-bit little-endian representation, colors stored as Red 15:11, Green 10:5, Blue 4:0. 180 * <pre> 181 * byte byte 182 * <--------- i --------> | <------ i + 1 ------> 183 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 184 * | BLUE | GREEN | RED | 185 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 186 * 0 4 5 7 0 2 3 7 187 * bit 188 * </pre> 189 * 190 * This format corresponds to {@link android.graphics.PixelFormat#RGB_565} and 191 * {@link android.graphics.ImageFormat#RGB_565}. 192 */ 193 public static final int COLOR_Format16bitRGB565 = 6; 194 /** @deprecated Use {@link #COLOR_Format16bitRGB565}. */ 195 public static final int COLOR_Format16bitBGR565 = 7; 196 /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */ 197 public static final int COLOR_Format18bitRGB666 = 8; 198 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 199 public static final int COLOR_Format18bitARGB1665 = 9; 200 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 201 public static final int COLOR_Format19bitARGB1666 = 10; 202 203 /** @deprecated Use {@link #COLOR_Format24bitBGR888} or {@link #COLOR_FormatRGBFlexible}. */ 204 public static final int COLOR_Format24bitRGB888 = 11; 205 206 /** 207 * 24 bits per pixel RGB color format, with 8-bit red, green & blue components. 208 * <p> 209 * Using 24-bit little-endian representation, colors stored as Red 7:0, Green 15:8, Blue 23:16. 210 * <pre> 211 * byte byte byte 212 * <------ i -----> | <---- i+1 ----> | <---- i+2 -----> 213 * +-----------------+-----------------+-----------------+ 214 * | RED | GREEN | BLUE | 215 * +-----------------+-----------------+-----------------+ 216 * </pre> 217 * 218 * This format corresponds to {@link android.graphics.PixelFormat#RGB_888}, and can also be 219 * represented as a flexible format by {@link #COLOR_FormatRGBFlexible}. 220 */ 221 public static final int COLOR_Format24bitBGR888 = 12; 222 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 223 public static final int COLOR_Format24bitARGB1887 = 13; 224 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 225 public static final int COLOR_Format25bitARGB1888 = 14; 226 227 /** 228 * @deprecated Use {@link #COLOR_Format32bitABGR8888} Or {@link #COLOR_FormatRGBAFlexible}. 229 */ 230 public static final int COLOR_Format32bitBGRA8888 = 15; 231 /** 232 * @deprecated Use {@link #COLOR_Format32bitABGR8888} Or {@link #COLOR_FormatRGBAFlexible}. 233 */ 234 public static final int COLOR_Format32bitARGB8888 = 16; 235 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 236 public static final int COLOR_FormatYUV411Planar = 17; 237 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 238 public static final int COLOR_FormatYUV411PackedPlanar = 18; 239 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 240 public static final int COLOR_FormatYUV420Planar = 19; 241 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 242 public static final int COLOR_FormatYUV420PackedPlanar = 20; 243 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 244 public static final int COLOR_FormatYUV420SemiPlanar = 21; 245 246 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 247 public static final int COLOR_FormatYUV422Planar = 22; 248 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 249 public static final int COLOR_FormatYUV422PackedPlanar = 23; 250 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 251 public static final int COLOR_FormatYUV422SemiPlanar = 24; 252 253 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 254 public static final int COLOR_FormatYCbYCr = 25; 255 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 256 public static final int COLOR_FormatYCrYCb = 26; 257 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 258 public static final int COLOR_FormatCbYCrY = 27; 259 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 260 public static final int COLOR_FormatCrYCbY = 28; 261 262 /** @deprecated Use {@link #COLOR_FormatYUV444Flexible}. */ 263 public static final int COLOR_FormatYUV444Interleaved = 29; 264 265 /** 266 * SMIA 8-bit Bayer format. 267 * Each byte represents the top 8-bits of a 10-bit signal. 268 */ 269 public static final int COLOR_FormatRawBayer8bit = 30; 270 /** 271 * SMIA 10-bit Bayer format. 272 */ 273 public static final int COLOR_FormatRawBayer10bit = 31; 274 275 /** 276 * SMIA 8-bit compressed Bayer format. 277 * Each byte represents a sample from the 10-bit signal that is compressed into 8-bits 278 * using DPCM/PCM compression, as defined by the SMIA Functional Specification. 279 */ 280 public static final int COLOR_FormatRawBayer8bitcompressed = 32; 281 282 /** @deprecated Use {@link #COLOR_FormatL8}. */ 283 public static final int COLOR_FormatL2 = 33; 284 /** @deprecated Use {@link #COLOR_FormatL8}. */ 285 public static final int COLOR_FormatL4 = 34; 286 287 /** 288 * 8 bits per pixel Y color format. 289 * <p> 290 * Each byte contains a single pixel. 291 * This format corresponds to {@link android.graphics.PixelFormat#L_8}. 292 */ 293 public static final int COLOR_FormatL8 = 35; 294 295 /** 296 * 16 bits per pixel, little-endian Y color format. 297 * <p> 298 * <pre> 299 * byte byte 300 * <--------- i --------> | <------ i + 1 ------> 301 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 302 * | Y | 303 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 304 * 0 7 0 7 305 * bit 306 * </pre> 307 */ 308 public static final int COLOR_FormatL16 = 36; 309 /** @deprecated Use {@link #COLOR_FormatL16}. */ 310 public static final int COLOR_FormatL24 = 37; 311 312 /** 313 * 32 bits per pixel, little-endian Y color format. 314 * <p> 315 * <pre> 316 * byte byte byte byte 317 * <------ i -----> | <---- i+1 ----> | <---- i+2 ----> | <---- i+3 -----> 318 * +-----------------+-----------------+-----------------+-----------------+ 319 * | Y | 320 * +-----------------+-----------------+-----------------+-----------------+ 321 * 0 7 0 7 0 7 0 7 322 * bit 323 * </pre> 324 * 325 * @deprecated Use {@link #COLOR_FormatL16}. 326 */ 327 public static final int COLOR_FormatL32 = 38; 328 329 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 330 public static final int COLOR_FormatYUV420PackedSemiPlanar = 39; 331 /** @deprecated Use {@link #COLOR_FormatYUV422Flexible}. */ 332 public static final int COLOR_FormatYUV422PackedSemiPlanar = 40; 333 334 /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */ 335 public static final int COLOR_Format18BitBGR666 = 41; 336 337 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 338 public static final int COLOR_Format24BitARGB6666 = 42; 339 /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */ 340 public static final int COLOR_Format24BitABGR6666 = 43; 341 342 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 343 public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100; 344 // COLOR_FormatSurface indicates that the data will be a GraphicBuffer metadata reference. 345 // In OMX this is called OMX_COLOR_FormatAndroidOpaque. 346 public static final int COLOR_FormatSurface = 0x7F000789; 347 348 /** 349 * 32 bits per pixel RGBA color format, with 8-bit red, green, blue, and alpha components. 350 * <p> 351 * Using 32-bit little-endian representation, colors stored as Red 7:0, Green 15:8, 352 * Blue 23:16, and Alpha 31:24. 353 * <pre> 354 * byte byte byte byte 355 * <------ i -----> | <---- i+1 ----> | <---- i+2 ----> | <---- i+3 -----> 356 * +-----------------+-----------------+-----------------+-----------------+ 357 * | RED | GREEN | BLUE | ALPHA | 358 * +-----------------+-----------------+-----------------+-----------------+ 359 * </pre> 360 * 361 * This corresponds to {@link android.graphics.PixelFormat#RGBA_8888}. 362 */ 363 public static final int COLOR_Format32bitABGR8888 = 0x7F00A000; 364 365 /** 366 * Flexible 12 bits per pixel, subsampled YUV color format with 8-bit chroma and luma 367 * components. 368 * <p> 369 * Chroma planes are subsampled by 2 both horizontally and vertically. 370 * Use this format with {@link Image}. 371 * This format corresponds to {@link android.graphics.ImageFormat#YUV_420_888}, 372 * and can represent the {@link #COLOR_FormatYUV411Planar}, 373 * {@link #COLOR_FormatYUV411PackedPlanar}, {@link #COLOR_FormatYUV420Planar}, 374 * {@link #COLOR_FormatYUV420PackedPlanar}, {@link #COLOR_FormatYUV420SemiPlanar} 375 * and {@link #COLOR_FormatYUV420PackedSemiPlanar} formats. 376 * 377 * @see Image#getFormat 378 */ 379 public static final int COLOR_FormatYUV420Flexible = 0x7F420888; 380 381 /** 382 * Flexible 16 bits per pixel, subsampled YUV color format with 8-bit chroma and luma 383 * components. 384 * <p> 385 * Chroma planes are horizontally subsampled by 2. Use this format with {@link Image}. 386 * This format corresponds to {@link android.graphics.ImageFormat#YUV_422_888}, 387 * and can represent the {@link #COLOR_FormatYCbYCr}, {@link #COLOR_FormatYCrYCb}, 388 * {@link #COLOR_FormatCbYCrY}, {@link #COLOR_FormatCrYCbY}, 389 * {@link #COLOR_FormatYUV422Planar}, {@link #COLOR_FormatYUV422PackedPlanar}, 390 * {@link #COLOR_FormatYUV422SemiPlanar} and {@link #COLOR_FormatYUV422PackedSemiPlanar} 391 * formats. 392 * 393 * @see Image#getFormat 394 */ 395 public static final int COLOR_FormatYUV422Flexible = 0x7F422888; 396 397 /** 398 * Flexible 24 bits per pixel YUV color format with 8-bit chroma and luma 399 * components. 400 * <p> 401 * Chroma planes are not subsampled. Use this format with {@link Image}. 402 * This format corresponds to {@link android.graphics.ImageFormat#YUV_444_888}, 403 * and can represent the {@link #COLOR_FormatYUV444Interleaved} format. 404 * @see Image#getFormat 405 */ 406 public static final int COLOR_FormatYUV444Flexible = 0x7F444888; 407 408 /** 409 * Flexible 24 bits per pixel RGB color format with 8-bit red, green and blue 410 * components. 411 * <p> 412 * Use this format with {@link Image}. This format corresponds to 413 * {@link android.graphics.ImageFormat#FLEX_RGB_888}, and can represent 414 * {@link #COLOR_Format24bitBGR888} and {@link #COLOR_Format24bitRGB888} formats. 415 * @see Image#getFormat. 416 */ 417 public static final int COLOR_FormatRGBFlexible = 0x7F36B888; 418 419 /** 420 * Flexible 32 bits per pixel RGBA color format with 8-bit red, green, blue, and alpha 421 * components. 422 * <p> 423 * Use this format with {@link Image}. This format corresponds to 424 * {@link android.graphics.ImageFormat#FLEX_RGBA_8888}, and can represent 425 * {@link #COLOR_Format32bitBGRA8888}, {@link #COLOR_Format32bitABGR8888} and 426 * {@link #COLOR_Format32bitARGB8888} formats. 427 * 428 * @see Image#getFormat 429 */ 430 public static final int COLOR_FormatRGBAFlexible = 0x7F36A888; 431 432 /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ 433 public static final int COLOR_QCOM_FormatYUV420SemiPlanar = 0x7fa30c00; 434 435 /** 436 * Defined in the OpenMAX IL specs, color format values are drawn from 437 * OMX_COLOR_FORMATTYPE. 438 */ 439 public int[] colorFormats; // NOTE this array is modifiable by user 440 441 // FEATURES 442 443 private int mFlagsSupported; 444 private int mFlagsRequired; 445 private int mFlagsVerified; 446 447 /** 448 * <b>video decoder only</b>: codec supports seamless resolution changes. 449 */ 450 public static final String FEATURE_AdaptivePlayback = "adaptive-playback"; 451 452 /** 453 * <b>video decoder only</b>: codec supports secure decryption. 454 */ 455 public static final String FEATURE_SecurePlayback = "secure-playback"; 456 457 /** 458 * <b>video or audio decoder only</b>: codec supports tunneled playback. 459 */ 460 public static final String FEATURE_TunneledPlayback = "tunneled-playback"; 461 462 /** 463 * 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 */ isFeatureSupported(String name)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 */ isFeatureRequired(String name)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 */ validFeatures()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 getValidFeatures()499 private Feature[] getValidFeatures() { 500 if (!isEncoder()) { 501 return decoderFeatures; 502 } 503 return new Feature[] {}; 504 } 505 checkFeature(String name, int flags)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 */ isRegular()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 */ isFormatSupported(MediaFormat format)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 */ getDefaultFormat()588 public MediaFormat getDefaultFormat() { 589 return mDefaultFormat; 590 } 591 592 /** 593 * Returns the mime type for which this codec-capability object was created. 594 */ getMimeType()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 */ getMaxSupportedInstances()607 public int getMaxSupportedInstances() { 608 return mMaxSupportedInstances; 609 } 610 isAudio()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 */ getAudioCapabilities()618 public AudioCapabilities getAudioCapabilities() { 619 return mAudioCaps; 620 } 621 isEncoder()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 */ getEncoderCapabilities()629 public EncoderCapabilities getEncoderCapabilities() { 630 return mEncoderCaps; 631 } 632 isVideo()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 */ getVideoCapabilities()640 public VideoCapabilities getVideoCapabilities() { 641 return mVideoCaps; 642 } 643 644 /** @hide */ dup()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 */ createFromProfileLevel( String mime, int profile, int level)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 CodecCapabilities( CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags, Map<String, Object>defaultFormatMap, Map<String, Object>capabilitiesMap)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 CodecCapabilities( CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags, MediaFormat defaultFormat, MediaFormat info)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 */ getBitrateRange()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 */ getSupportedSampleRates()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 */ getSupportedSampleRateRanges()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 */ getMaxInputChannelCount()780 public int getMaxInputChannelCount() { 781 return mMaxInputChannelCount; 782 } 783 784 /* no public constructor */ AudioCapabilities()785 private AudioCapabilities() { } 786 787 /** @hide */ create( MediaFormat info, CodecCapabilities parent)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 */ init(MediaFormat info, CodecCapabilities parent)796 public void init(MediaFormat info, CodecCapabilities parent) { 797 mParent = parent; 798 initWithPlatformLimits(); 799 applyLevelLimits(); 800 parseFromInfo(info); 801 } 802 initWithPlatformLimits()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 supports(Integer sampleRate, Integer inputChannels)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 */ isSampleRateSupported(int sampleRate)830 public boolean isSampleRateSupported(int sampleRate) { 831 return supports(sampleRate, null); 832 } 833 834 /** modifies rates */ limitSampleRates(int[] 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 createDiscreteSampleRates()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 */ limitSampleRates(Range<Integer>[] 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 applyLevelLimits()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 applyLimits(int maxInputChannels, Range<Integer> bitRates)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 parseFromInfo(MediaFormat info)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 */ setDefaultFormat(MediaFormat format)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 */ supportsFormat(MediaFormat format)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 */ getBitrateRange()1028 public Range<Integer> getBitrateRange() { 1029 return mBitrateRange; 1030 } 1031 1032 /** 1033 * Returns the range of supported video widths. 1034 */ getSupportedWidths()1035 public Range<Integer> getSupportedWidths() { 1036 return mWidthRange; 1037 } 1038 1039 /** 1040 * Returns the range of supported video heights. 1041 */ getSupportedHeights()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 */ getWidthAlignment()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 */ getHeightAlignment()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 */ getSmallerDimensionUpperLimit()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 */ getSupportedFrameRates()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 */ getSupportedWidthsFor(int height)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 */ getSupportedHeightsFor(int width)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 */ getSupportedFrameRatesFor(int width, int height)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 getBlockCount(int width, int height)1209 private int getBlockCount(int width, int height) { 1210 return Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight); 1211 } 1212 1213 @NonNull findClosestSize(int width, int height)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 estimateFrameRatesFor(int width, int height)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 getAchievableFrameRatesFor(int width, int height)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 */ areSizeAndRateSupported( int width, int height, double frameRate)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 */ isSizeSupported(int width, int height)1290 public boolean isSizeSupported(int width, int height) { 1291 return supports(width, height, null); 1292 } 1293 supports( Integer width, Integer height, Number rate)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 */ supportsFormat(MediaFormat format)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 */ VideoCapabilities()1343 private VideoCapabilities() { } 1344 1345 /** @hide */ create( MediaFormat info, CodecCapabilities parent)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 */ init(MediaFormat info, CodecCapabilities parent)1354 public void init(MediaFormat info, CodecCapabilities parent) { 1355 mParent = parent; 1356 initWithPlatformLimits(); 1357 applyLevelLimits(); 1358 parseFromInfo(info); 1359 updateLimits(); 1360 } 1361 1362 /** @hide */ getBlockSize()1363 public Size getBlockSize() { 1364 return new Size(mBlockWidth, mBlockHeight); 1365 } 1366 1367 /** @hide */ getBlockCountRange()1368 public Range<Integer> getBlockCountRange() { 1369 return mBlockCountRange; 1370 } 1371 1372 /** @hide */ getBlocksPerSecondRange()1373 public Range<Long> getBlocksPerSecondRange() { 1374 return mBlocksPerSecondRange; 1375 } 1376 1377 /** @hide */ getAspectRatioRange(boolean blocks)1378 public Range<Rational> getAspectRatioRange(boolean blocks) { 1379 return blocks ? mBlockAspectRatioRange : mAspectRatioRange; 1380 } 1381 initWithPlatformLimits()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 getMeasuredFrameRates(Map<String, Object> map)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 parseFromInfo(MediaFormat info)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 applyBlockLimits( int blockWidth, int blockHeight, Range<Integer> counts, Range<Long> rates, Range<Rational> ratios)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 applyAlignment(int widthAlignment, int heightAlignment)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 updateLimits()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 applyMacroBlockLimits( int maxHorizontalBlocks, int maxVerticalBlocks, int maxBlocks, long maxBlocksPerSecond, int blockWidth, int blockHeight, int widthAlignment, int heightAlignment)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 applyLevelLimits()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 */ getQualityRange()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 */ getComplexityRange()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 parseBitrateMode(String mode)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 */ isBitrateModeSupported(int mode)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 */ EncoderCapabilities()2263 private EncoderCapabilities() { } 2264 2265 /** @hide */ create( MediaFormat info, CodecCapabilities parent)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 */ init(MediaFormat info, CodecCapabilities parent)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 applyLevelLimits()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 parseFromInfo(MediaFormat info)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 supports( Integer complexity, Integer quality, Integer profile)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 */ setDefaultFormat(MediaFormat format)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 */ supportsFormat(MediaFormat format)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 */ getCapabilitiesForType( String type)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 */ makeRegular()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