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

Commit b3e76b60 authored by Ray Essick's avatar Ray Essick
Browse files

Rework how QP bounds are passed, AVC encoder

Pass via an (variable length) set of settings for picture types
instead of the fixed I/P/B types. Also makes it possible to
pass a max without also passing a min.
This is for the AVC software encoder; other codecs will be modified
accordingly.

Bug: 181830609
Test: vq testing, ALOG
Change-Id: I9086c0d83e625a7a815ce2c104352fdac165b927
parent a0ae6979
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;