blob: 77493422eef665e1166a3aa88eb727e79b21fdb5 [file] [log] [blame]
/* ------------------------------------------------------------------
* Copyright (C) 2008 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#include "avcenc_lib.h"
#include "oscl_base_macros.h"
#include "oscl_math.h"
/* rate control variables */
#define OMEGA 0.9
#define GAMMAP 0.5
#define BETAP 0.5
#define RC_MAX_QUANT 51
#define RC_MIN_QUANT 10 //cap to 10 to prevent rate fluctuation
#define MINVALUE 4.0
#define QP_DELTA 5 //Define the largest variation of quantization parameters
#define QP_DELTA_I 10
#define I_SLICE_BIT_RATIO 1.0 // ratio of I-frame size over P-frame size
#define I_OVER_P_RATIO 3.8
/* local functions */
void RCUpdateRCModel(AVCEncObject *encvid);
double ComputeFrameMAD(AVCCommonObj *video, AVCRateControl *rateCtrl);
void RCModelEstimator(AVCRateControl *rateCtrl, int n_windowSize, bool *m_rgRejected);
void updateMADModel(AVCCommonObj *video, AVCRateControl *rateCtrl);
void MADModelEstimator(AVCCommonObj *video, AVCRateControl *rateCtrl, int n_windowSize,
double *MADPictureC1, double *MADPictureC2, bool *PictureRejected);
double QP2Qstep(int QP);
int Qstep2QP(double Qstep);
AVCEnc_Status RCDetermineFrameNum(AVCEncObject *encvid, AVCRateControl *rateCtrl, uint32 modTime, uint *frameNum)
{
AVCCommonObj *video = encvid->common;
AVCSliceHeader *sliceHdr = video->sliceHdr;
uint32 modTimeRef = encvid->modTimeRef;
int32 currFrameNum ;
int frameInc;
/* check with the buffer fullness to make sure that we have enough bits to encode this frame */
/* we can use a threshold to guarantee minimum picture quality */
/**********************************/
/* for now, the default is to encode every frame, To Be Changed */
if (rateCtrl->first_frame)
{
encvid->modTimeRef = modTime;
encvid->wrapModTime = 0;
encvid->prevFrameNum = 0;
encvid->prevProcFrameNum = 0;
*frameNum = 0;
/* set frame type to IDR-frame */
video->nal_unit_type = AVC_NALTYPE_IDR;
sliceHdr->slice_type = AVC_I_ALL_SLICE;
video->slice_type = AVC_I_SLICE;
return AVCENC_SUCCESS;
}
else
{
if (modTime < modTimeRef) /* modTime wrapped around */
{
encvid->wrapModTime += ((uint32)0xFFFFFFFF - modTimeRef) + 1;
encvid->modTimeRef = modTimeRef = 0;
}
modTime += encvid->wrapModTime; /* wrapModTime is non zero after wrap-around */
currFrameNum = (int32)(((modTime - modTimeRef) * rateCtrl->frame_rate + 200) / 1000); /* add small roundings */
if (currFrameNum <= (int32)video->prevFrameNum || currFrameNum == (int32)encvid->prevProcFrameNum)
{
return AVCENC_FAIL; /* this is a late frame do not encode it */
}
frameInc = currFrameNum - video->prevFrameNum;
RCUpdateBuffer(video, rateCtrl, frameInc); /* in case more frames dropped */
*frameNum = currFrameNum;
/* This part would be similar to DetermineVopType of m4venc */
if ((*frameNum >= (uint)rateCtrl->idrPeriod && rateCtrl->idrPeriod > 0) || *frameNum > video->MaxFrameNum) /* first frame or IDR*/
{
/* set frame type to IDR-frame */
if (rateCtrl->idrPeriod)
{
encvid->modTimeRef += (uint32)(rateCtrl->idrPeriod * 1000 / rateCtrl->frame_rate);
*frameNum -= rateCtrl->idrPeriod;
}
else
{
encvid->modTimeRef += (uint32)(video->MaxFrameNum * 1000 / rateCtrl->frame_rate);
*frameNum -= video->MaxFrameNum;
}
video->nal_unit_type = AVC_NALTYPE_IDR;
sliceHdr->slice_type = AVC_I_ALL_SLICE;
video->slice_type = AVC_I_SLICE;
}
else
{
video->nal_unit_type = AVC_NALTYPE_SLICE;
sliceHdr->slice_type = AVC_P_ALL_SLICE;
video->slice_type = AVC_P_SLICE;
}
encvid->prevProcFrameNum = currFrameNum;
}
return AVCENC_SUCCESS;
}
void RCUpdateBuffer(AVCCommonObj *video, AVCRateControl *rateCtrl, int frameInc)
{
int tmp;
OSCL_UNUSED_ARG(video);
if (rateCtrl->rcEnable == TRUE)
{
if (frameInc > 1)
{
tmp = rateCtrl->bitsPerFrame * (frameInc - 1);
rateCtrl->CurrentBufferFullness -= tmp;
if (rateCtrl->CurrentBufferFullness < 0)
{
rateCtrl->CurrentBufferFullness = 0;
}
}
}
}
AVCEnc_Status InitRateControlModule(AVCHandle *avcHandle)
{
AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
AVCCommonObj *video = encvid->common;
AVCRateControl *rateCtrl = encvid->rateCtrl;
double L1, L2, L3, bpp;
int qp;
int i;
double BufferSize;
rateCtrl->MADofMB = (double*) avcHandle->CBAVC_Malloc(encvid->avcHandle->userData,
video->PicSizeInMbs * sizeof(double), DEFAULT_ATTR);
if (rateCtrl->rcEnable == TRUE)
{
rateCtrl->basicUnit = video->PicSizeInMbs;//video->PicWidthInMbs; // // default
if (rateCtrl->idrPeriod == 1 && rateCtrl->basicUnit < (int)video->PicSizeInMbs) // all I's
{
rateCtrl->basicUnit = video->PicSizeInMbs; // only do frame-level RC for this case
}
rateCtrl->BUCFMAD = (double*) avcHandle->CBAVC_Malloc(encvid->avcHandle->userData,
video->PicHeightInMbs * sizeof(double), DEFAULT_ATTR);
rateCtrl->BUPFMAD = (double*) avcHandle->CBAVC_Malloc(encvid->avcHandle->userData,
video->PicHeightInMbs * sizeof(double), DEFAULT_ATTR);
if (!rateCtrl->MADofMB || !rateCtrl->BUCFMAD || !rateCtrl->BUPFMAD)
{
CleanupRateControlModule(avcHandle);
return AVCENC_MEMORY_FAIL;
}
/// at the sequence level
if (rateCtrl->basicUnit > (int)video->PicSizeInMbs)
rateCtrl->basicUnit = video->PicSizeInMbs;
if (rateCtrl->basicUnit < (int)video->PicSizeInMbs)
rateCtrl->TotalNumberofBasicUnit = video->PicSizeInMbs / rateCtrl->basicUnit;
/*initialize the parameters of fluid flow traffic model*/
rateCtrl->bitsPerFrame = (int32)(rateCtrl->bitRate / rateCtrl->frame_rate);
BufferSize = rateCtrl->cpbSize;
//BufferSize = rateCtrl->bitRate * 2.56; // for testing
rateCtrl->CurrentBufferFullness = 0;
/*HRD consideration*/
rateCtrl->initDelayOffset = (int32)(BufferSize * 0.8); // for testing
/*initialize the previous window size*/
rateCtrl->m_windowSize = 0;
rateCtrl->MADm_windowSize = 0;
rateCtrl->NumberofCodedPFrame = 0;
rateCtrl->NumberofGOP = 0;
/*remaining # of bits in GOP */
rateCtrl->R = 0;
/*quadratic rate-distortion model*/
rateCtrl->PPreHeader = 0;
rateCtrl->m_X1 = rateCtrl->bitRate * 1.0;
rateCtrl->m_X2 = 0.0;
/* linear prediction model for P picture*/
rateCtrl->PMADPictureC1 = 1.0;
rateCtrl->PMADPictureC2 = 0.0;
for (i = 0;i < 20;i++)
{
rateCtrl->m_rgQp[i] = 0;
rateCtrl->m_rgRp[i] = 0.0;
rateCtrl->PPictureMAD[i] = 0.0;
}
rateCtrl->PPictureMAD[20] = 0.0;
/*basic unit layer rate control*/
rateCtrl->PAveHeaderBits1 = 0;
rateCtrl->PAveHeaderBits3 = 0;
if (rateCtrl->TotalNumberofBasicUnit >= 9)
rateCtrl->DDquant = 1;
else
rateCtrl->DDquant = 2;
/*compute the initial QP*/
bpp = 1.0 * rateCtrl->bitRate / (rateCtrl->frame_rate * (video->PicSizeInMbs << 8));
if (video->PicWidthInSamplesL == 176)
{
L1 = 0.1;
L2 = 0.3;
L3 = 0.6;
}
else if (video->PicWidthInSamplesL == 352)
{
L1 = 0.2;
L2 = 0.6;
L3 = 1.2;
}
else
{
L1 = 0.6;
L2 = 1.4;
L3 = 2.4;
}
if (rateCtrl->initQP == 0)
{
if (bpp <= L1)
qp = 35;
else
if (bpp <= L2)
qp = 25;
else
if (bpp <= L3)
qp = 20;
else
qp = 15;
rateCtrl->initQP = qp;
}
rateCtrl->PAveFrameQP = rateCtrl->initQP;
}
return AVCENC_SUCCESS;
}
void CleanupRateControlModule(AVCHandle *avcHandle)
{
AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
AVCRateControl *rateCtrl = encvid->rateCtrl;
if (rateCtrl->MADofMB)
{
avcHandle->CBAVC_Free(avcHandle->userData, (int)(rateCtrl->MADofMB));
}
if (rateCtrl->BUCFMAD)
{
avcHandle->CBAVC_Free(avcHandle->userData, (int)(rateCtrl->BUCFMAD));
}
if (rateCtrl->BUPFMAD)
{
avcHandle->CBAVC_Free(avcHandle->userData, (int)(rateCtrl->BUPFMAD));
}
return ;
}
void RCInitGOP(AVCEncObject *encvid)
{
AVCCommonObj *video = encvid->common;
AVCRateControl *rateCtrl = encvid->rateCtrl;
int np = rateCtrl->idrPeriod - 1;
bool Overum = FALSE;
int OverBits;
int OverDuantQp;
int AllocatedBits;
int GOPDquant;
int PAverageQp;
OsclFloat denom, numer;
bool initGOP = TRUE;
if (rateCtrl->rcEnable == TRUE)
{
/*** additional part from JM12.4 RC3 ****/
if (np < 0)
{
np = video->MaxFrameNum - 1; // IPPPPPP
}
else if (np == 0)
{
np = (1 << 16) - 1; // IIIIIII
if (rateCtrl->first_frame == FALSE)
{
initGOP = FALSE;
}
}
if (initGOP == TRUE)
{
numer = (OsclFloat)((np + 1) * rateCtrl->bitsPerFrame);
denom = (OsclFloat)((np + 1) + I_SLICE_BIT_RATIO - 1);
rateCtrl->RCPSliceBits = (int)(numer / denom + 0.5);
rateCtrl->RCISliceBits = (np == 0) ? (int)(I_SLICE_BIT_RATIO * rateCtrl->RCPSliceBits + 0.5) : 0;
/* check if the last GOP over uses its budget. If yes, the initial QP of the I frame in
the coming GOP will be increased.*/
if (rateCtrl->R < 0)
Overum = TRUE;
OverBits = -rateCtrl->R;
/*initialize the lower bound and the upper bound for the target bits of each frame, HRD consideration*/
rateCtrl->LowerBound = (int32)(rateCtrl->R + rateCtrl->bitsPerFrame);
rateCtrl->UpperBound1 = (int32)(rateCtrl->R + rateCtrl->initDelayOffset);
/*compute the total number of bits for the current GOP*/
AllocatedBits = (int)((1 + np) * rateCtrl->bitsPerFrame);
rateCtrl->R += AllocatedBits;
rateCtrl->Np = np;
OverDuantQp = (int)(8 * OverBits / AllocatedBits + 0.5);
rateCtrl->GOPOverdue = FALSE;
/*Compute InitialQp for each GOP*/
rateCtrl->NumberofGOP++;
if (rateCtrl->NumberofGOP == 1)
{
//rateCtrl->QPLastGOP = rateCtrl->initQP ; this causes too much quality fluctuation in I-frame
}
else
{
/*compute the average QP of P frames in the previous GOP*/
PAverageQp = (int)(1.0 * rateCtrl->TotalQpforPPicture / rateCtrl->NumberofPPicture + 0.5);
GOPDquant = (int)(0.5 + 1.0 * (np + 1) / 15);
if (GOPDquant > 2)
GOPDquant = 2;
PAverageQp -= GOPDquant;
if (rateCtrl->basicUnit < (int)video->PicSizeInMbs)
{
if (PAverageQp > (int)(rateCtrl->QPLastPFrame - 2))
PAverageQp--;
// this clipping causes too much quality fluctuation in I-frame
//PAverageQp = AVC_MAX(rateCtrl->QPLastGOP-2, PAverageQp);
//PAverageQp = AVC_MIN(rateCtrl->QPLastGOP+2, PAverageQp);
PAverageQp = AVC_MIN(RC_MAX_QUANT, PAverageQp);
PAverageQp = AVC_MAX(RC_MIN_QUANT, PAverageQp);
}
//rateCtrl->QPLastGOP =
rateCtrl->initQP = PAverageQp;
rateCtrl->Pm_Qp = PAverageQp;
rateCtrl->PAveFrameQP = PAverageQp;
}
rateCtrl->TotalQpforPPicture = 0;
rateCtrl->NumberofPPicture = 0;
}
}
return ;
}
void RCInitFrameQP(AVCEncObject *encvid)
{
AVCCommonObj *video = encvid->common;
AVCRateControl *rateCtrl = encvid->rateCtrl;
AVCPicParamSet *picParam = video->currPicParams;
int i;
int32 T = 0, T1 = 0;
int32 UpperBound;
int np = rateCtrl->idrPeriod - 1; // TotalPFrame
int bits;
if (rateCtrl->rcEnable == TRUE)
{
if (np < 0) np = video->MaxFrameNum - 1; // IPPPPP case
else if (np == 0) np = (1 << 16) - 1;
rateCtrl->NumberofCodedMacroBlocks = 0;
if ((video->slice_type == AVC_P_SLICE) || (rateCtrl->idrPeriod == 1 && rateCtrl->first_frame == FALSE))
{
/* predefine the target buffer level for each picture.
frame layer rate control */
if (rateCtrl->basicUnit == (int)video->PicSizeInMbs)
{
if (rateCtrl->NumberofPPicture == 1)
{
rateCtrl->TargetBufferLevel = rateCtrl->CurrentBufferFullness;
rateCtrl->DeltaP = rateCtrl->CurrentBufferFullness / (np - 1);
rateCtrl->TargetBufferLevel -= (int)rateCtrl->DeltaP;
}
else if (rateCtrl->NumberofPPicture > 1)
rateCtrl->TargetBufferLevel -= (int)rateCtrl->DeltaP;
}
/* basic unit layer rate control */
else
{
if (rateCtrl->NumberofCodedPFrame > 0)
{
for (i = 0;i < rateCtrl->TotalNumberofBasicUnit;i++)
rateCtrl->BUPFMAD[i] = rateCtrl->BUCFMAD[i];
}
if (rateCtrl->NumberofGOP == 1)
{
if (rateCtrl->NumberofPPicture == 1)
{
rateCtrl->TargetBufferLevel = rateCtrl->CurrentBufferFullness;
rateCtrl->DeltaP = rateCtrl->CurrentBufferFullness / (np - 1);
rateCtrl->TargetBufferLevel -= (int)rateCtrl->DeltaP;
}
else if (rateCtrl->NumberofPPicture > 1)
rateCtrl->TargetBufferLevel -= (int)rateCtrl->DeltaP;
}
else if (rateCtrl->NumberofGOP > 1)
{
if (rateCtrl->NumberofPPicture == 0)
{
rateCtrl->TargetBufferLevel = rateCtrl->CurrentBufferFullness;
rateCtrl->DeltaP = rateCtrl->CurrentBufferFullness / np;
rateCtrl->TargetBufferLevel -= (int)rateCtrl->DeltaP;
}
else if (rateCtrl->NumberofPPicture > 0)
rateCtrl->TargetBufferLevel -= (int)rateCtrl->DeltaP;
}
}
}
/* additional code from RC3 */
if (video->slice_type == AVC_P_SLICE || rateCtrl->first_frame == 0)
{
if (rateCtrl->NumberofCodedPFrame > 0)
{
if (rateCtrl->idrPeriod == 1) // all I frames
{
T = rateCtrl->R / (rateCtrl->Np + 1); // ratio
T1 = (int32)(rateCtrl->bitsPerFrame - GAMMAP * (rateCtrl->CurrentBufferFullness - rateCtrl->TargetBufferLevel) + 0.5);
T1 = AVC_MAX(0, T1);
T = (int32)(BETAP * T + (1.0 - BETAP) * T1 + 0.5);
}
else
{
bits = (video->slice_type == AVC_P_SLICE) ? rateCtrl->RCPSliceBits : rateCtrl->RCISliceBits;
// this part deviates from the JM code */
T = (bits * rateCtrl->R) / (rateCtrl->bitsPerFrame * (rateCtrl->Np + 1)); // ratio
if (video->slice_type == AVC_I_SLICE)
{
T = (int32)(T / (I_OVER_P_RATIO * 4));
}
else
{
T1 = (int32)(rateCtrl->bitsPerFrame - GAMMAP * (rateCtrl->CurrentBufferFullness - rateCtrl->TargetBufferLevel) + 0.5);
T1 = AVC_MAX(0, T1);
T = (int32)(BETAP * T + (1.0 - BETAP) * T1 + 0.5);
}
}
}
/* reserve some bits for smoothing, commented out */
/* HRD consideration */
if (video->slice_type == AVC_P_SLICE || rateCtrl->idrPeriod == 1)
{
UpperBound = (int32)(OMEGA * rateCtrl->UpperBound1);
T = AVC_MAX(T, rateCtrl->LowerBound);
rateCtrl->T = AVC_MIN(T, UpperBound);
}
else
{
rateCtrl->T = T;
}
}
/* frame layer rate control */
rateCtrl->NumberofHeaderBits = 0;
rateCtrl->NumberofTextureBits = 0;
/* basic unit layer rate control */
if (rateCtrl->basicUnit < (int)video->PicSizeInMbs)
{
rateCtrl->TotalFrameQP = 0;
rateCtrl->NumberofBasicUnitHeaderBits = 0;
rateCtrl->NumberofBasicUnitTextureBits = 0;
rateCtrl->TotalMADBasicUnit = 0;
rateCtrl->NumberofBasicUnit = rateCtrl->TotalNumberofBasicUnit;
}
video->QPy = rateCtrl->m_Qc = rateCtrl->PAveFrameQP = RCCalculateQP(encvid, rateCtrl);
rateCtrl->numFrameBits = 0; // reset
} // rcEnable
else
{
video->QPy = rateCtrl->initQP;
}
// printf(" %d ",video->QPy);
if (video->CurrPicNum == 0 && encvid->outOfBandParamSet == FALSE)
{
picParam->pic_init_qs_minus26 = 0;
picParam->pic_init_qp_minus26 = video->QPy - 26;
}
// need this for motion estimation
encvid->lambda_mode = QP2QUANT[AVC_MAX(0,video->QPy-SHIFT_QP)];
encvid->lambda_motion = LAMBDA_FACTOR(encvid->lambda_mode);
return ;
}
int RCCalculateQP(AVCEncObject *encvid, AVCRateControl *rateCtrl)
{
AVCCommonObj *video = encvid->common;
double dtmp;
int m_Bits;
int PAverageQP;
int SumofBasicUnit;
int i;
double sqrt_dtmp;
double PreviousPictureMAD;
double MADPictureC1;
double MADPictureC2;
double m_X1 = rateCtrl->m_X1;
double m_X2 = rateCtrl->m_X2;
int m_Qc ;
double m_Qstep;
int m_Qp;
double CurrentBUMAD;
double TotalBUMAD;
int m_Hp;
int TotalBasicUnitBits;
int np = rateCtrl->idrPeriod - 1;
if (np < 0) np = video->MaxFrameNum - 1; // IPPPPP case
else if (np == 0) np = (1 << 16) - 1; // IIIIII case
int Qstep2QP(double Qstep);
/* frame layer rate control */
if (rateCtrl->basicUnit == (int)video->PicSizeInMbs || (video->slice_type != AVC_P_SLICE && rateCtrl->idrPeriod == 1)) // I_slice for basic unit comes here too
{
if (rateCtrl->first_frame) //(video->slice_type==AVC_I_SLICE)
{
m_Qc = rateCtrl->initQP;
rateCtrl->Pm_Qp = m_Qc;
return m_Qc;
}
else if ((rateCtrl->first_frame == FALSE) && (rateCtrl->NumberofPPicture == 0)) /* first P-frame */
{
m_Qc = rateCtrl->initQP;
//if(active_sps->frame_mbs_only_flag)
rateCtrl->TotalQpforPPicture += m_Qc;
rateCtrl->Pm_Qp = m_Qc;
return m_Qc;
}
else /* subsequent frames */
{
MADPictureC1 = rateCtrl->PMADPictureC1;
MADPictureC2 = rateCtrl->PMADPictureC2;
PreviousPictureMAD = rateCtrl->PPictureMAD[0];
m_Qp = rateCtrl->Pm_Qp;
m_Hp = rateCtrl->PPreHeader;
if (rateCtrl->basicUnit < (int)video->PicSizeInMbs && video->slice_type != AVC_P_SLICE)
{
PreviousPictureMAD = rateCtrl->PreviousWholeFrameMAD;
}
if (video->slice_type == AVC_I_SLICE)
{
m_Hp = 0;
}
/* predict the MAD of current picture*/
rateCtrl->CurrentFrameMAD = MADPictureC1 * PreviousPictureMAD + MADPictureC2;
/*compute the number of bits for the texture*/
if (rateCtrl->T < 0) /* if target bits is already below zero, just increase Qp */
{
m_Qc = m_Qp + QP_DELTA;
m_Qc = AVC_MIN(m_Qc, RC_MAX_QUANT); // clipping
}
else /* get QP from R-Q model */
{
if (video->slice_type != AVC_P_SLICE && rateCtrl->idrPeriod != 1)
{
if (rateCtrl->basicUnit < (int)video->PicSizeInMbs)
{
m_Bits = (rateCtrl->T - m_Hp) / rateCtrl->TotalNumberofBasicUnit;
}
else
{
m_Bits = rateCtrl->T - m_Hp;
}
}
else
{
m_Bits = rateCtrl->T - m_Hp;
m_Bits = AVC_MAX(m_Bits, (int)(rateCtrl->bitsPerFrame / MINVALUE));
}
dtmp = rateCtrl->CurrentFrameMAD * m_X1 * rateCtrl->CurrentFrameMAD * m_X1 \
+ 4 * m_X2 * rateCtrl->CurrentFrameMAD * m_Bits;
if (dtmp > 0) sqrt_dtmp = oscl_sqrt(dtmp);
else sqrt_dtmp = 0.0;
if ((m_X2 == 0.0) || (dtmp < 0) || ((sqrt_dtmp - m_X1 * rateCtrl->CurrentFrameMAD) <= 0.0)) // fall back 1st order mode
m_Qstep = (float)(m_X1 * rateCtrl->CurrentFrameMAD / (double) m_Bits);
else // 2nd order mode
m_Qstep = (float)((2 * m_X2 * rateCtrl->CurrentFrameMAD) / (sqrt_dtmp - m_X1 * rateCtrl->CurrentFrameMAD));
m_Qc = Qstep2QP(m_Qstep);
m_Qc = AVC_MIN(m_Qc, RC_MAX_QUANT); // clipping
m_Qc = AVC_MAX(RC_MIN_QUANT, m_Qc);
if (video->slice_type == AVC_P_SLICE)
{
m_Qc = AVC_MIN(m_Qp + QP_DELTA, m_Qc); // control variation
m_Qc = AVC_MAX(m_Qp - QP_DELTA, m_Qc); // control variation
}
else
{
m_Qc = AVC_MIN(m_Qp + QP_DELTA_I, m_Qc); // control variation
m_Qc = AVC_MAX(m_Qp - QP_DELTA_I, m_Qc); // control variation
}
}
rateCtrl->TotalQpforPPicture += m_Qc;
rateCtrl->Pm_Qp = m_Qc;
return m_Qc;
}
}
/**********basic unit layer rate control*********/
else
{
if (rateCtrl->first_frame) //(video->slice_type==AVC_I_SLICE)
{
m_Qc = rateCtrl->initQP;
rateCtrl->Pm_Qp = m_Qc;
return m_Qc;
}
else //if(video->slice_type==AVC_P_SLICE)
{
if ((rateCtrl->NumberofGOP == 1) && (rateCtrl->NumberofPPicture == 0))
{
/*top field of the first P frame*/
m_Qc = rateCtrl->initQP;
rateCtrl->NumberofBasicUnitHeaderBits = 0;
rateCtrl->NumberofBasicUnitTextureBits = 0;
rateCtrl->NumberofBasicUnit--;
/*bottom field of the first P frame*/
if (rateCtrl->NumberofBasicUnit == 0)
{
rateCtrl->TotalQpforPPicture += m_Qc;
rateCtrl->PAveFrameQP = m_Qc;
rateCtrl->PAveHeaderBits3 = rateCtrl->PAveHeaderBits2;
}
rateCtrl->Pm_Qp = m_Qc;
rateCtrl->TotalFrameQP += m_Qc;
return m_Qc;
}
else /* subsequent P-frames */
{
m_Hp = rateCtrl->PPreHeader;
m_Qp = rateCtrl->Pm_Qp;
MADPictureC1 = rateCtrl->PMADPictureC1;
MADPictureC2 = rateCtrl->PMADPictureC2;
SumofBasicUnit = rateCtrl->TotalNumberofBasicUnit;
/*the average QP of the previous frame is used to coded the first basic unit of the current frame or field*/
if (rateCtrl->NumberofBasicUnit == SumofBasicUnit)
{
if (rateCtrl->T <= 0)
{
m_Qc = rateCtrl->PAveFrameQP + 2;
if (m_Qc > RC_MAX_QUANT)
m_Qc = RC_MAX_QUANT;
rateCtrl->GOPOverdue = TRUE;
}
else
{
m_Qc = rateCtrl->PAveFrameQP;
}
rateCtrl->TotalFrameQP += m_Qc;
rateCtrl->NumberofBasicUnit--;
rateCtrl->Pm_Qp = rateCtrl->PAveFrameQP;
return m_Qc;
}
else
{
/*compute the number of remaining bits*/
TotalBasicUnitBits = rateCtrl->NumberofBasicUnitHeaderBits + rateCtrl->NumberofBasicUnitTextureBits;
rateCtrl->T -= TotalBasicUnitBits;
rateCtrl->NumberofBasicUnitHeaderBits = 0;
rateCtrl->NumberofBasicUnitTextureBits = 0;
if (rateCtrl->T < 0)
{
if (rateCtrl->GOPOverdue == TRUE)
m_Qc = m_Qp + 2;
else
m_Qc = m_Qp + rateCtrl->DDquant;//2
m_Qc = AVC_MIN(m_Qc, RC_MAX_QUANT); // clipping
if (rateCtrl->basicUnit >= (int)video->PicWidthInMbs)
m_Qc = AVC_MIN(m_Qc, rateCtrl->PAveFrameQP + 6);
else
m_Qc = AVC_MIN(m_Qc, rateCtrl->PAveFrameQP + 3);
rateCtrl->TotalFrameQP += m_Qc;
rateCtrl->NumberofBasicUnit--;
if (rateCtrl->NumberofBasicUnit == 0)
{
PAverageQP = (int)(1.0 * rateCtrl->TotalFrameQP / rateCtrl->TotalNumberofBasicUnit + 0.5);
if (rateCtrl->NumberofPPicture == (np - 1))
rateCtrl->QPLastPFrame = PAverageQP;
rateCtrl->TotalQpforPPicture += PAverageQP;
rateCtrl->PAveFrameQP = PAverageQP;
rateCtrl->PAveHeaderBits3 = rateCtrl->PAveHeaderBits2;
}
if (rateCtrl->GOPOverdue == TRUE)
rateCtrl->Pm_Qp = rateCtrl->PAveFrameQP;
else
rateCtrl->Pm_Qp = m_Qc;
return m_Qc;
}
else
{
/*predict the MAD of current picture*/
rateCtrl->CurrentFrameMAD = MADPictureC1 * rateCtrl->BUPFMAD[rateCtrl->TotalNumberofBasicUnit-rateCtrl->NumberofBasicUnit] + MADPictureC2;
TotalBUMAD = 0;
for (i = rateCtrl->TotalNumberofBasicUnit - 1; i >= (rateCtrl->TotalNumberofBasicUnit - rateCtrl->NumberofBasicUnit);i--)
{
CurrentBUMAD = MADPictureC1 * rateCtrl->BUPFMAD[i] + MADPictureC2;
TotalBUMAD += CurrentBUMAD * CurrentBUMAD;
}
/*compute the total number of bits for the current basic unit*/
m_Bits = (int)(rateCtrl->T * rateCtrl->CurrentFrameMAD * rateCtrl->CurrentFrameMAD / TotalBUMAD);
/*compute the number of texture bits*/
m_Bits -= rateCtrl->PAveHeaderBits2;
m_Bits = AVC_MAX(m_Bits, (int)(rateCtrl->bitsPerFrame / (MINVALUE * rateCtrl->TotalNumberofBasicUnit)));
dtmp = rateCtrl->CurrentFrameMAD * m_X1 * rateCtrl->CurrentFrameMAD * m_X1 \
+ 4 * m_X2 * rateCtrl->CurrentFrameMAD * m_Bits;
if ((m_X2 == 0.0) || (dtmp < 0) || ((oscl_sqrt(dtmp) - m_X1 * rateCtrl->CurrentFrameMAD) <= 0.0)) // fall back 1st order mode
m_Qstep = (float)(m_X1 * rateCtrl->CurrentFrameMAD / (double) m_Bits);
else // 2nd order mode
m_Qstep = (float)((2 * m_X2 * rateCtrl->CurrentFrameMAD) / (oscl_sqrt(dtmp) - m_X1 * rateCtrl->CurrentFrameMAD));
m_Qc = Qstep2QP(m_Qstep);
m_Qc = AVC_MIN(m_Qp + rateCtrl->DDquant, m_Qc); // control variation
if (rateCtrl->basicUnit >= (int)video->PicWidthInMbs)
m_Qc = AVC_MIN(rateCtrl->PAveFrameQP + 6, m_Qc);
else
m_Qc = AVC_MIN(rateCtrl->PAveFrameQP + 3, m_Qc);
m_Qc = AVC_MIN(m_Qc, RC_MAX_QUANT); // clipping
m_Qc = AVC_MAX(m_Qp - rateCtrl->DDquant, m_Qc); // control variation
if (rateCtrl->basicUnit >= (int)video->PicWidthInMbs)
m_Qc = AVC_MAX(rateCtrl->PAveFrameQP - 6, m_Qc);
else
m_Qc = AVC_MAX(rateCtrl->PAveFrameQP - 3, m_Qc);
m_Qc = AVC_MAX(RC_MIN_QUANT, m_Qc);
rateCtrl->TotalFrameQP += m_Qc;
rateCtrl->Pm_Qp = m_Qc;
rateCtrl->NumberofBasicUnit--;
if ((rateCtrl->NumberofBasicUnit == 0) && (video->slice_type == AVC_P_SLICE))
{
/*frame coding or field coding*/
PAverageQP = (int)(1.0 * rateCtrl->TotalFrameQP / rateCtrl->TotalNumberofBasicUnit + 0.5);
if (rateCtrl->NumberofPPicture == (np - 1))
rateCtrl->QPLastPFrame = PAverageQP;
rateCtrl->TotalQpforPPicture += PAverageQP;
rateCtrl->PAveFrameQP = PAverageQP;
rateCtrl->PAveHeaderBits3 = rateCtrl->PAveHeaderBits2;
}
return m_Qc;
}
}
} /* subsequent P-frames */
} /* AVC_P_SLICE */
}
return m_Qc;
}
void RCInitChromaQP(AVCEncObject *encvid)
{
AVCCommonObj *video = encvid->common;
AVCMacroblock *currMB = video->currMB;
int q_bits;
/* we have to do the same thing for AVC_CLIP3(0,51,video->QSy) */
video->QPy_div_6 = (currMB->QPy * 43) >> 8;
video->QPy_mod_6 = currMB->QPy - 6 * video->QPy_div_6;
currMB->QPc = video->QPc = mapQPi2QPc[AVC_CLIP3(0,51,currMB->QPy + video->currPicParams->chroma_qp_index_offset)];
video->QPc_div_6 = (video->QPc * 43) >> 8;
video->QPc_mod_6 = video->QPc - 6 * video->QPc_div_6;
/* pre-calculate this to save computation */
q_bits = 4 + video->QPy_div_6;
if (video->slice_type == AVC_I_SLICE)
{
encvid->qp_const = 682 << q_bits; // intra
}
else
{
encvid->qp_const = 342 << q_bits; // inter
}
q_bits = 4 + video->QPc_div_6;
if (video->slice_type == AVC_I_SLICE)
{
encvid->qp_const_c = 682 << q_bits; // intra
}
else
{
encvid->qp_const_c = 342 << q_bits; // inter
}
encvid->lambda_mode = QP2QUANT[AVC_MAX(0,currMB->QPy-SHIFT_QP)];
encvid->lambda_motion = LAMBDA_FACTOR(encvid->lambda_mode);
return ;
}
void RCInitMBQP(AVCEncObject *encvid)
{
AVCCommonObj *video = encvid->common;
AVCRateControl *rateCtrl = encvid->rateCtrl;
AVCMacroblock *currMB = video->currMB;
currMB->QPy = video->QPy; /* set to previous value or picture level */
if (rateCtrl->rcEnable == TRUE)
{
if (((video->slice_type == AVC_P_SLICE) || (rateCtrl->idrPeriod == 1 && rateCtrl->first_frame == FALSE)) && (rateCtrl->NumberofCodedMacroBlocks > 0)
&& (rateCtrl->NumberofCodedMacroBlocks % rateCtrl->basicUnit == 0))
{
RCUpdateRCModel(encvid);
currMB->QPy = rateCtrl->m_Qc = RCCalculateQP(encvid, rateCtrl);
}
}
RCInitChromaQP(encvid);
}
void RCCalculateMAD(AVCEncObject *encvid, AVCMacroblock *currMB, uint8 *orgL, int orgPitch)
{
AVCCommonObj *video = encvid->common;
AVCRateControl *rateCtrl = encvid->rateCtrl;
uint32 dmin_lx;
if (rateCtrl->rcEnable == TRUE)
{
if (currMB->mb_intra)
{
if (currMB->mbMode == AVC_I16)
{
dmin_lx = (0xFFFF << 16) | orgPitch;
rateCtrl->MADofMB[video->mbNum] = AVCSAD_Macroblock_C(orgL,
encvid->pred_i16[currMB->i16Mode], dmin_lx, NULL);
}
else /* i4 */
{
rateCtrl->MADofMB[video->mbNum] = encvid->i4_sad / 256.;
}
}
/* for INTER, we have already saved it with the MV search */
if (rateCtrl->basicUnit < (int)video->PicSizeInMbs)
{
rateCtrl->TotalMADBasicUnit += rateCtrl->MADofMB[video->mbNum];
}
}
return ;
}
void RCRestoreQP(AVCMacroblock *currMB, AVCCommonObj *video, AVCEncObject *encvid)
{
currMB->QPy = video->QPy; /* use previous QP */
RCInitChromaQP(encvid);
return ;
}
AVCEnc_Status RCUpdateFrame(AVCEncObject *encvid)
{
AVCCommonObj *video = encvid->common;
AVCRateControl *rateCtrl = encvid->rateCtrl;
AVCEnc_Status status = AVCENC_SUCCESS;
int nbits = rateCtrl->numFrameBits;
int32 tmp;
/* update the complexity weight of I, P, B frame */
int Avem_Qc;
int X = 0;
if (rateCtrl->rcEnable == TRUE)
{
/* frame layer rate control */
if (rateCtrl->basicUnit == (int)video->PicSizeInMbs)
X = (int)(nbits * rateCtrl->m_Qc + 0.5);
/* basic unit layer rate control */
else
{
if (video->slice_type == AVC_P_SLICE)
{
Avem_Qc = rateCtrl->TotalFrameQP / rateCtrl->TotalNumberofBasicUnit;
X = (int)(nbits * Avem_Qc + 0.5);
}
}
if (video->slice_type == AVC_P_SLICE || (rateCtrl->idrPeriod == 1))
{
rateCtrl->Np--;
rateCtrl->Wp = X;
rateCtrl->NumberofCodedPFrame++;
rateCtrl->NumberofPPicture++;
}
tmp = (int32)(rateCtrl->bitsPerFrame - nbits);
rateCtrl->CurrentBufferFullness -= tmp;
#if 1 // this part may not be necessary
if (rateCtrl->CurrentBufferFullness > rateCtrl->cpbSize*0.8 && video->slice_type != AVC_I_SLICE) /* skip current frame */
{
rateCtrl->curr_skip = 1;
rateCtrl->CurrentBufferFullness += tmp;
status = AVCENC_SKIPPED_PICTURE;
}
else
{
rateCtrl->curr_skip = 0;
/*update the lower bound and the upper bound for the target bits of each frame, HRD consideration*/
rateCtrl->R -= nbits; /* remaining # of bits in GOP */
rateCtrl->LowerBound += tmp;
rateCtrl->UpperBound1 += tmp;
}
#endif
if (video->slice_type == AVC_P_SLICE || (rateCtrl->idrPeriod == 1/* && !rateCtrl->first_frame*/))
{
RCUpdateRCModel(encvid);
rateCtrl->PreviousWholeFrameMAD = ComputeFrameMAD(video, rateCtrl);
}
}
rateCtrl->first_frame = 0; // reset here after we encode the first frame.
return status;
}
void RCUpdateRCModel(AVCEncObject *encvid)
{
AVCCommonObj *video = encvid->common;
AVCRateControl *rateCtrl = encvid->rateCtrl;
int n_windowSize;
int i;
double error[20], std = 0.0, threshold;
int m_Nc;
bool MADModelFlag = FALSE;
bool m_rgRejected[21];
int CodedBasicUnit;
/*frame layer rate control*/
if (rateCtrl->basicUnit == (int)video->PicSizeInMbs)
{
rateCtrl->CurrentFrameMAD = ComputeFrameMAD(video, rateCtrl);
m_Nc = rateCtrl->NumberofCodedPFrame;
}
/*basic unit layer rate control*/
else
{
/*compute the MAD of the current basic unit*/
rateCtrl->CurrentFrameMAD = rateCtrl->TotalMADBasicUnit / rateCtrl->basicUnit;
rateCtrl->TotalMADBasicUnit = 0;
/* compute the average number of header bits*/
CodedBasicUnit = rateCtrl->TotalNumberofBasicUnit - rateCtrl->NumberofBasicUnit;
if (CodedBasicUnit > 0)
{
rateCtrl->PAveHeaderBits1 = (int)(1.0 * (rateCtrl->PAveHeaderBits1 * (CodedBasicUnit - 1) + \
+ rateCtrl->NumberofBasicUnitHeaderBits) / CodedBasicUnit + 0.5);
if (rateCtrl->PAveHeaderBits3 == 0)
rateCtrl->PAveHeaderBits2 = rateCtrl->PAveHeaderBits1;
else
rateCtrl->PAveHeaderBits2 = (int)(1.0 * (rateCtrl->PAveHeaderBits1 * CodedBasicUnit + \
+ rateCtrl->PAveHeaderBits3 * rateCtrl->NumberofBasicUnit) / rateCtrl->TotalNumberofBasicUnit + 0.5);
}
/*update the record of MADs for reference*/
rateCtrl->BUCFMAD[rateCtrl->TotalNumberofBasicUnit-1-rateCtrl->NumberofBasicUnit] = rateCtrl->CurrentFrameMAD;
if (rateCtrl->NumberofBasicUnit != 0)
m_Nc = rateCtrl->NumberofCodedPFrame * rateCtrl->TotalNumberofBasicUnit + CodedBasicUnit;
else
m_Nc = (rateCtrl->NumberofCodedPFrame - 1) * rateCtrl->TotalNumberofBasicUnit + CodedBasicUnit;
}
if (m_Nc > 1)
MADModelFlag = TRUE;
rateCtrl->PPreHeader = rateCtrl->NumberofHeaderBits;
for (i = 19; i > 0; i--)
{// update the history
rateCtrl->m_rgQp[i] = rateCtrl->m_rgQp[i - 1];
rateCtrl->m_rgRp[i] = rateCtrl->m_rgRp[i - 1];
}
rateCtrl->m_rgQp[0] = QP2Qstep(rateCtrl->m_Qc); //*1.0/rateCtrl->CurrentFrameMAD;
/*frame layer rate control*/
if (rateCtrl->basicUnit == (int)video->PicSizeInMbs)
rateCtrl->m_rgRp[0] = rateCtrl->NumberofTextureBits * 1.0 / rateCtrl->CurrentFrameMAD;
/*basic unit layer rate control*/
else
rateCtrl->m_rgRp[0] = rateCtrl->NumberofBasicUnitTextureBits * 1.0 / rateCtrl->CurrentFrameMAD;
/*compute the size of window*/
n_windowSize = (rateCtrl->CurrentFrameMAD > rateCtrl->PreviousFrameMAD) ? (int)(rateCtrl->PreviousFrameMAD / rateCtrl->CurrentFrameMAD * 20)\
: (int)(rateCtrl->CurrentFrameMAD / rateCtrl->PreviousFrameMAD * 20);
n_windowSize = AVC_MAX(n_windowSize, 1);
n_windowSize = AVC_MIN(n_windowSize, m_Nc);
n_windowSize = AVC_MIN(n_windowSize, rateCtrl->m_windowSize + 1);
n_windowSize = AVC_MIN(n_windowSize, 20);
/*update the previous window size*/
rateCtrl->m_windowSize = n_windowSize;
for (i = 0; i < 20; i++)
{
m_rgRejected[i] = FALSE;
}
// initial RD model estimator
RCModelEstimator(rateCtrl, n_windowSize, m_rgRejected);
n_windowSize = rateCtrl->m_windowSize;
// remove outlier
for (i = 0; i < (int) n_windowSize; i++)
{
error[i] = rateCtrl->m_X1 / rateCtrl->m_rgQp[i] + rateCtrl->m_X2 / (rateCtrl->m_rgQp[i] * rateCtrl->m_rgQp[i]) - rateCtrl->m_rgRp[i];
std += error[i] * error[i];
}
threshold = (n_windowSize == 2) ? 0 : oscl_sqrt(std / n_windowSize);
for (i = 0; i < (int) n_windowSize; i++)
{
if (AVC_ABS(error[i]) > threshold)
m_rgRejected[i] = TRUE;
}
// always include the last data point
m_rgRejected[0] = FALSE;
// second RD model estimator
RCModelEstimator(rateCtrl, n_windowSize, m_rgRejected);
if (MADModelFlag)
updateMADModel(video, rateCtrl);
else if (video->slice_type == AVC_P_SLICE || rateCtrl->idrPeriod == 1)
rateCtrl->PPictureMAD[0] = rateCtrl->CurrentFrameMAD;
return ;
}
double ComputeFrameMAD(AVCCommonObj *video, AVCRateControl *rateCtrl)
{
double TotalMAD;
int i;
TotalMAD = 0.0;
for (i = 0;i < (int)video->PicSizeInMbs;i++)
TotalMAD += rateCtrl->MADofMB[i];
TotalMAD /= video->PicSizeInMbs;
return TotalMAD;
}
void RCModelEstimator(AVCRateControl *rateCtrl, int n_windowSize, bool *m_rgRejected)
{
int n_realSize = n_windowSize;
int i;
double oneSampleQ = 0;
double a00 = 0.0, a01 = 0.0, a10 = 0.0, a11 = 0.0, b0 = 0.0, b1 = 0.0;
double MatrixValue;
bool estimateX2 = FALSE;
double m_X1, m_X2;
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
m_X1 = m_X2 = 0.0;
for (i = 0; i < n_windowSize; i++)
{
if (!m_rgRejected[i])
oneSampleQ = rateCtrl->m_rgQp[i];
}
for (i = 0; i < n_windowSize; i++)
{// if all non-rejected Q are the same, take 1st order model
if ((rateCtrl->m_rgQp[i] != oneSampleQ) && !m_rgRejected[i])
estimateX2 = TRUE;
if (!m_rgRejected[i])
m_X1 += (rateCtrl->m_rgQp[i] * rateCtrl->m_rgRp[i]) / n_realSize;
}
// take 2nd order model to estimate X1 and X2
if ((n_realSize >= 1) && estimateX2)
{
for (i = 0; i < n_windowSize; i++)
{
if (!m_rgRejected[i])
{
a00 = a00 + 1.0;
a01 += 1.0 / rateCtrl->m_rgQp[i];
a10 = a01;
a11 += 1.0 / (rateCtrl->m_rgQp[i] * rateCtrl->m_rgQp[i]);
b0 += rateCtrl->m_rgQp[i] * rateCtrl->m_rgRp[i];
b1 += rateCtrl->m_rgRp[i];
}
}
// solve the equation of AX = B
MatrixValue = a00 * a11 - a01 * a10;
if (AVC_ABS(MatrixValue) > 0.000001)
{
m_X1 = (b0 * a11 - b1 * a01) / MatrixValue;
m_X2 = (b1 * a00 - b0 * a10) / MatrixValue;
}
else
{
m_X1 = b0 / a00;
m_X2 = 0.0;
}
}
rateCtrl->m_X1 = m_X1;
rateCtrl->m_X2 = m_X2;
}
void updateMADModel(AVCCommonObj *video, AVCRateControl *rateCtrl)
{
int n_windowSize;
int i;
double error[20], std = 0.0, threshold;
int m_Nc;
double MADPictureC1;
double MADPictureC2;
bool PictureRejected[21];
int CodedBasicUnit = rateCtrl->TotalNumberofBasicUnit - rateCtrl->NumberofBasicUnit;
if (rateCtrl->NumberofCodedPFrame > 0)
{
//assert (img->type!=P_SLICE);
/*frame layer rate control*/
if (rateCtrl->basicUnit == (int)video->PicSizeInMbs)
m_Nc = rateCtrl->NumberofCodedPFrame;
/*basic unit layer rate control*/
else
m_Nc = rateCtrl->NumberofCodedPFrame * rateCtrl->TotalNumberofBasicUnit + CodedBasicUnit;
for (i = 19; i > 0; i--)
{// update the history
rateCtrl->PPictureMAD[i] = rateCtrl->PPictureMAD[i - 1];
rateCtrl->ReferenceMAD[i] = rateCtrl->ReferenceMAD[i-1];
}
rateCtrl->PPictureMAD[0] = rateCtrl->CurrentFrameMAD;
if (rateCtrl->basicUnit == (int)video->PicSizeInMbs)
rateCtrl->ReferenceMAD[0] = rateCtrl->PPictureMAD[1];
else
{
rateCtrl->ReferenceMAD[0] = rateCtrl->BUPFMAD[rateCtrl->TotalNumberofBasicUnit-1-rateCtrl->NumberofBasicUnit];
}
MADPictureC1 = rateCtrl->PMADPictureC1;
MADPictureC2 = rateCtrl->PMADPictureC2;
/*compute the size of window*/
n_windowSize = (rateCtrl->CurrentFrameMAD > rateCtrl->PreviousFrameMAD) ? (int)(rateCtrl->PreviousFrameMAD / rateCtrl->CurrentFrameMAD * 20)\
: (int)(rateCtrl->CurrentFrameMAD / rateCtrl->PreviousFrameMAD * 20);
n_windowSize = AVC_MIN(n_windowSize, (m_Nc - 1));
n_windowSize = AVC_MAX(n_windowSize, 1);
n_windowSize = AVC_MIN(n_windowSize, rateCtrl->MADm_windowSize + 1);
n_windowSize = AVC_MIN(20, n_windowSize);
/*update the previous window size*/
rateCtrl->MADm_windowSize = n_windowSize;
for (i = 0; i < 20; i++)
{
PictureRejected[i] = FALSE;
}
//update the MAD for the previous frame
if (video->slice_type == AVC_P_SLICE)
rateCtrl->PreviousFrameMAD = rateCtrl->CurrentFrameMAD;
// initial MAD model estimator
MADModelEstimator(video, rateCtrl, n_windowSize, &MADPictureC1, &MADPictureC2,
PictureRejected);
// remove outlier
for (i = 0; i < (int) n_windowSize; i++)
{
error[i] = MADPictureC1 * rateCtrl->ReferenceMAD[i] + MADPictureC2 - rateCtrl->PPictureMAD[i];
std += error[i] * error[i];
}
threshold = (n_windowSize == 2) ? 0 : oscl_sqrt(std / n_windowSize);
for (i = 0; i < (int) n_windowSize; i++)
{
if (AVC_ABS(error[i]) > threshold)
PictureRejected[i] = TRUE;
}
// always include the last data point
PictureRejected[0] = FALSE;
// second MAD model estimator
MADModelEstimator(video, rateCtrl, n_windowSize, &MADPictureC1, &MADPictureC2,
PictureRejected);
}
}
void MADModelEstimator(AVCCommonObj *video, AVCRateControl *rateCtrl, int n_windowSize,
double *MADPictureC1, double *MADPictureC2, bool *PictureRejected)
{
int n_realSize = n_windowSize;
int i;
double oneSampleQ = 0;
double a00 = 0.0, a01 = 0.0, a10 = 0.0, a11 = 0.0, b0 = 0.0, b1 = 0.0;
double MatrixValue;
bool estimateX2 = FALSE;
for (i = 0; i < n_windowSize; i++)
{// find the number of samples which are not rejected
if (PictureRejected[i])
n_realSize--;
}
// default MAD model estimation results
*MADPictureC1 = *MADPictureC2 = 0.0;
for (i = 0; i < n_windowSize; i++)
{
if (!PictureRejected[i])
oneSampleQ = rateCtrl->PPictureMAD[i];
}
for (i = 0; i < n_windowSize; i++)
{// if all non-rejected MAD are the same, take 1st order model
if ((rateCtrl->PPictureMAD[i] != oneSampleQ) && !PictureRejected[i])
estimateX2 = TRUE;
if (!PictureRejected[i])
*MADPictureC1 += rateCtrl->PPictureMAD[i] / (rateCtrl->ReferenceMAD[i] * n_realSize);
}
// take 2nd order model to estimate X1 and X2
if ((n_realSize >= 1) && estimateX2)
{
for (i = 0; i < n_windowSize; i++)
{
if (!PictureRejected[i])
{
a00 = a00 + 1.0;
a01 += rateCtrl->ReferenceMAD[i];
a10 = a01;
a11 += rateCtrl->ReferenceMAD[i] * rateCtrl->ReferenceMAD[i];
b0 += rateCtrl->PPictureMAD[i];
b1 += rateCtrl->PPictureMAD[i] * rateCtrl->ReferenceMAD[i];
}
}
// solve the equation of AX = B
MatrixValue = a00 * a11 - a01 * a10;
if (AVC_ABS(MatrixValue) > 0.000001)
{
*MADPictureC2 = (b0 * a11 - b1 * a01) / MatrixValue;
*MADPictureC1 = (b1 * a00 - b0 * a10) / MatrixValue;
}
else
{
*MADPictureC1 = b0 / a01;
*MADPictureC2 = 0.0;
}
}
if (video->slice_type == AVC_P_SLICE)
{
rateCtrl->PMADPictureC1 = *MADPictureC1;
rateCtrl->PMADPictureC2 = *MADPictureC2;
}
}
/* convert from QP to Qstep */
double QP2Qstep(int QP)
{
int i;
double Qstep;
static const double QP2QSTEP[6] = { 0.625, 0.6875, 0.8125, 0.875, 1.0, 1.125 };
Qstep = QP2QSTEP[QP % 6];
for (i = 0; i < (QP / 6); i++)
Qstep *= 2;
return Qstep;
}
/* convert from step size to QP */
int Qstep2QP(double Qstep)
{
int q_per = 0, q_rem = 0;
// assert( Qstep >= QP2Qstep(0) && Qstep <= QP2Qstep(51) );
if (Qstep < QP2Qstep(0))
return 0;
else if (Qstep > QP2Qstep(51))
return 51;
while (Qstep > QP2Qstep(5))
{
Qstep /= 2;
q_per += 1;
}
if (Qstep <= (0.625 + 0.6875) / 2)
{
Qstep = 0.625;
q_rem = 0;
}
else if (Qstep <= (0.6875 + 0.8125) / 2)
{
Qstep = 0.6875;
q_rem = 1;
}
else if (Qstep <= (0.8125 + 0.875) / 2)
{
Qstep = 0.8125;
q_rem = 2;
}
else if (Qstep <= (0.875 + 1.0) / 2)
{
Qstep = 0.875;
q_rem = 3;
}
else if (Qstep <= (1.0 + 1.125) / 2)
{
Qstep = 1.0;
q_rem = 4;
}
else
{
Qstep = 1.125;
q_rem = 5;
}
return (q_per * 6 + q_rem);
}