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

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

Merge changes from topic "b181830609-part2" into sc-dev

* changes:
  Rework how QP bounds are passed, AVC encoder
  Rework how QP bounds are passed
parents e7be55d0 b3e76b60
Loading
Loading
Loading
Loading
+78 −106
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@
#include <log/log.h>
#include <utils/misc.h>

#include <algorithm>

#include <media/hardware/VideoAPI.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
@@ -120,6 +122,19 @@ public:
                .withSetter(GopSetter)
                .build());

        addParameter(
                DefineParam(mPictureQuantization, C2_PARAMKEY_PICTURE_QUANTIZATION)
                .withDefault(C2StreamPictureQuantizationTuning::output::AllocShared(
                        0 /* flexCount */, 0u /* stream */))
                .withFields({C2F(mPictureQuantization, m.values[0].type_).oneOf(
                                {C2Config::picture_type_t(I_FRAME),
                                  C2Config::picture_type_t(P_FRAME),
                                  C2Config::picture_type_t(B_FRAME)}),
                             C2F(mPictureQuantization, m.values[0].min).any(),
                             C2F(mPictureQuantization, m.values[0].max).any()})
                .withSetter(PictureQuantizationSetter)
                .build());

        addParameter(
                DefineParam(mActualInputDelay, C2_PARAMKEY_INPUT_DELAY)
                .withDefault(new C2PortActualDelayTuning::input(DEFAULT_B_FRAMES))
@@ -185,23 +200,6 @@ public:
                .withSetter(ProfileLevelSetter, mSize, mFrameRate, mBitrate)
                .build());

        addParameter(
                DefineParam(mQuantization, C2_PARAMKEY_QUANTIZATION)
                .withDefault(new C2StreamQuantizationInfo::output(0u,
                                      DEFAULT_QP_MAX, DEFAULT_QP_MIN,
                                      DEFAULT_QP_MAX, DEFAULT_QP_MIN,
                                      DEFAULT_QP_MAX, DEFAULT_QP_MIN))
                .withFields({
                        C2F(mQuantization, iMax).inRange(1, 51),
                        C2F(mQuantization, iMin).inRange(1, 51),
                        C2F(mQuantization, pMax).inRange(1, 51),
                        C2F(mQuantization, pMin).inRange(1, 51),
                        C2F(mQuantization, bMax).inRange(1, 51),
                        C2F(mQuantization, bMin).inRange(1, 51),
                 })
                .withSetter(QuantizationSetter)
                .build());

        addParameter(
                DefineParam(mRequestSync, C2_PARAMKEY_REQUEST_SYNC_FRAME)
                .withDefault(new C2StreamRequestSyncFrameTuning::output(0u, C2_FALSE))
@@ -237,70 +235,6 @@ public:
        return res;
    }

    static C2R QuantizationSetter(bool mayBlock, C2P<C2StreamQuantizationInfo::output> &me) {
        (void)mayBlock;
        (void)me;
        C2R res = C2R::Ok();

        ALOGV("QuantizationSetter enters max/min i %d/%d p %d/%d b %d/%d",
              me.v.iMax, me.v.iMin, me.v.pMax, me.v.pMin, me.v.bMax, me.v.bMin);

        // bounds checking
        constexpr int qp_lowest = 1;
        constexpr int qp_highest = 51;

        if (me.v.iMax < qp_lowest) {
            me.set().iMax = qp_lowest;
        } else if (me.v.iMax > qp_highest) {
            me.set().iMax = qp_highest;
        }

        if (me.v.iMin < qp_lowest) {
            me.set().iMin = qp_lowest;
        } else if (me.v.iMin > qp_highest) {
            me.set().iMin = qp_highest;
        }

        if (me.v.pMax < qp_lowest) {
            me.set().pMax = qp_lowest;
        } else if (me.v.pMax > qp_highest) {
            me.set().pMax = qp_highest;
        }

        if (me.v.pMin < qp_lowest) {
            me.set().pMin = qp_lowest;
        } else if (me.v.pMin > qp_highest) {
            me.set().pMin = qp_highest;
        }

        if (me.v.bMax < qp_lowest) {
            me.set().bMax = qp_lowest;
        } else if (me.v.bMax > qp_highest) {
            me.set().bMax = qp_highest;
        }

        if (me.v.bMin < qp_lowest) {
            me.set().bMin = qp_lowest;
        } else if (me.v.bMin > qp_highest) {
            me.set().bMin = qp_highest;
        }

        // consistency checking, e.g. min<max
        //
        if (me.v.iMax < me.v.iMin) {
            me.set().iMax = me.v.iMin;
        }
        if (me.v.pMax < me.v.pMin) {
            me.set().pMax = me.v.pMin;
        }
        if (me.v.bMax < me.v.bMin) {
            me.set().bMax = me.v.bMin;
        }

        // TODO: enforce any sort of i_max < p_max < b_max?

        return res;
    }

    static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::input> &oldMe,
                          C2P<C2StreamPictureSizeInfo::input> &me) {
@@ -418,6 +352,13 @@ public:
        return C2R::Ok();
    }

    static C2R PictureQuantizationSetter(bool mayBlock,
                                         C2P<C2StreamPictureQuantizationTuning::output> &me) {
        (void)mayBlock;
        (void)me;
        return C2R::Ok();
    }

    IV_PROFILE_T getProfile_l() const {
        switch (mProfileLevel->profile) {
        case PROFILE_AVC_CONSTRAINED_BASELINE:  [[fallthrough]];
@@ -475,7 +416,8 @@ public:
    std::shared_ptr<C2StreamBitrateInfo::output> getBitrate_l() const { return mBitrate; }
    std::shared_ptr<C2StreamRequestSyncFrameTuning::output> getRequestSync_l() const { return mRequestSync; }
    std::shared_ptr<C2StreamGopTuning::output> getGop_l() const { return mGop; }
    std::shared_ptr<C2StreamQuantizationInfo::output> getQuantization_l() const { return mQuantization; }
    std::shared_ptr<C2StreamPictureQuantizationTuning::output> getPictureQuantization_l() const
    { return mPictureQuantization; }

private:
    std::shared_ptr<C2StreamUsageTuning::input> mUsage;
@@ -487,7 +429,7 @@ private:
    std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
    std::shared_ptr<C2StreamSyncFrameIntervalTuning::output> mSyncFramePeriod;
    std::shared_ptr<C2StreamGopTuning::output> mGop;
    std::shared_ptr<C2StreamQuantizationInfo::output> mQuantization;
    std::shared_ptr<C2StreamPictureQuantizationTuning::output> mPictureQuantization;
};

#define ive_api_function  ih264e_api_function
@@ -748,36 +690,67 @@ c2_status_t C2SoftAvcEnc::setQp() {
    ive_ctl_set_qp_op_t s_qp_op;
    IV_STATUS_T status;

    ALOGV("in setQp()");

    // set the defaults
    s_qp_ip.e_cmd = IVE_CMD_VIDEO_CTL;
    s_qp_ip.e_sub_cmd = IVE_CMD_CTL_SET_QP;

    s_qp_ip.u4_i_qp = DEFAULT_I_QP;
    s_qp_ip.u4_i_qp_max = DEFAULT_QP_MAX;
    s_qp_ip.u4_i_qp_min = DEFAULT_QP_MIN;

    s_qp_ip.u4_p_qp = DEFAULT_P_QP;
    s_qp_ip.u4_p_qp_max = DEFAULT_QP_MAX;
    s_qp_ip.u4_p_qp_min = DEFAULT_QP_MIN;

    s_qp_ip.u4_b_qp = DEFAULT_P_QP;
    s_qp_ip.u4_b_qp_max = DEFAULT_QP_MAX;
    s_qp_ip.u4_b_qp_min = DEFAULT_QP_MIN;
    // these are the ones we're going to set, so want them to default ....
    // to the DEFAULT values for the codec instea dof CODEC_ bounding
    int32_t iMin = INT32_MIN, pMin = INT32_MIN, bMin = INT32_MIN;
    int32_t iMax = INT32_MAX, pMax = INT32_MAX, bMax = INT32_MAX;

    std::shared_ptr<C2StreamPictureQuantizationTuning::output> qp =
                    mIntf->getPictureQuantization_l();
    for (size_t i = 0; i < qp->flexCount(); ++i) {
        const C2PictureQuantizationStruct &layer = qp->m.values[i];

        if (layer.type_ == C2Config::picture_type_t(I_FRAME)) {
            iMax = layer.max;
            iMin = layer.min;
            ALOGV("iMin %d iMax %d", iMin, iMax);
        } else if (layer.type_ == C2Config::picture_type_t(P_FRAME)) {
            pMax = layer.max;
            pMin = layer.min;
            ALOGV("pMin %d pMax %d", pMin, pMax);
        } else if (layer.type_ == C2Config::picture_type_t(B_FRAME)) {
            bMax = layer.max;
            bMin = layer.min;
            ALOGV("bMin %d bMax %d", bMin, bMax);
        }
    }

    // INT32_{MIN,MAX} means unspecified, so use the codec's default
    if (iMax == INT32_MAX) iMax = DEFAULT_I_QP_MAX;
    if (iMin == INT32_MIN) iMin = DEFAULT_I_QP_MIN;
    if (pMax == INT32_MAX) pMax = DEFAULT_P_QP_MAX;
    if (pMin == INT32_MIN) pMin = DEFAULT_P_QP_MIN;
    if (bMax == INT32_MAX) bMax = DEFAULT_B_QP_MAX;
    if (bMin == INT32_MIN) bMin = DEFAULT_B_QP_MIN;

    // ensure we have legal values
    iMax = std::clamp(iMax, CODEC_QP_MIN, CODEC_QP_MAX);
    iMin = std::clamp(iMin, CODEC_QP_MIN, CODEC_QP_MAX);
    pMax = std::clamp(pMax, CODEC_QP_MIN, CODEC_QP_MAX);
    pMin = std::clamp(pMin, CODEC_QP_MIN, CODEC_QP_MAX);
    bMax = std::clamp(bMax, CODEC_QP_MIN, CODEC_QP_MAX);
    bMin = std::clamp(bMin, CODEC_QP_MIN, CODEC_QP_MAX);

    s_qp_ip.u4_i_qp_max = iMax;
    s_qp_ip.u4_i_qp_min = iMin;
    s_qp_ip.u4_p_qp_max = pMax;
    s_qp_ip.u4_p_qp_min = pMin;
    s_qp_ip.u4_b_qp_max = bMax;
    s_qp_ip.u4_b_qp_min = bMin;

    // ensure initial qp values are within our newly configured bounds...
    s_qp_ip.u4_i_qp = std::clamp(DEFAULT_I_QP, iMin, iMax);
    s_qp_ip.u4_p_qp = std::clamp(DEFAULT_P_QP, pMin, pMax);
    s_qp_ip.u4_b_qp = std::clamp(DEFAULT_B_QP, bMin, bMax);

    ALOGV("setting QP: i %d-%d p %d-%d b %d-%d", iMin, iMax, pMin, pMax, bMin, bMax);

    // parameter parsing ensured proper range 1..51, so only worry about ordering
    bool valid = true;
    if (mQuantization->iMax < mQuantization->iMin) valid = false;
    if (mQuantization->pMax < mQuantization->pMin) valid = false;
    if (mQuantization->bMax < mQuantization->bMin) valid = false;

    if (valid) {
        s_qp_ip.u4_i_qp_max = mQuantization->iMax;
        s_qp_ip.u4_i_qp_min = mQuantization->iMin;
        s_qp_ip.u4_p_qp_max = mQuantization->pMax;
        s_qp_ip.u4_p_qp_min = mQuantization->pMin;
        s_qp_ip.u4_b_qp_max = mQuantization->bMax;
        s_qp_ip.u4_b_qp_min = mQuantization->bMin;
    }

    s_qp_ip.u4_timestamp_high = -1;
    s_qp_ip.u4_timestamp_low = -1;
@@ -1026,7 +999,6 @@ c2_status_t C2SoftAvcEnc::initEncoder() {
        mIInterval = mIntf->getSyncFramePeriod_l();
        mIDRInterval = mIntf->getSyncFramePeriod_l();
        gop = mIntf->getGop_l();
        mQuantization = mIntf->getQuantization_l();
    }
    if (gop && gop->flexCount() > 0) {
        uint32_t syncInterval = 1;
+5 −1
Original line number Diff line number Diff line
@@ -100,6 +100,11 @@ namespace android {
#define STRLENGTH                   500
#define DEFAULT_CONSTRAINED_INTRA   0

/** limits as specified by h264 */
#define CODEC_QP_MIN                0
#define CODEC_QP_MAX                51


#define MIN(a, b) ((a) < (b))? (a) : (b)
#define MAX(a, b) ((a) > (b))? (a) : (b)
#define ALIGN16(x) ((((x) + 15) >> 4) << 4)
@@ -192,7 +197,6 @@ private:
    std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate;
    std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
    std::shared_ptr<C2StreamRequestSyncFrameTuning::output> mRequestSync;
    std::shared_ptr<C2StreamQuantizationInfo::output> mQuantization;

    uint32_t mOutBufferSize;
    UWORD32 mHeaderGenerated;
+26 −33
Original line number Diff line number Diff line
@@ -187,7 +187,7 @@ enum C2ParamIndexKind : C2Param::type_index_t {
    kParamIndexPictureType,
    kParamIndexHdr10PlusMetadata,

    kParamIndexQuantization,
    kParamIndexPictureQuantization,

    /* ------------------------------------ video components ------------------------------------ */

@@ -710,38 +710,6 @@ typedef C2StreamParam<C2Info, C2ProfileLevelStruct, kParamIndexProfileLevel>
        C2StreamProfileLevelInfo;
constexpr char C2_PARAMKEY_PROFILE_LEVEL[] = "coded.pl";

struct C2QuantizationStruct {
    int32_t iMax;  ///< max/min for I frames
    int32_t iMin;
    int32_t pMax;  ///< max/min for P frames
    int32_t pMin;
    int32_t bMax;  ///< max/min for B frames
    int32_t bMin;

    C2QuantizationStruct(
            int32_t iMax_ = INT32_MAX,
            int32_t iMin_ = INT32_MIN,
            int32_t pMax_ = INT32_MAX,
            int32_t pMin_ = INT32_MIN,
            int32_t bMax_ = INT32_MAX,
            int32_t bMin_ = INT32_MIN)
        : iMax(iMax_), iMin(iMin_),
          pMax(pMax_), pMin(pMin_),
          bMax(bMax_), bMin(bMin_) { }

    DEFINE_AND_DESCRIBE_C2STRUCT(Quantization)          // reference?
    C2FIELD(iMax, "i-max")
    C2FIELD(iMin, "i-min")
    C2FIELD(pMax, "p-max")
    C2FIELD(pMin, "p-min")
    C2FIELD(bMax, "b-max")
    C2FIELD(bMin, "b-min")
};

typedef C2StreamParam<C2Info, C2QuantizationStruct, kParamIndexQuantization>
        C2StreamQuantizationInfo;
constexpr char C2_PARAMKEY_QUANTIZATION[] = "coded.qp";

/**
 * Codec-specific initialization data.
 *
@@ -1732,6 +1700,31 @@ typedef C2StreamParam<C2Tuning, C2SimpleArrayStruct<C2GopLayerStruct>, kParamInd
        C2StreamGopTuning;
constexpr char C2_PARAMKEY_GOP[] = "coding.gop";

/**
 * Quantization
 * min/max for each picture type
 *
 */
struct C2PictureQuantizationStruct {
    C2PictureQuantizationStruct() : type_((C2Config::picture_type_t)0),
                                         min(INT32_MIN), max(INT32_MAX) {}
    C2PictureQuantizationStruct(C2Config::picture_type_t type, int32_t min_, int32_t max_)
        : type_(type), min(min_), max(max_) { }

    C2Config::picture_type_t type_;
    int32_t min;      // INT32_MIN == 'no lower bound specified'
    int32_t max;      // INT32_MAX == 'no upper bound specified'

    DEFINE_AND_DESCRIBE_C2STRUCT(PictureQuantization)
    C2FIELD(type_, "type")
    C2FIELD(min, "min")
    C2FIELD(max, "max")
};

typedef C2StreamParam<C2Tuning, C2SimpleArrayStruct<C2PictureQuantizationStruct>,
        kParamIndexPictureQuantization> C2StreamPictureQuantizationTuning;
constexpr char C2_PARAMKEY_PICTURE_QUANTIZATION[] = "coding.qp";

/**
 * Sync frame can be requested on demand by the client.
 *
+39 −0
Original line number Diff line number Diff line
@@ -1086,6 +1086,45 @@ void CCodec::configure(const sp<AMessage> &msg) {
            configUpdate.push_back(std::move(gop));
        }

        if ((config->mDomain & Config::IS_ENCODER)
                && (config->mDomain & Config::IS_VIDEO)) {
            // we may not use all 3 of these entries
            std::unique_ptr<C2StreamPictureQuantizationTuning::output> qp =
                C2StreamPictureQuantizationTuning::output::AllocUnique(3 /* flexCount */,
                                                                       0u /* stream */);

            int ix = 0;

            int32_t iMax = INT32_MAX;
            int32_t iMin = INT32_MIN;
            (void) sdkParams->findInt32(KEY_VIDEO_QP_I_MAX, &iMax);
            (void) sdkParams->findInt32(KEY_VIDEO_QP_I_MIN, &iMin);
            if (iMax != INT32_MAX || iMin != INT32_MIN) {
                qp->m.values[ix++] = {I_FRAME, iMin, iMax};
            }

            int32_t pMax = INT32_MAX;
            int32_t pMin = INT32_MIN;
            (void) sdkParams->findInt32(KEY_VIDEO_QP_P_MAX, &pMax);
            (void) sdkParams->findInt32(KEY_VIDEO_QP_P_MIN, &pMin);
            if (pMax != INT32_MAX || pMin != INT32_MIN) {
                qp->m.values[ix++] = {P_FRAME, pMin, pMax};
            }

            int32_t bMax = INT32_MAX;
            int32_t bMin = INT32_MIN;
            (void) sdkParams->findInt32(KEY_VIDEO_QP_B_MAX, &bMax);
            (void) sdkParams->findInt32(KEY_VIDEO_QP_B_MIN, &bMin);
            if (bMax != INT32_MAX || bMin != INT32_MIN) {
                qp->m.values[ix++] = {B_FRAME, bMin, bMax};
            }

            // adjust to reflect actual use.
            qp->setFlexCount(ix);

            configUpdate.push_back(std::move(qp));
        }

        err = config->setParameters(comp, configUpdate, C2_DONT_BLOCK);
        if (err != OK) {
            ALOGW("failed to configure c2 params");
+0 −13
Original line number Diff line number Diff line
@@ -729,19 +729,6 @@ void CCodecConfig::initializeStandardParams() {
            return C2Value();
        }));

    add(ConfigMapper(KEY_VIDEO_QP_I_MAX, C2_PARAMKEY_QUANTIZATION, "i-max")
        .limitTo(D::VIDEO & D::ENCODER));
    add(ConfigMapper(KEY_VIDEO_QP_I_MIN, C2_PARAMKEY_QUANTIZATION, "i-min")
        .limitTo(D::VIDEO & D::ENCODER));
    add(ConfigMapper(KEY_VIDEO_QP_P_MAX, C2_PARAMKEY_QUANTIZATION, "p-max")
        .limitTo(D::VIDEO & D::ENCODER));
    add(ConfigMapper(KEY_VIDEO_QP_P_MIN, C2_PARAMKEY_QUANTIZATION, "p-min")
        .limitTo(D::VIDEO & D::ENCODER));
    add(ConfigMapper(KEY_VIDEO_QP_B_MAX, C2_PARAMKEY_QUANTIZATION, "b-max")
        .limitTo(D::VIDEO & D::ENCODER));
    add(ConfigMapper(KEY_VIDEO_QP_B_MIN, C2_PARAMKEY_QUANTIZATION, "b-min")
        .limitTo(D::VIDEO & D::ENCODER));

    // convert to dBFS and add default
    add(ConfigMapper(KEY_AAC_DRC_TARGET_REFERENCE_LEVEL, C2_PARAMKEY_DRC_TARGET_REFERENCE_LEVEL, "value")
        .limitTo(D::AUDIO & D::DECODER & (D::CONFIG | D::PARAM | D::READ))