pls ignore the previous patch. It has a few bugs while merging. here is the fixed one :
# HG changeset patch # User Divya Manivannan <[email protected]> # Date 1448267770 -19800 # Mon Nov 23 14:06:10 2015 +0530 # Branch stable # Node ID 0c49c9cc75e4c1ef9534a28b49b97b9107636f5d # Parent 6b308775b6f065ea5002a76a40aa6f5d81e8ee50 rc: implement 2 pass CRF, when vbv is enabled. Allow CRF with VBV in 2nd pass to increase the quality of capped CRF in the first pass. diff -r 6b308775b6f0 -r 0c49c9cc75e4 source/common/param.cpp --- a/source/common/param.cpp Mon Nov 23 12:26:45 2015 +0530 +++ b/source/common/param.cpp Mon Nov 23 14:06:10 2015 +0530 @@ -1170,7 +1170,7 @@ CHECK(0 > param->noiseReductionIntra || param->noiseReductionIntra > 2000, "Valid noise reduction range 0 - 2000"); if (param->noiseReductionInter) CHECK(0 > param->noiseReductionInter || param->noiseReductionInter > 2000, "Valid noise reduction range 0 - 2000"); - CHECK(param->rc.rateControlMode == X265_RC_CRF && param->rc.bStatRead, + CHECK(param->rc.rateControlMode == X265_RC_CRF && param->rc.bStatRead && param->rc.vbvMaxBitrate == 0, "Constant rate-factor is incompatible with 2pass"); CHECK(param->rc.rateControlMode == X265_RC_CQP && param->rc.bStatRead, "Constant QP is incompatible with 2pass"); diff -r 6b308775b6f0 -r 0c49c9cc75e4 source/encoder/ratecontrol.cpp --- a/source/encoder/ratecontrol.cpp Mon Nov 23 12:26:45 2015 +0530 +++ b/source/encoder/ratecontrol.cpp Mon Nov 23 14:06:10 2015 +0530 @@ -142,6 +142,8 @@ rce->expectedVbv = rce2Pass->expectedVbv; rce->blurredComplexity = rce2Pass->blurredComplexity; rce->sliceType = rce2Pass->sliceType; + rce->qpNoVbv = rce2Pass->qpNoVbv; + rce->newQp = rce2Pass->newQp; } } // end anonymous namespace @@ -205,7 +207,7 @@ m_rateFactorMaxDecrement = m_param->rc.rfConstant - m_param->rc.rfConstantMin; } m_isAbr = m_param->rc.rateControlMode != X265_RC_CQP && !m_param->rc.bStatRead; - m_2pass = m_param->rc.rateControlMode == X265_RC_ABR && m_param->rc.bStatRead; + m_2pass = (m_param->rc.rateControlMode == X265_RC_ABR || m_param->rc.vbvMaxBitrate > 0) && m_param->rc.bStatRead; m_bitrate = m_param->rc.bitrate * 1000; m_frameDuration = (double)m_param->fpsDenom / m_param->fpsNum; m_qp = m_param->rc.qp; @@ -488,6 +490,12 @@ x265_log(m_param, X265_LOG_ERROR, "Rce Entries for 2 pass cannot be allocated\n"); return false; } + m_encOrder = X265_MALLOC(int, m_numEntries); + if (!m_encOrder) + { + x265_log(m_param, X265_LOG_ERROR, "Encode order for 2 pass cannot be allocated\n"); + return false; + } /* init all to skipped p frames */ for (int i = 0; i < m_numEntries; i++) { @@ -504,6 +512,7 @@ { RateControlEntry *rce; int frameNumber; + int encodeOrder; char picType; int e; char *next; @@ -511,13 +520,14 @@ next = strstr(p, ";"); if (next) *next++ = 0; - e = sscanf(p, " in:%d ", &frameNumber); + e = sscanf(p, " in:%d out:%d", &frameNumber, &encodeOrder); if (frameNumber < 0 || frameNumber >= m_numEntries) { x265_log(m_param, X265_LOG_ERROR, "bad frame number (%d) at stats line %d\n", frameNumber, i); return false; } - rce = &m_rce2Pass[frameNumber]; + rce = &m_rce2Pass[encodeOrder]; + m_encOrder[frameNumber] = encodeOrder; e += sscanf(p, " in:%*d out:%*d type:%c q:%lf q-aq:%lf q-noVbv:%lf tex:%d mv:%d misc:%d icu:%lf pcu:%lf scu:%lf", &picType, &qpRc, &qpAq, &qNoVbv, &rce->coeffBits, &rce->mvBits, &rce->miscBits, &rce->iCuCount, &rce->pCuCount, @@ -538,7 +548,7 @@ x265_log(m_param, X265_LOG_ERROR, "statistics are damaged at line %d, parser out=%d\n", i, e); return false; } - rce->qScale = x265_qp2qScale(qpRc); + rce->qScale = rce->newQScale = x265_qp2qScale(qpRc); totalQpAq += qpAq; rce->qpNoVbv = qNoVbv; rce->qpaRc = qpRc; @@ -546,8 +556,7 @@ p = next; } X265_FREE(statsBuf); - - if (m_param->rc.rateControlMode == X265_RC_ABR) + if (m_param->rc.rateControlMode == X265_RC_ABR || m_param->rc.vbvMaxBitrate > 0) { if (!initPass2()) return false; @@ -630,11 +639,8 @@ #undef MAX_DURATION } - -bool RateControl::initPass2() +bool RateControl::analyseABR2Pass(int startIndex, int endIndex, uint64_t allAvailableBits) { - uint64_t allConstBits = 0; - uint64_t allAvailableBits = uint64_t(m_param->rc.bitrate * 1000. * m_numEntries * m_frameDuration); double rateFactor, stepMult; double qBlur = m_param->rc.qblur; double cplxBlur = m_param->rc.complexityBlur; @@ -643,30 +649,19 @@ double *qScale, *blurredQscale; double baseCplx = m_ncu * (m_param->bframes ? 120 : 80); double clippedDuration = CLIP_DURATION(m_frameDuration) / BASE_FRAME_DURATION; - - /* find total/average complexity & const_bits */ - for (int i = 0; i < m_numEntries; i++) - allConstBits += m_rce2Pass[i].miscBits; - - if (allAvailableBits < allConstBits) - { - x265_log(m_param, X265_LOG_ERROR, "requested bitrate is too low. estimated minimum is %d kbps\n", - (int)(allConstBits * m_fps / m_numEntries * 1000.)); - return false; - } - + int framesCount = endIndex - startIndex + 1; /* Blur complexities, to reduce local fluctuation of QP. * We don't blur the QPs directly, because then one very simple frame * could drag down the QP of a nearby complex frame and give it more * bits than intended. */ - for (int i = 0; i < m_numEntries; i++) + for (int i = startIndex; i <= endIndex; i++) { double weightSum = 0; double cplxSum = 0; double weight = 1.0; double gaussianWeight; /* weighted average of cplx of future frames */ - for (int j = 1; j < cplxBlur * 2 && j < m_numEntries - i; j++) + for (int j = 1; j < cplxBlur * 2 && j <= endIndex - i; j++) { RateControlEntry *rcj = &m_rce2Pass[i + j]; weight *= 1 - pow(rcj->iCuCount / m_ncu, 2); @@ -690,11 +685,10 @@ } m_rce2Pass[i].blurredComplexity = cplxSum / weightSum; } - - CHECKED_MALLOC(qScale, double, m_numEntries); + CHECKED_MALLOC(qScale, double, framesCount); if (filterSize > 1) { - CHECKED_MALLOC(blurredQscale, double, m_numEntries); + CHECKED_MALLOC(blurredQscale, double, framesCount); } else blurredQscale = qScale; @@ -705,9 +699,8 @@ * because qscale2bits is not invertible, but we can start with the simple * approximation of scaling the 1st pass by the ratio of bitrates. * The search range is probably overkill, but speed doesn't matter here. */ - expectedBits = 1; - for (int i = 0; i < m_numEntries; i++) + for (int i = startIndex; i <= endIndex; i++) { RateControlEntry* rce = &m_rce2Pass[i]; double q = getQScale(rce, 1.0); @@ -784,12 +777,10 @@ X265_FREE(qScale); if (filterSize > 1) X265_FREE(blurredQscale); - if (m_isVbv) - if (!vbv2Pass(allAvailableBits)) + if (!vbv2Pass(allAvailableBits, endIndex, startIndex)) return false; - expectedBits = countExpectedBits(); - + expectedBits = countExpectedBits(startIndex, endIndex); if (fabs(expectedBits / allAvailableBits - 1.0) > 0.01) { double avgq = 0; @@ -822,7 +813,125 @@ return false; } -bool RateControl::vbv2Pass(uint64_t allAvailableBits) +bool RateControl::initPass2() +{ + uint64_t allConstBits = 0, allCodedBits = 0; + uint64_t allAvailableBits = uint64_t(m_param->rc.bitrate * 1000. * m_numEntries * m_frameDuration); + int startIndex, framesCount, endIndex, cnt; + int fps = (int)(m_fps + 0.5); + startIndex = endIndex = framesCount = 0; + allAvailableBits = uint64_t(m_param->rc.vbvMaxBitrate * 1000. * m_numEntries * m_frameDuration); + bool isQpModified = true; + int diffQp = 0; + int64_t targetBits = 0; + int64_t expectedBits = 0; + for (startIndex = 0, endIndex = 0; endIndex < m_numEntries; endIndex++) + { + allConstBits += m_rce2Pass[endIndex].miscBits; + allCodedBits += m_rce2Pass[endIndex].coeffBits + m_rce2Pass[endIndex].mvBits; + if (m_param->rc.rateControlMode == X265_RC_CRF) + { + framesCount = endIndex - startIndex + 1; + diffQp += int (m_rce2Pass[endIndex].qpaRc - m_rce2Pass[endIndex].qpNoVbv); + if (framesCount > fps) + diffQp -= int (m_rce2Pass[endIndex - fps].qpaRc - m_rce2Pass[endIndex - fps].qpNoVbv); + if (framesCount >= fps) + { + if (diffQp >= 1) + { + if (!isQpModified && endIndex > fps) + { + double factor = 2; + double step = 0; + for (int start = endIndex; start <= endIndex + fps - 1 && start < m_numEntries; start++) + { + RateControlEntry *rce = &m_rce2Pass[start]; + targetBits += qScale2bits(rce, x265_qp2qScale(rce->qpNoVbv)); + expectedBits += qScale2bits(rce, rce->qScale); + } + if (expectedBits < 0.95 * targetBits) + { + isQpModified = true; + while (endIndex + fps < m_numEntries) + { + step = pow(2, factor / 6.0); + expectedBits = 0; + for (int start = endIndex; start <= endIndex + fps - 1; start++) + { + RateControlEntry *rce = &m_rce2Pass[start]; + rce->newQScale = rce->qScale / step; + X265_CHECK(rce->newQScale >= 0, "new Qscale is negative\n"); + expectedBits += qScale2bits(rce, rce->newQScale); + rce->newQp = x265_qScale2qp(rce->newQScale); + } + if (expectedBits >= targetBits && step > 1) + factor *= 0.90; + else + break; + } + + if (m_isVbv && endIndex + fps < m_numEntries) + if (!vbv2Pass(targetBits, endIndex + fps - 1, endIndex)) + return false; + + double prevFactor = factor; + targetBits = 0; + expectedBits = 0; + + for (int start = endIndex - fps; start <= endIndex - 1; start++) + { + RateControlEntry *rce = &m_rce2Pass[start]; + targetBits += qScale2bits(rce, x265_qp2qScale(rce->qpNoVbv)); + } + while (1) + { + step = pow(2, factor / 6.0); + expectedBits = 0; + for (int start = endIndex - fps; start <= endIndex - 1; start++) + { + RateControlEntry *rce = &m_rce2Pass[start]; + rce->newQScale = rce->qScale * step; + X265_CHECK(rce->newQScale >= 0, "new Qscale is negative\n"); + expectedBits += qScale2bits(rce, rce->newQScale); + rce->newQp = x265_qScale2qp(rce->newQScale); + } + if (expectedBits > targetBits && step > 1) + factor *= 1.1; + else + break; + } + if (m_isVbv) + if (!vbv2Pass(targetBits, endIndex - 1, endIndex - fps)) + return false; + diffQp = 0; + startIndex = endIndex + 1; + targetBits = expectedBits = 0; + } + else + targetBits = expectedBits = 0; + } + } + else + isQpModified = false; + } + } + } + + if (m_param->rc.rateControlMode == X265_RC_ABR) + { + if (allAvailableBits < allConstBits) + { + x265_log(m_param, X265_LOG_ERROR, "requested bitrate is too low. estimated minimum is %d kbps\n", + (int)(allConstBits * m_fps / framesCount * 1000.)); + return false; + } + if (!analyseABR2Pass(0, m_numEntries - 1, allAvailableBits)) + return false; + } + return true; +} + +bool RateControl::vbv2Pass(uint64_t allAvailableBits, int endPos, int startPos) { /* for each interval of bufferFull .. underflow, uniformly increase the qp of all * frames in the interval until either buffer is full at some intermediate frame or the @@ -848,10 +957,10 @@ { /* not first iteration */ adjustment = X265_MAX(X265_MIN(expectedBits / allAvailableBits, 0.999), 0.9); fills[-1] = m_bufferSize * m_param->rc.vbvBufferInit; - t0 = 0; + t0 = startPos; /* fix overflows */ adjMin = 1; - while (adjMin && findUnderflow(fills, &t0, &t1, 1)) + while (adjMin && findUnderflow(fills, &t0, &t1, 1, endPos)) { adjMin = fixUnderflow(t0, t1, adjustment, MIN_QPSCALE, MAX_MAX_QPSCALE); t0 = t1; @@ -862,20 +971,16 @@ t0 = 0; /* fix underflows -- should be done after overflow, as we'd better undersize target than underflowing VBV */ adjMax = 1; - while (adjMax && findUnderflow(fills, &t0, &t1, 0)) + while (adjMax && findUnderflow(fills, &t0, &t1, 0, endPos)) adjMax = fixUnderflow(t0, t1, 1.001, MIN_QPSCALE, MAX_MAX_QPSCALE ); - - expectedBits = countExpectedBits(); + expectedBits = countExpectedBits(startPos, endPos); } - while ((expectedBits < .995 * allAvailableBits) && ((int64_t)(expectedBits+.5) > (int64_t)(prevBits+.5))); - + while ((expectedBits < .995 * allAvailableBits) && ((int64_t)(expectedBits+.5) > (int64_t)(prevBits+.5)) && !(m_param->rc.rateControlMode == X265_RC_CRF)); if (!adjMax) x265_log(m_param, X265_LOG_WARNING, "vbv-maxrate issue, qpmax or vbv-maxrate too low\n"); - /* store expected vbv filling values for tracking when encoding */ - for (int i = 0; i < m_numEntries; i++) + for (int i = startPos; i <= endPos; i++) m_rce2Pass[i].expectedVbv = m_bufferSize - fills[i]; - X265_FREE(fills - 1); return true; @@ -915,9 +1020,10 @@ m_param->bframes = 1; return X265_TYPE_AUTO; } - int frameType = m_rce2Pass[frameNum].sliceType == I_SLICE ? (frameNum > 0 && m_param->bOpenGOP ? X265_TYPE_I : X265_TYPE_IDR) - : m_rce2Pass[frameNum].sliceType == P_SLICE ? X265_TYPE_P - : (m_rce2Pass[frameNum].sliceType == B_SLICE && m_rce2Pass[frameNum].keptAsRef? X265_TYPE_BREF : X265_TYPE_B); + int index = m_encOrder[frameNum]; + int frameType = m_rce2Pass[index].sliceType == I_SLICE ? (frameNum > 0 && m_param->bOpenGOP ? X265_TYPE_I : X265_TYPE_IDR) + : m_rce2Pass[index].sliceType == P_SLICE ? X265_TYPE_P + : (m_rce2Pass[index].sliceType == B_SLICE && m_rce2Pass[index].keptAsRef ? X265_TYPE_BREF : X265_TYPE_B); return frameType; } else @@ -968,7 +1074,8 @@ if (m_param->rc.bStatRead) { X265_CHECK(rce->poc >= 0 && rce->poc < m_numEntries, "bad encode ordinal\n"); - copyRceData(rce, &m_rce2Pass[rce->poc]); + int index = m_encOrder[rce->poc]; + copyRceData(rce, &m_rce2Pass[index]); } rce->isActive = true; bool isRefFrameScenecut = m_sliceType!= I_SLICE && m_curSlice->m_refPicList[0][0]->m_lowres.bScenecut == 1; @@ -1032,6 +1139,16 @@ } } } + if (!m_isAbr && m_2pass && m_param->rc.rateControlMode == X265_RC_CRF) + { + rce->qScale = rce->newQScale; + rce->qpaRc = curEncData.m_avgQpRc = curEncData.m_avgQpAq = x265_qScale2qp(rce->newQScale); + m_qp = int(rce->qpaRc + 0.5); + rce->frameSizePlanned = qScale2bits(rce, rce->qScale); + m_framesDone++; + return m_qp; + } + if (m_isAbr || m_2pass) // ABR,CRF { if (m_isAbr || m_isVbv) @@ -1203,11 +1320,10 @@ } return q; } - -double RateControl::countExpectedBits() +double RateControl::countExpectedBits(int startPos, int endPos) { double expectedBits = 0; - for( int i = 0; i < m_numEntries; i++ ) + for (int i = startPos; i <= endPos; i++) { RateControlEntry *rce = &m_rce2Pass[i]; rce->expectedBits = (uint64_t)expectedBits; @@ -1215,8 +1331,7 @@ } return expectedBits; } - -bool RateControl::findUnderflow(double *fills, int *t0, int *t1, int over) +bool RateControl::findUnderflow(double *fills, int *t0, int *t1, int over, int endPos) { /* find an interval ending on an overflow or underflow (depending on whether * we're adding or removing bits), and starting on the earliest frame that @@ -1226,7 +1341,7 @@ double fill = fills[*t0 - 1]; double parity = over ? 1. : -1.; int start = -1, end = -1; - for (int i = *t0; i < m_numEntries; i++) + for (int i = *t0; i <= endPos; i++) { fill += (m_frameDuration * m_vbvMaxRate - qScale2bits(&m_rce2Pass[i], m_rce2Pass[i].newQScale)) * parity; @@ -1263,12 +1378,11 @@ } return adjusted; } - bool RateControl::cuTreeReadFor2Pass(Frame* frame) { - uint8_t sliceTypeActual = (uint8_t)m_rce2Pass[frame->m_poc].sliceType; - - if (m_rce2Pass[frame->m_poc].keptAsRef) + int index = m_encOrder[frame->m_poc]; + uint8_t sliceTypeActual = (uint8_t)m_rce2Pass[index].sliceType; + if (m_rce2Pass[index].keptAsRef) { /* TODO: We don't need pre-lookahead to measure AQ offsets, but there is currently * no way to signal this */ @@ -1948,6 +2062,8 @@ int RateControl::rowDiagonalVbvRateControl(Frame* curFrame, uint32_t row, RateControlEntry* rce, double& qpVbv) { + if (m_param->rc.bStatRead && m_param->rc.rateControlMode == X265_RC_CRF) + return 0; FrameData& curEncData = *curFrame->m_encData; double qScaleVbv = x265_qp2qScale(qpVbv); uint64_t rowSatdCost = curEncData.m_rowStat[row].diagSatd; @@ -2195,7 +2311,7 @@ if (m_param->rc.aqMode || m_isVbv) { - if (m_isVbv) + if (m_isVbv && !(m_2pass && m_param->rc.rateControlMode == X265_RC_CRF)) { /* determine avg QP decided by VBV rate control */ for (uint32_t i = 0; i < slice->m_sps->numCuInHeight; i++) diff -r 6b308775b6f0 -r 0c49c9cc75e4 source/encoder/ratecontrol.h --- a/source/encoder/ratecontrol.h Mon Nov 23 12:26:45 2015 +0530 +++ b/source/encoder/ratecontrol.h Mon Nov 23 14:06:10 2015 +0530 @@ -205,8 +205,8 @@ double m_lastAccumPNorm; double m_expectedBitsSum; /* sum of qscale2bits after rceq, ratefactor, and overflow, only includes finished frames */ int64_t m_predictedBits; + int *m_encOrder; RateControlEntry* m_rce2Pass; - struct { uint16_t *qpBuffer[2]; /* Global buffers for converting MB-tree quantizer data. */ @@ -258,11 +258,12 @@ void checkAndResetABR(RateControlEntry* rce, bool isFrameDone); double predictRowsSizeSum(Frame* pic, RateControlEntry* rce, double qpm, int32_t& encodedBits); bool initPass2(); + bool analyseABR2Pass(int startPoc, int endPoc, uint64_t allAvailableBits); void initFramePredictors(); double getDiffLimitedQScale(RateControlEntry *rce, double q); - double countExpectedBits(); - bool vbv2Pass(uint64_t allAvailableBits); - bool findUnderflow(double *fills, int *t0, int *t1, int over); + double countExpectedBits(int startPos, int framesCount); + bool vbv2Pass(uint64_t allAvailableBits, int frameCount, int startPos); + bool findUnderflow(double *fills, int *t0, int *t1, int over, int framesCount); bool fixUnderflow(int t0, int t1, double adjustment, double qscaleMin, double qscaleMax); }; } On Mon, Nov 23, 2015 at 2:16 PM, <[email protected]> wrote: > # HG changeset patch > # User Divya Manivannan <[email protected]> > # Date 1448267770 -19800 > # Mon Nov 23 14:06:10 2015 +0530 > # Branch stable > # Node ID ffb0111298cdfcf6fe77d143089144c23b644b2d > # Parent 6b308775b6f065ea5002a76a40aa6f5d81e8ee50 > rc: implement 2 pass CRF, when vbv is enabled. > > Allow CRF with VBV in 2nd pass to increase the quality of capped CRF in > the first pass. > > diff -r 6b308775b6f0 -r ffb0111298cd source/common/param.cpp > --- a/source/common/param.cpp Mon Nov 23 12:26:45 2015 +0530 > +++ b/source/common/param.cpp Mon Nov 23 14:06:10 2015 +0530 > @@ -1170,7 +1170,7 @@ > CHECK(0 > param->noiseReductionIntra || > param->noiseReductionIntra > 2000, "Valid noise reduction range 0 - 2000"); > if (param->noiseReductionInter) > CHECK(0 > param->noiseReductionInter || > param->noiseReductionInter > 2000, "Valid noise reduction range 0 - 2000"); > - CHECK(param->rc.rateControlMode == X265_RC_CRF && param->rc.bStatRead, > + CHECK(param->rc.rateControlMode == X265_RC_CRF && param->rc.bStatRead > && param->rc.vbvMaxBitrate == 0, > "Constant rate-factor is incompatible with 2pass"); > CHECK(param->rc.rateControlMode == X265_RC_CQP && param->rc.bStatRead, > "Constant QP is incompatible with 2pass"); > diff -r 6b308775b6f0 -r ffb0111298cd source/encoder/ratecontrol.cpp > --- a/source/encoder/ratecontrol.cpp Mon Nov 23 12:26:45 2015 +0530 > +++ b/source/encoder/ratecontrol.cpp Mon Nov 23 14:06:10 2015 +0530 > @@ -142,6 +142,8 @@ > rce->expectedVbv = rce2Pass->expectedVbv; > rce->blurredComplexity = rce2Pass->blurredComplexity; > rce->sliceType = rce2Pass->sliceType; > + rce->qpNoVbv = rce2Pass->qpNoVbv; > + rce->newQp = rce2Pass->newQp; > } > > } // end anonymous namespace > @@ -205,7 +207,7 @@ > m_rateFactorMaxDecrement = m_param->rc.rfConstant - > m_param->rc.rfConstantMin; > } > m_isAbr = m_param->rc.rateControlMode != X265_RC_CQP && > !m_param->rc.bStatRead; > - m_2pass = m_param->rc.rateControlMode == X265_RC_ABR && > m_param->rc.bStatRead; > + m_2pass = (m_param->rc.rateControlMode == X265_RC_ABR || > m_param->rc.vbvMaxBitrate > 0) && m_param->rc.bStatRead; > m_bitrate = m_param->rc.bitrate * 1000; > m_frameDuration = (double)m_param->fpsDenom / m_param->fpsNum; > m_qp = m_param->rc.qp; > @@ -488,6 +490,12 @@ > x265_log(m_param, X265_LOG_ERROR, "Rce Entries for 2 > pass cannot be allocated\n"); > return false; > } > + m_encOrder = X265_MALLOC(int, m_numEntries); > + if (!m_encOrder) > + { > + x265_log(m_param, X265_LOG_ERROR, "Encode order for 2 > pass cannot be allocated\n"); > + return false; > + } > /* init all to skipped p frames */ > for (int i = 0; i < m_numEntries; i++) > { > @@ -504,6 +512,7 @@ > { > RateControlEntry *rce; > int frameNumber; > + int encodeOrder; > char picType; > int e; > char *next; > @@ -511,13 +520,14 @@ > next = strstr(p, ";"); > if (next) > *next++ = 0; > - e = sscanf(p, " in:%d ", &frameNumber); > + e = sscanf(p, " in:%d out:%d", &frameNumber, > &encodeOrder); > if (frameNumber < 0 || frameNumber >= m_numEntries) > { > x265_log(m_param, X265_LOG_ERROR, "bad frame number > (%d) at stats line %d\n", frameNumber, i); > return false; > } > - rce = &m_rce2Pass[frameNumber]; > + rce = &m_rce2Pass[encodeOrder]; > + m_encOrder[frameNumber] = encodeOrder; > e += sscanf(p, " in:%*d out:%*d type:%c q:%lf q-aq:%lf > q-noVbv:%lf tex:%d mv:%d misc:%d icu:%lf pcu:%lf scu:%lf", > &picType, &qpRc, &qpAq, &qNoVbv, &rce->coeffBits, > &rce->mvBits, &rce->miscBits, &rce->iCuCount, > &rce->pCuCount, > @@ -546,8 +556,7 @@ > p = next; > } > X265_FREE(statsBuf); > - > - if (m_param->rc.rateControlMode == X265_RC_ABR) > + if (m_param->rc.rateControlMode == X265_RC_ABR || > m_param->rc.vbvMaxBitrate > 0) > { > if (!initPass2()) > return false; > @@ -630,11 +639,8 @@ > > #undef MAX_DURATION > } > - > -bool RateControl::initPass2() > +bool RateControl::analyseABR2Pass(int startIndex, int endIndex, uint64_t > allAvailableBits) > { > - uint64_t allConstBits = 0; > - uint64_t allAvailableBits = uint64_t(m_param->rc.bitrate * 1000. * > m_numEntries * m_frameDuration); > double rateFactor, stepMult; > double qBlur = m_param->rc.qblur; > double cplxBlur = m_param->rc.complexityBlur; > @@ -643,30 +649,19 @@ > double *qScale, *blurredQscale; > double baseCplx = m_ncu * (m_param->bframes ? 120 : 80); > double clippedDuration = CLIP_DURATION(m_frameDuration) / > BASE_FRAME_DURATION; > - > - /* find total/average complexity & const_bits */ > - for (int i = 0; i < m_numEntries; i++) > - allConstBits += m_rce2Pass[i].miscBits; > - > - if (allAvailableBits < allConstBits) > - { > - x265_log(m_param, X265_LOG_ERROR, "requested bitrate is too low. > estimated minimum is %d kbps\n", > - (int)(allConstBits * m_fps / m_numEntries * 1000.)); > - return false; > - } > - > + int framesCount = endIndex - startIndex + 1; > /* Blur complexities, to reduce local fluctuation of QP. > * We don't blur the QPs directly, because then one very simple frame > * could drag down the QP of a nearby complex frame and give it more > * bits than intended. */ > - for (int i = 0; i < m_numEntries; i++) > + for (int i = startIndex; i <= endIndex; i++) > { > double weightSum = 0; > double cplxSum = 0; > double weight = 1.0; > double gaussianWeight; > /* weighted average of cplx of future frames */ > - for (int j = 1; j < cplxBlur * 2 && j < m_numEntries - i; j++) > + for (int j = 1; j < cplxBlur * 2 && j <= endIndex - i; j++) > { > RateControlEntry *rcj = &m_rce2Pass[i + j]; > weight *= 1 - pow(rcj->iCuCount / m_ncu, 2); > @@ -690,11 +685,10 @@ > } > m_rce2Pass[i].blurredComplexity = cplxSum / weightSum; > } > - > - CHECKED_MALLOC(qScale, double, m_numEntries); > + CHECKED_MALLOC(qScale, double, framesCount); > if (filterSize > 1) > { > - CHECKED_MALLOC(blurredQscale, double, m_numEntries); > + CHECKED_MALLOC(blurredQscale, double, framesCount); > } > else > blurredQscale = qScale; > @@ -705,9 +699,8 @@ > * because qscale2bits is not invertible, but we can start with the > simple > * approximation of scaling the 1st pass by the ratio of bitrates. > * The search range is probably overkill, but speed doesn't matter > here. */ > - > expectedBits = 1; > - for (int i = 0; i < m_numEntries; i++) > + for (int i = startIndex; i <= endIndex; i++) > { > RateControlEntry* rce = &m_rce2Pass[i]; > double q = getQScale(rce, 1.0); > @@ -784,12 +777,10 @@ > X265_FREE(qScale); > if (filterSize > 1) > X265_FREE(blurredQscale); > - > if (m_isVbv) > - if (!vbv2Pass(allAvailableBits)) > + if (!vbv2Pass(allAvailableBits, endIndex, startIndex)) > return false; > - expectedBits = countExpectedBits(); > - > + expectedBits = countExpectedBits(startIndex, endIndex); > if (fabs(expectedBits / allAvailableBits - 1.0) > 0.01) > { > double avgq = 0; > @@ -822,7 +813,127 @@ > return false; > } > > -bool RateControl::vbv2Pass(uint64_t allAvailableBits) > +bool RateControl::initPass2() > +{ > + uint64_t allConstBits = 0, allCodedBits = 0; > + uint64_t allAvailableBits = uint64_t(m_param->rc.bitrate * 1000. * > m_numEntries * m_frameDuration); > + int startIndex, framesCount, endIndex, cnt; > + int fps = (int)(m_fps + 0.5); > + startIndex = endIndex = framesCount = 0; > + allAvailableBits = uint64_t(m_param->rc.vbvMaxBitrate * 1000. * > m_numEntries * m_frameDuration); > + bool isQpModified = true; > + int diffQp = 0; > + int64_t targetBits = 0; > + int64_t expectedBits = 0; > + for (startIndex = 0, endIndex = 0; endIndex < m_numEntries; > endIndex++) > + { > + allConstBits += m_rce2Pass[endIndex].miscBits; > + allCodedBits += m_rce2Pass[endIndex].coeffBits + > m_rce2Pass[endIndex].mvBits; > + if (m_param->rc.rateControlMode == X265_RC_CRF) > + { > + framesCount = endIndex - startIndex + 1; > + if (m_rce2Pass[endIndex].newQScale < 0) > + m_rce2Pass[endIndex].newQScale = > m_rce2Pass[endIndex].qScale; > + diffQp += int (m_rce2Pass[endIndex].qpaRc - > m_rce2Pass[endIndex].qpNoVbv); > + if (framesCount > fps) > + diffQp -= int (m_rce2Pass[endIndex - fps].qpaRc - > m_rce2Pass[endIndex - fps].qpNoVbv); > + if (framesCount >= fps) > + { > + if (diffQp >= 1) > + { > + if (!isQpModified && endIndex > fps) > + { > + double factor = 2; > + double step = 0; > + for (int start = endIndex; start <= endIndex + > fps - 1 && start < m_numEntries; start++) > + { > + RateControlEntry *rce = &m_rce2Pass[start]; > + targetBits += qScale2bits(rce, > x265_qp2qScale(rce->qpNoVbv)); > + expectedBits += qScale2bits(rce, rce->qScale); > + } > + if (expectedBits < 0.95 * targetBits) > + { > + isQpModified = true; > + while (endIndex + fps < m_numEntries) > + { > + step = pow(2, factor / 6.0); > + expectedBits = 0; > + for (int start = endIndex; start <= > endIndex + fps - 1; start++) > + { > + RateControlEntry *rce = > &m_rce2Pass[start]; > + rce->newQScale = rce->qScale / step; > + X265_CHECK(rce->newQScale >= 0, "new > Qscale is negative\n"); > + expectedBits += qScale2bits(rce, > rce->newQScale); > + rce->newQp = > x265_qScale2qp(rce->newQScale); > + } > + if (expectedBits >= targetBits && step > > 1) > + factor *= 0.90; > + else > + break; > + } > + > + if (m_isVbv && endIndex + fps < m_numEntries) > + if (!vbv2Pass(targetBits, endIndex + fps > - 1, endIndex)) > + return false; > + > + double prevFactor = factor; > + targetBits = 0; > + expectedBits = 0; > + > + for (int start = endIndex - fps; start <= > endIndex - 1; start++) > + { > + RateControlEntry *rce = > &m_rce2Pass[start]; > + targetBits += qScale2bits(rce, > x265_qp2qScale(rce->qpNoVbv)); > + } > + while (1) > + { > + step = pow(2, factor / 6.0); > + expectedBits = 0; > + for (int start = endIndex - fps; start <= > endIndex - 1; start++) > + { > + RateControlEntry *rce = > &m_rce2Pass[start]; > + rce->newQScale = rce->qScale * step; > + X265_CHECK(rce->newQScale >= 0, "new > Qscale is negative\n"); > + expectedBits += qScale2bits(rce, > rce->newQScale); > + rce->newQp = > x265_qScale2qp(rce->newQScale); > + } > + if (expectedBits > targetBits && step > 1) > + factor *= 1.1; > + else > + break; > + } > + if (m_isVbv) > + if (!vbv2Pass(targetBits, endIndex - 1, > endIndex - fps)) > + return false; > + diffQp = 0; > + startIndex = endIndex + 1; > + targetBits = expectedBits = 0; > + } > + else > + targetBits = expectedBits = 0; > + } > + } > + else > + isQpModified = false; > + } > + } > + } > + > + if (m_param->rc.rateControlMode == X265_RC_ABR) > + { > + if (allAvailableBits < allConstBits) > + { > + x265_log(m_param, X265_LOG_ERROR, "requested bitrate is too > low. estimated minimum is %d kbps\n", > + (int)(allConstBits * m_fps / framesCount * 1000.)); > + return false; > + } > + if (!analyseABR2Pass(0, m_numEntries - 1, allAvailableBits)) > + return false; > + } > + return true; > +} > + > +bool RateControl::vbv2Pass(uint64_t allAvailableBits, int endPos, int > startPos) > { > /* for each interval of bufferFull .. underflow, uniformly increase > the qp of all > * frames in the interval until either buffer is full at some > intermediate frame or the > @@ -848,10 +959,10 @@ > { /* not first iteration */ > adjustment = X265_MAX(X265_MIN(expectedBits / > allAvailableBits, 0.999), 0.9); > fills[-1] = m_bufferSize * m_param->rc.vbvBufferInit; > - t0 = 0; > + t0 = startPos; > /* fix overflows */ > adjMin = 1; > - while (adjMin && findUnderflow(fills, &t0, &t1, 1)) > + while (adjMin && findUnderflow(fills, &t0, &t1, 1, endPos)) > { > adjMin = fixUnderflow(t0, t1, adjustment, MIN_QPSCALE, > MAX_MAX_QPSCALE); > t0 = t1; > @@ -862,20 +973,16 @@ > t0 = 0; > /* fix underflows -- should be done after overflow, as we'd > better undersize target than underflowing VBV */ > adjMax = 1; > - while (adjMax && findUnderflow(fills, &t0, &t1, 0)) > + while (adjMax && findUnderflow(fills, &t0, &t1, 0, endPos)) > adjMax = fixUnderflow(t0, t1, 1.001, MIN_QPSCALE, > MAX_MAX_QPSCALE ); > - > - expectedBits = countExpectedBits(); > + expectedBits = countExpectedBits(startPos, endPos); > } > - while ((expectedBits < .995 * allAvailableBits) && > ((int64_t)(expectedBits+.5) > (int64_t)(prevBits+.5))); > - > + while ((expectedBits < .995 * allAvailableBits) && > ((int64_t)(expectedBits+.5) > (int64_t)(prevBits+.5)) && > !(m_param->rc.rateControlMode == X265_RC_CRF)); > if (!adjMax) > x265_log(m_param, X265_LOG_WARNING, "vbv-maxrate issue, qpmax or > vbv-maxrate too low\n"); > - > /* store expected vbv filling values for tracking when encoding */ > - for (int i = 0; i < m_numEntries; i++) > + for (int i = startPos; i <= endPos; i++) > m_rce2Pass[i].expectedVbv = m_bufferSize - fills[i]; > - > X265_FREE(fills - 1); > return true; > > @@ -915,9 +1022,10 @@ > m_param->bframes = 1; > return X265_TYPE_AUTO; > } > - int frameType = m_rce2Pass[frameNum].sliceType == I_SLICE ? > (frameNum > 0 && m_param->bOpenGOP ? X265_TYPE_I : X265_TYPE_IDR) > - : m_rce2Pass[frameNum].sliceType == P_SLICE ? > X265_TYPE_P > - : (m_rce2Pass[frameNum].sliceType == B_SLICE > && m_rce2Pass[frameNum].keptAsRef? X265_TYPE_BREF : X265_TYPE_B); > + int index = m_encOrder[frameNum]; > + int frameType = m_rce2Pass[index].sliceType == I_SLICE ? > (frameNum > 0 && m_param->bOpenGOP ? X265_TYPE_I : X265_TYPE_IDR) > + : m_rce2Pass[index].sliceType == P_SLICE ? > X265_TYPE_P > + : (m_rce2Pass[index].sliceType == B_SLICE && > m_rce2Pass[index].keptAsRef ? X265_TYPE_BREF : X265_TYPE_B); > return frameType; > } > else > @@ -968,7 +1076,8 @@ > if (m_param->rc.bStatRead) > { > X265_CHECK(rce->poc >= 0 && rce->poc < m_numEntries, "bad encode > ordinal\n"); > - copyRceData(rce, &m_rce2Pass[rce->poc]); > + int index = m_encOrder[rce->poc]; > + copyRceData(rce, &m_rce2Pass[index]); > } > rce->isActive = true; > bool isRefFrameScenecut = m_sliceType!= I_SLICE && > m_curSlice->m_refPicList[0][0]->m_lowres.bScenecut == 1; > @@ -1032,6 +1141,16 @@ > } > } > } > + if (!m_isAbr && m_2pass && m_param->rc.rateControlMode == X265_RC_CRF) > + { > + rce->qScale = rce->newQScale; > + rce->qpaRc = curEncData.m_avgQpRc = curEncData.m_avgQpAq = > x265_qScale2qp(rce->newQScale); > + m_qp = int(rce->qpaRc + 0.5); > + rce->frameSizePlanned = qScale2bits(rce, rce->qScale); > + m_framesDone++; > + return m_qp; > + } > + > if (m_isAbr || m_2pass) // ABR,CRF > { > if (m_isAbr || m_isVbv) > @@ -1203,11 +1322,10 @@ > } > return q; > } > - > -double RateControl::countExpectedBits() > +double RateControl::countExpectedBits(int startPos, int endPos) > { > double expectedBits = 0; > - for( int i = 0; i < m_numEntries; i++ ) > + for (int i = startPos; i <= endPos; i++) > { > RateControlEntry *rce = &m_rce2Pass[i]; > rce->expectedBits = (uint64_t)expectedBits; > @@ -1215,8 +1333,7 @@ > } > return expectedBits; > } > - > -bool RateControl::findUnderflow(double *fills, int *t0, int *t1, int over) > +bool RateControl::findUnderflow(double *fills, int *t0, int *t1, int > over, int endPos) > { > /* find an interval ending on an overflow or underflow (depending on > whether > * we're adding or removing bits), and starting on the earliest frame > that > @@ -1226,7 +1343,7 @@ > double fill = fills[*t0 - 1]; > double parity = over ? 1. : -1.; > int start = -1, end = -1; > - for (int i = *t0; i < m_numEntries; i++) > + for (int i = *t0; i <= endPos; i++) > { > fill += (m_frameDuration * m_vbvMaxRate - > qScale2bits(&m_rce2Pass[i], m_rce2Pass[i].newQScale)) * > parity; > @@ -1263,12 +1380,11 @@ > } > return adjusted; > } > - > bool RateControl::cuTreeReadFor2Pass(Frame* frame) > { > - uint8_t sliceTypeActual = (uint8_t)m_rce2Pass[frame->m_poc].sliceType; > - > - if (m_rce2Pass[frame->m_poc].keptAsRef) > + int index = m_encOrder[frame->m_poc]; > + uint8_t sliceTypeActual = (uint8_t)m_rce2Pass[index].sliceType; > + if (m_rce2Pass[index].keptAsRef) > { > /* TODO: We don't need pre-lookahead to measure AQ offsets, but > there is currently > * no way to signal this */ > @@ -1948,6 +2064,8 @@ > > int RateControl::rowDiagonalVbvRateControl(Frame* curFrame, uint32_t row, > RateControlEntry* rce, double& qpVbv) > { > + if (m_param->rc.bStatRead && m_param->rc.rateControlMode == > X265_RC_CRF) > + return 0; > FrameData& curEncData = *curFrame->m_encData; > double qScaleVbv = x265_qp2qScale(qpVbv); > uint64_t rowSatdCost = curEncData.m_rowStat[row].diagSatd; > @@ -2195,7 +2313,7 @@ > > if (m_param->rc.aqMode || m_isVbv) > { > - if (m_isVbv) > + if (m_isVbv && !(m_2pass && m_param->rc.rateControlMode == > X265_RC_CRF)) > { > /* determine avg QP decided by VBV rate control */ > for (uint32_t i = 0; i < slice->m_sps->numCuInHeight; i++) > diff -r 6b308775b6f0 -r ffb0111298cd source/encoder/ratecontrol.h > --- a/source/encoder/ratecontrol.h Mon Nov 23 12:26:45 2015 +0530 > +++ b/source/encoder/ratecontrol.h Mon Nov 23 14:06:10 2015 +0530 > @@ -205,8 +205,8 @@ > double m_lastAccumPNorm; > double m_expectedBitsSum; /* sum of qscale2bits after rceq, > ratefactor, and overflow, only includes finished frames */ > int64_t m_predictedBits; > + int *m_encOrder; > RateControlEntry* m_rce2Pass; > - > struct > { > uint16_t *qpBuffer[2]; /* Global buffers for converting MB-tree > quantizer data. */ > @@ -258,11 +258,12 @@ > void checkAndResetABR(RateControlEntry* rce, bool isFrameDone); > double predictRowsSizeSum(Frame* pic, RateControlEntry* rce, double > qpm, int32_t& encodedBits); > bool initPass2(); > + bool analyseABR2Pass(int startPoc, int endPoc, uint64_t > allAvailableBits); > void initFramePredictors(); > double getDiffLimitedQScale(RateControlEntry *rce, double q); > - double countExpectedBits(); > - bool vbv2Pass(uint64_t allAvailableBits); > - bool findUnderflow(double *fills, int *t0, int *t1, int over); > + double countExpectedBits(int startPos, int framesCount); > + bool vbv2Pass(uint64_t allAvailableBits, int frameCount, int > startPos); > + bool findUnderflow(double *fills, int *t0, int *t1, int over, int > framesCount); > bool fixUnderflow(int t0, int t1, double adjustment, double > qscaleMin, double qscaleMax); > }; > } >
_______________________________________________ x265-devel mailing list [email protected] https://mailman.videolan.org/listinfo/x265-devel
