Ethan HuggInitial Commit70e5e6212 years agoHistory
1049 lines · 35.4 KB · C++
RawDownload
/*!
 * \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);

Lines 1–500 of 1049.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t