using namespace x265;
/* Amortize the partial cost of I frames over the next N frames */
-const double RateControl::s_amortizeFraction = 0.85;
-const int RateControl::s_amortizeFrames = 75;
+
const int RateControl::s_slidingWindowFrames = 20;
const char *RateControl::s_defaultStatFileName = "x265_2pass.log";
/* Find the total AC energy of each block in all planes */
uint32_t RateControl::acEnergyCu(Frame* curFrame, uint32_t block_x, uint32_t block_y)
{
- intptr_t stride = curFrame->m_origPicYuv->m_stride;
- intptr_t cStride = curFrame->m_origPicYuv->m_strideC;
+ intptr_t stride = curFrame->m_fencPic->m_stride;
+ intptr_t cStride = curFrame->m_fencPic->m_strideC;
intptr_t blockOffsetLuma = block_x + (block_y * stride);
int colorFormat = m_param->internalCsp;
int hShift = CHROMA_H_SHIFT(colorFormat);
uint32_t var;
- var = acEnergyPlane(curFrame, curFrame->m_origPicYuv->m_picOrg[0] + blockOffsetLuma, stride, 0, colorFormat);
- var += acEnergyPlane(curFrame, curFrame->m_origPicYuv->m_picOrg[1] + blockOffsetChroma, cStride, 1, colorFormat);
- var += acEnergyPlane(curFrame, curFrame->m_origPicYuv->m_picOrg[2] + blockOffsetChroma, cStride, 2, colorFormat);
+ var = acEnergyPlane(curFrame, curFrame->m_fencPic->m_picOrg[0] + blockOffsetLuma, stride, 0, colorFormat);
+ var += acEnergyPlane(curFrame, curFrame->m_fencPic->m_picOrg[1] + blockOffsetChroma, cStride, 1, colorFormat);
+ var += acEnergyPlane(curFrame, curFrame->m_fencPic->m_picOrg[2] + blockOffsetChroma, cStride, 2, colorFormat);
x265_emms();
return var;
}
void RateControl::calcAdaptiveQuantFrame(Frame *curFrame)
{
/* Actual adaptive quantization */
- int maxCol = curFrame->m_origPicYuv->m_picWidth;
- int maxRow = curFrame->m_origPicYuv->m_picHeight;
+ int maxCol = curFrame->m_fencPic->m_picWidth;
+ int maxRow = curFrame->m_fencPic->m_picHeight;
for (int y = 0; y < 3; y++)
{
m_bTerminated = false;
m_finalFrameCount = 0;
m_numEntries = 0;
+ m_amortizeFraction = 0.85;
+ m_amortizeFrames = 75;
+ if (m_param->totalFrames <= 2 * m_fps)
+ {
+ m_amortizeFraction = m_amortizeFrames = 0;
+ }
if (m_param->rc.rateControlMode == X265_RC_CRF)
{
m_param->rc.qp = (int)m_param->rc.rfConstant;
/* Frame Predictors and Row predictors used in vbv */
for (int i = 0; i < 5; i++)
{
- m_pred[i].coeff = 2.0;
+ m_pred[i].coeff = 1.5;
m_pred[i].count = 1.0;
m_pred[i].decay = 0.5;
m_pred[i].offset = 0.0;
}
- m_predBfromP = m_pred[0];
+ m_pred[0].coeff = 1.0;
if (!m_statFileOut && (m_param->rc.bStatWrite || m_param->rc.bStatRead))
{
/* If the user hasn't defined the stat filename, use the default value */
rce->leadingNoBSatd = m_leadingNoBSatd;
if (curFrame->m_forceqp)
{
- m_qp = int32_t(curFrame->m_forceqp + 0.5) - 1;
+ m_qp = (int32_t)(curFrame->m_forceqp + 0.5) - 1;
m_qp = Clip3(QP_MIN, QP_MAX_MAX, m_qp);
rce->qpaRc = curEncData.m_avgQpRc = curEncData.m_avgQpAq = m_qp;
}
return false;
}
+double RateControl::tuneAbrQScaleFromFeedback(double qScale)
+{
+ double abrBuffer = 2 * m_param->rc.rateTolerance * m_bitrate;
+ if (m_currentSatd)
+ {
+ /* use framesDone instead of POC as poc count is not serial with bframes enabled */
+ double overflow = 1.0;
+ double timeDone = (double)(m_framesDone - m_param->frameNumThreads + 1) * m_frameDuration;
+ double wantedBits = timeDone * m_bitrate;
+ if (wantedBits > 0 && m_totalBits > 0 && !m_partialResidualFrames)
+ {
+ abrBuffer *= X265_MAX(1, sqrt(timeDone));
+ overflow = Clip3(.5, 2.0, 1.0 + (m_totalBits - wantedBits) / abrBuffer);
+ qScale *= overflow;
+ }
+ }
+ return qScale;
+}
+
double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)
{
double q;
q += m_pbOffset / 2;
else
q += m_pbOffset;
- rce->qpNoVbv = q;
- double qScale = x265_qp2qScale(q);
- if (!m_2pass && m_isVbv)
+ double qScale = x265_qp2qScale(q);
+ if (m_isCbr)
{
- if (m_leadingBframes > 5)
+ qScale = tuneAbrQScaleFromFeedback(qScale);
+ if (!m_isAbrReset)
{
- qScale = clipQscale(curFrame, rce, qScale);
- m_lastQScaleFor[m_sliceType] = qScale;
+ double lmin = m_lastQScaleFor[P_SLICE] / m_lstep;
+ double lmax = m_lastQScaleFor[P_SLICE] * m_lstep;
+ qScale = Clip3(lmin, lmax, qScale);
}
- rce->frameSizePlanned = predictSize(&m_predBfromP, qScale, (double)m_leadingNoBSatd);
+ q = x265_qScale2qp(qScale);
+ }
+ rce->qpNoVbv = q;
+ if (!m_2pass && m_isVbv)
+ {
+ qScale = clipQscale(curFrame, rce, qScale);
+ m_lastQScaleFor[m_sliceType] = qScale;
+ rce->frameSizePlanned = predictSize(&m_pred[m_sliceType], qScale, (double)m_currentSatd);
}
else if (m_2pass && m_isVbv)
{
* tradeoff between quality and bitrate precision. But at large
* tolerances, the bit distribution approaches that of 2pass. */
- double wantedBits, overflow = 1;
+ double overflow = 1;
m_shortTermCplxSum *= 0.5;
m_shortTermCplxCount *= 0.5;
{
if (!m_param->rc.bStatRead)
checkAndResetABR(rce, false);
- q = getQScale(rce, m_wantedBitsWindow / m_cplxrSum);
-
- /* ABR code can potentially be counterproductive in CBR, so just
- * don't bother. Don't run it if the frame complexity is zero
- * either. */
- if (!m_isCbr && m_currentSatd)
- {
- /* use framesDone instead of POC as poc count is not serial with bframes enabled */
- double timeDone = (double)(m_framesDone - m_param->frameNumThreads + 1) * m_frameDuration;
- wantedBits = timeDone * m_bitrate;
- if (wantedBits > 0 && m_totalBits > 0 && !m_partialResidualFrames)
- {
- abrBuffer *= X265_MAX(1, sqrt(timeDone));
- overflow = Clip3(.5, 2.0, 1.0 + (m_totalBits - wantedBits) / abrBuffer);
- q *= overflow;
- }
- }
+ double initialQScale = getQScale(rce, m_wantedBitsWindow / m_cplxrSum);
+ q = tuneAbrQScaleFromFeedback(initialQScale);
+ overflow = q / initialQScale;
}
-
if (m_sliceType == I_SLICE && m_param->keyframeMax > 1
&& m_lastNonBPictType != I_SLICE && !m_isAbrReset)
{
{
q = x265_qp2qScale(CRF_INIT_QP) / fabs(m_param->rc.ipFactor);
}
- else if (m_framesDone == 0 && !m_isVbv)
+ else if (m_framesDone == 0 && !m_isVbv && m_param->rc.rateControlMode == X265_RC_ABR)
{
/* for ABR alone, clip the first I frame qp */
double lqmax = x265_qp2qScale(ABR_INIT_QP_MAX) * m_lstep;
if (m_partialResidualFrames)
rce->rowTotalBits += m_partialResidualCost * m_partialResidualFrames;
- m_partialResidualFrames = X265_MIN(s_amortizeFrames, m_param->keyframeMax);
- m_partialResidualCost = (int)((rce->rowTotalBits * s_amortizeFraction) /m_partialResidualFrames);
+ m_partialResidualFrames = X265_MIN(m_amortizeFrames, m_param->keyframeMax);
+ m_partialResidualCost = (int)((rce->rowTotalBits * m_amortizeFraction) /m_partialResidualFrames);
rce->rowTotalBits -= m_partialResidualCost * m_partialResidualFrames;
}
else if (m_partialResidualFrames)
{
double frameQ[3];
double curBits;
- if (m_sliceType == B_SLICE)
- curBits = predictSize(&m_predBfromP, q, (double)m_currentSatd);
- else
- curBits = predictSize(&m_pred[m_sliceType], q, (double)m_currentSatd);
+ curBits = predictSize(&m_pred[m_sliceType], q, (double)m_currentSatd);
double bufferFillCur = m_bufferFill - curBits;
double targetFill;
- double totalDuration = 0;
+ double totalDuration = m_frameDuration;
+ bool isIFramePresent = m_sliceType == I_SLICE ? true : false;
frameQ[P_SLICE] = m_sliceType == I_SLICE ? q * m_param->rc.ipFactor : (m_sliceType == B_SLICE ? q / m_param->rc.pbFactor : q);
frameQ[B_SLICE] = frameQ[P_SLICE] * m_param->rc.pbFactor;
frameQ[I_SLICE] = frameQ[P_SLICE] / m_param->rc.ipFactor;
bufferFillCur += wantedFrameSize;
int64_t satd = curFrame->m_lowres.plannedSatd[j] >> (X265_DEPTH - 8);
type = IS_X265_TYPE_I(type) ? I_SLICE : IS_X265_TYPE_B(type) ? B_SLICE : P_SLICE;
+ if (type == I_SLICE)
+ isIFramePresent = true;
curBits = predictSize(&m_pred[type], frameQ[type], (double)satd);
bufferFillCur -= curBits;
}
- /* Try to get the buffer at least 50% filled, but don't set an impossible goal. */
- targetFill = X265_MIN(m_bufferFill + totalDuration * m_vbvMaxRate * 0.5, m_bufferSize * 0.5);
+ /* Try to get the buffer no more than 80% filled, but don't set an impossible goal. */
+ double tol = isIFramePresent ? 1 / totalDuration : totalDuration < 0.5 ? 2 : 1;
+ targetFill = X265_MIN(m_bufferFill + totalDuration * m_vbvMaxRate * 0.5 , m_bufferSize * (1 - 0.8 * totalDuration * tol));
if (bufferFillCur < targetFill)
{
q *= 1.01;
loopTerminate |= 1;
continue;
}
- /* Try to get the buffer no more than 80% filled, but don't set an impossible goal. */
- targetFill = Clip3(m_bufferSize * 0.8, m_bufferSize, m_bufferFill - totalDuration * m_vbvMaxRate * 0.5);
+ /* Try to get the buffer atleast 50% filled, but don't set an impossible goal. */
+ targetFill = Clip3(m_bufferSize - (m_bufferSize * totalDuration * 0.5), m_bufferSize, m_bufferFill - totalDuration * m_vbvMaxRate * 0.5);
if (m_isCbr && bufferFillCur > targetFill)
{
q /= 1.01;
if (pbits > rce->frameSizeMaximum)
q *= pbits / rce->frameSizeMaximum;
- // Check B-frame complexity, and use up any bits that would
- // overflow before the next P-frame.
- if (m_leadingBframes <= 5 && m_sliceType == P_SLICE && !m_singleFrameVbv)
- {
- int nb = m_leadingBframes;
- double bits = predictSize(&m_pred[m_sliceType], q, (double)m_currentSatd);
- double bbits = predictSize(&m_predBfromP, q * m_param->rc.pbFactor, (double)m_currentSatd);
- double space;
- if (bbits > m_bufferRate)
- nb = 0;
- double pbbits = nb * bbits;
-
- space = m_bufferFill + (1 + nb) * m_bufferRate - m_bufferSize;
- if (pbbits < space)
- q *= X265_MAX(pbbits / space, bits / (0.5 * m_bufferSize));
-
- q = X265_MAX(q0 / 2, q);
- }
-
if (!m_isCbr || (m_isAbr && m_currentSatd >= rce->movingAvgSum && q <= q0 / 2))
q = X265_MAX(q0, q);
&& refQScale > 0
&& refRowSatdCost > 0)
{
- if (abs(int32_t(refRowSatdCost - satdCostForPendingCus)) < (int32_t)satdCostForPendingCus / 2)
+ if (abs((int32_t)(refRowSatdCost - satdCostForPendingCus)) < (int32_t)satdCostForPendingCus / 2)
{
double predTotal = refRowBits * satdCostForPendingCus / refRowSatdCost * refQScale / qScale;
- totalSatdBits += int32_t((pred_s + predTotal) * 0.5);
+ totalSatdBits += (int32_t)((pred_s + predTotal) * 0.5);
continue;
}
}
- totalSatdBits += int32_t(pred_s);
+ totalSatdBits += (int32_t)pred_s;
}
- else
+ else if (picType == P_SLICE)
{
/* Our QP is lower than the reference! */
double pred_intra = predictSize(rce->rowPred[1], qScale, intraCost);
/* Sum: better to overestimate than underestimate by using only one of the two predictors. */
- totalSatdBits += int32_t(pred_intra + pred_s);
+ totalSatdBits += (int32_t)(pred_intra + pred_s);
}
+ else
+ totalSatdBits += (int32_t)pred_s;
}
}
if (row < sps.numCuInHeight - 1)
{
- /* B-frames shouldn't use lower QP than their reference frames. */
- if (rce->sliceType == B_SLICE)
- {
- Frame* refSlice1 = curEncData.m_slice->m_refPicList[0][0];
- Frame* refSlice2 = curEncData.m_slice->m_refPicList[1][0];
- qpMin = X265_MAX(qpMin, X265_MAX(refSlice1->m_encData->m_rowStat[row].diagQp, refSlice2->m_encData->m_rowStat[row].diagQp));
- qpVbv = X265_MAX(qpVbv, qpMin);
- }
/* More threads means we have to be more cautious in letting ratecontrol use up extra bits. */
- double rcTol = bufferLeftPlanned / m_param->frameNumThreads * m_param->rc.rateTolerance;
+ double rcTol = (bufferLeftPlanned * 0.2) / m_param->frameNumThreads * m_param->rc.rateTolerance;
int32_t encodedBitsSoFar = 0;
double accFrameBits = predictRowsSizeSum(curFrame, rce, qpVbv, encodedBitsSoFar);
while (qpVbv < qpMax
&& ((accFrameBits > rce->frameSizePlanned + rcTol) ||
- (rce->bufferFill - accFrameBits < bufferLeftPlanned * 0.5) ||
+ (rce->bufferFill - accFrameBits < bufferLeftPlanned * 0.2) ||
(accFrameBits > rce->frameSizePlanned && qpVbv < rce->qpNoVbv)))
{
qpVbv += stepSize;
{
if (var < 10)
return;
- const double range = 1.5;
+ const double range = 2;
double old_coeff = p->coeff / p->count;
double new_coeff = bits * q / var;
double new_coeff_clipped = Clip3(old_coeff / range, old_coeff * range, new_coeff);
/* previous I still had a residual; roll it into the new loan */
if (m_residualFrames)
bits += m_residualCost * m_residualFrames;
- m_residualFrames = X265_MIN(s_amortizeFrames, m_param->keyframeMax);
- m_residualCost = (int)((bits * s_amortizeFraction) / m_residualFrames);
+ m_residualFrames = X265_MIN(m_amortizeFrames, m_param->keyframeMax);
+ m_residualCost = (int)((bits * m_amortizeFraction) / m_residualFrames);
bits -= m_residualCost * m_residualFrames;
}
else if (m_residualFrames)
if (m_isVbv)
{
- if (rce->sliceType == B_SLICE)
- {
- m_bframeBits += actualBits;
- if (rce->bLastMiniGopBFrame)
- {
- if (rce->bframes != 0)
- updatePredictor(&m_predBfromP, x265_qp2qScale(rce->qpaRc), (double)rce->leadingNoBSatd, (double)m_bframeBits / rce->bframes);
- m_bframeBits = 0;
- }
- }
updateVbv(actualBits, rce);
if (m_param->bEmitHRDSEI)