Pushed to Release_3.5 On Fri, Dec 11, 2020 at 7:59 PM Niranjan Bala <niran...@multicorewareinc.com> wrote:
> > From 775cdc266297f390dab0256a5efa60c3781a3b0d Mon Sep 17 00:00:00 2001 > From: Niranjan Kumar <niran...@multicorewareinc.com> > Date: Wed, 21 Oct 2020 19:18:14 +0530 > Subject: [PATCH] Add: Forward and Backward masking > > Enables scenecut-aware-qp in a specified direction > 0 - Disabled > 1 - Forward masking > 2 - Backward masking > 3 - Bi-directional masking > --- > doc/reST/cli.rst | 95 +++++++++++++++++++++--------- > source/CMakeLists.txt | 2 +- > source/common/param.cpp | 90 ++++++++++++++++++++++------ > source/encoder/encoder.cpp | 8 +-- > source/encoder/ratecontrol.cpp | 68 +++++++++++++++------ > source/encoder/ratecontrol.h | 3 +- > source/test/rate-control-tests.txt | 4 +- > source/x265.h | 32 +++++++--- > source/x265cli.cpp | 10 ++-- > source/x265cli.h | 7 +-- > 10 files changed, 229 insertions(+), 90 deletions(-) > > diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst > index 1a1de9f50..e6acc7785 100755 > --- a/doc/reST/cli.rst > +++ b/doc/reST/cli.rst > @@ -1963,37 +1963,76 @@ Quality, rate control and rate distortion options > > **CLI ONLY** > > -.. option:: --scenecut-aware-qp, --no-scenecut-aware-qp > - > - It reduces the bits spent on the inter-frames within the > :option:`--scenecut-window` > - before and after a scenecut by increasing their QP in ratecontrol > pass2 algorithm > - without any deterioration in visual quality. If a scenecut falls > within the window, > - the QP of the inter-frames after this scenecut will not be modified. > - :option:`--scenecut-aware-qp` works only with --pass 2. Default > disabled. > - > -.. option:: --scenecut-window <integer> > +.. option:: --scenecut-aware-qp <integer> > > - The duration(in milliseconds) for which there is a reduction in the > bits spent > - on the inter-frames after a scenecut by increasing their QP, when > - :option:`--scenecut-aware-qp` is enabled. Default 500ms. > - > - **Range of values:** 0 to 1000 > - > -.. option:: --qp-delta-ref <double> > - > - The offset by which QP is incremented for inter-frames > - when :option:`--scenecut-aware-qp` is enabled. Default 5. > - > - **Range of values:** 0 to 10 > - > -.. option:: --qp-delta-nonref <double> > + It reduces the bits spent on the inter-frames within the scenecut window > + before and after a scenecut by increasing their QP in ratecontrol pass2 > algorithm > + without any deterioration in visual quality. If a scenecut falls within > the window, > + the QP of the inter-frames after this scenecut will not be modified. > + :option:`--scenecut-aware-qp` works only with --pass 2. Default 0. > > - The offset by which QP is incremented for non-referenced > - inter-frames when :option:`--scenecut-aware-qp` is enabled. > - The offset is computed from :option:`--qp-delta-ref` when it > - is not explicitly specified. > + +-------+---------------------------------------------------------------+ > + | Mode | Description | > + +=======+===============================================================+ > + | 0 | Disabled. | > + +-------+---------------------------------------------------------------+ > + | 1 | Forward masking. | > + | | Applies QP modification for frames after the scenecut. | > + +-------+---------------------------------------------------------------+ > + | 2 | Backward masking. | > + | | Applies QP modification for frames before the scenecut. | > + +-------+---------------------------------------------------------------+ > + | 3 | Bi-directional masking. | > + | | Applies QP modification for frames before and after | > + | | the scenecut. | > + +-------+---------------------------------------------------------------+ > > - **Range of values:** 0 to 10 > +.. option:: --masking-strength <string> > + > + Comma separated list of values which specifies the duration and offset > + for the QP increment for inter-frames when :option:`--scenecut-aware-qp` > + is enabled. > + > + When :option:`--scenecut-aware-qp` is:: > + * 1 (Forward masking): > + --masking-strength <fwdWindow,fwdRefQPDelta,fwdNonRefQPDelta> > + * 2 (Backward masking): > + --masking-strength <bwdWindow,bwdRefQPDelta,bwdNonRefQPDelta> > + * 3 (Bi-directional masking): > + --masking-strength > <fwdWindow,fwdRefQPDelta,fwdNonRefQPDelta,bwdWindow,bwdRefQPDelta,bwdNonRefQPDelta> > + > + > +-----------------+---------------------------------------------------------------+ > + | Parameter | Description > | > + > +=================+===============================================================+ > + | fwdWindow | The duration(in milliseconds) for which there is a > reduction | > + | | in the bits spent on the inter-frames after a > scenecut by | > + | | increasing their QP. Default 500ms. > | > + | | **Range of values:** 0 to 1000 > | > + > +-----------------+---------------------------------------------------------------+ > + | fwdRefQPDelta | The offset by which QP is incremented for > inter-frames | > + | | after a scenecut. Default 5. > | > + | | **Range of values:** 0 to 10 > | > + > +-----------------+---------------------------------------------------------------+ > + | fwdNonRefQPDelta| The offset by which QP is incremented for > non-referenced | > + | | inter-frames after a scenecut. The offset is > computed from | > + | | fwdRefQPDelta when it is not explicitly specified. > | > + | | **Range of values:** 0 to 10 > | > + > +-----------------+---------------------------------------------------------------+ > + | bwdWindow | The duration(in milliseconds) for which there is a > reduction | > + | | in the bits spent on the inter-frames before a > scenecut by | > + | | increasing their QP. Default 100ms. > | > + | | **Range of values:** 0 to 1000 > | > + > +-----------------+---------------------------------------------------------------+ > + | bwdRefQPDelta | The offset by which QP is incremented for > inter-frames | > + | | before a scenecut. The offset is computed from > | > + | | fwdRefQPDelta when it is not explicitly specified. > | > + | | **Range of values:** 0 to 10 > | > + > +-----------------+---------------------------------------------------------------+ > + | bwdNonRefQPDelta| The offset by which QP is incremented for > non-referenced | > + | | inter-frames before a scenecut. The offset is > computed from | > + | | bwdRefQPDelta when it is not explicitly specified. > | > + | | **Range of values:** 0 to 10 > | > + > +-----------------+---------------------------------------------------------------+ > > .. option:: --vbv-live-multi-pass, --no-vbv-live-multi-pass > > diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt > index 67e737512..48ca4af7c 100755 > --- a/source/CMakeLists.txt > +++ b/source/CMakeLists.txt > @@ -29,7 +29,7 @@ option(NATIVE_BUILD "Target the build CPU" OFF) > option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF) > mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD) > # X265_BUILD must be incremented each time the public API is changed > -set(X265_BUILD 198) > +set(X265_BUILD 199) > configure_file("${PROJECT_SOURCE_DIR}/x265.def.in" > "${PROJECT_BINARY_DIR}/x265.def") > configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in" > diff --git a/source/common/param.cpp b/source/common/param.cpp > index 47a7a7c47..7a9be18c3 100755 > --- a/source/common/param.cpp > +++ b/source/common/param.cpp > @@ -179,9 +179,12 @@ void x265_param_default(x265_param* param) > param->bEnableHRDConcatFlag = 0; > param->bEnableFades = 0; > param->bEnableSceneCutAwareQp = 0; > - param->scenecutWindow = 500; > - param->refQpDelta = 5; > - param->nonRefQpDelta = param->refQpDelta + (SLICE_TYPE_DELTA * > param->refQpDelta); > + param->fwdScenecutWindow = 500; > + param->fwdRefQpDelta = 5; > + param->fwdNonRefQpDelta = param->fwdRefQpDelta + (SLICE_TYPE_DELTA * > param->fwdRefQpDelta); > + param->bwdScenecutWindow = 100; > + param->bwdRefQpDelta = -1; > + param->bwdNonRefQpDelta = -1; > > /* Intra Coding Tools */ > param->bEnableConstrainedIntra = 0; > @@ -1344,10 +1347,51 @@ int x265_param_parse(x265_param* p, const char* > name, const char* value) > p->selectiveSAO = atoi(value); > } > OPT("fades") p->bEnableFades = atobool(value); > - OPT("scenecut-aware-qp") p->bEnableSceneCutAwareQp = > atobool(value); > - OPT("scenecut-window") p->scenecutWindow = atoi(value); > - OPT("qp-delta-ref") p->refQpDelta = atoi(value); > - OPT("qp-delta-nonref") p->nonRefQpDelta = atoi(value); > + OPT("scenecut-aware-qp") p->bEnableSceneCutAwareQp = atoi(value); > + OPT("masking-strength") > + { > + int window1; > + double refQpDelta1, nonRefQpDelta1; > + > + if (p->bEnableSceneCutAwareQp == FORWARD) > + { > + sscanf(value, "%d,%lf,%lf", &window1, &refQpDelta1, > &nonRefQpDelta1); > + if (window1 > 0) > + p->fwdScenecutWindow = window1; > + if (refQpDelta1 > 0) > + p->fwdRefQpDelta = refQpDelta1; > + if (nonRefQpDelta1 > 0) > + p->fwdNonRefQpDelta = nonRefQpDelta1; > + } > + else if (p->bEnableSceneCutAwareQp == BACKWARD) > + { > + sscanf(value, "%d,%lf,%lf", &window1, &refQpDelta1, > &nonRefQpDelta1); > + if (window1 > 0) > + p->bwdScenecutWindow = window1; > + if (refQpDelta1 > 0) > + p->bwdRefQpDelta = refQpDelta1; > + if (nonRefQpDelta1 > 0) > + p->bwdNonRefQpDelta = nonRefQpDelta1; > + } > + else if (p->bEnableSceneCutAwareQp == BI_DIRECTIONAL) > + { > + int window2; > + double refQpDelta2, nonRefQpDelta2; > + sscanf(value, "%d,%lf,%lf,%d,%lf,%lf", &window1, > &refQpDelta1, &nonRefQpDelta1, &window2, &refQpDelta2, &nonRefQpDelta2); > + if (window1 > 0) > + p->fwdScenecutWindow = window1; > + if (refQpDelta1 > 0) > + p->fwdRefQpDelta = refQpDelta1; > + if (nonRefQpDelta1 > 0) > + p->fwdNonRefQpDelta = nonRefQpDelta1; > + if (window2 > 0) > + p->bwdScenecutWindow = window2; > + if (refQpDelta2 > 0) > + p->bwdRefQpDelta = refQpDelta2; > + if (nonRefQpDelta2 > 0) > + p->bwdNonRefQpDelta = nonRefQpDelta2; > + } > + } > OPT("field") p->bField = atobool( value ); > OPT("cll") p->bEmitCLL = atobool(value); > OPT("frame-dup") p->bEnableFrameDuplication = atobool(value); > @@ -1787,12 +1831,19 @@ int x265_check_params(x265_param* param) > } > else > { > - CHECK(param->scenecutWindow < 0 || param->scenecutWindow > > 1000, > - "Invalid scenecut Window duration. Value must be between 0 > and 1000(inclusive)"); > - CHECK(param->refQpDelta < 0 || param->refQpDelta > 10, > - "Invalid refQpDelta value. Value must be between 0 and 10 > (inclusive)"); > - CHECK(param->nonRefQpDelta < 0 || param->nonRefQpDelta > 10, > - "Invalid nonRefQpDelta value. Value must be between 0 and 10 > (inclusive)"); > + CHECK(param->fwdScenecutWindow < 0 || > param->fwdScenecutWindow > 1000, > + "Invalid forward scenecut Window duration. Value must be > between 0 and 1000(inclusive)"); > + CHECK(param->fwdRefQpDelta < 0 || param->fwdRefQpDelta > 10, > + "Invalid fwdRefQpDelta value. Value must be between 0 and 10 > (inclusive)"); > + CHECK(param->fwdNonRefQpDelta < 0 || param->fwdNonRefQpDelta > > 10, > + "Invalid fwdNonRefQpDelta value. Value must be between 0 and > 10 (inclusive)"); > + > + CHECK(param->bwdScenecutWindow < 0 || > param->bwdScenecutWindow > 1000, > + "Invalid backward scenecut Window duration. Value must be > between 0 and 1000(inclusive)"); > + CHECK(param->bwdRefQpDelta < -1 || param->bwdRefQpDelta > 10, > + "Invalid bwdRefQpDelta value. Value must be between 0 and > 10 (inclusive)"); > + CHECK(param->bwdNonRefQpDelta < -1 || param->bwdNonRefQpDelta > > 10, > + "Invalid bwdNonRefQpDelta value. Value must be between 0 > and 10 (inclusive)"); > } > } > if (param->bEnableHME) > @@ -2252,9 +2303,9 @@ char *x265_param2string(x265_param* p, int padx, int > pady) > BOOL(p->bEnableSvtHevc, "svt"); > BOOL(p->bField, "field"); > s += sprintf(s, " qp-adaptation-range=%.2f", p->rc.qpAdaptationRange); > - BOOL(p->bEnableSceneCutAwareQp, "scenecut-aware-qp"); > + s += sprintf(s, " scenecut-aware-qp=%d", p->bEnableSceneCutAwareQp); > if (p->bEnableSceneCutAwareQp) > - s += sprintf(s, " scenecut-window=%d qp-delta-ref=%f > qp-delta-nonref=%f", p->scenecutWindow, p->refQpDelta, p->nonRefQpDelta); > + s += sprintf(s, " fwd-scenecut-window=%d fwd-ref-qp-delta=%f > fwd-nonref-qp-delta=%f bwd-scenecut-window=%d bwd-ref-qp-delta=%f > bwd-nonref-qp-delta=%f", p->fwdScenecutWindow, p->fwdRefQpDelta, > p->fwdNonRefQpDelta, p->bwdScenecutWindow, p->bwdRefQpDelta, > p->bwdNonRefQpDelta); > s += sprintf(s, "conformance-window-offsets right=%d bottom=%d", > p->confWinRightOffset, p->confWinBottomOffset); > s += sprintf(s, " decoder-max-rate=%d", p->decoderVbvMaxRate); > BOOL(p->bliveVBV2pass, "vbv-live-multi-pass"); > @@ -2608,9 +2659,12 @@ void x265_copy_params(x265_param* dst, x265_param* > src) > dst->bEnableSvtHevc = src->bEnableSvtHevc; > dst->bEnableFades = src->bEnableFades; > dst->bEnableSceneCutAwareQp = src->bEnableSceneCutAwareQp; > - dst->scenecutWindow = src->scenecutWindow; > - dst->refQpDelta = src->refQpDelta; > - dst->nonRefQpDelta = src->nonRefQpDelta; > + dst->fwdScenecutWindow = src->fwdScenecutWindow; > + dst->fwdRefQpDelta = src->fwdRefQpDelta; > + dst->fwdNonRefQpDelta = src->fwdNonRefQpDelta; > + dst->bwdScenecutWindow = src->bwdScenecutWindow; > + dst->bwdRefQpDelta = src->bwdRefQpDelta; > + dst->bwdNonRefQpDelta = src->bwdNonRefQpDelta; > dst->bField = src->bField; > > dst->confWinRightOffset = src->confWinRightOffset; > diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp > index 1f710e1ce..18c3b6788 100644 > --- a/source/encoder/encoder.cpp > +++ b/source/encoder/encoder.cpp > @@ -1810,13 +1810,13 @@ int Encoder::encode(const x265_picture* pic_in, > x265_picture* pic_out) > inFrame->m_lowres.m_bIsHardScenecut = isHardSC; > } > > - if (m_param->bEnableSceneCutAwareQp && m_param->rc.bStatRead) > + if ((m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL || > m_param->bEnableSceneCutAwareQp == BACKWARD) && m_param->rc.bStatRead) > { > RateControlEntry * rcEntry = NULL; > rcEntry = &(m_rateControl->m_rce2Pass[inFrame->m_poc]); > if(rcEntry->scenecut) > { > - int backwardWindow = X265_MIN(int((p->fpsNum / > p->fpsDenom) / 10), p->lookaheadDepth); > + int backwardWindow = > X265_MIN(int((m_param->bwdScenecutWindow / 1000.0) * (m_param->fpsNum / > m_param->fpsDenom)), p->lookaheadDepth); > for (int i = 1; i <= backwardWindow; i++) > { > int frameNum = inFrame->m_poc - i; > @@ -2242,7 +2242,7 @@ int Encoder::encode(const x265_picture* pic_in, > x265_picture* pic_out) > frameEnc = m_lookahead->getDecidedPicture(); > if (frameEnc && !pass && (!m_param->chunkEnd || > (m_encodedFrameNum < m_param->chunkEnd))) > { > - if (m_param->bEnableSceneCutAwareQp && m_param->rc.bStatRead) > + if ((m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL || > m_param->bEnableSceneCutAwareQp == FORWARD) && m_param->rc.bStatRead) > { > RateControlEntry * rcEntry; > rcEntry = &(m_rateControl->m_rce2Pass[frameEnc->m_poc]); > @@ -2253,7 +2253,7 @@ int Encoder::encode(const x265_picture* pic_in, > x265_picture* pic_out) > m_rateControl->m_lastScenecut = frameEnc->m_poc; > else > { > - int maxWindowSize = int((m_param->scenecutWindow > / 1000.0) * (m_param->fpsNum / m_param->fpsDenom) + 0.5); > + int maxWindowSize = > int((m_param->fwdScenecutWindow / 1000.0) * (m_param->fpsNum / > m_param->fpsDenom) + 0.5); > if (frameEnc->m_poc > > (m_rateControl->m_lastScenecut + maxWindowSize)) > m_rateControl->m_lastScenecut = > frameEnc->m_poc; > } > diff --git a/source/encoder/ratecontrol.cpp > b/source/encoder/ratecontrol.cpp > index 4e7d52419..554acfe38 100644 > --- a/source/encoder/ratecontrol.cpp > +++ b/source/encoder/ratecontrol.cpp > @@ -1858,7 +1858,10 @@ double RateControl::rateEstimateQscale(Frame* > curFrame, RateControlEntry *rce) > { > double lqmin = m_lmin[m_sliceType]; > double lqmax = m_lmax[m_sliceType]; > - qScale = scenecutAwareMasking(curFrame, qScale); > + if (m_param->bEnableSceneCutAwareQp == FORWARD || > m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL) > + qScale = forwardMasking(curFrame, qScale); > + else if (m_param->bEnableSceneCutAwareQp == BACKWARD || > m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL) > + qScale = backwardMasking(curFrame, qScale); > qScale = x265_clip3(lqmin, lqmax, qScale); > q = x265_qScale2qp(qScale); > rce->qpNoVbv = q; > @@ -1981,7 +1984,12 @@ double RateControl::rateEstimateQscale(Frame* > curFrame, RateControlEntry *rce) > { > double qmin = m_lmin[m_sliceType]; > double qmax = m_lmax[m_sliceType]; > - q = scenecutAwareMasking(curFrame, q); > + > + if (m_param->bEnableSceneCutAwareQp == FORWARD || > m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL) > + q = forwardMasking(curFrame, q); > + else if (m_param->bEnableSceneCutAwareQp == BACKWARD || > m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL) > + q = backwardMasking(curFrame, q); > + > q = x265_clip3(qmin, qmax, q); > rce->qpNoVbv = x265_qScale2qp(q); > } > @@ -2145,7 +2153,12 @@ double RateControl::rateEstimateQscale(Frame* > curFrame, RateControlEntry *rce) > { > double qmin = m_lmin[m_sliceType]; > double qmax = m_lmax[m_sliceType]; > - q = scenecutAwareMasking(curFrame, q); > + > + if (m_param->bEnableSceneCutAwareQp == FORWARD || > m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL) > + q = forwardMasking(curFrame, q); > + else if (m_param->bEnableSceneCutAwareQp == BACKWARD || > m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL) > + q = backwardMasking(curFrame, q); > + > q = x265_clip3(qmin, qmax, q); > rce->qpNoVbv = x265_qScale2qp(q); > } > @@ -3168,18 +3181,20 @@ void RateControl::splitbUsed(char bused[], > RateControlEntry *rce) > } > } > > -double RateControl::scenecutAwareMasking(Frame* curFrame, double q) > +double RateControl::forwardMasking(Frame* curFrame, double q) > { > double qp = x265_qScale2qp(q); > - uint32_t maxWindowSize = uint32_t((m_param->scenecutWindow / 1000.0) > * (m_param->fpsNum / m_param->fpsDenom) + 0.5); > + uint32_t maxWindowSize = uint32_t((m_param->fwdScenecutWindow / > 1000.0) * (m_param->fpsNum / m_param->fpsDenom) + 0.5); > uint32_t windowSize = maxWindowSize / 3; > int lastScenecut = m_top->m_rateControl->m_lastScenecut; > int lastIFrame = m_top->m_rateControl->m_lastScenecutAwareIFrame; > - double refQpDelta = double(m_param->refQpDelta); > - double nonRefQpDelta = double(m_param->nonRefQpDelta); > - double sliceTypeDelta = SLICE_TYPE_DELTA * refQpDelta; > - double window2Delta = WINDOW2_DELTA * refQpDelta; > - double window3Delta = WINDOW3_DELTA * refQpDelta; > + double fwdRefQpDelta = double(m_param->fwdRefQpDelta); > + double fwdNonRefQpDelta = double(m_param->fwdNonRefQpDelta); > + double bwdRefQpDelta = double(m_param->bwdRefQpDelta); > + double bwdNonRefQpDelta = double(m_param->bwdNonRefQpDelta); > + double sliceTypeDelta = SLICE_TYPE_DELTA * fwdRefQpDelta; > + double window2Delta = WINDOW2_DELTA * fwdRefQpDelta; > + double window3Delta = WINDOW3_DELTA * fwdRefQpDelta; > > if (curFrame->m_poc > lastScenecut && curFrame->m_poc <= > (lastScenecut + int(maxWindowSize))) > curFrame->m_isInsideWindow = FORWARD_WINDOW; > @@ -3194,7 +3209,7 @@ double RateControl::scenecutAwareMasking(Frame* > curFrame, double q) > if (!(lastIFrame > lastScenecut && lastIFrame <= > (lastScenecut + int(maxWindowSize)) > && curFrame->m_poc >= lastIFrame)) > { > - qp += refQpDelta - sliceTypeDelta; > + qp += fwdRefQpDelta - sliceTypeDelta; > if (((curFrame->m_poc) > (lastScenecut + > int(windowSize))) && ((curFrame->m_poc) <= (lastScenecut + 2 * > int(windowSize)))) > qp -= window2Delta; > else if (curFrame->m_poc > lastScenecut + 2 * > int(windowSize)) > @@ -3206,7 +3221,7 @@ double RateControl::scenecutAwareMasking(Frame* > curFrame, double q) > if (!(lastIFrame > lastScenecut && lastIFrame <= > (lastScenecut + int(maxWindowSize)) > && curFrame->m_poc >= lastIFrame)) > { > - qp += refQpDelta; > + qp += fwdRefQpDelta; > if (((curFrame->m_poc) > (lastScenecut + > int(windowSize))) && ((curFrame->m_poc) <= (lastScenecut + 2 * > int(windowSize)))) > qp -= window2Delta; > else if (curFrame->m_poc > lastScenecut + 2 * > int(windowSize)) > @@ -3218,7 +3233,7 @@ double RateControl::scenecutAwareMasking(Frame* > curFrame, double q) > if (!(lastIFrame > lastScenecut && lastIFrame <= > (lastScenecut + int(maxWindowSize)) > && curFrame->m_poc >= lastIFrame)) > { > - qp += nonRefQpDelta; > + qp += fwdNonRefQpDelta; > if (((curFrame->m_poc) > (lastScenecut + > int(windowSize))) && ((curFrame->m_poc) <= (lastScenecut + 2 * > int(windowSize)))) > qp -= window2Delta; > else if (curFrame->m_poc > lastScenecut + 2 * > int(windowSize)) > @@ -3226,16 +3241,31 @@ double RateControl::scenecutAwareMasking(Frame* > curFrame, double q) > } > } > } > - else if (curFrame->m_isInsideWindow == BACKWARD_WINDOW) > + > + return x265_qp2qScale(qp); > +} > +double RateControl::backwardMasking(Frame* curFrame, double q) > +{ > + double qp = x265_qScale2qp(q); > + double fwdRefQpDelta = double(m_param->fwdRefQpDelta); > + double window3Delta = WINDOW3_DELTA * fwdRefQpDelta; > + double bwdRefQpDelta = double(m_param->bwdRefQpDelta); > + double bwdNonRefQpDelta = double(m_param->bwdNonRefQpDelta); > + > + if (curFrame->m_isInsideWindow == BACKWARD_WINDOW) > { > - refQpDelta -= window3Delta; > - nonRefQpDelta -= window3Delta; > + if (bwdRefQpDelta < 0) > + bwdRefQpDelta = fwdRefQpDelta - window3Delta; > + double sliceTypeDelta = SLICE_TYPE_DELTA * bwdRefQpDelta; > + if (bwdNonRefQpDelta < 0) > + bwdNonRefQpDelta = bwdRefQpDelta + sliceTypeDelta; > + > if (curFrame->m_lowres.sliceType == X265_TYPE_P) > - qp += refQpDelta - sliceTypeDelta; > + qp += bwdRefQpDelta - sliceTypeDelta; > else if (curFrame->m_lowres.sliceType == X265_TYPE_BREF) > - qp += refQpDelta; > + qp += bwdRefQpDelta; > else if (curFrame->m_lowres.sliceType == X265_TYPE_B) > - qp += nonRefQpDelta; > + qp += bwdNonRefQpDelta; > } > > return x265_qp2qScale(qp); > diff --git a/source/encoder/ratecontrol.h b/source/encoder/ratecontrol.h > index 809e0c620..41bbddcf2 100644 > --- a/source/encoder/ratecontrol.h > +++ b/source/encoder/ratecontrol.h > @@ -269,7 +269,8 @@ public: > int writeRateControlFrameStats(Frame* curFrame, RateControlEntry* > rce); > bool initPass2(); > > - double scenecutAwareMasking(Frame* curFrame, double q); > + double forwardMasking(Frame* curFrame, double q); > + double backwardMasking(Frame* curFrame, double q); > > protected: > > diff --git a/source/test/rate-control-tests.txt > b/source/test/rate-control-tests.txt > index eed92f809..6c8f10cb6 100644 > --- a/source/test/rate-control-tests.txt > +++ b/source/test/rate-control-tests.txt > @@ -44,8 +44,8 @@ CrowdRun_1920x1080_50_10bit_422.yuv,--preset superfast > --bitrate 2500 --pass 1 - > RaceHorses_416x240_30_10bit.yuv,--preset medium --crf 26 --vbv-maxrate > 1000 --vbv-bufsize 1000 --pass 1::--preset fast --bitrate 1000 > --vbv-maxrate 1000 --vbv-bufsize 700 --pass 3 -F4::--preset slow --bitrate > 500 --vbv-maxrate 500 --vbv-bufsize 700 --pass 2 -F4 > sita_1920x1080_30.yuv, --preset ultrafast --crf 20 --no-cutree --keyint > 50 --min-keyint 50 --no-open-gop --pass 1 --vbv-bufsize 7000 --vbv-maxrate > 5000:: --preset ultrafast --crf 20 --no-cutree --keyint 50 --min-keyint 50 > --no-open-gop --pass 2 --vbv-bufsize 7000 --vbv-maxrate 5000 > --repeat-headers > sita_1920x1080_30.yuv, --preset medium --crf 20 --no-cutree --keyint 50 > --min-keyint 50 --no-open-gop --pass 1 --vbv-bufsize 7000 --vbv-maxrate > 5000 --repeat-headers --multi-pass-opt-rps:: --preset medium --crf 20 > --no-cutree --keyint 50 --min-keyint 50 --no-open-gop --pass 2 > --vbv-bufsize 7000 --vbv-maxrate 5000 --repeat-headers --multi-pass-opt-rps > -sintel_trailer_2k_1920x1080_24.yuv,--preset medium --bitrate 6000 > --no-cutree --aq-mode 0 --pass 1::--preset medium --bitrate 6000 > --no-cutree --aq-mode 0 --pass 2 --scenecut-aware-qp > -sintel_trailer_2k_1920x1080_24.yuv,--preset medium --bitrate 6000 > --no-cutree --aq-mode 0 --hist-scenecut --pass 1::--preset medium --bitrate > 6000 --no-cutree --aq-mode 0 --hist-scenecut --pass 2 --scenecut-aware-qp > --qp-delta-nonref 8 > +sintel_trailer_2k_1920x1080_24.yuv,--preset medium --bitrate 6000 > --no-cutree --aq-mode 0 --pass 1::--preset medium --bitrate 6000 > --no-cutree --aq-mode 0 --pass 2 --scenecut-aware-qp 1 > +sintel_trailer_2k_1920x1080_24.yuv,--preset medium --bitrate 6000 > --no-cutree --aq-mode 0 --hist-scenecut --pass 1::--preset medium --bitrate > 6000 --no-cutree --aq-mode 0 --hist-scenecut --pass 2 --scenecut-aware-qp 3 > --masking-strength 300,-1,7,100,2,3 > > # multi-pass rate control and analysis > ducks_take_off_1080p50.y4m,--bitrate 6000 --pass 1 > --multi-pass-opt-analysis --hash 1 --ssim --psnr:: --bitrate 6000 --pass > 2 --multi-pass-opt-analysis --hash 1 --ssim --psnr > diff --git a/source/x265.h b/source/x265.h > index f44040ba7..b064f67c2 100644 > --- a/source/x265.h > +++ b/source/x265.h > @@ -607,6 +607,9 @@ typedef enum > #define X265_ANALYSIS_SAVE 1 > #define X265_ANALYSIS_LOAD 2 > > +#define FORWARD 1 > +#define BACKWARD 2 > +#define BI_DIRECTIONAL 3 > #define SLICE_TYPE_DELTA 0.3 /* The offset decremented or > incremented for P-frames or b-frames respectively*/ > #define BACKWARD_WINDOW 1 /* Scenecut window before a scenecut */ > #define FORWARD_WINDOW 2 /* Scenecut window after a scenecut */ > @@ -1847,21 +1850,24 @@ typedef struct x265_param > Default 1 (Enabled). API only. */ > int bResetZoneConfig; > > - /* It reduces the bits spent on the inter-frames within the > scenecutWindow before and after a scenecut > + /* It reduces the bits spent on the inter-frames within the > scenecutWindow before and / or after a scenecut > * by increasing their QP in ratecontrol pass2 algorithm without any > deterioration in visual quality. > - * Default is disabled. */ > + * 0 - Disabled (default). > + * 1 - Forward masking. > + * 2 - Backward masking. > + * 3 - Bi-directional masking. */ > int bEnableSceneCutAwareQp; > > /* The duration(in milliseconds) for which there is a reduction in > the bits spent on the inter-frames after a scenecut > - * by increasing their QP, when bEnableSceneCutAwareQp is set. > Default is 500ms.*/ > - int scenecutWindow; > + * by increasing their QP, when bEnableSceneCutAwareQp is 1 or 3. > Default is 500ms.*/ > + int fwdScenecutWindow; > > - /* The offset by which QP is incremented for inter-frames when > bEnableSceneCutAwareQp is set. > + /* The offset by which QP is incremented for inter-frames after a > scenecut when bEnableSceneCutAwareQp is 1 or 3. > * Default is +5. */ > - double refQpDelta; > + double fwdRefQpDelta; > > - /* The offset by which QP is incremented for non-referenced > inter-frames when bEnableSceneCutAwareQp is set. */ > - double nonRefQpDelta; > + /* The offset by which QP is incremented for non-referenced > inter-frames after a scenecut when bEnableSceneCutAwareQp is 1 or 3. */ > + double fwdNonRefQpDelta; > > /* A genuine threshold used for histogram based scene cut detection. > * This threshold determines whether a frame is a scenecut or not > @@ -1932,6 +1938,16 @@ typedef struct x265_param > /* Maximum VBV fullness to be maintained. Default 80. Keep the buffer > * at max 80% full */ > double maxVbvFullness; > + > + /* The duration(in milliseconds) for which there is a reduction in > the bits spent on the inter-frames before a scenecut > + * by increasing their QP, when bEnableSceneCutAwareQp is 2 or 3. > Default is 100ms.*/ > + int bwdScenecutWindow; > + > + /* The offset by which QP is incremented for inter-frames before a > scenecut when bEnableSceneCutAwareQp is 2 or 3. */ > + double bwdRefQpDelta; > + > + /* The offset by which QP is incremented for non-referenced > inter-frames before a scenecut when bEnableSceneCutAwareQp is 2 or 3. */ > + double bwdNonRefQpDelta; > } x265_param; > > /* x265_param_alloc: > diff --git a/source/x265cli.cpp b/source/x265cli.cpp > index c28dd7f8c..0f50589c1 100755 > --- a/source/x265cli.cpp > +++ b/source/x265cli.cpp > @@ -177,10 +177,12 @@ namespace X265_NS { > H0(" --no-hist-scenecut Disables histogram based > scene-cut detection using histogram based algorithm.\n"); > H1(" --hist-threshold <0.0..1.0> Luma Edge histogram's > Normalized SAD threshold for histogram based scenecut detection Default > %.2f\n", param->edgeTransitionThreshold); > H0(" --[no-]fades Enable detection and > handling of fade-in regions. Default %s\n", OPT(param->bEnableFades)); > - H1(" --[no-]scenecut-aware-qp Enable increasing QP for > frames inside the scenecut window after scenecut. Default %s\n", > OPT(param->bEnableSceneCutAwareQp)); > - H1(" --scenecut-window <0..1000> QP incremental duration(in > milliseconds) when scenecut-aware-qp is enabled. Default %d\n", > param->scenecutWindow); > - H1(" --qp-delta-ref <0..10> QP offset to increment with > base QP for inter-frames. Default %f\n", param->refQpDelta); > - H1(" --qp-delta-nonref <0..10> QP offset to increment with > base QP for non-referenced inter-frames. Default %f\n", > param->nonRefQpDelta); > + H1(" --scenecut-aware-qp <0..3> Enable increasing QP for > frames inside the scenecut window around scenecut. Default %s\n", > OPT(param->bEnableSceneCutAwareQp)); > + H1(" 0 - Disabled\n"); > + H1(" 1 - Forward masking\n"); > + H1(" 2 - Backward masking\n"); > + H1(" 3 - Bidirectional > masking\n"); > + H1(" --masking-strength <string> Comma separated values which > specifies the duration and offset for the QP increment for inter-frames"); > H0(" --radl <integer> Number of RADL pictures > allowed in front of IDR. Default %d\n", param->radl); > H0(" --intra-refresh Use Periodic Intra Refresh > instead of IDR frames\n"); > H0(" --rc-lookahead <integer> Number of frames for > frame-type lookahead (determines encoder latency) Default %d\n", > param->lookaheadDepth); > diff --git a/source/x265cli.h b/source/x265cli.h > index a24d25435..7a2e0a267 100644 > --- a/source/x265cli.h > +++ b/source/x265cli.h > @@ -148,11 +148,8 @@ static const struct option long_options[] = > { "hist-threshold", required_argument, NULL, 0}, > { "fades", no_argument, NULL, 0 }, > { "no-fades", no_argument, NULL, 0 }, > - { "scenecut-aware-qp", no_argument, NULL, 0 }, > - { "no-scenecut-aware-qp", no_argument, NULL, 0 }, > - { "scenecut-window",required_argument, NULL, 0 }, > - { "qp-delta-ref", required_argument, NULL, 0 }, > - { "qp-delta-nonref",required_argument, NULL, 0 }, > + { "scenecut-aware-qp", required_argument, NULL, 0 }, > + { "masking-strength", required_argument, NULL, 0 }, > { "radl", required_argument, NULL, 0 }, > { "ctu-info", required_argument, NULL, 0 }, > { "intra-refresh", no_argument, NULL, 0 }, > -- > 2.18.0.windows.1 > > -- > > Thanks & Regards > *Niranjan Kumar B* > Video Codec Engineer > Media & AI Analytics > +91 958 511 1449 > <https://multicorewareinc.com/> > _______________________________________________ > x265-devel mailing list > x265-devel@videolan.org > https://mailman.videolan.org/listinfo/x265-devel > -- Regards, *Aruna Matheswaran,* Video Codec Engineer, Media & AI analytics BU,
_______________________________________________ x265-devel mailing list x265-devel@videolan.org https://mailman.videolan.org/listinfo/x265-devel