Merge changes I373db2f4,I3f0cc1dd,I05f8ed86,Iec0cc3d2,I01cfcaf1, ...
* changes:
codec2: signal aliases in XML vs. C2Store
codec2: Codec2InfoBuilder rework
stagefright: list only the first codec for a given name
stagefright: find codecs by their aliases as well
stagefright: MediaCodecsXmlParser: add support for parsing rank
stagefright: add method to MediaCodecInfoWriter to find existing info
stagefright: rework and simplify OmxInfoBuilder
codec2: CCodec plugin CreateInputSurface should create C2 HAL surface
codec2: C2PlatformStore: signal component traits via interface
codec2: make C2Component::Traits.aliases a vector of C2Strings
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
index c38e674..b9f3aa8 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
@@ -120,11 +120,9 @@
IComponentStore::ComponentTraits* d,
const C2Component::Traits& s);
-// ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
-// Note: The output d is only valid as long as aliasesBuffer remains alive.
+// ComponentTraits -> C2Component::Traits
bool objcpy(
C2Component::Traits* d,
- std::unique_ptr<std::vector<std::string>>* aliasesBuffer,
const IComponentStore::ComponentTraits& s);
// C2StructDescriptor -> StructDescriptor
diff --git a/media/codec2/hidl/1.0/utils/types.cpp b/media/codec2/hidl/1.0/utils/types.cpp
index caed839..02cdc23 100644
--- a/media/codec2/hidl/1.0/utils/types.cpp
+++ b/media/codec2/hidl/1.0/utils/types.cpp
@@ -351,7 +351,6 @@
// ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
bool objcpy(
C2Component::Traits* d,
- std::unique_ptr<std::vector<std::string>>* aliasesBuffer,
const IComponentStore::ComponentTraits& s) {
d->name = s.name.c_str();
@@ -394,15 +393,9 @@
d->rank = static_cast<C2Component::rank_t>(s.rank);
d->mediaType = s.mediaType.c_str();
-
- // aliasesBuffer must not be resized after this.
- *aliasesBuffer = std::make_unique<std::vector<std::string>>(
- s.aliases.size());
- (*aliasesBuffer)->resize(s.aliases.size());
- std::vector<C2StringLiteral> dAliases(s.aliases.size());
+ d->aliases.resize(s.aliases.size());
for (size_t i = 0; i < s.aliases.size(); ++i) {
- (**aliasesBuffer)[i] = s.aliases[i].c_str();
- d->aliases[i] = (**aliasesBuffer)[i].c_str();
+ d->aliases[i] = s.aliases[i];
}
return true;
}
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index e02c2ca..3808be5 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -564,9 +564,8 @@
return;
}
mTraitsList.resize(t.size());
- mAliasesBuffer.resize(t.size());
for (size_t i = 0; i < t.size(); ++i) {
- if (!objcpy(&mTraitsList[i], &mAliasesBuffer[i], t[i])) {
+ if (!objcpy(&mTraitsList[i], t[i])) {
LOG(ERROR) << "listComponents -- corrupted output.";
return;
}
diff --git a/media/codec2/hidl/client/include/codec2/hidl/client.h b/media/codec2/hidl/client/include/codec2/hidl/client.h
index 5b3afca..478ce6e 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/client.h
@@ -232,8 +232,6 @@
mutable bool mListed;
std::string mServiceName;
mutable std::vector<C2Component::Traits> mTraitsList;
- mutable std::vector<std::unique_ptr<std::vector<std::string>>>
- mAliasesBuffer;
sp<::android::hardware::media::bufferpool::V2_0::IClientManager>
mHostPoolManager;
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index ed1f85b..bc22045 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -937,6 +937,47 @@
(new AMessage(kWhatCreateInputSurface, this))->post();
}
+sp<PersistentSurface> CCodec::CreateOmxInputSurface() {
+ using namespace android::hardware::media::omx::V1_0;
+ using namespace android::hardware::media::omx::V1_0::utils;
+ using namespace android::hardware::graphics::bufferqueue::V1_0::utils;
+ typedef android::hardware::media::omx::V1_0::Status OmxStatus;
+ android::sp<IOmx> omx = IOmx::getService();
+ typedef android::hardware::graphics::bufferqueue::V1_0::
+ IGraphicBufferProducer HGraphicBufferProducer;
+ typedef android::hardware::media::omx::V1_0::
+ IGraphicBufferSource HGraphicBufferSource;
+ OmxStatus s;
+ android::sp<HGraphicBufferProducer> gbp;
+ android::sp<HGraphicBufferSource> gbs;
+ android::Return<void> transStatus = omx->createInputSurface(
+ [&s, &gbp, &gbs](
+ OmxStatus status,
+ const android::sp<HGraphicBufferProducer>& producer,
+ const android::sp<HGraphicBufferSource>& source) {
+ s = status;
+ gbp = producer;
+ gbs = source;
+ });
+ if (transStatus.isOk() && s == OmxStatus::OK) {
+ return new PersistentSurface(
+ new H2BGraphicBufferProducer(gbp),
+ sp<::android::IGraphicBufferSource>(new LWGraphicBufferSource(gbs)));
+ }
+
+ return nullptr;
+}
+
+sp<PersistentSurface> CCodec::CreateCompatibleInputSurface() {
+ sp<PersistentSurface> surface(CreateInputSurface());
+
+ if (surface == nullptr) {
+ surface = CreateOmxInputSurface();
+ }
+
+ return surface;
+}
+
void CCodec::createInputSurface() {
status_t err;
sp<IGraphicBufferProducer> bufferProducer;
@@ -949,7 +990,7 @@
outputFormat = config->mOutputFormat;
}
- std::shared_ptr<PersistentSurface> persistentSurface(CreateInputSurface());
+ sp<PersistentSurface> persistentSurface = CreateCompatibleInputSurface();
if (persistentSurface->getHidlTarget()) {
sp<IInputSurface> hidlInputSurface = IInputSurface::castFrom(
@@ -1669,46 +1710,17 @@
return new android::CCodec;
}
+// Create Codec 2.0 input surface
extern "C" android::PersistentSurface *CreateInputSurface() {
// Attempt to create a Codec2's input surface.
std::shared_ptr<android::Codec2Client::InputSurface> inputSurface =
android::Codec2Client::CreateInputSurface();
- if (inputSurface) {
- return new android::PersistentSurface(
- inputSurface->getGraphicBufferProducer(),
- static_cast<android::sp<android::hidl::base::V1_0::IBase>>(
- inputSurface->getHalInterface()));
+ if (!inputSurface) {
+ return nullptr;
}
-
- // Fall back to OMX.
- using namespace android::hardware::media::omx::V1_0;
- using namespace android::hardware::media::omx::V1_0::utils;
- using namespace android::hardware::graphics::bufferqueue::V1_0::utils;
- typedef android::hardware::media::omx::V1_0::Status OmxStatus;
- android::sp<IOmx> omx = IOmx::getService();
- typedef android::hardware::graphics::bufferqueue::V1_0::
- IGraphicBufferProducer HGraphicBufferProducer;
- typedef android::hardware::media::omx::V1_0::
- IGraphicBufferSource HGraphicBufferSource;
- OmxStatus s;
- android::sp<HGraphicBufferProducer> gbp;
- android::sp<HGraphicBufferSource> gbs;
- android::Return<void> transStatus = omx->createInputSurface(
- [&s, &gbp, &gbs](
- OmxStatus status,
- const android::sp<HGraphicBufferProducer>& producer,
- const android::sp<HGraphicBufferSource>& source) {
- s = status;
- gbp = producer;
- gbs = source;
- });
- if (transStatus.isOk() && s == OmxStatus::OK) {
- return new android::PersistentSurface(
- new H2BGraphicBufferProducer(gbp),
- sp<::android::IGraphicBufferSource>(
- new LWGraphicBufferSource(gbs)));
- }
-
- return nullptr;
+ return new android::PersistentSurface(
+ inputSurface->getGraphicBufferProducer(),
+ static_cast<android::sp<android::hidl::base::V1_0::IBase>>(
+ inputSurface->getHalInterface()));
}
diff --git a/media/codec2/sfplugin/CCodec.h b/media/codec2/sfplugin/CCodec.h
index bb8bd19..ba5f5f3 100644
--- a/media/codec2/sfplugin/CCodec.h
+++ b/media/codec2/sfplugin/CCodec.h
@@ -89,6 +89,16 @@
void flush();
void release(bool sendCallback);
+ /**
+ * Creates an input surface for the current device configuration compatible with CCodec.
+ * This could be backed by the C2 HAL or the OMX HAL.
+ */
+ static sp<PersistentSurface> CreateCompatibleInputSurface();
+
+ /// Creates an input surface to the OMX HAL
+ static sp<PersistentSurface> CreateOmxInputSurface();
+
+ /// handle a create input surface call
void createInputSurface();
void setInputSurface(const sp<PersistentSurface> &surface);
status_t setupInputSurface(const std::shared_ptr<InputSurfaceWrapper> &surface);
diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
index 5f0dd0b..ead0a9b 100644
--- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp
+++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
@@ -68,262 +68,146 @@
s.compare(s.size() - suffixLen, suffixLen, suffix) == 0;
}
-// Constants from ACodec
-constexpr OMX_U32 kPortIndexInput = 0;
-constexpr OMX_U32 kPortIndexOutput = 1;
-constexpr OMX_U32 kMaxIndicesToCheck = 32;
+void addSupportedProfileLevels(
+ std::shared_ptr<Codec2Client::Interface> intf,
+ MediaCodecInfo::CapabilitiesWriter *caps,
+ const Traits& trait, const std::string &mediaType) {
+ std::shared_ptr<C2Mapper::ProfileLevelMapper> mapper =
+ C2Mapper::GetProfileLevelMapper(trait.mediaType);
+ // if we don't know the media type, pass through all values unmapped
-status_t queryOmxCapabilities(
- const char* name, const char* mediaType, bool isEncoder,
- MediaCodecInfo::CapabilitiesWriter* caps) {
-
- const char *role = GetComponentRole(isEncoder, mediaType);
- if (role == nullptr) {
- return BAD_VALUE;
- }
-
- using namespace ::android::hardware::media::omx::V1_0;
- using ::android::hardware::Return;
- using ::android::hardware::Void;
- using ::android::hardware::hidl_vec;
- using ::android::hardware::media::omx::V1_0::utils::LWOmxNode;
-
- sp<IOmx> omx = IOmx::getService();
- if (!omx) {
- ALOGW("Could not obtain IOmx service.");
- return NO_INIT;
- }
-
- struct Observer : IOmxObserver {
- virtual Return<void> onMessages(const hidl_vec<Message>&) override {
- return Void();
- }
+ // TODO: we cannot find levels that are local 'maxima' without knowing the coding
+ // e.g. H.263 level 45 and level 30 could be two values for highest level as
+ // they don't include one another. For now we use the last supported value.
+ bool encoder = trait.kind == C2Component::KIND_ENCODER;
+ C2StreamProfileLevelInfo pl(encoder /* output */, 0u);
+ std::vector<C2FieldSupportedValuesQuery> profileQuery = {
+ C2FieldSupportedValuesQuery::Possible(C2ParamField(&pl, &pl.profile))
};
- sp<Observer> observer = new Observer();
- Status status;
- sp<IOmxNode> tOmxNode;
- Return<void> transStatus = omx->allocateNode(
- name, observer,
- [&status, &tOmxNode](Status s, const sp<IOmxNode>& n) {
- status = s;
- tOmxNode = n;
- });
- if (!transStatus.isOk()) {
- ALOGW("IOmx::allocateNode -- transaction failed.");
- return NO_INIT;
- }
- if (status != Status::OK) {
- ALOGW("IOmx::allocateNode -- error returned: %d.",
- static_cast<int>(status));
- return NO_INIT;
+ c2_status_t err = intf->querySupportedValues(profileQuery, C2_DONT_BLOCK);
+ ALOGV("query supported profiles -> %s | %s", asString(err), asString(profileQuery[0].status));
+ if (err != C2_OK || profileQuery[0].status != C2_OK) {
+ return;
}
- sp<LWOmxNode> omxNode = new LWOmxNode(tOmxNode);
-
- status_t err = SetComponentRole(omxNode, role);
- if (err != OK) {
- omxNode->freeNode();
- ALOGW("Failed to SetComponentRole: component = %s, role = %s.",
- name, role);
- return err;
+ // we only handle enumerated values
+ if (profileQuery[0].values.type != C2FieldSupportedValues::VALUES) {
+ return;
}
- bool isVideo = hasPrefix(mediaType, "video/") == 0;
- bool isImage = hasPrefix(mediaType, "image/") == 0;
+ // determine if codec supports HDR
+ bool supportsHdr = false;
+ bool supportsHdr10Plus = false;
- if (isVideo || isImage) {
- OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
- InitOMXParams(¶m);
- param.nPortIndex = isEncoder ? kPortIndexOutput : kPortIndexInput;
-
- for (OMX_U32 index = 0; index <= kMaxIndicesToCheck; ++index) {
- param.nProfileIndex = index;
- status_t err = omxNode->getParameter(
- OMX_IndexParamVideoProfileLevelQuerySupported,
- ¶m, sizeof(param));
- if (err != OK) {
+ std::vector<std::shared_ptr<C2ParamDescriptor>> paramDescs;
+ c2_status_t err1 = intf->querySupportedParams(¶mDescs);
+ if (err1 == C2_OK) {
+ for (const std::shared_ptr<C2ParamDescriptor> &desc : paramDescs) {
+ switch ((uint32_t)desc->index()) {
+ case C2StreamHdr10PlusInfo::output::PARAM_TYPE:
+ supportsHdr10Plus = true;
+ break;
+ case C2StreamHdrStaticInfo::output::PARAM_TYPE:
+ supportsHdr = true;
+ break;
+ default:
break;
}
- caps->addProfileLevel(param.eProfile, param.eLevel);
-
- // 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(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) {
- caps->addProfileLevel(OMX_VIDEO_AVCProfileConstrainedBaseline, param.eLevel);
- }
- }
-
- if (index == kMaxIndicesToCheck) {
- ALOGW("[%s] stopping checking profiles after %u: %x/%x",
- name, index,
- param.eProfile, param.eLevel);
- }
- }
-
- // Color format query
- // return colors in the order reported by the OMX component
- // prefix "flexible" standard ones with the flexible equivalent
- OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat;
- InitOMXParams(&portFormat);
- portFormat.nPortIndex = isEncoder ? kPortIndexInput : kPortIndexOutput;
- for (OMX_U32 index = 0; index <= kMaxIndicesToCheck; ++index) {
- portFormat.nIndex = index;
- status_t err = omxNode->getParameter(
- OMX_IndexParamVideoPortFormat,
- &portFormat, sizeof(portFormat));
- if (err != OK) {
- break;
- }
-
- OMX_U32 flexibleEquivalent;
- if (IsFlexibleColorFormat(
- omxNode, portFormat.eColorFormat, false /* usingNativeWindow */,
- &flexibleEquivalent)) {
- caps->addColorFormat(flexibleEquivalent);
- }
- caps->addColorFormat(portFormat.eColorFormat);
-
- if (index == kMaxIndicesToCheck) {
- ALOGW("[%s] stopping checking formats after %u: %s(%x)",
- name, index,
- asString(portFormat.eColorFormat), portFormat.eColorFormat);
- }
- }
- } else if (strcasecmp(mediaType, MEDIA_MIMETYPE_AUDIO_AAC) == 0) {
- // More audio codecs if they have profiles.
- OMX_AUDIO_PARAM_ANDROID_PROFILETYPE param;
- InitOMXParams(¶m);
- param.nPortIndex = isEncoder ? kPortIndexOutput : kPortIndexInput;
- for (OMX_U32 index = 0; index <= kMaxIndicesToCheck; ++index) {
- param.nProfileIndex = index;
- status_t err = omxNode->getParameter(
- (OMX_INDEXTYPE)OMX_IndexParamAudioProfileQuerySupported,
- ¶m, sizeof(param));
- if (err != OK) {
- break;
- }
- // For audio, level is ignored.
- caps->addProfileLevel(param.eProfile, 0 /* level */);
-
- if (index == kMaxIndicesToCheck) {
- ALOGW("[%s] stopping checking profiles after %u: %x",
- name, index,
- param.eProfile);
- }
- }
-
- // NOTE: Without Android extensions, OMX does not provide a way to query
- // AAC profile support
- if (param.nProfileIndex == 0) {
- ALOGW("component %s doesn't support profile query.", name);
}
}
- if (isVideo && !isEncoder) {
- native_handle_t *sidebandHandle = nullptr;
- if (omxNode->configureVideoTunnelMode(
- kPortIndexOutput, OMX_TRUE, 0, &sidebandHandle) == OK) {
- // tunneled playback includes adaptive playback
- } 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);
- }
- }
- }
+ // For VP9, the static info is always propagated by framework.
+ supportsHdr |= (mediaType == MIMETYPE_VIDEO_VP9);
- if (isVideo && isEncoder) {
- OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE params;
- InitOMXParams(¶ms);
- params.nPortIndex = kPortIndexOutput;
-
- 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 &&
- omxNode->getParameter(
- OMX_IndexParamVideoIntraRefresh, &fallbackParams,
- sizeof(fallbackParams)) != OK) {
- // intra refresh is not supported
- caps->removeDetail(MediaCodecInfo::Capabilities::FEATURE_INTRA_REFRESH);
- }
- }
-
- omxNode->freeNode();
- return OK;
-}
-
-void buildOmxInfo(const MediaCodecsXmlParser& parser,
- MediaCodecListWriter* writer) {
- uint32_t omxRank = ::android::base::GetUintProperty(
- "debug.stagefright.omx_default_rank", uint32_t(0x100));
- for (const MediaCodecsXmlParser::Codec& codec : parser.getCodecMap()) {
- const std::string &name = codec.first;
- if (!hasPrefix(codec.first, "OMX.")) {
+ for (C2Value::Primitive profile : profileQuery[0].values.values) {
+ pl.profile = (C2Config::profile_t)profile.ref<uint32_t>();
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ err = intf->config({&pl}, C2_DONT_BLOCK, &failures);
+ ALOGV("set profile to %u -> %s", pl.profile, asString(err));
+ std::vector<C2FieldSupportedValuesQuery> levelQuery = {
+ C2FieldSupportedValuesQuery::Current(C2ParamField(&pl, &pl.level))
+ };
+ err = intf->querySupportedValues(levelQuery, C2_DONT_BLOCK);
+ ALOGV("query supported levels -> %s | %s", asString(err), asString(levelQuery[0].status));
+ if (err != C2_OK || levelQuery[0].status != C2_OK
+ || levelQuery[0].values.type != C2FieldSupportedValues::VALUES
+ || levelQuery[0].values.values.size() == 0) {
continue;
}
- const MediaCodecsXmlParser::CodecProperties &properties = codec.second;
- bool encoder = properties.isEncoder;
- std::unique_ptr<MediaCodecInfoWriter> info =
- writer->addMediaCodecInfo();
- info->setName(name.c_str());
- info->setOwner("default");
- 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);
- // 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->addMediaType(mediaType.c_str());
- const MediaCodecsXmlParser::AttributeMap &attrMap = type.second;
- for (const MediaCodecsXmlParser::Attribute& attr : attrMap) {
- const std::string &key = attr.first;
- const std::string &value = attr.second;
- if (hasPrefix(key, "feature-") &&
- !hasPrefix(key, "feature-bitrate-modes")) {
- caps->addDetail(key.c_str(), hasPrefix(value, "1") ? 1 : 0);
- } else {
- caps->addDetail(key.c_str(), value.c_str());
+
+ C2Value::Primitive level = levelQuery[0].values.values.back();
+ pl.level = (C2Config::level_t)level.ref<uint32_t>();
+ ALOGV("supporting level: %u", pl.level);
+ int32_t sdkProfile, sdkLevel;
+ if (mapper && mapper->mapProfile(pl.profile, &sdkProfile)
+ && mapper->mapLevel(pl.level, &sdkLevel)) {
+ caps->addProfileLevel((uint32_t)sdkProfile, (uint32_t)sdkLevel);
+ // also list HDR profiles if component supports HDR
+ if (supportsHdr) {
+ auto hdrMapper = C2Mapper::GetHdrProfileLevelMapper(trait.mediaType);
+ if (hdrMapper && hdrMapper->mapProfile(pl.profile, &sdkProfile)) {
+ caps->addProfileLevel((uint32_t)sdkProfile, (uint32_t)sdkLevel);
+ }
+ if (supportsHdr10Plus) {
+ hdrMapper = C2Mapper::GetHdrProfileLevelMapper(
+ trait.mediaType, true /*isHdr10Plus*/);
+ if (hdrMapper && hdrMapper->mapProfile(pl.profile, &sdkProfile)) {
+ caps->addProfileLevel((uint32_t)sdkProfile, (uint32_t)sdkLevel);
+ }
}
}
- status_t err = queryOmxCapabilities(
- name.c_str(),
- mediaType.c_str(),
- encoder,
- caps.get());
- if (err != OK) {
- ALOGI("Failed to query capabilities for %s (media type: %s). Error: %d",
- name.c_str(),
- mediaType.c_str(),
- static_cast<int>(err));
+ } else if (!mapper) {
+ caps->addProfileLevel(pl.profile, pl.level);
+ }
+
+ // for H.263 also advertise the second highest level if the
+ // codec supports level 45, as level 45 only covers level 10
+ // TODO: move this to some form of a setting so it does not
+ // have to be here
+ if (mediaType == MIMETYPE_VIDEO_H263) {
+ C2Config::level_t nextLevel = C2Config::LEVEL_UNUSED;
+ for (C2Value::Primitive v : levelQuery[0].values.values) {
+ C2Config::level_t level = (C2Config::level_t)v.ref<uint32_t>();
+ if (level < C2Config::LEVEL_H263_45 && level > nextLevel) {
+ nextLevel = level;
+ }
}
+ if (nextLevel != C2Config::LEVEL_UNUSED
+ && nextLevel != pl.level
+ && mapper
+ && mapper->mapProfile(pl.profile, &sdkProfile)
+ && mapper->mapLevel(nextLevel, &sdkLevel)) {
+ caps->addProfileLevel(
+ (uint32_t)sdkProfile, (uint32_t)sdkLevel);
+ }
+ }
+ }
+}
+
+void addSupportedColorFormats(
+ std::shared_ptr<Codec2Client::Interface> intf,
+ MediaCodecInfo::CapabilitiesWriter *caps,
+ const Traits& trait, const std::string &mediaType) {
+ (void)intf;
+
+ // TODO: get this from intf() as well, but how do we map them to
+ // MediaCodec color formats?
+ bool encoder = trait.kind == C2Component::KIND_ENCODER;
+ if (mediaType.find("video") != std::string::npos) {
+ // vendor video codecs prefer opaque format
+ if (trait.name.find("android") == std::string::npos) {
+ caps->addColorFormat(COLOR_FormatSurface);
+ }
+ caps->addColorFormat(COLOR_FormatYUV420Flexible);
+ caps->addColorFormat(COLOR_FormatYUV420Planar);
+ caps->addColorFormat(COLOR_FormatYUV420SemiPlanar);
+ caps->addColorFormat(COLOR_FormatYUV420PackedPlanar);
+ caps->addColorFormat(COLOR_FormatYUV420PackedSemiPlanar);
+ // framework video encoders must support surface format, though it is unclear
+ // that they will be able to map it if it is opaque
+ if (encoder && trait.name.find("android") != std::string::npos) {
+ caps->addColorFormat(COLOR_FormatSurface);
}
}
}
@@ -335,7 +219,7 @@
// properly. (Assume "full" behavior eventually.)
//
// debug.stagefright.ccodec supports 5 values.
- // 0 - Only OMX components are available.
+ // 0 - No Codec 2.0 components are available.
// 1 - Audio decoders and encoders with prefix "c2.android." are available
// and ranked first.
// All other components with prefix "c2.android." are available with
@@ -366,306 +250,156 @@
MediaCodecsXmlParser parser(
MediaCodecsXmlParser::defaultSearchDirs,
- option == 0 ? "media_codecs.xml" :
- "media_codecs_c2.xml",
- option == 0 ? "media_codecs_performance.xml" :
- "media_codecs_performance_c2.xml");
+ "media_codecs_c2.xml",
+ "media_codecs_performance_c2.xml");
if (parser.getParsingStatus() != OK) {
ALOGD("XML parser no good");
return OK;
}
- bool surfaceTest(Codec2Client::CreateInputSurface());
- if (option == 0 || (option != 4 && !surfaceTest)) {
- buildOmxInfo(parser, writer);
- }
-
for (const Traits& trait : traits) {
C2Component::rank_t rank = trait.rank;
- std::shared_ptr<Codec2Client::Interface> intf =
- Codec2Client::CreateInterfaceByName(trait.name.c_str());
- if (!intf || parser.getCodecMap().count(intf->getName()) == 0) {
- ALOGD("%s not found in xml", trait.name.c_str());
- continue;
- }
- std::string canonName = intf->getName();
-
- // TODO: Remove this block once all codecs are enabled by default.
- switch (option) {
- case 0:
- continue;
- case 1:
- if (hasPrefix(canonName, "c2.vda.")) {
- break;
+ // Interface must be accessible for us to list the component, and there also
+ // must be an XML entry for the codec. Codec aliases listed in the traits
+ // allow additional XML entries to be specified for each alias. These will
+ // be listed as separate codecs. If no XML entry is specified for an alias,
+ // those will be treated as an additional alias specified in the XML entry
+ // for the interface name.
+ std::vector<std::string> nameAndAliases = trait.aliases;
+ nameAndAliases.insert(nameAndAliases.begin(), trait.name);
+ for (const std::string &nameOrAlias : nameAndAliases) {
+ bool isAlias = trait.name != nameOrAlias;
+ std::shared_ptr<Codec2Client::Interface> intf =
+ Codec2Client::CreateInterfaceByName(nameOrAlias.c_str());
+ if (!intf) {
+ ALOGD("could not create interface for %s'%s'",
+ isAlias ? "alias " : "",
+ nameOrAlias.c_str());
+ continue;
}
- if (hasPrefix(canonName, "c2.android.")) {
- if (trait.domain == C2Component::DOMAIN_AUDIO) {
+ if (parser.getCodecMap().count(nameOrAlias) == 0) {
+ if (isAlias) {
+ std::unique_ptr<MediaCodecInfoWriter> baseCodecInfo =
+ writer->findMediaCodecInfo(trait.name.c_str());
+ if (!baseCodecInfo) {
+ ALOGD("alias '%s' not found in xml but canonical codec info '%s' missing",
+ nameOrAlias.c_str(),
+ trait.name.c_str());
+ } else {
+ ALOGD("alias '%s' not found in xml; use an XML <Alias> tag for this",
+ nameOrAlias.c_str());
+ // merge alias into existing codec
+ baseCodecInfo->addAlias(nameOrAlias.c_str());
+ }
+ } else {
+ ALOGD("component '%s' not found in xml", trait.name.c_str());
+ }
+ continue;
+ }
+ std::string canonName = trait.name;
+
+ // TODO: Remove this block once all codecs are enabled by default.
+ switch (option) {
+ case 0:
+ continue;
+ case 1:
+ if (hasPrefix(canonName, "c2.vda.")) {
+ break;
+ }
+ if (hasPrefix(canonName, "c2.android.")) {
+ if (trait.domain == C2Component::DOMAIN_AUDIO) {
+ rank = 1;
+ break;
+ }
+ break;
+ }
+ if (hasSuffix(canonName, ".avc.decoder") ||
+ hasSuffix(canonName, ".avc.encoder")) {
+ rank = std::numeric_limits<decltype(rank)>::max();
+ break;
+ }
+ continue;
+ case 2:
+ if (hasPrefix(canonName, "c2.vda.")) {
+ break;
+ }
+ if (hasPrefix(canonName, "c2.android.")) {
rank = 1;
break;
}
+ if (hasSuffix(canonName, ".avc.decoder") ||
+ hasSuffix(canonName, ".avc.encoder")) {
+ rank = std::numeric_limits<decltype(rank)>::max();
+ break;
+ }
+ continue;
+ case 3:
+ if (hasPrefix(canonName, "c2.android.")) {
+ rank = 1;
+ }
break;
}
- if (hasSuffix(canonName, ".avc.decoder") ||
- hasSuffix(canonName, ".avc.encoder")) {
- rank = std::numeric_limits<decltype(rank)>::max();
- break;
- }
- continue;
- case 2:
- if (hasPrefix(canonName, "c2.vda.")) {
- break;
- }
- if (hasPrefix(canonName, "c2.android.")) {
- rank = 1;
- break;
- }
- if (hasSuffix(canonName, ".avc.decoder") ||
- hasSuffix(canonName, ".avc.encoder")) {
- rank = std::numeric_limits<decltype(rank)>::max();
- break;
- }
- continue;
- case 3:
- if (hasPrefix(canonName, "c2.android.")) {
- rank = 1;
- }
- break;
- }
- ALOGV("canonName = %s", canonName.c_str());
- std::unique_ptr<MediaCodecInfoWriter> codecInfo = writer->addMediaCodecInfo();
- codecInfo->setName(trait.name.c_str());
- codecInfo->setOwner(("codec2::" + trait.owner).c_str());
- const MediaCodecsXmlParser::CodecProperties &codec = parser.getCodecMap().at(canonName);
+ ALOGV("adding codec entry for '%s'", nameOrAlias.c_str());
+ std::unique_ptr<MediaCodecInfoWriter> codecInfo = writer->addMediaCodecInfo();
+ codecInfo->setName(nameOrAlias.c_str());
+ codecInfo->setOwner(("codec2::" + trait.owner).c_str());
+ const MediaCodecsXmlParser::CodecProperties &codec =
+ parser.getCodecMap().at(nameOrAlias);
- bool encoder = trait.kind == C2Component::KIND_ENCODER;
- typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs = 0;
+ bool encoder = trait.kind == C2Component::KIND_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") {
+ if (encoder) {
+ attrs |= MediaCodecInfo::kFlagIsEncoder;
+ }
+ if (trait.owner == "software") {
attrs |= MediaCodecInfo::kFlagIsSoftwareOnly;
- } else if (codec.quirkSet.find("attribute::software-codec") == codec.quirkSet.end()) {
- attrs |= MediaCodecInfo::kFlagIsHardwareAccelerated;
- }
- }
- codecInfo->setAttributes(attrs);
- codecInfo->setRank(rank);
-
- 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->addMediaType(mediaType.c_str());
- for (auto attrIt = attrMap.begin(); attrIt != attrMap.end(); ++attrIt) {
- std::string key, value;
- std::tie(key, value) = *attrIt;
- if (key.find("feature-") == 0 && key.find("feature-bitrate-modes") != 0) {
- caps->addDetail(key.c_str(), std::stoi(value));
- } else {
- caps->addDetail(key.c_str(), value.c_str());
+ } 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;
}
}
-
- bool gotProfileLevels = false;
- if (intf) {
- std::shared_ptr<C2Mapper::ProfileLevelMapper> mapper =
- C2Mapper::GetProfileLevelMapper(trait.mediaType);
- // if we don't know the media type, pass through all values unmapped
-
- // TODO: we cannot find levels that are local 'maxima' without knowing the coding
- // e.g. H.263 level 45 and level 30 could be two values for highest level as
- // they don't include one another. For now we use the last supported value.
- C2StreamProfileLevelInfo pl(encoder /* output */, 0u);
- std::vector<C2FieldSupportedValuesQuery> profileQuery = {
- C2FieldSupportedValuesQuery::Possible(C2ParamField(&pl, &pl.profile))
- };
-
- c2_status_t err = intf->querySupportedValues(profileQuery, C2_DONT_BLOCK);
- ALOGV("query supported profiles -> %s | %s",
- asString(err), asString(profileQuery[0].status));
- if (err == C2_OK && profileQuery[0].status == C2_OK) {
- if (profileQuery[0].values.type == C2FieldSupportedValues::VALUES) {
- std::vector<std::shared_ptr<C2ParamDescriptor>> paramDescs;
- c2_status_t err1 = intf->querySupportedParams(¶mDescs);
- bool isHdr = false, isHdr10Plus = false;
- if (err1 == C2_OK) {
- for (const std::shared_ptr<C2ParamDescriptor> &desc : paramDescs) {
- if ((uint32_t)desc->index() ==
- C2StreamHdr10PlusInfo::output::PARAM_TYPE) {
- isHdr10Plus = true;
- } else if ((uint32_t)desc->index() ==
- C2StreamHdrStaticInfo::output::PARAM_TYPE) {
- isHdr = true;
- }
- }
- }
- // For VP9, the static info is always propagated by framework.
- isHdr |= (mediaType == MIMETYPE_VIDEO_VP9);
-
- for (C2Value::Primitive profile : profileQuery[0].values.values) {
- pl.profile = (C2Config::profile_t)profile.ref<uint32_t>();
- std::vector<std::unique_ptr<C2SettingResult>> failures;
- err = intf->config({&pl}, C2_DONT_BLOCK, &failures);
- ALOGV("set profile to %u -> %s", pl.profile, asString(err));
- std::vector<C2FieldSupportedValuesQuery> levelQuery = {
- C2FieldSupportedValuesQuery::Current(C2ParamField(&pl, &pl.level))
- };
- err = intf->querySupportedValues(levelQuery, C2_DONT_BLOCK);
- ALOGV("query supported levels -> %s | %s",
- asString(err), asString(levelQuery[0].status));
- if (err == C2_OK && levelQuery[0].status == C2_OK) {
- if (levelQuery[0].values.type == C2FieldSupportedValues::VALUES
- && levelQuery[0].values.values.size() > 0) {
- C2Value::Primitive level = levelQuery[0].values.values.back();
- pl.level = (C2Config::level_t)level.ref<uint32_t>();
- ALOGV("supporting level: %u", pl.level);
- int32_t sdkProfile, sdkLevel;
- if (mapper && mapper->mapProfile(pl.profile, &sdkProfile)
- && mapper->mapLevel(pl.level, &sdkLevel)) {
- caps->addProfileLevel(
- (uint32_t)sdkProfile, (uint32_t)sdkLevel);
- gotProfileLevels = true;
- if (isHdr) {
- auto hdrMapper = C2Mapper::GetHdrProfileLevelMapper(
- trait.mediaType);
- if (hdrMapper && hdrMapper->mapProfile(
- pl.profile, &sdkProfile)) {
- caps->addProfileLevel(
- (uint32_t)sdkProfile,
- (uint32_t)sdkLevel);
- }
- if (isHdr10Plus) {
- hdrMapper = C2Mapper::GetHdrProfileLevelMapper(
- trait.mediaType, true /*isHdr10Plus*/);
- if (hdrMapper && hdrMapper->mapProfile(
- pl.profile, &sdkProfile)) {
- caps->addProfileLevel(
- (uint32_t)sdkProfile,
- (uint32_t)sdkLevel);
- }
- }
- }
- } else if (!mapper) {
- caps->addProfileLevel(pl.profile, pl.level);
- gotProfileLevels = true;
- }
-
- // for H.263 also advertise the second highest level if the
- // codec supports level 45, as level 45 only covers level 10
- // TODO: move this to some form of a setting so it does not
- // have to be here
- if (mediaType == MIMETYPE_VIDEO_H263) {
- C2Config::level_t nextLevel = C2Config::LEVEL_UNUSED;
- for (C2Value::Primitive v : levelQuery[0].values.values) {
- C2Config::level_t level =
- (C2Config::level_t)v.ref<uint32_t>();
- if (level < C2Config::LEVEL_H263_45
- && level > nextLevel) {
- nextLevel = level;
- }
- }
- if (nextLevel != C2Config::LEVEL_UNUSED
- && nextLevel != pl.level
- && mapper
- && mapper->mapProfile(pl.profile, &sdkProfile)
- && mapper->mapLevel(nextLevel, &sdkLevel)) {
- caps->addProfileLevel(
- (uint32_t)sdkProfile, (uint32_t)sdkLevel);
- }
- }
- }
- }
- }
- }
+ codecInfo->setAttributes(attrs);
+ if (!codec.rank.empty()) {
+ uint32_t xmlRank;
+ char dummy;
+ if (sscanf(codec.rank.c_str(), "%u%c", &xmlRank, &dummy) == 1) {
+ rank = xmlRank;
}
}
+ codecInfo->setRank(rank);
- if (!gotProfileLevels) {
- if (mediaType == MIMETYPE_VIDEO_VP9) {
- if (encoder) {
- caps->addProfileLevel(VP9Profile0, VP9Level41);
- } else {
- caps->addProfileLevel(VP9Profile0, VP9Level5);
- caps->addProfileLevel(VP9Profile2, VP9Level5);
- caps->addProfileLevel(VP9Profile2HDR, VP9Level5);
- }
- } else if (mediaType == MIMETYPE_VIDEO_AV1 && !encoder) {
- caps->addProfileLevel(AV1Profile0, AV1Level2);
- caps->addProfileLevel(AV1Profile0, AV1Level21);
- caps->addProfileLevel(AV1Profile1, AV1Level22);
- caps->addProfileLevel(AV1Profile1, AV1Level3);
- caps->addProfileLevel(AV1Profile2, AV1Level31);
- caps->addProfileLevel(AV1Profile2, AV1Level32);
- } else if (mediaType == MIMETYPE_VIDEO_HEVC && !encoder) {
- caps->addProfileLevel(HEVCProfileMain, HEVCMainTierLevel51);
- caps->addProfileLevel(HEVCProfileMainStill, HEVCMainTierLevel51);
- } else if (mediaType == MIMETYPE_VIDEO_VP8) {
- if (encoder) {
- caps->addProfileLevel(VP8ProfileMain, VP8Level_Version0);
- } else {
- caps->addProfileLevel(VP8ProfileMain, VP8Level_Version0);
- }
- } else if (mediaType == MIMETYPE_VIDEO_AVC) {
- if (encoder) {
- caps->addProfileLevel(AVCProfileBaseline, AVCLevel41);
-// caps->addProfileLevel(AVCProfileConstrainedBaseline, AVCLevel41);
- caps->addProfileLevel(AVCProfileMain, AVCLevel41);
- } else {
- caps->addProfileLevel(AVCProfileBaseline, AVCLevel52);
- caps->addProfileLevel(AVCProfileConstrainedBaseline, AVCLevel52);
- caps->addProfileLevel(AVCProfileMain, AVCLevel52);
- caps->addProfileLevel(AVCProfileConstrainedHigh, AVCLevel52);
- caps->addProfileLevel(AVCProfileHigh, AVCLevel52);
- }
- } else if (mediaType == MIMETYPE_VIDEO_MPEG4) {
- if (encoder) {
- caps->addProfileLevel(MPEG4ProfileSimple, MPEG4Level2);
- } else {
- caps->addProfileLevel(MPEG4ProfileSimple, MPEG4Level3);
- }
- } else if (mediaType == MIMETYPE_VIDEO_H263) {
- if (encoder) {
- caps->addProfileLevel(H263ProfileBaseline, H263Level45);
- } else {
- caps->addProfileLevel(H263ProfileBaseline, H263Level30);
- caps->addProfileLevel(H263ProfileBaseline, H263Level45);
- caps->addProfileLevel(H263ProfileISWV2, H263Level30);
- caps->addProfileLevel(H263ProfileISWV2, H263Level45);
- }
- } else if (mediaType == MIMETYPE_VIDEO_MPEG2 && !encoder) {
- caps->addProfileLevel(MPEG2ProfileSimple, MPEG2LevelHL);
- caps->addProfileLevel(MPEG2ProfileMain, MPEG2LevelHL);
- }
+ for (const std::string &alias : codec.aliases) {
+ ALOGV("adding alias '%s'", alias.c_str());
+ codecInfo->addAlias(alias.c_str());
}
- // TODO: get this from intf() as well, but how do we map them to
- // MediaCodec color formats?
- if (mediaType.find("video") != std::string::npos) {
- // vendor video codecs prefer opaque format
- if (trait.name.find("android") == std::string::npos) {
- caps->addColorFormat(COLOR_FormatSurface);
+ 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->addMediaType(mediaType.c_str());
+ for (auto attrIt = attrMap.begin(); attrIt != attrMap.end(); ++attrIt) {
+ std::string key, value;
+ std::tie(key, value) = *attrIt;
+ if (key.find("feature-") == 0 && key.find("feature-bitrate-modes") != 0) {
+ int32_t intValue = 0;
+ // Ignore trailing bad characters and default to 0.
+ (void)sscanf(value.c_str(), "%d", &intValue);
+ caps->addDetail(key.c_str(), intValue);
+ } else {
+ caps->addDetail(key.c_str(), value.c_str());
+ }
}
- caps->addColorFormat(COLOR_FormatYUV420Flexible);
- caps->addColorFormat(COLOR_FormatYUV420Planar);
- caps->addColorFormat(COLOR_FormatYUV420SemiPlanar);
- caps->addColorFormat(COLOR_FormatYUV420PackedPlanar);
- caps->addColorFormat(COLOR_FormatYUV420PackedSemiPlanar);
- // framework video encoders must support surface format, though it is unclear
- // that they will be able to map it if it is opaque
- if (encoder && trait.name.find("android") != std::string::npos) {
- caps->addColorFormat(COLOR_FormatSurface);
- }
+
+ addSupportedProfileLevels(intf, caps.get(), trait, mediaType);
+ addSupportedColorFormats(intf, caps.get(), trait, mediaType);
}
}
}
@@ -677,4 +411,3 @@
extern "C" android::MediaCodecListBuilderBase *CreateBuilder() {
return new android::Codec2InfoBuilder;
}
-
diff --git a/media/codec2/vndk/C2Store.cpp b/media/codec2/vndk/C2Store.cpp
index dc7e89c..f07d9b0 100644
--- a/media/codec2/vndk/C2Store.cpp
+++ b/media/codec2/vndk/C2Store.cpp
@@ -517,7 +517,6 @@
*
* \note Only used by ComponentLoader.
*
- * \param alias[in] module alias
* \param libPath[in] library path
*
* \retval C2_OK the component module has been successfully loaded
@@ -527,7 +526,7 @@
* \retval C2_REFUSED permission denied to load the component module (unexpected)
* \retval C2_TIMED_OUT could not load the module within the time limit (unexpected)
*/
- c2_status_t init(std::string alias, std::string libPath);
+ c2_status_t init(std::string libPath);
virtual ~ComponentModule() override;
@@ -570,7 +569,7 @@
std::shared_ptr<ComponentModule> localModule = mModule.lock();
if (localModule == nullptr) {
localModule = std::make_shared<ComponentModule>();
- res = localModule->init(mAlias, mLibPath);
+ res = localModule->init(mLibPath);
if (res == C2_OK) {
mModule = localModule;
}
@@ -582,13 +581,12 @@
/**
* Creates a component loader for a specific library path (or name).
*/
- ComponentLoader(std::string alias, std::string libPath)
- : mAlias(alias), mLibPath(libPath) {}
+ ComponentLoader(std::string libPath)
+ : mLibPath(libPath) {}
private:
std::mutex mMutex; ///< mutex guarding the module
std::weak_ptr<ComponentModule> mModule; ///< weak reference to the loaded module
- std::string mAlias; ///< component alias
std::string mLibPath; ///< library path
};
@@ -624,9 +622,10 @@
};
/**
- * Retrieves the component loader for a component.
+ * Retrieves the component module for a component.
*
- * \return a non-ref-holding pointer to the component loader.
+ * \param module pointer to a shared_pointer where the component module will be stored on
+ * success.
*
* \retval C2_OK the component loader has been successfully retrieved
* \retval C2_NO_MEMORY not enough memory to locate the component loader
@@ -640,16 +639,25 @@
* component but some components could not be loaded due to lack of
* permissions)
*/
- c2_status_t findComponent(C2String name, ComponentLoader **loader);
+ c2_status_t findComponent(C2String name, std::shared_ptr<ComponentModule> *module);
- std::map<C2String, ComponentLoader> mComponents; ///< map of name -> components
- std::vector<C2String> mComponentsList; ///< list of components
+ /**
+ * Loads each component module and discover its contents.
+ */
+ void visitComponents();
+
+ std::mutex mMutex; ///< mutex guarding the component lists during construction
+ bool mVisited; ///< component modules visited
+ std::map<C2String, ComponentLoader> mComponents; ///< path -> component module
+ std::map<C2String, C2String> mComponentNameToPath; ///< name -> path
+ std::vector<std::shared_ptr<const C2Component::Traits>> mComponentList;
+
std::shared_ptr<C2ReflectorHelper> mReflector;
Interface mInterface;
};
c2_status_t C2PlatformComponentStore::ComponentModule::init(
- std::string alias, std::string libPath) {
+ std::string libPath) {
ALOGV("in %s", __func__);
ALOGV("loading dll");
mLibHandle = dlopen(libPath.c_str(), RTLD_NOW|RTLD_NODELETE);
@@ -684,13 +692,27 @@
std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
if (traits) {
- if (alias != intf->getName()) {
- ALOGV("%s is alias to %s", alias.c_str(), intf->getName().c_str());
+ traits->name = intf->getName();
+
+ C2ComponentKindSetting kind;
+ C2ComponentDomainSetting domain;
+ res = intf->query_vb({ &kind, &domain }, {}, C2_MAY_BLOCK, nullptr);
+ bool fixDomain = res != C2_OK;
+ if (res == C2_OK) {
+ traits->kind = kind.value;
+ traits->domain = domain.value;
+ } else {
+ // TODO: remove this fall-back
+ ALOGD("failed to query interface for kind and domain: %d", res);
+
+ traits->kind =
+ (traits->name.find("encoder") != std::string::npos) ? C2Component::KIND_ENCODER :
+ (traits->name.find("decoder") != std::string::npos) ? C2Component::KIND_DECODER :
+ C2Component::KIND_OTHER;
}
- traits->name = alias;
- // TODO: get this from interface properly.
- bool encoder = (traits->name.find("encoder") != std::string::npos);
- uint32_t mediaTypeIndex = encoder ? C2PortMimeConfig::output::PARAM_TYPE
+
+ uint32_t mediaTypeIndex =
+ traits->kind == C2Component::KIND_ENCODER ? C2PortMimeConfig::output::PARAM_TYPE
: C2PortMimeConfig::input::PARAM_TYPE;
std::vector<std::unique_ptr<C2Param>> params;
res = intf->query_vb({}, { mediaTypeIndex }, C2_MAY_BLOCK, ¶ms);
@@ -702,29 +724,54 @@
ALOGD("failed to query interface: unexpected vector size: %zu", params.size());
return mInit;
}
- C2PortMimeConfig *mediaTypeConfig = (C2PortMimeConfig *)(params[0].get());
+ C2PortMimeConfig *mediaTypeConfig = C2PortMimeConfig::From(params[0].get());
if (mediaTypeConfig == nullptr) {
ALOGD("failed to query media type");
return mInit;
}
- traits->mediaType = mediaTypeConfig->m.value;
- // TODO: get this properly.
- traits->rank = 0x200;
+ traits->mediaType =
+ std::string(mediaTypeConfig->m.value,
+ strnlen(mediaTypeConfig->m.value, mediaTypeConfig->flexCount()));
- // TODO: define these values properly
- bool decoder = (traits->name.find("decoder") != std::string::npos);
- traits->kind =
- decoder ? C2Component::KIND_DECODER :
- encoder ? C2Component::KIND_ENCODER :
- C2Component::KIND_OTHER;
- if (strncmp(traits->mediaType.c_str(), "audio/", 6) == 0) {
- traits->domain = C2Component::DOMAIN_AUDIO;
- } else if (strncmp(traits->mediaType.c_str(), "video/", 6) == 0) {
- traits->domain = C2Component::DOMAIN_VIDEO;
- } else if (strncmp(traits->mediaType.c_str(), "image/", 6) == 0) {
- traits->domain = C2Component::DOMAIN_IMAGE;
- } else {
- traits->domain = C2Component::DOMAIN_OTHER;
+ if (fixDomain) {
+ if (strncmp(traits->mediaType.c_str(), "audio/", 6) == 0) {
+ traits->domain = C2Component::DOMAIN_AUDIO;
+ } else if (strncmp(traits->mediaType.c_str(), "video/", 6) == 0) {
+ traits->domain = C2Component::DOMAIN_VIDEO;
+ } else if (strncmp(traits->mediaType.c_str(), "image/", 6) == 0) {
+ traits->domain = C2Component::DOMAIN_IMAGE;
+ } else {
+ traits->domain = C2Component::DOMAIN_OTHER;
+ }
+ }
+
+ // TODO: get this properly from the store during emplace
+ switch (traits->domain) {
+ case C2Component::DOMAIN_AUDIO:
+ traits->rank = 8;
+ break;
+ default:
+ traits->rank = 512;
+ }
+
+ params.clear();
+ res = intf->query_vb({}, { C2ComponentAliasesSetting::PARAM_TYPE }, C2_MAY_BLOCK, ¶ms);
+ if (res == C2_OK && params.size() == 1u) {
+ C2ComponentAliasesSetting *aliasesSetting =
+ C2ComponentAliasesSetting::From(params[0].get());
+ if (aliasesSetting) {
+ // Split aliases on ','
+ // This looks simpler in plain C and even std::string would still make a copy.
+ char *aliases = ::strndup(aliasesSetting->m.value, aliasesSetting->flexCount());
+ ALOGD("'%s' has aliases: '%s'", intf->getName().c_str(), aliases);
+
+ for (char *tok, *ptr, *str = aliases; (tok = ::strtok_r(str, ",", &ptr));
+ str = nullptr) {
+ traits->aliases.push_back(tok);
+ ALOGD("adding alias: '%s'", tok);
+ }
+ free(aliases);
+ }
}
}
mTraits = traits;
@@ -783,82 +830,45 @@
}
C2PlatformComponentStore::C2PlatformComponentStore()
- : mReflector(std::make_shared<C2ReflectorHelper>()),
+ : mVisited(false),
+ mReflector(std::make_shared<C2ReflectorHelper>()),
mInterface(mReflector) {
- auto emplace = [this](const char *alias, const char *libPath) {
- // ComponentLoader is neither copiable nor movable, so it must be
- // constructed in-place. Now ComponentLoader takes two arguments in
- // constructor, so we need to use piecewise_construct to achieve this
- // behavior.
- mComponents.emplace(
- std::piecewise_construct,
- std::forward_as_tuple(alias),
- std::forward_as_tuple(alias, libPath));
- mComponentsList.emplace_back(alias);
+ auto emplace = [this](const char *libPath) {
+ mComponents.emplace(libPath, libPath);
};
- // TODO: move this also into a .so so it can be updated
- emplace("c2.android.avc.decoder", "libcodec2_soft_avcdec.so");
- emplace("c2.android.avc.encoder", "libcodec2_soft_avcenc.so");
- emplace("c2.android.aac.decoder", "libcodec2_soft_aacdec.so");
- emplace("c2.android.aac.encoder", "libcodec2_soft_aacenc.so");
- emplace("c2.android.amrnb.decoder", "libcodec2_soft_amrnbdec.so");
- emplace("c2.android.amrnb.encoder", "libcodec2_soft_amrnbenc.so");
- emplace("c2.android.amrwb.decoder", "libcodec2_soft_amrwbdec.so");
- emplace("c2.android.amrwb.encoder", "libcodec2_soft_amrwbenc.so");
- emplace("c2.android.hevc.decoder", "libcodec2_soft_hevcdec.so");
- emplace("c2.android.g711.alaw.decoder", "libcodec2_soft_g711alawdec.so");
- emplace("c2.android.g711.mlaw.decoder", "libcodec2_soft_g711mlawdec.so");
- emplace("c2.android.mpeg2.decoder", "libcodec2_soft_mpeg2dec.so");
- emplace("c2.android.h263.decoder", "libcodec2_soft_h263dec.so");
- emplace("c2.android.h263.encoder", "libcodec2_soft_h263enc.so");
- emplace("c2.android.mpeg4.decoder", "libcodec2_soft_mpeg4dec.so");
- emplace("c2.android.mpeg4.encoder", "libcodec2_soft_mpeg4enc.so");
- emplace("c2.android.mp3.decoder", "libcodec2_soft_mp3dec.so");
- emplace("c2.android.vorbis.decoder", "libcodec2_soft_vorbisdec.so");
- emplace("c2.android.opus.decoder", "libcodec2_soft_opusdec.so");
- emplace("c2.android.opus.encoder", "libcodec2_soft_opusenc.so");
- emplace("c2.android.vp8.decoder", "libcodec2_soft_vp8dec.so");
- emplace("c2.android.vp9.decoder", "libcodec2_soft_vp9dec.so");
- emplace("c2.android.vp8.encoder", "libcodec2_soft_vp8enc.so");
- emplace("c2.android.vp9.encoder", "libcodec2_soft_vp9enc.so");
- emplace("c2.android.av1.decoder", "libcodec2_soft_av1dec.so");
- emplace("c2.android.raw.decoder", "libcodec2_soft_rawdec.so");
- emplace("c2.android.flac.decoder", "libcodec2_soft_flacdec.so");
- emplace("c2.android.flac.encoder", "libcodec2_soft_flacenc.so");
- emplace("c2.android.gsm.decoder", "libcodec2_soft_gsmdec.so");
- emplace("c2.android.xaac.decoder", "libcodec2_soft_xaacdec.so");
- // "Aliases"
- // TODO: use aliases proper from C2Component::Traits
- emplace("OMX.google.h264.decoder", "libcodec2_soft_avcdec.so");
- emplace("OMX.google.h264.encoder", "libcodec2_soft_avcenc.so");
- emplace("OMX.google.aac.decoder", "libcodec2_soft_aacdec.so");
- emplace("OMX.google.aac.encoder", "libcodec2_soft_aacenc.so");
- emplace("OMX.google.amrnb.decoder", "libcodec2_soft_amrnbdec.so");
- emplace("OMX.google.amrnb.encoder", "libcodec2_soft_amrnbenc.so");
- emplace("OMX.google.amrwb.decoder", "libcodec2_soft_amrwbdec.so");
- emplace("OMX.google.amrwb.encoder", "libcodec2_soft_amrwbenc.so");
- emplace("OMX.google.hevc.decoder", "libcodec2_soft_hevcdec.so");
- emplace("OMX.google.g711.alaw.decoder", "libcodec2_soft_g711alawdec.so");
- emplace("OMX.google.g711.mlaw.decoder", "libcodec2_soft_g711mlawdec.so");
- emplace("OMX.google.mpeg2.decoder", "libcodec2_soft_mpeg2dec.so");
- emplace("OMX.google.h263.decoder", "libcodec2_soft_h263dec.so");
- emplace("OMX.google.h263.encoder", "libcodec2_soft_h263enc.so");
- emplace("OMX.google.mpeg4.decoder", "libcodec2_soft_mpeg4dec.so");
- emplace("OMX.google.mpeg4.encoder", "libcodec2_soft_mpeg4enc.so");
- emplace("OMX.google.mp3.decoder", "libcodec2_soft_mp3dec.so");
- emplace("OMX.google.vorbis.decoder", "libcodec2_soft_vorbisdec.so");
- emplace("OMX.google.opus.decoder", "libcodec2_soft_opusdec.so");
- emplace("OMX.google.vp8.decoder", "libcodec2_soft_vp8dec.so");
- emplace("OMX.google.vp9.decoder", "libcodec2_soft_vp9dec.so");
- emplace("OMX.google.vp8.encoder", "libcodec2_soft_vp8enc.so");
- emplace("OMX.google.vp9.encoder", "libcodec2_soft_vp9enc.so");
- emplace("OMX.google.raw.decoder", "libcodec2_soft_rawdec.so");
- emplace("OMX.google.flac.decoder", "libcodec2_soft_flacdec.so");
- emplace("OMX.google.flac.encoder", "libcodec2_soft_flacenc.so");
- emplace("OMX.google.gsm.decoder", "libcodec2_soft_gsmdec.so");
- emplace("OMX.google.xaac.decoder", "libcodec2_soft_xaacdec.so");
+ // TODO: move this also into a .so so it can be updated
+ emplace("libcodec2_soft_aacdec.so");
+ emplace("libcodec2_soft_aacenc.so");
+ emplace("libcodec2_soft_amrnbdec.so");
+ emplace("libcodec2_soft_amrnbenc.so");
+ emplace("libcodec2_soft_amrwbdec.so");
+ emplace("libcodec2_soft_amrwbenc.so");
+ emplace("libcodec2_soft_av1dec.so");
+ emplace("libcodec2_soft_avcdec.so");
+ emplace("libcodec2_soft_avcenc.so");
+ emplace("libcodec2_soft_flacdec.so");
+ emplace("libcodec2_soft_flacenc.so");
+ emplace("libcodec2_soft_g711alawdec.so");
+ emplace("libcodec2_soft_g711mlawdec.so");
+ emplace("libcodec2_soft_gsmdec.so");
+ emplace("libcodec2_soft_h263dec.so");
+ emplace("libcodec2_soft_h263enc.so");
+ emplace("libcodec2_soft_hevcdec.so");
+ emplace("libcodec2_soft_mp3dec.so");
+ emplace("libcodec2_soft_mpeg2dec.so");
+ emplace("libcodec2_soft_mpeg4dec.so");
+ emplace("libcodec2_soft_mpeg4enc.so");
+ emplace("libcodec2_soft_opusdec.so");
+ emplace("libcodec2_soft_opusenc.so");
+ emplace("libcodec2_soft_rawdec.so");
+ emplace("libcodec2_soft_vorbisdec.so");
+ emplace("libcodec2_soft_vp8dec.so");
+ emplace("libcodec2_soft_vp8enc.so");
+ emplace("libcodec2_soft_vp9dec.so");
+ emplace("libcodec2_soft_vp9enc.so");
+ emplace("libcodec2_soft_xaacdec.so");
}
c2_status_t C2PlatformComponentStore::copyBuffer(
@@ -881,47 +891,56 @@
return mInterface.config(params, C2_MAY_BLOCK, failures);
}
-std::vector<std::shared_ptr<const C2Component::Traits>> C2PlatformComponentStore::listComponents() {
- // This method SHALL return within 500ms.
- std::vector<std::shared_ptr<const C2Component::Traits>> list;
- for (const C2String &alias : mComponentsList) {
- ComponentLoader &loader = mComponents.at(alias);
+void C2PlatformComponentStore::visitComponents() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mVisited) {
+ return;
+ }
+ for (auto &pathAndLoader : mComponents) {
+ const C2String &path = pathAndLoader.first;
+ ComponentLoader &loader = pathAndLoader.second;
std::shared_ptr<ComponentModule> module;
- c2_status_t res = loader.fetchModule(&module);
- if (res == C2_OK) {
+ if (loader.fetchModule(&module) == C2_OK) {
std::shared_ptr<const C2Component::Traits> traits = module->getTraits();
if (traits) {
- list.push_back(traits);
+ mComponentList.push_back(traits);
+ mComponentNameToPath.emplace(traits->name, path);
+ for (const C2String &alias : traits->aliases) {
+ mComponentNameToPath.emplace(alias, path);
+ }
}
}
}
- return list;
+ mVisited = true;
}
-c2_status_t C2PlatformComponentStore::findComponent(C2String name, ComponentLoader **loader) {
- *loader = nullptr;
- auto pos = mComponents.find(name);
- // TODO: check aliases
- if (pos == mComponents.end()) {
- return C2_NOT_FOUND;
+std::vector<std::shared_ptr<const C2Component::Traits>> C2PlatformComponentStore::listComponents() {
+ // This method SHALL return within 500ms.
+ visitComponents();
+ return mComponentList;
+}
+
+c2_status_t C2PlatformComponentStore::findComponent(
+ C2String name, std::shared_ptr<ComponentModule> *module) {
+ (*module).reset();
+ visitComponents();
+
+ auto pos = mComponentNameToPath.find(name);
+ if (pos != mComponentNameToPath.end()) {
+ return mComponents.at(pos->second).fetchModule(module);
}
- *loader = &pos->second;
- return C2_OK;
+ return C2_NOT_FOUND;
}
c2_status_t C2PlatformComponentStore::createComponent(
C2String name, std::shared_ptr<C2Component> *const component) {
// This method SHALL return within 100ms.
component->reset();
- ComponentLoader *loader;
- c2_status_t res = findComponent(name, &loader);
+ std::shared_ptr<ComponentModule> module;
+ c2_status_t res = findComponent(name, &module);
if (res == C2_OK) {
- std::shared_ptr<ComponentModule> module;
- res = loader->fetchModule(&module);
- if (res == C2_OK) {
- // TODO: get a unique node ID
- res = module->createComponent(0, component);
- }
+ // TODO: get a unique node ID
+ res = module->createComponent(0, component);
}
return res;
}
@@ -930,15 +949,11 @@
C2String name, std::shared_ptr<C2ComponentInterface> *const interface) {
// This method SHALL return within 100ms.
interface->reset();
- ComponentLoader *loader;
- c2_status_t res = findComponent(name, &loader);
+ std::shared_ptr<ComponentModule> module;
+ c2_status_t res = findComponent(name, &module);
if (res == C2_OK) {
- std::shared_ptr<ComponentModule> module;
- res = loader->fetchModule(&module);
- if (res == C2_OK) {
- // TODO: get a unique node ID
- res = module->createInterface(0, interface);
- }
+ // TODO: get a unique node ID
+ res = module->createInterface(0, interface);
}
return res;
}
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 93478e9..3d58d4b 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -77,7 +77,8 @@
return profilingNeeded;
}
-OmxInfoBuilder sOmxInfoBuilder;
+OmxInfoBuilder sOmxInfoBuilder{true /* allowSurfaceEncoders */};
+OmxInfoBuilder sOmxNoSurfaceEncoderInfoBuilder{false /* allowSurfaceEncoders */};
Mutex sCodec2InfoBuilderMutex;
std::unique_ptr<MediaCodecListBuilderBase> sCodec2InfoBuilder;
@@ -98,7 +99,11 @@
sp<PersistentSurface> surfaceTest =
StagefrightPluginLoader::GetCCodecInstance()->createInputSurface();
if (surfaceTest == nullptr) {
+ ALOGD("Allowing all OMX codecs");
builders.push_back(&sOmxInfoBuilder);
+ } else {
+ ALOGD("Allowing only non-surface-encoder OMX codecs");
+ builders.push_back(&sOmxNoSurfaceEncoderInfoBuilder);
}
builders.push_back(GetCodec2InfoBuilder());
return builders;
@@ -219,6 +224,21 @@
return info1 == nullptr
|| (info2 != nullptr && info1->getRank() < info2->getRank());
});
+
+ // remove duplicate entries
+ bool dedupe = property_get_bool("debug.stagefright.dedupe-codecs", true);
+ if (dedupe) {
+ std::set<std::string> codecsSeen;
+ for (auto it = mCodecInfos.begin(); it != mCodecInfos.end(); ) {
+ std::string codecName = (*it)->getCodecName();
+ if (codecsSeen.count(codecName) == 0) {
+ codecsSeen.emplace(codecName);
+ it++;
+ } else {
+ it = mCodecInfos.erase(it);
+ }
+ }
+ }
}
MediaCodecList::~MediaCodecList() {
@@ -268,10 +288,17 @@
}
ssize_t MediaCodecList::findCodecByName(const char *name) const {
+ Vector<AString> aliases;
for (size_t i = 0; i < mCodecInfos.size(); ++i) {
if (strcmp(mCodecInfos[i]->getCodecName(), name) == 0) {
return i;
}
+ mCodecInfos[i]->getAliases(&aliases);
+ for (const AString &alias : aliases) {
+ if (alias == name) {
+ return i;
+ }
+ }
}
return -ENOENT;
diff --git a/media/libstagefright/MediaCodecListWriter.cpp b/media/libstagefright/MediaCodecListWriter.cpp
index b32e470..c4fb199 100644
--- a/media/libstagefright/MediaCodecListWriter.cpp
+++ b/media/libstagefright/MediaCodecListWriter.cpp
@@ -37,6 +37,16 @@
new MediaCodecInfoWriter(info.get()));
}
+std::unique_ptr<MediaCodecInfoWriter>
+ MediaCodecListWriter::findMediaCodecInfo(const char *name) {
+ for (const sp<MediaCodecInfo> &info : mCodecInfos) {
+ if (!strcmp(info->getCodecName(), name)) {
+ return std::unique_ptr<MediaCodecInfoWriter>(new MediaCodecInfoWriter(info.get()));
+ }
+ }
+ return nullptr;
+}
+
void MediaCodecListWriter::writeGlobalSettings(
const sp<AMessage> &globalSettings) const {
for (const std::pair<std::string, std::string> &kv : mGlobalSettings) {
diff --git a/media/libstagefright/OmxInfoBuilder.cpp b/media/libstagefright/OmxInfoBuilder.cpp
index 382c947..8910463 100644
--- a/media/libstagefright/OmxInfoBuilder.cpp
+++ b/media/libstagefright/OmxInfoBuilder.cpp
@@ -21,8 +21,8 @@
#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
#endif
+#include <android-base/properties.h>
#include <utils/Log.h>
-#include <cutils/properties.h>
#include <media/stagefright/foundation/MediaDefs.h>
#include <media/stagefright/OmxInfoBuilder.h>
@@ -53,7 +53,7 @@
namespace /* unnamed */ {
bool hasPrefix(const hidl_string& s, const char* prefix) {
- return strncmp(s.c_str(), prefix, strlen(prefix)) == 0;
+ return strncasecmp(s.c_str(), prefix, strlen(prefix)) == 0;
}
status_t queryCapabilities(
@@ -87,7 +87,8 @@
} // unnamed namespace
-OmxInfoBuilder::OmxInfoBuilder() {
+OmxInfoBuilder::OmxInfoBuilder(bool allowSurfaceEncoders)
+ : mAllowSurfaceEncoders(allowSurfaceEncoders) {
}
status_t OmxInfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
@@ -135,81 +136,80 @@
// Convert roles to lists of codecs
// codec name -> index into swCodecs/hwCodecs
- std::map<hidl_string, std::unique_ptr<MediaCodecInfoWriter>>
- swCodecName2Info, hwCodecName2Info;
+ std::map<hidl_string, std::unique_ptr<MediaCodecInfoWriter>> codecName2Info;
- char rank[PROPERTY_VALUE_MAX];
- uint32_t defaultRank = 0x100;
- if (property_get("debug.stagefright.omx_default_rank", rank, nullptr)) {
- defaultRank = std::strtoul(rank, nullptr, 10);
- }
+ uint32_t defaultRank =
+ ::android::base::GetUintProperty("debug.stagefright.omx_default_rank", 0x100u);
+ uint32_t defaultSwAudioRank =
+ ::android::base::GetUintProperty("debug.stagefright.omx_default_rank.sw-audio", 0x10u);
+ uint32_t defaultSwOtherRank =
+ ::android::base::GetUintProperty("debug.stagefright.omx_default_rank.sw-other", 0x210u);
+
for (const IOmxStore::RoleInfo& role : roles) {
const hidl_string& typeName = role.type;
bool isEncoder = role.isEncoder;
- bool preferPlatformNodes = role.preferPlatformNodes;
- // If preferPlatformNodes is true, hardware nodes must be added after
- // platform (software) nodes. hwCodecs is used to hold hardware nodes
- // that need to be added after software nodes for the same role.
- std::vector<const IOmxStore::NodeInfo*> hwCodecs;
- for (const IOmxStore::NodeInfo& node : role.nodes) {
+ bool isAudio = hasPrefix(role.type, "audio/");
+ bool isVideoOrImage = hasPrefix(role.type, "video/") || hasPrefix(role.type, "image/");
+
+ for (const IOmxStore::NodeInfo &node : role.nodes) {
const hidl_string& nodeName = node.name;
+
+ // currently image and video encoders use surface input
+ if (!mAllowSurfaceEncoders && isVideoOrImage && isEncoder) {
+ ALOGD("disabling %s for media type %s because we are not using OMX input surface",
+ nodeName.c_str(), role.type.c_str());
+ continue;
+ }
+
bool isSoftware = hasPrefix(nodeName, "OMX.google");
- MediaCodecInfoWriter* info;
- if (isSoftware) {
- auto c2i = swCodecName2Info.find(nodeName);
- if (c2i == swCodecName2Info.end()) {
- // Create a new MediaCodecInfo for a new node.
- c2i = swCodecName2Info.insert(std::make_pair(
- nodeName, writer->addMediaCodecInfo())).first;
- info = c2i->second.get();
- info->setName(nodeName.c_str());
- info->setOwner(node.owner.c_str());
- 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
- // existing MediaCodecInfoWriter.
- info = c2i->second.get();
- }
- } else {
- auto c2i = hwCodecName2Info.find(nodeName);
- if (c2i == hwCodecName2Info.end()) {
- // Create a new MediaCodecInfo for a new node.
- if (!preferPlatformNodes) {
- c2i = hwCodecName2Info.insert(std::make_pair(
- nodeName, writer->addMediaCodecInfo())).first;
- info = c2i->second.get();
- info->setName(nodeName.c_str());
- info->setOwner(node.owner.c_str());
- 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
- // added after all software nodes.
- hwCodecs.push_back(&node);
- continue;
+ uint32_t rank = isSoftware
+ ? (isAudio ? defaultSwAudioRank : defaultSwOtherRank)
+ : defaultRank;
+ // get rank from IOmxStore via attribute
+ for (const IOmxStore::Attribute& attribute : node.attributes) {
+ if (attribute.key == "rank") {
+ uint32_t oldRank = rank;
+ char dummy;
+ if (sscanf(attribute.value.c_str(), "%u%c", &rank, &dummy) != 1) {
+ rank = oldRank;
}
- } else {
- // The node has been seen before. Simply retrieve the
- // existing MediaCodecInfoWriter.
- info = c2i->second.get();
+ break;
}
}
+
+ MediaCodecInfoWriter* info;
+ auto c2i = codecName2Info.find(nodeName);
+ if (c2i == codecName2Info.end()) {
+ // Create a new MediaCodecInfo for a new node.
+ c2i = codecName2Info.insert(std::make_pair(
+ nodeName, writer->addMediaCodecInfo())).first;
+ info = c2i->second.get();
+ info->setName(nodeName.c_str());
+ info->setOwner(node.owner.c_str());
+ info->setRank(rank);
+
+ typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs = 0;
+ // all OMX codecs are vendor codecs (in the vendor partition), but
+ // treat OMX.google codecs as non-hardware-accelerated and non-vendor
+ if (!isSoftware) {
+ attrs |= MediaCodecInfo::kFlagIsVendor;
+ if (std::count_if(
+ node.attributes.begin(), node.attributes.end(),
+ [](const IOmxStore::Attribute &i) -> bool {
+ return i.key == "attribute::software-codec";
+ })) {
+ attrs |= MediaCodecInfo::kFlagIsHardwareAccelerated;
+ }
+ }
+ if (isEncoder) {
+ attrs |= MediaCodecInfo::kFlagIsEncoder;
+ }
+ info->setAttributes(attrs);
+ } else {
+ // The node has been seen before. Simply retrieve the
+ // existing MediaCodecInfoWriter.
+ info = c2i->second.get();
+ }
std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
info->addMediaType(typeName.c_str());
if (queryCapabilities(
@@ -219,54 +219,8 @@
info->removeMediaType(typeName.c_str());
}
}
-
- // If preferPlatformNodes is true, hardware nodes will not have been
- // added in the loop above, but rather saved in hwCodecs. They are
- // going to be added here.
- if (preferPlatformNodes) {
- for (const IOmxStore::NodeInfo *node : hwCodecs) {
- MediaCodecInfoWriter* info;
- const hidl_string& nodeName = node->name;
- auto c2i = hwCodecName2Info.find(nodeName);
- if (c2i == hwCodecName2Info.end()) {
- // Create a new MediaCodecInfo for a new node.
- c2i = hwCodecName2Info.insert(std::make_pair(
- nodeName, writer->addMediaCodecInfo())).first;
- info = c2i->second.get();
- info->setName(nodeName.c_str());
- info->setOwner(node->owner.c_str());
- 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
- // existing MediaCodecInfoWriter.
- info = c2i->second.get();
- }
- std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
- info->addMediaType(typeName.c_str());
- if (queryCapabilities(
- *node, typeName.c_str(), isEncoder, caps.get()) != OK) {
- ALOGW("Fail to add media type %s to codec %s "
- "after software codecs",
- typeName.c_str(), nodeName.c_str());
- info->removeMediaType(typeName.c_str());
- }
- }
- }
}
return OK;
}
} // namespace android
-
diff --git a/media/libstagefright/data/media_codecs_google_c2_audio.xml b/media/libstagefright/data/media_codecs_google_c2_audio.xml
index 88cd08d..f664395 100644
--- a/media/libstagefright/data/media_codecs_google_c2_audio.xml
+++ b/media/libstagefright/data/media_codecs_google_c2_audio.xml
@@ -17,51 +17,61 @@
<Included>
<Decoders>
<MediaCodec name="c2.android.mp3.decoder" type="audio/mpeg">
+ <Alias name="OMX.google.mp3.decoder" />
<Limit name="channel-count" max="2" />
<Limit name="sample-rate" ranges="8000,11025,12000,16000,22050,24000,32000,44100,48000" />
<Limit name="bitrate" range="8000-320000" />
</MediaCodec>
<MediaCodec name="c2.android.amrnb.decoder" type="audio/3gpp">
+ <Alias name="OMX.google.amrnb.decoder" />
<Limit name="channel-count" max="1" />
<Limit name="sample-rate" ranges="8000" />
<Limit name="bitrate" range="4750-12200" />
</MediaCodec>
<MediaCodec name="c2.android.amrwb.decoder" type="audio/amr-wb">
+ <Alias name="OMX.google.amrwb.decoder" />
<Limit name="channel-count" max="1" />
<Limit name="sample-rate" ranges="16000" />
<Limit name="bitrate" range="6600-23850" />
</MediaCodec>
<MediaCodec name="c2.android.aac.decoder" type="audio/mp4a-latm">
+ <Alias name="OMX.google.aac.decoder" />
<Limit name="channel-count" max="8" />
<Limit name="sample-rate" ranges="7350,8000,11025,12000,16000,22050,24000,32000,44100,48000" />
<Limit name="bitrate" range="8000-960000" />
</MediaCodec>
<MediaCodec name="c2.android.g711.alaw.decoder" type="audio/g711-alaw">
+ <Alias name="OMX.google.g711.alaw.decoder" />
<Limit name="channel-count" max="1" />
<Limit name="sample-rate" ranges="8000-48000" />
<Limit name="bitrate" range="64000" />
</MediaCodec>
<MediaCodec name="c2.android.g711.mlaw.decoder" type="audio/g711-mlaw">
+ <Alias name="OMX.google.g711.mlaw.decoder" />
<Limit name="channel-count" max="1" />
<Limit name="sample-rate" ranges="8000-48000" />
<Limit name="bitrate" range="64000" />
</MediaCodec>
<MediaCodec name="c2.android.vorbis.decoder" type="audio/vorbis">
+ <Alias name="OMX.google.vorbis.decoder" />
<Limit name="channel-count" max="8" />
<Limit name="sample-rate" ranges="8000-96000" />
<Limit name="bitrate" range="32000-500000" />
</MediaCodec>
<MediaCodec name="c2.android.opus.decoder" type="audio/opus">
+ <Alias name="OMX.google.opus.decoder" />
<Limit name="channel-count" max="8" />
<Limit name="sample-rate" ranges="48000" />
<Limit name="bitrate" range="6000-510000" />
</MediaCodec>
<MediaCodec name="c2.android.raw.decoder" type="audio/raw">
+ <Alias name="OMX.google.raw.decoder" />
<Limit name="channel-count" max="8" />
<Limit name="sample-rate" ranges="8000-96000" />
<Limit name="bitrate" range="1-10000000" />
</MediaCodec>
<MediaCodec name="c2.android.flac.decoder" type="audio/flac">
+ <Alias name="OMX.google.flac.decoder" />
<Limit name="channel-count" max="8" />
<Limit name="sample-rate" ranges="1-655350" />
<Limit name="bitrate" range="1-21000000" />
@@ -69,24 +79,28 @@
</Decoders>
<Encoders>
<MediaCodec name="c2.android.aac.encoder" type="audio/mp4a-latm">
+ <Alias name="OMX.google.aac.decoder" />
<Limit name="channel-count" max="6" />
<Limit name="sample-rate" ranges="8000,11025,12000,16000,22050,24000,32000,44100,48000" />
<!-- also may support 64000, 88200 and 96000 Hz -->
<Limit name="bitrate" range="8000-960000" />
</MediaCodec>
<MediaCodec name="c2.android.amrnb.encoder" type="audio/3gpp">
+ <Alias name="OMX.google.amrnb.decoder" />
<Limit name="channel-count" max="1" />
<Limit name="sample-rate" ranges="8000" />
<Limit name="bitrate" range="4750-12200" />
<Feature name="bitrate-modes" value="CBR" />
</MediaCodec>
<MediaCodec name="c2.android.amrwb.encoder" type="audio/amr-wb">
+ <Alias name="OMX.google.amrwb.decoder" />
<Limit name="channel-count" max="1" />
<Limit name="sample-rate" ranges="16000" />
<Limit name="bitrate" range="6600-23850" />
<Feature name="bitrate-modes" value="CBR" />
</MediaCodec>
<MediaCodec name="c2.android.flac.encoder" type="audio/flac">
+ <Alias name="OMX.google.flac.decoder" />
<Limit name="channel-count" max="2" />
<Limit name="sample-rate" ranges="1-655350" />
<Limit name="bitrate" range="1-21000000" />
diff --git a/media/libstagefright/data/media_codecs_google_c2_telephony.xml b/media/libstagefright/data/media_codecs_google_c2_telephony.xml
index d1055b3..950b092 100644
--- a/media/libstagefright/data/media_codecs_google_c2_telephony.xml
+++ b/media/libstagefright/data/media_codecs_google_c2_telephony.xml
@@ -17,6 +17,7 @@
<Included>
<Decoders>
<MediaCodec name="c2.android.gsm.decoder" type="audio/gsm">
+ <Alias name="OMX.google.gsm.decoder" />
<Limit name="channel-count" max="1" />
<Limit name="sample-rate" ranges="8000" />
<Limit name="bitrate" range="13000" />
diff --git a/media/libstagefright/data/media_codecs_google_c2_tv.xml b/media/libstagefright/data/media_codecs_google_c2_tv.xml
index fa082c7..1b00dc9 100644
--- a/media/libstagefright/data/media_codecs_google_c2_tv.xml
+++ b/media/libstagefright/data/media_codecs_google_c2_tv.xml
@@ -17,6 +17,7 @@
<Included>
<Decoders>
<MediaCodec name="c2.android.mpeg2.decoder" type="video/mpeg2">
+ <Alias name="OMX.google.mpeg2.decoder" />
<!-- profiles and levels: ProfileMain : LevelHL -->
<Limit name="size" min="16x16" max="1920x1088" />
<Limit name="alignment" value="2x2" />
diff --git a/media/libstagefright/data/media_codecs_google_c2_video.xml b/media/libstagefright/data/media_codecs_google_c2_video.xml
index c49789e..5c2d96d 100644
--- a/media/libstagefright/data/media_codecs_google_c2_video.xml
+++ b/media/libstagefright/data/media_codecs_google_c2_video.xml
@@ -17,6 +17,7 @@
<Included>
<Decoders>
<MediaCodec name="c2.android.mpeg4.decoder" type="video/mp4v-es">
+ <Alias name="OMX.google.mpeg4.decoder" />
<!-- profiles and levels: ProfileSimple : Level3 -->
<Limit name="size" min="2x2" max="352x288" />
<Limit name="alignment" value="2x2" />
@@ -26,6 +27,7 @@
<Feature name="adaptive-playback" />
</MediaCodec>
<MediaCodec name="c2.android.h263.decoder" type="video/3gpp">
+ <Alias name="OMX.google.h263.decoder" />
<!-- profiles and levels: ProfileBaseline : Level30, ProfileBaseline : Level45
ProfileISWV2 : Level30, ProfileISWV2 : Level45 -->
<Limit name="size" min="2x2" max="352x288" />
@@ -34,6 +36,7 @@
<Feature name="adaptive-playback" />
</MediaCodec>
<MediaCodec name="c2.android.avc.decoder" type="video/avc">
+ <Alias name="OMX.google.h264.decoder" />
<!-- profiles and levels: ProfileHigh : Level52 -->
<Limit name="size" min="2x2" max="4080x4080" />
<Limit name="alignment" value="2x2" />
@@ -44,6 +47,7 @@
<Feature name="adaptive-playback" />
</MediaCodec>
<MediaCodec name="c2.android.hevc.decoder" type="video/hevc">
+ <Alias name="OMX.google.hevc.decoder" />
<!-- profiles and levels: ProfileMain : MainTierLevel51 -->
<Limit name="size" min="2x2" max="4096x4096" />
<Limit name="alignment" value="2x2" />
@@ -54,6 +58,7 @@
<Feature name="adaptive-playback" />
</MediaCodec>
<MediaCodec name="c2.android.vp8.decoder" type="video/x-vnd.on2.vp8">
+ <Alias name="OMX.google.vp8.decoder" />
<Limit name="size" min="2x2" max="2048x2048" />
<Limit name="alignment" value="2x2" />
<Limit name="block-size" value="16x16" />
@@ -63,6 +68,7 @@
<Feature name="adaptive-playback" />
</MediaCodec>
<MediaCodec name="c2.android.vp9.decoder" type="video/x-vnd.on2.vp9">
+ <Alias name="OMX.google.vp9.decoder" />
<Limit name="size" min="2x2" max="2048x2048" />
<Limit name="alignment" value="2x2" />
<Limit name="block-size" value="16x16" />
@@ -84,12 +90,14 @@
<Encoders>
<MediaCodec name="c2.android.h263.encoder" type="video/3gpp">
+ <Alias name="OMX.google.h263.encoder" />
<!-- profiles and levels: ProfileBaseline : Level45 -->
<Limit name="size" min="176x144" max="176x144" />
<Limit name="alignment" value="16x16" />
<Limit name="bitrate" range="1-128000" />
</MediaCodec>
<MediaCodec name="c2.android.avc.encoder" type="video/avc">
+ <Alias name="OMX.google.h264.encoder" />
<!-- profiles and levels: ProfileBaseline : Level41 -->
<Limit name="size" min="16x16" max="2048x2048" />
<Limit name="alignment" value="2x2" />
@@ -100,6 +108,7 @@
<Feature name="intra-refresh" />
</MediaCodec>
<MediaCodec name="c2.android.mpeg4.encoder" type="video/mp4v-es">
+ <Alias name="OMX.google.mpeg4.encoder" />
<!-- profiles and levels: ProfileCore : Level2 -->
<Limit name="size" min="16x16" max="176x144" />
<Limit name="alignment" value="16x16" />
@@ -108,6 +117,7 @@
<Limit name="bitrate" range="1-64000" />
</MediaCodec>
<MediaCodec name="c2.android.vp8.encoder" type="video/x-vnd.on2.vp8">
+ <Alias name="OMX.google.vp8.encoder" />
<!-- profiles and levels: ProfileMain : Level_Version0-3 -->
<Limit name="size" min="2x2" max="2048x2048" />
<Limit name="alignment" value="2x2" />
@@ -118,6 +128,7 @@
<Feature name="bitrate-modes" value="VBR,CBR" />
</MediaCodec>
<MediaCodec name="c2.android.vp9.encoder" type="video/x-vnd.on2.vp9">
+ <Alias name="OMX.google.vp9.encoder" />
<!-- profiles and levels: ProfileMain : Level_Version0-3 -->
<Limit name="size" min="2x2" max="2048x2048" />
<Limit name="alignment" value="2x2" />
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecListWriter.h b/media/libstagefright/include/media/stagefright/MediaCodecListWriter.h
index 59f57c7..f53b23e 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecListWriter.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecListWriter.h
@@ -48,6 +48,13 @@
* added `MediaCodecInfo` object.
*/
std::unique_ptr<MediaCodecInfoWriter> addMediaCodecInfo();
+ /**
+ * Find an existing `MediaCodecInfo` object for a codec name and return a
+ * `MediaCodecInfoWriter` object associated with the found added `MediaCodecInfo`.
+ *
+ * @return The `MediaCodecInfoWriter` object if found, or nullptr if not found.
+ */
+ std::unique_ptr<MediaCodecInfoWriter> findMediaCodecInfo(const char *codecName);
private:
MediaCodecListWriter() = default;
diff --git a/media/libstagefright/include/media/stagefright/OmxInfoBuilder.h b/media/libstagefright/include/media/stagefright/OmxInfoBuilder.h
index 28f6094..1410a16 100644
--- a/media/libstagefright/include/media/stagefright/OmxInfoBuilder.h
+++ b/media/libstagefright/include/media/stagefright/OmxInfoBuilder.h
@@ -23,8 +23,11 @@
namespace android {
class OmxInfoBuilder : public MediaCodecListBuilderBase {
+private:
+ bool mAllowSurfaceEncoders; // allow surface encoders
+
public:
- OmxInfoBuilder();
+ explicit OmxInfoBuilder(bool allowSurfaceEncoders);
~OmxInfoBuilder() override = default;
status_t buildMediaCodecList(MediaCodecListWriter* writer) override;
};
diff --git a/media/libstagefright/omx/1.0/OmxStore.cpp b/media/libstagefright/omx/1.0/OmxStore.cpp
index 447af6f..2e041e3 100644
--- a/media/libstagefright/omx/1.0/OmxStore.cpp
+++ b/media/libstagefright/omx/1.0/OmxStore.cpp
@@ -61,10 +61,7 @@
role.role = rolePair.first;
role.type = rolePair.second.type;
role.isEncoder = rolePair.second.isEncoder;
- // TODO: Currently, preferPlatformNodes information is not available in
- // the xml file. Once we have a way to provide this information, it
- // should be parsed properly.
- role.preferPlatformNodes = rolePair.first.compare(0, 5, "audio") == 0;
+ role.preferPlatformNodes = false; // deprecated and ignored, using rank instead
hidl_vec<NodeInfo>& nodeList = role.nodes;
nodeList.resize(rolePair.second.nodeList.size());
size_t j = 0;
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
index 6e541ba..7046f61 100644
--- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -502,6 +502,7 @@
const char *name = nullptr;
const char *type = nullptr;
const char *update = nullptr;
+ const char *rank = nullptr;
size_t i = 0;
while (attrs[i] != nullptr) {
@@ -523,6 +524,12 @@
return BAD_VALUE;
}
update = attrs[i];
+ } else if (strEq(attrs[i], "rank")) {
+ if (attrs[++i] == nullptr) {
+ ALOGE("addMediaCodecFromAttributes: rank is null");
+ return BAD_VALUE;
+ }
+ rank = attrs[i];
} else {
ALOGE("addMediaCodecFromAttributes: unrecognized attribute: %s", attrs[i]);
return BAD_VALUE;
@@ -579,6 +586,15 @@
}
}
+ if (rank != nullptr) {
+ if (!mCurrentCodec->second.rank.empty() && mCurrentCodec->second.rank != rank) {
+ ALOGE("addMediaCodecFromAttributes: code \"%s\" rank changed from \"%s\" to \"%s\"",
+ name, mCurrentCodec->second.rank.c_str(), rank);
+ return BAD_VALUE;
+ }
+ mCurrentCodec->second.rank = rank;
+ }
+
return OK;
}
@@ -1035,6 +1051,7 @@
const auto& codecName = codec.first;
bool isEncoder = codec.second.isEncoder;
size_t order = codec.second.order;
+ std::string rank = codec.second.rank;
const auto& typeMap = codec.second.typeMap;
for (const auto& type : typeMap) {
const auto& typeName = type.first;
@@ -1090,6 +1107,9 @@
nodeInfo.attributeList.push_back(Attribute{quirk, "present"});
}
}
+ if (!rank.empty()) {
+ nodeInfo.attributeList.push_back(Attribute{"rank", rank});
+ }
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 fd949da..7a986b7 100644
--- a/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h
+++ b/media/libstagefright/xmlparser/include/media/stagefright/xmlparser/MediaCodecsXmlParser.h
@@ -66,6 +66,7 @@
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
+ std::string rank; ///< Rank of this codec. This is a numeric string.
};
typedef std::pair<std::string, CodecProperties> Codec;