/*
 * Copyright (C) 2018 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 "Codec2InfoBuilder"
#include <log/log.h>

#include <strings.h>

#include <C2Component.h>
#include <C2Config.h>
#include <C2Debug.h>
#include <C2PlatformSupport.h>
#include <Codec2Mapper.h>

#include <OMX_Audio.h>
#include <OMX_AudioExt.h>
#include <OMX_IndexExt.h>
#include <OMX_Types.h>
#include <OMX_Video.h>
#include <OMX_VideoExt.h>
#include <OMX_AsString.h>

#include <android/hardware/media/omx/1.0/IOmx.h>
#include <android/hardware/media/omx/1.0/IOmxObserver.h>
#include <android/hardware/media/omx/1.0/IOmxNode.h>
#include <android/hardware/media/omx/1.0/types.h>

#include <android-base/properties.h>
#include <codec2/hidl/client.h>
#include <cutils/native_handle.h>
#include <media/omx/1.0/WOmxNode.h>
#include <media/stagefright/foundation/ALookup.h>
#include <media/stagefright/foundation/MediaDefs.h>
#include <media/stagefright/omx/OMXUtils.h>
#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
#include <media/stagefright/Codec2InfoBuilder.h>
#include <media/stagefright/MediaCodecConstants.h>

namespace android {

using Traits = C2Component::Traits;

namespace /* unnamed */ {

bool hasPrefix(const std::string& s, const char* prefix) {
    size_t prefixLen = strlen(prefix);
    return s.compare(0, prefixLen, prefix) == 0;
}

bool hasSuffix(const std::string& s, const char* suffix) {
    size_t suffixLen = strlen(suffix);
    return suffixLen > s.size() ? false :
            s.compare(s.size() - suffixLen, suffixLen, suffix) == 0;
}

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

    // 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))
    };

    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;
    }

    // we only handle enumerated values
    if (profileQuery[0].values.type != C2FieldSupportedValues::VALUES) {
        return;
    }

    // determine if codec supports HDR
    bool supportsHdr = false;
    bool supportsHdr10Plus = false;

    std::vector<std::shared_ptr<C2ParamDescriptor>> paramDescs;
    c2_status_t err1 = intf->querySupportedParams(&paramDescs);
    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;
            }
        }
    }

    // For VP9/AV1, the static info is always propagated by framework.
    supportsHdr |= (mediaType == MIMETYPE_VIDEO_VP9);
    supportsHdr |= (mediaType == MIMETYPE_VIDEO_AV1);

    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;
        }

        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);
                    }
                }
            }
        } 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
            || mediaType.find("image") != 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);
        }
    }
}

class Switch {
    enum Flags : uint8_t {
        // flags
        IS_ENABLED = (1 << 0),
        BY_DEFAULT = (1 << 1),
    };

    constexpr Switch(uint8_t flags) : mFlags(flags) {}

    uint8_t mFlags;

public:
    // have to create class due to this bool conversion operator...
    constexpr operator bool() const {
        return mFlags & IS_ENABLED;
    }

    constexpr Switch operator!() const {
        return Switch(mFlags ^ IS_ENABLED);
    }

    static constexpr Switch DISABLED() { return 0; };
    static constexpr Switch ENABLED() { return IS_ENABLED; };
    static constexpr Switch DISABLED_BY_DEFAULT() { return BY_DEFAULT; };
    static constexpr Switch ENABLED_BY_DEFAULT() { return IS_ENABLED | BY_DEFAULT; };

    const char *toString(const char *def = "??") const {
        switch (mFlags) {
        case 0:                         return "0";
        case IS_ENABLED:                return "1";
        case BY_DEFAULT:                return "(0)";
        case IS_ENABLED | BY_DEFAULT:   return "(1)";
        default: return def;
        }
    }

};

const char *asString(const Switch &s, const char *def = "??") {
    return s.toString(def);
}

Switch isSettingEnabled(
        std::string setting, const MediaCodecsXmlParser::AttributeMap &settings,
        Switch def = Switch::DISABLED_BY_DEFAULT()) {
    const auto enablement = settings.find(setting);
    if (enablement == settings.end()) {
        return def;
    }
    return enablement->second == "1" ? Switch::ENABLED() : Switch::DISABLED();
}

Switch isVariantEnabled(
        std::string variant, const MediaCodecsXmlParser::AttributeMap &settings) {
    return isSettingEnabled("variant-" + variant, settings);
}

Switch isVariantExpressionEnabled(
        std::string exp, const MediaCodecsXmlParser::AttributeMap &settings) {
    if (!exp.empty() && exp.at(0) == '!') {
        return !isVariantEnabled(exp.substr(1, exp.size() - 1), settings);
    }
    return isVariantEnabled(exp, settings);
}

Switch isDomainEnabled(
        std::string domain, const MediaCodecsXmlParser::AttributeMap &settings) {
    return isSettingEnabled("domain-" + domain, settings);
}

} // unnamed namespace

status_t Codec2InfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
    // TODO: Remove run-time configurations once all codecs are working
    // properly. (Assume "full" behavior eventually.)
    //
    // debug.stagefright.ccodec supports 5 values.
    //   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
    //       their normal ranks.
    //       Components with prefix "c2.vda." are available with their normal
    //       ranks.
    //       All other components with suffix ".avc.decoder" or ".avc.encoder"
    //       are available but ranked last.
    //   2 - Components with prefix "c2.android." are available and ranked
    //       first.
    //       Components with prefix "c2.vda." are available with their normal
    //       ranks.
    //       All other components with suffix ".avc.decoder" or ".avc.encoder"
    //       are available but ranked last.
    //   3 - Components with prefix "c2.android." are available and ranked
    //       first.
    //       All other components are available with their normal ranks.
    //   4 - All components are available with their normal ranks.
    //
    // The default value (boot time) is 1.
    //
    // Note: Currently, OMX components have default rank 0x100, while all
    // Codec2.0 software components have default rank 0x200.
    int option = ::android::base::GetIntProperty("debug.stagefright.ccodec", 4);

    // Obtain Codec2Client
    std::vector<Traits> traits = Codec2Client::ListComponents();

    // parse APEX XML first, followed by vendor XML.
    // Note: APEX XML names do not depend on ro.media.xml_variant.* properties.
    MediaCodecsXmlParser parser;
    parser.parseXmlFilesInSearchDirs(
            { "media_codecs.xml", "media_codecs_performance.xml" },
            { "/apex/com.android.media.swcodec/etc" });

    // TODO: remove these c2-specific files once product moved to default file names
    parser.parseXmlFilesInSearchDirs(
            { "media_codecs_c2.xml", "media_codecs_performance_c2.xml" });

    // parse default XML files
    parser.parseXmlFilesInSearchDirs();

    if (parser.getParsingStatus() != OK) {
        ALOGD("XML parser no good");
        return OK;
    }

    MediaCodecsXmlParser::AttributeMap settings = parser.getServiceAttributeMap();
    for (const auto &v : settings) {
        if (!hasPrefix(v.first, "media-type-")
                && !hasPrefix(v.first, "domain-")
                && !hasPrefix(v.first, "variant-")) {
            writer->addGlobalSetting(v.first.c_str(), v.second.c_str());
        }
    }

    for (const Traits& trait : traits) {
        C2Component::rank_t rank = trait.rank;

        // 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 (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;
            }

            const MediaCodecsXmlParser::CodecProperties &codec =
                parser.getCodecMap().at(nameOrAlias);

            // verify that either the codec is explicitly enabled, or one of its domains is
            bool codecEnabled = codec.quirkSet.find("attribute::disabled") == codec.quirkSet.end();
            if (!codecEnabled) {
                for (const std::string &domain : codec.domainSet) {
                    const Switch enabled = isDomainEnabled(domain, settings);
                    ALOGV("codec entry '%s' is in domain '%s' that is '%s'",
                            nameOrAlias.c_str(), domain.c_str(), asString(enabled));
                    if (enabled) {
                        codecEnabled = true;
                        break;
                    }
                }
            }
            // if codec has variants, also check that at least one of them is enabled
            bool variantEnabled = codec.variantSet.empty();
            for (const std::string &variant : codec.variantSet) {
                const Switch enabled = isVariantExpressionEnabled(variant, settings);
                ALOGV("codec entry '%s' has a variant '%s' that is '%s'",
                        nameOrAlias.c_str(), variant.c_str(), asString(enabled));
                if (enabled) {
                    variantEnabled = true;
                    break;
                }
            }
            if (!codecEnabled || !variantEnabled) {
                ALOGD("codec entry for '%s' is disabled", nameOrAlias.c_str());
                continue;
            }

            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());

            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") {
                    attrs |= MediaCodecInfo::kFlagIsSoftwareOnly;
                } else if (codec.quirkSet.find("attribute::software-codec")
                        == codec.quirkSet.end()) {
                    attrs |= MediaCodecInfo::kFlagIsHardwareAccelerated;
                }
            }
            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;
                }
            }
            ALOGV("rank: %u", (unsigned)rank);
            codecInfo->setRank(rank);

            for (const std::string &alias : codec.aliases) {
                ALOGV("adding alias '%s'", alias.c_str());
                codecInfo->addAlias(alias.c_str());
            }

            for (auto typeIt = codec.typeMap.begin(); typeIt != codec.typeMap.end(); ++typeIt) {
                const std::string &mediaType = typeIt->first;
                const Switch typeEnabled = isSettingEnabled(
                        "media-type-" + mediaType, settings, Switch::ENABLED_BY_DEFAULT());
                const Switch domainTypeEnabled = isSettingEnabled(
                        "media-type-" + mediaType + (encoder ? "-encoder" : "-decoder"),
                        settings, Switch::ENABLED_BY_DEFAULT());
                ALOGV("type '%s-%s' is '%s/%s'",
                        mediaType.c_str(), (encoder ? "encoder" : "decoder"),
                        asString(typeEnabled), asString(domainTypeEnabled));
                if (!typeEnabled || !domainTypeEnabled) {
                    ALOGD("media type '%s' for codec entry '%s' is disabled", mediaType.c_str(),
                            nameOrAlias.c_str());
                    continue;
                }

                ALOGI("adding type '%s'", typeIt->first.c_str());
                const MediaCodecsXmlParser::AttributeMap &attrMap = typeIt->second;
                std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
                    codecInfo->addMediaType(mediaType.c_str());
                for (const auto &v : attrMap) {
                    std::string key = v.first;
                    std::string value = v.second;

                    size_t variantSep = key.find(":::");
                    if (variantSep != std::string::npos) {
                        std::string variant = key.substr(0, variantSep);
                        const Switch enabled = isVariantExpressionEnabled(variant, settings);
                        ALOGV("variant '%s' is '%s'", variant.c_str(), asString(enabled));
                        if (!enabled) {
                            continue;
                        }
                        key = key.substr(variantSep + 3);
                    }

                    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());
                    }
                }

                addSupportedProfileLevels(intf, caps.get(), trait, mediaType);
                addSupportedColorFormats(intf, caps.get(), trait, mediaType);
            }
        }
    }
    return OK;
}

}  // namespace android

extern "C" android::MediaCodecListBuilderBase *CreateBuilder() {
    return new android::Codec2InfoBuilder;
}
