Showing the changes to codec/encoder/core/src/ratectl.cpp (1 of 308 files). Show all
Unified · Split
| @@ -0,0 +1,1049 @@ | |||
| 1 | /*! | ||
| 2 | * \copy | ||
| 3 | * Copyright (c) 2009-2013, Cisco Systems | ||
| 4 | * All rights reserved. | ||
| 5 | * | ||
| 6 | * Redistribution and use in source and binary forms, with or without | ||
| 7 | * modification, are permitted provided that the following conditions | ||
| 8 | * are met: | ||
| 9 | * | ||
| 10 | * * Redistributions of source code must retain the above copyright | ||
| 11 | * notice, this list of conditions and the following disclaimer. | ||
| 12 | * | ||
| 13 | * * Redistributions in binary form must reproduce the above copyright | ||
| 14 | * notice, this list of conditions and the following disclaimer in | ||
| 15 | * the documentation and/or other materials provided with the | ||
| 16 | * distribution. | ||
| 17 | * | ||
| 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
| 21 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
| 22 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
| 23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
| 24 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
| 25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
| 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
| 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
| 28 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
| 29 | * POSSIBILITY OF SUCH DAMAGE. | ||
| 30 | * | ||
| 31 | * | ||
| 32 | * ratectl.c | ||
| 33 | * | ||
| 34 | * Abstract | ||
| 35 | * Rate Control | ||
| 36 | * | ||
| 37 | * History | ||
| 38 | * 9/8/2009 Created | ||
| 39 | * 12/26/2011 Modified | ||
| 40 | * | ||
| 41 | * | ||
| 42 | * | ||
| 43 | *************************************************************************/ | ||
| 44 | #include <stdlib.h> | ||
| 45 | #include <stdio.h> | ||
| 46 | #include <math.h> | ||
| 47 | #include "rc.h" | ||
| 48 | #include "encoder_context.h" | ||
| 49 | #include "utils.h" | ||
| 50 | #include "svc_enc_golomb.h" | ||
| 51 | |||
| 52 | |||
| 53 | namespace WelsSVCEnc { | ||
| 54 | |||
| 55 | //#define _TEST_TEMP_RC_ | ||
| 56 | #ifdef _TEST_TEMP_RC_ | ||
| 57 | //#define _NOT_USE_AQ_FOR_TEST_ | ||
| 58 | FILE *fp_test_rc = NULL; | ||
| 59 | FILE *fp_vgop = NULL; | ||
| 60 | #endif | ||
| 61 | #define _BITS_RANGE 0 | ||
| 62 | |||
| 63 | void RcInitLayerMemory(SWelsSvcRc *pWelsSvcRc, CMemoryAlign *pMA, const int32_t kiMaxTl) | ||
| 64 | { | ||
| 65 | const int32_t kiSliceNum = pWelsSvcRc->iSliceNum; | ||
| 66 | const int32_t kiGomSize = pWelsSvcRc->iGomSize; | ||
| 67 | const int32_t kiGomSizeD = kiGomSize * sizeof(double); | ||
| 68 | const int32_t kiGomSizeI = kiGomSize * sizeof(int32_t); | ||
| 69 | const int32_t kiLayerRcSize = kiGomSizeD + (kiGomSizeI*3) + sizeof(SRCSlicing)*kiSliceNum + sizeof(SRCTemporal)*kiMaxTl; | ||
| 70 | uint8_t *pBaseMem = (uint8_t *)pMA->WelsMalloc(kiLayerRcSize, "rc_layer_memory"); | ||
| 71 | |||
| 72 | if (NULL == pBaseMem) | ||
| 73 | return; | ||
| 74 | |||
| 75 | pWelsSvcRc->pGomComplexity = (double *)pBaseMem; | ||
| 76 | pBaseMem += kiGomSizeD; | ||
| 77 | pWelsSvcRc->pGomForegroundBlockNum = (int32_t *)pBaseMem; | ||
| 78 | pBaseMem += kiGomSizeI; | ||
| 79 | pWelsSvcRc->pCurrentFrameGomSad = (int32_t *)pBaseMem; | ||
| 80 | pBaseMem += kiGomSizeI; | ||
| 81 | pWelsSvcRc->pGomCost = (int32_t *)pBaseMem; | ||
| 82 | pBaseMem += kiGomSizeI; | ||
| 83 | pWelsSvcRc->pSlicingOverRc = (SRCSlicing *)pBaseMem; | ||
| 84 | pBaseMem += sizeof(SRCSlicing)*kiSliceNum; | ||
| 85 | pWelsSvcRc->pTemporalOverRc = (SRCTemporal *)pBaseMem; | ||
| 86 | } | ||
| 87 | |||
| 88 | void RcFreeLayerMemory(SWelsSvcRc *pWelsSvcRc, CMemoryAlign *pMA) | ||
| 89 | { | ||
| 90 | if (pWelsSvcRc != NULL && pWelsSvcRc->pGomComplexity != NULL) | ||
| 91 | { | ||
| 92 | pMA->WelsFree(pWelsSvcRc->pGomComplexity, "rc_layer_memory"); | ||
| 93 | pWelsSvcRc->pGomComplexity = NULL; | ||
| 94 | pWelsSvcRc->pGomForegroundBlockNum = NULL; | ||
| 95 | pWelsSvcRc->pCurrentFrameGomSad = NULL; | ||
| 96 | pWelsSvcRc->pGomCost = NULL; | ||
| 97 | pWelsSvcRc->pSlicingOverRc = NULL; | ||
| 98 | pWelsSvcRc->pTemporalOverRc = NULL; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | static inline double RcConvertQp2QStep(double dQP) | ||
| 103 | { | ||
| 104 | return pow( 2.0, (dQP-4.0)/6.0 ); | ||
| 105 | } | ||
| 106 | static inline double RcConvertQStep2Qp(double dQpStep) | ||
| 107 | { | ||
| 108 | return (6 * log(dQpStep) / log(2.0) + 4.0); | ||
| 109 | } | ||
| 110 | |||
| 111 | void RcInitSequenceParameter(sWelsEncCtx *pEncCtx) | ||
| 112 | { | ||
| 113 | SWelsSvcRc *pWelsSvcRc = NULL; | ||
| 114 | SDLayerParam *pDLayerParam = NULL; | ||
| 115 | |||
| 116 | int32_t j = 0; | ||
| 117 | int32_t iMbWidth = 0; | ||
| 118 | |||
| 119 | BOOL_T bMultiSliceMode = FALSE; | ||
| 120 | int32_t iGomRowMode0 = 1, iGomRowMode1 = 1; | ||
| 121 | #ifdef _TEST_TEMP_RC_ | ||
| 122 | fp_test_rc = fopen("testRC.dat","w"); | ||
| 123 | fp_vgop = fopen("vgop.dat","w"); | ||
| 124 | #endif | ||
| 125 | for( j=0; j<pEncCtx->pSvcParam->iNumDependencyLayer; j++ ) | ||
| 126 | { | ||
| 127 | SSliceCtx *pSliceCtx = &pEncCtx->pSliceCtxList[j]; | ||
| 128 | pWelsSvcRc = &pEncCtx->pWelsSvcRc[j]; | ||
| 129 | pDLayerParam = &pEncCtx->pSvcParam->sDependencyLayers[j]; | ||
| 130 | iMbWidth = (pDLayerParam->iFrameWidth>>4); | ||
| 131 | pWelsSvcRc->iNumberMbFrame = iMbWidth*(pDLayerParam->iFrameHeight>>4); | ||
| 132 | pWelsSvcRc->iSliceNum= pSliceCtx->iSliceNumInFrame; | ||
| 133 | |||
| 134 | pWelsSvcRc->iRcVaryPercentage = _BITS_RANGE; // % -- for temp | ||
| 135 | pWelsSvcRc->dRcVaryRatio = (double)pWelsSvcRc->iRcVaryPercentage/MAX_BITS_VARY_PERCENTAGE; | ||
| 136 | |||
| 137 | pWelsSvcRc->dSkipBufferRatio = SKIP_RATIO; | ||
| 138 | |||
| 139 | pWelsSvcRc->iQpRangeUpperInFrame = QP_RANGE_UPPER_MODE1 - (int32_t)((QP_RANGE_UPPER_MODE1 - QP_RANGE_MODE0)*pWelsSvcRc->dRcVaryRatio + 0.5); | ||
| 140 | pWelsSvcRc->iQpRangeLowerInFrame = QP_RANGE_LOWER_MODE1 - (int32_t)((QP_RANGE_LOWER_MODE1 - QP_RANGE_MODE0)*pWelsSvcRc->dRcVaryRatio + 0.5); | ||
| 141 | |||
| 142 | if( iMbWidth<=MB_WIDTH_THRESHOLD_90P ) | ||
| 143 | { | ||
| 144 | pWelsSvcRc->iSkipQpValue = SKIP_QP_90P; | ||
| 145 | iGomRowMode0 = GOM_ROW_MODE0_90P; | ||
| 146 | iGomRowMode1 = GOM_ROW_MODE1_90P; | ||
| 147 | } | ||
| 148 | else if( iMbWidth<=MB_WIDTH_THRESHOLD_180P ) | ||
| 149 | { | ||
| 150 | pWelsSvcRc->iSkipQpValue = SKIP_QP_180P; | ||
| 151 | iGomRowMode0 = GOM_ROW_MODE0_180P; | ||
| 152 | iGomRowMode1 = GOM_ROW_MODE1_180P; | ||
| 153 | } | ||
| 154 | else if( iMbWidth<=MB_WIDTH_THRESHOLD_360P ) | ||
| 155 | { | ||
| 156 | pWelsSvcRc->iSkipQpValue = SKIP_QP_360P; | ||
| 157 | iGomRowMode0 = GOM_ROW_MODE0_360P; | ||
| 158 | iGomRowMode1 = GOM_ROW_MODE1_360P; | ||
| 159 | } | ||
| 160 | else | ||
| 161 | { | ||
| 162 | pWelsSvcRc->iSkipQpValue = SKIP_QP_720P; | ||
| 163 | iGomRowMode0 = GOM_ROW_MODE0_720P; | ||
| 164 | iGomRowMode1 = GOM_ROW_MODE1_720P; | ||
| 165 | } | ||
| 166 | iGomRowMode0 = iGomRowMode1 + (int32_t)((iGomRowMode0 - iGomRowMode1)*pWelsSvcRc->dRcVaryRatio + 0.5); | ||
| 167 | |||
| 168 | pWelsSvcRc->iNumberMbGom = iMbWidth*iGomRowMode0; | ||
| 169 | |||
| 170 | pWelsSvcRc->iMinQp = GOM_MIN_QP_MODE; | ||
| 171 | pWelsSvcRc->iMaxQp = GOM_MAX_QP_MODE; | ||
| 172 | |||
| 173 | 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); | ||
| 174 | 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); | ||
| 175 | |||
| 176 | pWelsSvcRc->iSkipFrameNum = 0; | ||
| 177 | pWelsSvcRc->iGomSize = (pWelsSvcRc->iNumberMbFrame+pWelsSvcRc->iNumberMbGom-1)/pWelsSvcRc->iNumberMbGom; | ||
| 178 | |||
| 179 | |||
| 180 | RcInitLayerMemory( pWelsSvcRc, pEncCtx->pMemAlign, 1+pDLayerParam->iHighestTemporalId ); | ||
| 181 | |||
| 182 | bMultiSliceMode = ( (SM_RASTER_SLICE == pDLayerParam->sMso.uiSliceMode) || | ||
| 183 | (SM_ROWMB_SLICE == pDLayerParam->sMso.uiSliceMode) || | ||
| 184 | (SM_DYN_SLICE == pDLayerParam->sMso.uiSliceMode) ); | ||
| 185 | if( bMultiSliceMode ) | ||
| 186 | pWelsSvcRc->iNumberMbGom = pWelsSvcRc->iNumberMbFrame; | ||
| 187 | } | ||
| 188 | } | ||
| 189 | |||
| 190 | |||
| 191 | void RcInitTlWeight(sWelsEncCtx *pEncCtx) | ||
| 192 | { | ||
| 193 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 194 | SRCTemporal *pTOverRc = pWelsSvcRc->pTemporalOverRc; | ||
| 195 | SDLayerParam *pDLayerParam = &pEncCtx->pSvcParam->sDependencyLayers[pEncCtx->uiDependencyId]; | ||
| 196 | const int32_t kiDecompositionStages = pDLayerParam->iDecompositionStages; | ||
| 197 | const int32_t kiHighestTid = pDLayerParam->iHighestTemporalId; | ||
| 198 | |||
| 199 | //Index 0:Virtual GOP size, Index 1:Frame rate | ||
| 200 | 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}}; | ||
| 201 | const int32_t kiGopSize = (1<<kiDecompositionStages); | ||
| 202 | int32_t i, k, n; | ||
| 203 | |||
| 204 | n = 0; | ||
| 205 | while (n <= kiHighestTid) | ||
| 206 | { | ||
| 207 | pTOverRc[n].dTlayerWeight = WeightArray[kiDecompositionStages][n]; | ||
| 208 | ++ n; | ||
| 209 | } | ||
| 210 | //Calculate the frame index for the current frame and its reference frame | ||
| 211 | for( n=0; n<VGOP_SIZE; n+=kiGopSize ) | ||
| 212 | { | ||
| 213 | pWelsSvcRc->iTlOfFrames[n] = 0; | ||
| 214 | for( i=1; i<=kiDecompositionStages; i++ ) | ||
| 215 | { | ||
| 216 | for( k=1<<(kiDecompositionStages-i); k<kiGopSize; k+=(kiGopSize>>(i-1)) ) | ||
| 217 | { | ||
| 218 | pWelsSvcRc->iTlOfFrames[k+n]=i; | ||
| 219 | } | ||
| 220 | } | ||
| 221 | } | ||
| 222 | pWelsSvcRc->iPreviousGopSize = kiGopSize; | ||
| 223 | pWelsSvcRc->iGopNumberInVGop = VGOP_SIZE/kiGopSize; | ||
| 224 | } | ||
| 225 | |||
| 226 | void RcUpdateBitrateFps(sWelsEncCtx *pEncCtx) | ||
| 227 | { | ||
| 228 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 229 | SRCTemporal *pTOverRc = pWelsSvcRc->pTemporalOverRc; | ||
| 230 | SDLayerParam *pDLayerParam = &pEncCtx->pSvcParam->sDependencyLayers[pEncCtx->uiDependencyId]; | ||
| 231 | const int32_t kiGopSize = (1<<pDLayerParam->iDecompositionStages); | ||
| 232 | const int32_t kiHighestTid = pDLayerParam->iHighestTemporalId; | ||
| 233 | double input_dBitsPerFrame = pDLayerParam->iSpatialBitrate / pDLayerParam->fInputFrameRate; | ||
| 234 | const int32_t kiGopBits = (int32_t)(input_dBitsPerFrame*kiGopSize); | ||
| 235 | int32_t i; | ||
| 236 | |||
| 237 | pWelsSvcRc->iBitRate = pDLayerParam->iSpatialBitrate; | ||
| 238 | pWelsSvcRc->fFrameRate = pDLayerParam->fInputFrameRate; | ||
| 239 | |||
| 240 | double dTargetVaryRange = FRAME_iTargetBits_VARY_RANGE*(1.0 - pWelsSvcRc->dRcVaryRatio); | ||
| 241 | double dMinBitsRatio = 1.0 - dTargetVaryRange; | ||
| 242 | double dMaxBitsRatio = 1.0 + FRAME_iTargetBits_VARY_RANGE;//dTargetVaryRange; | ||
| 243 | |||
| 244 | for( i=0; i<=kiHighestTid; i++) | ||
| 245 | { | ||
| 246 | const double kdConstraitBits = kiGopBits*pTOverRc[i].dTlayerWeight; | ||
| 247 | pTOverRc[i].iMinBitsTl = (int32_t)(kdConstraitBits*dMinBitsRatio); | ||
| 248 | pTOverRc[i].iMaxBitsTl = (int32_t)(kdConstraitBits*dMaxBitsRatio); | ||
| 249 | } | ||
| 250 | //When bitrate is changed, pBuffer size should be updated | ||
| 251 | pWelsSvcRc->iBufferSizeSkip = (int32_t)(pWelsSvcRc->iBitRate * pWelsSvcRc->dSkipBufferRatio); | ||
| 252 | pWelsSvcRc->iBufferSizePadding = (int32_t)(pWelsSvcRc->iBitRate * PADDING_BUFFER_RATIO); | ||
| 253 | |||
| 254 | //change remaining bits | ||
| 255 | if(pWelsSvcRc->dBitsPerFrame > 0.1) | ||
| 256 | pWelsSvcRc->iRemainingBits = (int32_t)(pWelsSvcRc->iRemainingBits*input_dBitsPerFrame/pWelsSvcRc->dBitsPerFrame); | ||
| 257 | pWelsSvcRc->dBitsPerFrame = input_dBitsPerFrame; | ||
| 258 | } | ||
| 259 | |||
| 260 | |||
| 261 | void RcInitVGop(sWelsEncCtx *pEncCtx) | ||
| 262 | { | ||
| 263 | const int32_t kiDid = pEncCtx->uiDependencyId; | ||
| 264 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[kiDid]; | ||
| 265 | SRCTemporal *pTOverRc = pWelsSvcRc->pTemporalOverRc; | ||
| 266 | const int32_t kiHighestTid = pEncCtx->pSvcParam->sDependencyLayers[kiDid].iHighestTemporalId; | ||
| 267 | |||
| 268 | pWelsSvcRc->iRemainingBits = (int32_t)(VGOP_SIZE*pWelsSvcRc->dBitsPerFrame); | ||
| 269 | pWelsSvcRc->dRemainingWeights = pWelsSvcRc->iGopNumberInVGop; | ||
| 270 | |||
| 271 | pWelsSvcRc->iFrameCodedInVGop = 0; | ||
| 272 | pWelsSvcRc->iGopIndexInVGop = 0; | ||
| 273 | |||
| 274 | for (int32_t i = 0; i <= kiHighestTid; ++ i) | ||
| 275 | pTOverRc[i].iGopBitsDq = 0; | ||
| 276 | pWelsSvcRc->iSkipFrameInVGop=0; | ||
| 277 | } | ||
| 278 | |||
| 279 | void RcInitRefreshParameter(sWelsEncCtx *pEncCtx) | ||
| 280 | { | ||
| 281 | const int32_t kiDid = pEncCtx->uiDependencyId; | ||
| 282 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[kiDid]; | ||
| 283 | SRCTemporal *pTOverRc = pWelsSvcRc->pTemporalOverRc; | ||
| 284 | SDLayerParam *pDLayerParam = &pEncCtx->pSvcParam->sDependencyLayers[kiDid]; | ||
| 285 | const int32_t kiHighestTid = pDLayerParam->iHighestTemporalId; | ||
| 286 | int32_t i; | ||
| 287 | |||
| 288 | //I frame R-Q Model | ||
| 289 | pWelsSvcRc->iIntraComplexity = 0; | ||
| 290 | pWelsSvcRc->iIntraMbCount = 0; | ||
| 291 | |||
| 292 | //P frame R-Q Model | ||
| 293 | for(i=0; i<=kiHighestTid; i++) | ||
| 294 | { | ||
| 295 | pTOverRc[i].iPFrameNum = 0; | ||
| 296 | pTOverRc[i].dLinearCmplx = 0.0; | ||
| 297 | pTOverRc[i].iFrameCmplxMean = 0; | ||
| 298 | } | ||
| 299 | |||
| 300 | pWelsSvcRc->iBufferFullnessSkip = 0; | ||
| 301 | pWelsSvcRc->iBufferFullnessPadding = 0; | ||
| 302 | |||
| 303 | pWelsSvcRc->iGopIndexInVGop = 0; | ||
| 304 | pWelsSvcRc->iRemainingBits = 0; | ||
| 305 | pWelsSvcRc->dBitsPerFrame = 0.0; | ||
| 306 | |||
| 307 | //Backup the initial bitrate and fps | ||
| 308 | pWelsSvcRc->iPreviousBitrate = pDLayerParam->iSpatialBitrate; | ||
| 309 | pWelsSvcRc->dPreviousFps = pDLayerParam->fInputFrameRate; | ||
| 310 | |||
| 311 | memset( pWelsSvcRc->pCurrentFrameGomSad, 0, pWelsSvcRc->iGomSize*sizeof(int32_t) ); | ||
| 312 | |||
| 313 | RcInitTlWeight(pEncCtx); | ||
| 314 | RcUpdateBitrateFps(pEncCtx); | ||
| 315 | RcInitVGop(pEncCtx); | ||
| 316 | } | ||
| 317 | |||
| 318 | bool_t RcJudgeBitrateFpsUpdate(sWelsEncCtx *pEncCtx) | ||
| 319 | { | ||
| 320 | int32_t iCurDid = pEncCtx->uiDependencyId; | ||
| 321 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[iCurDid]; | ||
| 322 | SDLayerParam *pDLayerParam = &pEncCtx->pSvcParam->sDependencyLayers[iCurDid]; | ||
| 323 | |||
| 324 | if((pWelsSvcRc->iPreviousBitrate != pDLayerParam->iSpatialBitrate) || | ||
| 325 | (pWelsSvcRc->dPreviousFps-pDLayerParam->fInputFrameRate)>EPSN || | ||
| 326 | (pWelsSvcRc->dPreviousFps-pDLayerParam->fInputFrameRate)<-EPSN) | ||
| 327 | { | ||
| 328 | pWelsSvcRc->iPreviousBitrate = pDLayerParam->iSpatialBitrate; | ||
| 329 | pWelsSvcRc->dPreviousFps = pDLayerParam->fInputFrameRate; | ||
| 330 | return true; | ||
| 331 | } | ||
| 332 | else | ||
| 333 | return false; | ||
| 334 | } | ||
| 335 | |||
| 336 | #if GOM_TRACE_FLAG | ||
| 337 | void RcTraceVGopBitrate(sWelsEncCtx *pEncCtx) | ||
| 338 | { | ||
| 339 | const int32_t kiDid = pEncCtx->uiDependencyId; | ||
| 340 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[kiDid]; | ||
| 341 | |||
| 342 | if( pWelsSvcRc->iFrameCodedInVGop ) | ||
| 343 | { | ||
| 344 | const int32_t kiHighestTid = pEncCtx->pSvcParam->sDependencyLayers[kiDid].iHighestTemporalId; | ||
| 345 | SRCTemporal *pTOverRc = pWelsSvcRc->pTemporalOverRc; | ||
| 346 | int32_t iVGopBitrate; | ||
| 347 | int32_t iTotalBits = pWelsSvcRc->iPaddingBitrateStat; | ||
| 348 | int32_t iTid = 0; | ||
| 349 | while (iTid <= kiHighestTid) | ||
| 350 | { | ||
| 351 | iTotalBits += pTOverRc[iTid].iGopBitsDq; | ||
| 352 | ++ iTid; | ||
| 353 | } | ||
| 354 | int32_t iFrameInVGop = pWelsSvcRc->iFrameCodedInVGop+pWelsSvcRc->iSkipFrameInVGop; | ||
| 355 | if(0 != iFrameInVGop) | ||
| 356 | iVGopBitrate = (int32_t)( iTotalBits/iFrameInVGop *pWelsSvcRc->fFrameRate ); | ||
| 357 | #ifdef _TEST_TEMP_Rc_ | ||
| 358 | fprintf(fp_vgop,"%d\n",(int32_t)((double)iTotalBits/iFrameInVGop)); | ||
| 359 | #endif | ||
| 360 | WelsLog( pEncCtx, WELS_LOG_INFO,"[Rc] VGOPbitrate%d: %d \n", kiDid, iVGopBitrate); | ||
| 361 | if ( iTotalBits > 0 ) | ||
| 362 | { | ||
| 363 | iTid = 0; | ||
| 364 | while (iTid <= kiHighestTid) | ||
| 365 | { | ||
| 366 | WelsLog( pEncCtx, WELS_LOG_INFO,"T%d=%8.3f \n", iTid, (double)(pTOverRc[iTid].iGopBitsDq/iTotalBits) ); | ||
| 367 | ++ iTid; | ||
| 368 | } | ||
| 369 | } | ||
| 370 | } | ||
| 371 | } | ||
| 372 | #endif | ||
| 373 | |||
| 374 | void RcUpdateTemporalZero(sWelsEncCtx *pEncCtx) | ||
| 375 | { | ||
| 376 | const int32_t kiDid = pEncCtx->uiDependencyId; | ||
| 377 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[kiDid]; | ||
| 378 | SDLayerParam *pDLayerParam = &pEncCtx->pSvcParam->sDependencyLayers[kiDid]; | ||
| 379 | const int32_t kiGopSize = (1<<pDLayerParam->iDecompositionStages); | ||
| 380 | |||
| 381 | if( pWelsSvcRc->iPreviousGopSize != kiGopSize ) | ||
| 382 | { | ||
| 383 | #if GOM_TRACE_FLAG | ||
| 384 | RcTraceVGopBitrate(pEncCtx); | ||
| 385 | #endif | ||
| 386 | RcInitTlWeight(pEncCtx); | ||
| 387 | RcInitVGop(pEncCtx); | ||
| 388 | } | ||
| 389 | else if( pWelsSvcRc->iGopIndexInVGop == pWelsSvcRc->iGopNumberInVGop || pEncCtx->eSliceType == I_SLICE) | ||
| 390 | { | ||
| 391 | #if GOM_TRACE_FLAG | ||
| 392 | RcTraceVGopBitrate(pEncCtx); | ||
| 393 | #endif | ||
| 394 | RcInitVGop(pEncCtx); | ||
| 395 | } | ||
| 396 | pWelsSvcRc->iGopIndexInVGop++; | ||
| 397 | } | ||
| 398 | |||
| 399 | |||
| 400 | void RcInitIdrQp(sWelsEncCtx *pEncCtx) | ||
| 401 | { | ||
| 402 | double dBpp = 0; | ||
| 403 | int32_t i; | ||
| 404 | |||
| 405 | //64k@6fps for 90p: bpp 0.74 QP:24 | ||
| 406 | //192k@12fps for 180p: bpp 0.28 QP:26 | ||
| 407 | //512k@24fps for 360p: bpp 0.09 QP:30 | ||
| 408 | //1500k@30fps for 720p: bpp 0.05 QP:32 | ||
| 409 | 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}}; | ||
| 410 | int32_t dInitialQPArray[4][4] = {{28, 26, 24, 22}, {30, 28, 26, 24}, {32, 30, 28, 26}, {34, 32, 30, 28}}; | ||
| 411 | int32_t iBppIndex = 0; | ||
| 412 | |||
| 413 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 414 | SDLayerParam *pDLayerParam = &pEncCtx->pSvcParam->sDependencyLayers[pEncCtx->uiDependencyId]; | ||
| 415 | |||
| 416 | if (pDLayerParam->fOutputFrameRate > EPSN && pDLayerParam->iFrameWidth && pDLayerParam->iFrameHeight) | ||
| 417 | dBpp=(double)(pDLayerParam->iSpatialBitrate) / (double)(pDLayerParam->fOutputFrameRate * pDLayerParam->iFrameWidth * pDLayerParam->iFrameHeight); | ||
| 418 | else | ||
| 419 | dBpp = 0.1; | ||
| 420 | |||
| 421 | //Area*2 | ||
| 422 | if ( pDLayerParam->iFrameWidth*pDLayerParam->iFrameHeight <= 28800 ) // 90p video:160*90 | ||
| 423 | iBppIndex = 0; | ||
| 424 | else if ( pDLayerParam->iFrameWidth*pDLayerParam->iFrameHeight <= 115200 ) // 180p video:320*180 | ||
| 425 | iBppIndex = 1; | ||
| 426 | else if ( pDLayerParam->iFrameWidth*pDLayerParam->iFrameHeight <= 460800 ) // 360p video:640*360 | ||
| 427 | iBppIndex = 2; | ||
| 428 | else | ||
| 429 | iBppIndex = 3; | ||
| 430 | |||
| 431 | //Search | ||
| 432 | for( i=0; i<3; i++ ) | ||
| 433 | { | ||
| 434 | if ( dBpp<=dBppArray[iBppIndex][i] ) | ||
| 435 | break; | ||
| 436 | } | ||
| 437 | pWelsSvcRc->iInitialQp = dInitialQPArray[iBppIndex][i]; | ||
| 438 | pWelsSvcRc->iInitialQp = (int32_t)WELS_CLIP3( pWelsSvcRc->iInitialQp, MIN_IDR_QP, MAX_IDR_QP ); | ||
| 439 | pEncCtx->iGlobalQp = pWelsSvcRc->iInitialQp; | ||
| 440 | pWelsSvcRc->dQStep = RcConvertQp2QStep(pEncCtx->iGlobalQp); | ||
| 441 | pWelsSvcRc->iLastCalculatedQScale = pEncCtx->iGlobalQp; | ||
| 442 | } | ||
| 443 | |||
| 444 | void RcCalculateIdrQp(sWelsEncCtx *pEncCtx) | ||
| 445 | { | ||
| 446 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 447 | //obtain the idr qp using previous idr complexity | ||
| 448 | if(pWelsSvcRc->iNumberMbFrame != pWelsSvcRc->iIntraMbCount){ | ||
| 449 | pWelsSvcRc->iIntraComplexity = (int32_t)((double)pWelsSvcRc->iIntraComplexity*pWelsSvcRc->iNumberMbFrame/pWelsSvcRc->iIntraMbCount + 0.5); | ||
| 450 | } | ||
| 451 | pWelsSvcRc->iInitialQp = (int32_t)RcConvertQStep2Qp( (double)pWelsSvcRc->iIntraComplexity/pWelsSvcRc->iTargetBits); | ||
| 452 | pWelsSvcRc->iInitialQp = (int32_t)WELS_CLIP3( pWelsSvcRc->iInitialQp, MIN_IDR_QP, MAX_IDR_QP ); | ||
| 453 | pEncCtx->iGlobalQp = pWelsSvcRc->iInitialQp; | ||
| 454 | pWelsSvcRc->dQStep = RcConvertQp2QStep(pEncCtx->iGlobalQp); | ||
| 455 | pWelsSvcRc->iLastCalculatedQScale = pEncCtx->iGlobalQp; | ||
| 456 | } | ||
| 457 | |||
| 458 | |||
| 459 | void RcCalculatePictureQp(sWelsEncCtx *pEncCtx) | ||
| 460 | { | ||
| 461 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 462 | int32_t iTl = pEncCtx->uiTemporalId; | ||
| 463 | SRCTemporal *pTOverRc = &pWelsSvcRc->pTemporalOverRc[iTl]; | ||
| 464 | int32_t iLumaQp = 0; | ||
| 465 | |||
| 466 | if(0 == pTOverRc->iPFrameNum) | ||
| 467 | { | ||
| 468 | iLumaQp = pWelsSvcRc->iInitialQp; | ||
| 469 | } | ||
| 470 | else{ | ||
| 471 | double dCmplxRatio = (double)pEncCtx->pVaa->sComplexityAnalysisParam.iFrameComplexity/pTOverRc->iFrameCmplxMean; | ||
| 472 | dCmplxRatio = WELS_CLIP3(dCmplxRatio, 1.0-FRAME_CMPLX_RATIO_RANGE, 1.0+FRAME_CMPLX_RATIO_RANGE); | ||
| 473 | |||
| 474 | pWelsSvcRc->dQStep = pTOverRc->dLinearCmplx*dCmplxRatio / pWelsSvcRc->iTargetBits; | ||
| 475 | iLumaQp = (int32_t)( RcConvertQStep2Qp( pWelsSvcRc->dQStep )+0.5 ); | ||
| 476 | |||
| 477 | //limit QP | ||
| 478 | int32_t iLastIdxCodecInVGop = pWelsSvcRc->iFrameCodedInVGop - 1; | ||
| 479 | if(iLastIdxCodecInVGop < 0) | ||
| 480 | iLastIdxCodecInVGop += VGOP_SIZE; | ||
| 481 | int32_t iTlLast = pWelsSvcRc->iTlOfFrames[iLastIdxCodecInVGop]; | ||
| 482 | int32_t iDeltaQpTemporal = iTl - iTlLast; | ||
| 483 | if(0 == iTlLast && iTl > 0) | ||
| 484 | iDeltaQpTemporal += 3; | ||
| 485 | else if(0 == iTl && iTlLast > 0) | ||
| 486 | iDeltaQpTemporal -= 3; | ||
| 487 | |||
| 488 | iLumaQp = WELS_CLIP3(iLumaQp, | ||
| 489 | pWelsSvcRc->iLastCalculatedQScale - pWelsSvcRc->iFrameDeltaQpLower +iDeltaQpTemporal, pWelsSvcRc->iLastCalculatedQScale + pWelsSvcRc->iFrameDeltaQpUpper + iDeltaQpTemporal); | ||
| 490 | } | ||
| 491 | |||
| 492 | iLumaQp = WELS_CLIP3(iLumaQp, GOM_MIN_QP_MODE, GOM_MAX_QP_MODE); | ||
| 493 | |||
| 494 | pWelsSvcRc->dQStep = RcConvertQp2QStep(iLumaQp); | ||
| 495 | pWelsSvcRc->iLastCalculatedQScale = iLumaQp; | ||
| 496 | #ifndef _NOT_USE_AQ_FOR_TEST_ | ||
| 497 | if(pEncCtx->pSvcParam->bEnableAdaptiveQuant) | ||
| 498 | { | ||
| 499 | |||
| 500 | iLumaQp = (int32_t)WELS_CLIP3(iLumaQp - pEncCtx->pVaa->sAdaptiveQuantParam.dAverMotionTextureIndexToDeltaQp, pWelsSvcRc->iMinQp, pWelsSvcRc->iMaxQp); | ||
| 501 | } | ||
| 502 | #endif | ||
| 503 | pEncCtx->iGlobalQp = iLumaQp; | ||
| 504 | } | ||
| 505 | |||
| 506 | void RcInitSliceInformation(sWelsEncCtx *pEncCtx) | ||
| 507 | { | ||
| 508 | SSliceCtx *pCurSliceCtx = pEncCtx->pCurDqLayer->pSliceEncCtx; | ||
| 509 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 510 | SRCSlicing *pSOverRc = &pWelsSvcRc->pSlicingOverRc[0]; | ||
| 511 | const int32_t kiSliceNum = pCurSliceCtx->iSliceNumInFrame; | ||
| 512 | const double kdBitsPerMb = (double)pWelsSvcRc->iTargetBits / pWelsSvcRc->iNumberMbFrame; | ||
| 513 | |||
| 514 | for(int32_t i=0; i<kiSliceNum; i++ ) | ||
| 515 | { | ||
| 516 | pSOverRc->iStartMbSlice = | ||
| 517 | pSOverRc->iEndMbSlice = pCurSliceCtx->pFirstMbInSlice[i]; | ||
| 518 | pSOverRc->iEndMbSlice += (pCurSliceCtx->pCountMbNumInSlice[i]-1); | ||
| 519 | pSOverRc->iTotalQpSlice = 0; | ||
| 520 | pSOverRc->iTotalMbSlice = 0; | ||
| 521 | pSOverRc->iTargetBitsSlice = (int32_t)(kdBitsPerMb * pCurSliceCtx->pCountMbNumInSlice[i]); | ||
| 522 | pSOverRc->iFrameBitsSlice = 0; | ||
| 523 | pSOverRc->iGomBitsSlice = 0; | ||
| 524 | ++ pSOverRc; | ||
| 525 | } | ||
| 526 | } | ||
| 527 | |||
| 528 | void RcDecideTargetBits(sWelsEncCtx *pEncCtx) | ||
| 529 | { | ||
| 530 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 531 | SRCTemporal *pTOverRc = &pWelsSvcRc->pTemporalOverRc[pEncCtx->uiTemporalId]; | ||
| 532 | //allocate bits | ||
| 533 | if(pEncCtx->eSliceType == I_SLICE) | ||
| 534 | { | ||
| 535 | pWelsSvcRc->iTargetBits = (int32_t)( pWelsSvcRc->dBitsPerFrame * IDR_BITRATE_RATIO ); | ||
| 536 | } | ||
| 537 | else | ||
| 538 | { | ||
| 539 | pWelsSvcRc->iTargetBits = (int32_t)( pWelsSvcRc->iRemainingBits*pTOverRc->dTlayerWeight/pWelsSvcRc->dRemainingWeights ); | ||
| 540 | pWelsSvcRc->iTargetBits = WELS_CLIP3( pWelsSvcRc->iTargetBits, pTOverRc->iMinBitsTl, pTOverRc->iMaxBitsTl); | ||
| 541 | } | ||
| 542 | pWelsSvcRc->dRemainingWeights -= pTOverRc->dTlayerWeight; | ||
| 543 | } | ||
| 544 | |||
| 545 | |||
| 546 | void RcInitGoomParameters(sWelsEncCtx *pEncCtx) | ||
| 547 | { | ||
| 548 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 549 | SRCSlicing *pSOverRc = &pWelsSvcRc->pSlicingOverRc[0]; | ||
| 550 | const int32_t kiSliceNum = pWelsSvcRc->iSliceNum; | ||
| 551 | const int32_t kiGlobalQp = pEncCtx->iGlobalQp; | ||
| 552 | |||
| 553 | pWelsSvcRc->iAverageFrameQp = 0; | ||
| 554 | for(int32_t i=0; i<kiSliceNum; ++i ) | ||
| 555 | { | ||
| 556 | pSOverRc->iComplexityIndexSlice = 0; | ||
| 557 | pSOverRc->iCalculatedQpSlice = kiGlobalQp; | ||
| 558 | ++ pSOverRc; | ||
| 559 | } | ||
| 560 | memset( pWelsSvcRc->pGomComplexity, 0, pWelsSvcRc->iGomSize*sizeof(double) ); | ||
| 561 | memset( pWelsSvcRc->pGomCost, 0, pWelsSvcRc->iGomSize*sizeof(int32_t) ); | ||
| 562 | } | ||
| 563 | |||
| 564 | void RcCalculateMbQp(sWelsEncCtx *pEncCtx,SMB* pCurMb, const int32_t kiSliceId) | ||
| 565 | { | ||
| 566 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 567 | SRCSlicing *pSOverRc = &pWelsSvcRc->pSlicingOverRc[kiSliceId]; | ||
| 568 | int32_t iLumaQp = pSOverRc->iCalculatedQpSlice; | ||
| 569 | |||
| 570 | #ifndef _NOT_USE_AQ_FOR_TEST_ | ||
| 571 | if ( pEncCtx->pSvcParam->bEnableAdaptiveQuant ) | ||
| 572 | { | ||
| 573 | iLumaQp = (int8_t)WELS_CLIP3(iLumaQp + | ||
| 574 | pEncCtx->pVaa->sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp[pCurMb->iMbXY], pWelsSvcRc->iMinQp, 51); | ||
| 575 | } | ||
| 576 | #endif | ||
| 577 | pCurMb->uiChromaQp = g_kuiChromaQpTable[iLumaQp]; | ||
| 578 | pCurMb->uiLumaQp = iLumaQp; | ||
| 579 | } | ||
| 580 | |||
| 581 | SWelsSvcRc* RcJudgeBaseUsability(sWelsEncCtx *pEncCtx) | ||
| 582 | { | ||
| 583 | SWelsSvcRc *pWelsSvcRc = NULL, *pWelsSvcRc_Base = NULL; | ||
| 584 | SDLayerParam *pDlpBase = NULL, *pDLayerParam = NULL; | ||
| 585 | |||
| 586 | if( pEncCtx->uiDependencyId<=0 ) | ||
| 587 | return NULL; | ||
| 588 | |||
| 589 | pDlpBase = &pEncCtx->pSvcParam->sDependencyLayers[pEncCtx->uiDependencyId-1]; | ||
| 590 | pWelsSvcRc_Base = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId-1]; | ||
| 591 | if( pEncCtx->uiTemporalId<=pDlpBase->iDecompositionStages ) | ||
| 592 | { | ||
| 593 | pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 594 | pWelsSvcRc_Base = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId-1]; | ||
| 595 | pDLayerParam = &pEncCtx->pSvcParam->sDependencyLayers[pEncCtx->uiDependencyId]; | ||
| 596 | pDlpBase = &pEncCtx->pSvcParam->sDependencyLayers[pEncCtx->uiDependencyId-1]; | ||
| 597 | if( (pDLayerParam->iFrameWidth*pDLayerParam->iFrameHeight/pWelsSvcRc->iNumberMbGom) == | ||
| 598 | (pDlpBase->iFrameWidth*pDlpBase->iFrameHeight/pWelsSvcRc_Base->iNumberMbGom) ) | ||
| 599 | return pWelsSvcRc_Base; | ||
| 600 | else | ||
| 601 | return NULL; | ||
| 602 | } | ||
| 603 | else | ||
| 604 | return NULL; | ||
| 605 | } | ||
| 606 | |||
| 607 | void RcGomTargetBits(sWelsEncCtx *pEncCtx, const int32_t kiSliceId) | ||
| 608 | { | ||
| 609 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 610 | SWelsSvcRc *pWelsSvcRc_Base = NULL; | ||
| 611 | SRCSlicing *pSOverRc = &pWelsSvcRc->pSlicingOverRc[kiSliceId]; | ||
| 612 | |||
| 613 | double dAllocateBits = 0; | ||
| 614 | int32_t iSumSad = 0; | ||
| 615 | int32_t iLastGomIndex = 0; | ||
| 616 | int32_t iLeftBits = 0; | ||
| 617 | const int32_t kiComplexityIndex = pSOverRc->iComplexityIndexSlice; | ||
| 618 | int32_t i; | ||
| 619 | |||
| 620 | iLastGomIndex = pSOverRc->iEndMbSlice/pWelsSvcRc->iNumberMbGom; | ||
| 621 | iLeftBits = pSOverRc->iTargetBitsSlice-pSOverRc->iFrameBitsSlice; | ||
| 622 | |||
| 623 | if(iLeftBits <= 0) | ||
| 624 | { | ||
| 625 | pSOverRc->iGomTargetBits = 0; | ||
| 626 | return; | ||
| 627 | } | ||
| 628 | else if( kiComplexityIndex >= iLastGomIndex) | ||
| 629 | { | ||
| 630 | dAllocateBits = iLeftBits; | ||
| 631 | } | ||
| 632 | else | ||
| 633 | { | ||
| 634 | pWelsSvcRc_Base = RcJudgeBaseUsability(pEncCtx); | ||
| 635 | pWelsSvcRc_Base = (pWelsSvcRc_Base) ? pWelsSvcRc_Base : pWelsSvcRc; | ||
| 636 | for( i=kiComplexityIndex; i<=iLastGomIndex; i++ ) | ||
| 637 | { | ||
| 638 | iSumSad += pWelsSvcRc_Base->pCurrentFrameGomSad[i]; | ||
| 639 | } | ||
| 640 | if(0 == iSumSad) | ||
| 641 | dAllocateBits = (double)iLeftBits/(iLastGomIndex-kiComplexityIndex); | ||
| 642 | else | ||
| 643 | dAllocateBits = (double)iLeftBits*pWelsSvcRc_Base->pCurrentFrameGomSad[kiComplexityIndex+1]/iSumSad; | ||
| 644 | |||
| 645 | } | ||
| 646 | pSOverRc->iGomTargetBits = int32_t(dAllocateBits + 0.5); | ||
| 647 | } | ||
| 648 | |||
| 649 | |||
| 650 | |||
| 651 | void RcCalculateGomQp(sWelsEncCtx *pEncCtx, SMB* pCurMb, int32_t iSliceId) | ||
| 652 | { | ||
| 653 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 654 | SRCSlicing *pSOverRc = &pWelsSvcRc->pSlicingOverRc[iSliceId]; | ||
| 655 | double dBitsRatio = 1.0; | ||
| 656 | |||
| 657 | int32_t iLeftBits = pSOverRc->iTargetBitsSlice - pSOverRc->iFrameBitsSlice; | ||
| 658 | int32_t iTargetLeftBits = iLeftBits + pSOverRc->iGomBitsSlice - pSOverRc->iGomTargetBits; | ||
| 659 | |||
| 660 | if(iLeftBits <= 0) | ||
| 661 | { | ||
| 662 | pSOverRc->iCalculatedQpSlice += 2; | ||
| 663 | } | ||
| 664 | else | ||
| 665 | { | ||
| 666 | //globe decision | ||
| 667 | dBitsRatio = iLeftBits / (iTargetLeftBits + 0.1); | ||
| 668 | if(dBitsRatio < 0.8409) //2^(-1.5/6) | ||
| 669 | pSOverRc->iCalculatedQpSlice += 2; | ||
| 670 | else if(dBitsRatio < 0.9439) //2^(-0.5/6) | ||
| 671 | pSOverRc->iCalculatedQpSlice += 1; | ||
| 672 | else if(dBitsRatio > 1.06) //2^(0.5/6) | ||
| 673 | pSOverRc->iCalculatedQpSlice -= 1; | ||
| 674 | else if(dBitsRatio > 1.19) //2^(1.5/6) | ||
| 675 | pSOverRc->iCalculatedQpSlice -= 2; | ||
| 676 | } | ||
| 677 | |||
| 678 | pSOverRc->iCalculatedQpSlice = WELS_CLIP3( pSOverRc->iCalculatedQpSlice, | ||
| 679 | pEncCtx->iGlobalQp-pWelsSvcRc->iQpRangeLowerInFrame, pEncCtx->iGlobalQp+pWelsSvcRc->iQpRangeUpperInFrame ); | ||
| 680 | pSOverRc->iCalculatedQpSlice = WELS_CLIP3(pSOverRc->iCalculatedQpSlice, pWelsSvcRc->iMinQp, pWelsSvcRc->iMaxQp); | ||
| 681 | |||
| 682 | pSOverRc->iGomBitsSlice = 0; | ||
| 683 | |||
| 684 | } | ||
| 685 | |||
| 686 | void RcVBufferCalculationSkip(sWelsEncCtx *pEncCtx) | ||
| 687 | { | ||
| 688 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 689 | SRCTemporal *pTOverRc = pWelsSvcRc->pTemporalOverRc; | ||
| 690 | const int32_t kiOutputBits = (int32_t)(pWelsSvcRc->dBitsPerFrame + 0.5); | ||
| 691 | //condition 1: whole pBuffer fullness | ||
| 692 | pWelsSvcRc->iBufferFullnessSkip += (pWelsSvcRc->iFrameDqBits - kiOutputBits); | ||
| 693 | //condition 2: VGOP bits constraint | ||
| 694 | const int32_t kiVGopBits = (int32_t)(pWelsSvcRc->dBitsPerFrame * VGOP_SIZE); | ||
| 695 | int32_t iVGopBitsPred = 0; | ||
| 696 | for(int32_t i = pWelsSvcRc->iFrameCodedInVGop+1; i<VGOP_SIZE; i++ ) | ||
| 697 | iVGopBitsPred += pTOverRc[pWelsSvcRc->iTlOfFrames[i]].iMinBitsTl; | ||
| 698 | iVGopBitsPred -= pWelsSvcRc->iRemainingBits; | ||
| 699 | double dIncPercent = iVGopBitsPred*100.0/kiVGopBits - (double)VGOP_BITS_PERCENTAGE_DIFF; | ||
| 700 | |||
| 701 | if( (pWelsSvcRc->iBufferFullnessSkip > pWelsSvcRc->iBufferSizeSkip && pWelsSvcRc->iAverageFrameQp > pWelsSvcRc->iSkipQpValue) | ||
| 702 | || (dIncPercent > pWelsSvcRc->iRcVaryPercentage)) | ||
| 703 | { | ||
| 704 | pEncCtx->iSkipFrameFlag=1; | ||
| 705 | pWelsSvcRc->iBufferFullnessSkip = pWelsSvcRc->iBufferFullnessSkip-kiOutputBits; | ||
| 706 | #ifdef FRAME_INFO_OUTPUT | ||
| 707 | fprintf(stderr, "skip one frame\n"); | ||
| 708 | #endif | ||
| 709 | } | ||
| 710 | |||
| 711 | if( pWelsSvcRc->iBufferFullnessSkip<0 ) | ||
| 712 | pWelsSvcRc->iBufferFullnessSkip = 0; | ||
| 713 | |||
| 714 | if( pEncCtx->iSkipFrameFlag==1 ) | ||
| 715 | { | ||
| 716 | pWelsSvcRc->iRemainingBits += (int32_t)(pWelsSvcRc->dBitsPerFrame + 0.5); | ||
| 717 | pWelsSvcRc->iSkipFrameNum++; | ||
| 718 | pWelsSvcRc->iSkipFrameInVGop++; | ||
| 719 | } | ||
| 720 | } | ||
| 721 | |||
| 722 | void RcVBufferCalculationPadding(sWelsEncCtx *pEncCtx) | ||
| 723 | { | ||
| 724 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 725 | const int32_t kiOutputBits = (int32_t)(pWelsSvcRc->dBitsPerFrame + 0.5); | ||
| 726 | const int32_t kiBufferThreshold = (int32_t)(PADDING_THRESHOLD*(-pWelsSvcRc->iBufferSizePadding)); | ||
| 727 | |||
| 728 | pWelsSvcRc->iBufferFullnessPadding += (pWelsSvcRc->iFrameDqBits - kiOutputBits); | ||
| 729 | |||
| 730 | if( pWelsSvcRc->iBufferFullnessPadding < kiBufferThreshold ) | ||
| 731 | { | ||
| 732 | pWelsSvcRc->iPaddingSize = -pWelsSvcRc->iBufferFullnessPadding; | ||
| 733 | pWelsSvcRc->iPaddingSize >>= 3; // /8 | ||
| 734 | pWelsSvcRc->iBufferFullnessPadding = 0; | ||
| 735 | } | ||
| 736 | else | ||
| 737 | pWelsSvcRc->iPaddingSize=0; | ||
| 738 | } | ||
| 739 | |||
| 740 | |||
| 741 | void RcTraceFrameBits(sWelsEncCtx *pEncCtx) | ||
| 742 | { | ||
| 743 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 744 | |||
| 745 | WelsLog( pEncCtx, WELS_LOG_INFO,"[Rc] encoding_qp%d, qp = %3d, index = %8d, iTid = %1d, used = %8d, target = %8d, remaingbits = %8d\n", | ||
| 746 | pEncCtx->uiDependencyId, pWelsSvcRc->iAverageFrameQp, pEncCtx->uiFrameIdxRc, pEncCtx->uiTemporalId, pWelsSvcRc->iFrameDqBits, | ||
| 747 | pWelsSvcRc->iTargetBits,pWelsSvcRc->iRemainingBits); | ||
| 748 | } | ||
| 749 | |||
| 750 | void RcUpdatePictureQpBits(sWelsEncCtx *pEncCtx, int32_t iCodedBits) | ||
| 751 | { | ||
| 752 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 753 | SRCSlicing *pSOverRc = &pWelsSvcRc->pSlicingOverRc[0]; | ||
| 754 | SSliceCtx *pCurSliceCtx = pEncCtx->pCurDqLayer->pSliceEncCtx; | ||
| 755 | int32_t iTotalQp = 0, iTotalMb = 0; | ||
| 756 | int32_t i; | ||
| 757 | |||
| 758 | if(pEncCtx->eSliceType == P_SLICE) | ||
| 759 | { | ||
| 760 | for( i=0; i<pCurSliceCtx->iSliceNumInFrame; i++ ) | ||
| 761 | { | ||
| 762 | iTotalQp += pSOverRc->iTotalQpSlice; | ||
| 763 | iTotalMb += pSOverRc->iTotalMbSlice; | ||
| 764 | ++ pSOverRc; | ||
| 765 | } | ||
| 766 | if(iTotalMb > 0) | ||
| 767 | pWelsSvcRc->iAverageFrameQp = (int32_t)(1.0*iTotalQp/iTotalMb+0.5); | ||
| 768 | else | ||
| 769 | pWelsSvcRc->iAverageFrameQp = pEncCtx->iGlobalQp; | ||
| 770 | } | ||
| 771 | else | ||
| 772 | { | ||
| 773 | pWelsSvcRc->iAverageFrameQp = pEncCtx->iGlobalQp; | ||
| 774 | } | ||
| 775 | pWelsSvcRc->iFrameDqBits = iCodedBits; | ||
| 776 | pWelsSvcRc->pTemporalOverRc[pEncCtx->uiTemporalId].iGopBitsDq += pWelsSvcRc->iFrameDqBits; | ||
| 777 | } | ||
| 778 | |||
| 779 | void RcUpdateIntraComplexity(sWelsEncCtx *pEncCtx) | ||
| 780 | { | ||
| 781 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 782 | double iAlpha = 1.0/(1+pWelsSvcRc->iIdrNum); | ||
| 783 | if(iAlpha < 0.25) iAlpha = 0.25; | ||
| 784 | |||
| 785 | double dIntraCmplx = pWelsSvcRc->dQStep*pWelsSvcRc->iFrameDqBits; | ||
| 786 | dIntraCmplx = (1.0-iAlpha)*pWelsSvcRc->iIntraComplexity + iAlpha*dIntraCmplx; | ||
| 787 | pWelsSvcRc->iIntraComplexity = (int32_t)(dIntraCmplx + 0.5); | ||
| 788 | pWelsSvcRc->iIntraMbCount = pWelsSvcRc->iNumberMbFrame; | ||
| 789 | |||
| 790 | pWelsSvcRc->iIdrNum++; | ||
| 791 | if(pWelsSvcRc->iIdrNum > 255) | ||
| 792 | pWelsSvcRc->iIdrNum = 255; | ||
| 793 | } | ||
| 794 | |||
| 795 | void RcUpdateFrameComplexity(sWelsEncCtx *pEncCtx) | ||
| 796 | { | ||
| 797 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 798 | const int32_t kiTl = pEncCtx->uiTemporalId; | ||
| 799 | SRCTemporal *pTOverRc = &pWelsSvcRc->pTemporalOverRc[kiTl]; | ||
| 800 | |||
| 801 | if(0 == pTOverRc->iPFrameNum){ | ||
| 802 | pTOverRc->dLinearCmplx = pWelsSvcRc->iFrameDqBits * pWelsSvcRc->dQStep; | ||
| 803 | } | ||
| 804 | else{ | ||
| 805 | pTOverRc->dLinearCmplx = LINEAR_MODEL_DECAY_FACTOR*pTOverRc->dLinearCmplx | ||
| 806 | + (1.0-LINEAR_MODEL_DECAY_FACTOR)*(pWelsSvcRc->iFrameDqBits * pWelsSvcRc->dQStep); | ||
| 807 | } | ||
| 808 | double iAlpha = 1.0/(1+pTOverRc->iPFrameNum); | ||
| 809 | if(iAlpha < SMOOTH_FACTOR_MIN_VALUE) | ||
| 810 | iAlpha = SMOOTH_FACTOR_MIN_VALUE; | ||
| 811 | pTOverRc->iFrameCmplxMean = (int32_t)((1.0-iAlpha)*pTOverRc->iFrameCmplxMean + iAlpha*pEncCtx->pVaa->sComplexityAnalysisParam.iFrameComplexity + 0.5); | ||
| 812 | |||
| 813 | pTOverRc->iPFrameNum++; | ||
| 814 | if(pTOverRc->iPFrameNum > 255) | ||
| 815 | pTOverRc->iPFrameNum = 255; | ||
| 816 | } | ||
| 817 | |||
| 818 | int32_t RcCalculateCascadingQp(struct TagWelsEncCtx *pEncCtx, int32_t iQp) | ||
| 819 | { | ||
| 820 | int32_t iTemporalQp = 0; | ||
| 821 | if( pEncCtx->pSvcParam->iDecompStages ) | ||
| 822 | { | ||
| 823 | if( pEncCtx->uiTemporalId==0 ) | ||
| 824 | iTemporalQp = iQp - 3 - (pEncCtx->pSvcParam->iDecompStages-1); | ||
| 825 | else | ||
| 826 | iTemporalQp = iQp - (pEncCtx->pSvcParam->iDecompStages - pEncCtx->uiTemporalId); | ||
| 827 | iTemporalQp = WELS_CLIP3( iTemporalQp, 1, 51 ); | ||
| 828 | } | ||
| 829 | else | ||
| 830 | iTemporalQp = iQp; | ||
| 831 | return iTemporalQp; | ||
| 832 | } | ||
| 833 | |||
| 834 | void WelsRcPictureInitGom(void *pCtx) | ||
| 835 | { | ||
| 836 | sWelsEncCtx *pEncCtx = (sWelsEncCtx*)pCtx; | ||
| 837 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 838 | |||
| 839 | if ( pEncCtx->eSliceType == I_SLICE ) | ||
| 840 | { | ||
| 841 | if(0 == pWelsSvcRc->iIdrNum) //iIdrNum == 0 means encoder has been initialed | ||
| 842 | { | ||
| 843 | RcInitRefreshParameter(pEncCtx); | ||
| 844 | } | ||
| 845 | } | ||
| 846 | if( RcJudgeBitrateFpsUpdate(pEncCtx)) | ||
| 847 | { | ||
| 848 | RcUpdateBitrateFps(pEncCtx); | ||
| 849 | } | ||
| 850 | if( pEncCtx->uiTemporalId == 0 ) | ||
| 851 | { | ||
| 852 | RcUpdateTemporalZero(pEncCtx); | ||
| 853 | } | ||
| 854 | RcDecideTargetBits(pEncCtx); | ||
| 855 | //decide globe_qp | ||
| 856 | if(pEncCtx->eSliceType == I_SLICE) | ||
| 857 | { | ||
| 858 | if(0 == pWelsSvcRc->iIdrNum) | ||
| 859 | RcInitIdrQp(pEncCtx); | ||
| 860 | else | ||
| 861 | { | ||
| 862 | RcCalculateIdrQp(pEncCtx); | ||
| 863 | } | ||
| 864 | } | ||
| 865 | else | ||
| 866 | { | ||
| 867 | RcCalculatePictureQp(pEncCtx); | ||
| 868 | } | ||
| 869 | RcInitSliceInformation(pEncCtx); | ||
| 870 | RcInitGoomParameters(pEncCtx); | ||
| 871 | |||
| 872 | } | ||
| 873 | |||
| 874 | |||
| 875 | |||
| 876 | void WelsRcPictureInfoUpdateGom(void *pCtx, int32_t layer_size) | ||
| 877 | { | ||
| 878 | sWelsEncCtx *pEncCtx = (sWelsEncCtx*)pCtx; | ||
| 879 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 880 | int32_t iCodedBits = (layer_size<<3); | ||
| 881 | |||
| 882 | RcUpdatePictureQpBits(pEncCtx, iCodedBits); | ||
| 883 | |||
| 884 | if ( pEncCtx->eSliceType == P_SLICE ) | ||
| 885 | { | ||
| 886 | RcUpdateFrameComplexity(pEncCtx); | ||
| 887 | } | ||
| 888 | else | ||
| 889 | { | ||
| 890 | RcUpdateIntraComplexity(pEncCtx); | ||
| 891 | } | ||
| 892 | pWelsSvcRc->iRemainingBits -= pWelsSvcRc->iFrameDqBits; | ||
| 893 | |||
| 894 | #if GOM_TRACE_FLAG | ||
| 895 | RcTraceFrameBits(pEncCtx); | ||
| 896 | #endif | ||
| 897 | |||
| 898 | |||
| 899 | #if SKIP_FRAME_FLAG | ||
| 900 | if ( pEncCtx->uiDependencyId == pEncCtx->pSvcParam->iNumDependencyLayer - 1 ) | ||
| 901 | { | ||
| 902 | RcVBufferCalculationSkip(pEncCtx); | ||
| 903 | } | ||
| 904 | #endif | ||
| 905 | |||
| 906 | if ( pEncCtx->pSvcParam->iPaddingFlag ) | ||
| 907 | RcVBufferCalculationPadding(pEncCtx); | ||
| 908 | pWelsSvcRc->iFrameCodedInVGop++; | ||
| 909 | #ifdef _TEST_TEMP_Rc_ | ||
| 910 | fprintf(fp_test_rc, "%d\n", pWelsSvcRc->iFrameDqBits); | ||
| 911 | if(pEncCtx->iSkipFrameFlag) | ||
| 912 | fprintf(fp_test_rc, "0\n"); | ||
| 913 | fflush(fp_test_rc); | ||
| 914 | #endif | ||
| 915 | } | ||
| 916 | |||
| 917 | void WelsRcMbInitGom(void *pCtx, SMB* pCurMb, SSlice *pSlice) | ||
| 918 | { | ||
| 919 | sWelsEncCtx *pEncCtx = (sWelsEncCtx*)pCtx; | ||
| 920 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 921 | const int32_t kiSliceId = pSlice->uiSliceIdx; | ||
| 922 | SRCSlicing *pSOverRc = &pWelsSvcRc->pSlicingOverRc[kiSliceId]; | ||
| 923 | SBitStringAux * bs = pSlice->pSliceBsa; | ||
| 924 | |||
| 925 | |||
| 926 | pSOverRc->iBsPosSlice = BsGetBitsPos(bs); | ||
| 927 | |||
| 928 | if(pEncCtx->eSliceType==I_SLICE) | ||
| 929 | return; | ||
| 930 | //calculate gom qp and target bits at the beginning of gom | ||
| 931 | if(0 == (pCurMb->iMbXY%pWelsSvcRc->iNumberMbGom)){ | ||
| 932 | if(pCurMb->iMbXY != pSOverRc->iStartMbSlice){ | ||
| 933 | pSOverRc->iComplexityIndexSlice++; | ||
| 934 | RcCalculateGomQp(pEncCtx, pCurMb, kiSliceId); | ||
| 935 | } | ||
| 936 | RcGomTargetBits(pEncCtx, kiSliceId); | ||
| 937 | } | ||
| 938 | |||
| 939 | RcCalculateMbQp(pEncCtx,pCurMb,kiSliceId); | ||
| 940 | } | ||
| 941 | |||
| 942 | void WelsRcMbInfoUpdateGom(void *pCtx, SMB* pCurMb, int32_t iCostLuma, SSlice *pSlice) | ||
| 943 | { | ||
| 944 | sWelsEncCtx *pEncCtx = (sWelsEncCtx*)pCtx; | ||
| 945 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 946 | SBitStringAux * bs = pSlice->pSliceBsa; | ||
| 947 | int32_t iSliceId = pSlice->uiSliceIdx; | ||
| 948 | SRCSlicing *pSOverRc = &pWelsSvcRc->pSlicingOverRc[iSliceId]; | ||
| 949 | const int32_t kiComplexityIndex = pSOverRc->iComplexityIndexSlice; | ||
| 950 | |||
| 951 | int32_t cur_mb_bits = BsGetBitsPos(bs) - pSOverRc->iBsPosSlice; | ||
| 952 | pSOverRc->iFrameBitsSlice += cur_mb_bits; | ||
| 953 | pSOverRc->iGomBitsSlice += cur_mb_bits; | ||
| 954 | |||
| 955 | pWelsSvcRc->pGomCost[kiComplexityIndex] += iCostLuma; | ||
| 956 | |||
| 957 | if(cur_mb_bits > 0){ | ||
| 958 | pSOverRc->iTotalQpSlice += pCurMb->uiLumaQp; | ||
| 959 | pSOverRc->iTotalMbSlice++; | ||
| 960 | } | ||
| 961 | } | ||
| 962 | |||
| 963 | void WelsRcPictureInitDisable(void *pCtx) | ||
| 964 | { | ||
| 965 | sWelsEncCtx *pEncCtx = (sWelsEncCtx*)pCtx; | ||
| 966 | SWelsSvcRc *pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId]; | ||
| 967 | SDLayerParam *pDLayerParam = &pEncCtx->pSvcParam->sDependencyLayers[pEncCtx->uiDependencyId]; | ||
| 968 | |||
| 969 | const int32_t kiQp = pDLayerParam->iDLayerQp; | ||
| 970 | |||
| 971 | pEncCtx->iGlobalQp = RcCalculateCascadingQp( pEncCtx, kiQp ); | ||
| 972 | |||
| 973 | if ( pEncCtx->pSvcParam->bEnableAdaptiveQuant && (pEncCtx->eSliceType == P_SLICE) ) | ||
| 974 | { | ||
| 975 | pEncCtx->iGlobalQp = (int32_t)WELS_CLIP3(pEncCtx->iGlobalQp - | ||
| 976 | pEncCtx->pVaa->sAdaptiveQuantParam.dAverMotionTextureIndexToDeltaQp, GOM_MIN_QP_MODE, GOM_MAX_QP_MODE); | ||
| 977 | } | ||
| 978 | pWelsSvcRc->iAverageFrameQp = pEncCtx->iGlobalQp; | ||
| 979 | } | ||
| 980 | |||
| 981 | void WelsRcPictureInfoUpdateDisable(void *pCtx, int32_t layer_size) | ||
| 982 | { | ||
| 983 | } | ||
| 984 | |||
| 985 | void WelsRcMbInitDisable(void *pCtx, SMB* pCurMb, SSlice *pSlice) | ||
| 986 | { | ||
| 987 | sWelsEncCtx *pEncCtx = (sWelsEncCtx*)pCtx; | ||
| 988 | int32_t iLumaQp = pEncCtx->iGlobalQp; | ||
| 989 | |||
| 990 | if ( pEncCtx->pSvcParam->bEnableAdaptiveQuant && (pEncCtx->eSliceType == P_SLICE) ) | ||
| 991 | { | ||
| 992 | iLumaQp = (int8_t)WELS_CLIP3(iLumaQp + | ||
| 993 | pEncCtx->pVaa->sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp[pCurMb->iMbXY], GOM_MIN_QP_MODE, 51); | ||
| 994 | } | ||
| 995 | pCurMb->uiChromaQp = g_kuiChromaQpTable[iLumaQp]; | ||
| 996 | pCurMb->uiLumaQp = iLumaQp; | ||
| 997 | } | ||
| 998 | |||
| 999 | void WelsRcMbInfoUpdateDisable(void *pCtx, SMB* pCurMb, int32_t iCostLuma, SSlice *pSlice) | ||
| 1000 | { | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | |||
| 1004 | void WelsRcInitModule(void *pCtx, int32_t iModule) | ||
| 1005 | { | ||
| 1006 | sWelsEncCtx *pEncCtx = (sWelsEncCtx*)pCtx; | ||
| 1007 | SWelsRcFunc * pRcf = &pEncCtx->pFuncList->pfRc; | ||
| 1008 | |||
| 1009 | switch(iModule) | ||
| 1010 | { | ||
| 1011 | case WELS_RC_DISABLE: | ||
| 1012 | pRcf->pfWelsRcPictureInit = WelsRcPictureInitDisable; | ||
| 1013 | pRcf->pfWelsRcPictureInfoUpdate = WelsRcPictureInfoUpdateDisable; | ||
| 1014 | pRcf->pfWelsRcMbInit = WelsRcMbInitDisable; | ||
| 1015 | pRcf->pfWelsRcMbInfoUpdate = WelsRcMbInfoUpdateDisable; | ||
| 1016 | break; | ||
| 1017 | case WELS_RC_GOM: | ||
| 1018 | default: | ||
| 1019 | pRcf->pfWelsRcPictureInit = WelsRcPictureInitGom; | ||
| 1020 | pRcf->pfWelsRcPictureInfoUpdate = WelsRcPictureInfoUpdateGom; | ||
| 1021 | pRcf->pfWelsRcMbInit = WelsRcMbInitGom; | ||
| 1022 | pRcf->pfWelsRcMbInfoUpdate = WelsRcMbInfoUpdateGom; | ||
| 1023 | break; | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | RcInitSequenceParameter(pEncCtx); | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | void WelsRcFreeMemory(void *pCtx) | ||
| 1030 | { | ||
| 1031 | sWelsEncCtx *pEncCtx = (sWelsEncCtx*)pCtx; | ||
| 1032 | SWelsSvcRc *pWelsSvcRc = NULL; | ||
| 1033 | int32_t i = 0; | ||
| 1034 | #ifdef _TEST_TEMP_Rc_ | ||
| 1035 | if(fp_test_rc) | ||
| 1036 | fclose(fp_test_rc); | ||
| 1037 | fp_test_rc = NULL; | ||
| 1038 | if(fp_vgop) | ||
| 1039 | fclose(fp_vgop); | ||
| 1040 | fp_vgop = NULL; | ||
| 1041 | #endif | ||
| 1042 | for( i=0; i<pEncCtx->pSvcParam->iNumDependencyLayer; i++ ) | ||
| 1043 | { | ||
| 1044 | pWelsSvcRc = &pEncCtx->pWelsSvcRc[i]; | ||
| 1045 | RcFreeLayerMemory(pWelsSvcRc, pEncCtx->pMemAlign); | ||
| 1046 | } | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | }//end of namespace | ||