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

Commit c70268aa authored by Wonsik Kim's avatar Wonsik Kim Committed by Android (Google) Code Review
Browse files

Merge changes Ieab560be,Icb294e1b,Ia664c15b

* changes:
  CCodec: fix C2OMXNode assumption that components are in the same process
  CCodec: Allow bitrate to be not set in CQ mode for video encoders
  C2SoftHEVCEnc: Add support for constant quality encoding
parents e92e7a88 4f3314d2
Loading
Loading
Loading
Loading
+85 −1
Original line number Diff line number Diff line
@@ -93,6 +93,20 @@ class C2SoftHevcEnc::IntfImpl : public C2InterfaceHelper {
                .build());

        // matches limits in codec library
        addParameter(
            DefineParam(mBitrateMode, C2_PARAMKEY_BITRATE_MODE)
                .withDefault(new C2StreamBitrateModeTuning::output(
                        0u, C2Config::BITRATE_VARIABLE))
                .withFields({
                    C2F(mBitrateMode, value).oneOf({
                        C2Config::BITRATE_CONST,
                        C2Config::BITRATE_VARIABLE,
                        C2Config::BITRATE_IGNORE})
                })
                .withSetter(
                    Setter<decltype(*mBitrateMode)>::StrictValueWithNoDeps)
                .build());

        addParameter(
            DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
                .withDefault(new C2StreamBitrateInfo::output(0u, 64000))
@@ -101,6 +115,20 @@ class C2SoftHevcEnc::IntfImpl : public C2InterfaceHelper {
                .build());

        // matches levels allowed within codec library
        addParameter(
                DefineParam(mComplexity, C2_PARAMKEY_COMPLEXITY)
                .withDefault(new C2StreamComplexityTuning::output(0u, 0))
                .withFields({C2F(mComplexity, value).inRange(0, 10)})
                .withSetter(Setter<decltype(*mComplexity)>::NonStrictValueWithNoDeps)
                .build());

        addParameter(
                DefineParam(mQuality, C2_PARAMKEY_QUALITY)
                .withDefault(new C2StreamQualityTuning::output(0u, 80))
                .withFields({C2F(mQuality, value).inRange(0, 100)})
                .withSetter(Setter<decltype(*mQuality)>::NonStrictValueWithNoDeps)
                .build());

        addParameter(
            DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
                .withDefault(new C2StreamProfileLevelInfo::output(
@@ -287,12 +315,21 @@ class C2SoftHevcEnc::IntfImpl : public C2InterfaceHelper {
    std::shared_ptr<C2StreamFrameRateInfo::output> getFrameRate_l() const {
        return mFrameRate;
    }
    std::shared_ptr<C2StreamBitrateModeTuning::output> getBitrateMode_l() const {
        return mBitrateMode;
    }
    std::shared_ptr<C2StreamBitrateInfo::output> getBitrate_l() const {
        return mBitrate;
    }
    std::shared_ptr<C2StreamRequestSyncFrameTuning::output> getRequestSync_l() const {
        return mRequestSync;
    }
    std::shared_ptr<C2StreamComplexityTuning::output> getComplexity_l() const {
        return mComplexity;
    }
    std::shared_ptr<C2StreamQualityTuning::output> getQuality_l() const {
        return mQuality;
    }

   private:
    std::shared_ptr<C2StreamBufferTypeSetting::input> mInputFormat;
@@ -304,6 +341,9 @@ class C2SoftHevcEnc::IntfImpl : public C2InterfaceHelper {
    std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate;
    std::shared_ptr<C2StreamRequestSyncFrameTuning::output> mRequestSync;
    std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
    std::shared_ptr<C2StreamBitrateModeTuning::output> mBitrateMode;
    std::shared_ptr<C2StreamComplexityTuning::output> mComplexity;
    std::shared_ptr<C2StreamQualityTuning::output> mQuality;
    std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
    std::shared_ptr<C2StreamSyncFrameIntervalTuning::output> mSyncFramePeriod;
};
@@ -387,6 +427,19 @@ static void fillEmptyWork(const std::unique_ptr<C2Work>& work) {
    work->workletsProcessed = 1u;
}

static int getQpFromQuality(int quality) {
    int qp;
#define MIN_QP 4
#define MAX_QP 50
    /* Quality: 100 -> Qp : MIN_QP
     * Quality: 0 -> Qp : MAX_QP
     * Qp = ((MIN_QP - MAX_QP) * quality / 100) + MAX_QP;
     */
    qp = ((MIN_QP - MAX_QP) * quality / 100) + MAX_QP;
    qp = std::min(qp, MAX_QP);
    qp = std::max(qp, MIN_QP);
    return qp;
}
c2_status_t C2SoftHevcEnc::initEncParams() {
    mCodecCtx = nullptr;
    mNumCores = std::min(GetCPUCoreCount(), (size_t) CODEC_MAX_CORES);
@@ -416,9 +469,37 @@ c2_status_t C2SoftHevcEnc::initEncParams() {
    mIvVideoColorFormat = IV_YUV_420P;
    mEncParams.s_multi_thrd_prms.i4_max_num_cores = mNumCores;
    mEncParams.s_out_strm_prms.i4_codec_profile = mHevcEncProfile;
    mEncParams.s_config_prms.i4_rate_control_mode = 2;
    mEncParams.s_lap_prms.i4_rc_look_ahead_pics = 0;

    switch (mBitrateMode->value) {
        case C2Config::BITRATE_IGNORE:
            mEncParams.s_config_prms.i4_rate_control_mode = 3;
            mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_frame_qp[0] =
                getQpFromQuality(mQuality->value);
            break;
        case C2Config::BITRATE_CONST:
            mEncParams.s_config_prms.i4_rate_control_mode = 5;
            break;
        case C2Config::BITRATE_VARIABLE:
            [[fallthrough]];
        default:
            mEncParams.s_config_prms.i4_rate_control_mode = 2;
            break;
        break;
    }

    if (mComplexity->value == 10) {
        mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P0;
    } else if (mComplexity->value >= 8) {
        mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P2;
    } else if (mComplexity->value >= 7) {
        mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P3;
    } else if (mComplexity->value >= 5) {
        mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P4;
    } else {
        mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P5;
    }

    return C2_OK;
}

@@ -447,11 +528,14 @@ c2_status_t C2SoftHevcEnc::initEncoder() {
    {
        IntfImpl::Lock lock = mIntf->lock();
        mSize = mIntf->getSize_l();
        mBitrateMode = mIntf->getBitrateMode_l();
        mBitrate = mIntf->getBitrate_l();
        mFrameRate = mIntf->getFrameRate_l();
        mHevcEncProfile = mIntf->getProfile_l();
        mHevcEncLevel = mIntf->getLevel_l();
        mIDRInterval = mIntf->getSyncFramePeriod_l();
        mComplexity = mIntf->getComplexity_l();
        mQuality = mIntf->getQuality_l();
    }

    c2_status_t status = initEncParams();
+3 −0
Original line number Diff line number Diff line
@@ -77,6 +77,9 @@ struct C2SoftHevcEnc : public SimpleC2Component {
    std::shared_ptr<C2StreamPictureSizeInfo::input> mSize;
    std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate;
    std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
    std::shared_ptr<C2StreamBitrateModeTuning::output> mBitrateMode;
    std::shared_ptr<C2StreamComplexityTuning::output> mComplexity;
    std::shared_ptr<C2StreamQualityTuning::output> mQuality;

#ifdef FILE_DUMP_ENABLE
    char mInFile[200];
+17 −7
Original line number Diff line number Diff line
@@ -272,19 +272,14 @@ status_t C2OMXNode::emptyBuffer(
    work->input.buffers.clear();
    if (block) {
        std::shared_ptr<C2Buffer> c2Buffer(
                // TODO: fence
                new Buffer2D(block->share(
                        C2Rect(block->width(), block->height()), ::C2Fence())),
                [buffer, source = getSource()](C2Buffer *ptr) {
                    delete ptr;
                    // TODO: fence
                    (void)source->onInputBufferEmptied(buffer, -1);
                });
                        C2Rect(block->width(), block->height()), ::C2Fence())));
        work->input.buffers.push_back(c2Buffer);
    }
    work->worklets.clear();
    work->worklets.emplace_back(new C2Worklet);
    std::list<std::unique_ptr<C2Work>> items;
    uint64_t index = work->input.ordinal.frameIndex.peeku();
    items.push_back(std::move(work));

    c2_status_t err = comp->queue(&items);
@@ -292,6 +287,7 @@ status_t C2OMXNode::emptyBuffer(
        return UNKNOWN_ERROR;
    }

    (void)mBufferIdsInUse.emplace(index, buffer);
    return OK;
}

@@ -326,4 +322,18 @@ void C2OMXNode::setFrameSize(uint32_t width, uint32_t height) {
    mHeight = height;
}

void C2OMXNode::onInputBufferDone(c2_cntr64_t index) {
    if (!mBufferSource) {
        ALOGD("Buffer source not set (index=%llu)", index.peekull());
        return;
    }
    auto it = mBufferIdsInUse.find(index.peeku());
    if (it == mBufferIdsInUse.end()) {
        ALOGV("Untracked input index %llu (maybe already removed)", index.peekull());
        return;
    }
    (void)mBufferSource->onInputBufferEmptied(it->second, -1);
    (void)mBufferIdsInUse.erase(it);
}

}  // namespace android
+16 −0
Original line number Diff line number Diff line
@@ -75,9 +75,23 @@ struct C2OMXNode : public BnOMXNode {
            OMX_INDEXTYPE *index) override;
    status_t dispatchMessage(const omx_message &msg) override;

    /**
     * Returns underlying IOMXBufferSource object.
     */
    sp<IOMXBufferSource> getSource();

    /**
     * Configure the frame size.
     */
    void setFrameSize(uint32_t width, uint32_t height);

    /**
     * Clean up work item reference.
     *
     * \param index input work index
     */
    void onInputBufferDone(c2_cntr64_t index);

private:
    std::weak_ptr<Codec2Client::Component> mComp;
    sp<IOMXBufferSource> mBufferSource;
@@ -96,6 +110,8 @@ private:
    bool mFirstInputFrame; // true for first input
    c2_cntr64_t mPrevInputTimestamp; // input timestamp for previous frame
    c2_cntr64_t mPrevCodecTimestamp; // adjusted (codec) timestamp for previous frame

    std::map<uint64_t, buffer_id> mBufferIdsInUse;
};

}  // namespace android
+29 −4
Original line number Diff line number Diff line
@@ -370,6 +370,10 @@ public:
        return err;
    }

    void onInputBufferDone(c2_cntr64_t index) override {
        mNode->onInputBufferDone(index);
    }

private:
    sp<BGraphicBufferSource> mSource;
    sp<C2OMXNode> mNode;
@@ -742,11 +746,22 @@ void CCodec::configure(const sp<AMessage> &msg) {
                return BAD_VALUE;
            }
            if ((config->mDomain & Config::IS_ENCODER) && (config->mDomain & Config::IS_VIDEO)) {
                C2Config::bitrate_mode_t mode = C2Config::BITRATE_VARIABLE;
                if (msg->findInt32(KEY_BITRATE_MODE, &i32)) {
                    mode = (C2Config::bitrate_mode_t) i32;
                }
                if (mode == BITRATE_MODE_CQ) {
                    if (!msg->findInt32(KEY_QUALITY, &i32)) {
                        ALOGD("quality is missing, which is required for video encoders in CQ.");
                        return BAD_VALUE;
                    }
                } else {
                    if (!msg->findInt32(KEY_BIT_RATE, &i32)
                            && !msg->findFloat(KEY_BIT_RATE, &flt)) {
                        ALOGD("bitrate is missing, which is required for video encoders.");
                        return BAD_VALUE;
                    }
                }
                if (!msg->findInt32(KEY_I_FRAME_INTERVAL, &i32)
                        && !msg->findFloat(KEY_I_FRAME_INTERVAL, &flt)) {
                    ALOGD("I frame interval is missing, which is required for video encoders.");
@@ -1572,6 +1587,13 @@ void CCodec::onWorkDone(std::list<std::unique_ptr<C2Work>> &workItems) {

void CCodec::onInputBufferDone(uint64_t frameIndex, size_t arrayIndex) {
    mChannel->onInputBufferDone(frameIndex, arrayIndex);
    if (arrayIndex == 0) {
        // We always put no more than one buffer per work, if we use an input surface.
        Mutexed<Config>::Locked config(mConfig);
        if (config->mInputSurface) {
            config->mInputSurface->onInputBufferDone(frameIndex);
        }
    }
}

void CCodec::onMessageReceived(const sp<AMessage> &msg) {
@@ -1704,6 +1726,9 @@ void CCodec::onMessageReceived(const sp<AMessage> &msg) {
                    ++stream;
                }
            }
            if (config->mInputSurface) {
                config->mInputSurface->onInputBufferDone(work->input.ordinal.frameIndex);
            }
            mChannel->onWorkDone(
                    std::move(work), changed ? config->mOutputFormat : nullptr,
                    initData.hasChanged() ? initData.update().get() : nullptr);
Loading