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

Commit 60fff47f authored by Ray Essick's avatar Ray Essick Committed by Android (Google) Code Review
Browse files

Merge "Update mediaformatshaper library" into sc-dev

parents dcc50119 970f1c8a
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -36,6 +36,7 @@ cc_defaults {
    name: "libmediaformatshaper_defaults",
    name: "libmediaformatshaper_defaults",
    srcs: [
    srcs: [
        "CodecProperties.cpp",
        "CodecProperties.cpp",
        "CodecSeeding.cpp",
        "FormatShaper.cpp",
        "FormatShaper.cpp",
        "ManageShapingCodecs.cpp",
        "ManageShapingCodecs.cpp",
        "VideoShaper.cpp",
        "VideoShaper.cpp",
+33 −0
Original line number Original line Diff line number Diff line
@@ -26,6 +26,7 @@ namespace android {
namespace mediaformatshaper {
namespace mediaformatshaper {


CodecProperties::CodecProperties(std::string name, std::string mediaType) {
CodecProperties::CodecProperties(std::string name, std::string mediaType) {
    ALOGV("CodecProperties(%s, %s)", name.c_str(), mediaType.c_str());
    mName = name;
    mName = name;
    mMediaType = mediaType;
    mMediaType = mediaType;
}
}
@@ -58,6 +59,38 @@ int CodecProperties::supportedApi() {
    return mApi;
    return mApi;
}
}


void CodecProperties::setFeatureValue(std::string key, int32_t value) {
    ALOGD("setFeatureValue(%s,%d)", key.c_str(), value);
    mFeatures.insert({key, value});

    if (!strcmp(key.c_str(), "vq-minimum-quality")) {
        setSupportedMinimumQuality(value);
    } else if (!strcmp(key.c_str(), "vq-supports-qp")) {      // key from prototyping
        setSupportsQp(1);
    } else if (!strcmp(key.c_str(), "qp-bounds")) {           // official key
        setSupportsQp(1);
    } else if (!strcmp(key.c_str(), "vq-target-qpmax")) {
        setTargetQpMax(value);
    } else if (!strcmp(key.c_str(), "vq-target-bppx100")) {
        double bpp = value / 100.0;
        setBpp(bpp);
    }
}

bool CodecProperties::getFeatureValue(std::string key, int32_t *valuep) {
    ALOGV("getFeatureValue(%s)", key.c_str());
    if (valuep == nullptr) {
        return false;
    }
    auto mapped = mFeatures.find(key);
    if (mapped != mFeatures.end()) {
        *valuep = mapped->second;
        return true;
    }
    return false;
}


std::string CodecProperties::getMapping(std::string key, std::string kind) {
std::string CodecProperties::getMapping(std::string key, std::string kind) {
    ALOGV("getMapping(key %s, kind %s )", key.c_str(), kind.c_str());
    ALOGV("getMapping(key %s, kind %s )", key.c_str(), kind.c_str());
    //play with mMappings
    //play with mMappings
+127 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright 2021, 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 "CodecSeeding"
#include <utils/Log.h>

#include <string>

#include <media/formatshaper/CodecProperties.h>

namespace android {
namespace mediaformatshaper {

/*
 * a block of pre-loads; things the library seeds into the codecproperties based
 * on the mediaType.
 * XXX: parsing from a file is likely better than embedding in code.
 */
typedef struct {
    const char *key;
    int32_t value;
} preloadFeature_t;

typedef struct {
    const char *mediaType;
    preloadFeature_t *features;
} preloadProperties_t;

/*
 * 240 = 2.4 bits per pixel-per-second == 5mbps@1080, 2.3mbps@720p, which is about where
 * we want our initial floor for now.
 */

static preloadFeature_t featuresAvc[] = {
      {"vq-target-bppx100", 240},
      {nullptr, 0}
};

static preloadFeature_t featuresHevc[] = {
      {"vq-target-bppx100", 240},
      {nullptr, 0}
};

static preloadFeature_t featuresGenericVideo[] = {
      {"vq-target-bppx100", 240},
      {nullptr, 0}
};

static preloadProperties_t preloadProperties[] = {
    { "video/avc", featuresAvc},
    { "video/hevc", &featuresHevc[0]},

    // wildcard for any video format not already captured
    { "video/*", &featuresGenericVideo[0]},
    { nullptr, nullptr}
};

void CodecProperties::Seed() {
    ALOGV("Seed: for codec %s, mediatype %s", mName.c_str(), mMediaType.c_str());

    // load me up with initial configuration data
    int count = 0;
    for (int i=0;; i++) {
        preloadProperties_t *p = &preloadProperties[i];
        if (p->mediaType == nullptr) {
            break;
        }
        bool found = false;
        if (strcmp(p->mediaType, mMediaType.c_str()) == 0) {
            found = true;
        }
        const char *r;
        if (!found && (r = strchr(p->mediaType, '*')) != NULL) {
            // wildcard; check the prefix
            size_t len = r - p->mediaType;
            if (strncmp(p->mediaType, mMediaType.c_str(), len) == 0) {
                found = true;
            }
        }

        if (!found) {
            continue;
        }
        ALOGV("seeding from mediaType '%s'", p->mediaType);

        // walk through, filling things
        if (p->features != nullptr) {
            for (int j=0;; j++) {
                preloadFeature_t *q = &p->features[j];
                if (q->key == nullptr) {
                    break;
                }
                setFeatureValue(q->key, q->value);
                count++;
            }
            break;
        }
    }
    ALOGV("loaded %d preset values", count);
}

// a chance, as we register the codec and accept no further updates, to
// override any poor configuration that arrived from the device's XML files.
//
void CodecProperties::Finish() {
    ALOGV("Finish: for codec %s, mediatype %s", mName.c_str(), mMediaType.c_str());

    // currently a no-op
}

} // namespace mediaformatshaper
} // namespace android
+12 −13
Original line number Original line Diff line number Diff line
@@ -93,19 +93,9 @@ int setFeature(shaperHandle_t shaper, const char *feature, int value) {
        return -1;
        return -1;
    }
    }


    if (!strcmp(feature, "vq-minimum-quality")) {
    // save a map of all features
        codec->setSupportedMinimumQuality(value);
    codec->setFeatureValue(feature, value);
    } else if (!strcmp(feature, "vq-supports-qp")) {

        codec->setSupportsQp(value != 0);
    } else if (!strcmp(feature, "vq-target-qpmax")) {
        codec->setTargetQpMax(value);
    } else if (!strcmp(feature, "vq-target-bppx100")) {
        double bpp = value / 100.0;
        codec->setBpp(bpp);
    } else {
        // changed nothing, don't mark as configured
        return 0;
    }
    return 0;
    return 0;
}
}


@@ -120,6 +110,9 @@ shaperHandle_t findShaper(const char *codecName, const char *mediaType) {


shaperHandle_t createShaper(const char *codecName, const char *mediaType) {
shaperHandle_t createShaper(const char *codecName, const char *mediaType) {
    CodecProperties *codec = new CodecProperties(codecName, mediaType);
    CodecProperties *codec = new CodecProperties(codecName, mediaType);
    if (codec != nullptr) {
        codec->Seed();
    }
    return (shaperHandle_t) codec;
    return (shaperHandle_t) codec;
}
}


@@ -134,6 +127,12 @@ shaperHandle_t registerShaper(shaperHandle_t shaper, const char *codecName, cons
        return nullptr;
        return nullptr;
    }
    }


    // any final cleanup for the parameters. This allows us to override
    // bad parameters from a devices XML file.
    codec->Finish();

    // may return a different codec, if we lost a race.
    // if so, registerCodec() reclaims the one we tried to register for us.
    codec = registerCodec(codec, codecName, mediaType);
    codec = registerCodec(codec, codecName, mediaType);
    return (shaperHandle_t) codec;
    return (shaperHandle_t) codec;
}
}
+43 −25
Original line number Original line Diff line number Diff line
@@ -44,42 +44,60 @@ namespace mediaformatshaper {
#define	AMEDIAFORMAT_VIDEO_QP_P_MAX	"video-qp-p-max"
#define	AMEDIAFORMAT_VIDEO_QP_P_MAX	"video-qp-p-max"
#define	AMEDIAFORMAT_VIDEO_QP_P_MIN	"video-qp-p-min"
#define	AMEDIAFORMAT_VIDEO_QP_P_MIN	"video-qp-p-min"


// defined in the SDK, but not in the NDK
//
static const int BITRATE_MODE_VBR = 1;

//
//
// Caller retains ownership of and responsibility for inFormat
// Caller retains ownership of and responsibility for inFormat
//
//
int VQApply(CodecProperties *codec, vqOps_t *info, AMediaFormat* inFormat, int flags) {
int VQApply(CodecProperties *codec, vqOps_t *info, AMediaFormat* inFormat, int flags) {
    ALOGV("codecName %s inFormat %p flags x%x", codec->getName().c_str(), inFormat, flags);
    ALOGV("codecName %s inFormat %p flags x%x", codec->getName().c_str(), inFormat, flags);


    int32_t bitRateMode = -1;
    if (AMediaFormat_getInt32(inFormat, AMEDIAFORMAT_KEY_BITRATE_MODE, &bitRateMode)
        && bitRateMode != BITRATE_MODE_VBR) {
        ALOGD("minquality: applies only to VBR encoding");
        return 0;
    }

    if (codec->supportedMinimumQuality() > 0) {
    if (codec->supportedMinimumQuality() > 0) {
        // allow the codec provided minimum quality behavior to work at it
        // allow the codec provided minimum quality behavior to work at it
        ALOGD("minquality(codec): codec says %d", codec->supportedMinimumQuality());
        ALOGD("minquality: codec claims to implement minquality=%d",
              codec->supportedMinimumQuality());
        return 0;
        return 0;
    }
    }


    ALOGD("considering other ways to improve quality...");

    //
    //
    // apply any and all tools that we have.
    // apply any and all tools that we have.
    // -- qp
    // -- qp
    // -- minimum bits-per-pixel
    // -- minimum bits-per-pixel
    //
    //
    if (codec->supportsQp()) {
    if (!codec->supportsQp()) {
        ALOGD("minquality: no qp bounding in codec %s", codec->getName().c_str());
    } else {
        // use a (configurable) QP value to force better quality
        // use a (configurable) QP value to force better quality
        //
        //
        // XXX: augment this so that we don't lower an existing QP setting
        int32_t qpmax = codec->targetQpMax();
        // (e.g. if user set it to 40, we don't want to set it back to 45)
        int32_t qpmaxUser = INT32_MAX;
        int qpmax = codec->targetQpMax();
        if (hasQp(inFormat)) {
        if (qpmax <= 0) {
            (void) AMediaFormat_getInt32(inFormat, AMEDIAFORMAT_VIDEO_QP_MAX, &qpmaxUser);
                qpmax = 45;
            ALOGD("minquality by QP: format already sets QP");
                ALOGD("use default substitute QpMax == %d", qpmax);
        }

        // if the system didn't do one, use what the user provided
        if (qpmax == 0 && qpmaxUser != INT32_MAX) {
                qpmax = qpmaxUser;
        }
        }
        // XXX: if both said something, how do we want to reconcile that

        if (qpmax > 0) {
            ALOGD("minquality by QP: inject %s=%d", AMEDIAFORMAT_VIDEO_QP_MAX, qpmax);
            ALOGD("minquality by QP: inject %s=%d", AMEDIAFORMAT_VIDEO_QP_MAX, qpmax);
            AMediaFormat_setInt32(inFormat, AMEDIAFORMAT_VIDEO_QP_MAX, qpmax);
            AMediaFormat_setInt32(inFormat, AMEDIAFORMAT_VIDEO_QP_MAX, qpmax);


            // force spreading the QP across frame types, since we imposing a value
            // force spreading the QP across frame types, since we imposing a value
            qpSpreadMaxPerFrameType(inFormat, info->qpDelta, info->qpMax, /* override */ true);
            qpSpreadMaxPerFrameType(inFormat, info->qpDelta, info->qpMax, /* override */ true);
    } else {
        }
        ALOGD("codec %s: no qp bounding", codec->getName().c_str());
    }
    }


    double bpp = codec->getBpp();
    double bpp = codec->getBpp();
@@ -108,7 +126,7 @@ int VQApply(CodecProperties *codec, vqOps_t *info, AMediaFormat* inFormat, int f
              bitrateConfigured, bitrateFloor, codec->getBpp(), height, width);
              bitrateConfigured, bitrateFloor, codec->getBpp(), height, width);


        if (bitrateConfigured < bitrateFloor) {
        if (bitrateConfigured < bitrateFloor) {
            ALOGD("minquality/target bitrate raised from %d to %" PRId64 " to maintain quality",
            ALOGD("minquality/target bitrate raised from %d to %" PRId64 " bps",
                  bitrateConfigured, bitrateFloor);
                  bitrateConfigured, bitrateFloor);
            AMediaFormat_setInt32(inFormat, AMEDIAFORMAT_KEY_BIT_RATE, (int32_t)bitrateFloor);
            AMediaFormat_setInt32(inFormat, AMEDIAFORMAT_KEY_BIT_RATE, (int32_t)bitrateFloor);
        }
        }
@@ -121,16 +139,16 @@ int VQApply(CodecProperties *codec, vqOps_t *info, AMediaFormat* inFormat, int f
bool hasQpPerFrameType(AMediaFormat *format) {
bool hasQpPerFrameType(AMediaFormat *format) {
    int32_t value;
    int32_t value;


    if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MAX, &value)
    if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MAX, &value)
        || !AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MIN, &value)) {
        || AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MIN, &value)) {
        return true;
        return true;
    }
    }
    if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MAX, &value)
    if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MAX, &value)
        || !AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MIN, &value)) {
        || AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MIN, &value)) {
        return true;
        return true;
    }
    }
    if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MAX, &value)
    if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MAX, &value)
        || !AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MIN, &value)) {
        || AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MIN, &value)) {
        return true;
        return true;
    }
    }
    return false;
    return false;
@@ -138,8 +156,8 @@ bool hasQpPerFrameType(AMediaFormat *format) {


bool hasQp(AMediaFormat *format) {
bool hasQp(AMediaFormat *format) {
    int32_t value;
    int32_t value;
    if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_MAX, &value)
    if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_MAX, &value)
        || !AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_MIN, &value)) {
        || AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_MIN, &value)) {
        return true;
        return true;
    }
    }
    return hasQpPerFrameType(format);
    return hasQpPerFrameType(format);
Loading