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 | |