media/stagefright: add support for codec attributes in MediaCodecInfo
- Move away from int flags, and signal capabilities in info AMessage/Map
instead.
- Add more attributes (other than isEncoder).
- Parse aliases, attributes and performance points from XML
- Add plumbing for codec aliases and attributes
- Use proper 'mediaType' phrase for supported types.
Bug: 119631295
Bug: 112370870
Bug: 112374531
Change-Id: I41ea555ca26ab09be176fb96a3138043d960caa3
diff --git a/media/codec2/core/include/C2Component.h b/media/codec2/core/include/C2Component.h
index 8810725..ecf8d2e 100644
--- a/media/codec2/core/include/C2Component.h
+++ b/media/codec2/core/include/C2Component.h
@@ -409,12 +409,13 @@
kind_t kind; ///< component kind
rank_t rank; ///< component rank
C2String mediaType; ///< media type supported by the component
+ C2String owner; ///< name of the component store owning this component
/**
* name alias(es) for backward compatibility.
* \note Multiple components can have the same alias as long as their media-type differs.
*/
- std::vector<C2StringLiteral> aliases; ///< name aliases for backward compatibility
+ std::vector<C2String> aliases; ///< name aliases for backward compatibility
};
// METHODS AVAILABLE WHEN RUNNING
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index ff3e534..f5cc9ff 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -557,6 +557,7 @@
for (size_t i = 0; i < t.size(); ++i) {
c2_status_t status = objcpy(
&mTraitsList[i], &mAliasesBuffer[i], t[i]);
+ mTraitsList[i].owner = mInstanceName;
if (status != C2_OK) {
ALOGE("listComponents -- corrupted output.");
return;
diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
index 5d0ccd2..70ffa83 100644
--- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp
+++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
@@ -73,10 +73,10 @@
constexpr OMX_U32 kMaxIndicesToCheck = 32;
status_t queryOmxCapabilities(
- const char* name, const char* mime, bool isEncoder,
+ const char* name, const char* mediaType, bool isEncoder,
MediaCodecInfo::CapabilitiesWriter* caps) {
- const char *role = GetComponentRole(isEncoder, mime);
+ const char *role = GetComponentRole(isEncoder, mediaType);
if (role == nullptr) {
return BAD_VALUE;
}
@@ -128,8 +128,8 @@
return err;
}
- bool isVideo = hasPrefix(mime, "video/") == 0;
- bool isImage = hasPrefix(mime, "image/") == 0;
+ bool isVideo = hasPrefix(mediaType, "video/") == 0;
+ bool isImage = hasPrefix(mediaType, "image/") == 0;
if (isVideo || isImage) {
OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
@@ -149,7 +149,7 @@
// AVC components may not list the constrained profiles explicitly, but
// decoders that support a profile also support its constrained version.
// Encoders must explicitly support constrained profiles.
- if (!isEncoder && strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC) == 0) {
+ if (!isEncoder && strcasecmp(mediaType, MEDIA_MIMETYPE_VIDEO_AVC) == 0) {
if (param.eProfile == OMX_VIDEO_AVCProfileHigh) {
caps->addProfileLevel(OMX_VIDEO_AVCProfileConstrainedHigh, param.eLevel);
} else if (param.eProfile == OMX_VIDEO_AVCProfileBaseline) {
@@ -193,7 +193,7 @@
asString(portFormat.eColorFormat), portFormat.eColorFormat);
}
}
- } else if (strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC) == 0) {
+ } else if (strcasecmp(mediaType, MEDIA_MIMETYPE_AUDIO_AAC) == 0) {
// More audio codecs if they have profiles.
OMX_AUDIO_PARAM_ANDROID_PROFILETYPE param;
InitOMXParams(¶m);
@@ -228,14 +228,17 @@
if (omxNode->configureVideoTunnelMode(
kPortIndexOutput, OMX_TRUE, 0, &sidebandHandle) == OK) {
// tunneled playback includes adaptive playback
- caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback
- | MediaCodecInfo::Capabilities::kFlagSupportsTunneledPlayback);
- } else if (omxNode->setPortMode(
- kPortIndexOutput, IOMX::kPortModeDynamicANWBuffer) == OK ||
- omxNode->prepareForAdaptivePlayback(
- kPortIndexOutput, OMX_TRUE,
- 1280 /* width */, 720 /* height */) == OK) {
- caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback);
+ } else {
+ // tunneled playback is not supported
+ caps->removeDetail(MediaCodecInfo::Capabilities::FEATURE_TUNNELED_PLAYBACK);
+ if (omxNode->setPortMode(
+ kPortIndexOutput, IOMX::kPortModeDynamicANWBuffer) == OK ||
+ omxNode->prepareForAdaptivePlayback(
+ kPortIndexOutput, OMX_TRUE,
+ 1280 /* width */, 720 /* height */) != OK) {
+ // adaptive playback is not supported
+ caps->removeDetail(MediaCodecInfo::Capabilities::FEATURE_ADAPTIVE_PLAYBACK);
+ }
}
}
@@ -243,11 +246,20 @@
OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE params;
InitOMXParams(¶ms);
params.nPortIndex = kPortIndexOutput;
- // TODO: should we verify if fallback is supported?
+
+ OMX_VIDEO_PARAM_INTRAREFRESHTYPE fallbackParams;
+ InitOMXParams(&fallbackParams);
+ fallbackParams.nPortIndex = kPortIndexOutput;
+ fallbackParams.eRefreshMode = OMX_VIDEO_IntraRefreshCyclic;
+
if (omxNode->getConfig(
(OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh,
- ¶ms, sizeof(params)) == OK) {
- caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsIntraRefresh);
+ ¶ms, sizeof(params)) != OK &&
+ omxNode->getParameter(
+ OMX_IndexParamVideoIntraRefresh, &fallbackParams,
+ sizeof(fallbackParams)) != OK) {
+ // intra refresh is not supported
+ caps->removeDetail(MediaCodecInfo::Capabilities::FEATURE_INTRA_REFRESH);
}
}
@@ -270,12 +282,26 @@
writer->addMediaCodecInfo();
info->setName(name.c_str());
info->setOwner("default");
- info->setEncoder(encoder);
+ typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs = 0;
+ if (encoder) {
+ attrs |= MediaCodecInfo::kFlagIsEncoder;
+ }
+ // NOTE: we don't support software-only codecs in OMX
+ if (!hasPrefix(name, "OMX.google.")) {
+ attrs |= MediaCodecInfo::kFlagIsVendor;
+ if (properties.quirkSet.find("attribute::software-codec")
+ == properties.quirkSet.end()) {
+ attrs |= MediaCodecInfo::kFlagIsHardwareAccelerated;
+ }
+ }
+ info->setAttributes(attrs);
info->setRank(omxRank);
- for (const MediaCodecsXmlParser::Type& type : properties.typeMap) {
- const std::string &mime = type.first;
+ // OMX components don't have aliases
+ for (const MediaCodecsXmlParser::Type &type : properties.typeMap) {
+ const std::string &mediaType = type.first;
+
std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
- info->addMime(mime.c_str());
+ info->addMediaType(mediaType.c_str());
const MediaCodecsXmlParser::AttributeMap &attrMap = type.second;
for (const MediaCodecsXmlParser::Attribute& attr : attrMap) {
const std::string &key = attr.first;
@@ -289,13 +315,13 @@
}
status_t err = queryOmxCapabilities(
name.c_str(),
- mime.c_str(),
+ mediaType.c_str(),
encoder,
caps.get());
if (err != OK) {
- ALOGE("Failed to query capabilities for %s (mime: %s). Error: %d",
+ ALOGI("Failed to query capabilities for %s (media type: %s). Error: %d",
name.c_str(),
- mime.c_str(),
+ mediaType.c_str(),
static_cast<int>(err));
}
}
@@ -407,20 +433,40 @@
break;
}
+ ALOGV("canonName = %s", canonName.c_str());
std::unique_ptr<MediaCodecInfoWriter> codecInfo = writer->addMediaCodecInfo();
codecInfo->setName(trait.name.c_str());
- codecInfo->setOwner("codec2");
+ codecInfo->setOwner(("codec2::" + trait.owner).c_str());
+ const MediaCodecsXmlParser::CodecProperties &codec = parser.getCodecMap().at(canonName);
+
bool encoder = trait.kind == C2Component::KIND_ENCODER;
- codecInfo->setEncoder(encoder);
+ typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs = 0;
+
+ if (encoder) {
+ attrs |= MediaCodecInfo::kFlagIsEncoder;
+ }
+ if (trait.owner == "software") {
+ attrs |= MediaCodecInfo::kFlagIsSoftwareOnly;
+ } else {
+ attrs |= MediaCodecInfo::kFlagIsVendor;
+ if (trait.owner == "vendor-software") {
+ attrs |= MediaCodecInfo::kFlagIsSoftwareOnly;
+ } else if (codec.quirkSet.find("attribute::software-codec") == codec.quirkSet.end()) {
+ attrs |= MediaCodecInfo::kFlagIsHardwareAccelerated;
+ }
+ }
+ codecInfo->setAttributes(attrs);
codecInfo->setRank(rank);
- const MediaCodecsXmlParser::CodecProperties &codec =
- parser.getCodecMap().at(canonName);
+
+ for (const std::string &alias : codec.aliases) {
+ codecInfo->addAlias(alias.c_str());
+ }
for (auto typeIt = codec.typeMap.begin(); typeIt != codec.typeMap.end(); ++typeIt) {
const std::string &mediaType = typeIt->first;
const MediaCodecsXmlParser::AttributeMap &attrMap = typeIt->second;
std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
- codecInfo->addMime(mediaType.c_str());
+ codecInfo->addMediaType(mediaType.c_str());
for (auto attrIt = attrMap.begin(); attrIt != attrMap.end(); ++attrIt) {
std::string key, value;
std::tie(key, value) = *attrIt;
diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp
index 5308e1c..86ad997 100644
--- a/media/libmedia/MediaCodecInfo.cpp
+++ b/media/libmedia/MediaCodecInfo.cpp
@@ -28,6 +28,15 @@
namespace android {
+/** This redundant redeclaration is needed for C++ pre 14 */
+constexpr char MediaCodecInfo::Capabilities::FEATURE_ADAPTIVE_PLAYBACK[];
+constexpr char MediaCodecInfo::Capabilities::FEATURE_DYNAMIC_TIMESTAMP[];
+constexpr char MediaCodecInfo::Capabilities::FEATURE_FRAME_PARSING[];
+constexpr char MediaCodecInfo::Capabilities::FEATURE_INTRA_REFRESH[];
+constexpr char MediaCodecInfo::Capabilities::FEATURE_MULTIPLE_FRAMES[];
+constexpr char MediaCodecInfo::Capabilities::FEATURE_SECURE_PLAYBACK[];
+constexpr char MediaCodecInfo::Capabilities::FEATURE_TUNNELED_PLAYBACK[];
+
void MediaCodecInfo::Capabilities::getSupportedProfileLevels(
Vector<ProfileLevel> *profileLevels) const {
profileLevels->clear();
@@ -40,16 +49,11 @@
colorFormats->appendVector(mColorFormats);
}
-uint32_t MediaCodecInfo::Capabilities::getFlags() const {
- return mFlags;
-}
-
const sp<AMessage> MediaCodecInfo::Capabilities::getDetails() const {
return mDetails;
}
-MediaCodecInfo::Capabilities::Capabilities()
- : mFlags(0) {
+MediaCodecInfo::Capabilities::Capabilities() {
mDetails = new AMessage;
}
@@ -73,12 +77,10 @@
caps->mColorFormats.push_back(color);
}
}
- uint32_t flags = static_cast<uint32_t>(parcel.readInt32());
sp<AMessage> details = AMessage::FromParcel(parcel);
if (details == NULL)
return NULL;
if (caps != NULL) {
- caps->mFlags = flags;
caps->mDetails = details;
}
return caps;
@@ -96,7 +98,6 @@
for (size_t i = 0; i < mColorFormats.size(); i++) {
parcel->writeInt32(mColorFormats.itemAt(i));
}
- parcel->writeInt32(mFlags);
mDetails->writeToParcel(parcel);
return OK;
}
@@ -111,6 +112,14 @@
mCap->mDetails->setInt32(key, value);
}
+void MediaCodecInfo::CapabilitiesWriter::removeDetail(const char* key) {
+ if (mCap->mDetails->removeEntryAt(mCap->mDetails->findEntryByName(key)) == OK) {
+ ALOGD("successfully removed detail %s", key);
+ } else {
+ ALOGD("detail %s wasn't present to remove", key);
+ }
+}
+
void MediaCodecInfo::CapabilitiesWriter::addProfileLevel(
uint32_t profile, uint32_t level) {
ProfileLevel profileLevel;
@@ -129,32 +138,32 @@
}
}
-void MediaCodecInfo::CapabilitiesWriter::addFlags(uint32_t flags) {
- mCap->mFlags |= flags;
-}
-
MediaCodecInfo::CapabilitiesWriter::CapabilitiesWriter(
MediaCodecInfo::Capabilities* cap) : mCap(cap) {
}
-bool MediaCodecInfo::isEncoder() const {
- return mIsEncoder;
+MediaCodecInfo::Attributes MediaCodecInfo::getAttributes() const {
+ return mAttributes;
}
-uint32_t MediaCodecInfo::rank() const {
+uint32_t MediaCodecInfo::getRank() const {
return mRank;
}
-void MediaCodecInfo::getSupportedMimes(Vector<AString> *mimes) const {
- mimes->clear();
+void MediaCodecInfo::getAliases(Vector<AString> *aliases) const {
+ *aliases = mAliases;
+}
+
+void MediaCodecInfo::getSupportedMediaTypes(Vector<AString> *mediaTypes) const {
+ mediaTypes->clear();
for (size_t ix = 0; ix < mCaps.size(); ix++) {
- mimes->push_back(mCaps.keyAt(ix));
+ mediaTypes->push_back(mCaps.keyAt(ix));
}
}
const sp<MediaCodecInfo::Capabilities>
-MediaCodecInfo::getCapabilitiesFor(const char *mime) const {
- ssize_t ix = getCapabilityIndex(mime);
+MediaCodecInfo::getCapabilitiesFor(const char *mediaType) const {
+ ssize_t ix = getCapabilityIndex(mediaType);
if (ix >= 0) {
return mCaps.valueAt(ix);
}
@@ -173,21 +182,26 @@
sp<MediaCodecInfo> MediaCodecInfo::FromParcel(const Parcel &parcel) {
AString name = AString::FromParcel(parcel);
AString owner = AString::FromParcel(parcel);
- bool isEncoder = static_cast<bool>(parcel.readInt32());
+ Attributes attributes = static_cast<Attributes>(parcel.readInt32());
uint32_t rank = parcel.readUint32();
sp<MediaCodecInfo> info = new MediaCodecInfo;
info->mName = name;
info->mOwner = owner;
- info->mIsEncoder = isEncoder;
+ info->mAttributes = attributes;
info->mRank = rank;
+ size_t numAliases = static_cast<size_t>(parcel.readInt32());
+ for (size_t i = 0; i < numAliases; i++) {
+ AString alias = AString::FromParcel(parcel);
+ info->mAliases.add(alias);
+ }
size_t size = static_cast<size_t>(parcel.readInt32());
for (size_t i = 0; i < size; i++) {
- AString mime = AString::FromParcel(parcel);
+ AString mediaType = AString::FromParcel(parcel);
sp<Capabilities> caps = Capabilities::FromParcel(parcel);
if (caps == NULL)
return NULL;
if (info != NULL) {
- info->mCaps.add(mime, caps);
+ info->mCaps.add(mediaType, caps);
}
}
return info;
@@ -196,8 +210,12 @@
status_t MediaCodecInfo::writeToParcel(Parcel *parcel) const {
mName.writeToParcel(parcel);
mOwner.writeToParcel(parcel);
- parcel->writeInt32(mIsEncoder);
+ parcel->writeInt32(mAttributes);
parcel->writeUint32(mRank);
+ parcel->writeInt32(mAliases.size());
+ for (const AString &alias : mAliases) {
+ alias.writeToParcel(parcel);
+ }
parcel->writeInt32(mCaps.size());
for (size_t i = 0; i < mCaps.size(); i++) {
mCaps.keyAt(i).writeToParcel(parcel);
@@ -206,10 +224,10 @@
return OK;
}
-ssize_t MediaCodecInfo::getCapabilityIndex(const char *mime) const {
- if (mime) {
+ssize_t MediaCodecInfo::getCapabilityIndex(const char *mediaType) const {
+ if (mediaType) {
for (size_t ix = 0; ix < mCaps.size(); ix++) {
- if (mCaps.keyAt(ix).equalsIgnoreCase(mime)) {
+ if (mCaps.keyAt(ix).equalsIgnoreCase(mediaType)) {
return ix;
}
}
@@ -217,19 +235,26 @@
return -1;
}
-MediaCodecInfo::MediaCodecInfo() : mRank(0x100) {
+MediaCodecInfo::MediaCodecInfo()
+ : mAttributes((MediaCodecInfo::Attributes)0),
+ mRank(0x100) {
}
void MediaCodecInfoWriter::setName(const char* name) {
mInfo->mName = name;
}
+void MediaCodecInfoWriter::addAlias(const char* name) {
+ mInfo->mAliases.add(name);
+}
+
void MediaCodecInfoWriter::setOwner(const char* owner) {
mInfo->mOwner = owner;
}
-void MediaCodecInfoWriter::setEncoder(bool isEncoder) {
- mInfo->mIsEncoder = isEncoder;
+void MediaCodecInfoWriter::setAttributes(
+ typename std::underlying_type<MediaCodecInfo::Attributes>::type attributes) {
+ mInfo->mAttributes = (MediaCodecInfo::Attributes)attributes;
}
void MediaCodecInfoWriter::setRank(uint32_t rank) {
@@ -237,21 +262,21 @@
}
std::unique_ptr<MediaCodecInfo::CapabilitiesWriter>
- MediaCodecInfoWriter::addMime(const char *mime) {
- ssize_t ix = mInfo->getCapabilityIndex(mime);
+ MediaCodecInfoWriter::addMediaType(const char *mediaType) {
+ ssize_t ix = mInfo->getCapabilityIndex(mediaType);
if (ix >= 0) {
return std::unique_ptr<MediaCodecInfo::CapabilitiesWriter>(
new MediaCodecInfo::CapabilitiesWriter(
mInfo->mCaps.valueAt(ix).get()));
}
sp<MediaCodecInfo::Capabilities> caps = new MediaCodecInfo::Capabilities();
- mInfo->mCaps.add(AString(mime), caps);
+ mInfo->mCaps.add(AString(mediaType), caps);
return std::unique_ptr<MediaCodecInfo::CapabilitiesWriter>(
new MediaCodecInfo::CapabilitiesWriter(caps.get()));
}
-bool MediaCodecInfoWriter::removeMime(const char *mime) {
- ssize_t ix = mInfo->getCapabilityIndex(mime);
+bool MediaCodecInfoWriter::removeMediaType(const char *mediaType) {
+ ssize_t ix = mInfo->getCapabilityIndex(mediaType);
if (ix >= 0) {
mInfo->mCaps.removeItemsAt(ix);
return true;
diff --git a/media/libmedia/include/media/MediaCodecInfo.h b/media/libmedia/include/media/MediaCodecInfo.h
index b3777d3..54f565a 100644
--- a/media/libmedia/include/media/MediaCodecInfo.h
+++ b/media/libmedia/include/media/MediaCodecInfo.h
@@ -30,6 +30,8 @@
#include <utils/Vector.h>
#include <utils/StrongPointer.h>
+#include <type_traits>
+
namespace android {
struct AMessage;
@@ -51,21 +53,47 @@
struct CapabilitiesWriter;
+ enum Attributes : int32_t {
+ // attribute flags
+ kFlagIsEncoder = 1 << 0,
+ kFlagIsVendor = 1 << 1,
+ kFlagIsSoftwareOnly = 1 << 2,
+ kFlagIsHardwareAccelerated = 1 << 3,
+ };
+
struct Capabilities : public RefBase {
- enum {
- // decoder flags
- kFlagSupportsAdaptivePlayback = 1 << 0,
- kFlagSupportsSecurePlayback = 1 << 1,
- kFlagSupportsTunneledPlayback = 1 << 2,
+ constexpr static char FEATURE_ADAPTIVE_PLAYBACK[] = "feature-adaptive-playback";
+ constexpr static char FEATURE_DYNAMIC_TIMESTAMP[] = "feature-dynamic-timestamp";
+ constexpr static char FEATURE_FRAME_PARSING[] = "feature-frame-parsing";
+ constexpr static char FEATURE_INTRA_REFRESH[] = "feature-frame-parsing";
+ constexpr static char FEATURE_MULTIPLE_FRAMES[] = "feature-multiple-frames";
+ constexpr static char FEATURE_SECURE_PLAYBACK[] = "feature-secure-playback";
+ constexpr static char FEATURE_TUNNELED_PLAYBACK[] = "feature-tunneled-playback";
- // encoder flags
- kFlagSupportsIntraRefresh = 1 << 0,
-
- };
-
+ /**
+ * Returns the supported levels for each supported profile in a target array.
+ *
+ * @param profileLevels target array for the profile levels.
+ */
void getSupportedProfileLevels(Vector<ProfileLevel> *profileLevels) const;
+
+ /**
+ * Returns the supported color formats in a target array. Only used for video/image
+ * components.
+ *
+ * @param colorFormats target array for the color formats.
+ */
void getSupportedColorFormats(Vector<uint32_t> *colorFormats) const;
- uint32_t getFlags() const;
+
+ /**
+ * Returns metadata associated with this codec capability.
+ *
+ * This contains:
+ * - features,
+ * - performance data.
+ *
+ * TODO: expose this as separate API-s and wrap here.
+ */
const sp<AMessage> getDetails() const;
protected:
@@ -73,7 +101,6 @@
SortedVector<ProfileLevel> mProfileLevelsSorted;
Vector<uint32_t> mColorFormats;
SortedVector<uint32_t> mColorFormatsSorted;
- uint32_t mFlags;
sp<AMessage> mDetails;
Capabilities();
@@ -93,8 +120,7 @@
/**
* This class is used for modifying information inside a `Capabilities`
* object. An object of type `CapabilitiesWriter` can be obtained by calling
- * `MediaCodecInfoWriter::addMime()` or
- * `MediaCodecInfoWriter::updateMime()`.
+ * `MediaCodecInfoWriter::addMediaType()`.
*/
struct CapabilitiesWriter {
/**
@@ -122,6 +148,13 @@
*/
void addDetail(const char* key, int32_t value);
/**
+ * Removes a key-value pair from the list of details. If the key is not
+ * present, this call does nothing.
+ *
+ * @param key The key.
+ */
+ void removeDetail(const char* key);
+ /**
* Add a profile-level pair. If this profile-level pair already exists,
* it will be ignored.
*
@@ -136,13 +169,7 @@
* @param format The color format.
*/
void addColorFormat(uint32_t format);
- /**
- * Add flags. The underlying operation is bitwise-or. In other words,
- * bits that have already been set will be ignored.
- *
- * @param flags The additional flags.
- */
- void addFlags(uint32_t flags);
+
private:
/**
* The associated `Capabilities` object.
@@ -158,19 +185,42 @@
friend MediaCodecInfoWriter;
};
- bool isEncoder() const;
- void getSupportedMimes(Vector<AString> *mimes) const;
- const sp<Capabilities> getCapabilitiesFor(const char *mime) const;
+ inline bool isEncoder() const {
+ return getAttributes() & kFlagIsEncoder;
+ }
+
+ Attributes getAttributes() const;
+ void getSupportedMediaTypes(Vector<AString> *mediaTypes) const;
+ const sp<Capabilities> getCapabilitiesFor(const char *mediaType) const;
const char *getCodecName() const;
/**
+ * Returns a vector containing alternate names for the codec.
+ *
+ * \param aliases the destination array for the aliases. This is cleared.
+ *
+ * Multiple codecs may share alternate names as long as their supported media types are
+ * distinct; however, these will result in different aliases for the MediaCodec user as
+ * the canonical codec has to be resolved without knowing the media type in
+ * MediaCodec::CreateByComponentName.
+ */
+ void getAliases(Vector<AString> *aliases) const;
+
+ /**
* Return the name of the service that hosts the codec. This value is not
* visible at the Java level.
*
* Currently, this is the "instance name" of the IOmx service.
*/
const char *getOwnerName() const;
- uint32_t rank() const;
+
+ /**
+ * Returns the rank of the component.
+ *
+ * Technically this is defined to be per media type, but that makes ordering the MediaCodecList
+ * impossible as MediaCodecList is ordered by codec name.
+ */
+ uint32_t getRank() const;
/**
* Serialization over Binder
@@ -181,11 +231,12 @@
private:
AString mName;
AString mOwner;
- bool mIsEncoder;
+ Attributes mAttributes;
KeyedVector<AString, sp<Capabilities> > mCaps;
+ Vector<AString> mAliases;
uint32_t mRank;
- ssize_t getCapabilityIndex(const char *mime) const;
+ ssize_t getCapabilityIndex(const char *mediaType) const;
/**
* Construct an `MediaCodecInfo` object. After the construction, its
@@ -219,6 +270,13 @@
*/
void setName(const char* name);
/**
+ * Adds an alias (alternate name) for the codec. Multiple codecs can share an alternate name
+ * as long as their supported media types are distinct.
+ *
+ * @param name an alternate name.
+ */
+ void addAlias(const char* name);
+ /**
* Set the owner name of the codec.
*
* This "owner name" is the name of the `IOmx` instance that supports this
@@ -228,32 +286,32 @@
*/
void setOwner(const char* owner);
/**
- * Set whether this codec is an encoder or a decoder.
+ * Sets codec attributes.
*
- * @param isEncoder Whether this codec is an encoder or a decoder.
+ * @param attributes Codec attributes.
*/
- void setEncoder(bool isEncoder = true);
+ void setAttributes(typename std::underlying_type<MediaCodecInfo::Attributes>::type attributes);
/**
- * Add a mime to an indexed list and return a `CapabilitiesWriter` object
+ * Add a media type to an indexed list and return a `CapabilitiesWriter` object
* that can be used for modifying the associated `Capabilities`.
*
- * If the mime already exists, this function will return the
- * `CapabilitiesWriter` associated with the mime.
+ * If the media type already exists, this function will return the
+ * `CapabilitiesWriter` associated with the media type.
*
- * @param[in] mime The name of a new mime to add.
+ * @param[in] mediaType The name of a new media type to add.
* @return writer The `CapabilitiesWriter` object for modifying the
- * `Capabilities` associated with the mime. `writer` will be valid
- * regardless of whether `mime` already exists or not.
+ * `Capabilities` associated with the media type. `writer` will be valid
+ * regardless of whether `mediaType` already exists or not.
*/
- std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> addMime(
- const char* mime);
+ std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> addMediaType(
+ const char* mediaType);
/**
- * Remove a mime.
+ * Remove a media type.
*
- * @param mime The name of the mime to remove.
- * @return `true` if `mime` is removed; `false` if `mime` is not found.
+ * @param mediaType The name of the media type to remove.
+ * @return `true` if `mediaType` is removed; `false` if `mediaType` is not found.
*/
- bool removeMime(const char* mime);
+ bool removeMediaType(const char* mediaType);
/**
* Set rank of the codec. MediaCodecList will stable-sort the list according
* to rank in non-descending order.
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index dadfe28..a1a2660 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -8682,14 +8682,17 @@
if (omxNode->configureVideoTunnelMode(
kPortIndexOutput, OMX_TRUE, 0, &sidebandHandle) == OK) {
// tunneled playback includes adaptive playback
- caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback
- | MediaCodecInfo::Capabilities::kFlagSupportsTunneledPlayback);
- } else if (omxNode->setPortMode(
- kPortIndexOutput, IOMX::kPortModeDynamicANWBuffer) == OK ||
- omxNode->prepareForAdaptivePlayback(
- kPortIndexOutput, OMX_TRUE,
- 1280 /* width */, 720 /* height */) == OK) {
- caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsAdaptivePlayback);
+ } else {
+ // tunneled playback is not supported
+ caps->removeDetail(MediaCodecInfo::Capabilities::FEATURE_TUNNELED_PLAYBACK);
+ if (omxNode->setPortMode(
+ kPortIndexOutput, IOMX::kPortModeDynamicANWBuffer) != OK &&
+ omxNode->prepareForAdaptivePlayback(
+ kPortIndexOutput, OMX_TRUE,
+ 1280 /* width */, 720 /* height */) != OK) {
+ // adaptive playback is not supported
+ caps->removeDetail(MediaCodecInfo::Capabilities::FEATURE_ADAPTIVE_PLAYBACK);
+ }
}
}
@@ -8697,11 +8700,20 @@
OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE params;
InitOMXParams(¶ms);
params.nPortIndex = kPortIndexOutput;
- // TODO: should we verify if fallback is supported?
+
+ OMX_VIDEO_PARAM_INTRAREFRESHTYPE fallbackParams;
+ InitOMXParams(&fallbackParams);
+ fallbackParams.nPortIndex = kPortIndexOutput;
+ fallbackParams.eRefreshMode = OMX_VIDEO_IntraRefreshCyclic;
+
if (omxNode->getConfig(
(OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh,
- ¶ms, sizeof(params)) == OK) {
- caps->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsIntraRefresh);
+ ¶ms, sizeof(params)) != OK &&
+ omxNode->getParameter(
+ OMX_IndexParamVideoIntraRefresh, &fallbackParams,
+ sizeof(fallbackParams)) != OK) {
+ // intra refresh is not supported
+ caps->removeDetail(MediaCodecInfo::Capabilities::FEATURE_INTRA_REFRESH);
}
}
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 7816fae..2547888 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -911,10 +911,10 @@
continue;
}
mCodecInfo = mcl->getCodecInfo(codecIdx);
- Vector<AString> mimes;
- mCodecInfo->getSupportedMimes(&mimes);
- for (size_t i = 0; i < mimes.size(); i++) {
- if (mimes[i].startsWith("video/")) {
+ Vector<AString> mediaTypes;
+ mCodecInfo->getSupportedMediaTypes(&mediaTypes);
+ for (size_t i = 0; i < mediaTypes.size(); i++) {
+ if (mediaTypes[i].startsWith("video/")) {
mIsVideo = true;
break;
}
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index eaff283..93478e9 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -215,13 +215,9 @@
mCodecInfos.begin(),
mCodecInfos.end(),
[](const sp<MediaCodecInfo> &info1, const sp<MediaCodecInfo> &info2) {
- if (info2 == nullptr) {
- return false;
- } else if (info1 == nullptr) {
- return true;
- } else {
- return info1->rank() < info2->rank();
- }
+ // null is lowest
+ return info1 == nullptr
+ || (info2 != nullptr && info1->getRank() < info2->getRank());
});
}
diff --git a/media/libstagefright/MediaCodecListOverrides.cpp b/media/libstagefright/MediaCodecListOverrides.cpp
index cac53f4..dd7c3e6 100644
--- a/media/libstagefright/MediaCodecListOverrides.cpp
+++ b/media/libstagefright/MediaCodecListOverrides.cpp
@@ -228,18 +228,18 @@
continue;
}
- Vector<AString> mimes;
- info->getSupportedMimes(&mimes);
- for (size_t i = 0; i < mimes.size(); ++i) {
+ Vector<AString> mediaTypes;
+ info->getSupportedMediaTypes(&mediaTypes);
+ for (size_t i = 0; i < mediaTypes.size(); ++i) {
const sp<MediaCodecInfo::Capabilities> &caps =
- info->getCapabilitiesFor(mimes[i].c_str());
+ info->getCapabilitiesFor(mediaTypes[i].c_str());
if (!forceToMeasure &&
(caps->getDetails()->contains("max-supported-instances") ||
caps->getDetails()->contains("max-concurrent-instances"))) {
continue;
}
- size_t max = doProfileCodecs(info->isEncoder(), name, mimes[i], caps);
+ size_t max = doProfileCodecs(info->isEncoder(), name, mediaTypes[i], caps);
if (max > 0) {
CodecSettings settings;
char maxStr[32];
@@ -248,7 +248,7 @@
AString key = name;
key.append(" ");
- key.append(mimes[i]);
+ key.append(mediaTypes[i]);
if (info->isEncoder()) {
encoder_results->add(key, settings);
diff --git a/media/libstagefright/OmxInfoBuilder.cpp b/media/libstagefright/OmxInfoBuilder.cpp
index 96b896b..382c947 100644
--- a/media/libstagefright/OmxInfoBuilder.cpp
+++ b/media/libstagefright/OmxInfoBuilder.cpp
@@ -57,14 +57,9 @@
}
status_t queryCapabilities(
- const IOmxStore::NodeInfo& node, const char* mime, bool isEncoder,
+ const IOmxStore::NodeInfo& node, const char* mediaType, bool isEncoder,
MediaCodecInfo::CapabilitiesWriter* caps) {
sp<ACodec> codec = new ACodec();
- status_t err = codec->queryCapabilities(
- node.owner.c_str(), node.name.c_str(), mime, isEncoder, caps);
- if (err != OK) {
- return err;
- }
for (const auto& attribute : node.attributes) {
// All features have an int32 value except
// "feature-bitrate-modes", which has a string value.
@@ -81,6 +76,12 @@
attribute.key.c_str(), attribute.value.c_str());
}
}
+ // query capabilities may remove capabilities that are not actually supported by the codec
+ status_t err = codec->queryCapabilities(
+ node.owner.c_str(), node.name.c_str(), mediaType, isEncoder, caps);
+ if (err != OK) {
+ return err;
+ }
return OK;
}
@@ -163,7 +164,10 @@
info = c2i->second.get();
info->setName(nodeName.c_str());
info->setOwner(node.owner.c_str());
- info->setEncoder(isEncoder);
+ info->setAttributes(
+ // all OMX codecs are vendor codecs (in the vendor partition), but
+ // treat OMX.google codecs as non-hardware-accelerated and non-vendor
+ (isEncoder ? MediaCodecInfo::kFlagIsEncoder : 0));
info->setRank(defaultRank);
} else {
// The node has been seen before. Simply retrieve the
@@ -180,7 +184,19 @@
info = c2i->second.get();
info->setName(nodeName.c_str());
info->setOwner(node.owner.c_str());
- info->setEncoder(isEncoder);
+ typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs =
+ MediaCodecInfo::kFlagIsVendor;
+ if (isEncoder) {
+ attrs |= MediaCodecInfo::kFlagIsEncoder;
+ }
+ if (std::count_if(
+ node.attributes.begin(), node.attributes.end(),
+ [](const IOmxStore::Attribute &i) -> bool {
+ return i.key == "attribute::software-codec";
+ })) {
+ attrs |= MediaCodecInfo::kFlagIsHardwareAccelerated;
+ }
+ info->setAttributes(attrs);
info->setRank(defaultRank);
} else {
// If preferPlatformNodes is true, this node must be
@@ -195,12 +211,12 @@
}
}
std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
- info->addMime(typeName.c_str());
+ info->addMediaType(typeName.c_str());
if (queryCapabilities(
node, typeName.c_str(), isEncoder, caps.get()) != OK) {
- ALOGW("Fail to add mime %s to codec %s",
+ ALOGW("Fail to add media type %s to codec %s",
typeName.c_str(), nodeName.c_str());
- info->removeMime(typeName.c_str());
+ info->removeMediaType(typeName.c_str());
}
}
@@ -219,7 +235,18 @@
info = c2i->second.get();
info->setName(nodeName.c_str());
info->setOwner(node->owner.c_str());
- info->setEncoder(isEncoder);
+ typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs =
+ MediaCodecInfo::kFlagIsVendor;
+ if (isEncoder) {
+ attrs |= MediaCodecInfo::kFlagIsEncoder;
+ }
+ if (std::count_if(
+ node->attributes.begin(), node->attributes.end(),
+ [](const IOmxStore::Attribute &i) -> bool {
+ return i.key == "attribute::software-codec";
+ })) {
+ attrs |= MediaCodecInfo::kFlagIsHardwareAccelerated;
+ }
info->setRank(defaultRank);
} else {
// The node has been seen before. Simply retrieve the
@@ -227,13 +254,13 @@
info = c2i->second.get();
}
std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
- info->addMime(typeName.c_str());
+ info->addMediaType(typeName.c_str());
if (queryCapabilities(
*node, typeName.c_str(), isEncoder, caps.get()) != OK) {
- ALOGW("Fail to add mime %s to codec %s "
+ ALOGW("Fail to add media type %s to codec %s "
"after software codecs",
typeName.c_str(), nodeName.c_str());
- info->removeMime(typeName.c_str());
+ info->removeMediaType(typeName.c_str());
}
}
}
diff --git a/media/libstagefright/omx/1.0/Omx.cpp b/media/libstagefright/omx/1.0/Omx.cpp
index 4e2d398..121bb1a 100644
--- a/media/libstagefright/omx/1.0/Omx.cpp
+++ b/media/libstagefright/omx/1.0/Omx.cpp
@@ -124,11 +124,11 @@
} else {
uint32_t quirks = 0;
for (const auto& quirk : codec->second.quirkSet) {
- if (quirk == "requires-allocate-on-input-ports") {
+ if (quirk == "quirk::requires-allocate-on-input-ports") {
quirks |= OMXNodeInstance::
kRequiresAllocateBufferOnInputPorts;
}
- if (quirk == "requires-allocate-on-output-ports") {
+ if (quirk == "quirk::requires-allocate-on-output-ports") {
quirks |= OMXNodeInstance::
kRequiresAllocateBufferOnOutputPorts;
}
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
index 2dec9fa..6e541ba 100644
--- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -26,8 +26,9 @@
#include <sys/stat.h>
#include <expat.h>
-#include <cctype>
#include <algorithm>
+#include <cctype>
+#include <string>
namespace android {
@@ -326,8 +327,8 @@
case SECTION_DECODER:
case SECTION_ENCODER:
{
- if (strEq(name, "Quirk")) {
- (void)addQuirk(attrs);
+ if (strEq(name, "Quirk") || strEq(name, "Attribute")) {
+ (void)addQuirk(attrs, name);
} else if (strEq(name, "Type")) {
(void)addTypeFromAttributes(attrs,
(mCurrentSection == SECTION_ENCODER));
@@ -348,6 +349,8 @@
if (outside &&
(strEq(name, "Limit") || strEq(name, "Feature"))) {
ALOGW("ignoring %s specified outside of a Type", name);
+ } else if (strEq(name, "Alias")) {
+ (void)addAlias(attrs);
} else if (strEq(name, "Limit")) {
(void)addLimit(attrs);
} else if (strEq(name, "Feature")) {
@@ -579,7 +582,7 @@
return OK;
}
-status_t MediaCodecsXmlParser::addQuirk(const char **attrs) {
+status_t MediaCodecsXmlParser::addQuirk(const char **attrs, const char *tag) {
if (mCurrentCodec == mCodecMap.end()) {
return BAD_VALUE;
}
@@ -606,7 +609,12 @@
return BAD_VALUE;
}
- mCurrentCodec->second.quirkSet.emplace(name);
+ std::string tagString = tag;
+ std::transform(tagString.begin(), tagString.end(), tagString.begin(), ::tolower);
+ tagString.append("::");
+ tagString.append(name);
+ mCurrentCodec->second.quirkSet.emplace(tagString.c_str());
+ ALOGI("adding %s to %s", tagString.c_str(), mCurrentCodec->first.c_str());
return OK;
}
@@ -760,6 +768,7 @@
strEq(a_name, "quality") ||
strEq(a_name, "size") ||
strEq(a_name, "measured-blocks-per-second") ||
+ strHasPrefix(a_name, "performance-point-") ||
strHasPrefix(a_name, "measured-frame-rate-")) {
// "range" is specified in exactly one of the following forms:
// 1) min-max
@@ -964,6 +973,34 @@
return OK;
}
+status_t MediaCodecsXmlParser::addAlias(const char **attrs) {
+ size_t i = 0;
+ const char *name = nullptr;
+
+ while (attrs[i] != nullptr) {
+ if (strEq(attrs[i], "name")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addAlias: name is null");
+ return BAD_VALUE;
+ }
+ name = attrs[i];
+ } else {
+ ALOGE("addAlias: unrecognized attribute: %s", attrs[i]);
+ return BAD_VALUE;
+ }
+ ++i;
+ }
+
+ // Every feature must have a name.
+ if (name == nullptr) {
+ ALOGE("alias with no 'name' attribute");
+ return BAD_VALUE;
+ }
+
+ mCurrentCodec->second.aliases.emplace_back(name);
+ return OK;
+}
+
const MediaCodecsXmlParser::AttributeMap&
MediaCodecsXmlParser::getServiceAttributeMap() const {
return mServiceAttributeMap;
@@ -1041,11 +1078,18 @@
NodeInfo nodeInfo;
nodeInfo.name = codecName;
+ // NOTE: no aliases are exposed in role info
+ // attribute quirks are exposed as node attributes
nodeInfo.attributeList.reserve(typeAttributeMap.size());
for (const auto& attribute : typeAttributeMap) {
nodeInfo.attributeList.push_back(
Attribute{attribute.first, attribute.second});
}
+ for (const std::string &quirk : codec.second.quirkSet) {
+ if (strHasPrefix(quirk.c_str(), "attribute::")) {
+ nodeInfo.attributeList.push_back(Attribute{quirk, "present"});
+ }
+ }
nodeList->insert(std::make_pair(
std::move(order), std::move(nodeInfo)));
}
diff --git a/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h b/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h
index cc69e52..fd949da 100644
--- a/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h
+++ b/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h
@@ -65,6 +65,7 @@
size_t order; ///< Order of appearance in the file (starting from 0)
QuirkSet quirkSet; ///< Set of quirks requested by this codec
TypeMap typeMap; ///< Map of types supported by this codec
+ std::vector<std::string> aliases; ///< Name aliases for this codec
};
typedef std::pair<std::string, CodecProperties> Codec;
@@ -76,6 +77,7 @@
struct NodeInfo {
std::string name;
std::vector<Attribute> attributeList;
+ // note: aliases are not exposed here as they are not part of the role map
};
/**
@@ -171,8 +173,9 @@
void addMediaCodec(bool encoder, const char *name,
const char *type = nullptr);
- status_t addQuirk(const char **attrs);
+ status_t addQuirk(const char **attrs, const char *tag);
status_t addTypeFromAttributes(const char **attrs, bool encoder);
+ status_t addAlias(const char **attrs);
status_t addLimit(const char **attrs);
status_t addFeature(const char **attrs);
void addType(const char *name);