Mercurial > x265
changeset 11959:ecba08b10f3a draft
Add support for RADL pictures
author | Aruna Matheswaran <aruna@multicorewareinc.com> |
---|---|
date | Fri, 22 Dec 2017 14:50:08 +0530 |
parents | 95fc0c4f03db |
children | ff02513b92c0 |
files | doc/reST/cli.rst source/CMakeLists.txt source/common/lowres.cpp source/common/lowres.h source/common/param.cpp source/encoder/dpb.cpp source/encoder/encoder.cpp source/encoder/search.cpp source/encoder/slicetype.cpp source/encoder/weightPrediction.cpp source/test/regression-tests.txt source/x265.h source/x265cli.h |
diffstat | 13 files changed, 92 insertions(+-), 37 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/reST/cli.rst Fri Dec 22 15:14:57 2017 +0530 +++ b/doc/reST/cli.rst Fri Dec 22 14:50:08 2017 +0530 @@ -1345,7 +1345,14 @@ Slice decision options This value represents the percentage difference between the inter cost and intra cost of a frame used in scenecut detection. For example, a value of 5 indicates, if the inter cost of a frame is greater than or equal to 95 percent of the intra cost of the frame, - then detect this frame as scenecut. Values between 5 and 15 are recommended. Default 5. + then detect this frame as scenecut. Values between 5 and 15 are recommended. Default 5. + +.. option:: --radl <integer> + + Number of RADL pictures allowed infront of IDR. Requires fixed keyframe interval. + Recommended value is 2-3. Default 0 (disabled). + + **Range of values: Between 0 and `--bframes` .. option:: --ctu-info <0, 1, 2, 4, 6>
--- a/source/CMakeLists.txt Fri Dec 22 15:14:57 2017 +0530 +++ b/source/CMakeLists.txt Fri Dec 22 14:50:08 2017 +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 149) +set(X265_BUILD 150) 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 Dec 22 15:14:57 2017 +0530 +++ b/source/common/lowres.cpp Fri Dec 22 14:50:08 2017 +0530 @@ -89,7 +89,7 @@ bool Lowres::create(PicYuv *origPic, int } } - for (int i = 0; i < bframes + 1; i++) + for (int i = 0; i < bframes + 2; i++) { CHECKED_MALLOC(lowresMvs[0][i], MV, cuCount); CHECKED_MALLOC(lowresMvs[1][i], MV, cuCount); @@ -118,7 +118,7 @@ void Lowres::destroy() } } - for (int i = 0; i < bframes + 1; i++) + for (int i = 0; i < bframes + 2; i++) { X265_FREE(lowresMvs[0][i]); X265_FREE(lowresMvs[1][i]); @@ -152,7 +152,7 @@ void Lowres::init(PicYuv *origPic, int p for (int x = 0; x < bframes + 2; x++) rowSatds[y][x][0] = -1; - for (int i = 0; i < bframes + 1; i++) + for (int i = 0; i < bframes + 2; i++) { lowresMvs[0][i][0].x = 0x7FFF; lowresMvs[1][i][0].x = 0x7FFF;
--- a/source/common/lowres.h Fri Dec 22 15:14:57 2017 +0530 +++ b/source/common/lowres.h Fri Dec 22 14:50:08 2017 +0530 @@ -130,8 +130,8 @@ struct Lowres : public ReferencePlanes int64_t satdCost; uint16_t* lowresCostForRc; uint16_t* lowresCosts[X265_BFRAME_MAX + 2][X265_BFRAME_MAX + 2]; - int32_t* lowresMvCosts[2][X265_BFRAME_MAX + 1]; - MV* lowresMvs[2][X265_BFRAME_MAX + 1]; + int32_t* lowresMvCosts[2][X265_BFRAME_MAX + 2]; + MV* lowresMvs[2][X265_BFRAME_MAX + 2]; uint32_t maxBlocksInRow; uint32_t maxBlocksInCol; uint32_t maxBlocksInRowFullRes;
--- a/source/common/param.cpp Fri Dec 22 15:14:57 2017 +0530 +++ b/source/common/param.cpp Fri Dec 22 14:50:08 2017 +0530 @@ -154,6 +154,7 @@ void x265_param_default(x265_param* para param->lookaheadSlices = 8; param->lookaheadThreads = 0; param->scenecutBias = 5.0; + param->radl = 0; /* Intra Coding Tools */ param->bEnableConstrainedIntra = 0; param->bEnableStrongIntraSmoothing = 1; @@ -1010,6 +1011,7 @@ int x265_param_parse(x265_param* p, cons OPT("gop-lookahead") p->gopLookahead = atoi(value); OPT("analysis-save") p->analysisSave = strdup(value); OPT("analysis-load") p->analysisLoad = strdup(value); + OPT("radl") p->radl = atoi(value); else return X265_PARAM_BAD_NAME; } @@ -1316,6 +1318,8 @@ int x265_check_params(x265_param* param) "scenecutThreshold must be greater than 0"); CHECK(param->scenecutBias < 0 || 100 < param->scenecutBias, "scenecut-bias must be between 0 and 100"); + CHECK(param->radl < 0 || param->radl > param->bframes, + "radl must be between 0 and bframes"); CHECK(param->rdPenalty < 0 || param->rdPenalty > 2, "Valid penalty for 32x32 intra TU in non-I slices. 0:disabled 1:RD-penalty 2:maximum"); CHECK(param->keyframeMax < -1, @@ -1575,6 +1579,7 @@ char *x265_param2string(x265_param* p, i s += sprintf(s, " rc-lookahead=%d", p->lookaheadDepth); s += sprintf(s, " lookahead-slices=%d", p->lookaheadSlices); s += sprintf(s, " scenecut=%d", p->scenecutThreshold); + s += sprintf(s, " radl=%d", p->radl); BOOL(p->bIntraRefresh, "intra-refresh"); s += sprintf(s, " ctu=%d", p->maxCUSize); s += sprintf(s, " min-cu-size=%d", p->minCUSize);
--- a/source/encoder/dpb.cpp Fri Dec 22 15:14:57 2017 +0530 +++ b/source/encoder/dpb.cpp Fri Dec 22 14:50:08 2017 +0530 @@ -181,7 +181,10 @@ void DPB::prepareEncode(Frame *newFrame) // Mark pictures in m_piclist as unreferenced if they are not included in RPS applyReferencePictureSet(&slice->m_rps, pocCurr); - slice->m_numRefIdx[0] = X265_MIN(newFrame->m_param->maxNumReferences, slice->m_rps.numberOfNegativePictures); // Ensuring L0 contains just the -ve POC + if (slice->m_sliceType != I_SLICE) + slice->m_numRefIdx[0] = x265_clip3(1, newFrame->m_param->maxNumReferences, slice->m_rps.numberOfNegativePictures); + else + slice->m_numRefIdx[0] = X265_MIN(newFrame->m_param->maxNumReferences, slice->m_rps.numberOfNegativePictures); // Ensuring L0 contains just the -ve POC slice->m_numRefIdx[1] = X265_MIN(newFrame->m_param->bBPyramid ? 2 : 1, slice->m_rps.numberOfPositivePictures); slice->setRefPicList(m_picList); @@ -230,11 +233,14 @@ void DPB::computeRPS(int curPoc, bool is { if ((iterPic->m_poc != curPoc) && iterPic->m_encData->m_bHasReferences) { - rps->poc[poci] = iterPic->m_poc; - rps->deltaPOC[poci] = rps->poc[poci] - curPoc; - (rps->deltaPOC[poci] < 0) ? numNeg++ : numPos++; - rps->bUsed[poci] = !isRAP; - poci++; + if ((m_lastIDR >= curPoc) || (m_lastIDR <= iterPic->m_poc)) + { + rps->poc[poci] = iterPic->m_poc; + rps->deltaPOC[poci] = rps->poc[poci] - curPoc; + (rps->deltaPOC[poci] < 0) ? numNeg++ : numPos++; + rps->bUsed[poci] = !isRAP; + poci++; + } } iterPic = iterPic->m_next; }
--- a/source/encoder/encoder.cpp Fri Dec 22 15:14:57 2017 +0530 +++ b/source/encoder/encoder.cpp Fri Dec 22 14:50:08 2017 +0530 @@ -3046,6 +3046,12 @@ void Encoder::configure(x265_param *p) p->maxCUDepth = p->maxLog2CUSize - g_log2Size[p->minCUSize]; p->unitSizeDepth = p->maxLog2CUSize - LOG2_UNIT_SIZE; p->num4x4Partitions = (1U << (p->unitSizeDepth << 1)); + + if (p->radl && (p->keyframeMax != p->keyframeMin)) + { + p->radl = 0; + x265_log(p, X265_LOG_WARNING, "Radl requires fixed gop-length (keyint == min-keyint). Disabling radl.\n"); + } } void Encoder::allocAnalysis(x265_analysis_data* analysis)
--- a/source/encoder/search.cpp Fri Dec 22 15:14:57 2017 +0530 +++ b/source/encoder/search.cpp Fri Dec 22 14:50:08 2017 +0530 @@ -1947,7 +1947,7 @@ MV Search::getLowresMV(const CUData& cu, /* poc difference is out of range for lookahead */ return 0; - MV* mvs = m_frame->m_lowres.lowresMvs[list][diffPoc - 1]; + MV* mvs = m_frame->m_lowres.lowresMvs[list][diffPoc]; if (mvs[0].x == 0x7FFF) /* this motion search was not estimated by lookahead */ return 0;
--- a/source/encoder/slicetype.cpp Fri Dec 22 15:14:57 2017 +0530 +++ b/source/encoder/slicetype.cpp Fri Dec 22 14:50:08 2017 +0530 @@ -879,7 +879,7 @@ void Lookahead::getEstimatedPictureCost( Slice *slice = curFrame->m_encData->m_slice; int p0 = 0, p1, b; int poc = slice->m_poc; - int l0poc = slice->m_refPOCList[0][0]; + int l0poc = slice->m_rps.numberOfNegativePictures ? slice->m_refPOCList[0][0] : -1; int l1poc = slice->m_refPOCList[1][0]; switch (slice->m_sliceType) @@ -896,11 +896,22 @@ void Lookahead::getEstimatedPictureCost( break; case B_SLICE: - b = poc - l0poc; - p1 = b + l1poc - poc; - frames[p0] = &slice->m_refFrameList[0][0]->m_lowres; - frames[b] = &curFrame->m_lowres; - frames[p1] = &slice->m_refFrameList[1][0]->m_lowres; + if (l0poc >= 0) + { + b = poc - l0poc; + p1 = b + l1poc - poc; + frames[p0] = &slice->m_refFrameList[0][0]->m_lowres; + frames[b] = &curFrame->m_lowres; + frames[p1] = &slice->m_refFrameList[1][0]->m_lowres; + } + else + { + p0 = b = 0; + p1 = b + l1poc - poc; + frames[p0] = frames[b] = &curFrame->m_lowres; + frames[p1] = &slice->m_refFrameList[1][0]->m_lowres; + } + break; default: @@ -1120,12 +1131,20 @@ void Lookahead::slicetypeDecide() /* Closed GOP */ m_lastKeyframe = frm.frameNum; frm.bKeyframe = true; - if (bframes > 0) + if (bframes > 0 && !m_param->radl) { list[bframes - 1]->m_lowres.sliceType = X265_TYPE_P; bframes--; } } + if (m_param->radl && !m_param->bOpenGOP && list[bframes + 1]) + { + if ((frm.frameNum - m_lastKeyframe) > (m_param->keyframeMax - m_param->radl - 1) && (frm.frameNum - m_lastKeyframe) < m_param->keyframeMax) + frm.sliceType = X265_TYPE_B; + if ((frm.frameNum - m_lastKeyframe) == (m_param->keyframeMax - m_param->radl - 1)) + frm.sliceType = X265_TYPE_P; + } + if (bframes == m_param->bframes || !list[bframes + 1]) { if (IS_X265_TYPE_B(frm.sliceType)) @@ -1175,8 +1194,13 @@ void Lookahead::slicetypeDecide() if (bframes) { p0 = 0; // last nonb + bool isp0available = frames[bframes + 1]->sliceType == X265_TYPE_IDR ? false : true; + for (b = 1; b <= bframes; b++) { + if (!isp0available) + p0 = b; + if (frames[b]->sliceType == X265_TYPE_B) for (p1 = b; frames[p1]->sliceType == X265_TYPE_B; p1++) ; // find new nonb or bref @@ -1186,7 +1210,10 @@ void Lookahead::slicetypeDecide() estGroup.singleCost(p0, p1, b); if (frames[b]->sliceType == X265_TYPE_BREF) + { p0 = b; + isp0available = true; + } } } } @@ -1413,12 +1440,12 @@ void Lookahead::slicetypeAnalyse(Lowres continue; /* Skip search if already done */ - if (frames[b]->lowresMvs[0][i - 1][0].x != 0x7FFF) + if (frames[b]->lowresMvs[0][i][0].x != 0x7FFF) continue; /* perform search to p1 at same distance, if possible */ int p1 = b + i; - if (p1 >= numFrames || frames[b]->lowresMvs[1][i - 1][0].x != 0x7FFF) + if (p1 >= numFrames || frames[b]->lowresMvs[1][i][0].x != 0x7FFF) p1 = b; estGroup.add(p0, p1, b); @@ -1440,7 +1467,7 @@ void Lookahead::slicetypeAnalyse(Lowres /* only measure frame cost in this pass if motion searches * are already done */ - if (frames[b]->lowresMvs[0][i - 1][0].x == 0x7FFF) + if (frames[b]->lowresMvs[0][i][0].x == 0x7FFF) continue; int p0 = b - i; @@ -1452,7 +1479,7 @@ void Lookahead::slicetypeAnalyse(Lowres break; /* ensure P1 search is done */ - if (j && frames[b]->lowresMvs[1][j - 1][0].x == 0x7FFF) + if (j && frames[b]->lowresMvs[1][j][0].x == 0x7FFF) continue; /* ensure frame cost is not done */ @@ -1867,7 +1894,7 @@ void Lookahead::aqMotion(Lowres **frames void Lookahead::calcMotionAdaptiveQuantFrame(Lowres **frames, int p0, int p1, int b) { - int listDist[2] = { b - p0 - 1, p1 - b - 1 }; + int listDist[2] = { b - p0, p1 - b }; int32_t strideInCU = m_8x8Width; double qp_adj = 0, avg_adj = 0, avg_adj_pow2 = 0, sd; for (uint16_t blocky = 0; blocky < m_8x8Height; blocky++) @@ -2030,7 +2057,7 @@ void Lookahead::estimateCUPropagate(Lowr int32_t distScaleFactor = (((b - p0) << 8) + ((p1 - p0) >> 1)) / (p1 - p0); int32_t bipredWeight = m_param->bEnableWeightedBiPred ? 64 - (distScaleFactor >> 2) : 32; int32_t bipredWeights[2] = { bipredWeight, 64 - bipredWeight }; - int listDist[2] = { b - p0 - 1, p1 - b - 1 }; + int listDist[2] = { b - p0, p1 - b }; memset(m_scratch, 0, m_8x8Width * sizeof(int)); @@ -2305,17 +2332,15 @@ int64_t CostEstimateGroup::estimateFrame score = fenc->costEst[b - p0][p1 - b]; else { - X265_CHECK(p0 != b, "I frame estimates should always be pre-calculated\n"); - bool bDoSearch[2]; - bDoSearch[0] = p0 < b && fenc->lowresMvs[0][b - p0 - 1][0].x == 0x7FFF; - bDoSearch[1] = p1 > b && fenc->lowresMvs[1][p1 - b - 1][0].x == 0x7FFF; + bDoSearch[0] = fenc->lowresMvs[0][b - p0][0].x == 0x7FFF; + bDoSearch[1] = p1 > b && fenc->lowresMvs[1][p1 - b][0].x == 0x7FFF; #if CHECKED_BUILD - X265_CHECK(!(p0 < b && fenc->lowresMvs[0][b - p0 - 1][0].x == 0x7FFE), "motion search batch duplication L0\n"); - X265_CHECK(!(p1 > b && fenc->lowresMvs[1][p1 - b - 1][0].x == 0x7FFE), "motion search batch duplication L1\n"); - if (bDoSearch[0]) fenc->lowresMvs[0][b - p0 - 1][0].x = 0x7FFE; - if (bDoSearch[1]) fenc->lowresMvs[1][p1 - b - 1][0].x = 0x7FFE; + X265_CHECK(!(p0 < b && fenc->lowresMvs[0][b - p0][0].x == 0x7FFE), "motion search batch duplication L0\n"); + X265_CHECK(!(p1 > b && fenc->lowresMvs[1][p1 - b][0].x == 0x7FFE), "motion search batch duplication L1\n"); + if (bDoSearch[0]) fenc->lowresMvs[0][b - p0][0].x = 0x7FFE; + if (bDoSearch[1]) fenc->lowresMvs[1][p1 - b][0].x = 0x7FFE; #endif fenc->weightedRef[b - p0].isWeighted = false; @@ -2406,7 +2431,7 @@ void CostEstimateGroup::estimateCUCost(L /* A small, arbitrary bias to avoid VBV problems caused by zero-residual lookahead blocks. */ int lowresPenalty = 4; - int listDist[2] = { b - p0 - 1, p1 - b - 1 }; + int listDist[2] = { b - p0, p1 - b}; MV mvmin, mvmax; int bcost = tld.me.COST_MAX;
--- a/source/encoder/weightPrediction.cpp Fri Dec 22 15:14:57 2017 +0530 +++ b/source/encoder/weightPrediction.cpp Fri Dec 22 14:50:08 2017 +0530 @@ -323,7 +323,7 @@ void weightAnalyse(Slice& slice, Frame& if (!plane && diffPoc <= param.bframes + 1) { - mvs = fenc.lowresMvs[list][diffPoc - 1]; + mvs = fenc.lowresMvs[list][diffPoc]; /* test whether this motion search was performed by lookahead */ if (mvs[0].x != 0x7FFF)
--- a/source/test/regression-tests.txt Fri Dec 22 15:14:57 2017 +0530 +++ b/source/test/regression-tests.txt Fri Dec 22 14:50:08 2017 +0530 @@ -151,6 +151,7 @@ Kimono1_1920x1080_24_400.yuv,--preset me Kimono1_1920x1080_24_400.yuv,--preset veryslow --crf 4 --cu-lossless --slices 2 --limit-refs 3 --limit-modes 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 # Main12 intraCost overflow bug test 720p50_parkrun_ter.y4m,--preset medium
--- a/source/x265.h Fri Dec 22 15:14:57 2017 +0530 +++ b/source/x265.h Fri Dec 22 14:50:08 2017 +0530 @@ -1268,6 +1268,7 @@ typedef struct x265_param /* internally enable if tune grain is set */ int bEnableConstVbv; + } rc; /*== Video Usability Information ==*/ @@ -1542,6 +1543,8 @@ typedef struct x265_param * to reduce the amount of work the encoder must perform. Default disabled. */ const char* analysisLoad; + /*Number of RADL pictures allowed in front of IDR*/ + int radl; } x265_param; /* x265_param_alloc:
--- a/source/x265cli.h Fri Dec 22 15:14:57 2017 +0530 +++ b/source/x265cli.h Fri Dec 22 14:50:08 2017 +0530 @@ -124,6 +124,7 @@ static const struct option long_options[ { "scenecut", required_argument, NULL, 0 }, { "no-scenecut", no_argument, NULL, 0 }, { "scenecut-bias", required_argument, NULL, 0 }, + { "radl", required_argument, NULL, 0 }, { "ctu-info", required_argument, NULL, 0 }, { "intra-refresh", no_argument, NULL, 0 }, { "rc-lookahead", required_argument, NULL, 0 }, @@ -427,6 +428,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(" --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); H1(" --lookahead-slices <0..16> Number of slices to use per lookahead cost estimate. Default %d\n", param->lookaheadSlices);