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.util.Log; 20 import android.util.Pair; 21 import android.util.Range; 22 import android.util.Rational; 23 import android.util.Size; 24 25 import java.util.ArrayList; 26 import java.util.Arrays; 27 import java.util.Comparator; 28 import java.util.HashMap; 29 import java.util.Map; 30 import java.util.Set; 31 32 import static android.media.Utils.intersectSortedDistinctRanges; 33 import static android.media.Utils.sortDistinctRanges; 34 import static com.android.internal.util.Preconditions.checkArgumentPositive; 35 import static com.android.internal.util.Preconditions.checkNotNull; 36 37 /** 38 * Provides information about a given media codec available on the device. You can 39 * iterate through all codecs available by querying {@link MediaCodecList}. For example, 40 * here's how to find an encoder that supports a given MIME type: 41 * <pre> 42 * private static MediaCodecInfo selectCodec(String mimeType) { 43 * int numCodecs = MediaCodecList.getCodecCount(); 44 * for (int i = 0; i < numCodecs; i++) { 45 * MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i); 46 * 47 * if (!codecInfo.isEncoder()) { 48 * continue; 49 * } 50 * 51 * String[] types = codecInfo.getSupportedTypes(); 52 * for (int j = 0; j < types.length; j++) { 53 * if (types[j].equalsIgnoreCase(mimeType)) { 54 * return codecInfo; 55 * } 56 * } 57 * } 58 * return null; 59 * }</pre> 60 * 61 */ 62 public final class MediaCodecInfo { 63 private boolean mIsEncoder; 64 private String mName; 65 private Map<String, CodecCapabilities> mCaps; 66 67 /* package private */ MediaCodecInfo( 68 String name, boolean isEncoder, CodecCapabilities[] caps) { 69 mName = name; 70 mIsEncoder = isEncoder; 71 mCaps = new HashMap<String, CodecCapabilities>(); 72 for (CodecCapabilities c: caps) { 73 mCaps.put(c.getMimeType(), c); 74 } 75 } 76 77 /** 78 * Retrieve the codec name. 79 */ 80 public final String getName() { 81 return mName; 82 } 83 84 /** 85 * Query if the codec is an encoder. 86 */ 87 public final boolean isEncoder() { 88 return mIsEncoder; 89 } 90 91 /** 92 * Query the media types supported by the codec. 93 */ 94 public final String[] getSupportedTypes() { 95 Set<String> typeSet = mCaps.keySet(); 96 String[] types = typeSet.toArray(new String[typeSet.size()]); 97 Arrays.sort(types); 98 return types; 99 } 100 101 private static int checkPowerOfTwo(int value, String message) { 102 if ((value & (value - 1)) != 0) { 103 throw new IllegalArgumentException(message); 104 } 105 return value; 106 } 107 108 private static class Feature { 109 public String mName; 110 public int mValue; 111 public boolean mDefault; 112 public Feature(String name, int value, boolean def) { 113 mName = name; 114 mValue = value; 115 mDefault = def; 116 } 117 } 118 119 // COMMON CONSTANTS 120 private static final Range<Integer> POSITIVE_INTEGERS = 121 Range.create(1, Integer.MAX_VALUE); 122 private static final Range<Long> POSITIVE_LONGS = 123 Range.create(1l, Long.MAX_VALUE); 124 private static final Range<Rational> POSITIVE_RATIONALS = 125 Range.create(new Rational(1, Integer.MAX_VALUE), 126 new Rational(Integer.MAX_VALUE, 1)); 127 private static final Range<Integer> SIZE_RANGE = Range.create(1, 32768); 128 private static final Range<Integer> FRAME_RATE_RANGE = Range.create(0, 960); 129 130 // found stuff that is not supported by framework (=> this should not happen) 131 private static final int ERROR_UNRECOGNIZED = (1 << 0); 132 // found profile/level for which we don't have capability estimates 133 private static final int ERROR_UNSUPPORTED = (1 << 1); 134 // have not found any profile/level for which we don't have capability estimate 135 private static final int ERROR_NONE_SUPPORTED = (1 << 2); 136 137 138 /** 139 * Encapsulates the capabilities of a given codec component. 140 * For example, what profile/level combinations it supports and what colorspaces 141 * it is capable of providing the decoded data in, as well as some 142 * codec-type specific capability flags. 143 * <p>You can get an instance for a given {@link MediaCodecInfo} object with 144 * {@link MediaCodecInfo#getCapabilitiesForType getCapabilitiesForType()}, passing a MIME type. 145 */ 146 public static final class CodecCapabilities { 147 public CodecCapabilities() { 148 } 149 150 // CLASSIFICATION 151 private String mMime; 152 153 // LEGACY FIELDS 154 155 // Enumerates supported profile/level combinations as defined 156 // by the type of encoded data. These combinations impose restrictions 157 // on video resolution, bitrate... and limit the available encoder tools 158 // such as B-frame support, arithmetic coding... 159 public CodecProfileLevel[] profileLevels; // NOTE this array is modifiable by user 160 161 // from OMX_COLOR_FORMATTYPE 162 public static final int COLOR_FormatMonochrome = 1; 163 public static final int COLOR_Format8bitRGB332 = 2; 164 public static final int COLOR_Format12bitRGB444 = 3; 165 public static final int COLOR_Format16bitARGB4444 = 4; 166 public static final int COLOR_Format16bitARGB1555 = 5; 167 public static final int COLOR_Format16bitRGB565 = 6; 168 public static final int COLOR_Format16bitBGR565 = 7; 169 public static final int COLOR_Format18bitRGB666 = 8; 170 public static final int COLOR_Format18bitARGB1665 = 9; 171 public static final int COLOR_Format19bitARGB1666 = 10; 172 public static final int COLOR_Format24bitRGB888 = 11; 173 public static final int COLOR_Format24bitBGR888 = 12; 174 public static final int COLOR_Format24bitARGB1887 = 13; 175 public static final int COLOR_Format25bitARGB1888 = 14; 176 public static final int COLOR_Format32bitBGRA8888 = 15; 177 public static final int COLOR_Format32bitARGB8888 = 16; 178 public static final int COLOR_FormatYUV411Planar = 17; 179 public static final int COLOR_FormatYUV411PackedPlanar = 18; 180 public static final int COLOR_FormatYUV420Planar = 19; 181 public static final int COLOR_FormatYUV420PackedPlanar = 20; 182 public static final int COLOR_FormatYUV420SemiPlanar = 21; 183 public static final int COLOR_FormatYUV422Planar = 22; 184 public static final int COLOR_FormatYUV422PackedPlanar = 23; 185 public static final int COLOR_FormatYUV422SemiPlanar = 24; 186 public static final int COLOR_FormatYCbYCr = 25; 187 public static final int COLOR_FormatYCrYCb = 26; 188 public static final int COLOR_FormatCbYCrY = 27; 189 public static final int COLOR_FormatCrYCbY = 28; 190 public static final int COLOR_FormatYUV444Interleaved = 29; 191 public static final int COLOR_FormatRawBayer8bit = 30; 192 public static final int COLOR_FormatRawBayer10bit = 31; 193 public static final int COLOR_FormatRawBayer8bitcompressed = 32; 194 public static final int COLOR_FormatL2 = 33; 195 public static final int COLOR_FormatL4 = 34; 196 public static final int COLOR_FormatL8 = 35; 197 public static final int COLOR_FormatL16 = 36; 198 public static final int COLOR_FormatL24 = 37; 199 public static final int COLOR_FormatL32 = 38; 200 public static final int COLOR_FormatYUV420PackedSemiPlanar = 39; 201 public static final int COLOR_FormatYUV422PackedSemiPlanar = 40; 202 public static final int COLOR_Format18BitBGR666 = 41; 203 public static final int COLOR_Format24BitARGB6666 = 42; 204 public static final int COLOR_Format24BitABGR6666 = 43; 205 206 public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100; 207 // COLOR_FormatSurface indicates that the data will be a GraphicBuffer metadata reference. 208 // In OMX this is called OMX_COLOR_FormatAndroidOpaque. 209 public static final int COLOR_FormatSurface = 0x7F000789; 210 // This corresponds to YUV_420_888 format 211 public static final int COLOR_FormatYUV420Flexible = 0x7F420888; 212 public static final int COLOR_QCOM_FormatYUV420SemiPlanar = 0x7fa30c00; 213 214 /** 215 * Defined in the OpenMAX IL specs, color format values are drawn from 216 * OMX_COLOR_FORMATTYPE. 217 */ 218 public int[] colorFormats; // NOTE this array is modifiable by user 219 220 // FEATURES 221 222 private int mFlagsSupported; 223 private int mFlagsRequired; 224 private int mFlagsVerified; 225 226 /** 227 * <b>video decoder only</b>: codec supports seamless resolution changes. 228 */ 229 public static final String FEATURE_AdaptivePlayback = "adaptive-playback"; 230 231 /** 232 * <b>video decoder only</b>: codec supports secure decryption. 233 */ 234 public static final String FEATURE_SecurePlayback = "secure-playback"; 235 236 /** 237 * <b>video or audio decoder only</b>: codec supports tunneled playback. 238 */ 239 public static final String FEATURE_TunneledPlayback = "tunneled-playback"; 240 241 /** 242 * Query codec feature capabilities. 243 * <p> 244 * These features are supported to be used by the codec. These 245 * include optional features that can be turned on, as well as 246 * features that are always on. 247 */ 248 public final boolean isFeatureSupported(String name) { 249 return checkFeature(name, mFlagsSupported); 250 } 251 252 /** 253 * Query codec feature requirements. 254 * <p> 255 * These features are required to be used by the codec, and as such, 256 * they are always turned on. 257 */ 258 public final boolean isFeatureRequired(String name) { 259 return checkFeature(name, mFlagsRequired); 260 } 261 262 private static final Feature[] decoderFeatures = { 263 new Feature(FEATURE_AdaptivePlayback, (1 << 0), true), 264 new Feature(FEATURE_SecurePlayback, (1 << 1), false), 265 new Feature(FEATURE_TunneledPlayback, (1 << 2), false), 266 }; 267 268 /** @hide */ 269 public String[] validFeatures() { 270 Feature[] features = getValidFeatures(); 271 String[] res = new String[features.length]; 272 for (int i = 0; i < res.length; i++) { 273 res[i] = features[i].mName; 274 } 275 return res; 276 } 277 278 private Feature[] getValidFeatures() { 279 if (!isEncoder()) { 280 return decoderFeatures; 281 } 282 return new Feature[] {}; 283 } 284 285 private boolean checkFeature(String name, int flags) { 286 for (Feature feat: getValidFeatures()) { 287 if (feat.mName.equals(name)) { 288 return (flags & feat.mValue) != 0; 289 } 290 } 291 return false; 292 } 293 294 /** @hide */ 295 public boolean isRegular() { 296 // regular codecs only require default features 297 for (Feature feat: getValidFeatures()) { 298 if (!feat.mDefault && isFeatureRequired(feat.mName)) { 299 return false; 300 } 301 } 302 return true; 303 } 304 305 /** 306 * Query whether codec supports a given {@link MediaFormat}. 307 * @param format media format with optional feature directives. 308 * @throws IllegalArgumentException if format is not a valid media format. 309 * @return whether the codec capabilities support the given format 310 * and feature requests. 311 */ 312 public final boolean isFormatSupported(MediaFormat format) { 313 final Map<String, Object> map = format.getMap(); 314 final String mime = (String)map.get(MediaFormat.KEY_MIME); 315 316 // mime must match if present 317 if (mime != null && !mMime.equalsIgnoreCase(mime)) { 318 return false; 319 } 320 321 // check feature support 322 for (Feature feat: getValidFeatures()) { 323 Integer yesNo = (Integer)map.get(MediaFormat.KEY_FEATURE_ + feat.mName); 324 if (yesNo == null) { 325 continue; 326 } 327 if ((yesNo == 1 && !isFeatureSupported(feat.mName)) || 328 (yesNo == 0 && isFeatureRequired(feat.mName))) { 329 return false; 330 } 331 } 332 if (mAudioCaps != null && !mAudioCaps.supportsFormat(format)) { 333 return false; 334 } 335 if (mVideoCaps != null && !mVideoCaps.supportsFormat(format)) { 336 return false; 337 } 338 if (mEncoderCaps != null && !mEncoderCaps.supportsFormat(format)) { 339 return false; 340 } 341 return true; 342 } 343 344 // errors while reading profile levels - accessed from sister capabilities 345 int mError; 346 347 private static final String TAG = "CodecCapabilities"; 348 349 // NEW-STYLE CAPABILITIES 350 private AudioCapabilities mAudioCaps; 351 private VideoCapabilities mVideoCaps; 352 private EncoderCapabilities mEncoderCaps; 353 private MediaFormat mDefaultFormat; 354 355 /** 356 * Returns a MediaFormat object with default values for configurations that have 357 * defaults. 358 */ 359 public MediaFormat getDefaultFormat() { 360 return mDefaultFormat; 361 } 362 363 /** 364 * Returns the mime type for which this codec-capability object was created. 365 */ 366 public String getMimeType() { 367 return mMime; 368 } 369 370 private boolean isAudio() { 371 return mAudioCaps != null; 372 } 373 374 /** 375 * Returns the audio capabilities or {@code null} if this is not an audio codec. 376 */ 377 public AudioCapabilities getAudioCapabilities() { 378 return mAudioCaps; 379 } 380 381 private boolean isEncoder() { 382 return mEncoderCaps != null; 383 } 384 385 /** 386 * Returns the encoding capabilities or {@code null} if this is not an encoder. 387 */ 388 public EncoderCapabilities getEncoderCapabilities() { 389 return mEncoderCaps; 390 } 391 392 private boolean isVideo() { 393 return mVideoCaps != null; 394 } 395 396 /** 397 * Returns the video capabilities or {@code null} if this is not a video codec. 398 */ 399 public VideoCapabilities getVideoCapabilities() { 400 return mVideoCaps; 401 } 402 403 /** @hide */ 404 public CodecCapabilities dup() { 405 return new CodecCapabilities( 406 // clone writable arrays 407 Arrays.copyOf(profileLevels, profileLevels.length), 408 Arrays.copyOf(colorFormats, colorFormats.length), 409 isEncoder(), 410 mFlagsVerified, 411 mDefaultFormat, 412 mCapabilitiesInfo); 413 } 414 415 /** 416 * Retrieve the codec capabilities for a certain {@code mime type}, {@code 417 * profile} and {@code level}. If the type, or profile-level combination 418 * is not understood by the framework, it returns null. 419 */ 420 public static CodecCapabilities createFromProfileLevel( 421 String mime, int profile, int level) { 422 CodecProfileLevel pl = new CodecProfileLevel(); 423 pl.profile = profile; 424 pl.level = level; 425 MediaFormat defaultFormat = new MediaFormat(); 426 defaultFormat.setString(MediaFormat.KEY_MIME, mime); 427 428 CodecCapabilities ret = new CodecCapabilities( 429 new CodecProfileLevel[] { pl }, new int[0], true /* encoder */, 430 0 /* flags */, defaultFormat, new MediaFormat() /* info */); 431 if (ret.mError != 0) { 432 return null; 433 } 434 return ret; 435 } 436 437 /* package private */ CodecCapabilities( 438 CodecProfileLevel[] profLevs, int[] colFmts, 439 boolean encoder, int flags, 440 Map<String, Object>defaultFormatMap, 441 Map<String, Object>capabilitiesMap) { 442 this(profLevs, colFmts, encoder, flags, 443 new MediaFormat(defaultFormatMap), 444 new MediaFormat(capabilitiesMap)); 445 } 446 447 private MediaFormat mCapabilitiesInfo; 448 449 /* package private */ CodecCapabilities( 450 CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags, 451 MediaFormat defaultFormat, MediaFormat info) { 452 final Map<String, Object> map = info.getMap(); 453 profileLevels = profLevs; 454 colorFormats = colFmts; 455 mFlagsVerified = flags; 456 mDefaultFormat = defaultFormat; 457 mCapabilitiesInfo = info; 458 mMime = mDefaultFormat.getString(MediaFormat.KEY_MIME); 459 460 if (mMime.toLowerCase().startsWith("audio/")) { 461 mAudioCaps = AudioCapabilities.create(info, this); 462 mAudioCaps.setDefaultFormat(mDefaultFormat); 463 } else if (mMime.toLowerCase().startsWith("video/")) { 464 mVideoCaps = VideoCapabilities.create(info, this); 465 } 466 if (encoder) { 467 mEncoderCaps = EncoderCapabilities.create(info, this); 468 mEncoderCaps.setDefaultFormat(mDefaultFormat); 469 } 470 471 for (Feature feat: getValidFeatures()) { 472 String key = MediaFormat.KEY_FEATURE_ + feat.mName; 473 Integer yesNo = (Integer)map.get(key); 474 if (yesNo == null) { 475 continue; 476 } 477 if (yesNo > 0) { 478 mFlagsRequired |= feat.mValue; 479 } 480 mFlagsSupported |= feat.mValue; 481 mDefaultFormat.setInteger(key, 1); 482 // TODO restrict features by mFlagsVerified once all codecs reliably verify them 483 } 484 } 485 } 486 487 /** 488 * A class that supports querying the audio capabilities of a codec. 489 */ 490 public static final class AudioCapabilities { 491 private static final String TAG = "AudioCapabilities"; 492 private CodecCapabilities mParent; 493 private Range<Integer> mBitrateRange; 494 495 private int[] mSampleRates; 496 private Range<Integer>[] mSampleRateRanges; 497 private int mMaxInputChannelCount; 498 499 private static final int MAX_INPUT_CHANNEL_COUNT = 30; 500 501 /** 502 * Returns the range of supported bitrates in bits/second. 503 */ 504 public Range<Integer> getBitrateRange() { 505 return mBitrateRange; 506 } 507 508 /** 509 * Returns the array of supported sample rates if the codec 510 * supports only discrete values. Otherwise, it returns 511 * {@code null}. The array is sorted in ascending order. 512 */ 513 public int[] getSupportedSampleRates() { 514 return Arrays.copyOf(mSampleRates, mSampleRates.length); 515 } 516 517 /** 518 * Returns the array of supported sample rate ranges. The 519 * array is sorted in ascending order, and the ranges are 520 * distinct. 521 */ 522 public Range<Integer>[] getSupportedSampleRateRanges() { 523 return Arrays.copyOf(mSampleRateRanges, mSampleRateRanges.length); 524 } 525 526 /** 527 * Returns the maximum number of input channels supported. The codec 528 * supports any number of channels between 1 and this maximum value. 529 */ 530 public int getMaxInputChannelCount() { 531 return mMaxInputChannelCount; 532 } 533 534 /* no public constructor */ 535 private AudioCapabilities() { } 536 537 /** @hide */ 538 public static AudioCapabilities create( 539 MediaFormat info, CodecCapabilities parent) { 540 AudioCapabilities caps = new AudioCapabilities(); 541 caps.init(info, parent); 542 return caps; 543 } 544 545 /** @hide */ 546 public void init(MediaFormat info, CodecCapabilities parent) { 547 mParent = parent; 548 initWithPlatformLimits(); 549 applyLevelLimits(); 550 parseFromInfo(info); 551 } 552 553 private void initWithPlatformLimits() { 554 mBitrateRange = Range.create(0, Integer.MAX_VALUE); 555 mMaxInputChannelCount = MAX_INPUT_CHANNEL_COUNT; 556 // mBitrateRange = Range.create(1, 320000); 557 mSampleRateRanges = new Range[] { Range.create(8000, 96000) }; 558 mSampleRates = null; 559 } 560 561 private boolean supports(Integer sampleRate, Integer inputChannels) { 562 // channels and sample rates are checked orthogonally 563 if (inputChannels != null && 564 (inputChannels < 1 || inputChannels > mMaxInputChannelCount)) { 565 return false; 566 } 567 if (sampleRate != null) { 568 int ix = Utils.binarySearchDistinctRanges( 569 mSampleRateRanges, sampleRate); 570 if (ix < 0) { 571 return false; 572 } 573 } 574 return true; 575 } 576 577 /** 578 * Query whether the sample rate is supported by the codec. 579 */ 580 public boolean isSampleRateSupported(int sampleRate) { 581 return supports(sampleRate, null); 582 } 583 584 /** modifies rates */ 585 private void limitSampleRates(int[] rates) { 586 Arrays.sort(rates); 587 ArrayList<Range<Integer>> ranges = new ArrayList<Range<Integer>>(); 588 for (int rate: rates) { 589 if (supports(rate, null /* channels */)) { 590 ranges.add(Range.create(rate, rate)); 591 } 592 } 593 mSampleRateRanges = ranges.toArray(new Range[ranges.size()]); 594 createDiscreteSampleRates(); 595 } 596 597 private void createDiscreteSampleRates() { 598 mSampleRates = new int[mSampleRateRanges.length]; 599 for (int i = 0; i < mSampleRateRanges.length; i++) { 600 mSampleRates[i] = mSampleRateRanges[i].getLower(); 601 } 602 } 603 604 /** modifies rateRanges */ 605 private void limitSampleRates(Range<Integer>[] rateRanges) { 606 sortDistinctRanges(rateRanges); 607 mSampleRateRanges = intersectSortedDistinctRanges(mSampleRateRanges, rateRanges); 608 609 // check if all values are discrete 610 for (Range<Integer> range: mSampleRateRanges) { 611 if (!range.getLower().equals(range.getUpper())) { 612 mSampleRates = null; 613 return; 614 } 615 } 616 createDiscreteSampleRates(); 617 } 618 619 private void applyLevelLimits() { 620 int[] sampleRates = null; 621 Range<Integer> sampleRateRange = null, bitRates = null; 622 int maxChannels = 0; 623 String mime = mParent.getMimeType(); 624 625 if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MPEG)) { 626 sampleRates = new int[] { 627 8000, 11025, 12000, 628 16000, 22050, 24000, 629 32000, 44100, 48000 }; 630 bitRates = Range.create(8000, 320000); 631 maxChannels = 2; 632 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)) { 633 sampleRates = new int[] { 8000 }; 634 bitRates = Range.create(4750, 12200); 635 maxChannels = 1; 636 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB)) { 637 sampleRates = new int[] { 16000 }; 638 bitRates = Range.create(6600, 23850); 639 maxChannels = 1; 640 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC)) { 641 sampleRates = new int[] { 642 7350, 8000, 643 11025, 12000, 16000, 644 22050, 24000, 32000, 645 44100, 48000, 64000, 646 88200, 96000 }; 647 bitRates = Range.create(8000, 510000); 648 maxChannels = 48; 649 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_VORBIS)) { 650 bitRates = Range.create(32000, 500000); 651 sampleRates = new int[] { 8000, 12000, 16000, 24000, 48000, 192000 }; 652 maxChannels = 255; 653 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_OPUS)) { 654 bitRates = Range.create(6000, 510000); 655 sampleRates = new int[] { 8000, 12000, 16000, 24000, 48000 }; 656 maxChannels = 255; 657 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW)) { 658 sampleRateRange = Range.create(1, 96000); 659 bitRates = Range.create(1, 10000000); 660 maxChannels = 8; 661 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) { 662 sampleRateRange = Range.create(1, 655350); 663 // lossless codec, so bitrate is ignored 664 maxChannels = 255; 665 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW) 666 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)) { 667 sampleRates = new int[] { 8000 }; 668 bitRates = Range.create(64000, 64000); 669 // platform allows multiple channels for this format 670 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) { 671 sampleRates = new int[] { 8000 }; 672 bitRates = Range.create(13000, 13000); 673 maxChannels = 1; 674 } else { 675 Log.w(TAG, "Unsupported mime " + mime); 676 mParent.mError |= ERROR_UNSUPPORTED; 677 } 678 679 // restrict ranges 680 if (sampleRates != null) { 681 limitSampleRates(sampleRates); 682 } else if (sampleRateRange != null) { 683 limitSampleRates(new Range[] { sampleRateRange }); 684 } 685 applyLimits(maxChannels, bitRates); 686 } 687 688 private void applyLimits(int maxInputChannels, Range<Integer> bitRates) { 689 mMaxInputChannelCount = Range.create(1, mMaxInputChannelCount) 690 .clamp(maxInputChannels); 691 if (bitRates != null) { 692 mBitrateRange = mBitrateRange.intersect(bitRates); 693 } 694 } 695 696 private void parseFromInfo(MediaFormat info) { 697 int maxInputChannels = MAX_INPUT_CHANNEL_COUNT; 698 Range<Integer> bitRates = POSITIVE_INTEGERS; 699 700 if (info.containsKey("sample-rate-ranges")) { 701 String[] rateStrings = info.getString("sample-rate-ranges").split(","); 702 Range<Integer>[] rateRanges = new Range[rateStrings.length]; 703 for (int i = 0; i < rateStrings.length; i++) { 704 rateRanges[i] = Utils.parseIntRange(rateStrings[i], null); 705 } 706 limitSampleRates(rateRanges); 707 } 708 if (info.containsKey("max-channel-count")) { 709 maxInputChannels = Utils.parseIntSafely( 710 info.getString("max-channel-count"), maxInputChannels); 711 } 712 if (info.containsKey("bitrate-range")) { 713 bitRates = bitRates.intersect( 714 Utils.parseIntRange(info.getString("bitrate"), bitRates)); 715 } 716 applyLimits(maxInputChannels, bitRates); 717 } 718 719 /** @hide */ 720 public void setDefaultFormat(MediaFormat format) { 721 // report settings that have only a single choice 722 if (mBitrateRange.getLower().equals(mBitrateRange.getUpper())) { 723 format.setInteger(MediaFormat.KEY_BIT_RATE, mBitrateRange.getLower()); 724 } 725 if (mMaxInputChannelCount == 1) { 726 // mono-only format 727 format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); 728 } 729 if (mSampleRates != null && mSampleRates.length == 1) { 730 format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRates[0]); 731 } 732 } 733 734 /** @hide */ 735 public boolean supportsFormat(MediaFormat format) { 736 Map<String, Object> map = format.getMap(); 737 Integer sampleRate = (Integer)map.get(MediaFormat.KEY_SAMPLE_RATE); 738 Integer channels = (Integer)map.get(MediaFormat.KEY_CHANNEL_COUNT); 739 if (!supports(sampleRate, channels)) { 740 return false; 741 } 742 743 // nothing to do for: 744 // KEY_CHANNEL_MASK: codecs don't get this 745 // KEY_IS_ADTS: required feature for all AAC decoders 746 return true; 747 } 748 } 749 750 /** 751 * A class that supports querying the video capabilities of a codec. 752 */ 753 public static final class VideoCapabilities { 754 private static final String TAG = "VideoCapabilities"; 755 private CodecCapabilities mParent; 756 private Range<Integer> mBitrateRange; 757 758 private Range<Integer> mHeightRange; 759 private Range<Integer> mWidthRange; 760 private Range<Integer> mBlockCountRange; 761 private Range<Integer> mHorizontalBlockRange; 762 private Range<Integer> mVerticalBlockRange; 763 private Range<Rational> mAspectRatioRange; 764 private Range<Rational> mBlockAspectRatioRange; 765 private Range<Long> mBlocksPerSecondRange; 766 private Range<Integer> mFrameRateRange; 767 768 private int mBlockWidth; 769 private int mBlockHeight; 770 private int mWidthAlignment; 771 private int mHeightAlignment; 772 private int mSmallerDimensionUpperLimit; 773 774 /** 775 * Returns the range of supported bitrates in bits/second. 776 */ 777 public Range<Integer> getBitrateRange() { 778 return mBitrateRange; 779 } 780 781 /** 782 * Returns the range of supported video widths. 783 */ 784 public Range<Integer> getSupportedWidths() { 785 return mWidthRange; 786 } 787 788 /** 789 * Returns the range of supported video heights. 790 */ 791 public Range<Integer> getSupportedHeights() { 792 return mHeightRange; 793 } 794 795 /** 796 * Returns the alignment requirement for video width (in pixels). 797 * 798 * This is a power-of-2 value that video width must be a 799 * multiple of. 800 */ 801 public int getWidthAlignment() { 802 return mWidthAlignment; 803 } 804 805 /** 806 * Returns the alignment requirement for video height (in pixels). 807 * 808 * This is a power-of-2 value that video height must be a 809 * multiple of. 810 */ 811 public int getHeightAlignment() { 812 return mHeightAlignment; 813 } 814 815 /** 816 * Return the upper limit on the smaller dimension of width or height. 817 * <p></p> 818 * Some codecs have a limit on the smaller dimension, whether it be 819 * the width or the height. E.g. a codec may only be able to handle 820 * up to 1920x1080 both in landscape and portrait mode (1080x1920). 821 * In this case the maximum width and height are both 1920, but the 822 * smaller dimension limit will be 1080. For other codecs, this is 823 * {@code Math.min(getSupportedWidths().getUpper(), 824 * getSupportedHeights().getUpper())}. 825 * 826 * @hide 827 */ 828 public int getSmallerDimensionUpperLimit() { 829 return mSmallerDimensionUpperLimit; 830 } 831 832 /** 833 * Returns the range of supported frame rates. 834 * <p> 835 * This is not a performance indicator. Rather, it expresses the 836 * limits specified in the coding standard, based on the complexities 837 * of encoding material for later playback at a certain frame rate, 838 * or the decoding of such material in non-realtime. 839 */ 840 public Range<Integer> getSupportedFrameRates() { 841 return mFrameRateRange; 842 } 843 844 /** 845 * Returns the range of supported video widths for a video height. 846 * @param height the height of the video 847 */ 848 public Range<Integer> getSupportedWidthsFor(int height) { 849 try { 850 Range<Integer> range = mWidthRange; 851 if (!mHeightRange.contains(height) 852 || (height % mHeightAlignment) != 0) { 853 throw new IllegalArgumentException("unsupported height"); 854 } 855 final int heightInBlocks = Utils.divUp(height, mBlockHeight); 856 857 // constrain by block count and by block aspect ratio 858 final int minWidthInBlocks = Math.max( 859 Utils.divUp(mBlockCountRange.getLower(), heightInBlocks), 860 (int)Math.ceil(mBlockAspectRatioRange.getLower().doubleValue() 861 * heightInBlocks)); 862 final int maxWidthInBlocks = Math.min( 863 mBlockCountRange.getUpper() / heightInBlocks, 864 (int)(mBlockAspectRatioRange.getUpper().doubleValue() 865 * heightInBlocks)); 866 range = range.intersect( 867 (minWidthInBlocks - 1) * mBlockWidth + mWidthAlignment, 868 maxWidthInBlocks * mBlockWidth); 869 870 // constrain by smaller dimension limit 871 if (height > mSmallerDimensionUpperLimit) { 872 range = range.intersect(1, mSmallerDimensionUpperLimit); 873 } 874 875 // constrain by aspect ratio 876 range = range.intersect( 877 (int)Math.ceil(mAspectRatioRange.getLower().doubleValue() 878 * height), 879 (int)(mAspectRatioRange.getUpper().doubleValue() * height)); 880 return range; 881 } catch (IllegalArgumentException e) { 882 // should not be here 883 Log.w(TAG, "could not get supported widths for " + height , e); 884 throw new IllegalArgumentException("unsupported height"); 885 } 886 } 887 888 /** 889 * Returns the range of supported video heights for a video width 890 * @param width the width of the video 891 */ 892 public Range<Integer> getSupportedHeightsFor(int width) { 893 try { 894 Range<Integer> range = mHeightRange; 895 if (!mWidthRange.contains(width) 896 || (width % mWidthAlignment) != 0) { 897 throw new IllegalArgumentException("unsupported width"); 898 } 899 final int widthInBlocks = Utils.divUp(width, mBlockWidth); 900 901 // constrain by block count and by block aspect ratio 902 final int minHeightInBlocks = Math.max( 903 Utils.divUp(mBlockCountRange.getLower(), widthInBlocks), 904 (int)Math.ceil(widthInBlocks / 905 mBlockAspectRatioRange.getUpper().doubleValue())); 906 final int maxHeightInBlocks = Math.min( 907 mBlockCountRange.getUpper() / widthInBlocks, 908 (int)(widthInBlocks / 909 mBlockAspectRatioRange.getLower().doubleValue())); 910 range = range.intersect( 911 (minHeightInBlocks - 1) * mBlockHeight + mHeightAlignment, 912 maxHeightInBlocks * mBlockHeight); 913 914 // constrain by smaller dimension limit 915 if (width > mSmallerDimensionUpperLimit) { 916 range = range.intersect(1, mSmallerDimensionUpperLimit); 917 } 918 919 // constrain by aspect ratio 920 range = range.intersect( 921 (int)Math.ceil(width / 922 mAspectRatioRange.getUpper().doubleValue()), 923 (int)(width / mAspectRatioRange.getLower().doubleValue())); 924 return range; 925 } catch (IllegalArgumentException e) { 926 // should not be here 927 Log.w(TAG, "could not get supported heights for " + width , e); 928 throw new IllegalArgumentException("unsupported width"); 929 } 930 } 931 932 /** 933 * Returns the range of supported video frame rates for a video size. 934 * <p> 935 * This is not a performance indicator. Rather, it expresses the limits specified in 936 * the coding standard, based on the complexities of encoding material of a given 937 * size for later playback at a certain frame rate, or the decoding of such material 938 * in non-realtime. 939 940 * @param width the width of the video 941 * @param height the height of the video 942 */ 943 public Range<Double> getSupportedFrameRatesFor(int width, int height) { 944 Range<Integer> range = mHeightRange; 945 if (!supports(width, height, null)) { 946 throw new IllegalArgumentException("unsupported size"); 947 } 948 final int blockCount = 949 Utils.divUp(width, mBlockWidth) * Utils.divUp(height, mBlockHeight); 950 951 return Range.create( 952 Math.max(mBlocksPerSecondRange.getLower() / (double) blockCount, 953 (double) mFrameRateRange.getLower()), 954 Math.min(mBlocksPerSecondRange.getUpper() / (double) blockCount, 955 (double) mFrameRateRange.getUpper())); 956 } 957 958 /** 959 * Returns whether a given video size ({@code width} and 960 * {@code height}) and {@code frameRate} combination is supported. 961 */ 962 public boolean areSizeAndRateSupported( 963 int width, int height, double frameRate) { 964 return supports(width, height, frameRate); 965 } 966 967 /** 968 * Returns whether a given video size ({@code width} and 969 * {@code height}) is supported. 970 */ 971 public boolean isSizeSupported(int width, int height) { 972 return supports(width, height, null); 973 } 974 975 private boolean supports( 976 Integer width, Integer height, Double rate) { 977 boolean ok = true; 978 979 if (ok && width != null) { 980 ok = mWidthRange.contains(width) 981 && (width % mWidthAlignment == 0); 982 } 983 if (ok && height != null) { 984 ok = mHeightRange.contains(height) 985 && (height % mHeightAlignment == 0); 986 } 987 if (ok && rate != null) { 988 ok = mFrameRateRange.contains(Utils.intRangeFor(rate)); 989 } 990 if (ok && height != null && width != null) { 991 ok = Math.min(height, width) <= mSmallerDimensionUpperLimit; 992 993 final int widthInBlocks = Utils.divUp(width, mBlockWidth); 994 final int heightInBlocks = Utils.divUp(height, mBlockHeight); 995 final int blockCount = widthInBlocks * heightInBlocks; 996 ok = ok && mBlockCountRange.contains(blockCount) 997 && mBlockAspectRatioRange.contains( 998 new Rational(widthInBlocks, heightInBlocks)) 999 && mAspectRatioRange.contains(new Rational(width, height)); 1000 if (ok && rate != null) { 1001 double blocksPerSec = blockCount * rate; 1002 ok = mBlocksPerSecondRange.contains( 1003 Utils.longRangeFor(blocksPerSec)); 1004 } 1005 } 1006 return ok; 1007 } 1008 1009 /** 1010 * @hide 1011 * @throws java.lang.ClassCastException */ 1012 public boolean supportsFormat(MediaFormat format) { 1013 final Map<String, Object> map = format.getMap(); 1014 Integer width = (Integer)map.get(MediaFormat.KEY_WIDTH); 1015 Integer height = (Integer)map.get(MediaFormat.KEY_HEIGHT); 1016 Double rate = (Double)map.get(MediaFormat.KEY_FRAME_RATE); 1017 1018 // we ignore color-format for now as it is not reliably reported by codec 1019 1020 return supports(width, height, rate); 1021 } 1022 1023 /* no public constructor */ 1024 private VideoCapabilities() { } 1025 1026 /** @hide */ 1027 public static VideoCapabilities create( 1028 MediaFormat info, CodecCapabilities parent) { 1029 VideoCapabilities caps = new VideoCapabilities(); 1030 caps.init(info, parent); 1031 return caps; 1032 } 1033 1034 /** @hide */ 1035 public void init(MediaFormat info, CodecCapabilities parent) { 1036 mParent = parent; 1037 initWithPlatformLimits(); 1038 applyLevelLimits(); 1039 parseFromInfo(info); 1040 updateLimits(); 1041 } 1042 1043 /** @hide */ 1044 public Size getBlockSize() { 1045 return new Size(mBlockWidth, mBlockHeight); 1046 } 1047 1048 /** @hide */ 1049 public Range<Integer> getBlockCountRange() { 1050 return mBlockCountRange; 1051 } 1052 1053 /** @hide */ 1054 public Range<Long> getBlocksPerSecondRange() { 1055 return mBlocksPerSecondRange; 1056 } 1057 1058 /** @hide */ 1059 public Range<Rational> getAspectRatioRange(boolean blocks) { 1060 return blocks ? mBlockAspectRatioRange : mAspectRatioRange; 1061 } 1062 1063 private void initWithPlatformLimits() { 1064 mBitrateRange = Range.create(0, Integer.MAX_VALUE); 1065 1066 mWidthRange = SIZE_RANGE; 1067 mHeightRange = SIZE_RANGE; 1068 mFrameRateRange = FRAME_RATE_RANGE; 1069 1070 mHorizontalBlockRange = SIZE_RANGE; 1071 mVerticalBlockRange = SIZE_RANGE; 1072 1073 // full positive ranges are supported as these get calculated 1074 mBlockCountRange = POSITIVE_INTEGERS; 1075 mBlocksPerSecondRange = POSITIVE_LONGS; 1076 1077 mBlockAspectRatioRange = POSITIVE_RATIONALS; 1078 mAspectRatioRange = POSITIVE_RATIONALS; 1079 1080 // YUV 4:2:0 requires 2:2 alignment 1081 mWidthAlignment = 2; 1082 mHeightAlignment = 2; 1083 mBlockWidth = 2; 1084 mBlockHeight = 2; 1085 mSmallerDimensionUpperLimit = SIZE_RANGE.getUpper(); 1086 } 1087 1088 private void parseFromInfo(MediaFormat info) { 1089 final Map<String, Object> map = info.getMap(); 1090 Size blockSize = new Size(mBlockWidth, mBlockHeight); 1091 Size alignment = new Size(mWidthAlignment, mHeightAlignment); 1092 Range<Integer> counts = null, widths = null, heights = null; 1093 Range<Integer> frameRates = null; 1094 Range<Long> blockRates = null; 1095 Range<Rational> ratios = null, blockRatios = null; 1096 1097 blockSize = Utils.parseSize(map.get("block-size"), blockSize); 1098 alignment = Utils.parseSize(map.get("alignment"), alignment); 1099 counts = Utils.parseIntRange(map.get("block-count-range"), null); 1100 blockRates = 1101 Utils.parseLongRange(map.get("blocks-per-second-range"), null); 1102 { 1103 Object o = map.get("size-range"); 1104 Pair<Size, Size> sizeRange = Utils.parseSizeRange(o); 1105 if (sizeRange != null) { 1106 try { 1107 widths = Range.create( 1108 sizeRange.first.getWidth(), 1109 sizeRange.second.getWidth()); 1110 heights = Range.create( 1111 sizeRange.first.getHeight(), 1112 sizeRange.second.getHeight()); 1113 } catch (IllegalArgumentException e) { 1114 Log.w(TAG, "could not parse size range '" + o + "'"); 1115 widths = null; 1116 heights = null; 1117 } 1118 } 1119 } 1120 // for now this just means using the smaller max size as 2nd 1121 // upper limit. 1122 // for now we are keeping the profile specific "width/height 1123 // in macroblocks" limits. 1124 if (Integer.valueOf(1).equals(map.get("feature-can-swap-width-height"))) { 1125 if (widths != null) { 1126 mSmallerDimensionUpperLimit = 1127 Math.min(widths.getUpper(), heights.getUpper()); 1128 widths = heights = widths.extend(heights); 1129 } else { 1130 Log.w(TAG, "feature can-swap-width-height is best used with size-range"); 1131 mSmallerDimensionUpperLimit = 1132 Math.min(mWidthRange.getUpper(), mHeightRange.getUpper()); 1133 mWidthRange = mHeightRange = mWidthRange.extend(mHeightRange); 1134 } 1135 } 1136 1137 ratios = Utils.parseRationalRange( 1138 map.get("block-aspect-ratio-range"), null); 1139 blockRatios = Utils.parseRationalRange( 1140 map.get("pixel-aspect-ratio-range"), null); 1141 frameRates = Utils.parseIntRange(map.get("frame-rate-range"), null); 1142 if (frameRates != null) { 1143 try { 1144 frameRates = frameRates.intersect(FRAME_RATE_RANGE); 1145 } catch (IllegalArgumentException e) { 1146 Log.w(TAG, "frame rate range (" + frameRates 1147 + ") is out of limits: " + FRAME_RATE_RANGE); 1148 frameRates = null; 1149 } 1150 } 1151 1152 checkPowerOfTwo( 1153 blockSize.getWidth(), "block-size width must be power of two"); 1154 checkPowerOfTwo( 1155 blockSize.getHeight(), "block-size height must be power of two"); 1156 1157 checkPowerOfTwo( 1158 alignment.getWidth(), "alignment width must be power of two"); 1159 checkPowerOfTwo( 1160 alignment.getHeight(), "alignment height must be power of two"); 1161 1162 // update block-size and alignment 1163 applyMacroBlockLimits( 1164 Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, 1165 Long.MAX_VALUE, blockSize.getWidth(), blockSize.getHeight(), 1166 alignment.getWidth(), alignment.getHeight()); 1167 1168 if ((mParent.mError & ERROR_UNSUPPORTED) != 0) { 1169 // codec supports profiles that we don't know. 1170 // Use supplied values clipped to platform limits 1171 if (widths != null) { 1172 mWidthRange = SIZE_RANGE.intersect(widths); 1173 } 1174 if (heights != null) { 1175 mHeightRange = SIZE_RANGE.intersect(heights); 1176 } 1177 if (counts != null) { 1178 mBlockCountRange = POSITIVE_INTEGERS.intersect( 1179 Utils.factorRange(counts, mBlockWidth * mBlockHeight 1180 / blockSize.getWidth() / blockSize.getHeight())); 1181 } 1182 if (blockRates != null) { 1183 mBlocksPerSecondRange = POSITIVE_LONGS.intersect( 1184 Utils.factorRange(blockRates, mBlockWidth * mBlockHeight 1185 / blockSize.getWidth() / blockSize.getHeight())); 1186 } 1187 if (blockRatios != null) { 1188 mBlockAspectRatioRange = POSITIVE_RATIONALS.intersect( 1189 Utils.scaleRange(blockRatios, 1190 mBlockHeight / blockSize.getHeight(), 1191 mBlockWidth / blockSize.getWidth())); 1192 } 1193 if (ratios != null) { 1194 mAspectRatioRange = POSITIVE_RATIONALS.intersect(ratios); 1195 } 1196 if (frameRates != null) { 1197 mFrameRateRange = FRAME_RATE_RANGE.intersect(frameRates); 1198 } 1199 } else { 1200 // no unsupported profile/levels, so restrict values to known limits 1201 if (widths != null) { 1202 mWidthRange = mWidthRange.intersect(widths); 1203 } 1204 if (heights != null) { 1205 mHeightRange = mHeightRange.intersect(heights); 1206 } 1207 if (counts != null) { 1208 mBlockCountRange = mBlockCountRange.intersect( 1209 Utils.factorRange(counts, mBlockWidth * mBlockHeight 1210 / blockSize.getWidth() / blockSize.getHeight())); 1211 } 1212 if (blockRates != null) { 1213 mBlocksPerSecondRange = mBlocksPerSecondRange.intersect( 1214 Utils.factorRange(blockRates, mBlockWidth * mBlockHeight 1215 / blockSize.getWidth() / blockSize.getHeight())); 1216 } 1217 if (blockRatios != null) { 1218 mBlockAspectRatioRange = mBlockAspectRatioRange.intersect( 1219 Utils.scaleRange(blockRatios, 1220 mBlockHeight / blockSize.getHeight(), 1221 mBlockWidth / blockSize.getWidth())); 1222 } 1223 if (ratios != null) { 1224 mAspectRatioRange = mAspectRatioRange.intersect(ratios); 1225 } 1226 if (frameRates != null) { 1227 mFrameRateRange = mFrameRateRange.intersect(frameRates); 1228 } 1229 } 1230 updateLimits(); 1231 } 1232 1233 private void applyBlockLimits( 1234 int blockWidth, int blockHeight, 1235 Range<Integer> counts, Range<Long> rates, Range<Rational> ratios) { 1236 checkPowerOfTwo(blockWidth, "blockWidth must be a power of two"); 1237 checkPowerOfTwo(blockHeight, "blockHeight must be a power of two"); 1238 1239 final int newBlockWidth = Math.max(blockWidth, mBlockWidth); 1240 final int newBlockHeight = Math.max(blockHeight, mBlockHeight); 1241 1242 // factor will always be a power-of-2 1243 int factor = 1244 newBlockWidth * newBlockHeight / mBlockWidth / mBlockHeight; 1245 if (factor != 1) { 1246 mBlockCountRange = Utils.factorRange(mBlockCountRange, factor); 1247 mBlocksPerSecondRange = Utils.factorRange( 1248 mBlocksPerSecondRange, factor); 1249 mBlockAspectRatioRange = Utils.scaleRange( 1250 mBlockAspectRatioRange, 1251 newBlockHeight / mBlockHeight, 1252 newBlockWidth / mBlockWidth); 1253 mHorizontalBlockRange = Utils.factorRange( 1254 mHorizontalBlockRange, newBlockWidth / mBlockWidth); 1255 mVerticalBlockRange = Utils.factorRange( 1256 mVerticalBlockRange, newBlockHeight / mBlockHeight); 1257 } 1258 factor = newBlockWidth * newBlockHeight / blockWidth / blockHeight; 1259 if (factor != 1) { 1260 counts = Utils.factorRange(counts, factor); 1261 rates = Utils.factorRange(rates, factor); 1262 ratios = Utils.scaleRange( 1263 ratios, newBlockHeight / blockHeight, 1264 newBlockWidth / blockWidth); 1265 } 1266 mBlockCountRange = mBlockCountRange.intersect(counts); 1267 mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(rates); 1268 mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(ratios); 1269 mBlockWidth = newBlockWidth; 1270 mBlockHeight = newBlockHeight; 1271 } 1272 1273 private void applyAlignment(int widthAlignment, int heightAlignment) { 1274 checkPowerOfTwo(widthAlignment, "widthAlignment must be a power of two"); 1275 checkPowerOfTwo(heightAlignment, "heightAlignment must be a power of two"); 1276 1277 if (widthAlignment > mBlockWidth || heightAlignment > mBlockHeight) { 1278 // maintain assumption that 0 < alignment <= block-size 1279 applyBlockLimits( 1280 Math.max(widthAlignment, mBlockWidth), 1281 Math.max(heightAlignment, mBlockHeight), 1282 POSITIVE_INTEGERS, POSITIVE_LONGS, POSITIVE_RATIONALS); 1283 } 1284 1285 mWidthAlignment = Math.max(widthAlignment, mWidthAlignment); 1286 mHeightAlignment = Math.max(heightAlignment, mHeightAlignment); 1287 1288 mWidthRange = Utils.alignRange(mWidthRange, mWidthAlignment); 1289 mHeightRange = Utils.alignRange(mHeightRange, mHeightAlignment); 1290 } 1291 1292 private void updateLimits() { 1293 // pixels -> blocks <- counts 1294 mHorizontalBlockRange = mHorizontalBlockRange.intersect( 1295 Utils.factorRange(mWidthRange, mBlockWidth)); 1296 mHorizontalBlockRange = mHorizontalBlockRange.intersect( 1297 Range.create( 1298 mBlockCountRange.getLower() / mVerticalBlockRange.getUpper(), 1299 mBlockCountRange.getUpper() / mVerticalBlockRange.getLower())); 1300 mVerticalBlockRange = mVerticalBlockRange.intersect( 1301 Utils.factorRange(mHeightRange, mBlockHeight)); 1302 mVerticalBlockRange = mVerticalBlockRange.intersect( 1303 Range.create( 1304 mBlockCountRange.getLower() / mHorizontalBlockRange.getUpper(), 1305 mBlockCountRange.getUpper() / mHorizontalBlockRange.getLower())); 1306 mBlockCountRange = mBlockCountRange.intersect( 1307 Range.create( 1308 mHorizontalBlockRange.getLower() 1309 * mVerticalBlockRange.getLower(), 1310 mHorizontalBlockRange.getUpper() 1311 * mVerticalBlockRange.getUpper())); 1312 mBlockAspectRatioRange = mBlockAspectRatioRange.intersect( 1313 new Rational( 1314 mHorizontalBlockRange.getLower(), mVerticalBlockRange.getUpper()), 1315 new Rational( 1316 mHorizontalBlockRange.getUpper(), mVerticalBlockRange.getLower())); 1317 1318 // blocks -> pixels 1319 mWidthRange = mWidthRange.intersect( 1320 (mHorizontalBlockRange.getLower() - 1) * mBlockWidth + mWidthAlignment, 1321 mHorizontalBlockRange.getUpper() * mBlockWidth); 1322 mHeightRange = mHeightRange.intersect( 1323 (mVerticalBlockRange.getLower() - 1) * mBlockHeight + mHeightAlignment, 1324 mVerticalBlockRange.getUpper() * mBlockHeight); 1325 mAspectRatioRange = mAspectRatioRange.intersect( 1326 new Rational(mWidthRange.getLower(), mHeightRange.getUpper()), 1327 new Rational(mWidthRange.getUpper(), mHeightRange.getLower())); 1328 1329 mSmallerDimensionUpperLimit = Math.min( 1330 mSmallerDimensionUpperLimit, 1331 Math.min(mWidthRange.getUpper(), mHeightRange.getUpper())); 1332 1333 // blocks -> rate 1334 mBlocksPerSecondRange = mBlocksPerSecondRange.intersect( 1335 mBlockCountRange.getLower() * (long)mFrameRateRange.getLower(), 1336 mBlockCountRange.getUpper() * (long)mFrameRateRange.getUpper()); 1337 mFrameRateRange = mFrameRateRange.intersect( 1338 (int)(mBlocksPerSecondRange.getLower() 1339 / mBlockCountRange.getUpper()), 1340 (int)(mBlocksPerSecondRange.getUpper() 1341 / (double)mBlockCountRange.getLower())); 1342 } 1343 1344 private void applyMacroBlockLimits( 1345 int maxHorizontalBlocks, int maxVerticalBlocks, 1346 int maxBlocks, long maxBlocksPerSecond, 1347 int blockWidth, int blockHeight, 1348 int widthAlignment, int heightAlignment) { 1349 applyAlignment(widthAlignment, heightAlignment); 1350 applyBlockLimits( 1351 blockWidth, blockHeight, Range.create(1, maxBlocks), 1352 Range.create(1L, maxBlocksPerSecond), 1353 Range.create( 1354 new Rational(1, maxVerticalBlocks), 1355 new Rational(maxHorizontalBlocks, 1))); 1356 mHorizontalBlockRange = 1357 mHorizontalBlockRange.intersect( 1358 1, maxHorizontalBlocks / (mBlockWidth / blockWidth)); 1359 mVerticalBlockRange = 1360 mVerticalBlockRange.intersect( 1361 1, maxVerticalBlocks / (mBlockHeight / blockHeight)); 1362 } 1363 1364 private void applyLevelLimits() { 1365 int maxBlocksPerSecond = 0; 1366 int maxBlocks = 0; 1367 int maxBps = 0; 1368 int maxDPBBlocks = 0; 1369 1370 int errors = ERROR_NONE_SUPPORTED; 1371 CodecProfileLevel[] profileLevels = mParent.profileLevels; 1372 String mime = mParent.getMimeType(); 1373 1374 if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC)) { 1375 maxBlocks = 99; 1376 maxBlocksPerSecond = 1485; 1377 maxBps = 64000; 1378 maxDPBBlocks = 396; 1379 for (CodecProfileLevel profileLevel: profileLevels) { 1380 int MBPS = 0, FS = 0, BR = 0, DPB = 0; 1381 boolean supported = true; 1382 switch (profileLevel.level) { 1383 case CodecProfileLevel.AVCLevel1: 1384 MBPS = 1485; FS = 99; BR = 64; DPB = 396; break; 1385 case CodecProfileLevel.AVCLevel1b: 1386 MBPS = 1485; FS = 99; BR = 128; DPB = 396; break; 1387 case CodecProfileLevel.AVCLevel11: 1388 MBPS = 3000; FS = 396; BR = 192; DPB = 900; break; 1389 case CodecProfileLevel.AVCLevel12: 1390 MBPS = 6000; FS = 396; BR = 384; DPB = 2376; break; 1391 case CodecProfileLevel.AVCLevel13: 1392 MBPS = 11880; FS = 396; BR = 768; DPB = 2376; break; 1393 case CodecProfileLevel.AVCLevel2: 1394 MBPS = 11880; FS = 396; BR = 2000; DPB = 2376; break; 1395 case CodecProfileLevel.AVCLevel21: 1396 MBPS = 19800; FS = 792; BR = 4000; DPB = 4752; break; 1397 case CodecProfileLevel.AVCLevel22: 1398 MBPS = 20250; FS = 1620; BR = 4000; DPB = 8100; break; 1399 case CodecProfileLevel.AVCLevel3: 1400 MBPS = 40500; FS = 1620; BR = 10000; DPB = 8100; break; 1401 case CodecProfileLevel.AVCLevel31: 1402 MBPS = 108000; FS = 3600; BR = 14000; DPB = 18000; break; 1403 case CodecProfileLevel.AVCLevel32: 1404 MBPS = 216000; FS = 5120; BR = 20000; DPB = 20480; break; 1405 case CodecProfileLevel.AVCLevel4: 1406 MBPS = 245760; FS = 8192; BR = 20000; DPB = 32768; break; 1407 case CodecProfileLevel.AVCLevel41: 1408 MBPS = 245760; FS = 8192; BR = 50000; DPB = 32768; break; 1409 case CodecProfileLevel.AVCLevel42: 1410 MBPS = 522240; FS = 8704; BR = 50000; DPB = 34816; break; 1411 case CodecProfileLevel.AVCLevel5: 1412 MBPS = 589824; FS = 22080; BR = 135000; DPB = 110400; break; 1413 case CodecProfileLevel.AVCLevel51: 1414 MBPS = 983040; FS = 36864; BR = 240000; DPB = 184320; break; 1415 case CodecProfileLevel.AVCLevel52: 1416 MBPS = 2073600; FS = 36864; BR = 240000; DPB = 184320; break; 1417 default: 1418 Log.w(TAG, "Unrecognized level " 1419 + profileLevel.level + " for " + mime); 1420 errors |= ERROR_UNRECOGNIZED; 1421 } 1422 switch (profileLevel.profile) { 1423 case CodecProfileLevel.AVCProfileHigh: 1424 BR *= 1250; break; 1425 case CodecProfileLevel.AVCProfileHigh10: 1426 BR *= 3000; break; 1427 case CodecProfileLevel.AVCProfileExtended: 1428 case CodecProfileLevel.AVCProfileHigh422: 1429 case CodecProfileLevel.AVCProfileHigh444: 1430 Log.w(TAG, "Unsupported profile " 1431 + profileLevel.profile + " for " + mime); 1432 errors |= ERROR_UNSUPPORTED; 1433 supported = false; 1434 // fall through - treat as base profile 1435 case CodecProfileLevel.AVCProfileBaseline: 1436 case CodecProfileLevel.AVCProfileMain: 1437 BR *= 1000; break; 1438 default: 1439 Log.w(TAG, "Unrecognized profile " 1440 + profileLevel.profile + " for " + mime); 1441 errors |= ERROR_UNRECOGNIZED; 1442 BR *= 1000; 1443 } 1444 if (supported) { 1445 errors &= ~ERROR_NONE_SUPPORTED; 1446 } 1447 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); 1448 maxBlocks = Math.max(FS, maxBlocks); 1449 maxBps = Math.max(BR, maxBps); 1450 maxDPBBlocks = Math.max(maxDPBBlocks, DPB); 1451 } 1452 1453 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8)); 1454 applyMacroBlockLimits( 1455 maxLengthInBlocks, maxLengthInBlocks, 1456 maxBlocks, maxBlocksPerSecond, 1457 16 /* blockWidth */, 16 /* blockHeight */, 1458 1 /* widthAlignment */, 1 /* heightAlignment */); 1459 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) { 1460 int maxWidth = 11, maxHeight = 9, maxRate = 15; 1461 maxBlocks = 99; 1462 maxBlocksPerSecond = 1485; 1463 maxBps = 64000; 1464 for (CodecProfileLevel profileLevel: profileLevels) { 1465 int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0; 1466 boolean supported = true; 1467 switch (profileLevel.profile) { 1468 case CodecProfileLevel.MPEG4ProfileSimple: 1469 switch (profileLevel.level) { 1470 case CodecProfileLevel.MPEG4Level0: 1471 FR = 15; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 64; break; 1472 case CodecProfileLevel.MPEG4Level1: 1473 FR = 30; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 64; break; 1474 case CodecProfileLevel.MPEG4Level0b: 1475 FR = 30; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 128; break; 1476 case CodecProfileLevel.MPEG4Level2: 1477 FR = 30; W = 22; H = 18; MBPS = 5940; FS = 396; BR = 128; break; 1478 case CodecProfileLevel.MPEG4Level3: 1479 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384; break; 1480 case CodecProfileLevel.MPEG4Level4: 1481 case CodecProfileLevel.MPEG4Level4a: 1482 case CodecProfileLevel.MPEG4Level5: 1483 // While MPEG4 SP does not have level 4 or 5, some vendors 1484 // report it. Use the same limits as level 3, but mark as 1485 // unsupported. 1486 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384; 1487 supported = false; 1488 break; 1489 default: 1490 Log.w(TAG, "Unrecognized profile/level " 1491 + profileLevel.profile + "/" 1492 + profileLevel.level + " for " + mime); 1493 errors |= ERROR_UNRECOGNIZED; 1494 } 1495 break; 1496 case CodecProfileLevel.MPEG4ProfileAdvancedSimple: 1497 switch (profileLevel.level) { 1498 case CodecProfileLevel.MPEG4Level0: 1499 case CodecProfileLevel.MPEG4Level1: 1500 FR = 30; W = 11; H = 9; MBPS = 2970; FS = 99; BR = 128; break; 1501 case CodecProfileLevel.MPEG4Level2: 1502 FR = 30; W = 22; H = 18; MBPS = 5940; FS = 396; BR = 384; break; 1503 case CodecProfileLevel.MPEG4Level3: 1504 FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 768; break; 1505 // case CodecProfileLevel.MPEG4Level3b: 1506 // TODO: MPEG4 level 3b is not defined in OMX 1507 // MBPS = 11880; FS = 396; BR = 1500; break; 1508 case CodecProfileLevel.MPEG4Level4: 1509 case CodecProfileLevel.MPEG4Level4a: 1510 // TODO: MPEG4 level 4a is not defined in spec 1511 FR = 30; W = 44; H = 36; MBPS = 23760; FS = 792; BR = 3000; break; 1512 case CodecProfileLevel.MPEG4Level5: 1513 FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 8000; break; 1514 default: 1515 Log.w(TAG, "Unrecognized profile/level " 1516 + profileLevel.profile + "/" 1517 + profileLevel.level + " for " + mime); 1518 errors |= ERROR_UNRECOGNIZED; 1519 } 1520 break; 1521 case CodecProfileLevel.MPEG4ProfileMain: // 2-4 1522 case CodecProfileLevel.MPEG4ProfileNbit: // 2 1523 case CodecProfileLevel.MPEG4ProfileAdvancedRealTime: // 1-4 1524 case CodecProfileLevel.MPEG4ProfileCoreScalable: // 1-3 1525 case CodecProfileLevel.MPEG4ProfileAdvancedCoding: // 1-4 1526 case CodecProfileLevel.MPEG4ProfileCore: // 1-2 1527 case CodecProfileLevel.MPEG4ProfileAdvancedCore: // 1-4 1528 case CodecProfileLevel.MPEG4ProfileSimpleScalable: // 0-2 1529 case CodecProfileLevel.MPEG4ProfileAdvancedScalable: // 1-3 1530 case CodecProfileLevel.MPEG4ProfileHybrid: // 1-2 1531 case CodecProfileLevel.MPEG4ProfileBasicAnimated: // 1-2 1532 case CodecProfileLevel.MPEG4ProfileScalableTexture: // 1 1533 case CodecProfileLevel.MPEG4ProfileSimpleFace: // 1-2 1534 case CodecProfileLevel.MPEG4ProfileSimpleFBA: // 1-2 1535 Log.i(TAG, "Unsupported profile " 1536 + profileLevel.profile + " for " + mime); 1537 errors |= ERROR_UNSUPPORTED; 1538 supported = false; 1539 break; 1540 default: 1541 Log.w(TAG, "Unrecognized profile " 1542 + profileLevel.profile + " for " + mime); 1543 errors |= ERROR_UNRECOGNIZED; 1544 } 1545 if (supported) { 1546 errors &= ~ERROR_NONE_SUPPORTED; 1547 } 1548 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); 1549 maxBlocks = Math.max(FS, maxBlocks); 1550 maxBps = Math.max(BR * 1000, maxBps); 1551 maxWidth = Math.max(W, maxWidth); 1552 maxHeight = Math.max(H, maxHeight); 1553 maxRate = Math.max(FR, maxRate); 1554 } 1555 applyMacroBlockLimits(maxWidth, maxHeight, 1556 maxBlocks, maxBlocksPerSecond, 1557 16 /* blockWidth */, 16 /* blockHeight */, 1558 1 /* widthAlignment */, 1 /* heightAlignment */); 1559 mFrameRateRange = mFrameRateRange.intersect(12, maxRate); 1560 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) { 1561 int maxWidth = 11, maxHeight = 9, maxRate = 15; 1562 maxBlocks = 99; 1563 maxBlocksPerSecond = 1485; 1564 maxBps = 64000; 1565 for (CodecProfileLevel profileLevel: profileLevels) { 1566 int MBPS = 0, BR = 0, FR = 0, W = 0, H = 0; 1567 switch (profileLevel.level) { 1568 case CodecProfileLevel.H263Level10: 1569 FR = 15; W = 11; H = 9; BR = 1; MBPS = W * H * FR; break; 1570 case CodecProfileLevel.H263Level20: 1571 // only supports CIF, 0..QCIF 1572 FR = 30; W = 22; H = 18; BR = 2; MBPS = W * H * FR; break; 1573 case CodecProfileLevel.H263Level30: 1574 // only supports CIF, 0..QCIF 1575 FR = 30; W = 22; H = 18; BR = 6; MBPS = W * H * FR; break; 1576 case CodecProfileLevel.H263Level40: 1577 // only supports CIF, 0..QCIF 1578 FR = 30; W = 22; H = 18; BR = 32; MBPS = W * H * FR; break; 1579 case CodecProfileLevel.H263Level45: 1580 // only implies level 10 support 1581 FR = 30; W = 11; H = 9; BR = 2; MBPS = W * H * FR; break; 1582 case CodecProfileLevel.H263Level50: 1583 // only supports 50fps for H > 15 1584 FR = 60; W = 22; H = 18; BR = 64; MBPS = W * H * 50; break; 1585 case CodecProfileLevel.H263Level60: 1586 // only supports 50fps for H > 15 1587 FR = 60; W = 45; H = 18; BR = 128; MBPS = W * H * 50; break; 1588 case CodecProfileLevel.H263Level70: 1589 // only supports 50fps for H > 30 1590 FR = 60; W = 45; H = 36; BR = 256; MBPS = W * H * 50; break; 1591 default: 1592 Log.w(TAG, "Unrecognized profile/level " + profileLevel.profile 1593 + "/" + profileLevel.level + " for " + mime); 1594 errors |= ERROR_UNRECOGNIZED; 1595 } 1596 switch (profileLevel.profile) { 1597 case CodecProfileLevel.H263ProfileBackwardCompatible: 1598 case CodecProfileLevel.H263ProfileBaseline: 1599 case CodecProfileLevel.H263ProfileH320Coding: 1600 case CodecProfileLevel.H263ProfileHighCompression: 1601 case CodecProfileLevel.H263ProfileHighLatency: 1602 case CodecProfileLevel.H263ProfileInterlace: 1603 case CodecProfileLevel.H263ProfileInternet: 1604 case CodecProfileLevel.H263ProfileISWV2: 1605 case CodecProfileLevel.H263ProfileISWV3: 1606 break; 1607 default: 1608 Log.w(TAG, "Unrecognized profile " 1609 + profileLevel.profile + " for " + mime); 1610 errors |= ERROR_UNRECOGNIZED; 1611 } 1612 errors &= ~ERROR_NONE_SUPPORTED; 1613 maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); 1614 maxBlocks = Math.max(W * H, maxBlocks); 1615 maxBps = Math.max(BR * 64000, maxBps); 1616 maxWidth = Math.max(W, maxWidth); 1617 maxHeight = Math.max(H, maxHeight); 1618 maxRate = Math.max(FR, maxRate); 1619 } 1620 applyMacroBlockLimits(maxWidth, maxHeight, 1621 maxBlocks, maxBlocksPerSecond, 1622 16 /* blockWidth */, 16 /* blockHeight */, 1623 1 /* widthAlignment */, 1 /* heightAlignment */); 1624 mFrameRateRange = Range.create(1, maxRate); 1625 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8) || 1626 mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) { 1627 maxBlocks = maxBlocksPerSecond = Integer.MAX_VALUE; 1628 1629 // TODO: set to 100Mbps for now, need a number for VPX 1630 maxBps = 100000000; 1631 1632 // profile levels are not indicative for VPx, but verify 1633 // them nonetheless 1634 for (CodecProfileLevel profileLevel: profileLevels) { 1635 switch (profileLevel.level) { 1636 case CodecProfileLevel.VP8Level_Version0: 1637 case CodecProfileLevel.VP8Level_Version1: 1638 case CodecProfileLevel.VP8Level_Version2: 1639 case CodecProfileLevel.VP8Level_Version3: 1640 break; 1641 default: 1642 Log.w(TAG, "Unrecognized level " 1643 + profileLevel.level + " for " + mime); 1644 errors |= ERROR_UNRECOGNIZED; 1645 } 1646 switch (profileLevel.profile) { 1647 case CodecProfileLevel.VP8ProfileMain: 1648 break; 1649 default: 1650 Log.w(TAG, "Unrecognized profile " 1651 + profileLevel.profile + " for " + mime); 1652 errors |= ERROR_UNRECOGNIZED; 1653 } 1654 errors &= ~ERROR_NONE_SUPPORTED; 1655 } 1656 1657 final int blockSize = 1658 mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8) ? 16 : 8; 1659 applyMacroBlockLimits(Short.MAX_VALUE, Short.MAX_VALUE, 1660 maxBlocks, maxBlocksPerSecond, blockSize, blockSize, 1661 1 /* widthAlignment */, 1 /* heightAlignment */); 1662 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) { 1663 maxBlocks = 36864; 1664 maxBlocksPerSecond = maxBlocks * 15; 1665 maxBps = 128000; 1666 for (CodecProfileLevel profileLevel: profileLevels) { 1667 double FR = 0; 1668 int FS = 0; 1669 int BR = 0; 1670 switch (profileLevel.level) { 1671 case CodecProfileLevel.HEVCMainTierLevel1: 1672 case CodecProfileLevel.HEVCHighTierLevel1: 1673 FR = 15; FS = 36864; BR = 128; break; 1674 case CodecProfileLevel.HEVCMainTierLevel2: 1675 case CodecProfileLevel.HEVCHighTierLevel2: 1676 FR = 30; FS = 122880; BR = 1500; break; 1677 case CodecProfileLevel.HEVCMainTierLevel21: 1678 case CodecProfileLevel.HEVCHighTierLevel21: 1679 FR = 30; FS = 245760; BR = 3000; break; 1680 case CodecProfileLevel.HEVCMainTierLevel3: 1681 case CodecProfileLevel.HEVCHighTierLevel3: 1682 FR = 30; FS = 552960; BR = 6000; break; 1683 case CodecProfileLevel.HEVCMainTierLevel31: 1684 case CodecProfileLevel.HEVCHighTierLevel31: 1685 FR = 33.75; FS = 983040; BR = 10000; break; 1686 case CodecProfileLevel.HEVCMainTierLevel4: 1687 FR = 30; FS = 2228224; BR = 12000; break; 1688 case CodecProfileLevel.HEVCHighTierLevel4: 1689 FR = 30; FS = 2228224; BR = 30000; break; 1690 case CodecProfileLevel.HEVCMainTierLevel41: 1691 FR = 60; FS = 2228224; BR = 20000; break; 1692 case CodecProfileLevel.HEVCHighTierLevel41: 1693 FR = 60; FS = 2228224; BR = 50000; break; 1694 case CodecProfileLevel.HEVCMainTierLevel5: 1695 FR = 30; FS = 8912896; BR = 25000; break; 1696 case CodecProfileLevel.HEVCHighTierLevel5: 1697 FR = 30; FS = 8912896; BR = 100000; break; 1698 case CodecProfileLevel.HEVCMainTierLevel51: 1699 FR = 60; FS = 8912896; BR = 40000; break; 1700 case CodecProfileLevel.HEVCHighTierLevel51: 1701 FR = 60; FS = 8912896; BR = 160000; break; 1702 case CodecProfileLevel.HEVCMainTierLevel52: 1703 FR = 120; FS = 8912896; BR = 60000; break; 1704 case CodecProfileLevel.HEVCHighTierLevel52: 1705 FR = 120; FS = 8912896; BR = 240000; break; 1706 case CodecProfileLevel.HEVCMainTierLevel6: 1707 FR = 30; FS = 35651584; BR = 60000; break; 1708 case CodecProfileLevel.HEVCHighTierLevel6: 1709 FR = 30; FS = 35651584; BR = 240000; break; 1710 case CodecProfileLevel.HEVCMainTierLevel61: 1711 FR = 60; FS = 35651584; BR = 120000; break; 1712 case CodecProfileLevel.HEVCHighTierLevel61: 1713 FR = 60; FS = 35651584; BR = 480000; break; 1714 case CodecProfileLevel.HEVCMainTierLevel62: 1715 FR = 120; FS = 35651584; BR = 240000; break; 1716 case CodecProfileLevel.HEVCHighTierLevel62: 1717 FR = 120; FS = 35651584; BR = 800000; break; 1718 default: 1719 Log.w(TAG, "Unrecognized level " 1720 + profileLevel.level + " for " + mime); 1721 errors |= ERROR_UNRECOGNIZED; 1722 } 1723 switch (profileLevel.profile) { 1724 case CodecProfileLevel.HEVCProfileMain: 1725 case CodecProfileLevel.HEVCProfileMain10: 1726 break; 1727 default: 1728 Log.w(TAG, "Unrecognized profile " 1729 + profileLevel.profile + " for " + mime); 1730 errors |= ERROR_UNRECOGNIZED; 1731 } 1732 1733 /* DPB logic: 1734 if (width * height <= FS / 4) DPB = 16; 1735 else if (width * height <= FS / 2) DPB = 12; 1736 else if (width * height <= FS * 0.75) DPB = 8; 1737 else DPB = 6; 1738 */ 1739 1740 errors &= ~ERROR_NONE_SUPPORTED; 1741 maxBlocksPerSecond = Math.max((int)(FR * FS), maxBlocksPerSecond); 1742 maxBlocks = Math.max(FS, maxBlocks); 1743 maxBps = Math.max(BR * 1000, maxBps); 1744 } 1745 1746 int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8)); 1747 // CTBs are at least 8x8 1748 maxBlocks = Utils.divUp(maxBlocks, 8 * 8); 1749 maxBlocksPerSecond = Utils.divUp(maxBlocksPerSecond, 8 * 8); 1750 maxLengthInBlocks = Utils.divUp(maxLengthInBlocks, 8); 1751 1752 applyMacroBlockLimits( 1753 maxLengthInBlocks, maxLengthInBlocks, 1754 maxBlocks, maxBlocksPerSecond, 1755 8 /* blockWidth */, 8 /* blockHeight */, 1756 1 /* widthAlignment */, 1 /* heightAlignment */); 1757 } else { 1758 Log.w(TAG, "Unsupported mime " + mime); 1759 // using minimal bitrate here. should be overriden by 1760 // info from media_codecs.xml 1761 maxBps = 64000; 1762 errors |= ERROR_UNSUPPORTED; 1763 } 1764 mBitrateRange = Range.create(1, maxBps); 1765 mParent.mError |= errors; 1766 } 1767 } 1768 1769 /** 1770 * A class that supports querying the encoding capabilities of a codec. 1771 */ 1772 public static final class EncoderCapabilities { 1773 /** 1774 * Returns the supported range of quality values. 1775 * 1776 * @hide 1777 */ 1778 public Range<Integer> getQualityRange() { 1779 return mQualityRange; 1780 } 1781 1782 /** 1783 * Returns the supported range of encoder complexity values. 1784 * <p> 1785 * Some codecs may support multiple complexity levels, where higher 1786 * complexity values use more encoder tools (e.g. perform more 1787 * intensive calculations) to improve the quality or the compression 1788 * ratio. Use a lower value to save power and/or time. 1789 */ 1790 public Range<Integer> getComplexityRange() { 1791 return mComplexityRange; 1792 } 1793 1794 /** Constant quality mode */ 1795 public static final int BITRATE_MODE_CQ = 0; 1796 /** Variable bitrate mode */ 1797 public static final int BITRATE_MODE_VBR = 1; 1798 /** Constant bitrate mode */ 1799 public static final int BITRATE_MODE_CBR = 2; 1800 1801 private static final Feature[] bitrates = new Feature[] { 1802 new Feature("VBR", BITRATE_MODE_VBR, true), 1803 new Feature("CBR", BITRATE_MODE_CBR, false), 1804 new Feature("CQ", BITRATE_MODE_CQ, false) 1805 }; 1806 1807 private static int parseBitrateMode(String mode) { 1808 for (Feature feat: bitrates) { 1809 if (feat.mName.equalsIgnoreCase(mode)) { 1810 return feat.mValue; 1811 } 1812 } 1813 return 0; 1814 } 1815 1816 /** 1817 * Query whether a bitrate mode is supported. 1818 */ 1819 public boolean isBitrateModeSupported(int mode) { 1820 for (Feature feat: bitrates) { 1821 if (mode == feat.mValue) { 1822 return (mBitControl & (1 << mode)) != 0; 1823 } 1824 } 1825 return false; 1826 } 1827 1828 private Range<Integer> mQualityRange; 1829 private Range<Integer> mComplexityRange; 1830 private CodecCapabilities mParent; 1831 1832 /* no public constructor */ 1833 private EncoderCapabilities() { } 1834 1835 /** @hide */ 1836 public static EncoderCapabilities create( 1837 MediaFormat info, CodecCapabilities parent) { 1838 EncoderCapabilities caps = new EncoderCapabilities(); 1839 caps.init(info, parent); 1840 return caps; 1841 } 1842 1843 /** @hide */ 1844 public void init(MediaFormat info, CodecCapabilities parent) { 1845 // no support for complexity or quality yet 1846 mParent = parent; 1847 mComplexityRange = Range.create(0, 0); 1848 mQualityRange = Range.create(0, 0); 1849 mBitControl = (1 << BITRATE_MODE_VBR); 1850 1851 applyLevelLimits(); 1852 parseFromInfo(info); 1853 } 1854 1855 private void applyLevelLimits() { 1856 String mime = mParent.getMimeType(); 1857 if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) { 1858 mComplexityRange = Range.create(0, 8); 1859 mBitControl = (1 << BITRATE_MODE_CQ); 1860 } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB) 1861 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB) 1862 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW) 1863 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW) 1864 || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) { 1865 mBitControl = (1 << BITRATE_MODE_CBR); 1866 } 1867 } 1868 1869 private int mBitControl; 1870 private Integer mDefaultComplexity; 1871 private Integer mDefaultQuality; 1872 private String mQualityScale; 1873 1874 private void parseFromInfo(MediaFormat info) { 1875 Map<String, Object> map = info.getMap(); 1876 1877 if (info.containsKey("complexity-range")) { 1878 mComplexityRange = Utils 1879 .parseIntRange(info.getString("complexity-range"), mComplexityRange); 1880 // TODO should we limit this to level limits? 1881 } 1882 if (info.containsKey("quality-range")) { 1883 mQualityRange = Utils 1884 .parseIntRange(info.getString("quality-range"), mQualityRange); 1885 } 1886 if (info.containsKey("feature-bitrate-control")) { 1887 for (String mode: info.getString("feature-bitrate-control").split(",")) { 1888 mBitControl |= parseBitrateMode(mode); 1889 } 1890 } 1891 1892 try { 1893 mDefaultComplexity = Integer.parseInt((String)map.get("complexity-default")); 1894 } catch (NumberFormatException e) { } 1895 1896 try { 1897 mDefaultQuality = Integer.parseInt((String)map.get("quality-default")); 1898 } catch (NumberFormatException e) { } 1899 1900 mQualityScale = (String)map.get("quality-scale"); 1901 } 1902 1903 private boolean supports( 1904 Integer complexity, Integer quality, Integer profile) { 1905 boolean ok = true; 1906 if (ok && complexity != null) { 1907 ok = mComplexityRange.contains(complexity); 1908 } 1909 if (ok && quality != null) { 1910 ok = mQualityRange.contains(quality); 1911 } 1912 if (ok && profile != null) { 1913 for (CodecProfileLevel pl: mParent.profileLevels) { 1914 if (pl.profile == profile) { 1915 profile = null; 1916 break; 1917 } 1918 } 1919 ok = profile == null; 1920 } 1921 return ok; 1922 } 1923 1924 /** @hide */ 1925 public void setDefaultFormat(MediaFormat format) { 1926 // don't list trivial quality/complexity as default for now 1927 if (!mQualityRange.getUpper().equals(mQualityRange.getLower()) 1928 && mDefaultQuality != null) { 1929 format.setInteger(MediaFormat.KEY_QUALITY, mDefaultQuality); 1930 } 1931 if (!mComplexityRange.getUpper().equals(mComplexityRange.getLower()) 1932 && mDefaultComplexity != null) { 1933 format.setInteger(MediaFormat.KEY_COMPLEXITY, mDefaultComplexity); 1934 } 1935 // bitrates are listed in order of preference 1936 for (Feature feat: bitrates) { 1937 if ((mBitControl & (1 << feat.mValue)) != 0) { 1938 format.setInteger(MediaFormat.KEY_BITRATE_MODE, feat.mValue); 1939 break; 1940 } 1941 } 1942 } 1943 1944 /** @hide */ 1945 public boolean supportsFormat(MediaFormat format) { 1946 final Map<String, Object> map = format.getMap(); 1947 final String mime = mParent.getMimeType(); 1948 1949 Integer mode = (Integer)map.get(MediaFormat.KEY_BITRATE_MODE); 1950 if (mode != null && !isBitrateModeSupported(mode)) { 1951 return false; 1952 } 1953 1954 Integer complexity = (Integer)map.get(MediaFormat.KEY_COMPLEXITY); 1955 if (MediaFormat.MIMETYPE_AUDIO_FLAC.equalsIgnoreCase(mime)) { 1956 Integer flacComplexity = 1957 (Integer)map.get(MediaFormat.KEY_FLAC_COMPRESSION_LEVEL); 1958 if (complexity == null) { 1959 complexity = flacComplexity; 1960 } else if (flacComplexity != null && complexity != flacComplexity) { 1961 throw new IllegalArgumentException( 1962 "conflicting values for complexity and " + 1963 "flac-compression-level"); 1964 } 1965 } 1966 1967 // other audio parameters 1968 Integer profile = (Integer)map.get(MediaFormat.KEY_PROFILE); 1969 if (MediaFormat.MIMETYPE_AUDIO_AAC.equalsIgnoreCase(mime)) { 1970 Integer aacProfile = (Integer)map.get(MediaFormat.KEY_AAC_PROFILE); 1971 if (profile == null) { 1972 profile = aacProfile; 1973 } else if (aacProfile != null && aacProfile != profile) { 1974 throw new IllegalArgumentException( 1975 "conflicting values for profile and aac-profile"); 1976 } 1977 } 1978 1979 Integer quality = (Integer)map.get(MediaFormat.KEY_QUALITY); 1980 1981 return supports(complexity, quality, profile); 1982 } 1983 }; 1984 1985 /** 1986 * Encapsulates the profiles available for a codec component. 1987 * <p>You can get a set of {@link MediaCodecInfo.CodecProfileLevel} objects for a given 1988 * {@link MediaCodecInfo} object from the 1989 * {@link MediaCodecInfo.CodecCapabilities#profileLevels} field. 1990 */ 1991 public static final class CodecProfileLevel { 1992 // from OMX_VIDEO_AVCPROFILETYPE 1993 public static final int AVCProfileBaseline = 0x01; 1994 public static final int AVCProfileMain = 0x02; 1995 public static final int AVCProfileExtended = 0x04; 1996 public static final int AVCProfileHigh = 0x08; 1997 public static final int AVCProfileHigh10 = 0x10; 1998 public static final int AVCProfileHigh422 = 0x20; 1999 public static final int AVCProfileHigh444 = 0x40; 2000 2001 // from OMX_VIDEO_AVCLEVELTYPE 2002 public static final int AVCLevel1 = 0x01; 2003 public static final int AVCLevel1b = 0x02; 2004 public static final int AVCLevel11 = 0x04; 2005 public static final int AVCLevel12 = 0x08; 2006 public static final int AVCLevel13 = 0x10; 2007 public static final int AVCLevel2 = 0x20; 2008 public static final int AVCLevel21 = 0x40; 2009 public static final int AVCLevel22 = 0x80; 2010 public static final int AVCLevel3 = 0x100; 2011 public static final int AVCLevel31 = 0x200; 2012 public static final int AVCLevel32 = 0x400; 2013 public static final int AVCLevel4 = 0x800; 2014 public static final int AVCLevel41 = 0x1000; 2015 public static final int AVCLevel42 = 0x2000; 2016 public static final int AVCLevel5 = 0x4000; 2017 public static final int AVCLevel51 = 0x8000; 2018 public static final int AVCLevel52 = 0x10000; 2019 2020 // from OMX_VIDEO_H263PROFILETYPE 2021 public static final int H263ProfileBaseline = 0x01; 2022 public static final int H263ProfileH320Coding = 0x02; 2023 public static final int H263ProfileBackwardCompatible = 0x04; 2024 public static final int H263ProfileISWV2 = 0x08; 2025 public static final int H263ProfileISWV3 = 0x10; 2026 public static final int H263ProfileHighCompression = 0x20; 2027 public static final int H263ProfileInternet = 0x40; 2028 public static final int H263ProfileInterlace = 0x80; 2029 public static final int H263ProfileHighLatency = 0x100; 2030 2031 // from OMX_VIDEO_H263LEVELTYPE 2032 public static final int H263Level10 = 0x01; 2033 public static final int H263Level20 = 0x02; 2034 public static final int H263Level30 = 0x04; 2035 public static final int H263Level40 = 0x08; 2036 public static final int H263Level45 = 0x10; 2037 public static final int H263Level50 = 0x20; 2038 public static final int H263Level60 = 0x40; 2039 public static final int H263Level70 = 0x80; 2040 2041 // from OMX_VIDEO_MPEG4PROFILETYPE 2042 public static final int MPEG4ProfileSimple = 0x01; 2043 public static final int MPEG4ProfileSimpleScalable = 0x02; 2044 public static final int MPEG4ProfileCore = 0x04; 2045 public static final int MPEG4ProfileMain = 0x08; 2046 public static final int MPEG4ProfileNbit = 0x10; 2047 public static final int MPEG4ProfileScalableTexture = 0x20; 2048 public static final int MPEG4ProfileSimpleFace = 0x40; 2049 public static final int MPEG4ProfileSimpleFBA = 0x80; 2050 public static final int MPEG4ProfileBasicAnimated = 0x100; 2051 public static final int MPEG4ProfileHybrid = 0x200; 2052 public static final int MPEG4ProfileAdvancedRealTime = 0x400; 2053 public static final int MPEG4ProfileCoreScalable = 0x800; 2054 public static final int MPEG4ProfileAdvancedCoding = 0x1000; 2055 public static final int MPEG4ProfileAdvancedCore = 0x2000; 2056 public static final int MPEG4ProfileAdvancedScalable = 0x4000; 2057 public static final int MPEG4ProfileAdvancedSimple = 0x8000; 2058 2059 // from OMX_VIDEO_MPEG4LEVELTYPE 2060 public static final int MPEG4Level0 = 0x01; 2061 public static final int MPEG4Level0b = 0x02; 2062 public static final int MPEG4Level1 = 0x04; 2063 public static final int MPEG4Level2 = 0x08; 2064 public static final int MPEG4Level3 = 0x10; 2065 public static final int MPEG4Level4 = 0x20; 2066 public static final int MPEG4Level4a = 0x40; 2067 public static final int MPEG4Level5 = 0x80; 2068 2069 // from OMX_AUDIO_AACPROFILETYPE 2070 public static final int AACObjectMain = 1; 2071 public static final int AACObjectLC = 2; 2072 public static final int AACObjectSSR = 3; 2073 public static final int AACObjectLTP = 4; 2074 public static final int AACObjectHE = 5; 2075 public static final int AACObjectScalable = 6; 2076 public static final int AACObjectERLC = 17; 2077 public static final int AACObjectLD = 23; 2078 public static final int AACObjectHE_PS = 29; 2079 public static final int AACObjectELD = 39; 2080 2081 // from OMX_VIDEO_VP8LEVELTYPE 2082 public static final int VP8Level_Version0 = 0x01; 2083 public static final int VP8Level_Version1 = 0x02; 2084 public static final int VP8Level_Version2 = 0x04; 2085 public static final int VP8Level_Version3 = 0x08; 2086 2087 // from OMX_VIDEO_VP8PROFILETYPE 2088 public static final int VP8ProfileMain = 0x01; 2089 2090 // from OMX_VIDEO_HEVCPROFILETYPE 2091 public static final int HEVCProfileMain = 0x01; 2092 public static final int HEVCProfileMain10 = 0x02; 2093 2094 // from OMX_VIDEO_HEVCLEVELTYPE 2095 public static final int HEVCMainTierLevel1 = 0x1; 2096 public static final int HEVCHighTierLevel1 = 0x2; 2097 public static final int HEVCMainTierLevel2 = 0x4; 2098 public static final int HEVCHighTierLevel2 = 0x8; 2099 public static final int HEVCMainTierLevel21 = 0x10; 2100 public static final int HEVCHighTierLevel21 = 0x20; 2101 public static final int HEVCMainTierLevel3 = 0x40; 2102 public static final int HEVCHighTierLevel3 = 0x80; 2103 public static final int HEVCMainTierLevel31 = 0x100; 2104 public static final int HEVCHighTierLevel31 = 0x200; 2105 public static final int HEVCMainTierLevel4 = 0x400; 2106 public static final int HEVCHighTierLevel4 = 0x800; 2107 public static final int HEVCMainTierLevel41 = 0x1000; 2108 public static final int HEVCHighTierLevel41 = 0x2000; 2109 public static final int HEVCMainTierLevel5 = 0x4000; 2110 public static final int HEVCHighTierLevel5 = 0x8000; 2111 public static final int HEVCMainTierLevel51 = 0x10000; 2112 public static final int HEVCHighTierLevel51 = 0x20000; 2113 public static final int HEVCMainTierLevel52 = 0x40000; 2114 public static final int HEVCHighTierLevel52 = 0x80000; 2115 public static final int HEVCMainTierLevel6 = 0x100000; 2116 public static final int HEVCHighTierLevel6 = 0x200000; 2117 public static final int HEVCMainTierLevel61 = 0x400000; 2118 public static final int HEVCHighTierLevel61 = 0x800000; 2119 public static final int HEVCMainTierLevel62 = 0x1000000; 2120 public static final int HEVCHighTierLevel62 = 0x2000000; 2121 2122 /** 2123 * Defined in the OpenMAX IL specs, depending on the type of media 2124 * this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE, 2125 * OMX_VIDEO_MPEG4PROFILETYPE or OMX_VIDEO_VP8PROFILETYPE. 2126 */ 2127 public int profile; 2128 2129 /** 2130 * Defined in the OpenMAX IL specs, depending on the type of media 2131 * this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE 2132 * OMX_VIDEO_MPEG4LEVELTYPE or OMX_VIDEO_VP8LEVELTYPE. 2133 */ 2134 public int level; 2135 }; 2136 2137 /** 2138 * Enumerates the capabilities of the codec component. Since a single 2139 * component can support data of a variety of types, the type has to be 2140 * specified to yield a meaningful result. 2141 * @param type The MIME type to query 2142 */ 2143 public final CodecCapabilities getCapabilitiesForType( 2144 String type) { 2145 CodecCapabilities caps = mCaps.get(type); 2146 if (caps == null) { 2147 throw new IllegalArgumentException("codec does not support type"); 2148 } 2149 // clone writable object 2150 return caps.dup(); 2151 } 2152 2153 /** @hide */ 2154 public MediaCodecInfo makeRegular() { 2155 ArrayList<CodecCapabilities> caps = new ArrayList<CodecCapabilities>(); 2156 for (CodecCapabilities c: mCaps.values()) { 2157 if (c.isRegular()) { 2158 caps.add(c); 2159 } 2160 } 2161 if (caps.size() == 0) { 2162 return null; 2163 } else if (caps.size() == mCaps.size()) { 2164 return this; 2165 } 2166 2167 return new MediaCodecInfo( 2168 mName, mIsEncoder, 2169 caps.toArray(new CodecCapabilities[caps.size()])); 2170 } 2171 } 2172