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

Commit a45fad9f authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "C2SoftMpeg4Enc: Add support for levels in mpeg4/h263 encoder" am: 61e0b547 am: 66877705

parents 7558913a 66877705
Loading
Loading
Loading
Loading
+98 −7
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@ constexpr char COMPONENT_NAME[] = "c2.android.h263.encoder";
const char *MEDIA_MIMETYPE_VIDEO = MEDIA_MIMETYPE_VIDEO_H263;
#endif

constexpr float VBV_DELAY = 5.0f;

} // namepsace

class C2SoftMpeg4Enc::IntfImpl : public SimpleInterface<void>::BaseParams {
@@ -131,7 +133,7 @@ class C2SoftMpeg4Enc::IntfImpl : public SimpleInterface<void>::BaseParams {
                            C2Config::LEVEL_MP4V_1,
                            C2Config::LEVEL_MP4V_2})
                })
                .withSetter(ProfileLevelSetter)
                .withSetter(ProfileLevelSetter, mSize, mFrameRate, mBitrate)
                .build());
#else
        addParameter(
@@ -148,7 +150,7 @@ class C2SoftMpeg4Enc::IntfImpl : public SimpleInterface<void>::BaseParams {
                            C2Config::LEVEL_H263_40,
                            C2Config::LEVEL_H263_45})
                })
                .withSetter(ProfileLevelSetter)
                .withSetter(ProfileLevelSetter, mSize, mFrameRate, mBitrate)
                .build());
#endif
    }
@@ -179,7 +181,10 @@ class C2SoftMpeg4Enc::IntfImpl : public SimpleInterface<void>::BaseParams {

    static C2R ProfileLevelSetter(
            bool mayBlock,
            C2P<C2StreamProfileLevelInfo::output> &me) {
            C2P<C2StreamProfileLevelInfo::output> &me,
            const C2P<C2StreamPictureSizeInfo::input> &size,
            const C2P<C2StreamFrameRateInfo::output> &frameRate,
            const C2P<C2StreamBitrateInfo::output> &bitrate) {
        (void)mayBlock;
        if (!me.F(me.v.profile).supportsAtAll(me.v.profile)) {
#ifdef MPEG4
@@ -188,11 +193,84 @@ class C2SoftMpeg4Enc::IntfImpl : public SimpleInterface<void>::BaseParams {
            me.set().profile = PROFILE_H263_BASELINE;
#endif
        }
        if (!me.F(me.v.level).supportsAtAll(me.v.level)) {

        struct LevelLimits {
            C2Config::level_t level;
            uint32_t sampleRate;
            uint32_t width;
            uint32_t height;
            uint32_t frameRate;
            uint32_t bitrate;
            uint32_t vbvSize;
        };

        constexpr LevelLimits kLimits[] = {
#ifdef MPEG4
            { LEVEL_MP4V_0, 380160, 176, 144, 15, 64000, 163840 },
            // { LEVEL_MP4V_0B, 380160, 176, 144, 15, 128000, 163840 },
            { LEVEL_MP4V_1, 380160, 176, 144, 30, 64000, 163840 },
            { LEVEL_MP4V_2, 1520640, 352, 288, 30, 128000, 655360 },
#else
            // HRD Buffer Size = (B + BPPmaxKb * 1024 bits)
            // where, (BPPmaxKb * 1024) is maximum number of bits per picture
            // that has been negotiated for use in the bitstream Sec 3.6 of T-Rec-H.263
            // and B = 4 * Rmax / PCF. Rmax is max bit rate and PCF is picture
            // clock frequency
            { LEVEL_H263_10, 380160, 176, 144, 15, 64000, 74077 },
            { LEVEL_H263_45, 380160, 176, 144, 15, 128000, 82619 },
            { LEVEL_H263_20, 1520640, 352, 288, 30, 128000, 279227 },
            { LEVEL_H263_30, 3041280, 352, 288, 30, 384000, 313395 },
            { LEVEL_H263_40, 3041280, 352, 288, 30, 2048000, 535483 },
            // { LEVEL_H263_50, 5068800, 352, 288, 60, 4096000, 808823 },
#endif
        };

        auto mbs = ((size.v.width + 15) / 16) * ((size.v.height + 15) / 16);
        auto sampleRate = mbs * frameRate.v.value * 16 * 16;
        auto vbvSize = bitrate.v.value * VBV_DELAY;

        // Check if the supplied level meets the MB / bitrate requirements. If
        // not, update the level with the lowest level meeting the requirements.
        bool found = false;

        // By default needsUpdate = false in case the supplied level does meet
        // the requirements.
        bool needsUpdate = false;
#ifdef MPEG4
        // For Level 0b, we want to update the level anyway, as library does not
        // seem to accept this value.
        if (me.v.level == LEVEL_MP4V_0B) {
            needsUpdate = true;
        }
#endif
        for (const LevelLimits &limit : kLimits) {
            if (sampleRate <= limit.sampleRate && size.v.width <= limit.width &&
                    vbvSize <= limit.vbvSize && size.v.height <= limit.height &&
                    bitrate.v.value <= limit.bitrate && frameRate.v.value <= limit.frameRate) {
                // This is the lowest level that meets the requirements, and if
                // we haven't seen the supplied level yet, that means we don't
                // need the update.
                if (needsUpdate) {
                    ALOGD("Given level %x does not cover current configuration: "
                          "adjusting to %x", me.v.level, limit.level);
                    me.set().level = limit.level;
                }
                found = true;
                break;
            }
            if (me.v.level == limit.level) {
                // We break out of the loop when the lowest feasible level is
                // found. The fact that we're here means that our level doesn't
                // meet the requirement and needs to be updated.
                needsUpdate = true;
            }
        }
        // If not found, set to the highest supported level.
        if (!found) {
#ifdef MPEG4
            me.set().level = LEVEL_MP4V_2;
#else
            me.set().level = LEVEL_H263_45;
            me.set().level = LEVEL_H263_40;
#endif
        }
        return C2R::Ok();
@@ -210,6 +288,18 @@ class C2SoftMpeg4Enc::IntfImpl : public SimpleInterface<void>::BaseParams {
        return (uint32_t)c2_max(c2_min(period + 0.5, double(UINT32_MAX)), 1.);
    }

    ProfileLevelType getProfileLevel_l() const {
#ifdef MPEG4
        if (mProfileLevel->level == LEVEL_MP4V_0) return SIMPLE_PROFILE_LEVEL0;
        else if (mProfileLevel->level == LEVEL_MP4V_1) return SIMPLE_PROFILE_LEVEL1;
        return SIMPLE_PROFILE_LEVEL2;  // level == LEVEL_MP4V_2
#else
        // library does not export h263 specific levels. No way to map C2 enums to
        // library specific constants. Return max supported level.
        return CORE_PROFILE_LEVEL2;
#endif
    }

   private:
    std::shared_ptr<C2StreamUsageTuning::input> mUsage;
    std::shared_ptr<C2StreamPictureSizeInfo::input> mSize;
@@ -325,8 +415,8 @@ c2_status_t C2SoftMpeg4Enc::initEncParams() {
    mEncParams->encHeight[0] = mSize->height;
    mEncParams->encFrameRate[0] = mFrameRate->value + 0.5;
    mEncParams->rcType = VBR_1;
    mEncParams->vbvDelay = 5.0f;
    mEncParams->profile_level = CORE_PROFILE_LEVEL2;
    mEncParams->vbvDelay = VBV_DELAY;
    mEncParams->profile_level = mProfileLevel;
    mEncParams->packetSize = 32;
    mEncParams->rvlcEnable = PV_OFF;
    mEncParams->numLayers = 1;
@@ -367,6 +457,7 @@ c2_status_t C2SoftMpeg4Enc::initEncoder() {
        mSize = mIntf->getSize_l();
        mBitrate = mIntf->getBitrate_l();
        mFrameRate = mIntf->getFrameRate_l();
        mProfileLevel = mIntf->getProfileLevel_l();
    }
    c2_status_t err = initEncParams();
    if (C2_OK != err) {
+1 −0
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ private:
    std::shared_ptr<C2StreamPictureSizeInfo::input> mSize;
    std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate;
    std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
    ProfileLevelType mProfileLevel;

    int64_t  mNumInputFrames;
    MP4EncodingMode mEncodeMode;