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