Mercurial > x265
changeset 12512:3f4fb9a2ac68 draft
api: Add option "--fades" to detect and handle fade-in regions
It does the following:
Force I-slice and
Initialize RC history for the brightest frame after fade-in.
author | Pooja Venkatesan <pooja@multicorewareinc.com> |
---|---|
date | Mon, 22 Apr 2019 11:11:35 +0530 |
parents | 35bcf7fb2b30 |
children | 220cdb4328a1 |
files | doc/reST/cli.rst source/CMakeLists.txt source/common/lowres.cpp source/common/lowres.h source/common/param.cpp source/encoder/ratecontrol.cpp source/encoder/ratecontrol.h source/encoder/slicetype.cpp source/encoder/slicetype.h source/test/regression-tests.txt source/x265.h source/x265cli.h |
diffstat | 12 files changed, 90 insertions(+-), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/reST/cli.rst Fri May 17 15:00:30 2019 +0530 +++ b/doc/reST/cli.rst Mon Apr 22 11:11:35 2019 +0530 @@ -1520,6 +1520,10 @@ Slice decision options slicetype decision may change with this option. 2 - flush the slicetype decided frames only. +.. option:: --fades, --no-fades + + Detect and handle fade-in regions. Default disabled. + Quality, rate control and rate distortion options =================================================
--- a/source/CMakeLists.txt Fri May 17 15:00:30 2019 +0530 +++ b/source/CMakeLists.txt Mon Apr 22 11:11:35 2019 +0530 @@ -29,7 +29,7 @@ option(NATIVE_BUILD "Target the build CP 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 173) +set(X265_BUILD 174) configure_file("${PROJECT_SOURCE_DIR}/x265.def.in" "${PROJECT_BINARY_DIR}/x265.def") configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
--- a/source/common/lowres.cpp Fri May 17 15:00:30 2019 +0530 +++ b/source/common/lowres.cpp Mon Apr 22 11:11:35 2019 +0530 @@ -82,7 +82,7 @@ bool Lowres::create(x265_param* param, P if (origPic->m_param->bAQMotion) CHECKED_MALLOC_ZERO(qpAqMotionOffset, double, cuCountFullRes); - if (origPic->m_param->bDynamicRefine) + if (origPic->m_param->bDynamicRefine || origPic->m_param->bEnableFades) CHECKED_MALLOC_ZERO(blockVariance, uint32_t, cuCountFullRes); if (!!param->rc.hevcAq) @@ -217,6 +217,7 @@ void Lowres::init(PicYuv *origPic, int p { bLastMiniGopBFrame = false; bKeyframe = false; // Not a keyframe unless identified by lookahead + bIsFadeEnd = false; frameNum = poc; leadingBframes = 0; indB = 0;
--- a/source/common/lowres.h Fri May 17 15:00:30 2019 +0530 +++ b/source/common/lowres.h Mon Apr 22 11:11:35 2019 +0530 @@ -160,6 +160,7 @@ struct Lowres : public ReferencePlanes bool bScenecut; // Set to false if the frame cannot possibly be part of a real scenecut. bool bKeyframe; bool bLastMiniGopBFrame; + bool bIsFadeEnd; double ipCostRatio; @@ -195,6 +196,7 @@ struct Lowres : public ReferencePlanes uint32_t* blockVariance; uint64_t wp_ssd[3]; // This is different than SSDY, this is sum(pixel^2) - sum(pixel)^2 for entire frame uint64_t wp_sum[3]; + double frameVariance; /* cutree intermediate data */ PicQPAdaptationLayer* pAQLayer;
--- a/source/common/param.cpp Fri May 17 15:00:30 2019 +0530 +++ b/source/common/param.cpp Mon Apr 22 11:11:35 2019 +0530 @@ -172,6 +172,7 @@ void x265_param_default(x265_param* para param->chunkStart = 0; param->chunkEnd = 0; param->bEnableHRDConcatFlag = 0; + param->bEnableFades = 0; /* Intra Coding Tools */ param->bEnableConstrainedIntra = 0; @@ -1265,6 +1266,7 @@ int x265_param_parse(x265_param* p, cons OPT("svt-pred-struct") x265_log(p, X265_LOG_WARNING, "Option %s is SVT-HEVC Encoder specific; Disabling it here \n", name); OPT("svt-fps-in-vps") x265_log(p, X265_LOG_WARNING, "Option %s is SVT-HEVC Encoder specific; Disabling it here \n", name); #endif + OPT("fades") p->bEnableFades = atobool(value); else return X265_PARAM_BAD_NAME; } @@ -2367,6 +2369,7 @@ void x265_copy_params(x265_param* dst, x dst->bEnableHRDConcatFlag = src->bEnableHRDConcatFlag; dst->dolbyProfile = src->dolbyProfile; dst->bEnableSvtHevc = src->bEnableSvtHevc; + dst->bEnableFades = src->bEnableFades; #ifdef SVT_HEVC memcpy(dst->svtHevcParam, src->svtHevcParam, sizeof(EB_H265_ENC_CONFIGURATION));
--- a/source/encoder/ratecontrol.cpp Fri May 17 15:00:30 2019 +0530 +++ b/source/encoder/ratecontrol.cpp Mon Apr 22 11:11:35 2019 +0530 @@ -1262,6 +1262,7 @@ int RateControl::rateControlStart(Frame* } rce->isActive = true; rce->scenecut = false; + rce->isFadeEnd = curFrame->m_lowres.bIsFadeEnd; bool isRefFrameScenecut = m_sliceType!= I_SLICE && m_curSlice->m_refFrameList[0][0]->m_lowres.bScenecut; m_isFirstMiniGop = m_sliceType == I_SLICE ? true : m_isFirstMiniGop; if (curFrame->m_lowres.bScenecut) @@ -1373,6 +1374,8 @@ int RateControl::rateControlStart(Frame* m_numBframesInPattern++; } } + if (rce->isFadeEnd) + m_isPatternPresent = true; } /* For a scenecut that occurs within the mini-gop, enable scene transition * switch until the next mini-gop to ensure a min qp for all the frames within @@ -2097,7 +2100,7 @@ void RateControl::checkAndResetABR(RateC double abrBuffer = 2 * m_rateTolerance * m_bitrate; // Check if current Slice is a scene cut that follows low detailed/blank frames - if (rce->lastSatd > 4 * rce->movingAvgSum || rce->scenecut) + if (rce->lastSatd > 4 * rce->movingAvgSum || rce->scenecut || rce->isFadeEnd) { if (!m_isAbrReset && rce->movingAvgSum > 0 && (m_isPatternPresent || !m_param->bframes)) @@ -2110,7 +2113,7 @@ void RateControl::checkAndResetABR(RateC shrtTermTotalBitsSum += m_encodedBitsWindow[i]; double underflow = (shrtTermTotalBitsSum - shrtTermWantedBits) / abrBuffer; const double epsilon = 0.0001f; - if (underflow < epsilon && !isFrameDone) + if ((underflow < epsilon || rce->isFadeEnd) && !isFrameDone) { init(*m_curSlice->m_sps); m_shortTermCplxSum = rce->lastSatd / (CLIP_DURATION(m_frameDuration) / BASE_FRAME_DURATION);
--- a/source/encoder/ratecontrol.h Fri May 17 15:00:30 2019 +0530 +++ b/source/encoder/ratecontrol.h Mon Apr 22 11:11:35 2019 +0530 @@ -115,6 +115,7 @@ struct RateControlEntry HRDTiming *hrdTiming; int rpsIdx; RPS rpsData; + bool isFadeEnd; }; class RateControl
--- a/source/encoder/slicetype.cpp Fri May 17 15:00:30 2019 +0530 +++ b/source/encoder/slicetype.cpp Mon Apr 22 11:11:35 2019 +0530 @@ -459,17 +459,21 @@ void LookaheadTLD::calcAdaptiveQuantFram } } - if (param->bDynamicRefine) + if (param->bDynamicRefine || param->bEnableFades) { - int blockXY = 0; + uint64_t blockXY = 0, rowVariance = 0; + curFrame->m_lowres.frameVariance = 0; for (int blockY = 0; blockY < maxRow; blockY += loopIncr) { for (int blockX = 0; blockX < maxCol; blockX += loopIncr) { curFrame->m_lowres.blockVariance[blockXY] = acEnergyCu(curFrame, blockX, blockY, param->internalCsp, param->rc.qgSize); + rowVariance += curFrame->m_lowres.blockVariance[blockXY]; blockXY++; } + curFrame->m_lowres.frameVariance += (rowVariance / maxCol); } + curFrame->m_lowres.frameVariance /= maxRow; } } @@ -757,6 +761,9 @@ Lookahead::Lookahead(x265_param *param, m_8x8Width = ((m_param->sourceWidth / 2) + X265_LOWRES_CU_SIZE - 1) >> X265_LOWRES_CU_BITS; m_cuCount = m_8x8Width * m_8x8Height; m_8x8Blocks = m_8x8Width > 2 && m_8x8Height > 2 ? (m_cuCount + 4 - 2 * (m_8x8Width + m_8x8Height)) : m_cuCount; + m_isFadeIn = false; + m_fadeCount = 0; + m_fadeStart = -1; /* Allow the strength to be adjusted via qcompress, since the two concepts * are very similar. */ @@ -1181,7 +1188,6 @@ void PreLookaheadGroup::processTasks(int void Lookahead::slicetypeDecide() { PreLookaheadGroup pre(*this); - Lowres* frames[X265_LOOKAHEAD_MAX + X265_BFRAME_MAX + 4]; Frame* list[X265_BFRAME_MAX + 4]; memset(frames, 0, sizeof(frames)); @@ -1226,6 +1232,54 @@ void Lookahead::slicetypeDecide() pre.waitForExit(); } + if(m_param->bEnableFades) + { + int j, endIndex = 0, length = X265_BFRAME_MAX + 4; + for (j = 0; j < length; j++) + m_frameVariance[j] = -1; + for (j = 0; list[j] != NULL; j++) + m_frameVariance[list[j]->m_poc % length] = list[j]->m_lowres.frameVariance; + for (int k = list[0]->m_poc % length; k <= list[j - 1]->m_poc % length; k++) + { + if (m_frameVariance[k] == -1) + break; + if((k > 0 && m_frameVariance[k] >= m_frameVariance[k - 1]) || + (k == 0 && m_frameVariance[k] >= m_frameVariance[length - 1])) + { + m_isFadeIn = true; + if (m_fadeCount == 0 && m_fadeStart == -1) + { + for(int temp = list[0]->m_poc; temp <= list[j - 1]->m_poc; temp++) + if (k == temp % length) { + m_fadeStart = temp ? temp - 1 : 0; + break; + } + } + m_fadeCount = list[endIndex]->m_poc > m_fadeStart ? list[endIndex]->m_poc - m_fadeStart : 0; + endIndex++; + } + else + { + if (m_isFadeIn && m_fadeCount >= m_param->fpsNum / m_param->fpsDenom) + { + for (int temp = 0; list[temp] != NULL; temp++) + { + if (list[temp]->m_poc == m_fadeStart + (int)m_fadeCount) + { + list[temp]->m_lowres.bIsFadeEnd = true; + break; + } + } + } + m_isFadeIn = false; + m_fadeCount = 0; + m_fadeStart = -1; + } + if (k == length - 1) + k = -1; + } + } + if (m_lastNonB && !m_param->rc.bStatRead && ((m_param->bFrameAdaptive && m_param->bframes) || m_param->rc.cuTree || m_param->scenecutThreshold || @@ -1285,6 +1339,9 @@ void Lookahead::slicetypeDecide() frm.sliceType = m_param->bOpenGOP && m_lastKeyframe >= 0 ? X265_TYPE_I : X265_TYPE_IDR; } } + if (frm.bIsFadeEnd){ + frm.sliceType = m_param->bOpenGOP && m_lastKeyframe >= 0 ? X265_TYPE_I : X265_TYPE_IDR; + } for (int i = 0; i < m_param->rc.zonefileCount; i++) { int curZoneStart = m_param->rc.zones[i].startFrame;
--- a/source/encoder/slicetype.h Fri May 17 15:00:30 2019 +0530 +++ b/source/encoder/slicetype.h Mon Apr 22 11:11:35 2019 +0530 @@ -134,6 +134,10 @@ public: bool m_isSceneTransition; int m_numPools; bool m_extendGopBoundary; + double m_frameVariance[X265_BFRAME_MAX + 4]; + bool m_isFadeIn; + uint64_t m_fadeCount; + int m_fadeStart; Lookahead(x265_param *param, ThreadPool *pool); #if DETAILED_CU_STATS int64_t m_slicetypeDecideElapsedTime;
--- a/source/test/regression-tests.txt Fri May 17 15:00:30 2019 +0530 +++ b/source/test/regression-tests.txt Mon Apr 22 11:11:35 2019 +0530 @@ -151,6 +151,7 @@ Kimono1_1920x1080_24_400.yuv,--preset ve Kimono1_1920x1080_24_400.yuv,--preset placebo --ctu 32 --max-tu-size 8 --limit-tu 2 big_buck_bunny_360p24.y4m, --keyint 60 --min-keyint 40 --gop-lookahead 14 BasketballDrive_1920x1080_50.y4m, --preset medium --no-open-gop --keyint 50 --min-keyint 50 --radl 2 --vbv-maxrate 5000 --vbv-bufsize 5000 +big_buck_bunny_360p24.y4m, --bitrate 500 --fades # Main12 intraCost overflow bug test 720p50_parkrun_ter.y4m,--preset medium
--- a/source/x265.h Fri May 17 15:00:30 2019 +0530 +++ b/source/x265.h Mon Apr 22 11:11:35 2019 +0530 @@ -1771,6 +1771,10 @@ typedef struct x265_param /* SVT-HEVC param structure. For internal use when SVT HEVC encoder is enabled */ void* svtHevcParam; + + /* Detect fade-in regions. Enforces I-slice for the brightest point. + Re-init RC history at that point in ABR mode. Default is disabled. */ + int bEnableFades; } x265_param; /* x265_param_alloc: * Allocates an x265_param instance. The returned param structure is not
--- a/source/x265cli.h Fri May 17 15:00:30 2019 +0530 +++ b/source/x265cli.h Mon Apr 22 11:11:35 2019 +0530 @@ -124,6 +124,8 @@ static const struct option long_options[ { "scenecut", required_argument, NULL, 0 }, { "no-scenecut", no_argument, NULL, 0 }, { "scenecut-bias", required_argument, NULL, 0 }, + { "fades", no_argument, NULL, 0 }, + { "no-fades", no_argument, NULL, 0 }, { "radl", required_argument, NULL, 0 }, { "ctu-info", required_argument, NULL, 0 }, { "intra-refresh", no_argument, NULL, 0 }, @@ -471,6 +473,7 @@ static void showHelp(x265_param *param) H0(" --no-scenecut Disable adaptive I-frame decision\n"); H0(" --scenecut <integer> How aggressively to insert extra I-frames. Default %d\n", param->scenecutThreshold); H1(" --scenecut-bias <0..100.0> Bias for scenecut detection. Default %.2f\n", param->scenecutBias); + H0(" --[no-]fades Enable detection and handling of fade-in regions. Default %s\n", OPT(param->bEnableFades)); 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);