Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6e6d94d5 authored by Songyue Han's avatar Songyue Han Committed by Automerger Merge Worker
Browse files

Merge "CodecCapabilities: Port EncoderCapabilities from Java to Native." into main am: aa1a64aa

parents a4e209c6 aa1a64aa
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -260,6 +260,7 @@ cc_library_shared {
    srcs: [
        "AudioCapabilities.cpp",
        "CodecCapabilities.cpp",
        "EncoderCapabilities.cpp",
        "VideoCapabilities.cpp",
        "CodecCapabilitiesUtils.cpp",
    ],
+205 −0
Original line number Diff line number Diff line
/*
 * Copyright 2024, 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 "EncoderCapabilities"

#include <android-base/strings.h>

#include <media/CodecCapabilities.h>
#include <media/EncoderCapabilities.h>
#include <media/stagefright/MediaCodecConstants.h>

namespace android {

const Range<int>& EncoderCapabilities::getQualityRange() {
    return mQualityRange;
}

const Range<int>& EncoderCapabilities::getComplexityRange() {
    return mComplexityRange;
}

// static
int EncoderCapabilities::ParseBitrateMode(std::string mode) {
    for (Feature feat: sBitrateModes) {
        if (base::EqualsIgnoreCase(feat.mName, mode)) {
            return feat.mValue;
        }
    }
    return 0;
}

bool EncoderCapabilities::isBitrateModeSupported(int mode) {
    for (Feature feat : sBitrateModes) {
        if (mode == feat.mValue) {
            return (mBitControl & (1 << mode)) != 0;
        }
    }
    return false;
}

// static
std::shared_ptr<EncoderCapabilities> EncoderCapabilities::Create(std::string mediaType,
        std::vector<ProfileLevel> profLevs, const sp<AMessage> &format) {
    std::shared_ptr<EncoderCapabilities> caps(new EncoderCapabilities());
    caps->init(mediaType, profLevs, format);
    return caps;
}

void EncoderCapabilities::init(std::string mediaType, std::vector<ProfileLevel> profLevs,
        const sp<AMessage> &format) {
    // no support for complexity or quality yet
    mMediaType = mediaType;
    mProfileLevels = profLevs;
    mComplexityRange = Range(0, 0);
    mQualityRange = Range(0, 0);
    mBitControl = (1 << BITRATE_MODE_VBR);

    applyLevelLimits();
    parseFromInfo(format);
}

void EncoderCapabilities::applyLevelLimits() {
    if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_FLAC)) {
        mComplexityRange = Range(0, 8);
        mBitControl = (1 << BITRATE_MODE_CQ);
    } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AMR_NB)
            || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AMR_WB)
            || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_G711_ALAW)
            || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_G711_MLAW)
            || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_MSGSM)) {
        mBitControl = (1 << BITRATE_MODE_CBR);
    }
}

void EncoderCapabilities::parseFromInfo(const sp<AMessage> &format) {
    AString complexityRangeAStr;
    if (format->findString("complexity-range", &complexityRangeAStr)) {
        std::optional<Range<int>> complexityRangeOpt
                = Range<int32_t>::Parse(std::string(complexityRangeAStr.c_str()));
        mComplexityRange = complexityRangeOpt.value_or(mComplexityRange);
        // TODO should we limit this to level limits?
    }
    AString qualityRangeAStr;
    if (format->findString("quality-range", &qualityRangeAStr)) {
        std::optional<Range<int>> qualityRangeOpt
                = Range<int32_t>::Parse(std::string(qualityRangeAStr.c_str()));
        mQualityRange = qualityRangeOpt.value_or(mQualityRange);
    }
    AString bitrateModesAStr;
    if (format->findString("feature-bitrate-modes", &bitrateModesAStr)) {
        mBitControl = 0;
        for (std::string mode: base::Split(std::string(bitrateModesAStr.c_str()), ",")) {
            mBitControl |= (1 << ParseBitrateMode(mode));
        }
    }
    format->findInt32("complexity-default", &mDefaultComplexity);
    format->findInt32("quality-default", &mDefaultQuality);
    AString qualityScaleAStr;
    if (format->findString("quality-scale", &qualityScaleAStr)) {
        mQualityScale = std::string(qualityScaleAStr.c_str());
    }
}

bool EncoderCapabilities::supports(
        std::optional<int> complexity, std::optional<int> quality, std::optional<int> profile) {
    bool ok = true;
    if (complexity) {
        ok &= mComplexityRange.contains(complexity.value());
    }
    if (quality) {
        ok &= mQualityRange.contains(quality.value());
    }
    if (profile) {
        ok &= std::any_of(mProfileLevels.begin(), mProfileLevels.end(),
                [&profile](ProfileLevel pl){ return pl.mProfile == profile.value(); });
    }
    return ok;
}

void EncoderCapabilities::getDefaultFormat(sp<AMessage> &format) {
    // don't list trivial quality/complexity as default for now
    if (mQualityRange.upper() != mQualityRange.lower()
            && mDefaultQuality != 0) {
        format->setInt32(KEY_QUALITY, mDefaultQuality);
    }
    if (mComplexityRange.upper() != mComplexityRange.lower()
            && mDefaultComplexity != 0) {
        format->setInt32(KEY_COMPLEXITY, mDefaultComplexity);
    }
    // bitrates are listed in order of preference
    for (Feature feat : sBitrateModes) {
        if ((mBitControl & (1 << feat.mValue)) != 0) {
            format->setInt32(KEY_BITRATE_MODE, feat.mValue);
            break;
        }
    }
}

bool EncoderCapabilities::supportsFormat(const sp<AMessage> &format) {
    int32_t mode;
    if (format->findInt32(KEY_BITRATE_MODE, &mode) && !isBitrateModeSupported(mode)) {
        return false;
    }

    int tmp;
    std::optional<int> complexity = std::nullopt;
    if (format->findInt32(KEY_COMPLEXITY, &tmp)) {
        complexity = tmp;
    }

    if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_FLAC)) {
        int flacComplexity;
        if (format->findInt32(KEY_FLAC_COMPRESSION_LEVEL, &flacComplexity)) {
            if (!complexity) {
                complexity = flacComplexity;
            } else if (flacComplexity != complexity.value()) {
                ALOGE("Conflicting values for complexity and flac-compression-level,"
                        " which are %d and %d", complexity.value(), flacComplexity);
                return false;
            }
        }
    }

    // other audio parameters
    std::optional<int> profile = std::nullopt;
    if (format->findInt32(KEY_PROFILE, &tmp)) {
        profile = tmp;
    }

    if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AAC)) {
        int aacProfile;
        if (format->findInt32(KEY_AAC_PROFILE, &aacProfile)) {
            if (!profile) {
                profile = aacProfile;
            } else if (aacProfile != profile.value()) {
                ALOGE("Conflicting values for profile and aac-profile, which are %d and %d",
                        profile.value(), aacProfile);
                return false;
            }
        }
    }

    std::optional<int> quality = std::nullopt;
    if (format->findInt32(KEY_QUALITY, &tmp)) {
        quality = tmp;
    }

    return supports(complexity, quality, profile);
}

}  // namespace android
 No newline at end of file
+3 −1
Original line number Diff line number Diff line
@@ -19,8 +19,9 @@
#define CODEC_CAPABILITIES_H_

#include <media/AudioCapabilities.h>
#include <media/VideoCapabilities.h>
#include <media/CodecCapabilitiesUtils.h>
#include <media/EncoderCapabilities.h>
#include <media/VideoCapabilities.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AString.h>
@@ -54,6 +55,7 @@ private:

    std::shared_ptr<AudioCapabilities> mAudioCaps;
    std::shared_ptr<VideoCapabilities> mVideoCaps;
    std::shared_ptr<EncoderCapabilities> mEncoderCaps;
};

}  // namespace android
+15 −0
Original line number Diff line number Diff line
@@ -42,6 +42,21 @@ struct ProfileLevel {
    }
};

struct Feature {
    std::string mName;
    int mValue;
    bool mDefault;
    bool mInternal;
    Feature(std::string name, int value, bool def, bool internal) {
        mName = name;
        mValue = value;
        mDefault = def;
        mInternal = internal;
    }
    Feature(std::string name, int value, bool def) :
        Feature(name, value, def, false /* internal */) {}
};

/**
 * Immutable class for describing the range of two numeric values.
 *
+105 −0
Original line number Diff line number Diff line
/*
 * Copyright 2024, 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.
 */

#ifndef ENCODER_CAPABILITIES_H_

#define ENCODER_CAPABILITIES_H_

#include <media/CodecCapabilitiesUtils.h>
#include <media/stagefright/foundation/AMessage.h>

#include <utils/StrongPointer.h>

namespace android {

/**
 * A class that supports querying the encoding capabilities of a codec.
 */
struct EncoderCapabilities {
    /**
    * Returns the supported range of quality values.
    *
    * Quality is implementation-specific. As a general rule, a higher quality
    * setting results in a better image quality and a lower compression ratio.
    */
    const Range<int>& getQualityRange();

    /**
     * Returns the supported range of encoder complexity values.
     * <p>
     * Some codecs may support multiple complexity levels, where higher
     * complexity values use more encoder tools (e.g. perform more
     * intensive calculations) to improve the quality or the compression
     * ratio.  Use a lower value to save power and/or time.
     */
    const Range<int>& getComplexityRange();

    /** Constant quality mode */
    inline static constexpr int BITRATE_MODE_CQ = 0;
    /** Variable bitrate mode */
    inline static constexpr int BITRATE_MODE_VBR = 1;
    /** Constant bitrate mode */
    inline static constexpr int BITRATE_MODE_CBR = 2;
    /** Constant bitrate mode with frame drops */
    inline static constexpr int BITRATE_MODE_CBR_FD =  3;

    /**
     * Query whether a bitrate mode is supported.
     */
    bool isBitrateModeSupported(int mode);

    /** @hide */
    static std::shared_ptr<EncoderCapabilities> Create(std::string mediaType,
            std::vector<ProfileLevel> profLevs, const sp<AMessage> &format);

    /** @hide */
    void getDefaultFormat(sp<AMessage> &format);

    /** @hide */
    bool supportsFormat(const sp<AMessage> &format);

private:
    inline static const Feature sBitrateModes[] = {
        Feature("VBR", BITRATE_MODE_VBR, true),
        Feature("CBR", BITRATE_MODE_CBR, false),
        Feature("CQ",  BITRATE_MODE_CQ,  false),
        Feature("CBR-FD", BITRATE_MODE_CBR_FD, false)
    };
    static int ParseBitrateMode(std::string mode);

    std::string mMediaType;
    std::vector<ProfileLevel> mProfileLevels;

    Range<int> mQualityRange;
    Range<int> mComplexityRange;
    int mBitControl;
    int mDefaultComplexity;
    int mDefaultQuality;
    std::string mQualityScale;

    /* no public constructor */
    EncoderCapabilities() {}
    void init(std::string mediaType, std::vector<ProfileLevel> profLevs,
            const sp<AMessage> &format);
    void applyLevelLimits();
    void parseFromInfo(const sp<AMessage> &format);
    bool supports(std::optional<int> complexity, std::optional<int> quality,
            std::optional<int> profile);
};

}  // namespace android

#endif // ENCODER_CAPABILITIES_H_
 No newline at end of file
Loading