Loading media/libmedia/CodecCapabilities.cpp +385 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "CodecCapabilities" #include <android-base/strings.h> #include <utils/Log.h> #include <media/CodecCapabilities.h> #include <media/CodecCapabilitiesUtils.h> Loading @@ -25,6 +26,58 @@ namespace android { static const int32_t HEVCHighTierLevels = HEVCHighTierLevel1 | HEVCHighTierLevel2 | HEVCHighTierLevel21 | HEVCHighTierLevel3 | HEVCHighTierLevel31 | HEVCHighTierLevel4 | HEVCHighTierLevel41 | HEVCHighTierLevel5 | HEVCHighTierLevel51 | HEVCHighTierLevel52 | HEVCHighTierLevel6 | HEVCHighTierLevel61 | HEVCHighTierLevel62; static const int32_t DEFAULT_MAX_SUPPORTED_INSTANCES = 32; static const int32_t MAX_SUPPORTED_INSTANCES_LIMIT = 256; // must not contain KEY_PROFILE static const std::set<std::pair<std::string, AMessage::Type>> AUDIO_LEVEL_CRITICAL_FORMAT_KEYS = { // We don't set level-specific limits for audio codecs today. Key candidates would // be sample rate, bit rate or channel count. // MediaFormat.KEY_SAMPLE_RATE, // MediaFormat.KEY_CHANNEL_COUNT, // MediaFormat.KEY_BIT_RATE, { KEY_MIME, AMessage::kTypeString } }; // CodecCapabilities Features static const std::vector<Feature> DECODER_FEATURES = { Feature(FEATURE_AdaptivePlayback, (1 << 0), true), Feature(FEATURE_SecurePlayback, (1 << 1), false), Feature(FEATURE_TunneledPlayback, (1 << 2), false), Feature(FEATURE_PartialFrame, (1 << 3), false), Feature(FEATURE_FrameParsing, (1 << 4), false), Feature(FEATURE_MultipleFrames, (1 << 5), false), Feature(FEATURE_DynamicTimestamp, (1 << 6), false), Feature(FEATURE_LowLatency, (1 << 7), true), // feature to exclude codec from REGULAR codec list Feature(FEATURE_SpecialCodec, (1 << 30), false, true), }; static const std::vector<Feature> ENCODER_FEATURES = { Feature(FEATURE_IntraRefresh, (1 << 0), false), Feature(FEATURE_MultipleFrames, (1 << 1), false), Feature(FEATURE_DynamicTimestamp, (1 << 2), false), Feature(FEATURE_QpBounds, (1 << 3), false), Feature(FEATURE_EncodingStatistics, (1 << 4), false), Feature(FEATURE_HdrEditing, (1 << 5), false), // feature to exclude codec from REGULAR codec list Feature(FEATURE_SpecialCodec, (1 << 30), false, true), }; // must not contain KEY_PROFILE static const std::set<std::pair<std::string, AMessage::Type>> VIDEO_LEVEL_CRITICAL_FORMAT_KEYS = { { KEY_WIDTH, AMessage::kTypeInt32 }, { KEY_HEIGHT, AMessage::kTypeInt32 }, { KEY_FRAME_RATE, AMessage::kTypeInt32 }, { KEY_BIT_RATE, AMessage::kTypeInt32 }, { KEY_MIME, AMessage::kTypeString } }; bool CodecCapabilities::SupportsBitrate(Range<int32_t> bitrateRange, const sp<AMessage> &format) { // consider max bitrate over average bitrate for support Loading @@ -46,6 +99,212 @@ bool CodecCapabilities::SupportsBitrate(Range<int32_t> bitrateRange, return true; } bool CodecCapabilities::isFeatureSupported(const std::string &name) const { return mFeaturesSupported.contains(name); } bool CodecCapabilities::isFeatureRequired(const std::string &name) const { return mFeaturesRequired.contains(name); } std::vector<std::string> CodecCapabilities::validFeatures() const { std::vector<std::string> res; for (const Feature& feature : getValidFeatures()) { if (!feature.mInternal) { res.push_back(feature.mName); } } return res; } std::vector<Feature> CodecCapabilities::getValidFeatures() const { if (isEncoder()) { return ENCODER_FEATURES; } else { return DECODER_FEATURES; } } bool CodecCapabilities::isRegular() const { // regular codecs only require default features std::vector<Feature> features = getValidFeatures(); return std::all_of(features.begin(), features.end(), [this](Feature feat){ return (feat.mDefault || !isFeatureRequired(feat.mName)); }); } bool CodecCapabilities::isFormatSupported(const sp<AMessage> &format) const { AString mediaType; format->findString(KEY_MIME, &mediaType); // mediaType must match if present if (!base::EqualsIgnoreCase(mMediaType, mediaType.c_str())) { return false; } // check feature support for (Feature feat: getValidFeatures()) { if (feat.mInternal) { continue; } int32_t yesNo; std::string key = KEY_FEATURE_; key = key + feat.mName; if (format->findInt32(key.c_str(), &yesNo)) { continue; } if ((yesNo == 1 && !isFeatureSupported(feat.mName)) || (yesNo == 0 && isFeatureRequired(feat.mName))) { return false; } } int32_t profile; if (format->findInt32(KEY_PROFILE, &profile)) { int32_t level = -1; format->findInt32(KEY_LEVEL, &level); if (!supportsProfileLevel(profile, level)) { return false; } // If we recognize this profile, check that this format is supported by the // highest level supported by the codec for that profile. (Ignore specified // level beyond the above profile/level check as level is only used as a // guidance. E.g. AVC Level 1 CIF format is supported if codec supports level 1.1 // even though max size for Level 1 is QCIF. However, MPEG2 Simple Profile // 1080p format is not supported even if codec supports Main Profile Level High, // as Simple Profile does not support 1080p. int32_t maxLevel = 0; for (ProfileLevel pl : mProfileLevels) { if (pl.mProfile == profile && pl.mLevel > maxLevel) { // H.263 levels are not completely ordered: // Level45 support only implies Level10 support if (!base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_H263) || pl.mLevel != H263Level45 || maxLevel == H263Level10) { maxLevel = pl.mLevel; } } } std::shared_ptr<CodecCapabilities> levelCaps = CreateFromProfileLevel(mMediaType, profile, maxLevel); // We must remove the profile from this format otherwise levelCaps.isFormatSupported // will get into this same condition and loop forever. Furthermore, since levelCaps // does not contain features and bitrate specific keys, keep only keys relevant for // a level check. sp<AMessage> levelCriticalFormat = new AMessage; // critical keys will always contain KEY_MIME, but should also contain others to be // meaningful if ((isVideo() || isAudio()) && levelCaps != nullptr) { const std::set<std::pair<std::string, AMessage::Type>> criticalKeys = isVideo() ? VIDEO_LEVEL_CRITICAL_FORMAT_KEYS : AUDIO_LEVEL_CRITICAL_FORMAT_KEYS; for (std::pair<std::string, AMessage::Type> key : criticalKeys) { if (format->contains(key.first.c_str())) { // AMessage::ItemData value = format->findItem(key.c_str()); // levelCriticalFormat->setItem(key.c_str(), value); switch (key.second) { case AMessage::kTypeInt32: { int32_t value; format->findInt32(key.first.c_str(), &value); levelCriticalFormat->setInt32(key.first.c_str(), value); break; } case AMessage::kTypeString: { AString value; format->findString(key.first.c_str(), &value); levelCriticalFormat->setString(key.first.c_str(), value); break; } default: ALOGE("Unsupported type"); } } } if (!levelCaps->isFormatSupported(levelCriticalFormat)) { return false; } } } if (mAudioCaps && !mAudioCaps->supportsFormat(format)) { return false; } if (mVideoCaps && !mVideoCaps->supportsFormat(format)) { return false; } if (mEncoderCaps && !mEncoderCaps->supportsFormat(format)) { return false; } return true; } bool CodecCapabilities::supportsProfileLevel(int32_t profile, int32_t level) const { for (ProfileLevel pl: mProfileLevels) { if (pl.mProfile != profile) { continue; } // No specific level requested if (level == -1) { return true; } // AAC doesn't use levels if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AAC)) { return true; } // DTS doesn't use levels if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS) || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS_HD) || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS_UHD)) { return true; } // H.263 levels are not completely ordered: // Level45 support only implies Level10 support if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_H263)) { if (pl.mLevel != level && pl.mLevel == H263Level45 && level > H263Level10) { continue; } } // MPEG4 levels are not completely ordered: // Level1 support only implies Level0 (and not Level0b) support if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_MPEG4)) { if (pl.mLevel != level && pl.mLevel == MPEG4Level1 && level > MPEG4Level0) { continue; } } // HEVC levels incorporate both tiers and levels. Verify tier support. if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_HEVC)) { bool supportsHighTier = (pl.mLevel & HEVCHighTierLevels) != 0; bool checkingHighTier = (level & HEVCHighTierLevels) != 0; // high tier levels are only supported by other high tier levels if (checkingHighTier && !supportsHighTier) { continue; } } if (pl.mLevel >= level) { // if we recognize the listed profile/level, we must also recognize the // profile/level arguments. if (CreateFromProfileLevel(mMediaType, profile, pl.mLevel) != nullptr) { return CreateFromProfileLevel(mMediaType, profile, level) != nullptr; } return true; } } return false; } sp<AMessage> CodecCapabilities::getDefaultFormat() const { return mDefaultFormat; } const std::string& CodecCapabilities::getMediaType() { return mMediaType; } Loading @@ -54,4 +313,130 @@ const std::vector<ProfileLevel>& CodecCapabilities::getProfileLevels() { return mProfileLevels; } std::vector<uint32_t> CodecCapabilities::getColorFormats() const { return mColorFormats; } int32_t CodecCapabilities::getMaxSupportedInstances() const { return mMaxSupportedInstances; } bool CodecCapabilities::isAudio() const { return mAudioCaps != nullptr; } std::shared_ptr<AudioCapabilities> CodecCapabilities::getAudioCapabilities() const { return mAudioCaps; } bool CodecCapabilities::isEncoder() const { return mEncoderCaps != nullptr; } std::shared_ptr<EncoderCapabilities> CodecCapabilities::getEncoderCapabilities() const { return mEncoderCaps; } bool CodecCapabilities::isVideo() const { return mVideoCaps != nullptr; } std::shared_ptr<VideoCapabilities> CodecCapabilities::getVideoCapabilities() const { return mVideoCaps; } // static std::shared_ptr<CodecCapabilities> CodecCapabilities::CreateFromProfileLevel( std::string mediaType, int32_t profile, int32_t level, int32_t maxConcurrentInstances) { ProfileLevel pl; pl.mProfile = profile; pl.mLevel = level; sp<AMessage> defaultFormat = new AMessage; defaultFormat->setString(KEY_MIME, mediaType.c_str()); std::vector<ProfileLevel> pls; pls.push_back(pl); std::vector<uint32_t> colFmts; sp<AMessage> capabilitiesInfo = new AMessage; std::shared_ptr<CodecCapabilities> ret(new CodecCapabilities()); ret->init(pls, colFmts, true /* encoder */, defaultFormat, capabilitiesInfo, maxConcurrentInstances); if (ret->getErrors() != 0) { return nullptr; } return ret; } void CodecCapabilities::init(std::vector<ProfileLevel> profLevs, std::vector<uint32_t> colFmts, bool encoder, sp<AMessage> &defaultFormat, sp<AMessage> &capabilitiesInfo, int32_t maxConcurrentInstances) { mColorFormats = colFmts; mDefaultFormat = defaultFormat; mCapabilitiesInfo = capabilitiesInfo; AString mediaTypeAStr; mDefaultFormat->findString(KEY_MIME, &mediaTypeAStr); mMediaType = mediaTypeAStr.c_str(); /* VP9 introduced profiles around 2016, so some VP9 codecs may not advertise any supported profiles. Determine the level for them using the info they provide. */ if (profLevs.size() == 0 && mMediaType == MIMETYPE_VIDEO_VP9) { ProfileLevel profLev; profLev.mProfile = VP9Profile0; profLev.mLevel = VideoCapabilities::EquivalentVP9Level(capabilitiesInfo); profLevs.push_back(profLev); } mProfileLevels = profLevs; if (mediaTypeAStr.startsWithIgnoreCase("audio/")) { mAudioCaps = AudioCapabilities::Create(mMediaType, profLevs, capabilitiesInfo); mAudioCaps->getDefaultFormat(mDefaultFormat); } else if (mediaTypeAStr.startsWithIgnoreCase("video/") || mediaTypeAStr.equalsIgnoreCase(MIMETYPE_IMAGE_ANDROID_HEIC)) { mVideoCaps = VideoCapabilities::Create(mMediaType, profLevs, capabilitiesInfo); } if (encoder) { mEncoderCaps = EncoderCapabilities::Create(mMediaType, profLevs, capabilitiesInfo); mEncoderCaps->getDefaultFormat(mDefaultFormat); } mMaxSupportedInstances = maxConcurrentInstances > 0 ? maxConcurrentInstances : DEFAULT_MAX_SUPPORTED_INSTANCES; int32_t maxInstances = mMaxSupportedInstances; capabilitiesInfo->findInt32("max-concurrent-instances", &maxInstances); mMaxSupportedInstances = Range(1, MAX_SUPPORTED_INSTANCES_LIMIT).clamp(maxInstances); mFeaturesRequired.clear(); mFeaturesSupported.clear(); for (Feature feat: getValidFeatures()) { std::string key = KEY_FEATURE_; key = key + feat.mName; int yesNo = -1; if (!capabilitiesInfo->findInt32(key.c_str(), &yesNo)) { continue; } if (yesNo > 0) { mFeaturesRequired.insert(feat.mName); } mFeaturesSupported.insert(feat.mName); if (!feat.mInternal) { mDefaultFormat->setInt32(key.c_str(), 1); } } } int32_t CodecCapabilities::getErrors() const { if (mAudioCaps) { return mAudioCaps->mError; } else if (mVideoCaps) { return mVideoCaps->mError; } return 0; } } // namespace android No newline at end of file media/libmedia/include/media/CodecCapabilities.h +216 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,26 @@ struct CodecCapabilities { static bool SupportsBitrate(Range<int32_t> bitrateRange, const sp<AMessage> &format); /** * Retrieve the codec capabilities for a certain {@code mime type}, {@code * profile} and {@code level}. If the type, or profile-level combination * is not understood by the framework, it returns null. * <p class=note> In {@link android.os.Build.VERSION_CODES#M}, calling this * method without calling any method of the {@link MediaCodecList} class beforehand * results in a {@link NullPointerException}.</p> */ static std::shared_ptr<CodecCapabilities> CreateFromProfileLevel(std::string mediaType, int32_t profile, int32_t level, int32_t maxConcurrentInstances = -1); CodecCapabilities() {}; /** * Init CodecCapabilities with settings. */ void init(std::vector<ProfileLevel> profLevs, std::vector<uint32_t> colFmts, bool encoder, sp<AMessage> &defaultFormat, sp<AMessage> &capabilitiesInfo, int32_t maxConcurrentInstances = 0); /** * Returns the media type for which this codec-capability object was created. */ Loading @@ -49,13 +69,209 @@ struct CodecCapabilities { */ const std::vector<ProfileLevel>& getProfileLevels(); /** * Returns the supported color formats. */ std::vector<uint32_t> getColorFormats() const; /** * Returns a media format with default values for configurations that have defaults. */ sp<AMessage> getDefaultFormat() const; /** * Returns the max number of the supported concurrent codec instances. * <p> * This is a hint for an upper bound. Applications should not expect to successfully * operate more instances than the returned value, but the actual number of * concurrently operable instances may be less as it depends on the available * resources at time of use. */ int32_t getMaxSupportedInstances() const; /** * Returns the audio capabilities or {@code null} if this is not an audio codec. */ std::shared_ptr<AudioCapabilities> getAudioCapabilities() const; /** * Returns the video capabilities or {@code null} if this is not a video codec. */ std::shared_ptr<VideoCapabilities> getVideoCapabilities() const; /** * Returns the encoding capabilities or {@code null} if this is not an encoder. */ std::shared_ptr<EncoderCapabilities> getEncoderCapabilities() const; std::vector<std::string> validFeatures() const; /** * Query codec feature capabilities. * <p> * These features are supported to be used by the codec. These * include optional features that can be turned on, as well as * features that are always on. */ bool isFeatureSupported(const std::string &name) const; /** * Query codec feature requirements. * <p> * These features are required to be used by the codec, and as such, * they are always turned on. */ bool isFeatureRequired(const std::string &name) const; bool isRegular() const; /** * Query whether codec supports a given {@link MediaFormat}. * * <p class=note> * <strong>Note:</strong> On {@link android.os.Build.VERSION_CODES#LOLLIPOP}, * {@code format} must not contain a {@linkplain MediaFormat#KEY_FRAME_RATE * frame rate}. Use * <code class=prettyprint>format.setString(MediaFormat.KEY_FRAME_RATE, null)</code> * to clear any existing frame rate setting in the format. * <p> * * The following table summarizes the format keys considered by this method. * This is especially important to consider when targeting a higher SDK version than the * minimum SDK version, as this method will disregard some keys on devices below the target * SDK version. * * <table style="width: 0%"> * <thead> * <tr> * <th rowspan=3>OS Version(s)</th> * <td colspan=3>{@code MediaFormat} keys considered for</th> * </tr><tr> * <th>Audio Codecs</th> * <th>Video Codecs</th> * <th>Encoders</th> * </tr> * </thead> * <tbody> * <tr> * <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP}</td> * <td rowspan=3>{@link MediaFormat#KEY_MIME}<sup>*</sup>,<br> * {@link MediaFormat#KEY_SAMPLE_RATE},<br> * {@link MediaFormat#KEY_CHANNEL_COUNT},</td> * <td>{@link MediaFormat#KEY_MIME}<sup>*</sup>,<br> * {@link CodecCapabilities#FEATURE_AdaptivePlayback}<sup>D</sup>,<br> * {@link CodecCapabilities#FEATURE_SecurePlayback}<sup>D</sup>,<br> * {@link CodecCapabilities#FEATURE_TunneledPlayback}<sup>D</sup>,<br> * {@link MediaFormat#KEY_WIDTH},<br> * {@link MediaFormat#KEY_HEIGHT},<br> * <strong>no</strong> {@code KEY_FRAME_RATE}</td> * <td rowspan=10>as to the left, plus<br> * {@link MediaFormat#KEY_BITRATE_MODE},<br> * {@link MediaFormat#KEY_PROFILE} * (and/or {@link MediaFormat#KEY_AAC_PROFILE}<sup>~</sup>),<br> * <!-- {link MediaFormat#KEY_QUALITY},<br> --> * {@link MediaFormat#KEY_COMPLEXITY} * (and/or {@link MediaFormat#KEY_FLAC_COMPRESSION_LEVEL}<sup>~</sup>)</td> * </tr><tr> * <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}</td> * <td rowspan=2>as above, plus<br> * {@link MediaFormat#KEY_FRAME_RATE}</td> * </tr><tr> * <td>{@link android.os.Build.VERSION_CODES#M}</td> * </tr><tr> * <td>{@link android.os.Build.VERSION_CODES#N}</td> * <td rowspan=2>as above, plus<br> * {@link MediaFormat#KEY_PROFILE},<br> * <!-- {link MediaFormat#KEY_MAX_BIT_RATE},<br> --> * {@link MediaFormat#KEY_BIT_RATE}</td> * <td rowspan=2>as above, plus<br> * {@link MediaFormat#KEY_PROFILE},<br> * {@link MediaFormat#KEY_LEVEL}<sup>+</sup>,<br> * <!-- {link MediaFormat#KEY_MAX_BIT_RATE},<br> --> * {@link MediaFormat#KEY_BIT_RATE},<br> * {@link CodecCapabilities#FEATURE_IntraRefresh}<sup>E</sup></td> * </tr><tr> * <td>{@link android.os.Build.VERSION_CODES#N_MR1}</td> * </tr><tr> * <td>{@link android.os.Build.VERSION_CODES#O}</td> * <td rowspan=3 colspan=2>as above, plus<br> * {@link CodecCapabilities#FEATURE_PartialFrame}<sup>D</sup></td> * </tr><tr> * <td>{@link android.os.Build.VERSION_CODES#O_MR1}</td> * </tr><tr> * <td>{@link android.os.Build.VERSION_CODES#P}</td> * </tr><tr> * <td>{@link android.os.Build.VERSION_CODES#Q}</td> * <td colspan=2>as above, plus<br> * {@link CodecCapabilities#FEATURE_FrameParsing}<sup>D</sup>,<br> * {@link CodecCapabilities#FEATURE_MultipleFrames},<br> * {@link CodecCapabilities#FEATURE_DynamicTimestamp}</td> * </tr><tr> * <td>{@link android.os.Build.VERSION_CODES#R}</td> * <td colspan=2>as above, plus<br> * {@link CodecCapabilities#FEATURE_LowLatency}<sup>D</sup></td> * </tr> * <tr> * <td colspan=4> * <p class=note><strong>Notes:</strong><br> * *: must be specified; otherwise, method returns {@code false}.<br> * +: method does not verify that the format parameters are supported * by the specified level.<br> * D: decoders only<br> * E: encoders only<br> * ~: if both keys are provided values must match * </td> * </tr> * </tbody> * </table> * * @param format media format with optional feature directives. * @return whether the codec capabilities support the given format * and feature requests. */ bool isFormatSupported(const sp<AMessage> &format) const; /** * If the CodecCapabilities contains an AudioCapabilities. * * Not a public API to users. */ bool isAudio() const; /** * If the CodecCapabilities contains a VideoCapabilities. * * Not a public API to users. */ bool isVideo() const; /** * If the CodecCapabilities contains an EncoderCapabilities. * * Not a public API to users. */ bool isEncoder() const; private: std::string mMediaType; std::vector<ProfileLevel> mProfileLevels; std::vector<uint32_t> mColorFormats; int32_t mMaxSupportedInstances; sp<AMessage> mDefaultFormat; sp<AMessage> mCapabilitiesInfo; // Features std::set<std::string> mFeaturesSupported; std::set<std::string> mFeaturesRequired; std::shared_ptr<AudioCapabilities> mAudioCaps; std::shared_ptr<VideoCapabilities> mVideoCaps; std::shared_ptr<EncoderCapabilities> mEncoderCaps; bool supportsProfileLevel(int32_t profile, int32_t level) const; std::vector<Feature> getValidFeatures() const; int32_t getErrors() const; }; } // namespace android Loading media/libstagefright/include/media/stagefright/MediaCodecConstants.h +5 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
media/libmedia/CodecCapabilities.cpp +385 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "CodecCapabilities" #include <android-base/strings.h> #include <utils/Log.h> #include <media/CodecCapabilities.h> #include <media/CodecCapabilitiesUtils.h> Loading @@ -25,6 +26,58 @@ namespace android { static const int32_t HEVCHighTierLevels = HEVCHighTierLevel1 | HEVCHighTierLevel2 | HEVCHighTierLevel21 | HEVCHighTierLevel3 | HEVCHighTierLevel31 | HEVCHighTierLevel4 | HEVCHighTierLevel41 | HEVCHighTierLevel5 | HEVCHighTierLevel51 | HEVCHighTierLevel52 | HEVCHighTierLevel6 | HEVCHighTierLevel61 | HEVCHighTierLevel62; static const int32_t DEFAULT_MAX_SUPPORTED_INSTANCES = 32; static const int32_t MAX_SUPPORTED_INSTANCES_LIMIT = 256; // must not contain KEY_PROFILE static const std::set<std::pair<std::string, AMessage::Type>> AUDIO_LEVEL_CRITICAL_FORMAT_KEYS = { // We don't set level-specific limits for audio codecs today. Key candidates would // be sample rate, bit rate or channel count. // MediaFormat.KEY_SAMPLE_RATE, // MediaFormat.KEY_CHANNEL_COUNT, // MediaFormat.KEY_BIT_RATE, { KEY_MIME, AMessage::kTypeString } }; // CodecCapabilities Features static const std::vector<Feature> DECODER_FEATURES = { Feature(FEATURE_AdaptivePlayback, (1 << 0), true), Feature(FEATURE_SecurePlayback, (1 << 1), false), Feature(FEATURE_TunneledPlayback, (1 << 2), false), Feature(FEATURE_PartialFrame, (1 << 3), false), Feature(FEATURE_FrameParsing, (1 << 4), false), Feature(FEATURE_MultipleFrames, (1 << 5), false), Feature(FEATURE_DynamicTimestamp, (1 << 6), false), Feature(FEATURE_LowLatency, (1 << 7), true), // feature to exclude codec from REGULAR codec list Feature(FEATURE_SpecialCodec, (1 << 30), false, true), }; static const std::vector<Feature> ENCODER_FEATURES = { Feature(FEATURE_IntraRefresh, (1 << 0), false), Feature(FEATURE_MultipleFrames, (1 << 1), false), Feature(FEATURE_DynamicTimestamp, (1 << 2), false), Feature(FEATURE_QpBounds, (1 << 3), false), Feature(FEATURE_EncodingStatistics, (1 << 4), false), Feature(FEATURE_HdrEditing, (1 << 5), false), // feature to exclude codec from REGULAR codec list Feature(FEATURE_SpecialCodec, (1 << 30), false, true), }; // must not contain KEY_PROFILE static const std::set<std::pair<std::string, AMessage::Type>> VIDEO_LEVEL_CRITICAL_FORMAT_KEYS = { { KEY_WIDTH, AMessage::kTypeInt32 }, { KEY_HEIGHT, AMessage::kTypeInt32 }, { KEY_FRAME_RATE, AMessage::kTypeInt32 }, { KEY_BIT_RATE, AMessage::kTypeInt32 }, { KEY_MIME, AMessage::kTypeString } }; bool CodecCapabilities::SupportsBitrate(Range<int32_t> bitrateRange, const sp<AMessage> &format) { // consider max bitrate over average bitrate for support Loading @@ -46,6 +99,212 @@ bool CodecCapabilities::SupportsBitrate(Range<int32_t> bitrateRange, return true; } bool CodecCapabilities::isFeatureSupported(const std::string &name) const { return mFeaturesSupported.contains(name); } bool CodecCapabilities::isFeatureRequired(const std::string &name) const { return mFeaturesRequired.contains(name); } std::vector<std::string> CodecCapabilities::validFeatures() const { std::vector<std::string> res; for (const Feature& feature : getValidFeatures()) { if (!feature.mInternal) { res.push_back(feature.mName); } } return res; } std::vector<Feature> CodecCapabilities::getValidFeatures() const { if (isEncoder()) { return ENCODER_FEATURES; } else { return DECODER_FEATURES; } } bool CodecCapabilities::isRegular() const { // regular codecs only require default features std::vector<Feature> features = getValidFeatures(); return std::all_of(features.begin(), features.end(), [this](Feature feat){ return (feat.mDefault || !isFeatureRequired(feat.mName)); }); } bool CodecCapabilities::isFormatSupported(const sp<AMessage> &format) const { AString mediaType; format->findString(KEY_MIME, &mediaType); // mediaType must match if present if (!base::EqualsIgnoreCase(mMediaType, mediaType.c_str())) { return false; } // check feature support for (Feature feat: getValidFeatures()) { if (feat.mInternal) { continue; } int32_t yesNo; std::string key = KEY_FEATURE_; key = key + feat.mName; if (format->findInt32(key.c_str(), &yesNo)) { continue; } if ((yesNo == 1 && !isFeatureSupported(feat.mName)) || (yesNo == 0 && isFeatureRequired(feat.mName))) { return false; } } int32_t profile; if (format->findInt32(KEY_PROFILE, &profile)) { int32_t level = -1; format->findInt32(KEY_LEVEL, &level); if (!supportsProfileLevel(profile, level)) { return false; } // If we recognize this profile, check that this format is supported by the // highest level supported by the codec for that profile. (Ignore specified // level beyond the above profile/level check as level is only used as a // guidance. E.g. AVC Level 1 CIF format is supported if codec supports level 1.1 // even though max size for Level 1 is QCIF. However, MPEG2 Simple Profile // 1080p format is not supported even if codec supports Main Profile Level High, // as Simple Profile does not support 1080p. int32_t maxLevel = 0; for (ProfileLevel pl : mProfileLevels) { if (pl.mProfile == profile && pl.mLevel > maxLevel) { // H.263 levels are not completely ordered: // Level45 support only implies Level10 support if (!base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_H263) || pl.mLevel != H263Level45 || maxLevel == H263Level10) { maxLevel = pl.mLevel; } } } std::shared_ptr<CodecCapabilities> levelCaps = CreateFromProfileLevel(mMediaType, profile, maxLevel); // We must remove the profile from this format otherwise levelCaps.isFormatSupported // will get into this same condition and loop forever. Furthermore, since levelCaps // does not contain features and bitrate specific keys, keep only keys relevant for // a level check. sp<AMessage> levelCriticalFormat = new AMessage; // critical keys will always contain KEY_MIME, but should also contain others to be // meaningful if ((isVideo() || isAudio()) && levelCaps != nullptr) { const std::set<std::pair<std::string, AMessage::Type>> criticalKeys = isVideo() ? VIDEO_LEVEL_CRITICAL_FORMAT_KEYS : AUDIO_LEVEL_CRITICAL_FORMAT_KEYS; for (std::pair<std::string, AMessage::Type> key : criticalKeys) { if (format->contains(key.first.c_str())) { // AMessage::ItemData value = format->findItem(key.c_str()); // levelCriticalFormat->setItem(key.c_str(), value); switch (key.second) { case AMessage::kTypeInt32: { int32_t value; format->findInt32(key.first.c_str(), &value); levelCriticalFormat->setInt32(key.first.c_str(), value); break; } case AMessage::kTypeString: { AString value; format->findString(key.first.c_str(), &value); levelCriticalFormat->setString(key.first.c_str(), value); break; } default: ALOGE("Unsupported type"); } } } if (!levelCaps->isFormatSupported(levelCriticalFormat)) { return false; } } } if (mAudioCaps && !mAudioCaps->supportsFormat(format)) { return false; } if (mVideoCaps && !mVideoCaps->supportsFormat(format)) { return false; } if (mEncoderCaps && !mEncoderCaps->supportsFormat(format)) { return false; } return true; } bool CodecCapabilities::supportsProfileLevel(int32_t profile, int32_t level) const { for (ProfileLevel pl: mProfileLevels) { if (pl.mProfile != profile) { continue; } // No specific level requested if (level == -1) { return true; } // AAC doesn't use levels if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AAC)) { return true; } // DTS doesn't use levels if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS) || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS_HD) || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS_UHD)) { return true; } // H.263 levels are not completely ordered: // Level45 support only implies Level10 support if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_H263)) { if (pl.mLevel != level && pl.mLevel == H263Level45 && level > H263Level10) { continue; } } // MPEG4 levels are not completely ordered: // Level1 support only implies Level0 (and not Level0b) support if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_MPEG4)) { if (pl.mLevel != level && pl.mLevel == MPEG4Level1 && level > MPEG4Level0) { continue; } } // HEVC levels incorporate both tiers and levels. Verify tier support. if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_HEVC)) { bool supportsHighTier = (pl.mLevel & HEVCHighTierLevels) != 0; bool checkingHighTier = (level & HEVCHighTierLevels) != 0; // high tier levels are only supported by other high tier levels if (checkingHighTier && !supportsHighTier) { continue; } } if (pl.mLevel >= level) { // if we recognize the listed profile/level, we must also recognize the // profile/level arguments. if (CreateFromProfileLevel(mMediaType, profile, pl.mLevel) != nullptr) { return CreateFromProfileLevel(mMediaType, profile, level) != nullptr; } return true; } } return false; } sp<AMessage> CodecCapabilities::getDefaultFormat() const { return mDefaultFormat; } const std::string& CodecCapabilities::getMediaType() { return mMediaType; } Loading @@ -54,4 +313,130 @@ const std::vector<ProfileLevel>& CodecCapabilities::getProfileLevels() { return mProfileLevels; } std::vector<uint32_t> CodecCapabilities::getColorFormats() const { return mColorFormats; } int32_t CodecCapabilities::getMaxSupportedInstances() const { return mMaxSupportedInstances; } bool CodecCapabilities::isAudio() const { return mAudioCaps != nullptr; } std::shared_ptr<AudioCapabilities> CodecCapabilities::getAudioCapabilities() const { return mAudioCaps; } bool CodecCapabilities::isEncoder() const { return mEncoderCaps != nullptr; } std::shared_ptr<EncoderCapabilities> CodecCapabilities::getEncoderCapabilities() const { return mEncoderCaps; } bool CodecCapabilities::isVideo() const { return mVideoCaps != nullptr; } std::shared_ptr<VideoCapabilities> CodecCapabilities::getVideoCapabilities() const { return mVideoCaps; } // static std::shared_ptr<CodecCapabilities> CodecCapabilities::CreateFromProfileLevel( std::string mediaType, int32_t profile, int32_t level, int32_t maxConcurrentInstances) { ProfileLevel pl; pl.mProfile = profile; pl.mLevel = level; sp<AMessage> defaultFormat = new AMessage; defaultFormat->setString(KEY_MIME, mediaType.c_str()); std::vector<ProfileLevel> pls; pls.push_back(pl); std::vector<uint32_t> colFmts; sp<AMessage> capabilitiesInfo = new AMessage; std::shared_ptr<CodecCapabilities> ret(new CodecCapabilities()); ret->init(pls, colFmts, true /* encoder */, defaultFormat, capabilitiesInfo, maxConcurrentInstances); if (ret->getErrors() != 0) { return nullptr; } return ret; } void CodecCapabilities::init(std::vector<ProfileLevel> profLevs, std::vector<uint32_t> colFmts, bool encoder, sp<AMessage> &defaultFormat, sp<AMessage> &capabilitiesInfo, int32_t maxConcurrentInstances) { mColorFormats = colFmts; mDefaultFormat = defaultFormat; mCapabilitiesInfo = capabilitiesInfo; AString mediaTypeAStr; mDefaultFormat->findString(KEY_MIME, &mediaTypeAStr); mMediaType = mediaTypeAStr.c_str(); /* VP9 introduced profiles around 2016, so some VP9 codecs may not advertise any supported profiles. Determine the level for them using the info they provide. */ if (profLevs.size() == 0 && mMediaType == MIMETYPE_VIDEO_VP9) { ProfileLevel profLev; profLev.mProfile = VP9Profile0; profLev.mLevel = VideoCapabilities::EquivalentVP9Level(capabilitiesInfo); profLevs.push_back(profLev); } mProfileLevels = profLevs; if (mediaTypeAStr.startsWithIgnoreCase("audio/")) { mAudioCaps = AudioCapabilities::Create(mMediaType, profLevs, capabilitiesInfo); mAudioCaps->getDefaultFormat(mDefaultFormat); } else if (mediaTypeAStr.startsWithIgnoreCase("video/") || mediaTypeAStr.equalsIgnoreCase(MIMETYPE_IMAGE_ANDROID_HEIC)) { mVideoCaps = VideoCapabilities::Create(mMediaType, profLevs, capabilitiesInfo); } if (encoder) { mEncoderCaps = EncoderCapabilities::Create(mMediaType, profLevs, capabilitiesInfo); mEncoderCaps->getDefaultFormat(mDefaultFormat); } mMaxSupportedInstances = maxConcurrentInstances > 0 ? maxConcurrentInstances : DEFAULT_MAX_SUPPORTED_INSTANCES; int32_t maxInstances = mMaxSupportedInstances; capabilitiesInfo->findInt32("max-concurrent-instances", &maxInstances); mMaxSupportedInstances = Range(1, MAX_SUPPORTED_INSTANCES_LIMIT).clamp(maxInstances); mFeaturesRequired.clear(); mFeaturesSupported.clear(); for (Feature feat: getValidFeatures()) { std::string key = KEY_FEATURE_; key = key + feat.mName; int yesNo = -1; if (!capabilitiesInfo->findInt32(key.c_str(), &yesNo)) { continue; } if (yesNo > 0) { mFeaturesRequired.insert(feat.mName); } mFeaturesSupported.insert(feat.mName); if (!feat.mInternal) { mDefaultFormat->setInt32(key.c_str(), 1); } } } int32_t CodecCapabilities::getErrors() const { if (mAudioCaps) { return mAudioCaps->mError; } else if (mVideoCaps) { return mVideoCaps->mError; } return 0; } } // namespace android No newline at end of file
media/libmedia/include/media/CodecCapabilities.h +216 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,26 @@ struct CodecCapabilities { static bool SupportsBitrate(Range<int32_t> bitrateRange, const sp<AMessage> &format); /** * Retrieve the codec capabilities for a certain {@code mime type}, {@code * profile} and {@code level}. If the type, or profile-level combination * is not understood by the framework, it returns null. * <p class=note> In {@link android.os.Build.VERSION_CODES#M}, calling this * method without calling any method of the {@link MediaCodecList} class beforehand * results in a {@link NullPointerException}.</p> */ static std::shared_ptr<CodecCapabilities> CreateFromProfileLevel(std::string mediaType, int32_t profile, int32_t level, int32_t maxConcurrentInstances = -1); CodecCapabilities() {}; /** * Init CodecCapabilities with settings. */ void init(std::vector<ProfileLevel> profLevs, std::vector<uint32_t> colFmts, bool encoder, sp<AMessage> &defaultFormat, sp<AMessage> &capabilitiesInfo, int32_t maxConcurrentInstances = 0); /** * Returns the media type for which this codec-capability object was created. */ Loading @@ -49,13 +69,209 @@ struct CodecCapabilities { */ const std::vector<ProfileLevel>& getProfileLevels(); /** * Returns the supported color formats. */ std::vector<uint32_t> getColorFormats() const; /** * Returns a media format with default values for configurations that have defaults. */ sp<AMessage> getDefaultFormat() const; /** * Returns the max number of the supported concurrent codec instances. * <p> * This is a hint for an upper bound. Applications should not expect to successfully * operate more instances than the returned value, but the actual number of * concurrently operable instances may be less as it depends on the available * resources at time of use. */ int32_t getMaxSupportedInstances() const; /** * Returns the audio capabilities or {@code null} if this is not an audio codec. */ std::shared_ptr<AudioCapabilities> getAudioCapabilities() const; /** * Returns the video capabilities or {@code null} if this is not a video codec. */ std::shared_ptr<VideoCapabilities> getVideoCapabilities() const; /** * Returns the encoding capabilities or {@code null} if this is not an encoder. */ std::shared_ptr<EncoderCapabilities> getEncoderCapabilities() const; std::vector<std::string> validFeatures() const; /** * Query codec feature capabilities. * <p> * These features are supported to be used by the codec. These * include optional features that can be turned on, as well as * features that are always on. */ bool isFeatureSupported(const std::string &name) const; /** * Query codec feature requirements. * <p> * These features are required to be used by the codec, and as such, * they are always turned on. */ bool isFeatureRequired(const std::string &name) const; bool isRegular() const; /** * Query whether codec supports a given {@link MediaFormat}. * * <p class=note> * <strong>Note:</strong> On {@link android.os.Build.VERSION_CODES#LOLLIPOP}, * {@code format} must not contain a {@linkplain MediaFormat#KEY_FRAME_RATE * frame rate}. Use * <code class=prettyprint>format.setString(MediaFormat.KEY_FRAME_RATE, null)</code> * to clear any existing frame rate setting in the format. * <p> * * The following table summarizes the format keys considered by this method. * This is especially important to consider when targeting a higher SDK version than the * minimum SDK version, as this method will disregard some keys on devices below the target * SDK version. * * <table style="width: 0%"> * <thead> * <tr> * <th rowspan=3>OS Version(s)</th> * <td colspan=3>{@code MediaFormat} keys considered for</th> * </tr><tr> * <th>Audio Codecs</th> * <th>Video Codecs</th> * <th>Encoders</th> * </tr> * </thead> * <tbody> * <tr> * <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP}</td> * <td rowspan=3>{@link MediaFormat#KEY_MIME}<sup>*</sup>,<br> * {@link MediaFormat#KEY_SAMPLE_RATE},<br> * {@link MediaFormat#KEY_CHANNEL_COUNT},</td> * <td>{@link MediaFormat#KEY_MIME}<sup>*</sup>,<br> * {@link CodecCapabilities#FEATURE_AdaptivePlayback}<sup>D</sup>,<br> * {@link CodecCapabilities#FEATURE_SecurePlayback}<sup>D</sup>,<br> * {@link CodecCapabilities#FEATURE_TunneledPlayback}<sup>D</sup>,<br> * {@link MediaFormat#KEY_WIDTH},<br> * {@link MediaFormat#KEY_HEIGHT},<br> * <strong>no</strong> {@code KEY_FRAME_RATE}</td> * <td rowspan=10>as to the left, plus<br> * {@link MediaFormat#KEY_BITRATE_MODE},<br> * {@link MediaFormat#KEY_PROFILE} * (and/or {@link MediaFormat#KEY_AAC_PROFILE}<sup>~</sup>),<br> * <!-- {link MediaFormat#KEY_QUALITY},<br> --> * {@link MediaFormat#KEY_COMPLEXITY} * (and/or {@link MediaFormat#KEY_FLAC_COMPRESSION_LEVEL}<sup>~</sup>)</td> * </tr><tr> * <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}</td> * <td rowspan=2>as above, plus<br> * {@link MediaFormat#KEY_FRAME_RATE}</td> * </tr><tr> * <td>{@link android.os.Build.VERSION_CODES#M}</td> * </tr><tr> * <td>{@link android.os.Build.VERSION_CODES#N}</td> * <td rowspan=2>as above, plus<br> * {@link MediaFormat#KEY_PROFILE},<br> * <!-- {link MediaFormat#KEY_MAX_BIT_RATE},<br> --> * {@link MediaFormat#KEY_BIT_RATE}</td> * <td rowspan=2>as above, plus<br> * {@link MediaFormat#KEY_PROFILE},<br> * {@link MediaFormat#KEY_LEVEL}<sup>+</sup>,<br> * <!-- {link MediaFormat#KEY_MAX_BIT_RATE},<br> --> * {@link MediaFormat#KEY_BIT_RATE},<br> * {@link CodecCapabilities#FEATURE_IntraRefresh}<sup>E</sup></td> * </tr><tr> * <td>{@link android.os.Build.VERSION_CODES#N_MR1}</td> * </tr><tr> * <td>{@link android.os.Build.VERSION_CODES#O}</td> * <td rowspan=3 colspan=2>as above, plus<br> * {@link CodecCapabilities#FEATURE_PartialFrame}<sup>D</sup></td> * </tr><tr> * <td>{@link android.os.Build.VERSION_CODES#O_MR1}</td> * </tr><tr> * <td>{@link android.os.Build.VERSION_CODES#P}</td> * </tr><tr> * <td>{@link android.os.Build.VERSION_CODES#Q}</td> * <td colspan=2>as above, plus<br> * {@link CodecCapabilities#FEATURE_FrameParsing}<sup>D</sup>,<br> * {@link CodecCapabilities#FEATURE_MultipleFrames},<br> * {@link CodecCapabilities#FEATURE_DynamicTimestamp}</td> * </tr><tr> * <td>{@link android.os.Build.VERSION_CODES#R}</td> * <td colspan=2>as above, plus<br> * {@link CodecCapabilities#FEATURE_LowLatency}<sup>D</sup></td> * </tr> * <tr> * <td colspan=4> * <p class=note><strong>Notes:</strong><br> * *: must be specified; otherwise, method returns {@code false}.<br> * +: method does not verify that the format parameters are supported * by the specified level.<br> * D: decoders only<br> * E: encoders only<br> * ~: if both keys are provided values must match * </td> * </tr> * </tbody> * </table> * * @param format media format with optional feature directives. * @return whether the codec capabilities support the given format * and feature requests. */ bool isFormatSupported(const sp<AMessage> &format) const; /** * If the CodecCapabilities contains an AudioCapabilities. * * Not a public API to users. */ bool isAudio() const; /** * If the CodecCapabilities contains a VideoCapabilities. * * Not a public API to users. */ bool isVideo() const; /** * If the CodecCapabilities contains an EncoderCapabilities. * * Not a public API to users. */ bool isEncoder() const; private: std::string mMediaType; std::vector<ProfileLevel> mProfileLevels; std::vector<uint32_t> mColorFormats; int32_t mMaxSupportedInstances; sp<AMessage> mDefaultFormat; sp<AMessage> mCapabilitiesInfo; // Features std::set<std::string> mFeaturesSupported; std::set<std::string> mFeaturesRequired; std::shared_ptr<AudioCapabilities> mAudioCaps; std::shared_ptr<VideoCapabilities> mVideoCaps; std::shared_ptr<EncoderCapabilities> mEncoderCaps; bool supportsProfileLevel(int32_t profile, int32_t level) const; std::vector<Feature> getValidFeatures() const; int32_t getErrors() const; }; } // namespace android Loading
media/libstagefright/include/media/stagefright/MediaCodecConstants.h +5 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes