/* * Copyright 2014, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //#define LOG_NDEBUG 0 #define LOG_TAG "MediaCodecInfo" #include <utils/Log.h> #include <media/IOMX.h> #include <media/MediaCodecInfo.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> #include <binder/Parcel.h> namespace android { void MediaCodecInfo::Capabilities::getSupportedProfileLevels( Vector<ProfileLevel> *profileLevels) const { profileLevels->clear(); profileLevels->appendVector(mProfileLevels); } void MediaCodecInfo::Capabilities::getSupportedColorFormats( Vector<uint32_t> *colorFormats) const { colorFormats->clear(); 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) { mDetails = new AMessage; } // static sp<MediaCodecInfo::Capabilities> MediaCodecInfo::Capabilities::FromParcel( const Parcel &parcel) { sp<MediaCodecInfo::Capabilities> caps = new Capabilities(); size_t size = static_cast<size_t>(parcel.readInt32()); for (size_t i = 0; i < size; i++) { ProfileLevel profileLevel; profileLevel.mProfile = static_cast<uint32_t>(parcel.readInt32()); profileLevel.mLevel = static_cast<uint32_t>(parcel.readInt32()); if (caps != NULL) { caps->mProfileLevels.push_back(profileLevel); } } size = static_cast<size_t>(parcel.readInt32()); for (size_t i = 0; i < size; i++) { uint32_t color = static_cast<uint32_t>(parcel.readInt32()); if (caps != NULL) { 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; } status_t MediaCodecInfo::Capabilities::writeToParcel(Parcel *parcel) const { CHECK_LE(mProfileLevels.size(), INT32_MAX); parcel->writeInt32(mProfileLevels.size()); for (size_t i = 0; i < mProfileLevels.size(); i++) { parcel->writeInt32(mProfileLevels.itemAt(i).mProfile); parcel->writeInt32(mProfileLevels.itemAt(i).mLevel); } CHECK_LE(mColorFormats.size(), INT32_MAX); parcel->writeInt32(mColorFormats.size()); for (size_t i = 0; i < mColorFormats.size(); i++) { parcel->writeInt32(mColorFormats.itemAt(i)); } parcel->writeInt32(mFlags); mDetails->writeToParcel(parcel); return OK; } void MediaCodecInfo::CapabilitiesBuilder::addProfileLevel(uint32_t profile, uint32_t level) { ProfileLevel profileLevel; profileLevel.mProfile = profile; profileLevel.mLevel = level; mProfileLevels.push_back(profileLevel); } void MediaCodecInfo::CapabilitiesBuilder::addColorFormat(uint32_t format) { mColorFormats.push(format); } void MediaCodecInfo::CapabilitiesBuilder::addFlags(uint32_t flags) { mFlags |= flags; } bool MediaCodecInfo::isEncoder() const { return mIsEncoder; } bool MediaCodecInfo::hasQuirk(const char *name) const { for (size_t ix = 0; ix < mQuirks.size(); ix++) { if (mQuirks.itemAt(ix).equalsIgnoreCase(name)) { return true; } } return false; } void MediaCodecInfo::getSupportedMimes(Vector<AString> *mimes) const { mimes->clear(); for (size_t ix = 0; ix < mCaps.size(); ix++) { mimes->push_back(mCaps.keyAt(ix)); } } const sp<MediaCodecInfo::Capabilities> MediaCodecInfo::getCapabilitiesFor(const char *mime) const { ssize_t ix = getCapabilityIndex(mime); if (ix >= 0) { return mCaps.valueAt(ix); } return NULL; } const char *MediaCodecInfo::getCodecName() const { return mName.c_str(); } // static sp<MediaCodecInfo> MediaCodecInfo::FromParcel(const Parcel &parcel) { AString name = AString::FromParcel(parcel); bool isEncoder = static_cast<bool>(parcel.readInt32()); sp<MediaCodecInfo> info = new MediaCodecInfo(name, isEncoder, NULL); size_t size = static_cast<size_t>(parcel.readInt32()); for (size_t i = 0; i < size; i++) { AString quirk = AString::FromParcel(parcel); if (info != NULL) { info->mQuirks.push_back(quirk); } } size = static_cast<size_t>(parcel.readInt32()); for (size_t i = 0; i < size; i++) { AString mime = AString::FromParcel(parcel); sp<Capabilities> caps = Capabilities::FromParcel(parcel); if (caps == NULL) return NULL; if (info != NULL) { info->mCaps.add(mime, caps); } } return info; } status_t MediaCodecInfo::writeToParcel(Parcel *parcel) const { mName.writeToParcel(parcel); parcel->writeInt32(mIsEncoder); parcel->writeInt32(mQuirks.size()); for (size_t i = 0; i < mQuirks.size(); i++) { mQuirks.itemAt(i).writeToParcel(parcel); } parcel->writeInt32(mCaps.size()); for (size_t i = 0; i < mCaps.size(); i++) { mCaps.keyAt(i).writeToParcel(parcel); mCaps.valueAt(i)->writeToParcel(parcel); } return OK; } ssize_t MediaCodecInfo::getCapabilityIndex(const char *mime) const { for (size_t ix = 0; ix < mCaps.size(); ix++) { if (mCaps.keyAt(ix).equalsIgnoreCase(mime)) { return ix; } } return -1; } MediaCodecInfo::MediaCodecInfo(AString name, bool encoder, const char *mime) : mName(name), mIsEncoder(encoder), mHasSoleMime(false) { if (mime != NULL) { addMime(mime); mHasSoleMime = true; } } status_t MediaCodecInfo::addMime(const char *mime) { if (mHasSoleMime) { ALOGE("Codec '%s' already had its type specified", mName.c_str()); return -EINVAL; } ssize_t ix = getCapabilityIndex(mime); if (ix >= 0) { mCurrentCaps = mCaps.valueAt(ix); } else { mCurrentCaps = new Capabilities(); mCaps.add(AString(mime), mCurrentCaps); } return OK; } status_t MediaCodecInfo::updateMime(const char *mime) { ssize_t ix = getCapabilityIndex(mime); if (ix < 0) { ALOGE("updateMime mime not found %s", mime); return -EINVAL; } mCurrentCaps = mCaps.valueAt(ix); return OK; } void MediaCodecInfo::removeMime(const char *mime) { ssize_t ix = getCapabilityIndex(mime); if (ix >= 0) { mCaps.removeItemsAt(ix); // mCurrentCaps will be removed when completed } } status_t MediaCodecInfo::initializeCapabilities(const sp<Capabilities> &caps) { // TRICKY: copy data to mCurrentCaps as it is a reference to // an element of the capabilites map. mCurrentCaps->mColorFormats.clear(); mCurrentCaps->mColorFormats.appendVector(caps->mColorFormats); mCurrentCaps->mProfileLevels.clear(); mCurrentCaps->mProfileLevels.appendVector(caps->mProfileLevels); mCurrentCaps->mFlags = caps->mFlags; mCurrentCaps->mDetails = caps->mDetails; return OK; } void MediaCodecInfo::addQuirk(const char *name) { if (!hasQuirk(name)) { mQuirks.push(name); } } void MediaCodecInfo::complete() { mCurrentCaps = NULL; } void MediaCodecInfo::addDetail(const AString &key, const AString &value) { mCurrentCaps->mDetails->setString(key.c_str(), value.c_str()); } void MediaCodecInfo::addFeature(const AString &key, int32_t value) { AString tag = "feature-"; tag.append(key); mCurrentCaps->mDetails->setInt32(tag.c_str(), value); } void MediaCodecInfo::addFeature(const AString &key, const char *value) { AString tag = "feature-"; tag.append(key); mCurrentCaps->mDetails->setString(tag.c_str(), value); } } // namespace android