📄 mode.cpp
字号:
{
nBitsHead += statSrc.nBitsHead;
nBitsY += statSrc.nBitsY;
nBitsCr += statSrc.nBitsCr;
nBitsCb += statSrc.nBitsCb;
nBitsA += statSrc.nBitsA;
// nBits1stShpCode += statSrc.nBits1stShpCode;
nBitsCOD += statSrc.nBitsCOD;
nBitsCBPY += statSrc.nBitsCBPY;
nBitsMCBPC += statSrc.nBitsMCBPC;
nBitsDQUANT += statSrc.nBitsDQUANT;
nBitsMODB += statSrc.nBitsMODB;
nBitsCBPB += statSrc.nBitsCBPB;
nBitsMBTYPE += statSrc.nBitsMBTYPE;
nBitsIntraPred += statSrc.nBitsIntraPred;
nBitsNoDCT += statSrc.nBitsNoDCT;
nBitsCODA += statSrc.nBitsCODA;
nBitsCBPA += statSrc.nBitsCBPA;
nBitsMODBA += statSrc.nBitsMODBA;
nBitsCBPBA += statSrc.nBitsCBPBA;
nBitsStuffing += statSrc.nBitsStuffing;
nSkipMB += statSrc.nSkipMB;
nInterMB += statSrc.nInterMB;
nInter4VMB += statSrc.nInter4VMB;
nIntraMB += statSrc.nIntraMB;
nDirectMB += statSrc.nDirectMB;
nForwardMB += statSrc.nForwardMB;
nBackwardMB += statSrc.nBackwardMB;
nInterpolateMB += statSrc.nInterpolateMB;
nBitsInterlace += statSrc.nBitsInterlace;
nFieldForwardMB += statSrc.nFieldForwardMB;
nFieldBackwardMB += statSrc.nFieldBackwardMB;
nFieldInterpolateMB += statSrc.nFieldInterpolateMB;
nFieldDirectMB += statSrc.nFieldDirectMB;
nFieldDCTMB += statSrc.nFieldDCTMB;
nVOPs += statSrc.nVOPs;
nBitsMV += statSrc.nBitsMV;
nBitsTexture += statSrc.nBitsTexture;
nBitsShape += statSrc.nBitsShape;
nBitsTotal += statSrc.nBitsTotal;
dSNRY += statSrc.dSNRY;
dSNRU += statSrc.dSNRU;
dSNRV += statSrc.dSNRV;
dSNRA += statSrc.dSNRA;
nQMB += statSrc.nQMB;
nQp += statSrc.nQp;
}
Void CStatistics::reset ()
{
nBitsHead = 0;
nBitsY = 0;
nBitsCr = 0;
nBitsCb = 0;
nBitsA = 0;
// nBits1stShpCode = 0;
nBitsCOD = 0;
nBitsCBPY = 0;
nBitsMCBPC = 0;
nBitsDQUANT = 0;
nBitsMODB = 0;
nBitsCBPB = 0;
nBitsMBTYPE = 0;
nBitsIntraPred = 0;
nBitsNoDCT = 0;
nBitsCODA = 0;
nBitsCBPA = 0;
nBitsMODBA = 0;
nBitsCBPBA = 0;
nBitsStuffing = 0;
nSkipMB = 0;
nInterMB = 0;
nInter4VMB = 0;
nIntraMB = 0;
nDirectMB = 0;
nForwardMB = 0;
nBackwardMB = 0;
nInterpolateMB = 0;
nBitsInterlace = 0;
nFieldForwardMB = 0;
nFieldBackwardMB = 0;
nFieldInterpolateMB = 0;
nFieldDirectMB = 0;
nFieldDCTMB = 0;
nVOPs = 0;
nBitsMV = 0;
nBitsTexture = 0;
nBitsShape = 0;
nBitsTotal = 0;
dSNRY = 0;
dSNRU = 0;
dSNRV = 0;
dSNRA = 0;
nQMB = 0;
nQp = 0;
}
CStatistics& CStatistics::operator = (const CStatistics& statSrc)
{
nBitsHead = statSrc.nBitsHead;
nBitsY = statSrc.nBitsY;
nBitsCr = statSrc.nBitsCr;
nBitsCb = statSrc.nBitsCb;
nBitsA = statSrc.nBitsA;
// nBits1stShpCode = statSrc.nBits1stShpCode;
nBitsCOD = statSrc.nBitsCOD;
nBitsCBPY = statSrc.nBitsCBPY;
nBitsMCBPC = statSrc.nBitsMCBPC;
nBitsDQUANT = statSrc.nBitsDQUANT;
nBitsMODB = statSrc.nBitsMODB;
nBitsCBPB = statSrc.nBitsCBPB;
nBitsMBTYPE = statSrc.nBitsMBTYPE;
nBitsIntraPred = statSrc.nBitsIntraPred;
nBitsNoDCT = statSrc.nBitsNoDCT;
nBitsCODA = statSrc.nBitsCODA;
nBitsCBPA = statSrc.nBitsCBPA;
nBitsMODBA = statSrc.nBitsMODBA;
nBitsCBPBA = statSrc.nBitsCBPBA;
nBitsStuffing = statSrc.nBitsStuffing;
nSkipMB = statSrc.nSkipMB;
nInterMB = statSrc.nInterMB;
nInter4VMB = statSrc.nInter4VMB;
nIntraMB = statSrc.nIntraMB;
nDirectMB = statSrc.nDirectMB;
nForwardMB = statSrc.nForwardMB;
nBackwardMB = statSrc.nBackwardMB;
nInterpolateMB = statSrc.nInterpolateMB;
nBitsInterlace = statSrc.nBitsInterlace;
nFieldForwardMB = statSrc.nFieldForwardMB;
nFieldBackwardMB = statSrc.nFieldBackwardMB;
nFieldInterpolateMB = statSrc.nFieldInterpolateMB;
nFieldDirectMB = statSrc.nFieldDirectMB;
nFieldDCTMB = statSrc.nFieldDCTMB;
nVOPs = statSrc.nVOPs;
nBitsMV = statSrc.nBitsMV;
nBitsTexture = statSrc.nBitsTexture;
nBitsShape = statSrc.nBitsShape;
nBitsTotal = statSrc.nBitsTotal;
dSNRY = statSrc.dSNRY;
dSNRU = statSrc.dSNRU;
dSNRV = statSrc.dSNRV;
dSNRA = statSrc.dSNRA;
nQMB = statSrc.nQMB;
nQp = statSrc.nQp;
return *this;
}
UInt CStatistics::total ()
{
nBitsTexture = nBitsY + nBitsCr + nBitsCb + nBitsA + nBitsCOD
+ nBitsCBPY + nBitsMCBPC + nBitsDQUANT
+ nBitsMODB + nBitsCBPB + nBitsMBTYPE
+ nBitsIntraPred + nBitsNoDCT
+ nBitsInterlace
+ nBitsCODA + nBitsCBPA + nBitsMODBA + nBitsCBPBA;
nBitsTotal = nBitsHead + nBitsTexture + nBitsMV + nBitsShape + nBitsStuffing;
return nBitsTotal;
}
UInt CStatistics::head ()
{
/*
UInt bitsHead = nBitsCr + nBitsCb + nBitsA + nBitsCOD
+ nBitsCBPY + nBitsMCBPC + nBitsDQUANT
+ nBitsMODB + nBitsCBPB + nBitsMBTYPE
+ nBitsIntraPred + nBitsNoDCT
+ nBitsInterlace
+ nBitsCODA + nBitsCBPA + nBitsMODBA + nBitsCBPBA;
bitsHead += nBitsHead + nBitsMV + nBitsShape + nBitsStuffing;
*/
UInt bitsHead = nBitsTotal - nBitsTexture;
return bitsHead;
}
Void CRCMode::reset (UInt uiFirstFrame, UInt uiLastFrame, UInt uiTemporalRate,
UInt uiBufferSize, Double mad, UInt uiBitsFirstFrame, Double dFrameHz)
{
m_Ts = (uiLastFrame - uiFirstFrame + 1) / 30.0;
m_Rs = (UInt) (uiBufferSize / m_Ts);
m_Ns = uiTemporalRate;
m_X1 = m_Rs * m_Ns / 2.0; // 1st order coefficient transient
m_X2 = 0.0; // 2nd order coeeficient transient
m_Nr = (uiLastFrame - uiFirstFrame + 1) / m_Ns - 1;
m_Nc = 0;
m_Rf = uiBitsFirstFrame;
m_Rc = uiBitsFirstFrame;
m_S = uiBitsFirstFrame;
m_Qc = 15;
m_Qp = 15; // a simple solution (assumption)
m_Rr = (UInt) (m_Ts * m_Rs) - m_Rf; // total number of bits available for this segment
m_Rp = m_Rr / m_Nr; // average bits to be removed from the buffer
m_Bs = m_Rs / 2; // assumed buffer size
m_B = m_Rs / 4; // current buffer level containing the bits for first frame
for (UInt i = 0; i < RC_MAX_SLIDING_WINDOW; i++) {// if 0, don't use that frame (rejected outliers)
m_rgQp[i] = 0;
m_rgRp[i] = 0.0;
}
m_Ec = mad;
m_skipNextFrame = FALSE;
}
UInt CRCMode::updateQuanStepsize ()
{
// Target bit calculation
m_T = (UInt) max (m_Rs / 30.0, m_Rr / m_Nr * (1.0 - RC_PAST_PERCENT) + m_S * RC_PAST_PERCENT); // a minimum of Rs/30 is assigned to each frame
m_T = (UInt) (m_T * (m_B + 2.0 * (m_Bs - m_B)) / (2.0 * m_B + (m_Bs - m_B))); // increase if less than half, decrease if more than half, don't change if half
if ((m_B + m_T) > (1.0 - RC_SAFETY_MARGIN) * m_Bs)
m_T = (UInt) max (m_Rs / 30.0, (1.0 - RC_SAFETY_MARGIN) * m_Bs - m_B); // to avoid buffer overflow
else if ((m_B - m_Rp + m_T) < RC_SAFETY_MARGIN * m_Bs)
m_T = m_Rp - m_B + (UInt) (RC_SAFETY_MARGIN * m_Bs); // to avoid buffer underflow
m_T = min (m_T, (UInt)m_Rr);
// Quantization level calculation
m_T = max (m_Rp / 3 + m_Hp, m_T);
Double dtmp = m_Ec * m_X1 * m_Ec * m_X1 + 4 * m_X2 * m_Ec * (m_T - m_Hp);
if ((m_X2 == 0.0) || (dtmp < 0) || ((sqrt (dtmp) - m_X1 * m_Ec) <= 0.0)) // fall back 1st order mode
m_Qc = (UInt) (m_X1 * m_Ec / (Double) (m_T - m_Hp));
else // 2nd order mode
m_Qc = (UInt) ((2 * m_X2 * m_Ec) / (sqrt (dtmp) - m_X1 * m_Ec));
m_Qc = (UInt) min (ceil(m_Qp * (1.0 + RC_MAX_Q_INCREASE)), (Double) m_Qc); // control variation
m_Qc = min (m_Qc, RC_MAX_QUANT); // clipping
m_Qc = (UInt) max (ceil(m_Qp * (1.0 - RC_MAX_Q_INCREASE)), (Double) m_Qc); // control variation
m_Qc = max (m_Qc, RC_MIN_QUANT); // clipping
return m_Qc;
}
Void CRCMode::updateRCModel (UInt uiBitsTotalCurr, UInt uiBitsHeadCurr)
{
UInt n_windowSize;
m_Rc = uiBitsTotalCurr; // total bits used for the current frame
m_B += m_Rc - m_Rp; // update buffer fillness
m_Rr -= m_Rc; // update the remaining bits
if (m_Nr != 1)
assert (m_Rr > 0.0); // check if there is any bits left, except the last frame
m_S = m_Rc; // update the previous bits
m_Hc = uiBitsHeadCurr; // update the current header and motion bits
m_Hp = m_Hc; // update the previous header and motion bits
m_Qp = m_Qc; // update the previous qunatization level
m_Nr--; // update the frame counter
m_Nc++;
Int i;
for (i = RC_MAX_SLIDING_WINDOW - 1; i > 0; i--) {// update the history
m_rgQp[i] = m_rgQp[i - 1];
m_rgRp[i] = m_rgRp[i - 1];
}
m_rgQp[0] = m_Qc;
m_rgRp[0] = (m_Rc - m_Hc) / m_Ec;
n_windowSize = (m_Ep > m_Ec) ? (UInt) (m_Ec / m_Ep * 20) : (UInt) (m_Ep / m_Ec * 20);
n_windowSize = max (n_windowSize, 1);
n_windowSize = min (n_windowSize, m_Nc);
for (i = 0; i < RC_MAX_SLIDING_WINDOW; i++) {
m_rgRejected[i] = FALSE;
}
// initial RD model estimator
RCModelEstimator (n_windowSize);
// remove outlier
Double error[20], std = 0.0, threshold;
for (i = 0; i < (Int) n_windowSize; i++) {
error[i] = m_X1 / m_rgQp[i] + m_X2 / (m_rgQp[i] * m_rgQp[i]) - m_rgRp[i];
std += error[i] * error[i];
}
threshold = (n_windowSize == 2) ? 0 : sqrt (std / n_windowSize);
for (i = 0; i < (Int) n_windowSize; i++) {
if (fabs(error[i]) > threshold)
m_rgRejected[i] = TRUE;
}
// always include the last data point
m_rgRejected[0] = FALSE;
// second RD model estimator
RCModelEstimator (n_windowSize);
}
Bool CRCMode::skipThisFrame ()
{
if (m_B > (Int) ((RC_SKIP_MARGIN / 100.0) * m_Bs)) { // buffer full!
m_skipNextFrame = TRUE; // set the status
m_Nr--; // skip one frame
m_B -= m_Rp; // decrease current buffer level
} else
m_skipNextFrame = FALSE;
return m_skipNextFrame;
}
Void CRCMode::RCModelEstimator (UInt n_windowSize)
{
UInt n_realSize = n_windowSize;
UInt i;
for (i = 0; i < n_windowSize; i++) {// find the number of samples which are not rejected
if (m_rgRejected[i])
n_realSize--;
}
// default RD model estimation results
Bool estimateX2 = FALSE;
m_X1 = m_X2 = 0.0;
Double oneSampleQ = 0.0;
for (i = 0; i < n_windowSize; i++) {
if (!m_rgRejected[i])
oneSampleQ = m_rgQp[i];
}
for (i = 0; i < n_windowSize; i++) {// if all non-rejected Q are the same, take 1st order model
if ((m_rgQp[i] != oneSampleQ) && !m_rgRejected[i])
estimateX2 = TRUE;
if (!m_rgRejected[i])
m_X1 += (m_rgQp[i] * m_rgRp[i]) / n_realSize;
}
// take 2nd order model to estimate X1 and X2
if ((n_realSize >= RC_START_RATE_CONTROL) && estimateX2) {
Double a00 = 0.0, a01 = 0.0, a10 = 0.0, a11 = 0.0, b0 = 0.0, b1 = 0.0;
for (UInt i = 0; i < n_windowSize; i++) {
if (!m_rgRejected[i]) {
a00 = a00 + 1.0;
a01 += 1.0 / m_rgQp[i];
a10 = a01;
a11 += 1.0 / (m_rgQp[i] * m_rgQp[i]);
b0 += m_rgQp[i] * m_rgRp[i];
b1 += m_rgRp[i];
}
}
// solve the equation of AX = B
CMatrix2x2D A = CMatrix2x2D (a00, a01, a10, a11);
CMatrix2x2D AInv = A.inverse ();
CVector2D B = CVector2D (b0, b1);
CVector2D solution = AInv.apply (B);
if (solution.x != 0.0) {
m_X1 = solution.x;
m_X2 = solution.y;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -