ref: 1928b9a1ba6f7c18ebc058835f308c3d7016a1da
dir: /codec/encoder/core/src/ratectl.cpp/
/*!
* \copy
* Copyright (c) 2009-2013, Cisco Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*
* ratectl.c
*
* Abstract
* Rate Control
*
* History
* 9/8/2009 Created
* 12/26/2011 Modified
*
*
*
*************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "rc.h"
#include "encoder_context.h"
#include "utils.h"
#include "svc_enc_golomb.h"
namespace WelsSVCEnc {
//#define _TEST_TEMP_RC_
#ifdef _TEST_TEMP_RC_
//#define _NOT_USE_AQ_FOR_TEST_
FILE *fp_test_rc = NULL;
FILE *fp_vgop = NULL;
#endif
#define _BITS_RANGE 0
void RcInitLayerMemory(SWelsSvcRc *pWelsSvcRc, CMemoryAlign *pMA, const int32_t kiMaxTl)
{
const int32_t kiSliceNum = pWelsSvcRc->iSliceNum;
const int32_t kiGomSize = pWelsSvcRc->iGomSize;
const int32_t kiGomSizeD = kiGomSize * sizeof(double);
const int32_t kiGomSizeI = kiGomSize * sizeof(int32_t);
const int32_t kiLayerRcSize = kiGomSizeD + (kiGomSizeI*3) + sizeof(SRCSlicing)*kiSliceNum + sizeof(SRCTemporal)*kiMaxTl;
uint8_t *pBaseMem = (uint8_t *)pMA->WelsMalloc(kiLayerRcSize, "rc_layer_memory");
if (NULL == pBaseMem)
return;
pWelsSvcRc->pGomComplexity = (double *)pBaseMem;
pBaseMem += kiGomSizeD;
pWelsSvcRc->pGomForegroundBlockNum = (int32_t *)pBaseMem;
pBaseMem += kiGomSizeI;
pWelsSvcRc->pCurrentFrameGomSad = (int32_t *)pBaseMem;
pBaseMem += kiGomSizeI;
pWelsSvcRc->pGomCost = (int32_t *)pBaseMem;
pBaseMem += kiGomSizeI;
pWelsSvcRc->pSlicingOverRc = (SRCSlicing *)pBaseMem;
pBaseMem += sizeof(SRCSlicing)*kiSliceNum;
pWelsSvcRc->pTemporalOverRc = (SRCTemporal *)pBaseMem;
}
void RcFreeLayerMemory(SWelsSvcRc *pWelsSvcRc, CMemoryAlign *pMA)
{
if (pWelsSvcRc != NULL && pWelsSvcRc->pGomComplexity != NULL)
{
pMA->WelsFree(pWelsSvcRc->pGomComplexity, "rc_layer_memory");
pWelsSvcRc->pGomComplexity = NULL;
pWelsSvcRc->pGomForegroundBlockNum = NULL;
pWelsSvcRc->pCurrentFrameGomSad = NULL;
pWelsSvcRc->pGomCost = NULL;
pWelsSvcRc->pSlicingOverRc = NULL;
pWelsSvcRc->pTemporalOverRc = NULL;
}
}
static inline double RcConvertQp2QStep(double dQP)
{
return pow( 2.0, (dQP-4.0)/6.0 );
}
static inline double RcConvertQStep2Qp(double dQpStep)
{
return (6 * log(dQpStep) / log(2.0) + 4.0);
}
void RcInitSequenceParameter(sWelsEncCtx *pEncCtx)
{
SWelsSvcRc *pWelsSvcRc = NULL;
SDLayerParam *pDLayerParam = NULL;
int32_t j = 0;
int32_t iMbWidth = 0;
BOOL_T bMultiSliceMode = FALSE;
int32_t iGomRowMode0 = 1, iGomRowMode1 = 1;
#ifdef _TEST_TEMP_RC_
fp_test_rc = fopen("testRC.dat","w");
fp_vgop = fopen("vgop.dat","w");
#endif
for( j=0; j<pEncCtx->pSvcParam->iNumDependencyLayer; j++ )
{
SSliceCtx *pSliceCtx = &pEncCtx->pSliceCtxList[j];
pWelsSvcRc = &pEncCtx->pWelsSvcRc[j];
pDLayerParam = &pEncCtx->pSvcParam->sDependencyLayers[j];
iMbWidth = (pDLayerParam->iFrameWidth>>4);
pWelsSvcRc->iNumberMbFrame = iMbWidth*(pDLayerParam->iFrameHeight>>4);
pWelsSvcRc->iSliceNum= pSliceCtx->iSliceNumInFrame;
pWelsSvcRc->iRcVaryPercentage = _BITS_RANGE; // % -- for temp
pWelsSvcRc->dRcVaryRatio = (double)pWelsSvcRc->iRcVaryPercentage/MAX_BITS_VARY_PERCENTAGE;
pWelsSvcRc->dSkipBufferRatio = SKIP_RATIO;
pWelsSvcRc->iQpRangeUpperInFrame = QP_RANGE_UPPER_MODE1 - (int32_t)((QP_RANGE_UPPER_MODE1 - QP_RANGE_MODE0)*pWelsSvcRc->dRcVaryRatio + 0.5);
pWelsSvcRc->iQpRangeLowerInFrame = QP_RANGE_LOWER_MODE1 - (int32_t)((QP_RANGE_LOWER_MODE1 - QP_RANGE_MODE0)*pWelsSvcRc->dRcVaryRatio + 0.5);
if( iMbWidth<=MB_WIDTH_THRESHOLD_90P )
{
pWelsSvcRc->iSkipQpValue = SKIP_QP_90P;
iGomRowMode0 = GOM_ROW_MODE0_90P;
iGomRowMode1 = GOM_ROW_MODE1_90P;
}
else if( iMbWidth<=MB_WIDTH_THRESHOLD_180P )
{
pWelsSvcRc->iSkipQpValue = SKIP_QP_180P;
iGomRowMode0 = GOM_ROW_MODE0_180P;
iGomRowMode1 = GOM_ROW_MODE1_180P;
}
else if( iMbWidth<=MB_WIDTH_THRESHOLD_360P )
{
pWelsSvcRc->iSkipQpValue = SKIP_QP_360P;
iGomRowMode0 = GOM_ROW_MODE0_360P;
iGomRowMode1 = GOM_ROW_MODE1_360P;
}
else
{
pWelsSvcRc->iSkipQpValue = SKIP_QP_720P;
iGomRowMode0 = GOM_ROW_MODE0_720P;
iGomRowMode1 = GOM_ROW_MODE1_720P;
}
iGomRowMode0 = iGomRowMode1 + (int32_t)((iGomRowMode0 - iGomRowMode1)*pWelsSvcRc->dRcVaryRatio + 0.5);
pWelsSvcRc->iNumberMbGom = iMbWidth*iGomRowMode0;
pWelsSvcRc->iMinQp = GOM_MIN_QP_MODE;
pWelsSvcRc->iMaxQp = GOM_MAX_QP_MODE;
pWelsSvcRc->iFrameDeltaQpUpper = LAST_FRAME_QP_RANGE_UPPER_MODE1 - (int32_t)((LAST_FRAME_QP_RANGE_UPPER_MODE1 - LAST_FRAME_QP_RANGE_UPPER_MODE0)*pWelsSvcRc->dRcVaryRatio + 0.5);
pWelsSvcRc->iFrameDeltaQpLower = LAST_FRAME_QP_RANGE_LOWER_MODE1 - (int32_t)((LAST_FRAME_QP_RANGE_LOWER_MODE1 - LAST_FRAME_QP_RANGE_LOWER_MODE0)*pWelsSvcRc->dRcVaryRatio + 0.5);
pWelsSvcRc->iSkipFrameNum = 0;
pWelsSvcRc->iGomSize = (pWelsSvcRc->iNumberMbFrame+pWelsSvcRc->iNumberMbGom-1)/pWelsSvcRc->iNumberMbGom;
RcInitLayerMemory( pWelsSvcRc, pEncCtx->pMemAlign, 1+pDLayerParam->iHighestTemporalId );
bMultiSliceMode = ( (SM_RASTER_SLICE == pDLayerParam->sMso.uiSliceMode) ||
(SM_ROWMB_SLICE == pDLayerParam->sMso.uiSliceMode) ||
(SM_DYN_SLICE == pDLayerParam->sMso.uiSliceMode) );
if( bMultiSliceMode )
pWelsSvcRc->iNumberMbGom = pWelsSvcRc->iNumberMbFrame;
}
}
void RcInitTlWeight(sWelsEncCtx *pEncCtx)
{
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
SRCTemporal *pTOverRc = pWelsSvcRc->pTemporalOverRc;
SDLayerParam *pDLayerParam = &pEncCtx->pSvcParam->sDependencyLayers[pEncCtx->uiDependencyId];
const int32_t kiDecompositionStages = pDLayerParam->iDecompositionStages;
const int32_t kiHighestTid = pDLayerParam->iHighestTemporalId;
//Index 0:Virtual GOP size, Index 1:Frame rate
double WeightArray[4][4] = { {1.0, 0, 0, 0}, {0.6, 0.4, 0, 0}, {0.4, 0.3, 0.15, 0}, {0.25, 0.15, 0.125, 0.0875}};
const int32_t kiGopSize = (1<<kiDecompositionStages);
int32_t i, k, n;
n = 0;
while (n <= kiHighestTid)
{
pTOverRc[n].dTlayerWeight = WeightArray[kiDecompositionStages][n];
++ n;
}
//Calculate the frame index for the current frame and its reference frame
for( n=0; n<VGOP_SIZE; n+=kiGopSize )
{
pWelsSvcRc->iTlOfFrames[n] = 0;
for( i=1; i<=kiDecompositionStages; i++ )
{
for( k=1<<(kiDecompositionStages-i); k<kiGopSize; k+=(kiGopSize>>(i-1)) )
{
pWelsSvcRc->iTlOfFrames[k+n]=i;
}
}
}
pWelsSvcRc->iPreviousGopSize = kiGopSize;
pWelsSvcRc->iGopNumberInVGop = VGOP_SIZE/kiGopSize;
}
void RcUpdateBitrateFps(sWelsEncCtx *pEncCtx)
{
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
SRCTemporal *pTOverRc = pWelsSvcRc->pTemporalOverRc;
SDLayerParam *pDLayerParam = &pEncCtx->pSvcParam->sDependencyLayers[pEncCtx->uiDependencyId];
const int32_t kiGopSize = (1<<pDLayerParam->iDecompositionStages);
const int32_t kiHighestTid = pDLayerParam->iHighestTemporalId;
double input_dBitsPerFrame = pDLayerParam->iSpatialBitrate / pDLayerParam->fInputFrameRate;
const int32_t kiGopBits = (int32_t)(input_dBitsPerFrame*kiGopSize);
int32_t i;
pWelsSvcRc->iBitRate = pDLayerParam->iSpatialBitrate;
pWelsSvcRc->fFrameRate = pDLayerParam->fInputFrameRate;
double dTargetVaryRange = FRAME_iTargetBits_VARY_RANGE*(1.0 - pWelsSvcRc->dRcVaryRatio);
double dMinBitsRatio = 1.0 - dTargetVaryRange;
double dMaxBitsRatio = 1.0 + FRAME_iTargetBits_VARY_RANGE;//dTargetVaryRange;
for( i=0; i<=kiHighestTid; i++)
{
const double kdConstraitBits = kiGopBits*pTOverRc[i].dTlayerWeight;
pTOverRc[i].iMinBitsTl = (int32_t)(kdConstraitBits*dMinBitsRatio);
pTOverRc[i].iMaxBitsTl = (int32_t)(kdConstraitBits*dMaxBitsRatio);
}
//When bitrate is changed, pBuffer size should be updated
pWelsSvcRc->iBufferSizeSkip = (int32_t)(pWelsSvcRc->iBitRate * pWelsSvcRc->dSkipBufferRatio);
pWelsSvcRc->iBufferSizePadding = (int32_t)(pWelsSvcRc->iBitRate * PADDING_BUFFER_RATIO);
//change remaining bits
if(pWelsSvcRc->dBitsPerFrame > 0.1)
pWelsSvcRc->iRemainingBits = (int32_t)(pWelsSvcRc->iRemainingBits*input_dBitsPerFrame/pWelsSvcRc->dBitsPerFrame);
pWelsSvcRc->dBitsPerFrame = input_dBitsPerFrame;
}
void RcInitVGop(sWelsEncCtx *pEncCtx)
{
const int32_t kiDid = pEncCtx->uiDependencyId;
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[kiDid];
SRCTemporal *pTOverRc = pWelsSvcRc->pTemporalOverRc;
const int32_t kiHighestTid = pEncCtx->pSvcParam->sDependencyLayers[kiDid].iHighestTemporalId;
pWelsSvcRc->iRemainingBits = (int32_t)(VGOP_SIZE*pWelsSvcRc->dBitsPerFrame);
pWelsSvcRc->dRemainingWeights = pWelsSvcRc->iGopNumberInVGop;
pWelsSvcRc->iFrameCodedInVGop = 0;
pWelsSvcRc->iGopIndexInVGop = 0;
for (int32_t i = 0; i <= kiHighestTid; ++ i)
pTOverRc[i].iGopBitsDq = 0;
pWelsSvcRc->iSkipFrameInVGop=0;
}
void RcInitRefreshParameter(sWelsEncCtx *pEncCtx)
{
const int32_t kiDid = pEncCtx->uiDependencyId;
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[kiDid];
SRCTemporal *pTOverRc = pWelsSvcRc->pTemporalOverRc;
SDLayerParam *pDLayerParam = &pEncCtx->pSvcParam->sDependencyLayers[kiDid];
const int32_t kiHighestTid = pDLayerParam->iHighestTemporalId;
int32_t i;
//I frame R-Q Model
pWelsSvcRc->iIntraComplexity = 0;
pWelsSvcRc->iIntraMbCount = 0;
//P frame R-Q Model
for(i=0; i<=kiHighestTid; i++)
{
pTOverRc[i].iPFrameNum = 0;
pTOverRc[i].dLinearCmplx = 0.0;
pTOverRc[i].iFrameCmplxMean = 0;
}
pWelsSvcRc->iBufferFullnessSkip = 0;
pWelsSvcRc->iBufferFullnessPadding = 0;
pWelsSvcRc->iGopIndexInVGop = 0;
pWelsSvcRc->iRemainingBits = 0;
pWelsSvcRc->dBitsPerFrame = 0.0;
//Backup the initial bitrate and fps
pWelsSvcRc->iPreviousBitrate = pDLayerParam->iSpatialBitrate;
pWelsSvcRc->dPreviousFps = pDLayerParam->fInputFrameRate;
memset( pWelsSvcRc->pCurrentFrameGomSad, 0, pWelsSvcRc->iGomSize*sizeof(int32_t) );
RcInitTlWeight(pEncCtx);
RcUpdateBitrateFps(pEncCtx);
RcInitVGop(pEncCtx);
}
bool_t RcJudgeBitrateFpsUpdate(sWelsEncCtx *pEncCtx)
{
int32_t iCurDid = pEncCtx->uiDependencyId;
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[iCurDid];
SDLayerParam *pDLayerParam = &pEncCtx->pSvcParam->sDependencyLayers[iCurDid];
if((pWelsSvcRc->iPreviousBitrate != pDLayerParam->iSpatialBitrate) ||
(pWelsSvcRc->dPreviousFps-pDLayerParam->fInputFrameRate)>EPSN ||
(pWelsSvcRc->dPreviousFps-pDLayerParam->fInputFrameRate)<-EPSN)
{
pWelsSvcRc->iPreviousBitrate = pDLayerParam->iSpatialBitrate;
pWelsSvcRc->dPreviousFps = pDLayerParam->fInputFrameRate;
return true;
}
else
return false;
}
#if GOM_TRACE_FLAG
void RcTraceVGopBitrate(sWelsEncCtx *pEncCtx)
{
const int32_t kiDid = pEncCtx->uiDependencyId;
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[kiDid];
if( pWelsSvcRc->iFrameCodedInVGop )
{
const int32_t kiHighestTid = pEncCtx->pSvcParam->sDependencyLayers[kiDid].iHighestTemporalId;
SRCTemporal *pTOverRc = pWelsSvcRc->pTemporalOverRc;
int32_t iVGopBitrate;
int32_t iTotalBits = pWelsSvcRc->iPaddingBitrateStat;
int32_t iTid = 0;
while (iTid <= kiHighestTid)
{
iTotalBits += pTOverRc[iTid].iGopBitsDq;
++ iTid;
}
int32_t iFrameInVGop = pWelsSvcRc->iFrameCodedInVGop+pWelsSvcRc->iSkipFrameInVGop;
if(0 != iFrameInVGop)
iVGopBitrate = (int32_t)( iTotalBits/iFrameInVGop *pWelsSvcRc->fFrameRate );
#ifdef _TEST_TEMP_Rc_
fprintf(fp_vgop,"%d\n",(int32_t)((double)iTotalBits/iFrameInVGop));
#endif
WelsLog( pEncCtx, WELS_LOG_INFO,"[Rc] VGOPbitrate%d: %d \n", kiDid, iVGopBitrate);
if ( iTotalBits > 0 )
{
iTid = 0;
while (iTid <= kiHighestTid)
{
WelsLog( pEncCtx, WELS_LOG_INFO,"T%d=%8.3f \n", iTid, (double)(pTOverRc[iTid].iGopBitsDq/iTotalBits) );
++ iTid;
}
}
}
}
#endif
void RcUpdateTemporalZero(sWelsEncCtx *pEncCtx)
{
const int32_t kiDid = pEncCtx->uiDependencyId;
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[kiDid];
SDLayerParam *pDLayerParam = &pEncCtx->pSvcParam->sDependencyLayers[kiDid];
const int32_t kiGopSize = (1<<pDLayerParam->iDecompositionStages);
if( pWelsSvcRc->iPreviousGopSize != kiGopSize )
{
#if GOM_TRACE_FLAG
RcTraceVGopBitrate(pEncCtx);
#endif
RcInitTlWeight(pEncCtx);
RcInitVGop(pEncCtx);
}
else if( pWelsSvcRc->iGopIndexInVGop == pWelsSvcRc->iGopNumberInVGop || pEncCtx->eSliceType == I_SLICE)
{
#if GOM_TRACE_FLAG
RcTraceVGopBitrate(pEncCtx);
#endif
RcInitVGop(pEncCtx);
}
pWelsSvcRc->iGopIndexInVGop++;
}
void RcInitIdrQp(sWelsEncCtx *pEncCtx)
{
double dBpp = 0;
int32_t i;
//64k@6fps for 90p: bpp 0.74 QP:24
//192k@12fps for 180p: bpp 0.28 QP:26
//512k@24fps for 360p: bpp 0.09 QP:30
//1500k@30fps for 720p: bpp 0.05 QP:32
double dBppArray[4][3] = {{0.5, 0.75, 1.0}, {0.2, 0.3, 0.4}, {0.05, 0.09, 0.13}, {0.03, 0.06, 0.1}};
int32_t dInitialQPArray[4][4] = {{28, 26, 24, 22}, {30, 28, 26, 24}, {32, 30, 28, 26}, {34, 32, 30, 28}};
int32_t iBppIndex = 0;
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
SDLayerParam *pDLayerParam = &pEncCtx->pSvcParam->sDependencyLayers[pEncCtx->uiDependencyId];
if (pDLayerParam->fOutputFrameRate > EPSN && pDLayerParam->iFrameWidth && pDLayerParam->iFrameHeight)
dBpp=(double)(pDLayerParam->iSpatialBitrate) / (double)(pDLayerParam->fOutputFrameRate * pDLayerParam->iFrameWidth * pDLayerParam->iFrameHeight);
else
dBpp = 0.1;
//Area*2
if ( pDLayerParam->iFrameWidth*pDLayerParam->iFrameHeight <= 28800 ) // 90p video:160*90
iBppIndex = 0;
else if ( pDLayerParam->iFrameWidth*pDLayerParam->iFrameHeight <= 115200 ) // 180p video:320*180
iBppIndex = 1;
else if ( pDLayerParam->iFrameWidth*pDLayerParam->iFrameHeight <= 460800 ) // 360p video:640*360
iBppIndex = 2;
else
iBppIndex = 3;
//Search
for( i=0; i<3; i++ )
{
if ( dBpp<=dBppArray[iBppIndex][i] )
break;
}
pWelsSvcRc->iInitialQp = dInitialQPArray[iBppIndex][i];
pWelsSvcRc->iInitialQp = (int32_t)WELS_CLIP3( pWelsSvcRc->iInitialQp, MIN_IDR_QP, MAX_IDR_QP );
pEncCtx->iGlobalQp = pWelsSvcRc->iInitialQp;
pWelsSvcRc->dQStep = RcConvertQp2QStep(pEncCtx->iGlobalQp);
pWelsSvcRc->iLastCalculatedQScale = pEncCtx->iGlobalQp;
}
void RcCalculateIdrQp(sWelsEncCtx *pEncCtx)
{
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
//obtain the idr qp using previous idr complexity
if(pWelsSvcRc->iNumberMbFrame != pWelsSvcRc->iIntraMbCount){
pWelsSvcRc->iIntraComplexity = (int32_t)((double)pWelsSvcRc->iIntraComplexity*pWelsSvcRc->iNumberMbFrame/pWelsSvcRc->iIntraMbCount + 0.5);
}
pWelsSvcRc->iInitialQp = (int32_t)RcConvertQStep2Qp( (double)pWelsSvcRc->iIntraComplexity/pWelsSvcRc->iTargetBits);
pWelsSvcRc->iInitialQp = (int32_t)WELS_CLIP3( pWelsSvcRc->iInitialQp, MIN_IDR_QP, MAX_IDR_QP );
pEncCtx->iGlobalQp = pWelsSvcRc->iInitialQp;
pWelsSvcRc->dQStep = RcConvertQp2QStep(pEncCtx->iGlobalQp);
pWelsSvcRc->iLastCalculatedQScale = pEncCtx->iGlobalQp;
}
void RcCalculatePictureQp(sWelsEncCtx *pEncCtx)
{
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
int32_t iTl = pEncCtx->uiTemporalId;
SRCTemporal *pTOverRc = &pWelsSvcRc->pTemporalOverRc[iTl];
int32_t iLumaQp = 0;
if(0 == pTOverRc->iPFrameNum)
{
iLumaQp = pWelsSvcRc->iInitialQp;
}
else{
double dCmplxRatio = (double)pEncCtx->pVaa->sComplexityAnalysisParam.iFrameComplexity/pTOverRc->iFrameCmplxMean;
dCmplxRatio = WELS_CLIP3(dCmplxRatio, 1.0-FRAME_CMPLX_RATIO_RANGE, 1.0+FRAME_CMPLX_RATIO_RANGE);
pWelsSvcRc->dQStep = pTOverRc->dLinearCmplx*dCmplxRatio / pWelsSvcRc->iTargetBits;
iLumaQp = (int32_t)( RcConvertQStep2Qp( pWelsSvcRc->dQStep )+0.5 );
//limit QP
int32_t iLastIdxCodecInVGop = pWelsSvcRc->iFrameCodedInVGop - 1;
if(iLastIdxCodecInVGop < 0)
iLastIdxCodecInVGop += VGOP_SIZE;
int32_t iTlLast = pWelsSvcRc->iTlOfFrames[iLastIdxCodecInVGop];
int32_t iDeltaQpTemporal = iTl - iTlLast;
if(0 == iTlLast && iTl > 0)
iDeltaQpTemporal += 3;
else if(0 == iTl && iTlLast > 0)
iDeltaQpTemporal -= 3;
iLumaQp = WELS_CLIP3(iLumaQp,
pWelsSvcRc->iLastCalculatedQScale - pWelsSvcRc->iFrameDeltaQpLower +iDeltaQpTemporal, pWelsSvcRc->iLastCalculatedQScale + pWelsSvcRc->iFrameDeltaQpUpper + iDeltaQpTemporal);
}
iLumaQp = WELS_CLIP3(iLumaQp, GOM_MIN_QP_MODE, GOM_MAX_QP_MODE);
pWelsSvcRc->dQStep = RcConvertQp2QStep(iLumaQp);
pWelsSvcRc->iLastCalculatedQScale = iLumaQp;
#ifndef _NOT_USE_AQ_FOR_TEST_
if(pEncCtx->pSvcParam->bEnableAdaptiveQuant)
{
iLumaQp = (int32_t)WELS_CLIP3(iLumaQp - pEncCtx->pVaa->sAdaptiveQuantParam.dAverMotionTextureIndexToDeltaQp, pWelsSvcRc->iMinQp, pWelsSvcRc->iMaxQp);
}
#endif
pEncCtx->iGlobalQp = iLumaQp;
}
void RcInitSliceInformation(sWelsEncCtx *pEncCtx)
{
SSliceCtx *pCurSliceCtx = pEncCtx->pCurDqLayer->pSliceEncCtx;
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
SRCSlicing *pSOverRc = &pWelsSvcRc->pSlicingOverRc[0];
const int32_t kiSliceNum = pCurSliceCtx->iSliceNumInFrame;
const double kdBitsPerMb = (double)pWelsSvcRc->iTargetBits / pWelsSvcRc->iNumberMbFrame;
for(int32_t i=0; i<kiSliceNum; i++ )
{
pSOverRc->iStartMbSlice =
pSOverRc->iEndMbSlice = pCurSliceCtx->pFirstMbInSlice[i];
pSOverRc->iEndMbSlice += (pCurSliceCtx->pCountMbNumInSlice[i]-1);
pSOverRc->iTotalQpSlice = 0;
pSOverRc->iTotalMbSlice = 0;
pSOverRc->iTargetBitsSlice = (int32_t)(kdBitsPerMb * pCurSliceCtx->pCountMbNumInSlice[i]);
pSOverRc->iFrameBitsSlice = 0;
pSOverRc->iGomBitsSlice = 0;
++ pSOverRc;
}
}
void RcDecideTargetBits(sWelsEncCtx *pEncCtx)
{
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
SRCTemporal *pTOverRc = &pWelsSvcRc->pTemporalOverRc[pEncCtx->uiTemporalId];
//allocate bits
if(pEncCtx->eSliceType == I_SLICE)
{
pWelsSvcRc->iTargetBits = (int32_t)( pWelsSvcRc->dBitsPerFrame * IDR_BITRATE_RATIO );
}
else
{
pWelsSvcRc->iTargetBits = (int32_t)( pWelsSvcRc->iRemainingBits*pTOverRc->dTlayerWeight/pWelsSvcRc->dRemainingWeights );
pWelsSvcRc->iTargetBits = WELS_CLIP3( pWelsSvcRc->iTargetBits, pTOverRc->iMinBitsTl, pTOverRc->iMaxBitsTl);
}
pWelsSvcRc->dRemainingWeights -= pTOverRc->dTlayerWeight;
}
void RcInitGoomParameters(sWelsEncCtx *pEncCtx)
{
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
SRCSlicing *pSOverRc = &pWelsSvcRc->pSlicingOverRc[0];
const int32_t kiSliceNum = pWelsSvcRc->iSliceNum;
const int32_t kiGlobalQp = pEncCtx->iGlobalQp;
pWelsSvcRc->iAverageFrameQp = 0;
for(int32_t i=0; i<kiSliceNum; ++i )
{
pSOverRc->iComplexityIndexSlice = 0;
pSOverRc->iCalculatedQpSlice = kiGlobalQp;
++ pSOverRc;
}
memset( pWelsSvcRc->pGomComplexity, 0, pWelsSvcRc->iGomSize*sizeof(double) );
memset( pWelsSvcRc->pGomCost, 0, pWelsSvcRc->iGomSize*sizeof(int32_t) );
}
void RcCalculateMbQp(sWelsEncCtx *pEncCtx,SMB* pCurMb, const int32_t kiSliceId)
{
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
SRCSlicing *pSOverRc = &pWelsSvcRc->pSlicingOverRc[kiSliceId];
int32_t iLumaQp = pSOverRc->iCalculatedQpSlice;
#ifndef _NOT_USE_AQ_FOR_TEST_
if ( pEncCtx->pSvcParam->bEnableAdaptiveQuant )
{
iLumaQp = (int8_t)WELS_CLIP3(iLumaQp +
pEncCtx->pVaa->sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp[pCurMb->iMbXY], pWelsSvcRc->iMinQp, 51);
}
#endif
pCurMb->uiChromaQp = g_kuiChromaQpTable[iLumaQp];
pCurMb->uiLumaQp = iLumaQp;
}
SWelsSvcRc* RcJudgeBaseUsability(sWelsEncCtx *pEncCtx)
{
SWelsSvcRc *pWelsSvcRc = NULL, *pWelsSvcRc_Base = NULL;
SDLayerParam *pDlpBase = NULL, *pDLayerParam = NULL;
if( pEncCtx->uiDependencyId<=0 )
return NULL;
pDlpBase = &pEncCtx->pSvcParam->sDependencyLayers[pEncCtx->uiDependencyId-1];
pWelsSvcRc_Base = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId-1];
if( pEncCtx->uiTemporalId<=pDlpBase->iDecompositionStages )
{
pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
pWelsSvcRc_Base = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId-1];
pDLayerParam = &pEncCtx->pSvcParam->sDependencyLayers[pEncCtx->uiDependencyId];
pDlpBase = &pEncCtx->pSvcParam->sDependencyLayers[pEncCtx->uiDependencyId-1];
if( (pDLayerParam->iFrameWidth*pDLayerParam->iFrameHeight/pWelsSvcRc->iNumberMbGom) ==
(pDlpBase->iFrameWidth*pDlpBase->iFrameHeight/pWelsSvcRc_Base->iNumberMbGom) )
return pWelsSvcRc_Base;
else
return NULL;
}
else
return NULL;
}
void RcGomTargetBits(sWelsEncCtx *pEncCtx, const int32_t kiSliceId)
{
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
SWelsSvcRc *pWelsSvcRc_Base = NULL;
SRCSlicing *pSOverRc = &pWelsSvcRc->pSlicingOverRc[kiSliceId];
double dAllocateBits = 0;
int32_t iSumSad = 0;
int32_t iLastGomIndex = 0;
int32_t iLeftBits = 0;
const int32_t kiComplexityIndex = pSOverRc->iComplexityIndexSlice;
int32_t i;
iLastGomIndex = pSOverRc->iEndMbSlice/pWelsSvcRc->iNumberMbGom;
iLeftBits = pSOverRc->iTargetBitsSlice-pSOverRc->iFrameBitsSlice;
if(iLeftBits <= 0)
{
pSOverRc->iGomTargetBits = 0;
return;
}
else if( kiComplexityIndex >= iLastGomIndex)
{
dAllocateBits = iLeftBits;
}
else
{
pWelsSvcRc_Base = RcJudgeBaseUsability(pEncCtx);
pWelsSvcRc_Base = (pWelsSvcRc_Base) ? pWelsSvcRc_Base : pWelsSvcRc;
for( i=kiComplexityIndex; i<=iLastGomIndex; i++ )
{
iSumSad += pWelsSvcRc_Base->pCurrentFrameGomSad[i];
}
if(0 == iSumSad)
dAllocateBits = (double)iLeftBits/(iLastGomIndex-kiComplexityIndex);
else
dAllocateBits = (double)iLeftBits*pWelsSvcRc_Base->pCurrentFrameGomSad[kiComplexityIndex+1]/iSumSad;
}
pSOverRc->iGomTargetBits = int32_t(dAllocateBits + 0.5);
}
void RcCalculateGomQp(sWelsEncCtx *pEncCtx, SMB* pCurMb, int32_t iSliceId)
{
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
SRCSlicing *pSOverRc = &pWelsSvcRc->pSlicingOverRc[iSliceId];
double dBitsRatio = 1.0;
int32_t iLeftBits = pSOverRc->iTargetBitsSlice - pSOverRc->iFrameBitsSlice;
int32_t iTargetLeftBits = iLeftBits + pSOverRc->iGomBitsSlice - pSOverRc->iGomTargetBits;
if(iLeftBits <= 0)
{
pSOverRc->iCalculatedQpSlice += 2;
}
else
{
//globe decision
dBitsRatio = iLeftBits / (iTargetLeftBits + 0.1);
if(dBitsRatio < 0.8409) //2^(-1.5/6)
pSOverRc->iCalculatedQpSlice += 2;
else if(dBitsRatio < 0.9439) //2^(-0.5/6)
pSOverRc->iCalculatedQpSlice += 1;
else if(dBitsRatio > 1.06) //2^(0.5/6)
pSOverRc->iCalculatedQpSlice -= 1;
else if(dBitsRatio > 1.19) //2^(1.5/6)
pSOverRc->iCalculatedQpSlice -= 2;
}
pSOverRc->iCalculatedQpSlice = WELS_CLIP3( pSOverRc->iCalculatedQpSlice,
pEncCtx->iGlobalQp-pWelsSvcRc->iQpRangeLowerInFrame, pEncCtx->iGlobalQp+pWelsSvcRc->iQpRangeUpperInFrame );
pSOverRc->iCalculatedQpSlice = WELS_CLIP3(pSOverRc->iCalculatedQpSlice, pWelsSvcRc->iMinQp, pWelsSvcRc->iMaxQp);
pSOverRc->iGomBitsSlice = 0;
}
void RcVBufferCalculationSkip(sWelsEncCtx *pEncCtx)
{
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
SRCTemporal *pTOverRc = pWelsSvcRc->pTemporalOverRc;
const int32_t kiOutputBits = (int32_t)(pWelsSvcRc->dBitsPerFrame + 0.5);
//condition 1: whole pBuffer fullness
pWelsSvcRc->iBufferFullnessSkip += (pWelsSvcRc->iFrameDqBits - kiOutputBits);
//condition 2: VGOP bits constraint
const int32_t kiVGopBits = (int32_t)(pWelsSvcRc->dBitsPerFrame * VGOP_SIZE);
int32_t iVGopBitsPred = 0;
for(int32_t i = pWelsSvcRc->iFrameCodedInVGop+1; i<VGOP_SIZE; i++ )
iVGopBitsPred += pTOverRc[pWelsSvcRc->iTlOfFrames[i]].iMinBitsTl;
iVGopBitsPred -= pWelsSvcRc->iRemainingBits;
double dIncPercent = iVGopBitsPred*100.0/kiVGopBits - (double)VGOP_BITS_PERCENTAGE_DIFF;
if( (pWelsSvcRc->iBufferFullnessSkip > pWelsSvcRc->iBufferSizeSkip && pWelsSvcRc->iAverageFrameQp > pWelsSvcRc->iSkipQpValue)
|| (dIncPercent > pWelsSvcRc->iRcVaryPercentage))
{
pEncCtx->iSkipFrameFlag=1;
pWelsSvcRc->iBufferFullnessSkip = pWelsSvcRc->iBufferFullnessSkip-kiOutputBits;
#ifdef FRAME_INFO_OUTPUT
fprintf(stderr, "skip one frame\n");
#endif
}
if( pWelsSvcRc->iBufferFullnessSkip<0 )
pWelsSvcRc->iBufferFullnessSkip = 0;
if( pEncCtx->iSkipFrameFlag==1 )
{
pWelsSvcRc->iRemainingBits += (int32_t)(pWelsSvcRc->dBitsPerFrame + 0.5);
pWelsSvcRc->iSkipFrameNum++;
pWelsSvcRc->iSkipFrameInVGop++;
}
}
void RcVBufferCalculationPadding(sWelsEncCtx *pEncCtx)
{
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
const int32_t kiOutputBits = (int32_t)(pWelsSvcRc->dBitsPerFrame + 0.5);
const int32_t kiBufferThreshold = (int32_t)(PADDING_THRESHOLD*(-pWelsSvcRc->iBufferSizePadding));
pWelsSvcRc->iBufferFullnessPadding += (pWelsSvcRc->iFrameDqBits - kiOutputBits);
if( pWelsSvcRc->iBufferFullnessPadding < kiBufferThreshold )
{
pWelsSvcRc->iPaddingSize = -pWelsSvcRc->iBufferFullnessPadding;
pWelsSvcRc->iPaddingSize >>= 3; // /8
pWelsSvcRc->iBufferFullnessPadding = 0;
}
else
pWelsSvcRc->iPaddingSize=0;
}
void RcTraceFrameBits(sWelsEncCtx *pEncCtx)
{
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
WelsLog( pEncCtx, WELS_LOG_INFO,"[Rc] encoding_qp%d, qp = %3d, index = %8d, iTid = %1d, used = %8d, target = %8d, remaingbits = %8d\n",
pEncCtx->uiDependencyId, pWelsSvcRc->iAverageFrameQp, pEncCtx->uiFrameIdxRc, pEncCtx->uiTemporalId, pWelsSvcRc->iFrameDqBits,
pWelsSvcRc->iTargetBits,pWelsSvcRc->iRemainingBits);
}
void RcUpdatePictureQpBits(sWelsEncCtx *pEncCtx, int32_t iCodedBits)
{
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
SRCSlicing *pSOverRc = &pWelsSvcRc->pSlicingOverRc[0];
SSliceCtx *pCurSliceCtx = pEncCtx->pCurDqLayer->pSliceEncCtx;
int32_t iTotalQp = 0, iTotalMb = 0;
int32_t i;
if(pEncCtx->eSliceType == P_SLICE)
{
for( i=0; i<pCurSliceCtx->iSliceNumInFrame; i++ )
{
iTotalQp += pSOverRc->iTotalQpSlice;
iTotalMb += pSOverRc->iTotalMbSlice;
++ pSOverRc;
}
if(iTotalMb > 0)
pWelsSvcRc->iAverageFrameQp = (int32_t)(1.0*iTotalQp/iTotalMb+0.5);
else
pWelsSvcRc->iAverageFrameQp = pEncCtx->iGlobalQp;
}
else
{
pWelsSvcRc->iAverageFrameQp = pEncCtx->iGlobalQp;
}
pWelsSvcRc->iFrameDqBits = iCodedBits;
pWelsSvcRc->pTemporalOverRc[pEncCtx->uiTemporalId].iGopBitsDq += pWelsSvcRc->iFrameDqBits;
}
void RcUpdateIntraComplexity(sWelsEncCtx *pEncCtx)
{
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
double iAlpha = 1.0/(1+pWelsSvcRc->iIdrNum);
if(iAlpha < 0.25) iAlpha = 0.25;
double dIntraCmplx = pWelsSvcRc->dQStep*pWelsSvcRc->iFrameDqBits;
dIntraCmplx = (1.0-iAlpha)*pWelsSvcRc->iIntraComplexity + iAlpha*dIntraCmplx;
pWelsSvcRc->iIntraComplexity = (int32_t)(dIntraCmplx + 0.5);
pWelsSvcRc->iIntraMbCount = pWelsSvcRc->iNumberMbFrame;
pWelsSvcRc->iIdrNum++;
if(pWelsSvcRc->iIdrNum > 255)
pWelsSvcRc->iIdrNum = 255;
}
void RcUpdateFrameComplexity(sWelsEncCtx *pEncCtx)
{
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
const int32_t kiTl = pEncCtx->uiTemporalId;
SRCTemporal *pTOverRc = &pWelsSvcRc->pTemporalOverRc[kiTl];
if(0 == pTOverRc->iPFrameNum){
pTOverRc->dLinearCmplx = pWelsSvcRc->iFrameDqBits * pWelsSvcRc->dQStep;
}
else{
pTOverRc->dLinearCmplx = LINEAR_MODEL_DECAY_FACTOR*pTOverRc->dLinearCmplx
+ (1.0-LINEAR_MODEL_DECAY_FACTOR)*(pWelsSvcRc->iFrameDqBits * pWelsSvcRc->dQStep);
}
double iAlpha = 1.0/(1+pTOverRc->iPFrameNum);
if(iAlpha < SMOOTH_FACTOR_MIN_VALUE)
iAlpha = SMOOTH_FACTOR_MIN_VALUE;
pTOverRc->iFrameCmplxMean = (int32_t)((1.0-iAlpha)*pTOverRc->iFrameCmplxMean + iAlpha*pEncCtx->pVaa->sComplexityAnalysisParam.iFrameComplexity + 0.5);
pTOverRc->iPFrameNum++;
if(pTOverRc->iPFrameNum > 255)
pTOverRc->iPFrameNum = 255;
}
int32_t RcCalculateCascadingQp(struct TagWelsEncCtx *pEncCtx, int32_t iQp)
{
int32_t iTemporalQp = 0;
if( pEncCtx->pSvcParam->iDecompStages )
{
if( pEncCtx->uiTemporalId==0 )
iTemporalQp = iQp - 3 - (pEncCtx->pSvcParam->iDecompStages-1);
else
iTemporalQp = iQp - (pEncCtx->pSvcParam->iDecompStages - pEncCtx->uiTemporalId);
iTemporalQp = WELS_CLIP3( iTemporalQp, 1, 51 );
}
else
iTemporalQp = iQp;
return iTemporalQp;
}
void WelsRcPictureInitGom(void *pCtx)
{
sWelsEncCtx *pEncCtx = (sWelsEncCtx*)pCtx;
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
if ( pEncCtx->eSliceType == I_SLICE )
{
if(0 == pWelsSvcRc->iIdrNum) //iIdrNum == 0 means encoder has been initialed
{
RcInitRefreshParameter(pEncCtx);
}
}
if( RcJudgeBitrateFpsUpdate(pEncCtx))
{
RcUpdateBitrateFps(pEncCtx);
}
if( pEncCtx->uiTemporalId == 0 )
{
RcUpdateTemporalZero(pEncCtx);
}
RcDecideTargetBits(pEncCtx);
//decide globe_qp
if(pEncCtx->eSliceType == I_SLICE)
{
if(0 == pWelsSvcRc->iIdrNum)
RcInitIdrQp(pEncCtx);
else
{
RcCalculateIdrQp(pEncCtx);
}
}
else
{
RcCalculatePictureQp(pEncCtx);
}
RcInitSliceInformation(pEncCtx);
RcInitGoomParameters(pEncCtx);
}
void WelsRcPictureInfoUpdateGom(void *pCtx, int32_t layer_size)
{
sWelsEncCtx *pEncCtx = (sWelsEncCtx*)pCtx;
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
int32_t iCodedBits = (layer_size<<3);
RcUpdatePictureQpBits(pEncCtx, iCodedBits);
if ( pEncCtx->eSliceType == P_SLICE )
{
RcUpdateFrameComplexity(pEncCtx);
}
else
{
RcUpdateIntraComplexity(pEncCtx);
}
pWelsSvcRc->iRemainingBits -= pWelsSvcRc->iFrameDqBits;
#if GOM_TRACE_FLAG
RcTraceFrameBits(pEncCtx);
#endif
#if SKIP_FRAME_FLAG
if ( pEncCtx->uiDependencyId == pEncCtx->pSvcParam->iNumDependencyLayer - 1 )
{
RcVBufferCalculationSkip(pEncCtx);
}
#endif
if ( pEncCtx->pSvcParam->iPaddingFlag )
RcVBufferCalculationPadding(pEncCtx);
pWelsSvcRc->iFrameCodedInVGop++;
#ifdef _TEST_TEMP_Rc_
fprintf(fp_test_rc, "%d\n", pWelsSvcRc->iFrameDqBits);
if(pEncCtx->iSkipFrameFlag)
fprintf(fp_test_rc, "0\n");
fflush(fp_test_rc);
#endif
}
void WelsRcMbInitGom(void *pCtx, SMB* pCurMb, SSlice *pSlice)
{
sWelsEncCtx *pEncCtx = (sWelsEncCtx*)pCtx;
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
const int32_t kiSliceId = pSlice->uiSliceIdx;
SRCSlicing *pSOverRc = &pWelsSvcRc->pSlicingOverRc[kiSliceId];
SBitStringAux * bs = pSlice->pSliceBsa;
pSOverRc->iBsPosSlice = BsGetBitsPos(bs);
if(pEncCtx->eSliceType==I_SLICE)
return;
//calculate gom qp and target bits at the beginning of gom
if(0 == (pCurMb->iMbXY%pWelsSvcRc->iNumberMbGom)){
if(pCurMb->iMbXY != pSOverRc->iStartMbSlice){
pSOverRc->iComplexityIndexSlice++;
RcCalculateGomQp(pEncCtx, pCurMb, kiSliceId);
}
RcGomTargetBits(pEncCtx, kiSliceId);
}
RcCalculateMbQp(pEncCtx,pCurMb,kiSliceId);
}
void WelsRcMbInfoUpdateGom(void *pCtx, SMB* pCurMb, int32_t iCostLuma, SSlice *pSlice)
{
sWelsEncCtx *pEncCtx = (sWelsEncCtx*)pCtx;
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
SBitStringAux * bs = pSlice->pSliceBsa;
int32_t iSliceId = pSlice->uiSliceIdx;
SRCSlicing *pSOverRc = &pWelsSvcRc->pSlicingOverRc[iSliceId];
const int32_t kiComplexityIndex = pSOverRc->iComplexityIndexSlice;
int32_t cur_mb_bits = BsGetBitsPos(bs) - pSOverRc->iBsPosSlice;
pSOverRc->iFrameBitsSlice += cur_mb_bits;
pSOverRc->iGomBitsSlice += cur_mb_bits;
pWelsSvcRc->pGomCost[kiComplexityIndex] += iCostLuma;
if(cur_mb_bits > 0){
pSOverRc->iTotalQpSlice += pCurMb->uiLumaQp;
pSOverRc->iTotalMbSlice++;
}
}
void WelsRcPictureInitDisable(void *pCtx)
{
sWelsEncCtx *pEncCtx = (sWelsEncCtx*)pCtx;
SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
SDLayerParam *pDLayerParam = &pEncCtx->pSvcParam->sDependencyLayers[pEncCtx->uiDependencyId];
const int32_t kiQp = pDLayerParam->iDLayerQp;
pEncCtx->iGlobalQp = RcCalculateCascadingQp( pEncCtx, kiQp );
if ( pEncCtx->pSvcParam->bEnableAdaptiveQuant && (pEncCtx->eSliceType == P_SLICE) )
{
pEncCtx->iGlobalQp = (int32_t)WELS_CLIP3(pEncCtx->iGlobalQp -
pEncCtx->pVaa->sAdaptiveQuantParam.dAverMotionTextureIndexToDeltaQp, GOM_MIN_QP_MODE, GOM_MAX_QP_MODE);
}
pWelsSvcRc->iAverageFrameQp = pEncCtx->iGlobalQp;
}
void WelsRcPictureInfoUpdateDisable(void *pCtx, int32_t layer_size)
{
}
void WelsRcMbInitDisable(void *pCtx, SMB* pCurMb, SSlice *pSlice)
{
sWelsEncCtx *pEncCtx = (sWelsEncCtx*)pCtx;
int32_t iLumaQp = pEncCtx->iGlobalQp;
if ( pEncCtx->pSvcParam->bEnableAdaptiveQuant && (pEncCtx->eSliceType == P_SLICE) )
{
iLumaQp = (int8_t)WELS_CLIP3(iLumaQp +
pEncCtx->pVaa->sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp[pCurMb->iMbXY], GOM_MIN_QP_MODE, 51);
}
pCurMb->uiChromaQp = g_kuiChromaQpTable[iLumaQp];
pCurMb->uiLumaQp = iLumaQp;
}
void WelsRcMbInfoUpdateDisable(void *pCtx, SMB* pCurMb, int32_t iCostLuma, SSlice *pSlice)
{
}
void WelsRcInitModule(void *pCtx, int32_t iModule)
{
sWelsEncCtx *pEncCtx = (sWelsEncCtx*)pCtx;
SWelsRcFunc * pRcf = &pEncCtx->pFuncList->pfRc;
switch(iModule)
{
case WELS_RC_DISABLE:
pRcf->pfWelsRcPictureInit = WelsRcPictureInitDisable;
pRcf->pfWelsRcPictureInfoUpdate = WelsRcPictureInfoUpdateDisable;
pRcf->pfWelsRcMbInit = WelsRcMbInitDisable;
pRcf->pfWelsRcMbInfoUpdate = WelsRcMbInfoUpdateDisable;
break;
case WELS_RC_GOM:
default:
pRcf->pfWelsRcPictureInit = WelsRcPictureInitGom;
pRcf->pfWelsRcPictureInfoUpdate = WelsRcPictureInfoUpdateGom;
pRcf->pfWelsRcMbInit = WelsRcMbInitGom;
pRcf->pfWelsRcMbInfoUpdate = WelsRcMbInfoUpdateGom;
break;
}
RcInitSequenceParameter(pEncCtx);
}
void WelsRcFreeMemory(void *pCtx)
{
sWelsEncCtx *pEncCtx = (sWelsEncCtx*)pCtx;
SWelsSvcRc *pWelsSvcRc = NULL;
int32_t i = 0;
#ifdef _TEST_TEMP_Rc_
if(fp_test_rc)
fclose(fp_test_rc);
fp_test_rc = NULL;
if(fp_vgop)
fclose(fp_vgop);
fp_vgop = NULL;
#endif
for( i=0; i<pEncCtx->pSvcParam->iNumDependencyLayer; i++ )
{
pWelsSvcRc = &pEncCtx->pWelsSvcRc[i];
RcFreeLayerMemory(pWelsSvcRc, pEncCtx->pMemAlign);
}
}
}//end of namespace