• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * \file    encoder_ext.c
33  *
34  * \brief   core encoder for SVC
35  *
36  * \date    7/24/2009 Created
37  *
38  *************************************************************************************
39  */
40 
41 #include "encoder.h"
42 #include "cpu.h"
43 #include "utils.h"
44 #include "svc_enc_golomb.h"
45 #include "au_set.h"
46 #include "picture_handle.h"
47 #include "svc_base_layer_md.h"
48 #include "svc_encode_slice.h"
49 #include "svc_mode_decision.h"
50 #include "decode_mb_aux.h"
51 #include "deblocking.h"
52 #include "ref_list_mgr_svc.h"
53 #include "ls_defines.h"
54 #include "crt_util_safe_x.h" // Safe CRT routines like utils for cross platforms
55 #include "slice_multi_threading.h"
56 #include "measure_time.h"
57 #include "svc_set_mb_syn.h"
58 
59 namespace WelsEnc {
60 
61 
62 int32_t WelsCodeOnePicPartition (sWelsEncCtx* pCtx,
63                                  SFrameBSInfo* pFrameBsInfo,
64                                  SLayerBSInfo* pLayerBsInfo,
65                                  int32_t* pNalIdxInLayer,
66                                  int32_t* pLayerSize,
67                                  int32_t iFirstMbIdxInPartition,
68                                  int32_t iEndMbIdxInPartition,
69                                  int32_t iStartSliceIdx
70                                 );
71 
72 
WelsBitRateVerification(SLogContext * pLogCtx,SSpatialLayerConfig * pLayerParam,int32_t iLayerId)73 int32_t WelsBitRateVerification (SLogContext* pLogCtx, SSpatialLayerConfig* pLayerParam, int32_t iLayerId) {
74   if ((pLayerParam->iSpatialBitrate <= 0)
75       || (static_cast<float> (pLayerParam->iSpatialBitrate) < pLayerParam->fFrameRate)) {
76     WelsLog (pLogCtx, WELS_LOG_ERROR, "Invalid bitrate settings in layer %d, bitrate= %d at FrameRate(%f)", iLayerId,
77              pLayerParam->iSpatialBitrate, pLayerParam->fFrameRate);
78     return ENC_RETURN_UNSUPPORTED_PARA;
79   }
80 
81   // deal with LEVEL_MAX_BR and MAX_BR setting
82   const SLevelLimits* pCurLevelLimit = g_ksLevelLimits;
83   while ((pCurLevelLimit->uiLevelIdc != LEVEL_5_2) && (pCurLevelLimit->uiLevelIdc != pLayerParam->uiLevelIdc))
84     pCurLevelLimit++;
85   const int32_t iLevelMaxBitrate = pCurLevelLimit->uiMaxBR * CpbBrNalFactor;
86   const int32_t iLevel52MaxBitrate = g_ksLevelLimits[LEVEL_NUMBER - 1].uiMaxBR * CpbBrNalFactor;
87   if (UNSPECIFIED_BIT_RATE != iLevelMaxBitrate) {
88     if ((pLayerParam->iMaxSpatialBitrate == UNSPECIFIED_BIT_RATE)
89         || (pLayerParam->iMaxSpatialBitrate > iLevel52MaxBitrate)) {
90       pLayerParam->iMaxSpatialBitrate = iLevelMaxBitrate;
91       WelsLog (pLogCtx, WELS_LOG_INFO,
92                "Current MaxSpatialBitrate is invalid (UNSPECIFIED_BIT_RATE or larger than LEVEL5_2) but level setting is valid, set iMaxSpatialBitrate to %d from level (%d)",
93                pLayerParam->iMaxSpatialBitrate, pLayerParam->uiLevelIdc);
94     } else if (pLayerParam->iMaxSpatialBitrate > iLevelMaxBitrate) {
95       ELevelIdc iCurLevel = pLayerParam->uiLevelIdc;
96       WelsAdjustLevel (pLayerParam, pCurLevelLimit);
97       WelsLog (pLogCtx, WELS_LOG_INFO,
98                "LevelIdc is changed from (%d) to (%d) according to the iMaxSpatialBitrate(%d)",
99                iCurLevel, pLayerParam->uiLevelIdc, pLayerParam->iMaxSpatialBitrate);
100     }
101   } else if ((pLayerParam->iMaxSpatialBitrate != UNSPECIFIED_BIT_RATE)
102              && (pLayerParam->iMaxSpatialBitrate > iLevel52MaxBitrate)) {
103     // no level limitation, just need to check if iMaxSpatialBitrate is too big from reasonable
104     WelsLog (pLogCtx, WELS_LOG_WARNING,
105              "No LevelIdc setting and iMaxSpatialBitrate (%d) is considered too big to be valid, changed to UNSPECIFIED_BIT_RATE",
106              pLayerParam->iMaxSpatialBitrate);
107     pLayerParam->iMaxSpatialBitrate = UNSPECIFIED_BIT_RATE;
108   }
109 
110   // deal with iSpatialBitrate and iMaxSpatialBitrate setting
111   if (pLayerParam->iMaxSpatialBitrate != UNSPECIFIED_BIT_RATE) {
112     if (pLayerParam->iMaxSpatialBitrate == pLayerParam->iSpatialBitrate) {
113       WelsLog (pLogCtx, WELS_LOG_INFO,
114                "Setting MaxSpatialBitrate (%d) the same at SpatialBitrate (%d) will make the actual bit rate lower than SpatialBitrate",
115                pLayerParam->iMaxSpatialBitrate, pLayerParam->iSpatialBitrate);
116     } else if (pLayerParam->iMaxSpatialBitrate < pLayerParam->iSpatialBitrate) {
117       WelsLog (pLogCtx, WELS_LOG_ERROR,
118                "MaxSpatialBitrate (%d) should be larger than SpatialBitrate (%d), considering it as error setting",
119                pLayerParam->iMaxSpatialBitrate, pLayerParam->iSpatialBitrate);
120       return ENC_RETURN_UNSUPPORTED_PARA;
121     }
122   }
123   return ENC_RETURN_SUCCESS;
124 }
125 
CheckProfileSetting(SLogContext * pLogCtx,SWelsSvcCodingParam * pParam,int32_t iLayer,EProfileIdc uiProfileIdc)126 void CheckProfileSetting (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam, int32_t iLayer, EProfileIdc uiProfileIdc) {
127   SSpatialLayerConfig* pLayerInfo = &pParam->sSpatialLayers[iLayer];
128   pLayerInfo->uiProfileIdc = uiProfileIdc;
129   if (pParam->bSimulcastAVC) {
130     if ((uiProfileIdc != PRO_BASELINE) && (uiProfileIdc != PRO_MAIN) && (uiProfileIdc != PRO_HIGH)) {
131       WelsLog (pLogCtx, WELS_LOG_WARNING, "layerId(%d) doesn't support profile(%d), change to UNSPECIFIC profile", iLayer,
132                uiProfileIdc);
133       pLayerInfo->uiProfileIdc = PRO_UNKNOWN;
134     }
135   } else {
136     if (iLayer == SPATIAL_LAYER_0) {
137       if ((uiProfileIdc != PRO_BASELINE) && (uiProfileIdc != PRO_MAIN) && (uiProfileIdc != PRO_HIGH)) {
138         WelsLog (pLogCtx, WELS_LOG_WARNING, "layerId(%d) doesn't support profile(%d), change to UNSPECIFIC profile", iLayer,
139                  uiProfileIdc);
140         pLayerInfo->uiProfileIdc = PRO_UNKNOWN;
141       }
142     } else {
143       if ((uiProfileIdc != PRO_SCALABLE_BASELINE) && (uiProfileIdc != PRO_SCALABLE_HIGH)) {
144         pLayerInfo->uiProfileIdc = PRO_SCALABLE_BASELINE;
145         WelsLog (pLogCtx, WELS_LOG_WARNING, "layerId(%d) doesn't support profile(%d), change to scalable baseline profile",
146                  iLayer, uiProfileIdc);
147       }
148     }
149   }
150 }
CheckLevelSetting(SLogContext * pLogCtx,SWelsSvcCodingParam * pParam,int32_t iLayer,ELevelIdc uiLevelIdc)151 void CheckLevelSetting (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam, int32_t iLayer, ELevelIdc uiLevelIdc) {
152   SSpatialLayerConfig* pLayerInfo = &pParam->sSpatialLayers[iLayer];
153   pLayerInfo->uiLevelIdc = LEVEL_UNKNOWN;
154   int32_t iLevelIdx = LEVEL_NUMBER - 1;
155   do {
156     if (g_ksLevelLimits[iLevelIdx].uiLevelIdc == uiLevelIdc) {
157       pLayerInfo->uiLevelIdc = uiLevelIdc;
158       break;
159     }
160     iLevelIdx--;
161   } while (iLevelIdx >= 0);
162 }
CheckReferenceNumSetting(SLogContext * pLogCtx,SWelsSvcCodingParam * pParam,int32_t iNumRef)163 void CheckReferenceNumSetting (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam, int32_t iNumRef) {
164   int32_t iRefUpperBound = (pParam->iUsageType == CAMERA_VIDEO_REAL_TIME) ?
165                            MAX_REFERENCE_PICTURE_COUNT_NUM_CAMERA : MAX_REFERENCE_PICTURE_COUNT_NUM_SCREEN;
166   pParam->iNumRefFrame = iNumRef;
167   if ((iNumRef < MIN_REF_PIC_COUNT) || (iNumRef > iRefUpperBound)) {
168     pParam->iNumRefFrame = AUTO_REF_PIC_COUNT;
169     WelsLog (pLogCtx, WELS_LOG_WARNING,
170              "doesn't support the number of reference frame(%d) change to auto select mode", iNumRef);
171   }
172 }
173 
SliceArgumentValidationFixedSliceMode(SLogContext * pLogCtx,SSliceArgument * pSliceArgument,const RC_MODES kiRCMode,const int32_t kiPicWidth,const int32_t kiPicHeight)174 int32_t SliceArgumentValidationFixedSliceMode (SLogContext* pLogCtx,
175     SSliceArgument* pSliceArgument, const RC_MODES  kiRCMode,
176     const int32_t kiPicWidth,       const int32_t kiPicHeight) {
177   int32_t iCpuCores            = 0;
178   int32_t iIdx                 = 0;
179   const int32_t iMbWidth       = (kiPicWidth + 15) >> 4;
180   const int32_t iMbHeight      = (kiPicHeight + 15) >> 4;
181   const int32_t iMbNumInFrame  = iMbWidth * iMbHeight;
182   bool  bSingleMode            = false;
183 
184   pSliceArgument->uiSliceSizeConstraint = 0;
185 
186   if (pSliceArgument->uiSliceNum == 0) {
187     WelsCPUFeatureDetect (&iCpuCores);
188     if (0 == iCpuCores) {
189       // cpuid not supported or doesn't expose the number of cores,
190       // use high level system API as followed to detect number of pysical/logic processor
191       iCpuCores = DynamicDetectCpuCores();
192     }
193     pSliceArgument->uiSliceNum = iCpuCores;
194   }
195 
196   if (pSliceArgument->uiSliceNum <= 1) {
197     WelsLog (pLogCtx, WELS_LOG_INFO,
198              "SliceArgumentValidationFixedSliceMode(), uiSliceNum(%d) you set for SM_FIXEDSLCNUM_SLICE, now turn to SM_SINGLE_SLICE type!",
199              pSliceArgument->uiSliceNum);
200     bSingleMode = true;
201   }
202 
203   // considering the coding efficient and performance,
204   // iCountMbNum constraint by MIN_NUM_MB_PER_SLICE condition of multi-pSlice mode settting
205   if (iMbNumInFrame <= MIN_NUM_MB_PER_SLICE) {
206     WelsLog (pLogCtx, WELS_LOG_INFO,
207              "SliceArgumentValidationFixedSliceMode(), uiSliceNum(%d) you set for SM_FIXEDSLCNUM_SLICE, now turn to SM_SINGLE_SLICE type as CountMbNum less than MIN_NUM_MB_PER_SLICE!",
208              pSliceArgument->uiSliceNum);
209     bSingleMode = true;
210   }
211 
212   if (bSingleMode) {
213     pSliceArgument->uiSliceMode = SM_SINGLE_SLICE;
214     pSliceArgument->uiSliceNum = 1;
215     for (iIdx = 0; iIdx < MAX_SLICES_NUM; iIdx++) {
216       pSliceArgument->uiSliceMbNum[iIdx] = 0;
217     }
218     return ENC_RETURN_SUCCESS;
219   }
220 
221   if (pSliceArgument->uiSliceNum > MAX_SLICES_NUM) {
222     pSliceArgument->uiSliceNum = MAX_SLICES_NUM;
223     WelsLog (pLogCtx, WELS_LOG_WARNING,
224              "SliceArgumentValidationFixedSliceMode(), uiSliceNum exceed MAX_SLICES_NUM! So setting slice num eqaul to MAX_SLICES_NUM(%d)!",
225              pSliceArgument->uiSliceNum);
226   }
227 
228   if (kiRCMode != RC_OFF_MODE) { // multiple slices verify with gom
229     //check uiSliceNum and set uiSliceMbNum with current uiSliceNum
230     if (!GomValidCheckSliceNum (iMbWidth, iMbHeight, &pSliceArgument->uiSliceNum)) {
231       WelsLog (pLogCtx, WELS_LOG_WARNING,
232                "SliceArgumentValidationFixedSliceMode(), unsupported setting with Resolution and uiSliceNum combination under RC on! So uiSliceNum is changed to %d!",
233                pSliceArgument->uiSliceNum);
234     }
235 
236     if (pSliceArgument->uiSliceNum <= 1 ||
237         !GomValidCheckSliceMbNum (iMbWidth, iMbHeight, pSliceArgument)) {
238       WelsLog (pLogCtx, WELS_LOG_ERROR,
239                "SliceArgumentValidationFixedSliceMode(), unsupported setting with Resolution and uiSliceNum (%d) combination  under RC on! Consider setting single slice with this resolution!",
240                pSliceArgument->uiSliceNum);
241       return ENC_RETURN_UNSUPPORTED_PARA;
242     }
243   } else if (!CheckFixedSliceNumMultiSliceSetting (iMbNumInFrame, pSliceArgument)) {
244     //check uiSliceMbNum with current uiSliceNum
245     WelsLog (pLogCtx, WELS_LOG_ERROR,
246              "SliceArgumentValidationFixedSliceMode(), invalid uiSliceMbNum (%d) settings!,now turn to SM_SINGLE_SLICE type",
247              pSliceArgument->uiSliceMbNum[0]);
248     pSliceArgument->uiSliceMode = SM_SINGLE_SLICE;
249     pSliceArgument->uiSliceNum  = 1;
250     for (iIdx = 0; iIdx < MAX_SLICES_NUM; iIdx++) {
251       pSliceArgument->uiSliceMbNum[iIdx] = 0;
252     }
253   }
254 
255   return ENC_RETURN_SUCCESS;
256 }
257 
258 
259 /*!
260  * \brief   validate checking in parameter configuration
261  * \pParam  pParam      SWelsSvcCodingParam*
262  * \return  successful - 0; otherwise none 0 for failed
263  */
ParamValidation(SLogContext * pLogCtx,SWelsSvcCodingParam * pCfg)264 int32_t ParamValidation (SLogContext* pLogCtx, SWelsSvcCodingParam* pCfg) {
265   const float fEpsn = 0.000001f;
266   int32_t i = 0;
267 
268   assert (pCfg != NULL);
269 
270   if (! (pCfg->iUsageType < INPUT_CONTENT_TYPE_ALL)) {
271     WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidation(),Invalid usage type = %d", pCfg->iUsageType);
272     return ENC_RETURN_UNSUPPORTED_PARA;
273   }
274   if (pCfg->iUsageType == SCREEN_CONTENT_REAL_TIME) {
275     if (pCfg->iSpatialLayerNum > 1) {
276       WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidation(),Invalid the number of Spatial layer(%d)for screen content",
277                pCfg->iSpatialLayerNum);
278       return ENC_RETURN_UNSUPPORTED_PARA;
279     }
280     if (pCfg->bEnableAdaptiveQuant) {
281       WelsLog (pLogCtx, WELS_LOG_WARNING,
282                "ParamValidation(), AdaptiveQuant(%d) is not supported yet for screen content, auto turned off",
283                pCfg->bEnableAdaptiveQuant);
284       pCfg->bEnableAdaptiveQuant = false;
285     }
286     if (pCfg->bEnableBackgroundDetection) {
287       WelsLog (pLogCtx, WELS_LOG_WARNING,
288                "ParamValidation(), BackgroundDetection(%d) is not supported yet for screen content, auto turned off",
289                pCfg->bEnableBackgroundDetection);
290       pCfg->bEnableBackgroundDetection = false;
291     }
292     if (pCfg->bEnableSceneChangeDetect == false) {
293       pCfg->bEnableSceneChangeDetect = true;
294       WelsLog (pLogCtx, WELS_LOG_WARNING,
295                "ParamValidation(), screen change detection should be turned on, change bEnableSceneChangeDetect as true");
296     }
297 
298   }
299 
300   //turn off adaptive quant now, algorithms needs to be refactored
301   pCfg->bEnableAdaptiveQuant = false;
302 
303   if (pCfg->iSpatialLayerNum > 1) {
304     for (i = pCfg->iSpatialLayerNum - 1; i > 0; i--) {
305       SSpatialLayerConfig* fDlpUp = &pCfg->sSpatialLayers[i];
306       SSpatialLayerConfig* fDlp = &pCfg->sSpatialLayers[i - 1];
307       if ((fDlp->iVideoWidth > fDlpUp->iVideoWidth) || (fDlp->iVideoHeight > fDlpUp->iVideoHeight)) {
308         WelsLog (pLogCtx, WELS_LOG_ERROR,
309                  "ParamValidation,Invalid resolution layer(%d) resolution(%d x %d) should be less than the upper spatial layer resolution(%d x %d) ",
310                  i, fDlp->iVideoWidth, fDlp->iVideoHeight, fDlpUp->iVideoWidth, fDlpUp->iVideoHeight);
311         return ENC_RETURN_UNSUPPORTED_PARA;
312       }
313     }
314   }
315 
316   if (!CheckInRangeCloseOpen (pCfg->iLoopFilterDisableIdc, DEBLOCKING_IDC_0, DEBLOCKING_IDC_2 + 1) ||
317       !CheckInRangeCloseOpen (pCfg->iLoopFilterAlphaC0Offset, DEBLOCKING_OFFSET_MINUS, DEBLOCKING_OFFSET + 1) ||
318       !CheckInRangeCloseOpen (pCfg->iLoopFilterBetaOffset, DEBLOCKING_OFFSET_MINUS, DEBLOCKING_OFFSET + 1)) {
319     WelsLog (pLogCtx, WELS_LOG_ERROR,
320              "ParamValidation, Invalid iLoopFilterDisableIdc(%d) or iLoopFilterAlphaC0Offset(%d) or iLoopFilterBetaOffset(%d)!",
321              pCfg->iLoopFilterDisableIdc, pCfg->iLoopFilterAlphaC0Offset, pCfg->iLoopFilterBetaOffset);
322     return ENC_RETURN_UNSUPPORTED_PARA;
323   }
324 
325   for (i = 0; i < pCfg->iSpatialLayerNum; ++ i) {
326     SSpatialLayerInternal* fDlp = &pCfg->sDependencyLayers[i];
327     SSpatialLayerConfig* pConfig = &pCfg->sSpatialLayers[i];
328     if (fDlp->fOutputFrameRate > fDlp->fInputFrameRate || (fDlp->fInputFrameRate >= -fEpsn
329         && fDlp->fInputFrameRate <= fEpsn)
330         || (fDlp->fOutputFrameRate >= -fEpsn && fDlp->fOutputFrameRate <= fEpsn)) {
331       WelsLog (pLogCtx, WELS_LOG_ERROR,
332                "Invalid settings in input frame rate(%.6f) or output frame rate(%.6f) of layer #%d config file..",
333                fDlp->fInputFrameRate, fDlp->fOutputFrameRate, i);
334       return ENC_RETURN_INVALIDINPUT;
335     }
336     if (UINT_MAX == GetLogFactor (fDlp->fOutputFrameRate, fDlp->fInputFrameRate)) {
337       WelsLog (pLogCtx, WELS_LOG_WARNING,
338                "AUTO CORRECT: Invalid settings in input frame rate(%.6f) and output frame rate(%.6f) of layer #%d config file: iResult of output frame rate divided by input frame rate should be power of 2(i.e,in/pOut=2^n). \n Auto correcting Output Framerate to Input Framerate %f!\n",
339                fDlp->fInputFrameRate, fDlp->fOutputFrameRate, i, fDlp->fInputFrameRate);
340       fDlp->fOutputFrameRate = fDlp->fInputFrameRate;
341       pConfig->fFrameRate = fDlp->fOutputFrameRate;
342     }
343   }
344 
345   if ((pCfg->iRCMode != RC_OFF_MODE) && (pCfg->iRCMode != RC_QUALITY_MODE) && (pCfg->iRCMode != RC_BUFFERBASED_MODE)
346       && (pCfg->iRCMode != RC_BITRATE_MODE) && (pCfg->iRCMode != RC_TIMESTAMP_MODE)) {
347     WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidation(),Invalid iRCMode = %d", pCfg->iRCMode);
348     return ENC_RETURN_UNSUPPORTED_PARA;
349   }
350   //bitrate setting validation
351   if (pCfg->iRCMode != RC_OFF_MODE) {
352     int32_t  iTotalBitrate = 0;
353     if (pCfg->iTargetBitrate <= 0) {
354       WelsLog (pLogCtx, WELS_LOG_ERROR, "Invalid bitrate settings in total configure, bitrate= %d", pCfg->iTargetBitrate);
355       return ENC_RETURN_INVALIDINPUT;
356     }
357     for (i = 0; i < pCfg->iSpatialLayerNum; ++ i) {
358       SSpatialLayerConfig* pSpatialLayer = &pCfg->sSpatialLayers[i];
359       iTotalBitrate += pSpatialLayer->iSpatialBitrate;
360 
361       if (WelsBitRateVerification (pLogCtx, pSpatialLayer, i) != ENC_RETURN_SUCCESS)
362         return ENC_RETURN_INVALIDINPUT;
363     }
364     if (iTotalBitrate > pCfg->iTargetBitrate) {
365       WelsLog (pLogCtx, WELS_LOG_ERROR,
366                "Invalid settings in bitrate. the sum of each layer bitrate(%d) is larger than total bitrate setting(%d)",
367                iTotalBitrate, pCfg->iTargetBitrate);
368       return ENC_RETURN_INVALIDINPUT;
369     }
370     if ((pCfg->iRCMode == RC_QUALITY_MODE) || (pCfg->iRCMode == RC_BITRATE_MODE) || (pCfg->iRCMode == RC_TIMESTAMP_MODE))
371       if (!pCfg->bEnableFrameSkip)
372         WelsLog (pLogCtx, WELS_LOG_WARNING,
373                  "bEnableFrameSkip = %d,bitrate can't be controlled for RC_QUALITY_MODE,RC_BITRATE_MODE and RC_TIMESTAMP_MODE without enabling skip frame.",
374                  pCfg->bEnableFrameSkip);
375     if ((pCfg->iMaxQp <= 0) || (pCfg->iMinQp <= 0)) {
376       if (pCfg->iUsageType == SCREEN_CONTENT_REAL_TIME) {
377         WelsLog (pLogCtx, WELS_LOG_INFO, "Change QP Range from(%d,%d) to (%d,%d)", pCfg->iMinQp, pCfg->iMaxQp, MIN_SCREEN_QP,
378                  MAX_SCREEN_QP);
379         pCfg->iMinQp = MIN_SCREEN_QP;
380         pCfg->iMaxQp = MAX_SCREEN_QP;
381       } else {
382         WelsLog (pLogCtx, WELS_LOG_INFO, "Change QP Range from(%d,%d) to (%d,%d)", pCfg->iMinQp, pCfg->iMaxQp,
383                  GOM_MIN_QP_MODE, MAX_LOW_BR_QP);
384         pCfg->iMinQp = GOM_MIN_QP_MODE;
385         pCfg->iMaxQp = MAX_LOW_BR_QP;
386       }
387 
388     }
389     pCfg->iMinQp = WELS_CLIP3 (pCfg->iMinQp, GOM_MIN_QP_MODE, QP_MAX_VALUE);
390     pCfg->iMaxQp = WELS_CLIP3 (pCfg->iMaxQp, pCfg->iMinQp, QP_MAX_VALUE);
391   }
392   // ref-frames validation
393   if (((pCfg->iUsageType == CAMERA_VIDEO_REAL_TIME) || (pCfg->iUsageType == SCREEN_CONTENT_REAL_TIME))
394       ? WelsCheckRefFrameLimitationNumRefFirst (pLogCtx, pCfg)
395       : WelsCheckRefFrameLimitationLevelIdcFirst (pLogCtx, pCfg)) {
396     WelsLog (pLogCtx, WELS_LOG_ERROR, "WelsCheckRefFrameLimitation failed");
397     return ENC_RETURN_INVALIDINPUT;
398   }
399   return ENC_RETURN_SUCCESS;
400 }
401 
402 
ParamValidationExt(SLogContext * pLogCtx,SWelsSvcCodingParam * pCodingParam)403 int32_t ParamValidationExt (SLogContext* pLogCtx, SWelsSvcCodingParam* pCodingParam) {
404   int8_t i = 0;
405   int32_t iIdx = 0;
406 
407   assert (pCodingParam != NULL);
408   if (NULL == pCodingParam)
409     return ENC_RETURN_INVALIDINPUT;
410 
411   if ((pCodingParam->iUsageType != CAMERA_VIDEO_REAL_TIME) && (pCodingParam->iUsageType != SCREEN_CONTENT_REAL_TIME)) {
412     WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(),Invalid usage type = %d", pCodingParam->iUsageType);
413     return ENC_RETURN_UNSUPPORTED_PARA;
414   }
415   if ((pCodingParam->iUsageType == SCREEN_CONTENT_REAL_TIME) && (!pCodingParam->bIsLosslessLink
416       && pCodingParam->bEnableLongTermReference)) {
417     WelsLog (pLogCtx, WELS_LOG_WARNING,
418              "ParamValidationExt(), setting lossy link for LTR under screen, which is not supported yet! Auto disabled LTR!");
419     pCodingParam->bEnableLongTermReference = false;
420   }
421   if (pCodingParam->iSpatialLayerNum < 1 || pCodingParam->iSpatialLayerNum > MAX_DEPENDENCY_LAYER) {
422     WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), monitor invalid pCodingParam->iSpatialLayerNum: %d!",
423              pCodingParam->iSpatialLayerNum);
424     return ENC_RETURN_UNSUPPORTED_PARA;
425   }
426 
427   if (pCodingParam->iTemporalLayerNum < 1 || pCodingParam->iTemporalLayerNum > MAX_TEMPORAL_LEVEL) {
428     WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), monitor invalid pCodingParam->iTemporalLayerNum: %d!",
429              pCodingParam->iTemporalLayerNum);
430     return ENC_RETURN_UNSUPPORTED_PARA;
431   }
432 
433   if (pCodingParam->uiGopSize < 1 || pCodingParam->uiGopSize > MAX_GOP_SIZE) {
434     WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), monitor invalid pCodingParam->uiGopSize: %d!",
435              pCodingParam->uiGopSize);
436     return ENC_RETURN_UNSUPPORTED_PARA;
437   }
438 
439 
440   if (pCodingParam->uiIntraPeriod && pCodingParam->uiIntraPeriod < pCodingParam->uiGopSize) {
441     WelsLog (pLogCtx, WELS_LOG_ERROR,
442              "ParamValidationExt(), uiIntraPeriod(%d) should be not less than that of uiGopSize(%d) or -1 specified!",
443              pCodingParam->uiIntraPeriod, pCodingParam->uiGopSize);
444     return ENC_RETURN_UNSUPPORTED_PARA;
445   }
446 
447   if (pCodingParam->uiIntraPeriod && (pCodingParam->uiIntraPeriod & (pCodingParam->uiGopSize - 1)) != 0) {
448     WelsLog (pLogCtx, WELS_LOG_ERROR,
449              "ParamValidationExt(), uiIntraPeriod(%d) should be multiple of uiGopSize(%d) or -1 specified!",
450              pCodingParam->uiIntraPeriod, pCodingParam->uiGopSize);
451     return ENC_RETURN_UNSUPPORTED_PARA;
452   }
453 
454   //about iMultipleThreadIdc, bDeblockingParallelFlag, iLoopFilterDisableIdc, & uiSliceMode
455   // (1) Single Thread
456   //    if (THREAD==1)//single thread
457   //            no parallel_deblocking: bDeblockingParallelFlag = 0;
458   // (2) Multi Thread: see uiSliceMode decision
459   if (pCodingParam->iMultipleThreadIdc == 1) {
460     //now is single thread. no parallel deblocking, set flag=0
461     pCodingParam->bDeblockingParallelFlag = false;
462   } else {
463     pCodingParam->bDeblockingParallelFlag = true;
464   }
465 
466   // eSpsPpsIdStrategy checkings
467   if (pCodingParam->iSpatialLayerNum > 1 && (!pCodingParam->bSimulcastAVC)
468       && (SPS_LISTING & pCodingParam->eSpsPpsIdStrategy)) {
469     WelsLog (pLogCtx, WELS_LOG_WARNING,
470              "ParamValidationExt(), eSpsPpsIdStrategy setting (%d) with multiple svc SpatialLayers (%d) not supported! eSpsPpsIdStrategy adjusted to CONSTANT_ID",
471              pCodingParam->eSpsPpsIdStrategy, pCodingParam->iSpatialLayerNum);
472     pCodingParam->eSpsPpsIdStrategy = CONSTANT_ID;
473   }
474   if (pCodingParam->iUsageType == SCREEN_CONTENT_REAL_TIME && (SPS_LISTING & pCodingParam->eSpsPpsIdStrategy)) {
475     WelsLog (pLogCtx, WELS_LOG_WARNING,
476              "ParamValidationExt(), eSpsPpsIdStrategy setting (%d) with iUsageType (%d) not supported! eSpsPpsIdStrategy adjusted to CONSTANT_ID",
477              pCodingParam->eSpsPpsIdStrategy, pCodingParam->iUsageType);
478     pCodingParam->eSpsPpsIdStrategy = CONSTANT_ID;
479   }
480 
481   if (pCodingParam->bSimulcastAVC && (SPS_LISTING & pCodingParam->eSpsPpsIdStrategy)) {
482     WelsLog (pLogCtx, WELS_LOG_INFO,
483              "ParamValidationExt(), eSpsPpsIdStrategy(%d) under bSimulcastAVC(%d) not supported yet, adjusted to INCREASING_ID",
484              pCodingParam->eSpsPpsIdStrategy, pCodingParam->bSimulcastAVC);
485     pCodingParam->eSpsPpsIdStrategy = INCREASING_ID;
486   }
487 
488   if (pCodingParam->bSimulcastAVC && pCodingParam->bPrefixNalAddingCtrl) {
489     WelsLog (pLogCtx, WELS_LOG_INFO,
490              "ParamValidationExt(), bSimulcastAVC(%d) is not compatible with bPrefixNalAddingCtrl(%d) true, adjusted bPrefixNalAddingCtrl to false",
491              pCodingParam->eSpsPpsIdStrategy, pCodingParam->bSimulcastAVC);
492     pCodingParam->bPrefixNalAddingCtrl = false;
493   }
494 
495   for (i = 0; i < pCodingParam->iSpatialLayerNum; ++ i) {
496     SSpatialLayerConfig* pSpatialLayer = &pCodingParam->sSpatialLayers[i];
497     int32_t kiPicWidth = pSpatialLayer->iVideoWidth;
498     int32_t kiPicHeight = pSpatialLayer->iVideoHeight;
499     uint32_t iMbWidth           = 0;
500     uint32_t iMbHeight          = 0;
501     int32_t iMbNumInFrame       = 0;
502     uint32_t iMaxSliceNum       = MAX_SLICES_NUM;
503     int32_t  iReturn            = 0;
504 
505     if ((pCodingParam->iPicWidth > 0) && (pCodingParam->iPicHeight > 0)
506         && (kiPicWidth == 0) && (kiPicHeight == 0)
507         && (pCodingParam->iSpatialLayerNum == 1)) {
508       kiPicWidth = pSpatialLayer->iVideoWidth = pCodingParam->iPicWidth;
509       kiPicHeight = pSpatialLayer->iVideoHeight = pCodingParam->iPicHeight;
510       WelsLog (pLogCtx, WELS_LOG_DEBUG,
511                "ParamValidationExt(), layer resolution is not set, set to general resolution %d x %d",
512                pSpatialLayer->iVideoWidth, pSpatialLayer->iVideoHeight);
513     }
514 
515     if ((kiPicWidth <= 0) || (kiPicHeight <= 0) || (kiPicWidth * kiPicHeight > (MAX_MBS_PER_FRAME << 8))) {
516       WelsLog (pLogCtx, WELS_LOG_ERROR,
517                "ParamValidationExt(), width > 0, height > 0, width * height <= %d, invalid %d x %d in dependency layer settings!",
518                (MAX_MBS_PER_FRAME << 8), kiPicWidth, kiPicHeight);
519       return ENC_RETURN_UNSUPPORTED_PARA;
520     }
521     if ((kiPicWidth & 0x0F) != 0 || (kiPicHeight & 0x0F) != 0) {
522       WelsLog (pLogCtx, WELS_LOG_ERROR,
523                "ParamValidationExt(), in layer #%d iWidth x iHeight(%d x %d) both should be multiple of 16, can not support with arbitrary size currently!",
524                i, kiPicWidth, kiPicHeight);
525       return ENC_RETURN_UNSUPPORTED_PARA;
526     }
527 
528     if (pSpatialLayer->sSliceArgument.uiSliceMode >= SM_RESERVED) {
529       WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceMode (%d) settings!",
530                pSpatialLayer->sSliceArgument.uiSliceMode);
531       return ENC_RETURN_UNSUPPORTED_PARA;
532     }
533     if ((pCodingParam->uiMaxNalSize != 0) && (pSpatialLayer->sSliceArgument.uiSliceMode != SM_SIZELIMITED_SLICE)) {
534       WelsLog (pLogCtx, WELS_LOG_WARNING,
535                "ParamValidationExt(), current layer %d uiSliceMode (%d) settings may not fulfill MaxNalSize = %d", i,
536                pSpatialLayer->sSliceArgument.uiSliceMode, pCodingParam->uiMaxNalSize);
537     }
538     CheckProfileSetting (pLogCtx, pCodingParam, i, pSpatialLayer->uiProfileIdc);
539     CheckLevelSetting (pLogCtx, pCodingParam, i, pSpatialLayer->uiLevelIdc);
540     //check pSlice settings under multi-pSlice
541     if (kiPicWidth <= 16 && kiPicHeight <= 16) {
542       //only have one MB, set to single_slice
543       pSpatialLayer->sSliceArgument.uiSliceMode = SM_SINGLE_SLICE;
544     }
545     switch (pSpatialLayer->sSliceArgument.uiSliceMode) {
546     case SM_SINGLE_SLICE:
547       pSpatialLayer->sSliceArgument.uiSliceNum = 1;
548       pSpatialLayer->sSliceArgument.uiSliceSizeConstraint = 0;
549       for (iIdx = 0; iIdx < MAX_SLICES_NUM; iIdx++) {
550         pSpatialLayer->sSliceArgument.uiSliceMbNum[iIdx] = 0;
551       }
552       break;
553     case SM_FIXEDSLCNUM_SLICE: {
554       iReturn = SliceArgumentValidationFixedSliceMode (pLogCtx, &pSpatialLayer->sSliceArgument, pCodingParam->iRCMode,
555                 kiPicWidth, kiPicHeight);
556       if (iReturn)
557         return ENC_RETURN_UNSUPPORTED_PARA;
558     }
559     break;
560     case SM_RASTER_SLICE: {
561       pSpatialLayer->sSliceArgument.uiSliceSizeConstraint = 0;
562 
563       iMbWidth  = (kiPicWidth + 15) >> 4;
564       iMbHeight = (kiPicHeight + 15) >> 4;
565       iMbNumInFrame = iMbWidth * iMbHeight;
566       iMaxSliceNum = MAX_SLICES_NUM;
567       if (pSpatialLayer->sSliceArgument.uiSliceMbNum[0] == 0) {
568         if (iMbHeight > iMaxSliceNum) {
569           WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceNum (%d) settings more than MAX(%d)!",
570                    iMbHeight, MAX_SLICES_NUM);
571           return ENC_RETURN_UNSUPPORTED_PARA;
572         }
573         pSpatialLayer->sSliceArgument.uiSliceNum = iMbHeight;
574         for (uint32_t j = 0; j < iMbHeight; j++) {
575           pSpatialLayer->sSliceArgument.uiSliceMbNum[j] = iMbWidth;
576         }
577         if (!CheckRowMbMultiSliceSetting (iMbWidth,
578                                           &pSpatialLayer->sSliceArgument)) { // verify interleave mode settings
579           WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!",
580                    pSpatialLayer->sSliceArgument.uiSliceMbNum[0]);
581           return ENC_RETURN_UNSUPPORTED_PARA;
582         }
583         break;
584       }
585 
586       if (!CheckRasterMultiSliceSetting (iMbNumInFrame,
587                                          &pSpatialLayer->sSliceArgument)) { // verify interleave mode settings
588         WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceMbNum (%d) settings!",
589                  pSpatialLayer->sSliceArgument.uiSliceMbNum[0]);
590         return ENC_RETURN_UNSUPPORTED_PARA;
591       }
592       if (pSpatialLayer->sSliceArgument.uiSliceNum <= 0
593           || pSpatialLayer->sSliceArgument.uiSliceNum > iMaxSliceNum) { // verify interleave mode settings
594         WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceNum (%d) in SM_RASTER_SLICE settings!",
595                  pSpatialLayer->sSliceArgument.uiSliceNum);
596         return ENC_RETURN_UNSUPPORTED_PARA;
597       }
598       if (pSpatialLayer->sSliceArgument.uiSliceNum == 1) {
599         WelsLog (pLogCtx, WELS_LOG_WARNING,
600                  "ParamValidationExt(), pSlice setting for SM_RASTER_SLICE now turn to SM_SINGLE_SLICE!");
601         pSpatialLayer->sSliceArgument.uiSliceMode = SM_SINGLE_SLICE;
602         break;
603       }
604       if ((pCodingParam->iRCMode != RC_OFF_MODE) && pSpatialLayer->sSliceArgument.uiSliceNum > 1) {
605         WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), WARNING: GOM based RC do not support SM_RASTER_SLICE!");
606       }
607       // considering the coding efficient and performance, iCountMbNum constraint by MIN_NUM_MB_PER_SLICE condition of multi-pSlice mode settting
608       if (iMbNumInFrame <= MIN_NUM_MB_PER_SLICE) {
609         pSpatialLayer->sSliceArgument.uiSliceMode = SM_SINGLE_SLICE;
610         pSpatialLayer->sSliceArgument.uiSliceNum = 1;
611         break;
612       }
613     }
614     break;
615     case SM_SIZELIMITED_SLICE: {
616       iMbWidth  = (kiPicWidth + 15) >> 4;
617       iMbHeight = (kiPicHeight + 15) >> 4;
618       if (pSpatialLayer->sSliceArgument.uiSliceSizeConstraint <= MAX_MACROBLOCK_SIZE_IN_BYTE) {
619         WelsLog (pLogCtx, WELS_LOG_ERROR,
620                  "ParamValidationExt(), invalid iSliceSize (%d) settings!should be larger than  MAX_MACROBLOCK_SIZE_IN_BYTE(%d)",
621                  pSpatialLayer->sSliceArgument.uiSliceSizeConstraint, MAX_MACROBLOCK_SIZE_IN_BYTE);
622         return ENC_RETURN_UNSUPPORTED_PARA;
623       }
624 
625       if (pCodingParam->uiMaxNalSize > 0) {
626         if (pCodingParam->uiMaxNalSize < (NAL_HEADER_ADD_0X30BYTES + MAX_MACROBLOCK_SIZE_IN_BYTE)) {
627           WelsLog (pLogCtx, WELS_LOG_ERROR,
628                    "ParamValidationExt(), invalid uiMaxNalSize (%d) settings! should be larger than (NAL_HEADER_ADD_0X30BYTES + MAX_MACROBLOCK_SIZE_IN_BYTE)(%d)",
629                    pCodingParam->uiMaxNalSize, (NAL_HEADER_ADD_0X30BYTES + MAX_MACROBLOCK_SIZE_IN_BYTE));
630           return ENC_RETURN_UNSUPPORTED_PARA;
631         }
632 
633         if (pSpatialLayer->sSliceArgument.uiSliceSizeConstraint > (pCodingParam->uiMaxNalSize -
634             NAL_HEADER_ADD_0X30BYTES)) {
635           WelsLog (pLogCtx, WELS_LOG_WARNING,
636                    "ParamValidationExt(), slice mode = SM_SIZELIMITED_SLICE, uiSliceSizeConstraint = %d ,uiMaxNalsize = %d, will take uiMaxNalsize!",
637                    pSpatialLayer->sSliceArgument.uiSliceSizeConstraint, pCodingParam->uiMaxNalSize);
638           pSpatialLayer->sSliceArgument.uiSliceSizeConstraint =  pCodingParam->uiMaxNalSize - NAL_HEADER_ADD_0X30BYTES;
639         }
640       }
641       pSpatialLayer->sSliceArgument.uiSliceSizeConstraint -= NAL_HEADER_ADD_0X30BYTES;
642     }
643     break;
644     default: {
645       WelsLog (pLogCtx, WELS_LOG_ERROR, "ParamValidationExt(), invalid uiSliceMode (%d) settings!",
646                pCodingParam->sSpatialLayers[0].sSliceArgument.uiSliceMode);
647       return ENC_RETURN_UNSUPPORTED_PARA;
648 
649     }
650     break;
651     }
652   }
653   for (i = 0; i < pCodingParam->iSpatialLayerNum; ++ i) {
654     SSpatialLayerConfig* pLayerInfo = &pCodingParam->sSpatialLayers[i];
655     if ((pLayerInfo->uiProfileIdc == PRO_BASELINE) || (pLayerInfo->uiProfileIdc == PRO_SCALABLE_BASELINE)) {
656       if (pCodingParam->iEntropyCodingModeFlag != 0) {
657         pCodingParam->iEntropyCodingModeFlag = 0;
658         WelsLog (pLogCtx, WELS_LOG_WARNING, "layerId(%d) Profile is baseline, Change CABAC to CAVLC", i);
659       }
660     } else if (pLayerInfo->uiProfileIdc == PRO_UNKNOWN) {
661       if ((i == 0) || pCodingParam->bSimulcastAVC) {
662         pLayerInfo->uiProfileIdc = (pCodingParam->iEntropyCodingModeFlag) ? PRO_HIGH : PRO_BASELINE;
663       } else {
664         pLayerInfo->uiProfileIdc = PRO_SCALABLE_BASELINE;
665       }
666     }
667   }
668   return ParamValidation (pLogCtx, pCodingParam);
669 }
670 
671 
WelsEncoderApplyFrameRate(SWelsSvcCodingParam * pParam)672 void WelsEncoderApplyFrameRate (SWelsSvcCodingParam* pParam) {
673   SSpatialLayerInternal* pLayerParamInternal;
674   SSpatialLayerConfig* pLayerParam;
675   const float kfEpsn = 0.000001f;
676   const int32_t kiNumLayer = pParam->iSpatialLayerNum;
677   int32_t i;
678   const float kfMaxFrameRate = pParam->fMaxFrameRate;
679   float fRatio;
680   float fTargetOutputFrameRate;
681 
682   //set input frame rate to each layer
683   for (i = 0; i < kiNumLayer; i++) {
684     pLayerParamInternal = & (pParam->sDependencyLayers[i]);
685     pLayerParam = & (pParam->sSpatialLayers[i]);
686     fRatio = pLayerParamInternal->fOutputFrameRate / pLayerParamInternal->fInputFrameRate;
687     if ((kfMaxFrameRate - pLayerParamInternal->fInputFrameRate) > kfEpsn
688         || (kfMaxFrameRate - pLayerParamInternal->fInputFrameRate) < -kfEpsn) {
689       pLayerParamInternal->fInputFrameRate = kfMaxFrameRate;
690       fTargetOutputFrameRate = kfMaxFrameRate * fRatio;
691       pLayerParamInternal->fOutputFrameRate = (fTargetOutputFrameRate >= 6) ? fTargetOutputFrameRate :
692                                               (pLayerParamInternal->fInputFrameRate);
693       pLayerParam->fFrameRate = pLayerParamInternal->fOutputFrameRate;
694       //TODO:{Sijia} from design, there is no sense to have temporal layer when under 6fps even with such setting?
695     }
696   }
697 }
698 
WelsEncoderApplyBitRate(SLogContext * pLogCtx,SWelsSvcCodingParam * pParam,int iLayer)699 int32_t WelsEncoderApplyBitRate (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam, int iLayer) {
700   //TODO (Sijia):  this is a temporary solution which keep the ratio between layers
701   //but it is also possible to fulfill the bitrate of lower layer first
702 
703   SSpatialLayerConfig* pLayerParam;
704   const int32_t iNumLayers = pParam->iSpatialLayerNum;
705   int32_t i, iOrigTotalBitrate = 0;
706   if (iLayer == SPATIAL_LAYER_ALL) {
707     //read old BR
708     for (i = 0; i < iNumLayers; i++) {
709       iOrigTotalBitrate += pParam->sSpatialLayers[i].iSpatialBitrate;
710     }
711     //write new BR
712     float fRatio = 0.0;
713     for (i = 0; i < iNumLayers; i++) {
714       pLayerParam = & (pParam->sSpatialLayers[i]);
715       fRatio = pLayerParam->iSpatialBitrate / (static_cast<float> (iOrigTotalBitrate));
716       pLayerParam->iSpatialBitrate = static_cast<int32_t> (pParam->iTargetBitrate * fRatio);
717 
718       if (WelsBitRateVerification (pLogCtx, pLayerParam, i) != ENC_RETURN_SUCCESS)
719         return ENC_RETURN_UNSUPPORTED_PARA;
720     }
721   } else {
722     return WelsBitRateVerification (pLogCtx, & (pParam->sSpatialLayers[iLayer]), iLayer);
723   }
724   return ENC_RETURN_SUCCESS;
725 }
WelsEncoderApplyBitVaryRang(SLogContext * pLogCtx,SWelsSvcCodingParam * pParam,int32_t iRang)726 int32_t WelsEncoderApplyBitVaryRang (SLogContext* pLogCtx, SWelsSvcCodingParam* pParam, int32_t iRang) {
727   SSpatialLayerConfig* pLayerParam;
728   const int32_t iNumLayers = pParam->iSpatialLayerNum;
729   for (int32_t i = 0; i < iNumLayers; i++) {
730     pLayerParam = & (pParam->sSpatialLayers[i]);
731     pLayerParam->iMaxSpatialBitrate = WELS_MIN ((int) (pLayerParam->iSpatialBitrate * (1 + iRang / 100.0)),
732                                       pLayerParam->iMaxSpatialBitrate);
733     if (WelsBitRateVerification (pLogCtx, pLayerParam, i) != ENC_RETURN_SUCCESS)
734       return ENC_RETURN_UNSUPPORTED_PARA;
735     WelsLog (pLogCtx, WELS_LOG_INFO,
736              "WelsEncoderApplyBitVaryRang:UpdateMaxBitrate layerId= %d,iMaxSpatialBitrate = %d", i, pLayerParam->iMaxSpatialBitrate);
737   }
738   return ENC_RETURN_SUCCESS;
739 }
740 
741 /*!
742  * \brief   acquire count number of layers and NALs based on configurable paramters dependency
743  * \pParam  pCtx            sWelsEncCtx*
744  * \pParam  pParam          SWelsSvcCodingParam*
745  * \pParam  pCountLayers    pointer of count number of layers indeed
746  * \pParam  iCountNals      pointer of count number of nals indeed
747  * \return  0 - successful; otherwise failed
748  */
AcquireLayersNals(sWelsEncCtx ** ppCtx,SWelsSvcCodingParam * pParam,int32_t * pCountLayers,int32_t * pCountNals)749 int32_t AcquireLayersNals (sWelsEncCtx** ppCtx, SWelsSvcCodingParam* pParam, int32_t* pCountLayers,
750                            int32_t* pCountNals) {
751   int32_t iCountNumLayers       = 0;
752   int32_t iCountNumNals         = 0;
753   int32_t iNumDependencyLayers  = 0;
754   int32_t iDIndex               = 0;
755 
756   if (NULL == pParam || NULL == ppCtx || NULL == *ppCtx)
757     return 1;
758 
759   iNumDependencyLayers = pParam->iSpatialLayerNum;
760 
761   do {
762     SSpatialLayerConfig* pDLayer = &pParam->sSpatialLayers[iDIndex];
763 //    pDLayer->ptr_cfg = pParam;
764     int32_t iOrgNumNals = iCountNumNals;
765 
766     //Note: Sep. 2010
767     //Review this part and suggest no change, since the memory over-use
768     //(1) counts little to the overall performance
769     //(2) should not be critial even under mobile case
770     if (SM_SIZELIMITED_SLICE == pDLayer->sSliceArgument.uiSliceMode) {
771       iCountNumNals += MAX_SLICES_NUM;
772       // plus prefix NALs
773       if (iDIndex == 0)
774         iCountNumNals += MAX_SLICES_NUM;
775       // MAX_SLICES_NUM < MAX_LAYER_NUM_OF_FRAME ensured at svc_enc_slice_segment.h
776       if (iCountNumNals - iOrgNumNals > MAX_NAL_UNITS_IN_LAYER) {
777         WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_ERROR,
778                  "AcquireLayersNals(), num_of_slice(%d) > existing slice(%d) at (iDid= %d), max=%d",
779                  iCountNumNals, iOrgNumNals, iDIndex, MAX_NAL_UNITS_IN_LAYER);
780         return 1;
781       }
782     } else { /*if ( SM_SINGLE_SLICE != pDLayer->sSliceArgument.uiSliceMode )*/
783       const int32_t kiNumOfSlice = GetInitialSliceNum (&pDLayer->sSliceArgument);
784 
785       // NEED check iCountNals value in case multiple slices is used
786       iCountNumNals += kiNumOfSlice; // for pSlice VCL NALs
787       // plus prefix NALs
788       if (iDIndex == 0)
789         iCountNumNals += kiNumOfSlice;
790       assert (iCountNumNals - iOrgNumNals <= MAX_NAL_UNITS_IN_LAYER);
791       if (kiNumOfSlice > MAX_SLICES_NUM) {
792         WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_ERROR,
793                  "AcquireLayersNals(), num_of_slice(%d) > MAX_SLICES_NUM(%d) per (iDid= %d, qid= %d) settings!",
794                  kiNumOfSlice, MAX_SLICES_NUM, iDIndex, 0);
795         return 1;
796       }
797     }
798 
799     if (iCountNumNals - iOrgNumNals > MAX_NAL_UNITS_IN_LAYER) {
800       WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_ERROR,
801                "AcquireLayersNals(), num_of_nals(%d) > MAX_NAL_UNITS_IN_LAYER(%d) per (iDid= %d, qid= %d) settings!",
802                (iCountNumNals - iOrgNumNals), MAX_NAL_UNITS_IN_LAYER, iDIndex, 0);
803       return 1;
804     }
805 
806     iCountNumLayers ++;
807 
808     ++ iDIndex;
809   } while (iDIndex < iNumDependencyLayers);
810 
811   if (NULL == (*ppCtx)->pFuncList || NULL == (*ppCtx)->pFuncList->pParametersetStrategy) {
812     WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_ERROR,
813              "AcquireLayersNals(), pFuncList and pParametersetStrategy needed to be initialized first!");
814     return 1;
815   }
816   // count parasets
817   iCountNumNals += 1 + iNumDependencyLayers + (iCountNumLayers << 1) +
818                    iCountNumLayers // plus iCountNumLayers for reserved application
819                    + (*ppCtx)->pFuncList->pParametersetStrategy->GetAllNeededParasetNum();
820 
821   // to check number of layers / nals / slices dependencies, 12/8/2010
822   if (iCountNumLayers > MAX_LAYER_NUM_OF_FRAME) {
823     WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_ERROR, "AcquireLayersNals(), iCountNumLayers(%d) > MAX_LAYER_NUM_OF_FRAME(%d)!",
824              iCountNumLayers, MAX_LAYER_NUM_OF_FRAME);
825     return 1;
826   }
827 
828   if (NULL != pCountLayers)
829     *pCountLayers = iCountNumLayers;
830   if (NULL != pCountNals)
831     *pCountNals = iCountNumNals;
832   return 0;
833 }
834 
InitMbInfo(sWelsEncCtx * pEnc,SMB * pList,SDqLayer * pLayer,const int32_t kiDlayerId,const int32_t kiMaxMbNum)835 static  void  InitMbInfo (sWelsEncCtx* pEnc, SMB*   pList, SDqLayer* pLayer, const int32_t kiDlayerId,
836                           const int32_t kiMaxMbNum) {
837   int32_t  iMbWidth     = pLayer->iMbWidth;
838   int32_t  iMbHeight    = pLayer->iMbHeight;
839   int32_t  iIdx;
840   int32_t  iMbNum       = iMbWidth * iMbHeight;
841   uint32_t uiNeighborAvail;
842   const int32_t kiOffset = (kiDlayerId & 0x01) * kiMaxMbNum;
843   SMVUnitXY (*pLayerMvUnitBlock4x4)[MB_BLOCK4x4_NUM] = (SMVUnitXY (*)[MB_BLOCK4x4_NUM]) (
844         &pEnc->pMvUnitBlock4x4[MB_BLOCK4x4_NUM * kiOffset]);
845   int8_t (*pLayerRefIndexBlock8x8)[MB_BLOCK8x8_NUM] = (int8_t (*)[MB_BLOCK8x8_NUM]) (
846         &pEnc->pRefIndexBlock4x4[MB_BLOCK8x8_NUM * kiOffset]);
847 
848   for (iIdx = 0; iIdx < iMbNum; iIdx++) {
849     bool     bLeft;
850     bool     bTop;
851     bool     bLeftTop;
852     bool     bRightTop;
853     int32_t  iLeftXY, iTopXY, iLeftTopXY, iRightTopXY;
854     uint16_t  uiSliceIdc; //[0..65535] > 36864 of LEVEL5.2
855 
856     pList[iIdx].iMbX = pEnc->pStrideTab->pMbIndexX[kiDlayerId][iIdx];
857     pList[iIdx].iMbY = pEnc->pStrideTab->pMbIndexY[kiDlayerId][iIdx];
858     pList[iIdx].iMbXY = iIdx;
859 
860     uiSliceIdc = WelsMbToSliceIdc (pLayer, iIdx);
861     iLeftXY = iIdx - 1;
862     iTopXY = iIdx - iMbWidth;
863     iLeftTopXY = iTopXY - 1;
864     iRightTopXY = iTopXY + 1;
865 
866     bLeft = (pList[iIdx].iMbX > 0) && (uiSliceIdc == WelsMbToSliceIdc (pLayer, iLeftXY));
867     bTop = (pList[iIdx].iMbY > 0) && (uiSliceIdc == WelsMbToSliceIdc (pLayer, iTopXY));
868     bLeftTop = (pList[iIdx].iMbX > 0) && (pList[iIdx].iMbY > 0) && (uiSliceIdc ==
869                WelsMbToSliceIdc (pLayer, iLeftTopXY));
870     bRightTop = (pList[iIdx].iMbX < (iMbWidth - 1)) && (pList[iIdx].iMbY > 0) && (uiSliceIdc ==
871                 WelsMbToSliceIdc (pLayer, iRightTopXY));
872 
873     uiNeighborAvail = 0;
874     if (bLeft) {
875       uiNeighborAvail |= LEFT_MB_POS;
876     }
877     if (bTop) {
878       uiNeighborAvail |= TOP_MB_POS;
879     }
880     if (bLeftTop) {
881       uiNeighborAvail |= TOPLEFT_MB_POS;
882     }
883     if (bRightTop) {
884       uiNeighborAvail |= TOPRIGHT_MB_POS;
885     }
886     pList[iIdx].uiSliceIdc      = uiSliceIdc; // merge from svc_hd_opt_b for multiple slices coding
887     pList[iIdx].uiNeighborAvail = uiNeighborAvail;
888     uiNeighborAvail = 0;
889     if (pList[iIdx].iMbX >= BASE_MV_MB_NMB)
890       uiNeighborAvail |= LEFT_MB_POS;
891     if (pList[iIdx].iMbX <= (iMbWidth - 1 - BASE_MV_MB_NMB))
892       uiNeighborAvail |= RIGHT_MB_POS;
893     if (pList[iIdx].iMbY >= BASE_MV_MB_NMB)
894       uiNeighborAvail |= TOP_MB_POS;
895     if (pList[iIdx].iMbY <= (iMbHeight - 1 - BASE_MV_MB_NMB))
896       uiNeighborAvail |= BOTTOM_MB_POS;
897 
898     pList[iIdx].sMv                     = pLayerMvUnitBlock4x4[iIdx];
899     pList[iIdx].pRefIndex               = pLayerRefIndexBlock8x8[iIdx];
900     pList[iIdx].pSadCost                = &pEnc->pSadCostMb[iIdx];
901     pList[iIdx].pIntra4x4PredMode       = &pEnc->pIntra4x4PredModeBlocks[iIdx * INTRA_4x4_MODE_NUM];
902     pList[iIdx].pNonZeroCount           = &pEnc->pNonZeroCountBlocks[iIdx * MB_LUMA_CHROMA_BLOCK4x4_NUM];
903   }
904 }
905 
906 
InitMbListD(sWelsEncCtx ** ppCtx)907 int32_t   InitMbListD (sWelsEncCtx** ppCtx) {
908   int32_t iNumDlayer = (*ppCtx)->pSvcParam->iSpatialLayerNum;
909   int32_t iMbSize[MAX_DEPENDENCY_LAYER] = { 0 };
910   int32_t iOverallMbNum = 0;
911   int32_t iMbWidth = 0;
912   int32_t iMbHeight = 0;
913   int32_t i;
914 
915   if (iNumDlayer > MAX_DEPENDENCY_LAYER)
916     return 1;
917 
918   for (i = 0; i < iNumDlayer; i++) {
919     iMbWidth = ((*ppCtx)->pSvcParam->sSpatialLayers[i].iVideoWidth + 15) >> 4;
920     iMbHeight = ((*ppCtx)->pSvcParam->sSpatialLayers[i].iVideoHeight + 15) >> 4;
921     iMbSize[i] = iMbWidth  * iMbHeight;
922     iOverallMbNum += iMbSize[i];
923   }
924 
925   (*ppCtx)->ppMbListD = static_cast<SMB**> ((*ppCtx)->pMemAlign->WelsMallocz (iNumDlayer * sizeof (SMB*), "ppMbListD"));
926   (*ppCtx)->ppMbListD[0] = NULL;
927   WELS_VERIFY_RETURN_IF (1, (*ppCtx)->ppMbListD == NULL)
928   (*ppCtx)->ppMbListD[0] = static_cast<SMB*> ((*ppCtx)->pMemAlign->WelsMallocz (iOverallMbNum * sizeof (SMB),
929                            "ppMbListD[0]"));
930   WELS_VERIFY_RETURN_IF (1, (*ppCtx)->ppMbListD[0] == NULL)
931   (*ppCtx)->ppDqLayerList[0]->sMbDataP = (*ppCtx)->ppMbListD[0];
932   InitMbInfo (*ppCtx, (*ppCtx)->ppMbListD[0], (*ppCtx)->ppDqLayerList[0], 0, iMbSize[iNumDlayer - 1]);
933   for (i = 1; i < iNumDlayer; i++) {
934     (*ppCtx)->ppMbListD[i] = (*ppCtx)->ppMbListD[i - 1] + iMbSize[i - 1];
935     (*ppCtx)->ppDqLayerList[i]->sMbDataP = (*ppCtx)->ppMbListD[i];
936     InitMbInfo (*ppCtx, (*ppCtx)->ppMbListD[i], (*ppCtx)->ppDqLayerList[i], i, iMbSize[iNumDlayer - 1]);
937   }
938 
939   return 0;
940 }
941 
FreeSliceInLayer(SDqLayer * pDq,CMemoryAlign * pMa)942 void FreeSliceInLayer (SDqLayer* pDq, CMemoryAlign* pMa) {
943   int32_t iIdx = 0;
944   for (; iIdx < MAX_THREADS_NUM; iIdx ++) {
945     FreeSliceBuffer (pDq->sSliceBufferInfo[iIdx].pSliceBuffer,
946                      pDq->sSliceBufferInfo[iIdx].iMaxSliceNum,
947                      pMa, "pSliceBuffer");
948   }
949 }
950 
FreeDqLayer(SDqLayer * & pDq,CMemoryAlign * pMa)951 void FreeDqLayer (SDqLayer*& pDq, CMemoryAlign* pMa) {
952   if (NULL == pDq) {
953     return;
954   }
955 
956   FreeSliceInLayer (pDq, pMa);
957 
958   if (pDq->ppSliceInLayer) {
959     pMa->WelsFree (pDq->ppSliceInLayer, "ppSliceInLayer");
960     pDq->ppSliceInLayer = NULL;
961   }
962 
963   if (pDq->pFirstMbIdxOfSlice) {
964     pMa->WelsFree (pDq->pFirstMbIdxOfSlice, "pFirstMbIdxOfSlice");
965     pDq->pFirstMbIdxOfSlice = NULL;
966   }
967 
968   if (pDq->pCountMbNumInSlice) {
969     pMa->WelsFree (pDq->pCountMbNumInSlice, "pCountMbNumInSlice");
970     pDq->pCountMbNumInSlice = NULL;
971   }
972 
973   if (pDq->pFeatureSearchPreparation) {
974     ReleaseFeatureSearchPreparation (pMa, pDq->pFeatureSearchPreparation->pFeatureOfBlock);
975     pMa->WelsFree (pDq->pFeatureSearchPreparation, "pFeatureSearchPreparation");
976     pDq->pFeatureSearchPreparation = NULL;
977   }
978 
979   UninitSlicePEncCtx (pDq, pMa);
980   pDq->iMaxSliceNum = 0;
981 
982   pMa->WelsFree (pDq, "pDqLayer");
983   pDq = NULL;
984 }
985 
FreeRefList(SRefList * & pRefList,CMemoryAlign * pMa,const int iMaxNumRefFrame)986 void  FreeRefList (SRefList*& pRefList, CMemoryAlign* pMa, const int iMaxNumRefFrame) {
987   if (NULL == pRefList) {
988     return;
989   }
990 
991   int32_t iRef = 0;
992   do {
993     if (pRefList->pRef[iRef] != NULL) {
994       FreePicture (pMa, &pRefList->pRef[iRef]);
995     }
996     ++ iRef;
997   } while (iRef < 1 + iMaxNumRefFrame);
998 
999   pMa->WelsFree (pRefList, "pRefList");
1000   pRefList = NULL;
1001 }
1002 
1003 /*!
1004  * \brief   initialize ppDqLayerList and slicepEncCtx_list due to count number of layers available
1005  * \pParam  pCtx            sWelsEncCtx*
1006  * \return  0 - successful; otherwise failed
1007  */
InitDqLayers(sWelsEncCtx ** ppCtx,SExistingParasetList * pExistingParasetList)1008 static inline int32_t InitDqLayers (sWelsEncCtx** ppCtx, SExistingParasetList* pExistingParasetList) {
1009   SWelsSvcCodingParam* pParam   = NULL;
1010   SWelsSPS* pSps                = NULL;
1011   SSubsetSps* pSubsetSps        = NULL;
1012   SWelsPPS* pPps                = NULL;
1013   CMemoryAlign* pMa             = NULL;
1014   int32_t iDlayerCount          = 0;
1015   int32_t iDlayerIndex          = 0;
1016   int32_t iSpsId               = 0;
1017   uint32_t iPpsId               = 0;
1018   uint32_t iNumRef              = 0;
1019   int32_t iResult               = 0;
1020 
1021   if (NULL == ppCtx || NULL == *ppCtx)
1022     return 1;
1023 
1024   pMa           = (*ppCtx)->pMemAlign;
1025   pParam        = (*ppCtx)->pSvcParam;
1026   iDlayerCount  = pParam->iSpatialLayerNum;
1027   iNumRef       = pParam->iMaxNumRefFrame;
1028 
1029   const int32_t kiFeatureStrategyIndex = FME_DEFAULT_FEATURE_INDEX;
1030   const int32_t kiMe16x16 = ME_DIA_CROSS;
1031   const int32_t kiMe8x8 = ME_DIA_CROSS_FME;
1032   const int32_t kiNeedFeatureStorage = (pParam->iUsageType != SCREEN_CONTENT_REAL_TIME) ? 0 :
1033                                        ((kiFeatureStrategyIndex << 16) + ((kiMe16x16 & 0x00FF) << 8) + (kiMe8x8 & 0x00FF));
1034 
1035   iDlayerIndex = 0;
1036   while (iDlayerIndex < iDlayerCount) {
1037     SRefList* pRefList          = NULL;
1038     uint32_t i                  = 0;
1039     const int32_t kiWidth       = pParam->sSpatialLayers[iDlayerIndex].iVideoWidth;
1040     const int32_t kiHeight      = pParam->sSpatialLayers[iDlayerIndex].iVideoHeight;
1041     int32_t iPicWidth           = WELS_ALIGN (kiWidth, MB_WIDTH_LUMA) + (PADDING_LENGTH << 1);  // with iWidth of horizon
1042     int32_t iPicChromaWidth     = iPicWidth >> 1;
1043 
1044     iPicWidth = WELS_ALIGN (iPicWidth,
1045                             32); // 32(or 16 for chroma below) to match original imp. here instead of iCacheLineSize
1046     iPicChromaWidth = WELS_ALIGN (iPicChromaWidth, 16);
1047 
1048     WelsGetEncBlockStrideOffset ((*ppCtx)->pStrideTab->pStrideEncBlockOffset[iDlayerIndex], iPicWidth, iPicChromaWidth);
1049 
1050     // pRef list
1051     pRefList = (SRefList*)pMa->WelsMallocz (sizeof (SRefList), "pRefList");
1052     WELS_VERIFY_RETURN_IF (1, (NULL == pRefList))
1053     do {
1054       pRefList->pRef[i] = AllocPicture (pMa, kiWidth, kiHeight, true,
1055                                         (iDlayerIndex == iDlayerCount - 1) ? kiNeedFeatureStorage : 0); // to use actual size of current layer
1056       WELS_VERIFY_RETURN_PROC_IF (1, (NULL == pRefList->pRef[i]), FreeRefList (pRefList, pMa, iNumRef))
1057       ++ i;
1058     } while (i < 1 + iNumRef);
1059 
1060     pRefList->pNextBuffer = pRefList->pRef[0];
1061     (*ppCtx)->ppRefPicListExt[iDlayerIndex] = pRefList;
1062     ++ iDlayerIndex;
1063   }
1064 
1065   iDlayerIndex = 0;
1066   while (iDlayerIndex < iDlayerCount) {
1067     SDqLayer* pDqLayer              = NULL;
1068     SSpatialLayerConfig* pDlayer    = &pParam->sSpatialLayers[iDlayerIndex];
1069     SSpatialLayerInternal* pParamInternal    = &pParam->sDependencyLayers[iDlayerIndex];
1070     const int32_t kiMbW             = (pDlayer->iVideoWidth + 0x0f) >> 4;
1071     const int32_t kiMbH             = (pDlayer->iVideoHeight + 0x0f) >> 4;
1072 
1073     pParamInternal->iCodingIndex = 0;
1074     pParamInternal->iFrameIndex = 0;
1075     pParamInternal->iFrameNum = 0;
1076     pParamInternal->iPOC = 0;
1077     pParamInternal->uiIdrPicId = 0;
1078     pParamInternal->bEncCurFrmAsIdrFlag = true;  // make sure first frame is IDR
1079     // pDq layers list
1080     pDqLayer = (SDqLayer*)pMa->WelsMallocz (sizeof (SDqLayer), "pDqLayer");
1081     WELS_VERIFY_RETURN_PROC_IF (1, (NULL == pDqLayer), FreeDqLayer (pDqLayer, pMa))
1082 
1083     pDqLayer->bNeedAdjustingSlicing = false;
1084 
1085     pDqLayer->iMbWidth  = kiMbW;
1086     pDqLayer->iMbHeight = kiMbH;
1087 
1088     int32_t iMaxSliceNum            = 1;
1089     const int32_t kiSliceNum = GetInitialSliceNum (&pDlayer->sSliceArgument);
1090     if (iMaxSliceNum < kiSliceNum)
1091       iMaxSliceNum = kiSliceNum;
1092     pDqLayer->iMaxSliceNum = iMaxSliceNum;
1093 
1094     iResult = InitSliceInLayer (*ppCtx, pDqLayer, iDlayerIndex, pMa);
1095     if (iResult) {
1096       WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_WARNING, "InitDqLayers(), InitSliceInLayer failed(%d)!", iResult);
1097       FreeDqLayer (pDqLayer, pMa);
1098       return iResult;
1099     }
1100 
1101     //deblocking parameters initialization
1102     //target-layer deblocking
1103     pDqLayer->iLoopFilterDisableIdc     = pParam->iLoopFilterDisableIdc;
1104     pDqLayer->iLoopFilterAlphaC0Offset  = (pParam->iLoopFilterAlphaC0Offset) << 1;
1105     pDqLayer->iLoopFilterBetaOffset     = (pParam->iLoopFilterBetaOffset) << 1;
1106     //parallel deblocking
1107     pDqLayer->bDeblockingParallelFlag   = pParam->bDeblockingParallelFlag;
1108 
1109     //deblocking parameter adjustment
1110     if (SM_SINGLE_SLICE == pDlayer->sSliceArgument.uiSliceMode) {
1111       //iLoopFilterDisableIdc: will be 0 or 1 under single_slice
1112       if (2 == pParam->iLoopFilterDisableIdc) {
1113         pDqLayer->iLoopFilterDisableIdc = 0;
1114       }
1115       //bDeblockingParallelFlag
1116       pDqLayer->bDeblockingParallelFlag = false;
1117     } else {
1118       //multi-pSlice
1119       if (0 == pDqLayer->iLoopFilterDisableIdc) {
1120         pDqLayer->bDeblockingParallelFlag = false;
1121       }
1122     }
1123 
1124     //
1125     if (kiNeedFeatureStorage && iDlayerIndex == iDlayerCount - 1) {
1126       pDqLayer->pFeatureSearchPreparation = static_cast<SFeatureSearchPreparation*> (pMa->WelsMallocz (sizeof (
1127                                               SFeatureSearchPreparation), "pFeatureSearchPreparation"));
1128       WELS_VERIFY_RETURN_IF (1, NULL == pDqLayer->pFeatureSearchPreparation)
1129       int32_t iReturn = RequestFeatureSearchPreparation (pMa, pDlayer->iVideoWidth, pDlayer->iVideoHeight,
1130                         kiNeedFeatureStorage,
1131                         pDqLayer->pFeatureSearchPreparation);
1132       WELS_VERIFY_RETURN_IF (1, ENC_RETURN_SUCCESS != iReturn)
1133     } else {
1134       pDqLayer->pFeatureSearchPreparation = NULL;
1135     }
1136 
1137     (*ppCtx)->ppDqLayerList[iDlayerIndex] = pDqLayer;
1138 
1139     ++ iDlayerIndex;
1140   }
1141 
1142   // for dynamically malloc for parameter sets memory instead of maximal items for standard to reduce size, 3/18/2010
1143   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pFuncList))
1144   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pFuncList->pParametersetStrategy))
1145   const int32_t kiNeededSpsNum = (*ppCtx)->pFuncList->pParametersetStrategy->GetNeededSpsNum();
1146   const int32_t kiNeededSubsetSpsNum = (*ppCtx)->pFuncList->pParametersetStrategy->GetNeededSubsetSpsNum();
1147   (*ppCtx)->pSpsArray = (SWelsSPS*)pMa->WelsMallocz (kiNeededSpsNum * sizeof (SWelsSPS), "pSpsArray");
1148   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pSpsArray))
1149   if (kiNeededSubsetSpsNum > 0) {
1150     (*ppCtx)->pSubsetArray = (SSubsetSps*)pMa->WelsMallocz (kiNeededSubsetSpsNum * sizeof (SSubsetSps), "pSubsetArray");
1151     WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pSubsetArray))
1152   } else {
1153     (*ppCtx)->pSubsetArray = NULL;
1154   }
1155 
1156   // PPS
1157   const int32_t kiNeededPpsNum = (*ppCtx)->pFuncList->pParametersetStrategy->GetNeededPpsNum();
1158   (*ppCtx)->pPPSArray = (SWelsPPS*)pMa->WelsMallocz (kiNeededPpsNum * sizeof (SWelsPPS), "pPPSArray");
1159   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pPPSArray))
1160 
1161   (*ppCtx)->pFuncList->pParametersetStrategy->LoadPrevious (pExistingParasetList, (*ppCtx)->pSpsArray,
1162       (*ppCtx)->pSubsetArray, (*ppCtx)->pPPSArray);
1163 
1164 
1165   (*ppCtx)->pDqIdcMap = (SDqIdc*)pMa->WelsMallocz (iDlayerCount * sizeof (SDqIdc), "pDqIdcMap");
1166   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pDqIdcMap))
1167 
1168   iDlayerIndex = 0;
1169   while (iDlayerIndex < iDlayerCount) {
1170     SDqIdc* pDqIdc                      = & (*ppCtx)->pDqIdcMap[iDlayerIndex];
1171     const bool bUseSubsetSps            = (!pParam->bSimulcastAVC) && (iDlayerIndex > BASE_DEPENDENCY_ID);
1172     SSpatialLayerConfig* pDlayerParam   = &pParam->sSpatialLayers[iDlayerIndex];
1173     bool bSvcBaselayer = (!pParam->bSimulcastAVC) && (iDlayerCount > BASE_DEPENDENCY_ID)
1174                          && (iDlayerIndex == BASE_DEPENDENCY_ID);
1175     pDqIdc->uiSpatialId = iDlayerIndex;
1176 
1177     iSpsId = (*ppCtx)->pFuncList->pParametersetStrategy->GenerateNewSps (*ppCtx, bUseSubsetSps, iDlayerIndex,
1178              iDlayerCount, iSpsId, pSps, pSubsetSps, bSvcBaselayer);
1179     WELS_VERIFY_RETURN_IF (ENC_RETURN_UNSUPPORTED_PARA, (0 > iSpsId))
1180     if (!bUseSubsetSps) {
1181       pSps = & ((*ppCtx)->pSpsArray[iSpsId]);
1182     } else {
1183       pSubsetSps = & ((*ppCtx)->pSubsetArray[iSpsId]);
1184     }
1185 
1186     iPpsId = (*ppCtx)->pFuncList->pParametersetStrategy->InitPps ((*ppCtx), iSpsId, pSps, pSubsetSps, iPpsId, true,
1187              bUseSubsetSps, pParam->iEntropyCodingModeFlag != 0);
1188     pPps = & ((*ppCtx)->pPPSArray[iPpsId]);
1189 
1190     // Not using FMO in SVC coding so far, come back if need FMO
1191     {
1192       iResult = InitSlicePEncCtx ((*ppCtx)->ppDqLayerList[iDlayerIndex],
1193                                   (*ppCtx)->pMemAlign,
1194                                   false,
1195                                   pSps->iMbWidth,
1196                                   pSps->iMbHeight,
1197                                   & (pDlayerParam->sSliceArgument),
1198                                   pPps);
1199       if (iResult) {
1200         WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_WARNING, "InitDqLayers(), InitSlicePEncCtx failed(%d)!", iResult);
1201         return iResult;
1202       }
1203     }
1204     pDqIdc->iSpsId = iSpsId;
1205     pDqIdc->iPpsId = iPpsId;
1206 
1207     if ((pParam->bSimulcastAVC) || (bUseSubsetSps))
1208       ++ iSpsId;
1209     ++ iPpsId;
1210     if (bUseSubsetSps) {
1211       ++ (*ppCtx)->iSubsetSpsNum;
1212     } else {
1213       ++ (*ppCtx)->iSpsNum;
1214     }
1215     ++ (*ppCtx)->iPpsNum;
1216 
1217     ++ iDlayerIndex;
1218   }
1219 
1220   (*ppCtx)->pFuncList->pParametersetStrategy->UpdateParaSetNum ((*ppCtx));
1221   return ENC_RETURN_SUCCESS;
1222 }
1223 
AllocStrideTables(sWelsEncCtx ** ppCtx,const int32_t kiNumSpatialLayers)1224 int32_t AllocStrideTables (sWelsEncCtx** ppCtx, const int32_t kiNumSpatialLayers) {
1225   CMemoryAlign* pMa             = (*ppCtx)->pMemAlign;
1226   SWelsSvcCodingParam* pParam   = (*ppCtx)->pSvcParam;
1227   SStrideTables* pPtr           = NULL;
1228   int16_t* pTmpRow              = NULL, *pRowX = NULL, *pRowY = NULL, *p = NULL;
1229   uint8_t* pBase                = NULL;
1230   uint8_t* pBaseDec = NULL, *pBaseEnc = NULL, *pBaseMbX = NULL, *pBaseMbY = NULL;
1231   struct {
1232     int32_t iMbWidth;
1233     int32_t iCountMbNum;                // count number of SMB in each spatial
1234     int32_t iSizeAllMbAlignCache;       // cache line size aligned in each spatial
1235   } sMbSizeMap[MAX_DEPENDENCY_LAYER] = {{ 0 }};
1236   int32_t iLineSizeY[MAX_DEPENDENCY_LAYER][2] = {{ 0 }};
1237   int32_t iLineSizeUV[MAX_DEPENDENCY_LAYER][2] = {{ 0 }};
1238   int32_t iMapSpatialIdx[MAX_DEPENDENCY_LAYER][2] = {{ 0 }};
1239   int32_t iSizeDec              = 0;
1240   int32_t iSizeEnc              = 0;
1241   int32_t iCountLayersNeedCs[2] = {0};
1242   const int32_t kiUnit1Size = 24 * sizeof (int32_t);
1243   int32_t iUnit2Size            = 0;
1244   int32_t iNeedAllocSize        = 0;
1245   int32_t iRowSize              = 0;
1246   int16_t iMaxMbWidth           = 0;
1247   int16_t iMaxMbHeight          = 0;
1248   int32_t i                     = 0;
1249   int32_t iSpatialIdx           = 0;
1250   int32_t iTemporalIdx          = 0;
1251   int32_t iCntTid               = 0;
1252 
1253   if (kiNumSpatialLayers <= 0 || kiNumSpatialLayers > MAX_DEPENDENCY_LAYER)
1254     return 1;
1255 
1256   pPtr = (SStrideTables*)pMa->WelsMallocz (sizeof (SStrideTables), "SStrideTables");
1257   if (NULL == pPtr)
1258     return 1;
1259   (*ppCtx)->pStrideTab = pPtr;
1260 
1261   iCntTid = pParam->iTemporalLayerNum > 1 ? 2 : 1;
1262 
1263   iSpatialIdx = 0;
1264   while (iSpatialIdx < kiNumSpatialLayers) {
1265     const int32_t kiTmpWidth = (pParam->sSpatialLayers[iSpatialIdx].iVideoWidth + 15) >> 4;
1266     const int32_t kiTmpHeight = (pParam->sSpatialLayers[iSpatialIdx].iVideoHeight + 15) >> 4;
1267     int32_t iNumMb = kiTmpWidth * kiTmpHeight;
1268 
1269     sMbSizeMap[iSpatialIdx].iMbWidth    = kiTmpWidth;
1270     sMbSizeMap[iSpatialIdx].iCountMbNum = iNumMb;
1271 
1272     iNumMb *= sizeof (int16_t);
1273     sMbSizeMap[iSpatialIdx].iSizeAllMbAlignCache = iNumMb;
1274     iUnit2Size += iNumMb;
1275 
1276     ++ iSpatialIdx;
1277   }
1278 
1279   // Adaptive size_cs, size_fdec by implementation dependency
1280   iTemporalIdx = 0;
1281   while (iTemporalIdx < iCntTid) {
1282     const bool kbBaseTemporalFlag = (iTemporalIdx == 0);
1283 
1284     iSpatialIdx = 0;
1285     while (iSpatialIdx < kiNumSpatialLayers) {
1286       SSpatialLayerConfig* fDlp = &pParam->sSpatialLayers[iSpatialIdx];
1287 
1288       const int32_t kiWidthPad = WELS_ALIGN (fDlp->iVideoWidth, 16) + (PADDING_LENGTH << 1);
1289       iLineSizeY[iSpatialIdx][kbBaseTemporalFlag]  = WELS_ALIGN (kiWidthPad, 32);
1290       iLineSizeUV[iSpatialIdx][kbBaseTemporalFlag] = WELS_ALIGN ((kiWidthPad >> 1), 16);
1291 
1292       iMapSpatialIdx[iCountLayersNeedCs[kbBaseTemporalFlag]][kbBaseTemporalFlag] = iSpatialIdx;
1293       ++ iCountLayersNeedCs[kbBaseTemporalFlag];
1294       ++ iSpatialIdx;
1295     }
1296     ++ iTemporalIdx;
1297   }
1298   iSizeDec = kiUnit1Size * (iCountLayersNeedCs[0] + iCountLayersNeedCs[1]);
1299   iSizeEnc = kiUnit1Size * kiNumSpatialLayers;
1300 
1301   iNeedAllocSize = iSizeDec + iSizeEnc + (iUnit2Size << 1);
1302 
1303   pBase = (uint8_t*)pMa->WelsMallocz (iNeedAllocSize, "pBase");
1304   if (NULL == pBase) {
1305     return 1;
1306   }
1307 
1308   pBaseDec = pBase;                     // iCountLayersNeedCs
1309   pBaseEnc = pBaseDec + iSizeDec;       // iNumSpatialLayers
1310   pBaseMbX = pBaseEnc + iSizeEnc;       // iNumSpatialLayers
1311   pBaseMbY = pBaseMbX + iUnit2Size;     // iNumSpatialLayers
1312 
1313   iTemporalIdx = 0;
1314   while (iTemporalIdx < iCntTid) {
1315     const bool kbBaseTemporalFlag = (iTemporalIdx == 0);
1316 
1317     iSpatialIdx = 0;
1318     while (iSpatialIdx < iCountLayersNeedCs[kbBaseTemporalFlag]) {
1319       const int32_t kiActualSpatialIdx = iMapSpatialIdx[iSpatialIdx][kbBaseTemporalFlag];
1320       const int32_t kiLumaWidth        = iLineSizeY[kiActualSpatialIdx][kbBaseTemporalFlag];
1321       const int32_t kiChromaWidth      = iLineSizeUV[kiActualSpatialIdx][kbBaseTemporalFlag];
1322 
1323       WelsGetEncBlockStrideOffset ((int32_t*)pBaseDec, kiLumaWidth, kiChromaWidth);
1324 
1325       pPtr->pStrideDecBlockOffset[kiActualSpatialIdx][kbBaseTemporalFlag] = (int32_t*)pBaseDec;
1326       pBaseDec += kiUnit1Size;
1327 
1328       ++ iSpatialIdx;
1329     }
1330     ++ iTemporalIdx;
1331   }
1332   iTemporalIdx = 0;
1333   while (iTemporalIdx < iCntTid) {
1334     const bool kbBaseTemporalFlag = (iTemporalIdx == 0);
1335 
1336     iSpatialIdx = 0;
1337     while (iSpatialIdx < kiNumSpatialLayers) {
1338       int32_t iMatchIndex = 0;
1339       bool bInMap = false;
1340       bool bMatchFlag = false;
1341 
1342       i = 0;
1343       while (i < iCountLayersNeedCs[kbBaseTemporalFlag]) {
1344         const int32_t kiActualIdx = iMapSpatialIdx[i][kbBaseTemporalFlag];
1345         if (kiActualIdx == iSpatialIdx) {
1346           bInMap = true;
1347           break;
1348         }
1349         if (!bMatchFlag) {
1350           iMatchIndex = kiActualIdx;
1351           bMatchFlag = true;
1352         }
1353         ++ i;
1354       }
1355 
1356       if (bInMap) {
1357         ++ iSpatialIdx;
1358         continue;
1359       }
1360 
1361       // not in spatial map and assign match one to it
1362       pPtr->pStrideDecBlockOffset[iSpatialIdx][kbBaseTemporalFlag] =
1363         pPtr->pStrideDecBlockOffset[iMatchIndex][kbBaseTemporalFlag];
1364 
1365       ++ iSpatialIdx;
1366     }
1367     ++ iTemporalIdx;
1368   }
1369 
1370   iSpatialIdx = 0;
1371   while (iSpatialIdx < kiNumSpatialLayers) {
1372     const int32_t kiAllocMbSize = sMbSizeMap[iSpatialIdx].iSizeAllMbAlignCache;
1373 
1374     pPtr->pStrideEncBlockOffset[iSpatialIdx]    = (int32_t*)pBaseEnc;
1375 
1376     pPtr->pMbIndexX[iSpatialIdx]                = (int16_t*)pBaseMbX;
1377     pPtr->pMbIndexY[iSpatialIdx]                = (int16_t*)pBaseMbY;
1378 
1379     pBaseEnc += kiUnit1Size;
1380     pBaseMbX += kiAllocMbSize;
1381     pBaseMbY += kiAllocMbSize;
1382 
1383     ++ iSpatialIdx;
1384   }
1385 
1386   while (iSpatialIdx < MAX_DEPENDENCY_LAYER) {
1387     pPtr->pStrideDecBlockOffset[iSpatialIdx][0] = NULL;
1388     pPtr->pStrideDecBlockOffset[iSpatialIdx][1] = NULL;
1389     pPtr->pStrideEncBlockOffset[iSpatialIdx]    = NULL;
1390     pPtr->pMbIndexX[iSpatialIdx]                = NULL;
1391     pPtr->pMbIndexY[iSpatialIdx]                = NULL;
1392 
1393     ++ iSpatialIdx;
1394   }
1395 
1396   // initialize pMbIndexX and pMbIndexY tables as below
1397 
1398   iMaxMbWidth   = sMbSizeMap[kiNumSpatialLayers - 1].iMbWidth;
1399   iMaxMbWidth   = WELS_ALIGN (iMaxMbWidth, 4);  // 4 loops for int16_t required introduced as below
1400   iRowSize      = iMaxMbWidth * sizeof (int16_t);
1401 
1402   pTmpRow = (int16_t*)pMa->WelsMallocz (iRowSize, "pTmpRow");
1403   if (NULL == pTmpRow) {
1404     return 1;
1405   }
1406   pRowX = pTmpRow;
1407   pRowY = pRowX;
1408   // initialize pRowX & pRowY
1409   i = 0;
1410   p = pRowX;
1411   while (i < iMaxMbWidth) {
1412     *p          = i;
1413     * (p + 1)   = 1 + i;
1414     * (p + 2)   = 2 + i;
1415     * (p + 3)   = 3 + i;
1416 
1417     p += 4;
1418     i += 4;
1419   }
1420 
1421   iSpatialIdx = kiNumSpatialLayers;
1422   while (--iSpatialIdx >= 0) {
1423     int16_t* pMbIndexX = pPtr->pMbIndexX[iSpatialIdx];
1424     const int32_t kiMbWidth     = sMbSizeMap[iSpatialIdx].iMbWidth;
1425     const int32_t kiMbHeight    = sMbSizeMap[iSpatialIdx].iCountMbNum / kiMbWidth;
1426     const int32_t kiLineSize    = kiMbWidth * sizeof (int16_t);
1427 
1428     i = 0;
1429     while (i < kiMbHeight) {
1430       memcpy (pMbIndexX, pRowX, kiLineSize); // confirmed_safe_unsafe_usage
1431 
1432       pMbIndexX += kiMbWidth;
1433       ++ i;
1434     }
1435   }
1436 
1437   memset (pRowY, 0, iRowSize);
1438   iMaxMbHeight = sMbSizeMap[kiNumSpatialLayers - 1].iCountMbNum / sMbSizeMap[kiNumSpatialLayers - 1].iMbWidth;
1439   i = 0;
1440   for (;;) {
1441     ENFORCE_STACK_ALIGN_1D (int16_t, t, 4, 16)
1442 
1443     int32_t t32 = 0;
1444     int16_t j = 0;
1445 
1446     for (iSpatialIdx = kiNumSpatialLayers - 1; iSpatialIdx >= 0; -- iSpatialIdx) {
1447       const int32_t kiMbWidth  = sMbSizeMap[iSpatialIdx].iMbWidth;
1448       const int32_t kiMbHeight = sMbSizeMap[iSpatialIdx].iCountMbNum / kiMbWidth;
1449       const int32_t kiLineSize = kiMbWidth * sizeof (int16_t);
1450       int16_t* pMbIndexY = pPtr->pMbIndexY[iSpatialIdx] + i * kiMbWidth;
1451 
1452       if (i < kiMbHeight) {
1453         memcpy (pMbIndexY, pRowY, kiLineSize); // confirmed_safe_unsafe_usage
1454       }
1455     }
1456     ++ i;
1457     if (i >= iMaxMbHeight)
1458       break;
1459 
1460     t32 = i | (i << 16);
1461     ST32 (t, t32);
1462     ST32 (t + 2, t32);
1463 
1464     p = pRowY;
1465     while (j < iMaxMbWidth) {
1466       ST64 (p, LD64 (t));
1467 
1468       p += 4;
1469       j += 4;
1470     }
1471   }
1472 
1473   pMa->WelsFree (pTmpRow, "pTmpRow");
1474   pTmpRow = NULL;
1475 
1476   return 0;
1477 }
RequestMemoryVaaScreen(SVAAFrameInfo * pVaa,CMemoryAlign * pMa,const int32_t iNumRef,const int32_t iCountMax8x8BNum)1478 int32_t RequestMemoryVaaScreen (SVAAFrameInfo* pVaa,  CMemoryAlign* pMa,  const int32_t iNumRef,
1479                                 const int32_t iCountMax8x8BNum) {
1480   SVAAFrameInfoExt* pVaaExt = static_cast<SVAAFrameInfoExt*> (pVaa);
1481 
1482   pVaaExt->pVaaBlockStaticIdc[0] = (static_cast<uint8_t*> (pMa->WelsMallocz (iNumRef * iCountMax8x8BNum * sizeof (
1483                                       uint8_t), "pVaa->pVaaBlockStaticIdc[0]")));
1484   if (NULL == pVaaExt->pVaaBlockStaticIdc[0]) {
1485     return 1;
1486   }
1487 
1488   for (int32_t idx = 1; idx < iNumRef; idx++) {
1489     pVaaExt->pVaaBlockStaticIdc[idx] = pVaaExt->pVaaBlockStaticIdc[idx - 1] + iCountMax8x8BNum;
1490   }
1491   return 0;
1492 }
ReleaseMemoryVaaScreen(SVAAFrameInfo * pVaa,CMemoryAlign * pMa,const int32_t iNumRef)1493 void ReleaseMemoryVaaScreen (SVAAFrameInfo* pVaa,  CMemoryAlign* pMa, const int32_t iNumRef) {
1494   SVAAFrameInfoExt* pVaaExt = static_cast<SVAAFrameInfoExt*> (pVaa);
1495   if (pVaaExt && pMa && pVaaExt->pVaaBlockStaticIdc[0]) {
1496     pMa->WelsFree (pVaaExt->pVaaBlockStaticIdc[0], "pVaa->pVaaBlockStaticIdc[0]");
1497 
1498     for (int32_t idx = 0; idx < iNumRef; idx++) {
1499       pVaaExt->pVaaBlockStaticIdc[idx] = NULL;
1500     }
1501   }
1502 }
1503 /*!
1504  * \brief   request specific memory for SVC
1505  * \pParam  pEncCtx     sWelsEncCtx*
1506  * \return  successful - 0; otherwise none 0 for failed
1507  */
GetMvMvdRange(SWelsSvcCodingParam * pParam,int32_t & iMvRange,int32_t & iMvdRange)1508 void GetMvMvdRange (SWelsSvcCodingParam* pParam, int32_t& iMvRange, int32_t& iMvdRange) {
1509   ELevelIdc iMinLevelIdc = LEVEL_5_2;
1510   int32_t iMinMv = 0;
1511   int32_t iMaxMv = 0;
1512   int32_t iFixMvRange = pParam->iUsageType ? EXPANDED_MV_RANGE : CAMERA_STARTMV_RANGE;
1513   int32_t iFixMvdRange = (pParam->iUsageType ? EXPANDED_MVD_RANGE : ((pParam->iSpatialLayerNum == 1) ? CAMERA_MVD_RANGE :
1514                           CAMERA_HIGHLAYER_MVD_RANGE));
1515   for (int32_t iLayer = 0; iLayer < pParam->iSpatialLayerNum; iLayer++) {
1516     if (pParam->sSpatialLayers[iLayer].uiLevelIdc < iMinLevelIdc)
1517       iMinLevelIdc = pParam->sSpatialLayers[iLayer].uiLevelIdc;
1518   }
1519   const SLevelLimits* pLevelLimit = g_ksLevelLimits;
1520   while ((pLevelLimit->uiLevelIdc != LEVEL_5_2) && (pLevelLimit->uiLevelIdc != iMinLevelIdc))
1521     pLevelLimit++;
1522   iMinMv = (pLevelLimit->iMinVmv) >> 2;
1523   iMaxMv = (pLevelLimit->iMaxVmv) >> 2;
1524 
1525   iMvRange = WELS_MIN (WELS_ABS (iMinMv), iMaxMv);
1526 
1527   iMvRange = WELS_MIN (iMvRange, iFixMvRange);
1528 
1529   iMvdRange = (iMvRange + 1) << 1;
1530 
1531   iMvdRange = WELS_MIN (iMvdRange, iFixMvdRange);
1532 }
RequestMemorySvc(sWelsEncCtx ** ppCtx,SExistingParasetList * pExistingParasetList)1533 int32_t RequestMemorySvc (sWelsEncCtx** ppCtx, SExistingParasetList* pExistingParasetList) {
1534   SWelsSvcCodingParam* pParam           = (*ppCtx)->pSvcParam;
1535   CMemoryAlign* pMa                     = (*ppCtx)->pMemAlign;
1536   SSpatialLayerConfig* pFinalSpatial    = NULL;
1537   int32_t iCountBsLen                   = 0;
1538   int32_t iCountNals                    = 0;
1539   int32_t iMaxPicWidth                  = 0;
1540   int32_t iMaxPicHeight                 = 0;
1541   int32_t iCountMaxMbNum                = 0;
1542   int32_t iIndex                        = 0;
1543   int32_t iCountLayers                  = 0;
1544   int32_t iResult                       = 0;
1545   float fCompressRatioThr               = .5f;
1546   const int32_t kiNumDependencyLayers   = pParam->iSpatialLayerNum;
1547   int32_t iVclLayersBsSizeCount         = 0;
1548   int32_t iNonVclLayersBsSizeCount      = 0;
1549   int32_t iTargetSpatialBsSize          = 0;
1550 
1551   if (kiNumDependencyLayers < 1 || kiNumDependencyLayers > MAX_DEPENDENCY_LAYER) {
1552     WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_WARNING, "RequestMemorySvc() failed due to invalid iNumDependencyLayers(%d)!",
1553              kiNumDependencyLayers);
1554     return 1;
1555   }
1556 
1557   if (pParam->uiGopSize == 0 || (pParam->uiIntraPeriod && ((pParam->uiIntraPeriod % pParam->uiGopSize) != 0))) {
1558     WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_WARNING,
1559              "RequestMemorySvc() failed due to invalid uiIntraPeriod(%d) (=multipler of uiGopSize(%d)!",
1560              pParam->uiIntraPeriod, pParam->uiGopSize);
1561     return 1;
1562   }
1563 
1564   pFinalSpatial = &pParam->sSpatialLayers[kiNumDependencyLayers - 1];
1565   iMaxPicWidth  = pFinalSpatial->iVideoWidth;
1566   iMaxPicHeight = pFinalSpatial->iVideoHeight;
1567   iCountMaxMbNum = ((15 + iMaxPicWidth) >> 4) * ((15 + iMaxPicHeight) >> 4);
1568 
1569   iResult = AcquireLayersNals (ppCtx, pParam, &iCountLayers, &iCountNals);
1570   if (iResult) {
1571     WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_WARNING, "RequestMemorySvc(), AcquireLayersNals failed(%d)!", iResult);
1572     return 1;
1573   }
1574 
1575   const int32_t kiSpsSize = (*ppCtx)->pFuncList->pParametersetStrategy->GetNeededSpsNum() * SPS_BUFFER_SIZE;
1576   const int32_t kiPpsSize = (*ppCtx)->pFuncList->pParametersetStrategy->GetNeededPpsNum() * PPS_BUFFER_SIZE;
1577   iNonVclLayersBsSizeCount = SSEI_BUFFER_SIZE + kiSpsSize + kiPpsSize;
1578 
1579   bool    bDynamicSlice = false;
1580   uint32_t uiMaxSliceNumEstimation = 0;
1581   int32_t iSliceBufferSize = 0;
1582   int32_t iMaxSliceBufferSize = 0;
1583   int32_t iTotalLength = 0;
1584   int32_t iLayerBsSize = 0;
1585   iIndex = 0;
1586   while (iIndex < pParam->iSpatialLayerNum) {
1587     SSpatialLayerConfig* fDlp = &pParam->sSpatialLayers[iIndex];
1588 
1589     fCompressRatioThr = COMPRESS_RATIO_THR;
1590 
1591     iLayerBsSize = WELS_ROUND (((3 * fDlp->iVideoWidth * fDlp->iVideoHeight) >> 1) * fCompressRatioThr) +
1592                    MAX_MACROBLOCK_SIZE_IN_BYTE_x2;
1593     iLayerBsSize = WELS_ALIGN (iLayerBsSize, 4); // 4 bytes alinged
1594     iVclLayersBsSizeCount += iLayerBsSize;
1595 
1596     SSliceArgument* pSliceArgument = & (fDlp->sSliceArgument);
1597     if (pSliceArgument->uiSliceMode == SM_SIZELIMITED_SLICE) {
1598       bDynamicSlice = true;
1599       uiMaxSliceNumEstimation = WELS_MIN (AVERSLICENUM_CONSTRAINT,
1600                                           (iLayerBsSize / pSliceArgument->uiSliceSizeConstraint) + 1);
1601       (*ppCtx)->iMaxSliceCount = WELS_MAX ((*ppCtx)->iMaxSliceCount, (int) uiMaxSliceNumEstimation);
1602       iSliceBufferSize = (WELS_MAX (pSliceArgument->uiSliceSizeConstraint,
1603                                     iLayerBsSize / uiMaxSliceNumEstimation) << 1) + MAX_MACROBLOCK_SIZE_IN_BYTE_x2;
1604     } else {
1605       (*ppCtx)->iMaxSliceCount = WELS_MAX ((*ppCtx)->iMaxSliceCount, (int) pSliceArgument->uiSliceNum);
1606       iSliceBufferSize = ((iLayerBsSize / pSliceArgument->uiSliceNum) << 1) + MAX_MACROBLOCK_SIZE_IN_BYTE_x2;
1607     }
1608     iMaxSliceBufferSize                = WELS_MAX (iMaxSliceBufferSize, iSliceBufferSize);
1609     (*ppCtx)->iSliceBufferSize[iIndex] = iSliceBufferSize;
1610     ++ iIndex;
1611   }
1612   iTargetSpatialBsSize = iLayerBsSize;
1613   iCountBsLen = iNonVclLayersBsSizeCount + iVclLayersBsSizeCount;
1614 
1615   iMaxSliceBufferSize = WELS_MIN (iMaxSliceBufferSize, iTargetSpatialBsSize);
1616   iTotalLength = iCountBsLen;
1617 
1618   pParam->iNumRefFrame = WELS_CLIP3 (pParam->iNumRefFrame, MIN_REF_PIC_COUNT,
1619                                      (pParam->iUsageType == CAMERA_VIDEO_REAL_TIME ? MAX_REFERENCE_PICTURE_COUNT_NUM_CAMERA :
1620                                       MAX_REFERENCE_PICTURE_COUNT_NUM_SCREEN));
1621 
1622   // Output
1623   (*ppCtx)->pOut = (SWelsEncoderOutput*)pMa->WelsMallocz (sizeof (SWelsEncoderOutput), "SWelsEncoderOutput");
1624   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pOut))
1625   (*ppCtx)->pOut->pBsBuffer = (uint8_t*)pMa->WelsMallocz (iCountBsLen, "pOut->pBsBuffer");
1626   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pOut->pBsBuffer))
1627   (*ppCtx)->pOut->uiSize = iCountBsLen;
1628   (*ppCtx)->pOut->sNalList = (SWelsNalRaw*)pMa->WelsMallocz (iCountNals * sizeof (SWelsNalRaw), "pOut->sNalList");
1629   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pOut->sNalList))
1630   (*ppCtx)->pOut->pNalLen = (int32_t*)pMa->WelsMallocz (iCountNals * sizeof (int32_t), "pOut->pNalLen");
1631   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pOut->pNalLen))
1632   (*ppCtx)->pOut->iCountNals    = iCountNals;
1633   (*ppCtx)->pOut->iNalIndex     = 0;
1634   (*ppCtx)->pOut->iLayerBsIndex = 0;
1635 
1636   (*ppCtx)->pFrameBs = (uint8_t*)pMa->WelsMalloc (iTotalLength, "pFrameBs");
1637   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pFrameBs))
1638   (*ppCtx)->iFrameBsSize = iTotalLength;
1639   (*ppCtx)->iPosBsBuffer = 0;
1640 
1641   // for dynamic slice mode&& CABAC,allocate slice buffer to restore slice data
1642   if (bDynamicSlice && pParam->iEntropyCodingModeFlag) {
1643     for (int32_t iIdx = 0; iIdx < MAX_THREADS_NUM; iIdx++) {
1644       (*ppCtx)->pDynamicBsBuffer[iIdx] = (uint8_t*)pMa->WelsMalloc (iMaxSliceBufferSize, "DynamicSliceBs");
1645       WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pDynamicBsBuffer[iIdx]))
1646     }
1647   }
1648   // for pSlice bs buffers
1649   if (pParam->iMultipleThreadIdc > 1
1650       && RequestMtResource (ppCtx, pParam, iCountBsLen, iMaxSliceBufferSize, bDynamicSlice)) {
1651     WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_WARNING, "RequestMemorySvc(), RequestMtResource failed!");
1652     return 1;
1653   }
1654 
1655   (*ppCtx)->pReferenceStrategy = IWelsReferenceStrategy::CreateReferenceStrategy ((*ppCtx), pParam->iUsageType,
1656                                  pParam->bEnableLongTermReference);
1657   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pReferenceStrategy))
1658 
1659   (*ppCtx)->pIntra4x4PredModeBlocks = static_cast<int8_t*>
1660                                       (pMa->WelsMallocz (iCountMaxMbNum * INTRA_4x4_MODE_NUM, "pIntra4x4PredModeBlocks"));
1661   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pIntra4x4PredModeBlocks))
1662 
1663   (*ppCtx)->pNonZeroCountBlocks = static_cast<int8_t*>
1664                                   (pMa->WelsMallocz (iCountMaxMbNum * MB_LUMA_CHROMA_BLOCK4x4_NUM, "pNonZeroCountBlocks"));
1665   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pNonZeroCountBlocks))
1666 
1667   (*ppCtx)->pMvUnitBlock4x4 = static_cast<SMVUnitXY*>
1668                               (pMa->WelsMallocz (iCountMaxMbNum * 2 * MB_BLOCK4x4_NUM * sizeof (SMVUnitXY), "pMvUnitBlock4x4"));
1669   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pMvUnitBlock4x4))
1670 
1671   (*ppCtx)->pRefIndexBlock4x4 = static_cast<int8_t*>
1672                                 (pMa->WelsMallocz (iCountMaxMbNum * 2 * MB_BLOCK8x8_NUM * sizeof (int8_t), "pRefIndexBlock4x4"));
1673   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pRefIndexBlock4x4))
1674 
1675   (*ppCtx)->pSadCostMb = static_cast<int32_t*>
1676                          (pMa->WelsMallocz (iCountMaxMbNum * sizeof (int32_t), "pSadCostMb"));
1677   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pSadCostMb))
1678 
1679   (*ppCtx)->iGlobalQp = 26;   // global qp in default
1680 
1681   (*ppCtx)->pLtr = (SLTRState*)pMa->WelsMallocz (kiNumDependencyLayers * sizeof (SLTRState), "SLTRState");
1682   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pLtr))
1683   int32_t i = 0;
1684   for (i = 0; i < kiNumDependencyLayers; i++) {
1685     ResetLtrState (& (*ppCtx)->pLtr[i]);
1686   }
1687 
1688   // stride tables
1689   if (AllocStrideTables (ppCtx, kiNumDependencyLayers)) {
1690     WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_WARNING, "RequestMemorySvc(), AllocStrideTables failed!");
1691     return 1;
1692   }
1693 
1694   //Rate control module memory allocation
1695   // only malloc once for RC pData, 12/14/2009
1696   (*ppCtx)->pWelsSvcRc = (SWelsSvcRc*)pMa->WelsMallocz (kiNumDependencyLayers * sizeof (SWelsSvcRc), "pWelsSvcRc");
1697   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pWelsSvcRc))
1698   //End of Rate control module memory allocation
1699 
1700   //pVaa memory allocation
1701   if (pParam->iUsageType == SCREEN_CONTENT_REAL_TIME) {
1702     (*ppCtx)->pVaa = (SVAAFrameInfoExt*)pMa->WelsMallocz (sizeof (SVAAFrameInfoExt), "pVaa");
1703     WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pVaa))
1704     if (RequestMemoryVaaScreen ((*ppCtx)->pVaa, pMa, (*ppCtx)->pSvcParam->iMaxNumRefFrame, iCountMaxMbNum << 2)) {
1705       WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_WARNING, "RequestMemorySvc(), RequestMemoryVaaScreen failed!");
1706       return 1;
1707     }
1708   } else {
1709     (*ppCtx)->pVaa = (SVAAFrameInfo*)pMa->WelsMallocz (sizeof (SVAAFrameInfo), "pVaa");
1710     WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pVaa))
1711   }
1712 
1713   if ((*ppCtx)->pSvcParam->bEnableAdaptiveQuant) { //malloc mem
1714     (*ppCtx)->pVaa->sAdaptiveQuantParam.pMotionTextureUnit   = static_cast<SMotionTextureUnit*>
1715         (pMa->WelsMallocz (iCountMaxMbNum * sizeof (SMotionTextureUnit), "pVaa->sAdaptiveQuantParam.pMotionTextureUnit"));
1716     WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pVaa->sAdaptiveQuantParam.pMotionTextureUnit))
1717     (*ppCtx)->pVaa->sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp   = static_cast<int8_t*>
1718         (pMa->WelsMallocz (iCountMaxMbNum * sizeof (int8_t), "pVaa->sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp"));
1719     WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pVaa->sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp))
1720   }
1721 
1722   (*ppCtx)->pVaa->pVaaBackgroundMbFlag = (int8_t*)pMa->WelsMallocz (iCountMaxMbNum * sizeof (int8_t),
1723                                          "pVaa->pVaaBackgroundMbFlag");
1724   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pVaa->pVaaBackgroundMbFlag))
1725 
1726   (*ppCtx)->pVaa->sVaaCalcInfo.pSad8x8 = static_cast<int32_t (*)[4]>
1727                                          (pMa->WelsMallocz (iCountMaxMbNum * 4 * sizeof (int32_t), "pVaa->sVaaCalcInfo.sad8x8"));
1728   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pVaa->sVaaCalcInfo.pSad8x8))
1729   (*ppCtx)->pVaa->sVaaCalcInfo.pSsd16x16 = static_cast<int32_t*>
1730       (pMa->WelsMallocz (iCountMaxMbNum * sizeof (int32_t), "pVaa->sVaaCalcInfo.pSsd16x16"));
1731   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pVaa->sVaaCalcInfo.pSsd16x16))
1732   (*ppCtx)->pVaa->sVaaCalcInfo.pSum16x16 = static_cast<int32_t*>
1733       (pMa->WelsMallocz (iCountMaxMbNum * sizeof (int32_t), "pVaa->sVaaCalcInfo.pSum16x16"));
1734   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pVaa->sVaaCalcInfo.pSum16x16))
1735   (*ppCtx)->pVaa->sVaaCalcInfo.pSumOfSquare16x16 = static_cast<int32_t*>
1736       (pMa->WelsMallocz (iCountMaxMbNum * sizeof (int32_t), "pVaa->sVaaCalcInfo.pSumOfSquare16x16"));
1737   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pVaa->sVaaCalcInfo.pSumOfSquare16x16))
1738 
1739   if ((*ppCtx)->pSvcParam->bEnableBackgroundDetection) { //BGD control
1740     (*ppCtx)->pVaa->sVaaCalcInfo.pSumOfDiff8x8 = static_cast<int32_t (*)[4]>
1741         (pMa->WelsMallocz (iCountMaxMbNum * 4 * sizeof (int32_t), "pVaa->sVaaCalcInfo.pSumOfDiff8x8"));
1742     WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pVaa->sVaaCalcInfo.pSumOfDiff8x8))
1743     (*ppCtx)->pVaa->sVaaCalcInfo.pMad8x8 = static_cast<uint8_t (*)[4]>
1744                                            (pMa->WelsMallocz (iCountMaxMbNum * 4 * sizeof (uint8_t), "pVaa->sVaaCalcInfo.pMad8x8"));
1745     WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pVaa->sVaaCalcInfo.pMad8x8))
1746   }
1747 
1748   //End of pVaa memory allocation
1749 
1750   (*ppCtx)->ppRefPicListExt = (SRefList**)pMa->WelsMallocz (kiNumDependencyLayers * sizeof (SRefList*),
1751                               "ppRefPicListExt");
1752   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->ppRefPicListExt))
1753 
1754   (*ppCtx)->ppDqLayerList = (SDqLayer**)pMa->WelsMallocz (kiNumDependencyLayers * sizeof (SDqLayer*), "ppDqLayerList");
1755   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->ppDqLayerList))
1756 
1757   iResult = InitDqLayers (ppCtx, pExistingParasetList);
1758   if (iResult) {
1759     WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_WARNING, "RequestMemorySvc(), InitDqLayers failed(%d)!", iResult);
1760     return iResult;
1761   }
1762 
1763   if (InitMbListD (ppCtx)) {
1764     WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_WARNING, "RequestMemorySvc(), InitMbListD failed!");
1765     return 1;
1766   }
1767 
1768   int32_t iMvdRange = 0;
1769   GetMvMvdRange (pParam, (*ppCtx)->iMvRange, iMvdRange);
1770   const uint32_t kuiMvdInterTableSize   = (iMvdRange << 2); //intepel*4=qpel
1771   const uint32_t kuiMvdInterTableStride =  1 + (kuiMvdInterTableSize << 1);//qpel_mv_range*2=(+/-);
1772   const uint32_t kuiMvdCacheAlignedSize = kuiMvdInterTableStride * sizeof (uint16_t);
1773 
1774   (*ppCtx)->iMvdCostTableSize = kuiMvdInterTableSize;
1775   (*ppCtx)->iMvdCostTableStride = kuiMvdInterTableStride;
1776   (*ppCtx)->pMvdCostTable = (uint16_t*)pMa->WelsMallocz (52 * kuiMvdCacheAlignedSize, "pMvdCostTable");
1777   WELS_VERIFY_RETURN_IF (1, (NULL == (*ppCtx)->pMvdCostTable))
1778   MvdCostInit ((*ppCtx)->pMvdCostTable, kuiMvdInterTableStride);  //should put to a better place?
1779 
1780   if ((*ppCtx)->ppRefPicListExt[0] != NULL && (*ppCtx)->ppRefPicListExt[0]->pRef[0] != NULL)
1781     (*ppCtx)->pDecPic = (*ppCtx)->ppRefPicListExt[0]->pRef[0];
1782   else
1783     (*ppCtx)->pDecPic = NULL; // error here
1784 
1785   (*ppCtx)->pSps = & (*ppCtx)->pSpsArray[0];
1786   (*ppCtx)->pPps = & (*ppCtx)->pPPSArray[0];
1787 
1788   return 0;
1789 }
1790 
1791 
1792 /*!
1793  * \brief   free memory in SVC core encoder
1794  * \pParam  pEncCtx     sWelsEncCtx*
1795  * \return  none
1796  */
FreeMemorySvc(sWelsEncCtx ** ppCtx)1797 void FreeMemorySvc (sWelsEncCtx** ppCtx) {
1798   if (NULL != *ppCtx) {
1799     sWelsEncCtx* pCtx = *ppCtx;
1800     CMemoryAlign* pMa = pCtx->pMemAlign;
1801     SWelsSvcCodingParam* pParam = pCtx->pSvcParam;
1802     int32_t ilayer = 0;
1803 
1804     // SStrideTables
1805     if (NULL != pCtx->pStrideTab) {
1806       if (NULL != pCtx->pStrideTab->pStrideDecBlockOffset[0][1]) {
1807         pMa->WelsFree (pCtx->pStrideTab->pStrideDecBlockOffset[0][1], "pBase");
1808         pCtx->pStrideTab->pStrideDecBlockOffset[0][1] = NULL;
1809       }
1810       pMa->WelsFree (pCtx->pStrideTab, "SStrideTables");
1811       pCtx->pStrideTab = NULL;
1812     }
1813     // pDq idc map
1814     if (NULL != pCtx->pDqIdcMap) {
1815       pMa->WelsFree (pCtx->pDqIdcMap, "pDqIdcMap");
1816       pCtx->pDqIdcMap = NULL;
1817     }
1818 
1819     if (NULL != pCtx->pOut) {
1820       // bs pBuffer
1821       if (NULL != pCtx->pOut->pBsBuffer) {
1822         pMa->WelsFree (pCtx->pOut->pBsBuffer, "pOut->pBsBuffer");
1823         pCtx->pOut->pBsBuffer = NULL;
1824       }
1825       // NALs list
1826       if (NULL != pCtx->pOut->sNalList) {
1827         pMa->WelsFree (pCtx->pOut->sNalList, "pOut->sNalList");
1828         pCtx->pOut->sNalList = NULL;
1829       }
1830       // NALs len
1831       if (NULL != pCtx->pOut->pNalLen) {
1832         pMa->WelsFree (pCtx->pOut->pNalLen, "pOut->pNalLen");
1833         pCtx->pOut->pNalLen = NULL;
1834       }
1835       pMa->WelsFree (pCtx->pOut, "SWelsEncoderOutput");
1836       pCtx->pOut = NULL;
1837     }
1838 
1839     if (pParam != NULL && pParam->iMultipleThreadIdc > 1)
1840       ReleaseMtResource (ppCtx);
1841 
1842     if (NULL != pCtx->pReferenceStrategy) {
1843       WELS_DELETE_OP (pCtx->pReferenceStrategy);
1844     }
1845 
1846     // frame bitstream pBuffer
1847     if (NULL != pCtx->pFrameBs) {
1848       pMa->WelsFree (pCtx->pFrameBs, "pFrameBs");
1849       pCtx->pFrameBs = NULL;
1850     }
1851     for (int32_t iIdx = 0; iIdx < MAX_THREADS_NUM; iIdx++) {
1852       pMa->WelsFree (pCtx->pDynamicBsBuffer[iIdx], "DynamicSliceBs");
1853       pCtx->pDynamicBsBuffer[iIdx] = NULL;
1854 
1855     }
1856     // pSpsArray
1857     if (NULL != pCtx->pSpsArray) {
1858       pMa->WelsFree (pCtx->pSpsArray, "pSpsArray");
1859       pCtx->pSpsArray = NULL;
1860     }
1861     // pPPSArray
1862     if (NULL != pCtx->pPPSArray) {
1863       pMa->WelsFree (pCtx->pPPSArray, "pPPSArray");
1864       pCtx->pPPSArray = NULL;
1865     }
1866     // subset_sps_array
1867     if (NULL != pCtx->pSubsetArray) {
1868       pMa->WelsFree (pCtx->pSubsetArray, "pSubsetArray");
1869       pCtx->pSubsetArray = NULL;
1870     }
1871 
1872     if (NULL != pCtx->pIntra4x4PredModeBlocks) {
1873       pMa->WelsFree (pCtx->pIntra4x4PredModeBlocks, "pIntra4x4PredModeBlocks");
1874       pCtx->pIntra4x4PredModeBlocks = NULL;
1875     }
1876 
1877     if (NULL != pCtx->pNonZeroCountBlocks) {
1878       pMa->WelsFree (pCtx->pNonZeroCountBlocks, "pNonZeroCountBlocks");
1879       pCtx->pNonZeroCountBlocks = NULL;
1880     }
1881 
1882     if (NULL != pCtx->pMvUnitBlock4x4) {
1883       pMa->WelsFree (pCtx->pMvUnitBlock4x4, "pMvUnitBlock4x4");
1884       pCtx->pMvUnitBlock4x4 = NULL;
1885     }
1886 
1887     if (NULL != pCtx->pRefIndexBlock4x4) {
1888       pMa->WelsFree (pCtx->pRefIndexBlock4x4, "pRefIndexBlock4x4");
1889       pCtx->pRefIndexBlock4x4 = NULL;
1890     }
1891 
1892     if (NULL != pCtx->ppMbListD) {
1893       if (NULL != pCtx->ppMbListD[0]) {
1894         pMa->WelsFree (pCtx->ppMbListD[0], "ppMbListD[0]");
1895         (*ppCtx)->ppMbListD[0] = NULL;
1896       }
1897       pMa->WelsFree (pCtx->ppMbListD, "ppMbListD");
1898       pCtx->ppMbListD = NULL;
1899     }
1900 
1901     if (NULL != pCtx->pSadCostMb) {
1902       pMa->WelsFree (pCtx->pSadCostMb, "pSadCostMb");
1903       pCtx->pSadCostMb = NULL;
1904     }
1905 
1906     // SLTRState
1907     if (NULL != pCtx->pLtr) {
1908       pMa->WelsFree (pCtx->pLtr, "SLTRState");
1909       pCtx->pLtr = NULL;
1910     }
1911 
1912     // pDq layers list
1913     ilayer = 0;
1914     if (NULL != pCtx->ppDqLayerList && pParam != NULL) {
1915       while (ilayer < pParam->iSpatialLayerNum) {
1916         SDqLayer* pDq = pCtx->ppDqLayerList[ilayer];
1917         // pDq layers
1918         if (NULL != pDq) {
1919           FreeDqLayer (pDq, pMa);
1920           pCtx->ppDqLayerList[ilayer] = NULL;
1921         }
1922         ++ ilayer;
1923       }
1924       pMa->WelsFree (pCtx->ppDqLayerList, "ppDqLayerList");
1925       pCtx->ppDqLayerList = NULL;
1926     }
1927     // reference picture list extension
1928     if (NULL != pCtx->ppRefPicListExt && pParam != NULL) {
1929       ilayer = 0;
1930       while (ilayer < pParam->iSpatialLayerNum) {
1931         FreeRefList (pCtx->ppRefPicListExt[ilayer], pMa, pParam->iMaxNumRefFrame);
1932         pCtx->ppRefPicListExt[ilayer] = NULL;
1933         ++ ilayer;
1934       }
1935 
1936       pMa->WelsFree (pCtx->ppRefPicListExt, "ppRefPicListExt");
1937       pCtx->ppRefPicListExt = NULL;
1938     }
1939 
1940     // VAA
1941     if (NULL != pCtx->pVaa) {
1942       if (pCtx->pSvcParam->bEnableAdaptiveQuant) { //free mem
1943         pMa->WelsFree (pCtx->pVaa->sAdaptiveQuantParam.pMotionTextureUnit, "pVaa->sAdaptiveQuantParam.pMotionTextureUnit");
1944         pCtx->pVaa->sAdaptiveQuantParam.pMotionTextureUnit = NULL;
1945         pMa->WelsFree (pCtx->pVaa->sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp,
1946                        "pVaa->sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp");
1947         pCtx->pVaa->sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp = NULL;
1948       }
1949 
1950       pMa->WelsFree (pCtx->pVaa->pVaaBackgroundMbFlag, "pVaa->pVaaBackgroundMbFlag");
1951       pCtx->pVaa->pVaaBackgroundMbFlag = NULL;
1952       pMa->WelsFree (pCtx->pVaa->sVaaCalcInfo.pSad8x8, "pVaa->sVaaCalcInfo.sad8x8");
1953       pCtx->pVaa->sVaaCalcInfo.pSad8x8 = NULL;
1954       pMa->WelsFree (pCtx->pVaa->sVaaCalcInfo.pSsd16x16, "pVaa->sVaaCalcInfo.pSsd16x16");
1955       pCtx->pVaa->sVaaCalcInfo.pSsd16x16 = NULL;
1956       pMa->WelsFree (pCtx->pVaa->sVaaCalcInfo.pSum16x16, "pVaa->sVaaCalcInfo.pSum16x16");
1957       pCtx->pVaa->sVaaCalcInfo.pSum16x16 = NULL;
1958       pMa->WelsFree (pCtx->pVaa->sVaaCalcInfo.pSumOfSquare16x16, "pVaa->sVaaCalcInfo.pSumOfSquare16x16");
1959       pCtx->pVaa->sVaaCalcInfo.pSumOfSquare16x16 = NULL;
1960 
1961       if (pCtx->pSvcParam->bEnableBackgroundDetection) { //BGD control
1962         pMa->WelsFree (pCtx->pVaa->sVaaCalcInfo.pSumOfDiff8x8, "pVaa->sVaaCalcInfo.pSumOfDiff8x8");
1963         pCtx->pVaa->sVaaCalcInfo.pSumOfDiff8x8 = NULL;
1964         pMa->WelsFree (pCtx->pVaa->sVaaCalcInfo.pMad8x8, "pVaa->sVaaCalcInfo.pMad8x8");
1965         pCtx->pVaa->sVaaCalcInfo.pMad8x8 = NULL;
1966       }
1967       if (pCtx->pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME)
1968         ReleaseMemoryVaaScreen (pCtx->pVaa, pMa, pCtx->pSvcParam->iMaxNumRefFrame);
1969       pMa->WelsFree (pCtx->pVaa, "pVaa");
1970       pCtx->pVaa = NULL;
1971     }
1972 
1973     // rate control module memory free
1974     if (NULL != pCtx->pWelsSvcRc) {
1975       WelsRcFreeMemory (pCtx);
1976       pMa->WelsFree (pCtx->pWelsSvcRc, "pWelsSvcRc");
1977       pCtx->pWelsSvcRc = NULL;
1978     }
1979 
1980     /* MVD cost tables for Inter */
1981     if (NULL != pCtx->pMvdCostTable) {
1982       pMa->WelsFree (pCtx->pMvdCostTable, "pMvdCostTable");
1983       pCtx->pMvdCostTable = NULL;
1984     }
1985 
1986     FreeCodingParam (&pCtx->pSvcParam, pMa);
1987     if (NULL != pCtx->pFuncList) {
1988       if (NULL != pCtx->pFuncList->pParametersetStrategy) {
1989         WELS_DELETE_OP (pCtx->pFuncList->pParametersetStrategy);
1990       }
1991 
1992       pMa->WelsFree (pCtx->pFuncList, "SWelsFuncPtrList");
1993       pCtx->pFuncList = NULL;
1994     }
1995 
1996 #if defined(MEMORY_MONITOR)
1997     assert (pMa->WelsGetMemoryUsage() == 0); // ensure all memory free well
1998 #endif//MEMORY_MONITOR
1999 
2000     if ((*ppCtx)->pMemAlign != NULL) {
2001       WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_INFO, "FreeMemorySvc(), verify memory usage (%d bytes) after free..",
2002                (*ppCtx)->pMemAlign->WelsGetMemoryUsage());
2003       WELS_DELETE_OP ((*ppCtx)->pMemAlign);
2004     }
2005 
2006     free (*ppCtx);
2007     *ppCtx = NULL;
2008   }
2009 }
2010 
InitSliceSettings(SLogContext * pLogCtx,SWelsSvcCodingParam * pCodingParam,const int32_t kiCpuCores,int16_t * pMaxSliceCount)2011 int32_t InitSliceSettings (SLogContext* pLogCtx,     SWelsSvcCodingParam* pCodingParam,
2012                            const int32_t kiCpuCores, int16_t* pMaxSliceCount) {
2013   int32_t iSpatialIdx = 0, iSpatialNum = pCodingParam->iSpatialLayerNum;
2014   uint16_t iMaxSliceCount = 0;
2015 
2016   do {
2017     SSpatialLayerConfig* pDlp           = &pCodingParam->sSpatialLayers[iSpatialIdx];
2018     SSliceArgument* pSliceArgument      = &pDlp->sSliceArgument;
2019     int32_t iReturn                     = 0;
2020 
2021     switch (pSliceArgument->uiSliceMode) {
2022     case SM_SIZELIMITED_SLICE:
2023       iMaxSliceCount = AVERSLICENUM_CONSTRAINT;
2024       break; // go through for SM_SIZELIMITED_SLICE?
2025     case SM_FIXEDSLCNUM_SLICE: {
2026       iReturn = SliceArgumentValidationFixedSliceMode (pLogCtx, &pDlp->sSliceArgument, pCodingParam->iRCMode,
2027                 pDlp->iVideoWidth, pDlp->iVideoHeight);
2028       if (iReturn)
2029         return ENC_RETURN_UNSUPPORTED_PARA;
2030 
2031       if (pSliceArgument->uiSliceNum > iMaxSliceCount) {
2032         iMaxSliceCount = pSliceArgument->uiSliceNum;
2033       }
2034     }
2035     break;
2036     case SM_SINGLE_SLICE:
2037       if (pSliceArgument->uiSliceNum > iMaxSliceCount)
2038         iMaxSliceCount = pSliceArgument->uiSliceNum;
2039       break;
2040     case SM_RASTER_SLICE:
2041       if (pSliceArgument->uiSliceNum > iMaxSliceCount)
2042         iMaxSliceCount = pSliceArgument->uiSliceNum;
2043       break;
2044     default:
2045       break;
2046     }
2047 
2048     ++ iSpatialIdx;
2049   } while (iSpatialIdx < iSpatialNum);
2050 
2051   pCodingParam->iMultipleThreadIdc = WELS_MIN (kiCpuCores, iMaxSliceCount);
2052   if (pCodingParam->iLoopFilterDisableIdc == 0
2053       && pCodingParam->iMultipleThreadIdc != 1) // Loop filter requested to be enabled, with threading enabled
2054     pCodingParam->iLoopFilterDisableIdc =
2055       2; // Disable loop filter on slice boundaries since that's not allowed with multithreading
2056   *pMaxSliceCount = iMaxSliceCount;
2057 
2058   return ENC_RETURN_SUCCESS;
2059 }
2060 
2061 /*!
2062  * \brief   log output for cpu features/capabilities
2063  */
OutputCpuFeaturesLog(SLogContext * pLogCtx,uint32_t uiCpuFeatureFlags,uint32_t uiCpuCores,int32_t iCacheLineSize)2064 void OutputCpuFeaturesLog (SLogContext* pLogCtx, uint32_t uiCpuFeatureFlags, uint32_t uiCpuCores,
2065                            int32_t iCacheLineSize) {
2066   // welstracer output
2067   WelsLog (pLogCtx, WELS_LOG_INFO, "WELS CPU features/capacities (0x%x) detected: \t"
2068            "HTT:      %c, "
2069            "MMX:      %c, "
2070            "MMXEX:    %c, "
2071            "SSE:      %c, "
2072            "SSE2:     %c, "
2073            "SSE3:     %c, "
2074            "SSSE3:    %c, "
2075            "SSE4.1:   %c, "
2076            "SSE4.2:   %c, "
2077            "AVX:      %c, "
2078            "FMA:      %c, "
2079            "X87-FPU:  %c, "
2080            "3DNOW:    %c, "
2081            "3DNOWEX:  %c, "
2082            "ALTIVEC:  %c, "
2083            "CMOV:     %c, "
2084            "MOVBE:    %c, "
2085            "AES:      %c, "
2086            "NUMBER OF LOGIC PROCESSORS ON CHIP: %d, "
2087            "CPU CACHE LINE SIZE (BYTES):        %d",
2088            uiCpuFeatureFlags,
2089            (uiCpuFeatureFlags & WELS_CPU_HTT) ? 'Y' : 'N',
2090            (uiCpuFeatureFlags & WELS_CPU_MMX) ? 'Y' : 'N',
2091            (uiCpuFeatureFlags & WELS_CPU_MMXEXT) ? 'Y' : 'N',
2092            (uiCpuFeatureFlags & WELS_CPU_SSE) ? 'Y' : 'N',
2093            (uiCpuFeatureFlags & WELS_CPU_SSE2) ? 'Y' : 'N',
2094            (uiCpuFeatureFlags & WELS_CPU_SSE3) ? 'Y' : 'N',
2095            (uiCpuFeatureFlags & WELS_CPU_SSSE3) ? 'Y' : 'N',
2096            (uiCpuFeatureFlags & WELS_CPU_SSE41) ? 'Y' : 'N',
2097            (uiCpuFeatureFlags & WELS_CPU_SSE42) ? 'Y' : 'N',
2098            (uiCpuFeatureFlags & WELS_CPU_AVX) ? 'Y' : 'N',
2099            (uiCpuFeatureFlags & WELS_CPU_FMA) ? 'Y' : 'N',
2100            (uiCpuFeatureFlags & WELS_CPU_FPU) ? 'Y' : 'N',
2101            (uiCpuFeatureFlags & WELS_CPU_3DNOW) ? 'Y' : 'N',
2102            (uiCpuFeatureFlags & WELS_CPU_3DNOWEXT) ? 'Y' : 'N',
2103            (uiCpuFeatureFlags & WELS_CPU_ALTIVEC) ? 'Y' : 'N',
2104            (uiCpuFeatureFlags & WELS_CPU_CMOV) ? 'Y' : 'N',
2105            (uiCpuFeatureFlags & WELS_CPU_MOVBE) ? 'Y' : 'N',
2106            (uiCpuFeatureFlags & WELS_CPU_AES) ? 'Y' : 'N',
2107            uiCpuCores,
2108            iCacheLineSize);
2109 }
2110 /*
2111  *
2112  * status information output
2113  */
2114 #if defined(STAT_OUTPUT)
StatOverallEncodingExt(sWelsEncCtx * pCtx)2115 void StatOverallEncodingExt (sWelsEncCtx* pCtx) {
2116   int8_t i = 0;
2117   int8_t j = 0;
2118   for (i = 0; i < pCtx->pSvcParam->iSpatialLayerNum; i++) {
2119     fprintf (stdout, "\nDependency layer : %d\n", i);
2120     fprintf (stdout, "Quality layer : %d\n", j);
2121     {
2122       const int32_t iCount = pCtx->sStatData[i][j].sSliceData.iSliceCount[I_SLICE] +
2123                              pCtx->sStatData[i][j].sSliceData.iSliceCount[P_SLICE] +
2124                              pCtx->sStatData[i][j].sSliceData.iSliceCount[B_SLICE];
2125 #if defined(MB_TYPES_CHECK)
2126       if (iCount > 0) {
2127         int32_t iCountNumIMb = pCtx->sStatData[i][j].sSliceData.iMbCount[I_SLICE][Intra4x4] +
2128                                pCtx->sStatData[i][j].sSliceData.iMbCount[I_SLICE][Intra16x16] + pCtx->sStatData[i][j].sSliceData.iMbCount[I_SLICE][7];
2129         int32_t iCountNumPMb =  pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Intra4x4] +
2130                                 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Intra16x16] +
2131                                 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][7] +
2132                                 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter16x16] +
2133                                 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter16x8] +
2134                                 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter8x16] +
2135                                 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter8x8] +
2136                                 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][10] +
2137                                 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][PSkip];
2138         int32_t count_p_mbL0 =  pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter16x16] +
2139                                 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter16x8] +
2140                                 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter8x16] +
2141                                 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter8x8] +
2142                                 pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][10];
2143 
2144         int32_t iMbCount = iCountNumIMb + iCountNumPMb;
2145         if (iMbCount > 0) {
2146           fprintf (stderr,
2147                    "SVC: overall Slices MBs: %d Avg\nI4x4: %.3f%% I16x16: %.3f%% IBL: %.3f%%\nP16x16: %.3f%% P16x8: %.3f%% P8x16: %.3f%% P8x8: %.3f%% SUBP8x8: %.3f%% PSKIP: %.3f%%\nILP(All): %.3f%% ILP(PL0): %.3f%% BLSKIP(PL0): %.3f%% RP(PL0): %.3f%%\n",
2148                    iMbCount,
2149                    (100.0f * (pCtx->sStatData[i][j].sSliceData.iMbCount[I_SLICE][Intra4x4] +
2150                               pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Intra4x4]) / iMbCount),
2151                    (100.0f * (pCtx->sStatData[i][j].sSliceData.iMbCount[I_SLICE][Intra16x16] +
2152                               pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Intra16x16]) / iMbCount),
2153                    (100.0f * (pCtx->sStatData[i][j].sSliceData.iMbCount[I_SLICE][7] +
2154                               pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][7]) / iMbCount),
2155                    (100.0f * pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter16x16] / iMbCount),
2156                    (100.0f * pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter16x8] / iMbCount),
2157                    (100.0f * pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter8x16] / iMbCount),
2158                    (100.0f * pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][Inter8x8] / iMbCount),
2159                    (100.0f * pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][10] / iMbCount),
2160                    (100.0f * pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][PSkip] / iMbCount),
2161                    (100.0f * pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][11] / iMbCount),
2162                    (100.0f * pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][11] / count_p_mbL0),
2163                    (100.0f * pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][8] / count_p_mbL0),
2164                    (100.0f * pCtx->sStatData[i][j].sSliceData.iMbCount[P_SLICE][9] / count_p_mbL0)
2165                   );
2166         }
2167       }
2168 #endif //#if defined(MB_TYPES_CHECK)
2169 
2170       if (iCount > 0) {
2171         fprintf (stdout, "SVC: overall PSNR Y: %2.3f U: %2.3f V: %2.3f kb/s: %.1f fps: %.3f\n\n",
2172                  (pCtx->sStatData[i][j].sQualityStat.rYPsnr[I_SLICE] + pCtx->sStatData[i][j].sQualityStat.rYPsnr[P_SLICE] +
2173                   pCtx->sStatData[i][j].sQualityStat.rYPsnr[B_SLICE]) / (float) (iCount),
2174                  (pCtx->sStatData[i][j].sQualityStat.rUPsnr[I_SLICE] + pCtx->sStatData[i][j].sQualityStat.rUPsnr[P_SLICE] +
2175                   pCtx->sStatData[i][j].sQualityStat.rUPsnr[B_SLICE]) / (float) (iCount),
2176                  (pCtx->sStatData[i][j].sQualityStat.rVPsnr[I_SLICE] + pCtx->sStatData[i][j].sQualityStat.rVPsnr[P_SLICE] +
2177                   pCtx->sStatData[i][j].sQualityStat.rVPsnr[B_SLICE]) / (float) (iCount),
2178                  1.0f * pCtx->pSvcParam->sDependencyLayers[i].fOutputFrameRate * (pCtx->sStatData[i][j].sSliceData.iSliceSize[I_SLICE] +
2179                      pCtx->sStatData[i][j].sSliceData.iSliceSize[P_SLICE] + pCtx->sStatData[i][j].sSliceData.iSliceSize[B_SLICE]) / (float) (
2180                    iCount + pCtx->pWelsSvcRc[i].iSkipFrameNum) / 1000,
2181                  1.0f * pCtx->pSvcParam->sDependencyLayers[i].fOutputFrameRate);
2182 
2183       }
2184 
2185     }
2186 
2187   }
2188 }
2189 #endif
2190 
2191 
GetMultipleThreadIdc(SLogContext * pLogCtx,SWelsSvcCodingParam * pCodingParam,int16_t & iSliceNum,int32_t & iCacheLineSize,uint32_t & uiCpuFeatureFlags)2192 int32_t GetMultipleThreadIdc (SLogContext* pLogCtx, SWelsSvcCodingParam* pCodingParam, int16_t& iSliceNum,
2193                               int32_t& iCacheLineSize, uint32_t& uiCpuFeatureFlags) {
2194   // for cpu features detection, Only detect once??
2195   int32_t uiCpuCores =
2196     0; // number of logic processors on physical processor package, zero logic processors means HTT not supported
2197   uiCpuFeatureFlags = WelsCPUFeatureDetect (&uiCpuCores); // detect cpu capacity features
2198 
2199 #ifdef X86_ASM
2200   if (uiCpuFeatureFlags & WELS_CPU_CACHELINE_128)
2201     iCacheLineSize = 128;
2202   else if (uiCpuFeatureFlags & WELS_CPU_CACHELINE_64)
2203     iCacheLineSize = 64;
2204   else if (uiCpuFeatureFlags & WELS_CPU_CACHELINE_32)
2205     iCacheLineSize = 32;
2206   else if (uiCpuFeatureFlags & WELS_CPU_CACHELINE_16)
2207     iCacheLineSize = 16;
2208   OutputCpuFeaturesLog (pLogCtx, uiCpuFeatureFlags, uiCpuCores, iCacheLineSize);
2209 #else
2210   iCacheLineSize = 16; // 16 bytes aligned in default
2211 #endif//X86_ASM
2212 
2213   if (0 == pCodingParam->iMultipleThreadIdc && uiCpuCores == 0) {
2214     // cpuid not supported or doesn't expose the number of cores,
2215     // use high level system API as followed to detect number of pysical/logic processor
2216     uiCpuCores = DynamicDetectCpuCores();
2217   }
2218 
2219   if (0 == pCodingParam->iMultipleThreadIdc)
2220     pCodingParam->iMultipleThreadIdc = (uiCpuCores > 0) ? uiCpuCores : 1;
2221 
2222   // So far so many cpu cores up to MAX_THREADS_NUM mean for server platforms,
2223   // for client application here it is constrained by maximal to MAX_THREADS_NUM
2224   pCodingParam->iMultipleThreadIdc = WELS_CLIP3 (pCodingParam->iMultipleThreadIdc, 1, MAX_THREADS_NUM);
2225   uiCpuCores = pCodingParam->iMultipleThreadIdc;
2226 
2227   if (InitSliceSettings (pLogCtx, pCodingParam, uiCpuCores, &iSliceNum)) {
2228     WelsLog (pLogCtx, WELS_LOG_ERROR, "GetMultipleThreadIdc(), InitSliceSettings failed.");
2229     return 1;
2230   }
2231   return 0;
2232 }
2233 
2234 /*!
2235  * \brief   uninitialize Wels encoder core library
2236  * \pParam  pEncCtx     sWelsEncCtx*
2237  * \return  none
2238  */
WelsUninitEncoderExt(sWelsEncCtx ** ppCtx)2239 void WelsUninitEncoderExt (sWelsEncCtx** ppCtx) {
2240   if (NULL == ppCtx || NULL == *ppCtx)
2241     return;
2242 
2243   WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_INFO,
2244            "WelsUninitEncoderExt(), pCtx= %p, iMultipleThreadIdc= %d.",
2245            (void*) (*ppCtx), (*ppCtx)->pSvcParam->iMultipleThreadIdc);
2246 
2247 #if defined(STAT_OUTPUT)
2248   StatOverallEncodingExt (*ppCtx);
2249 #endif
2250 
2251   if ((*ppCtx)->pSvcParam->iMultipleThreadIdc > 1 && (*ppCtx)->pSliceThreading != NULL) {
2252     const int32_t iThreadCount = (*ppCtx)->pSvcParam->iMultipleThreadIdc;
2253     int32_t iThreadIdx = 0;
2254 
2255     while (iThreadIdx < iThreadCount) {
2256       int res = 0;
2257       if ((*ppCtx)->pSliceThreading->pThreadHandles[iThreadIdx]) {
2258 
2259         res = WelsThreadJoin ((*ppCtx)->pSliceThreading->pThreadHandles[iThreadIdx]); // waiting thread exit
2260         WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_INFO, "WelsUninitEncoderExt(), pthread_join(pThreadHandles%d) return %d..",
2261                  iThreadIdx,
2262                  res);
2263         (*ppCtx)->pSliceThreading->pThreadHandles[iThreadIdx] = 0;
2264       }
2265       ++ iThreadIdx;
2266     }
2267   }
2268 
2269   if ((*ppCtx)->pVpp) {
2270     (*ppCtx)->pVpp->FreeSpatialPictures (*ppCtx);
2271     WELS_DELETE_OP ((*ppCtx)->pVpp);
2272   }
2273   FreeMemorySvc (ppCtx);
2274   *ppCtx = NULL;
2275 }
2276 
2277 /*!
2278  * \brief   initialize Wels avc encoder core library
2279  * \pParam  ppCtx       sWelsEncCtx**
2280  * \pParam  pParam      SWelsSvcCodingParam*
2281  * \return  successful - 0; otherwise none 0 for failed
2282  */
WelsInitEncoderExt(sWelsEncCtx ** ppCtx,SWelsSvcCodingParam * pCodingParam,SLogContext * pLogCtx,SExistingParasetList * pExistingParasetList)2283 int32_t WelsInitEncoderExt (sWelsEncCtx** ppCtx, SWelsSvcCodingParam* pCodingParam, SLogContext* pLogCtx,
2284                             SExistingParasetList* pExistingParasetList) {
2285   sWelsEncCtx* pCtx      = NULL;
2286   int32_t iRet           = 0;
2287   int16_t iSliceNum      = 1;    // number of slices used
2288   int32_t iCacheLineSize = 16;   // on chip cache line size in byte
2289   uint32_t uiCpuFeatureFlags = 0;
2290   if (NULL == ppCtx || NULL == pCodingParam) {
2291     WelsLog (pLogCtx, WELS_LOG_ERROR, "WelsInitEncoderExt(), NULL == ppCtx(0x%p) or NULL == pCodingParam(0x%p).",
2292              (void*)ppCtx, (void*)pCodingParam);
2293     return 1;
2294   }
2295 
2296   iRet = ParamValidationExt (pLogCtx, pCodingParam);
2297   if (iRet != 0) {
2298     WelsLog (pLogCtx, WELS_LOG_ERROR, "WelsInitEncoderExt(), ParamValidationExt failed return %d.", iRet);
2299     return iRet;
2300   }
2301   iRet = pCodingParam->DetermineTemporalSettings();
2302   if (iRet != ENC_RETURN_SUCCESS) {
2303     WelsLog (pLogCtx, WELS_LOG_ERROR,
2304              "WelsInitEncoderExt(), DetermineTemporalSettings failed return %d (check in/out frame rate and temporal layer setting! -- in/out = 2^x, x <= temppral_layer_num)",
2305              iRet);
2306     return iRet;
2307   }
2308   iRet = GetMultipleThreadIdc (pLogCtx, pCodingParam, iSliceNum, iCacheLineSize, uiCpuFeatureFlags);
2309   if (iRet != 0) {
2310     WelsLog (pLogCtx, WELS_LOG_ERROR, "WelsInitEncoderExt(), GetMultipleThreadIdc failed return %d.", iRet);
2311     return iRet;
2312   }
2313 
2314 
2315   *ppCtx = NULL;
2316 
2317   pCtx = static_cast<sWelsEncCtx*> (malloc (sizeof (sWelsEncCtx)));
2318 
2319   WELS_VERIFY_RETURN_IF (1, (NULL == pCtx))
2320   memset (pCtx, 0, sizeof (sWelsEncCtx));
2321 
2322   pCtx->sLogCtx = *pLogCtx;
2323 
2324   pCtx->pMemAlign = new CMemoryAlign (iCacheLineSize);
2325   WELS_VERIFY_RETURN_PROC_IF (1, (NULL == pCtx->pMemAlign), WelsUninitEncoderExt (&pCtx))
2326 
2327   iRet = AllocCodingParam (&pCtx->pSvcParam, pCtx->pMemAlign);
2328   if (iRet != 0) {
2329     WelsUninitEncoderExt (&pCtx);
2330     return iRet;
2331   }
2332   memcpy (pCtx->pSvcParam, pCodingParam, sizeof (SWelsSvcCodingParam)); // confirmed_safe_unsafe_usage
2333 
2334   pCtx->pFuncList = (SWelsFuncPtrList*)pCtx->pMemAlign->WelsMallocz (sizeof (SWelsFuncPtrList), "SWelsFuncPtrList");
2335   if (NULL == pCtx->pFuncList) {
2336     WelsUninitEncoderExt (&pCtx);
2337     return 1;
2338   }
2339   InitFunctionPointers (pCtx, pCtx->pSvcParam, uiCpuFeatureFlags);
2340 
2341   pCtx->iActiveThreadsNum = pCodingParam->iMultipleThreadIdc;
2342   pCtx->iMaxSliceCount = iSliceNum;
2343   iRet = RequestMemorySvc (&pCtx, pExistingParasetList);
2344   if (iRet != 0) {
2345     WelsLog (pLogCtx, WELS_LOG_ERROR, "WelsInitEncoderExt(), RequestMemorySvc failed return %d.", iRet);
2346     WelsUninitEncoderExt (&pCtx);
2347     return iRet;
2348   }
2349 
2350   if (pCodingParam->iEntropyCodingModeFlag)
2351     WelsCabacInit (pCtx);
2352   WelsRcInitModule (pCtx,  pCtx->pSvcParam->iRCMode);
2353 
2354   pCtx->pVpp = CWelsPreProcess::CreatePreProcess (pCtx);
2355   if (pCtx->pVpp == NULL) {
2356     iRet = 1;
2357     WelsLog (pLogCtx, WELS_LOG_ERROR, "WelsInitEncoderExt(), pOut of memory in case new CWelsPreProcess().");
2358     WelsUninitEncoderExt (&pCtx);
2359     return iRet;
2360   }
2361   if ((iRet = pCtx->pVpp->AllocSpatialPictures (pCtx, pCtx->pSvcParam)) != 0) {
2362     WelsLog (pLogCtx, WELS_LOG_ERROR, "WelsInitEncoderExt(), pVPP alloc spatial pictures failed");
2363     WelsUninitEncoderExt (&pCtx);
2364     return iRet;
2365   }
2366 
2367 #if defined(MEMORY_MONITOR)
2368   WelsLog (pLogCtx, WELS_LOG_INFO, "WelsInitEncoderExt() exit, overall memory usage: %llu bytes",
2369            static_cast<unsigned long long> (sizeof (sWelsEncCtx) /* requested size from malloc() or new operator */
2370                + pCtx->pMemAlign->WelsGetMemoryUsage())  /* requested size from CMemoryAlign::WelsMalloc() */
2371           );
2372 #endif//MEMORY_MONITOR
2373 
2374   pCtx->iStatisticsLogInterval = STATISTICS_LOG_INTERVAL_MS;
2375   pCtx->uiLastTimestamp = -1;
2376   pCtx->bDeliveryFlag = true;
2377   *ppCtx = pCtx;
2378 
2379   WelsLog (pLogCtx, WELS_LOG_INFO, "WelsInitEncoderExt(), pCtx= 0x%p.", (void*)pCtx);
2380 
2381   return 0;
2382 }
2383 /*!
2384  * \brief   get temporal level due to configuration and coding context
2385  */
GetTemporalLevel(SSpatialLayerInternal * fDlp,const int32_t kiFrameNum,const int32_t kiGopSize)2386 int32_t GetTemporalLevel (SSpatialLayerInternal* fDlp, const int32_t kiFrameNum, const int32_t kiGopSize) {
2387   const int32_t kiCodingIdx = kiFrameNum & (kiGopSize - 1);
2388 
2389   return fDlp->uiCodingIdx2TemporalId[kiCodingIdx];
2390 }
2391 
DynslcUpdateMbNeighbourInfoListForAllSlices(SDqLayer * pCurDq,SMB * pMbList)2392 void DynslcUpdateMbNeighbourInfoListForAllSlices (SDqLayer* pCurDq, SMB* pMbList) {
2393   SSliceCtx* pSliceCtx = &pCurDq->sSliceEncCtx;
2394   const int32_t kiMbWidth       = pSliceCtx->iMbWidth;
2395   const int32_t kiEndMbInSlice  = pSliceCtx->iMbNumInFrame - 1;
2396   int32_t  iIdx                 = 0;
2397 
2398   do {
2399     SMB* pMb = &pMbList[iIdx];
2400     UpdateMbNeighbor (pCurDq, pMb, kiMbWidth, WelsMbToSliceIdc (pCurDq, pMb->iMbXY));
2401     ++ iIdx;
2402   } while (iIdx <= kiEndMbInSlice);
2403 }
2404 
2405 /*
2406  * TUNE back if number of picture partition decision algorithm based on past if available
2407  */
PicPartitionNumDecision(sWelsEncCtx * pCtx)2408 int32_t PicPartitionNumDecision (sWelsEncCtx* pCtx) {
2409   int32_t iPartitionNum = 1;
2410   if (pCtx->pSvcParam->iMultipleThreadIdc > 1) {
2411     iPartitionNum = pCtx->pSvcParam->iMultipleThreadIdc;
2412   }
2413   return iPartitionNum;
2414 }
2415 
WelsInitCurrentQBLayerMltslc(sWelsEncCtx * pCtx)2416 void WelsInitCurrentQBLayerMltslc (sWelsEncCtx* pCtx) {
2417   //pData init
2418   SDqLayer*  pCurDq    = pCtx->pCurDqLayer;
2419   //mb_neighbor
2420   DynslcUpdateMbNeighbourInfoListForAllSlices (pCurDq, pCurDq->sMbDataP);
2421 }
2422 
UpdateSlicepEncCtxWithPartition(SDqLayer * pCurDq,int32_t iPartitionNum)2423 void UpdateSlicepEncCtxWithPartition (SDqLayer* pCurDq, int32_t iPartitionNum) {
2424   SSliceCtx* pSliceCtx                  = &pCurDq->sSliceEncCtx;
2425   const int32_t kiMbNumInFrame          = pSliceCtx->iMbNumInFrame;
2426   int32_t iCountMbNumPerPartition       = kiMbNumInFrame;
2427   int32_t iAssignableMbLeft             = kiMbNumInFrame;
2428   int32_t iCountMbNumInPartition        = 0;
2429   int32_t iFirstMbIdx                   = 0;
2430   int32_t i/*, j*/;
2431 
2432   if (iPartitionNum <= 0)
2433     iPartitionNum = 1;
2434   else if (iPartitionNum > AVERSLICENUM_CONSTRAINT)
2435     iPartitionNum = AVERSLICENUM_CONSTRAINT; // AVERSLICENUM_CONSTRAINT might be variable, however not fixed by MACRO
2436   iCountMbNumPerPartition /= iPartitionNum;
2437   if (iCountMbNumPerPartition == 0 || iCountMbNumPerPartition == 1) {
2438     iCountMbNumPerPartition = kiMbNumInFrame;
2439     iPartitionNum           = 1;
2440   }
2441 
2442   pSliceCtx->iSliceNumInFrame = iPartitionNum;
2443 
2444   i = 0;
2445   while (i < iPartitionNum) {
2446     if (i + 1 == iPartitionNum) {
2447       iCountMbNumInPartition = iAssignableMbLeft;
2448     } else {
2449       iCountMbNumInPartition = iCountMbNumPerPartition;
2450     }
2451 
2452     pCurDq->FirstMbIdxOfPartition[i]     = iFirstMbIdx;
2453     pCurDq->EndMbIdxOfPartition[i]       = iFirstMbIdx + iCountMbNumInPartition - 1;
2454     pCurDq->LastCodedMbIdxOfPartition[i] = 0;
2455     pCurDq->NumSliceCodedOfPartition[i]  = 0;
2456 
2457     WelsSetMemMultiplebytes_c (pSliceCtx->pOverallMbMap + iFirstMbIdx, i,
2458                                iCountMbNumInPartition, sizeof (uint16_t));
2459 
2460     // for next partition(or pSlice)
2461     iFirstMbIdx       += iCountMbNumInPartition;
2462     iAssignableMbLeft -= iCountMbNumInPartition;
2463     ++ i;
2464   }
2465 
2466   while (i < MAX_THREADS_NUM) {
2467     pCurDq->FirstMbIdxOfPartition[i]     = 0;
2468     pCurDq->EndMbIdxOfPartition[i]       = 0;
2469     pCurDq->LastCodedMbIdxOfPartition[i] = 0;
2470     pCurDq->NumSliceCodedOfPartition[i]  = 0;
2471     ++ i;
2472   }
2473 }
2474 
WelsInitCurrentDlayerMltslc(sWelsEncCtx * pCtx,int32_t iPartitionNum)2475 void WelsInitCurrentDlayerMltslc (sWelsEncCtx* pCtx, int32_t iPartitionNum) {
2476   SDqLayer* pCurDq      = pCtx->pCurDqLayer;
2477   SSliceCtx* pSliceCtx  = &pCurDq->sSliceEncCtx;
2478   uint32_t  uiMiniPacketSize  = 0;
2479 
2480   UpdateSlicepEncCtxWithPartition (pCurDq, iPartitionNum);
2481 
2482   if (I_SLICE == pCtx->eSliceType) { //check if uiSliceSizeConstraint too small
2483 #define byte_complexIMBat26 (60)
2484     uint8_t iCurDid    = pCtx->uiDependencyId;
2485     uint32_t uiFrmByte = 0;
2486 
2487     if (pCtx->pSvcParam->iRCMode != RC_OFF_MODE) {
2488       //RC case
2489       uiFrmByte = (
2490                     ((uint32_t) (pCtx->pSvcParam->sSpatialLayers[iCurDid].iSpatialBitrate)
2491                      / (uint32_t) (pCtx->pSvcParam->sDependencyLayers[iCurDid].fInputFrameRate)) >> 3);
2492     } else {
2493       //fixed QP case
2494       const int32_t iTtlMbNumInFrame = pSliceCtx->iMbNumInFrame;
2495       int32_t iQDeltaTo26 = (26 - pCtx->pSvcParam->sSpatialLayers[iCurDid].iDLayerQp);
2496 
2497       uiFrmByte = (iTtlMbNumInFrame * byte_complexIMBat26);
2498       if (iQDeltaTo26 > 0) {
2499         //smaller QP than 26
2500         uiFrmByte = (uint32_t) (uiFrmByte * ((float)iQDeltaTo26 / 4));
2501       } else if (iQDeltaTo26 < 0) {
2502         //larger QP than 26
2503         iQDeltaTo26 = ((-iQDeltaTo26) >> 2);   //delta mod 4
2504         uiFrmByte = (uiFrmByte >> (iQDeltaTo26));   //if delta 4, byte /2
2505       }
2506     }
2507 
2508     //MINPACKETSIZE_CONSTRAINT
2509     //suppose 16 byte per mb at average
2510     uiMiniPacketSize = (uint32_t) (uiFrmByte / pSliceCtx->iMaxSliceNumConstraint);
2511     if (pSliceCtx->uiSliceSizeConstraint < uiMiniPacketSize) {
2512       WelsLog (& (pCtx->sLogCtx),
2513                WELS_LOG_WARNING,
2514                "Set-SliceConstraint(%d) too small for current resolution (MB# %d) under QP/BR!",
2515                pSliceCtx->uiSliceSizeConstraint,
2516                pSliceCtx->iMbNumInFrame
2517               );
2518     }
2519   }
2520 
2521   WelsInitCurrentQBLayerMltslc (pCtx);
2522 }
2523 
2524 /*!
2525  * \brief   initialize current layer
2526  */
WelsInitCurrentLayer(sWelsEncCtx * pCtx,const int32_t kiWidth,const int32_t kiHeight)2527 void WelsInitCurrentLayer (sWelsEncCtx* pCtx,
2528                            const int32_t kiWidth,
2529                            const int32_t kiHeight) {
2530   SWelsSvcCodingParam* pParam   = pCtx->pSvcParam;
2531   SPicture* pEncPic             = pCtx->pEncPic;
2532   SPicture* pDecPic             = pCtx->pDecPic;
2533   SDqLayer* pCurDq              = pCtx->pCurDqLayer;
2534   SSlice*   pBaseSlice          = pCurDq->ppSliceInLayer[0];
2535   const uint8_t kiCurDid        = pCtx->uiDependencyId;
2536   const bool kbUseSubsetSpsFlag = (!pParam->bSimulcastAVC) && (kiCurDid > BASE_DEPENDENCY_ID);
2537   SNalUnitHeaderExt* pNalHdExt  = &pCurDq->sLayerInfo.sNalHeaderExt;
2538   SNalUnitHeader* pNalHd        = &pNalHdExt->sNalUnitHeader;
2539   SDqIdc* pDqIdc                = &pCtx->pDqIdcMap[kiCurDid];
2540   int32_t iIdx                  = 0;
2541   int32_t iSliceCount           = pCurDq->iMaxSliceNum;
2542   SSpatialLayerInternal* pParamInternal = &pParam->sDependencyLayers[kiCurDid];
2543   if (NULL == pCurDq || NULL == pBaseSlice)
2544     return;
2545 
2546   pCurDq->pDecPic = pDecPic;
2547 
2548   assert (iSliceCount > 0);
2549 
2550   int32_t iCurPpsId = pDqIdc->iPpsId;
2551   int32_t iCurSpsId = pDqIdc->iSpsId;
2552 
2553   iCurPpsId = pCtx->pFuncList->pParametersetStrategy->GetCurrentPpsId (iCurPpsId,
2554               WELS_ABS (pParamInternal->uiIdrPicId - 1) % MAX_PPS_COUNT);
2555 
2556   pBaseSlice->sSliceHeaderExt.sSliceHeader.iPpsId       = iCurPpsId;
2557   pCurDq->sLayerInfo.pPpsP                              =
2558     pBaseSlice->sSliceHeaderExt.sSliceHeader.pPps       = &pCtx->pPPSArray[iCurPpsId];
2559 
2560   pBaseSlice->sSliceHeaderExt.sSliceHeader.iSpsId       = iCurSpsId;
2561   if (kbUseSubsetSpsFlag) {
2562     pCurDq->sLayerInfo.pSubsetSpsP                      = &pCtx->pSubsetArray[iCurSpsId];
2563     pCurDq->sLayerInfo.pSpsP                            =
2564       pBaseSlice->sSliceHeaderExt.sSliceHeader.pSps     = &pCurDq->sLayerInfo.pSubsetSpsP->pSps;
2565   } else {
2566     pCurDq->sLayerInfo.pSubsetSpsP                      = NULL;
2567     pCurDq->sLayerInfo.pSpsP                            =
2568       pBaseSlice->sSliceHeaderExt.sSliceHeader.pSps     = &pCtx->pSpsArray[iCurSpsId];
2569   }
2570 
2571   pBaseSlice->bSliceHeaderExtFlag = (NAL_UNIT_CODED_SLICE_EXT == pCtx->eNalType);
2572 
2573   iIdx = 1;
2574   while (iIdx < iSliceCount) {
2575     InitSliceHeadWithBase (pCurDq->ppSliceInLayer[iIdx], pBaseSlice);
2576     ++ iIdx;
2577   }
2578 
2579   memset (pNalHdExt, 0, sizeof (SNalUnitHeaderExt));
2580   pNalHd->uiNalRefIdc                   = pCtx->eNalPriority;
2581   pNalHd->eNalUnitType                  = pCtx->eNalType;
2582 
2583   pNalHdExt->uiDependencyId             = kiCurDid;
2584   pNalHdExt->bDiscardableFlag           = (pCtx->bNeedPrefixNalFlag) ? (pNalHd->uiNalRefIdc == NRI_PRI_LOWEST) : false;
2585   pNalHdExt->bIdrFlag                   = (pParamInternal->iFrameNum == 0)
2586                                           && ((pCtx->eNalType == NAL_UNIT_CODED_SLICE_IDR)
2587                                               || (pCtx->eSliceType == I_SLICE));
2588   pNalHdExt->uiTemporalId               = pCtx->uiTemporalId;
2589 
2590   // pEncPic pData
2591   pCurDq->pEncData[0]   = pEncPic->pData[0];
2592   pCurDq->pEncData[1]   = pEncPic->pData[1];
2593   pCurDq->pEncData[2]   = pEncPic->pData[2];
2594   pCurDq->iEncStride[0] = pEncPic->iLineSize[0];
2595   pCurDq->iEncStride[1] = pEncPic->iLineSize[1];
2596   pCurDq->iEncStride[2] = pEncPic->iLineSize[2];
2597   // cs pData
2598   pCurDq->pCsData[0]    = pDecPic->pData[0];
2599   pCurDq->pCsData[1]    = pDecPic->pData[1];
2600   pCurDq->pCsData[2]    = pDecPic->pData[2];
2601   pCurDq->iCsStride[0]  = pDecPic->iLineSize[0];
2602   pCurDq->iCsStride[1]  = pDecPic->iLineSize[1];
2603   pCurDq->iCsStride[2]  = pDecPic->iLineSize[2];
2604 
2605   if (pCurDq->pRefLayer != NULL) {
2606     pCurDq->bBaseLayerAvailableFlag = true;
2607   } else {
2608     pCurDq->bBaseLayerAvailableFlag = false;
2609   }
2610 
2611   if (pCtx->pTaskManage) {
2612     pCtx->pTaskManage->InitFrame (kiCurDid);
2613   }
2614 }
2615 
SetFastCodingFunc(SWelsFuncPtrList * pFuncList)2616 static inline void SetFastCodingFunc (SWelsFuncPtrList* pFuncList) {
2617   pFuncList->pfIntraFineMd = WelsMdIntraFinePartitionVaa;
2618   pFuncList->sSampleDealingFuncs.pfMdCost = pFuncList->sSampleDealingFuncs.pfSampleSad;
2619   pFuncList->sSampleDealingFuncs.pfIntra16x16Combined3 = pFuncList->sSampleDealingFuncs.pfIntra16x16Combined3Sad;
2620   pFuncList->sSampleDealingFuncs.pfIntra8x8Combined3 = pFuncList->sSampleDealingFuncs.pfIntra8x8Combined3Sad;
2621 }
SetNormalCodingFunc(SWelsFuncPtrList * pFuncList)2622 static inline void SetNormalCodingFunc (SWelsFuncPtrList* pFuncList) {
2623   pFuncList->pfIntraFineMd = WelsMdIntraFinePartition;
2624   pFuncList->sSampleDealingFuncs.pfMdCost = pFuncList->sSampleDealingFuncs.pfSampleSatd;
2625   pFuncList->sSampleDealingFuncs.pfIntra16x16Combined3 =
2626     pFuncList->sSampleDealingFuncs.pfIntra16x16Combined3Satd;
2627   pFuncList->sSampleDealingFuncs.pfIntra8x8Combined3 =
2628     pFuncList->sSampleDealingFuncs.pfIntra8x8Combined3Satd;
2629   pFuncList->sSampleDealingFuncs.pfIntra4x4Combined3 =
2630     pFuncList->sSampleDealingFuncs.pfIntra4x4Combined3Satd;
2631 }
SetMeMethod(const uint8_t uiMethod,PSearchMethodFunc & pSearchMethodFunc)2632 bool SetMeMethod (const uint8_t uiMethod, PSearchMethodFunc& pSearchMethodFunc) {
2633   switch (uiMethod) {
2634   case  ME_DIA:
2635     pSearchMethodFunc  = WelsDiamondSearch;
2636     break;
2637   case  ME_CROSS:
2638     pSearchMethodFunc = WelsMotionCrossSearch;
2639     break;
2640   case  ME_DIA_CROSS:
2641     pSearchMethodFunc = WelsDiamondCrossSearch;
2642     break;
2643   case  ME_DIA_CROSS_FME:
2644     pSearchMethodFunc = WelsDiamondCrossFeatureSearch;
2645     break;
2646   case ME_FULL:
2647     pSearchMethodFunc = WelsDiamondSearch;
2648     return false;
2649   default:
2650     pSearchMethodFunc = WelsDiamondSearch;
2651     return false;
2652   }
2653   return true;
2654 }
2655 
2656 
2657 
PreprocessSliceCoding(sWelsEncCtx * pCtx)2658 void PreprocessSliceCoding (sWelsEncCtx* pCtx) {
2659   SDqLayer* pCurLayer           = pCtx->pCurDqLayer;
2660   //const bool kbBaseAvail      = pCurLayer->bBaseLayerAvailableFlag;
2661   bool bFastMode = (pCtx->pSvcParam->iComplexityMode == LOW_COMPLEXITY);
2662   SWelsFuncPtrList* pFuncList = pCtx->pFuncList;
2663   SLogContext* pLogCtx = & (pCtx->sLogCtx);
2664   /* function pointers conditional assignment under sWelsEncCtx, layer_mb_enc_rec (in stack) is exclusive */
2665   if ((pCtx->pSvcParam->iUsageType == CAMERA_VIDEO_REAL_TIME && bFastMode) ||
2666       (pCtx->pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME && P_SLICE == pCtx->eSliceType
2667        && bFastMode) //TODO: here is for sync with the origin code, consider the design again with more tests
2668      ) {
2669     SetFastCodingFunc (pFuncList);
2670   } else {
2671     SetNormalCodingFunc (pFuncList);
2672   }
2673 
2674   if (P_SLICE == pCtx->eSliceType) {
2675     for (int i = 0; i < BLOCK_STATIC_IDC_ALL; i++) {
2676       pFuncList->pfMotionSearch[i] = WelsMotionEstimateSearch;
2677     }
2678     pFuncList->pfSearchMethod[BLOCK_16x16]  =
2679       pFuncList->pfSearchMethod[BLOCK_16x8] =
2680         pFuncList->pfSearchMethod[BLOCK_8x16] =
2681           pFuncList->pfSearchMethod[BLOCK_8x8] =
2682             pFuncList->pfSearchMethod[BLOCK_4x4] =
2683               pFuncList->pfSearchMethod[BLOCK_8x4] =
2684                 pFuncList->pfSearchMethod[BLOCK_4x8] = WelsDiamondSearch;
2685     pFuncList->pfFirstIntraMode = WelsMdFirstIntraMode;
2686     pFuncList->sSampleDealingFuncs.pfMeCost = pCtx->pFuncList->sSampleDealingFuncs.pfSampleSatd;
2687     pFuncList->pfSetScrollingMv = SetScrollingMvToMdNull;
2688 
2689     if (bFastMode) {
2690       pFuncList->pfCalculateSatd = NotCalculateSatdCost;
2691       pFuncList->pfInterFineMd = WelsMdInterFinePartitionVaa;
2692     } else {
2693       pFuncList->pfCalculateSatd = CalculateSatdCost;
2694       pFuncList->pfInterFineMd = WelsMdInterFinePartition;
2695     }
2696   } else {
2697     pFuncList->sSampleDealingFuncs.pfMeCost = NULL;
2698   }
2699 
2700   //to init at each frame will be needed when dealing with hybrid content (camera+screen)
2701   if (pCtx->pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME) {
2702     if (P_SLICE == pCtx->eSliceType) {
2703       //MD related func pointers
2704       pFuncList->pfInterFineMd = WelsMdInterFinePartitionVaaOnScreen;
2705 
2706       //ME related func pointers
2707       SVAAFrameInfoExt* pVaaExt = static_cast<SVAAFrameInfoExt*> (pCtx->pVaa);
2708       if (pVaaExt->sScrollDetectInfo.bScrollDetectFlag
2709           && (pVaaExt->sScrollDetectInfo.iScrollMvX | pVaaExt->sScrollDetectInfo.iScrollMvY)) {
2710         pFuncList->pfSetScrollingMv = SetScrollingMvToMd;
2711       } else {
2712         pFuncList->pfSetScrollingMv = SetScrollingMvToMdNull;
2713       }
2714 
2715       pFuncList->pfMotionSearch[NO_STATIC] = WelsMotionEstimateSearch;
2716       pFuncList->pfMotionSearch[COLLOCATED_STATIC] = WelsMotionEstimateSearchStatic;
2717       pFuncList->pfMotionSearch[SCROLLED_STATIC] = WelsMotionEstimateSearchScrolled;
2718       //ME16x16
2719       if (!SetMeMethod (ME_DIA_CROSS, pFuncList->pfSearchMethod[BLOCK_16x16])) {
2720         WelsLog (pLogCtx, WELS_LOG_WARNING, "SetMeMethod(BLOCK_16x16) ME_DIA_CROSS unsuccessful, switched to default search");
2721       }
2722       //ME8x8
2723       SFeatureSearchPreparation* pFeatureSearchPreparation = pCurLayer->pFeatureSearchPreparation;
2724       if (pFeatureSearchPreparation) {
2725         pFeatureSearchPreparation->iHighFreMbCount = 0;
2726 
2727         //calculate bFMESwitchFlag
2728         SVAAFrameInfoExt* pVaaExt = static_cast<SVAAFrameInfoExt*> (pCtx->pVaa);
2729         const int32_t kiMbSize = pCurLayer->iMbHeight * pCurLayer->iMbWidth;
2730         pFeatureSearchPreparation->bFMESwitchFlag = CalcFMESwitchFlag (pFeatureSearchPreparation->uiFMEGoodFrameCount,
2731             pFeatureSearchPreparation->iHighFreMbCount * 100 / kiMbSize, pCtx->pVaa->sVaaCalcInfo.iFrameSad / kiMbSize,
2732             pVaaExt->sScrollDetectInfo.bScrollDetectFlag);
2733 
2734         //PerformFMEPreprocess
2735         SScreenBlockFeatureStorage* pScreenBlockFeatureStorage = pCurLayer->pRefPic->pScreenBlockFeatureStorage;
2736         pFeatureSearchPreparation->pRefBlockFeature = pScreenBlockFeatureStorage;
2737         if (pFeatureSearchPreparation->bFMESwitchFlag
2738             && !pScreenBlockFeatureStorage->bRefBlockFeatureCalculated) {
2739           SPicture* pRef = (pCtx->pSvcParam->bEnableLongTermReference ? pCurLayer->pRefOri[0] : pCurLayer->pRefPic);
2740           PerformFMEPreprocess (pFuncList, pRef, pFeatureSearchPreparation->pFeatureOfBlock,
2741                                 pScreenBlockFeatureStorage);
2742         }
2743 
2744         //assign ME pointer
2745         if (pFeatureSearchPreparation->bFMESwitchFlag && pScreenBlockFeatureStorage->bRefBlockFeatureCalculated
2746             && (!pScreenBlockFeatureStorage->iIs16x16)) {
2747           if (!SetMeMethod (ME_DIA_CROSS_FME, pFuncList->pfSearchMethod[BLOCK_8x8])) {
2748             WelsLog (pLogCtx, WELS_LOG_WARNING,
2749                      "SetMeMethod(BLOCK_8x8) ME_DIA_CROSS_FME unsuccessful, switched to default search");
2750           }
2751         }
2752 
2753         //assign UpdateFMESwitch pointer
2754         if (pFeatureSearchPreparation->bFMESwitchFlag) {
2755           pFuncList->pfUpdateFMESwitch = UpdateFMESwitch;
2756         } else {
2757           pFuncList->pfUpdateFMESwitch = UpdateFMESwitchNull;
2758         }
2759       }//if (pFeatureSearchPreparation)
2760     } else {
2761       //reset some status when at I_SLICE
2762       pCurLayer->pFeatureSearchPreparation->bFMESwitchFlag = true;
2763       pCurLayer->pFeatureSearchPreparation->uiFMEGoodFrameCount = FMESWITCH_DEFAULT_GOODFRAME_NUM;
2764     }
2765   }
2766 
2767   // update some layer dependent variable to save judgements in mb-level
2768   pCurLayer->bSatdInMdFlag = ((pFuncList->sSampleDealingFuncs.pfMeCost == pFuncList->sSampleDealingFuncs.pfSampleSatd)
2769                               && (pFuncList->sSampleDealingFuncs.pfMdCost == pFuncList->sSampleDealingFuncs.pfSampleSatd));
2770 
2771   const int32_t kiCurDid            = pCtx->uiDependencyId;
2772   const int32_t kiCurTid            = pCtx->uiTemporalId;
2773   if (pCurLayer->bDeblockingParallelFlag && (pCurLayer->iLoopFilterDisableIdc != 1)
2774 #if !defined(ENABLE_FRAME_DUMP)
2775       && (NRI_PRI_LOWEST != pCtx->eNalPriority)
2776       && (pCtx->pSvcParam->sDependencyLayers[kiCurDid].iHighestTemporalId == 0
2777           || kiCurTid < pCtx->pSvcParam->sDependencyLayers[kiCurDid].iHighestTemporalId)
2778 #endif// !ENABLE_FRAME_DUMP
2779      ) {
2780     pFuncList->pfDeblocking.pfDeblockingFilterSlice = DeblockingFilterSliceAvcbase;
2781   } else {
2782     pFuncList->pfDeblocking.pfDeblockingFilterSlice = DeblockingFilterSliceAvcbaseNull;
2783   }
2784 }
2785 
2786 /*!
2787  * \brief   swap pDq layers between current pDq layer and reference pDq layer
2788  */
2789 
WelsSwapDqLayers(sWelsEncCtx * pCtx,const int32_t kiNextDqIdx)2790 static inline void WelsSwapDqLayers (sWelsEncCtx* pCtx, const int32_t kiNextDqIdx) {
2791   // swap and assign reference
2792   SDqLayer* pTmpLayer           = pCtx->ppDqLayerList[kiNextDqIdx];
2793   SDqLayer* pRefLayer           = pCtx->pCurDqLayer;
2794   pCtx->pCurDqLayer             = pTmpLayer;
2795   pCtx->pCurDqLayer->pRefLayer  = pRefLayer;
2796 }
2797 
2798 /*!
2799  * \brief   prefetch reference picture after WelsBuildRefList
2800  */
PrefetchReferencePicture(sWelsEncCtx * pCtx,const EVideoFrameType keFrameType)2801 static inline void PrefetchReferencePicture (sWelsEncCtx* pCtx, const EVideoFrameType keFrameType) {
2802   const int32_t kiSliceCount = pCtx->pCurDqLayer->iMaxSliceNum;
2803   int32_t iIdx = 0;
2804   uint8_t uiRefIdx = -1;
2805 
2806   assert (kiSliceCount > 0);
2807   if (keFrameType != videoFrameTypeIDR) {
2808     assert (pCtx->iNumRef0 > 0);
2809     pCtx->pRefPic               = pCtx->pRefList0[0];   // always get item 0 due to reordering done
2810     pCtx->pCurDqLayer->pRefPic  = pCtx->pRefPic;
2811     uiRefIdx                    = 0;                    // reordered reference iIndex
2812   } else { // safe for IDR coding
2813     pCtx->pRefPic               = NULL;
2814     pCtx->pCurDqLayer->pRefPic  = NULL;
2815   }
2816 
2817   iIdx = 0;
2818   while (iIdx < kiSliceCount) {
2819     pCtx->pCurDqLayer->ppSliceInLayer[iIdx]->sSliceHeaderExt.sSliceHeader.uiRefIndex = uiRefIdx;
2820     ++ iIdx;
2821   }
2822 }
2823 
WelsWriteOneSPS(sWelsEncCtx * pCtx,const int32_t kiSpsIdx,int32_t & iNalSize)2824 int32_t WelsWriteOneSPS (sWelsEncCtx* pCtx, const int32_t kiSpsIdx, int32_t& iNalSize) {
2825   int iNal = pCtx->pOut->iNalIndex;
2826   WelsLoadNal (pCtx->pOut, NAL_UNIT_SPS, NRI_PRI_HIGHEST);
2827 
2828   WelsWriteSpsNal (&pCtx->pSpsArray[kiSpsIdx], &pCtx->pOut->sBsWrite,
2829                    pCtx->pFuncList->pParametersetStrategy->GetSpsIdOffsetList (PARA_SET_TYPE_AVCSPS));
2830   WelsUnloadNal (pCtx->pOut);
2831 
2832   int32_t iReturn = WelsEncodeNal (&pCtx->pOut->sNalList[iNal], NULL,
2833                                    pCtx->iFrameBsSize - pCtx->iPosBsBuffer,//available buffer to be written, so need to substract the used length
2834                                    pCtx->pFrameBs + pCtx->iPosBsBuffer,
2835                                    &iNalSize);
2836   WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS)
2837 
2838   pCtx->iPosBsBuffer += iNalSize;
2839   return ENC_RETURN_SUCCESS;
2840 }
2841 
WelsWriteOnePPS(sWelsEncCtx * pCtx,const int32_t kiPpsIdx,int32_t & iNalSize)2842 int32_t WelsWriteOnePPS (sWelsEncCtx* pCtx, const int32_t kiPpsIdx, int32_t& iNalSize) {
2843   //TODO
2844   int32_t iNal = pCtx->pOut->iNalIndex;
2845   /* generate picture parameter set */
2846   WelsLoadNal (pCtx->pOut, NAL_UNIT_PPS, NRI_PRI_HIGHEST);
2847 
2848   WelsWritePpsSyntax (&pCtx->pPPSArray[kiPpsIdx], &pCtx->pOut->sBsWrite,
2849                       pCtx->pFuncList->pParametersetStrategy);
2850   WelsUnloadNal (pCtx->pOut);
2851 
2852   int32_t iReturn = WelsEncodeNal (&pCtx->pOut->sNalList[iNal], NULL,
2853                                    pCtx->iFrameBsSize - pCtx->iPosBsBuffer,
2854                                    pCtx->pFrameBs + pCtx->iPosBsBuffer,
2855                                    &iNalSize);
2856   WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS)
2857 
2858   pCtx->iPosBsBuffer += iNalSize;
2859   return ENC_RETURN_SUCCESS;
2860 }
2861 
2862 
2863 /*!
2864  * \brief   write all parameter sets introduced in SVC extension
2865  * \return  writing results, success or error
2866  */
WelsWriteParameterSets(sWelsEncCtx * pCtx,int32_t * pNalLen,int32_t * pNumNal,int32_t * pTotalLength)2867 int32_t WelsWriteParameterSets (sWelsEncCtx* pCtx, int32_t* pNalLen, int32_t* pNumNal, int32_t* pTotalLength) {
2868   int32_t iSize = 0;
2869   int32_t iNal  = 0;
2870   int32_t iIdx  = 0;
2871   int32_t iId   = 0;
2872   int32_t iCountNal     = 0;
2873   int32_t iNalLength    = 0;
2874   int32_t iReturn = ENC_RETURN_SUCCESS;
2875 
2876   if (NULL == pCtx || NULL == pNalLen || NULL == pNumNal || NULL == pCtx->pFuncList->pParametersetStrategy)
2877     return ENC_RETURN_UNEXPECTED;
2878 
2879   *pTotalLength = 0;
2880   /* write all SPS */
2881   iIdx = 0;
2882   while (iIdx < pCtx->iSpsNum) {
2883     pCtx->pFuncList->pParametersetStrategy->Update (pCtx->pSpsArray[iIdx].uiSpsId, PARA_SET_TYPE_AVCSPS);
2884     /* generate sequence parameters set */
2885     iId = pCtx->pFuncList->pParametersetStrategy->GetSpsIdx (iIdx);
2886 
2887     WelsWriteOneSPS (pCtx, iId, iNalLength);
2888 
2889     pNalLen[iCountNal] = iNalLength;
2890     iSize += iNalLength;
2891 
2892     ++ iIdx;
2893     ++ iCountNal;
2894   }
2895 
2896   /* write all Subset SPS */
2897   iIdx = 0;
2898   while (iIdx < pCtx->iSubsetSpsNum) {
2899     iNal = pCtx->pOut->iNalIndex;
2900 
2901     pCtx->pFuncList->pParametersetStrategy->Update (pCtx->pSubsetArray[iIdx].pSps.uiSpsId, PARA_SET_TYPE_SUBSETSPS);
2902 
2903     iId = iIdx;
2904 
2905     /* generate Subset SPS */
2906     WelsLoadNal (pCtx->pOut, NAL_UNIT_SUBSET_SPS, NRI_PRI_HIGHEST);
2907 
2908     WelsWriteSubsetSpsSyntax (&pCtx->pSubsetArray[iId], &pCtx->pOut->sBsWrite,
2909                               pCtx->pFuncList->pParametersetStrategy->GetSpsIdOffsetList (PARA_SET_TYPE_SUBSETSPS));
2910     WelsUnloadNal (pCtx->pOut);
2911 
2912     iReturn = WelsEncodeNal (&pCtx->pOut->sNalList[iNal], NULL,
2913                              pCtx->iFrameBsSize - pCtx->iPosBsBuffer,//available buffer to be written, so need to substract the used length
2914                              pCtx->pFrameBs + pCtx->iPosBsBuffer,
2915                              &iNalLength);
2916     WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS)
2917     pNalLen[iCountNal] = iNalLength;
2918 
2919     pCtx->iPosBsBuffer  += iNalLength;
2920     iSize               += iNalLength;
2921 
2922     ++ iIdx;
2923     ++ iCountNal;
2924   }
2925 
2926   pCtx->pFuncList->pParametersetStrategy->UpdatePpsList (pCtx);
2927 
2928   iIdx = 0;
2929   while (iIdx < pCtx->iPpsNum) {
2930     pCtx->pFuncList->pParametersetStrategy->Update (pCtx->pPPSArray[iIdx].iPpsId, PARA_SET_TYPE_PPS);
2931 
2932     WelsWriteOnePPS (pCtx, iIdx, iNalLength);
2933 
2934     pNalLen[iCountNal] = iNalLength;
2935     iSize += iNalLength;
2936 
2937     ++ iIdx;
2938     ++ iCountNal;
2939   }
2940 
2941   *pNumNal = iCountNal;
2942   *pTotalLength = iSize;
2943 
2944   return ENC_RETURN_SUCCESS;
2945 }
2946 
AddPrefixNal(sWelsEncCtx * pCtx,SLayerBSInfo * pLayerBsInfo,int32_t * pNalLen,int32_t * pNalIdxInLayer,const EWelsNalUnitType keNalType,const EWelsNalRefIdc keNalRefIdc,int32_t & iPayloadSize)2947 static inline int32_t AddPrefixNal (sWelsEncCtx* pCtx,
2948                                     SLayerBSInfo* pLayerBsInfo,
2949                                     int32_t* pNalLen,
2950                                     int32_t* pNalIdxInLayer,
2951                                     const EWelsNalUnitType keNalType,
2952                                     const EWelsNalRefIdc keNalRefIdc,
2953                                     int32_t& iPayloadSize) {
2954   int32_t iReturn = ENC_RETURN_SUCCESS;
2955   iPayloadSize = 0;
2956 
2957   if (keNalRefIdc != NRI_PRI_LOWEST) {
2958     WelsLoadNal (pCtx->pOut, NAL_UNIT_PREFIX, keNalRefIdc);
2959 
2960     WelsWriteSVCPrefixNal (&pCtx->pOut->sBsWrite, keNalRefIdc, (NAL_UNIT_CODED_SLICE_IDR == keNalType));
2961 
2962     WelsUnloadNal (pCtx->pOut);
2963 
2964     iReturn = WelsEncodeNal (&pCtx->pOut->sNalList[pCtx->pOut->iNalIndex - 1],
2965                              &pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt,
2966                              pCtx->iFrameBsSize - pCtx->iPosBsBuffer,
2967                              pCtx->pFrameBs + pCtx->iPosBsBuffer,
2968                              &pNalLen[*pNalIdxInLayer]);
2969     WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS)
2970     iPayloadSize = pNalLen[*pNalIdxInLayer];
2971 
2972     pCtx->iPosBsBuffer += iPayloadSize;
2973 
2974     (*pNalIdxInLayer) ++;
2975   } else { // No Prefix NAL Unit RBSP syntax here, but need add NAL Unit Header extension
2976     WelsLoadNal (pCtx->pOut, NAL_UNIT_PREFIX, keNalRefIdc);
2977     // No need write any syntax of prefix NAL Unit RBSP here
2978     WelsUnloadNal (pCtx->pOut);
2979 
2980     iReturn = WelsEncodeNal (&pCtx->pOut->sNalList[pCtx->pOut->iNalIndex - 1],
2981                              &pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt,
2982                              pCtx->iFrameBsSize - pCtx->iPosBsBuffer,
2983                              pCtx->pFrameBs + pCtx->iPosBsBuffer,
2984                              &pNalLen[*pNalIdxInLayer]);
2985     WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS)
2986     iPayloadSize = pNalLen[*pNalIdxInLayer];
2987 
2988     pCtx->iPosBsBuffer += iPayloadSize;
2989 
2990     (*pNalIdxInLayer) ++;
2991   }
2992 
2993   return ENC_RETURN_SUCCESS;
2994 }
2995 
WritePadding(sWelsEncCtx * pCtx,int32_t iLen,int32_t & iSize)2996 int32_t WritePadding (sWelsEncCtx* pCtx, int32_t iLen, int32_t& iSize) {
2997   int32_t i = 0;
2998   int32_t iNal = 0;
2999   SBitStringAux* pBs = NULL;
3000   int32_t iNalLen;
3001 
3002   iSize = 0;
3003   iNal  = pCtx->pOut->iNalIndex;
3004   pBs   = &pCtx->pOut->sBsWrite;  // SBitStringAux instance for non VCL NALs decoding
3005 
3006   if ((pBs->pEndBuf - pBs->pCurBuf) < iLen || iNal >= pCtx->pOut->iCountNals) {
3007 #if GOM_TRACE_FLAG
3008     WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR,
3009              "[RC] paddingcal pBuffer overflow, bufferlen=%lld, paddinglen=%d, iNalIdx= %d, iCountNals= %d",
3010              static_cast<long long int> (pBs->pEndBuf - pBs->pCurBuf), iLen, iNal, pCtx->pOut->iCountNals);
3011 #endif
3012     return ENC_RETURN_MEMOVERFLOWFOUND;
3013   }
3014 
3015   WelsLoadNal (pCtx->pOut, NAL_UNIT_FILLER_DATA, NRI_PRI_LOWEST);
3016 
3017   for (i = 0; i < iLen; i++) {
3018     BsWriteBits (pBs, 8, 0xff);
3019   }
3020 
3021   BsRbspTrailingBits (pBs);
3022 
3023   WelsUnloadNal (pCtx->pOut);
3024   int32_t iReturn = WelsEncodeNal (&pCtx->pOut->sNalList[iNal], NULL,
3025                                    pCtx->iFrameBsSize - pCtx->iPosBsBuffer,
3026                                    pCtx->pFrameBs + pCtx->iPosBsBuffer,
3027                                    &iNalLen);
3028   WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS)
3029 
3030   pCtx->iPosBsBuffer += iNalLen;
3031   iSize              += iNalLen;
3032 
3033   return ENC_RETURN_SUCCESS;
3034 }
3035 
3036 /*
3037  * Force coding IDR as follows
3038  */
ForceCodingIDR(sWelsEncCtx * pCtx,int32_t iLayerId)3039 int32_t ForceCodingIDR (sWelsEncCtx* pCtx, int32_t iLayerId) {
3040   if (NULL == pCtx)
3041     return 1;
3042   if ((iLayerId < 0) || (iLayerId >= MAX_SPATIAL_LAYER_NUM) || (!pCtx->pSvcParam->bSimulcastAVC)) {
3043     for (int32_t iDid = 0; iDid < pCtx->pSvcParam->iSpatialLayerNum; iDid++) {
3044       SSpatialLayerInternal* pParamInternal = &pCtx->pSvcParam->sDependencyLayers[iDid];
3045       pParamInternal->iCodingIndex = 0;
3046       pParamInternal->iFrameIndex = 0;
3047       pParamInternal->iFrameNum = 0;
3048       pParamInternal->iPOC = 0;
3049       pParamInternal->bEncCurFrmAsIdrFlag = true;
3050       pCtx->sEncoderStatistics[0].uiIDRReqNum++;
3051     }
3052     WelsLog (&pCtx->sLogCtx, WELS_LOG_INFO, "ForceCodingIDR(iDid 0-%d)at InputFrameCount=%d\n",
3053              pCtx->pSvcParam->iSpatialLayerNum - 1, pCtx->sEncoderStatistics[0].uiInputFrameCount);
3054 
3055 
3056 
3057   } else {
3058     SSpatialLayerInternal* pParamInternal = &pCtx->pSvcParam->sDependencyLayers[iLayerId];
3059     pParamInternal->iCodingIndex = 0;
3060     pParamInternal->iFrameIndex = 0;
3061     pParamInternal->iFrameNum = 0;
3062     pParamInternal->iPOC = 0;
3063     pParamInternal->bEncCurFrmAsIdrFlag = true;
3064     pCtx->sEncoderStatistics[iLayerId].uiIDRReqNum++;
3065     WelsLog (&pCtx->sLogCtx, WELS_LOG_INFO, "ForceCodingIDR(iDid %d)at InputFrameCount=%d\n", iLayerId,
3066              pCtx->sEncoderStatistics[iLayerId].uiInputFrameCount);
3067   }
3068   pCtx->bCheckWindowStatusRefreshFlag = false;
3069 
3070 
3071   return 0;
3072 }
3073 
WelsEncoderEncodeParameterSets(sWelsEncCtx * pCtx,void * pDst)3074 int32_t WelsEncoderEncodeParameterSets (sWelsEncCtx* pCtx, void* pDst) {
3075   if (NULL == pCtx || NULL == pDst) {
3076     return ENC_RETURN_UNEXPECTED;
3077   }
3078 
3079   SFrameBSInfo* pFbi          = (SFrameBSInfo*)pDst;
3080   SLayerBSInfo* pLayerBsInfo  = &pFbi->sLayerInfo[0];
3081   int32_t iCountNal           = 0;
3082   int32_t iTotalLength        = 0;
3083 
3084   pLayerBsInfo->pBsBuf = pCtx->pFrameBs;
3085   pLayerBsInfo->pNalLengthInByte = pCtx->pOut->pNalLen;
3086   InitBits (&pCtx->pOut->sBsWrite, pCtx->pOut->pBsBuffer, pCtx->pOut->uiSize);
3087 
3088   pCtx->iPosBsBuffer = 0;
3089   int32_t iReturn = WelsWriteParameterSets (pCtx, &pLayerBsInfo->pNalLengthInByte[0], &iCountNal, &iTotalLength);
3090   WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS)
3091 
3092   pLayerBsInfo->uiSpatialId   = 0;
3093   pLayerBsInfo->uiTemporalId  = 0;
3094   pLayerBsInfo->uiQualityId   = 0;
3095   pLayerBsInfo->uiLayerType   = NON_VIDEO_CODING_LAYER;
3096   pLayerBsInfo->iNalCount     = iCountNal;
3097   pLayerBsInfo->eFrameType    = videoFrameTypeInvalid;
3098   pLayerBsInfo->iSubSeqId     = 0;
3099   //pCtx->eLastNalPriority      = NRI_PRI_HIGHEST;
3100   pFbi->iLayerNum             = 1;
3101   pFbi->eFrameType            = videoFrameTypeInvalid;
3102   WelsEmms();
3103 
3104   return ENC_RETURN_SUCCESS;
3105 }
3106 
GetSubSequenceId(sWelsEncCtx * pCtx,EVideoFrameType eFrameType)3107 int32_t GetSubSequenceId (sWelsEncCtx* pCtx, EVideoFrameType eFrameType) {
3108   int32_t iSubSeqId = 0;
3109   if (eFrameType == videoFrameTypeIDR)
3110     iSubSeqId = 0;
3111   else if (eFrameType == videoFrameTypeI)
3112     iSubSeqId = 1;
3113   else if (eFrameType == videoFrameTypeP) {
3114     if (pCtx->bCurFrameMarkedAsSceneLtr)
3115       iSubSeqId = 2;
3116     else
3117       iSubSeqId = 3 + pCtx->uiTemporalId; //T0:3 T1:4 T2:5 T3:6
3118   } else
3119     iSubSeqId = 3 + MAX_TEMPORAL_LAYER_NUM;
3120   return iSubSeqId;
3121 }
3122 
3123 // writing parasets for (simulcast) svc
WriteSsvcParaset(sWelsEncCtx * pCtx,const int32_t kiSpatialNum,SLayerBSInfo * & pLayerBsInfo,int32_t & iLayerNum,int32_t & iFrameSize)3124 int32_t WriteSsvcParaset (sWelsEncCtx* pCtx, const int32_t kiSpatialNum,
3125                           SLayerBSInfo*& pLayerBsInfo, int32_t& iLayerNum, int32_t& iFrameSize) {
3126   int32_t iNonVclSize = 0, iCountNal = 0, iReturn = ENC_RETURN_SUCCESS;
3127   iReturn = WelsWriteParameterSets (pCtx, &pLayerBsInfo->pNalLengthInByte[0], &iCountNal, &iNonVclSize);
3128   WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS)
3129   for (int32_t iSpatialId = 0; iSpatialId < kiSpatialNum; iSpatialId++) {
3130     SSpatialLayerInternal* pParamInternal = &pCtx->pSvcParam->sDependencyLayers[iSpatialId];
3131     if (pParamInternal->uiIdrPicId < 65535) {
3132       ++ pParamInternal->uiIdrPicId;
3133     } else {
3134       pParamInternal->uiIdrPicId = 0;
3135     }
3136   }
3137   pLayerBsInfo->uiSpatialId     = 0;
3138   pLayerBsInfo->uiTemporalId    = 0;
3139   pLayerBsInfo->uiQualityId     = 0;
3140   pLayerBsInfo->uiLayerType     = NON_VIDEO_CODING_LAYER;
3141   pLayerBsInfo->iNalCount       = iCountNal;
3142   pLayerBsInfo->eFrameType      = videoFrameTypeIDR;
3143   pLayerBsInfo->iSubSeqId = GetSubSequenceId (pCtx, videoFrameTypeIDR);
3144   //point to next pLayerBsInfo
3145   ++ pLayerBsInfo;
3146   ++ pCtx->pOut->iLayerBsIndex;
3147   pLayerBsInfo->pBsBuf           = pCtx->pFrameBs + pCtx->iPosBsBuffer;
3148   pLayerBsInfo->pNalLengthInByte = (pLayerBsInfo - 1)->pNalLengthInByte + iCountNal;
3149 
3150   //update for external countings
3151   ++ iLayerNum;
3152   iFrameSize += iNonVclSize;
3153   return iReturn;
3154 }
3155 
3156 // writing parasets for simulcast avc
WriteSavcParaset(sWelsEncCtx * pCtx,const int32_t iIdx,SLayerBSInfo * & pLayerBsInfo,int32_t & iLayerNum,int32_t & iFrameSize)3157 int32_t WriteSavcParaset (sWelsEncCtx* pCtx, const int32_t iIdx,
3158                           SLayerBSInfo*& pLayerBsInfo, int32_t& iLayerNum, int32_t& iFrameSize) {
3159   int32_t iNonVclSize = 0, iCountNal = 0, iReturn = ENC_RETURN_SUCCESS;
3160 
3161   // write SPS
3162   iNonVclSize = 0;
3163 
3164   //writing one NAL
3165   int32_t iNalSize = 0;
3166   iCountNal        = 0;
3167 
3168 
3169   if (pCtx->pFuncList->pParametersetStrategy) {
3170     pCtx->pFuncList->pParametersetStrategy->Update (pCtx->pSpsArray[iIdx].uiSpsId, PARA_SET_TYPE_AVCSPS);
3171   }
3172 
3173   iReturn          = WelsWriteOneSPS (pCtx, iIdx, iNalSize);
3174   WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS)
3175 
3176   pLayerBsInfo->pNalLengthInByte[iCountNal] = iNalSize;
3177   iNonVclSize += iNalSize;
3178   iCountNal = 1;
3179 
3180   //finish writing one NAL
3181 
3182   pLayerBsInfo->uiSpatialId   = iIdx;
3183   pLayerBsInfo->uiTemporalId  = 0;
3184   pLayerBsInfo->uiQualityId   = 0;
3185   pLayerBsInfo->uiLayerType   = NON_VIDEO_CODING_LAYER;
3186   pLayerBsInfo->iNalCount     = iCountNal;
3187   pLayerBsInfo->eFrameType    = videoFrameTypeIDR;
3188   pLayerBsInfo->iSubSeqId     = GetSubSequenceId (pCtx, videoFrameTypeIDR);
3189   //point to next pLayerBsInfo
3190   ++ pLayerBsInfo;
3191   ++ pCtx->pOut->iLayerBsIndex;
3192   pLayerBsInfo->pBsBuf           = pCtx->pFrameBs + pCtx->iPosBsBuffer;
3193   pLayerBsInfo->pNalLengthInByte = (pLayerBsInfo - 1)->pNalLengthInByte + iCountNal;
3194   //update for external countings
3195   ++ iLayerNum;
3196 
3197   // write PPS
3198 
3199   //TODO: under new strategy, will PPS be correctly updated?
3200 
3201   //writing one NAL
3202   iNalSize = 0;
3203   iCountNal        = 0;
3204 
3205   if (pCtx->pFuncList->pParametersetStrategy) {
3206     pCtx->pFuncList->pParametersetStrategy->Update (pCtx->pPPSArray[iIdx].iPpsId, PARA_SET_TYPE_PPS);
3207   }
3208 
3209   iReturn          = WelsWriteOnePPS (pCtx, iIdx, iNalSize);
3210   WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS)
3211 
3212   pLayerBsInfo->pNalLengthInByte[iCountNal] = iNalSize;
3213   iNonVclSize += iNalSize;
3214   iCountNal = 1;
3215   //finish writing one NAL
3216 
3217   pLayerBsInfo->uiSpatialId   = iIdx;
3218   pLayerBsInfo->uiTemporalId  = 0;
3219   pLayerBsInfo->uiQualityId   = 0;
3220   pLayerBsInfo->uiLayerType   = NON_VIDEO_CODING_LAYER;
3221   pLayerBsInfo->iNalCount     = iCountNal;
3222   pLayerBsInfo->eFrameType    = videoFrameTypeIDR;
3223   pLayerBsInfo->iSubSeqId     = GetSubSequenceId (pCtx, videoFrameTypeIDR);
3224   //point to next pLayerBsInfo
3225   ++ pLayerBsInfo;
3226   ++ pCtx->pOut->iLayerBsIndex;
3227   pLayerBsInfo->pBsBuf           = pCtx->pFrameBs + pCtx->iPosBsBuffer;
3228   pLayerBsInfo->pNalLengthInByte = (pLayerBsInfo - 1)->pNalLengthInByte + iCountNal;
3229   //update for external countings
3230   ++ iLayerNum;
3231 
3232   // to check number of layers / nals / slices dependencies
3233   if (iLayerNum > MAX_LAYER_NUM_OF_FRAME) {
3234     WelsLog (& pCtx->sLogCtx, WELS_LOG_ERROR, "WriteSavcParaset(), iLayerNum(%d) > MAX_LAYER_NUM_OF_FRAME(%d)!",
3235              iLayerNum, MAX_LAYER_NUM_OF_FRAME);
3236     return 1;
3237   }
3238 
3239   iFrameSize += iNonVclSize;
3240   return iReturn;
3241 }
3242 
3243 //cover the logic of simulcast avc + sps_pps_listing
WriteSavcParaset_Listing(sWelsEncCtx * pCtx,const int32_t kiSpatialNum,SLayerBSInfo * & pLayerBsInfo,int32_t & iLayerNum,int32_t & iFrameSize)3244 int32_t WriteSavcParaset_Listing (sWelsEncCtx* pCtx, const int32_t kiSpatialNum,
3245                                   SLayerBSInfo*& pLayerBsInfo, int32_t& iLayerNum, int32_t& iFrameSize) {
3246   int32_t iNonVclSize = 0, iCountNal = 0, iReturn = ENC_RETURN_SUCCESS;
3247 
3248   // write SPS
3249   iNonVclSize = 0;
3250 
3251   for (int32_t iSpatialId = 0; iSpatialId < kiSpatialNum; iSpatialId++) {
3252     SSpatialLayerInternal* pParamInternal = &pCtx->pSvcParam->sDependencyLayers[iSpatialId];
3253     if (pParamInternal->uiIdrPicId < 65535) {
3254       ++ pParamInternal->uiIdrPicId;
3255     } else {
3256       pParamInternal->uiIdrPicId = 0;
3257     }
3258 
3259     iCountNal = 0;
3260 
3261     for (int32_t iIdx = 0; iIdx < pCtx->iSpsNum; iIdx++) {
3262       //writing one NAL
3263       int32_t iNalSize = 0;
3264       iReturn = WelsWriteOneSPS (pCtx, iIdx, iNalSize);
3265       WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS)
3266 
3267       pLayerBsInfo->pNalLengthInByte[iCountNal] = iNalSize;
3268       iNonVclSize += iNalSize;
3269       iCountNal ++;
3270       //finish writing one NAL
3271     }
3272 
3273     pLayerBsInfo->uiSpatialId   = iSpatialId;
3274     pLayerBsInfo->uiTemporalId  = 0;
3275     pLayerBsInfo->uiQualityId   = 0;
3276     pLayerBsInfo->uiLayerType   = NON_VIDEO_CODING_LAYER;
3277     pLayerBsInfo->iNalCount     = iCountNal;
3278     pLayerBsInfo->eFrameType    = videoFrameTypeIDR;
3279     pLayerBsInfo->iSubSeqId     = GetSubSequenceId (pCtx, videoFrameTypeIDR);
3280     //point to next pLayerBsInfo
3281     ++ pLayerBsInfo;
3282     ++ pCtx->pOut->iLayerBsIndex;
3283     pLayerBsInfo->pBsBuf           = pCtx->pFrameBs + pCtx->iPosBsBuffer;
3284     pLayerBsInfo->pNalLengthInByte = (pLayerBsInfo - 1)->pNalLengthInByte + iCountNal;
3285     //update for external countings
3286     ++ iLayerNum;
3287   }
3288 
3289   // write PPS
3290   pCtx->pFuncList->pParametersetStrategy->UpdatePpsList (pCtx);
3291 
3292   //TODO: under new strategy, will PPS be correctly updated?
3293   for (int32_t iSpatialId = 0; iSpatialId < kiSpatialNum; iSpatialId++) {
3294     iCountNal = 0;
3295     for (int32_t iIdx = 0; iIdx < pCtx->iPpsNum; iIdx++) {
3296       //writing one NAL
3297       int32_t iNalSize = 0;
3298       iReturn = WelsWriteOnePPS (pCtx, iIdx, iNalSize);
3299       WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS)
3300 
3301       pLayerBsInfo->pNalLengthInByte[iCountNal] = iNalSize;
3302       iNonVclSize += iNalSize;
3303       iCountNal ++;
3304       //finish writing one NAL
3305     }
3306 
3307     pLayerBsInfo->uiSpatialId   = iSpatialId;
3308     pLayerBsInfo->uiTemporalId  = 0;
3309     pLayerBsInfo->uiQualityId   = 0;
3310     pLayerBsInfo->uiLayerType   = NON_VIDEO_CODING_LAYER;
3311     pLayerBsInfo->iNalCount     = iCountNal;
3312     pLayerBsInfo->eFrameType    = videoFrameTypeIDR;
3313     pLayerBsInfo->iSubSeqId     = GetSubSequenceId (pCtx, videoFrameTypeIDR);
3314     //point to next pLayerBsInfo
3315     ++ pLayerBsInfo;
3316     ++ pCtx->pOut->iLayerBsIndex;
3317     pLayerBsInfo->pBsBuf           = pCtx->pFrameBs + pCtx->iPosBsBuffer;
3318     pLayerBsInfo->pNalLengthInByte = (pLayerBsInfo - 1)->pNalLengthInByte + iCountNal;
3319     //update for external countings
3320     ++ iLayerNum;
3321   }
3322 
3323   // to check number of layers / nals / slices dependencies
3324   if (iLayerNum > MAX_LAYER_NUM_OF_FRAME) {
3325     WelsLog (& pCtx->sLogCtx, WELS_LOG_ERROR, "WriteSavcParaset(), iLayerNum(%d) > MAX_LAYER_NUM_OF_FRAME(%d)!",
3326              iLayerNum, MAX_LAYER_NUM_OF_FRAME);
3327     return ENC_RETURN_UNEXPECTED;
3328   }
3329 
3330   iFrameSize += iNonVclSize;
3331   return iReturn;
3332 }
3333 
StackBackEncoderStatus(sWelsEncCtx * pEncCtx,EVideoFrameType keFrameType)3334 void StackBackEncoderStatus (sWelsEncCtx* pEncCtx,
3335                              EVideoFrameType keFrameType) {
3336   SSpatialLayerInternal* pParamInternal = &pEncCtx->pSvcParam->sDependencyLayers[pEncCtx->uiDependencyId];
3337   // for bitstream writing
3338   pEncCtx->iPosBsBuffer        = 0;   // reset bs pBuffer position
3339   pEncCtx->pOut->iNalIndex     = 0;   // reset NAL index
3340   pEncCtx->pOut->iLayerBsIndex = 0;   // reset index of Layer Bs
3341 
3342   InitBits (&pEncCtx->pOut->sBsWrite, pEncCtx->pOut->pBsBuffer, pEncCtx->pOut->uiSize);
3343   if ((keFrameType == videoFrameTypeP) || (keFrameType == videoFrameTypeI)) {
3344     pParamInternal->iFrameIndex --;
3345     if (pParamInternal->iPOC != 0) {
3346       pParamInternal->iPOC -= 2;
3347     } else {
3348       pParamInternal->iPOC = (1 << pEncCtx->pSps->iLog2MaxPocLsb) - 2;
3349     }
3350 
3351     LoadBackFrameNum (pEncCtx, pEncCtx->uiDependencyId);
3352 
3353     pEncCtx->eNalType     = NAL_UNIT_CODED_SLICE;
3354     pEncCtx->eSliceType   = P_SLICE;
3355     //pEncCtx->eNalPriority = pEncCtx->eLastNalPriority; //not need this since eNalPriority will be updated at the beginning of coding a frame
3356   } else if (keFrameType == videoFrameTypeIDR) {
3357     pParamInternal->uiIdrPicId --;
3358 
3359     //set the next frame to be IDR
3360     ForceCodingIDR (pEncCtx, pEncCtx->uiDependencyId);
3361   } else { // B pictures are not supported now, any else?
3362     assert (0);
3363   }
3364 
3365   // no need to stack back RC info since the info is still useful for later RQ model calculation
3366   // no need to stack back MB slicing info for dynamic balancing, since the info is still refer-able
3367 }
3368 
ClearFrameBsInfo(sWelsEncCtx * pCtx,SFrameBSInfo * pFbi)3369 void ClearFrameBsInfo (sWelsEncCtx* pCtx, SFrameBSInfo* pFbi) {
3370   pFbi->sLayerInfo[0].pBsBuf           = pCtx->pFrameBs;
3371   pFbi->sLayerInfo[0].pNalLengthInByte = pCtx->pOut->pNalLen;
3372 
3373   for (int i = 0; i < pFbi->iLayerNum; i++) {
3374     pFbi->sLayerInfo[i].iNalCount = 0;
3375     pFbi->sLayerInfo[i].eFrameType = videoFrameTypeSkip;
3376   }
3377   pFbi->iLayerNum = 0;
3378   pFbi->iFrameSizeInBytes = 0;
3379 }
PrepareEncodeFrame(sWelsEncCtx * pCtx,SLayerBSInfo * & pLayerBsInfo,int32_t iSpatialNum,int8_t & iCurDid,int32_t & iCurTid,int32_t & iLayerNum,int32_t & iFrameSize,long long uiTimeStamp)3380 EVideoFrameType PrepareEncodeFrame (sWelsEncCtx* pCtx, SLayerBSInfo*& pLayerBsInfo, int32_t iSpatialNum,
3381                                     int8_t& iCurDid, int32_t& iCurTid,
3382                                     int32_t& iLayerNum, int32_t& iFrameSize, long long uiTimeStamp) {
3383   SWelsSvcCodingParam* pSvcParam        = pCtx->pSvcParam;
3384   SSpatialPicIndex* pSpatialIndexMap = &pCtx->sSpatialIndexMap[0];
3385 
3386   bool bSkipFrameFlag =  WelsRcCheckFrameStatus (pCtx, uiTimeStamp, iSpatialNum, iCurDid);
3387   EVideoFrameType eFrameType = DecideFrameType (pCtx, iSpatialNum, iCurDid, bSkipFrameFlag);
3388   if (eFrameType == videoFrameTypeSkip) {
3389     if (pSvcParam->bSimulcastAVC) {
3390       if (pCtx->pFuncList->pfRc.pfWelsUpdateBufferWhenSkip)
3391         pCtx->pFuncList->pfRc.pfWelsUpdateBufferWhenSkip (pCtx, iCurDid);
3392       WelsLog (& (pCtx->sLogCtx), WELS_LOG_DEBUG,
3393                "[Rc] Frame timestamp = %lld, iDid = %d,skip one frame due to target_br, continual skipped %d frames",
3394                uiTimeStamp, iCurDid, pCtx->pWelsSvcRc[iCurDid].iContinualSkipFrames);
3395     }
3396 
3397     else {
3398       if (pCtx->pFuncList->pfRc.pfWelsUpdateBufferWhenSkip) {
3399         for (int32_t i = 0; i < iSpatialNum; i++) {
3400           pCtx->pFuncList->pfRc.pfWelsUpdateBufferWhenSkip (pCtx, (pSpatialIndexMap + i)->iDid);
3401         }
3402       }
3403       WelsLog (& (pCtx->sLogCtx), WELS_LOG_DEBUG,
3404                "[Rc] Frame timestamp = %lld, iDid = %d,skip one frame due to target_br, continual skipped %d frames",
3405                uiTimeStamp, iCurDid, pCtx->pWelsSvcRc[iCurDid].iContinualSkipFrames);
3406     }
3407 
3408   } else {
3409     SSpatialLayerInternal* pParamInternal = &pSvcParam->sDependencyLayers[iCurDid];
3410 
3411     iCurTid = GetTemporalLevel (pParamInternal, pParamInternal->iCodingIndex,
3412                                 pSvcParam->uiGopSize);
3413     pCtx->uiTemporalId = iCurTid;
3414     if (eFrameType == videoFrameTypeIDR) {
3415       // write parameter sets bitstream or SEI/SSEI (if any) here
3416       // TODO: use function pointer instead
3417       if (! (SPS_LISTING & pCtx->pSvcParam->eSpsPpsIdStrategy)) {
3418         if (pSvcParam->bSimulcastAVC) {
3419           pCtx->iEncoderError = WriteSavcParaset (pCtx, iCurDid, pLayerBsInfo, iLayerNum, iFrameSize);
3420           ++ pParamInternal->uiIdrPicId;
3421         } else {
3422           pCtx->iEncoderError = WriteSsvcParaset (pCtx, iSpatialNum, pLayerBsInfo, iLayerNum, iFrameSize);
3423         }
3424       } else {
3425         pCtx->iEncoderError = WriteSavcParaset_Listing (pCtx, iSpatialNum, pLayerBsInfo, iLayerNum, iFrameSize);
3426 
3427 
3428       }
3429     }
3430   }
3431   return eFrameType;
3432 }
3433 /*!
3434  * \brief   core svc encoding process
3435  *
3436  * \pParam  pCtx            sWelsEncCtx*, encoder context
3437  * \pParam  pFbi            FrameBSInfo*
3438  * \pParam  pSrcPic         Source Picture
3439  * \return  EFrameType (videoFrameTypeIDR/videoFrameTypeI/videoFrameTypeP)
3440  */
WelsEncoderEncodeExt(sWelsEncCtx * pCtx,SFrameBSInfo * pFbi,const SSourcePicture * pSrcPic)3441 int32_t WelsEncoderEncodeExt (sWelsEncCtx* pCtx, SFrameBSInfo* pFbi, const SSourcePicture* pSrcPic) {
3442   if (pCtx == NULL) {
3443     return ENC_RETURN_MEMALLOCERR;
3444   }
3445   SLayerBSInfo* pLayerBsInfo            = &pFbi->sLayerInfo[0];
3446   SWelsSvcCodingParam* pSvcParam        = pCtx->pSvcParam;
3447   SSpatialPicIndex* pSpatialIndexMap = &pCtx->sSpatialIndexMap[0];
3448 #if defined(ENABLE_FRAME_DUMP) || defined(ENABLE_PSNR_CALC)
3449   SPicture* fsnr                = NULL;
3450 #endif//ENABLE_FRAME_DUMP || ENABLE_PSNR_CALC
3451   SPicture* pEncPic             = NULL; // to be decided later
3452 #if defined(MT_DEBUG)
3453   int32_t iDidList[MAX_DEPENDENCY_LAYER] = {0};
3454 #endif
3455   int32_t iLayerNum             = 0;
3456   int32_t iLayerSize            = 0;
3457   int32_t iSpatialNum           =
3458     0; // available count number of spatial layers due to frame size changed in this given frame
3459   int32_t iSpatialIdx           = 0; // iIndex of spatial layers due to frame size changed in this given frame
3460   int32_t iFrameSize            = 0;
3461   int32_t iNalIdxInLayer        = 0;
3462   int32_t iCountNal             = 0;
3463   EVideoFrameType eFrameType    = videoFrameTypeInvalid;
3464   int32_t iCurWidth             = 0;
3465   int32_t iCurHeight            = 0;
3466   EWelsNalUnitType eNalType     = NAL_UNIT_UNSPEC_0;
3467   EWelsNalRefIdc eNalRefIdc     = NRI_PRI_LOWEST;
3468   int8_t iCurDid                = 0;
3469   int32_t iCurTid                = 0;
3470   bool bAvcBased                = false;
3471   SLogContext* pLogCtx = & (pCtx->sLogCtx);
3472 #if defined(ENABLE_PSNR_CALC)
3473   float fSnrY = .0f, fSnrU = .0f, fSnrV = .0f;
3474 #endif//ENABLE_PSNR_CALC
3475 
3476 #if defined(_DEBUG)
3477   int32_t i = 0, j = 0, k = 0;
3478 #endif//_DEBUG
3479   pCtx->iEncoderError = ENC_RETURN_SUCCESS;
3480   pCtx->bCurFrameMarkedAsSceneLtr = false;
3481   pFbi->eFrameType = videoFrameTypeSkip;
3482   pFbi->iLayerNum = 0; // for initialization
3483   pFbi->uiTimeStamp = GetTimestampForRc (pSrcPic->uiTimeStamp, pCtx->uiLastTimestamp,
3484                                          pCtx->pSvcParam->sSpatialLayers[pCtx->pSvcParam->iSpatialLayerNum - 1].fFrameRate);
3485   for (int32_t iNalIdx = 0; iNalIdx < MAX_LAYER_NUM_OF_FRAME; iNalIdx++) {
3486     pFbi->sLayerInfo[iNalIdx].eFrameType = videoFrameTypeSkip;
3487     pFbi->sLayerInfo[iNalIdx].iNalCount  = 0;
3488   }
3489   // perform csc/denoise/downsample/padding, generate spatial layers
3490   iSpatialNum = pCtx->pVpp->BuildSpatialPicList (pCtx, pSrcPic);
3491   if (iSpatialNum == -1) {
3492     WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR, "Failed in allocating memory in BuildSpatialPicList");
3493     return ENC_RETURN_MEMALLOCERR;
3494   }
3495 
3496   if (pCtx->pFuncList->pfRc.pfWelsUpdateMaxBrWindowStatus) {
3497     pCtx->pFuncList->pfRc.pfWelsUpdateMaxBrWindowStatus (pCtx, iSpatialNum, pFbi->uiTimeStamp);
3498   }
3499 
3500   if (iSpatialNum < 1) {
3501     for (int32_t iDidIdx = 0; iDidIdx < pSvcParam->iSpatialLayerNum; iDidIdx++) {
3502       SSpatialLayerInternal* pParamInternal = &pSvcParam->sDependencyLayers[iDidIdx];
3503       pParamInternal->iCodingIndex ++;
3504     }
3505     pFbi->eFrameType = videoFrameTypeSkip;
3506     pLayerBsInfo->eFrameType = videoFrameTypeSkip;
3507     WelsLog (& (pCtx->sLogCtx), WELS_LOG_DEBUG,
3508              "[Rc] Frame timestamp = %lld, skip one frame due to preprocessing return (temporal layer settings or else)",
3509              pSrcPic->uiTimeStamp);
3510     return ENC_RETURN_SUCCESS;
3511   }
3512 
3513   InitBitStream (pCtx);
3514   pLayerBsInfo->pBsBuf = pCtx->pFrameBs ;
3515   pLayerBsInfo->pNalLengthInByte = pCtx->pOut->pNalLen;
3516   iCurDid = pSpatialIndexMap->iDid;
3517   pCtx->pCurDqLayer             = pCtx->ppDqLayerList[iCurDid];
3518   pCtx->pCurDqLayer->pRefLayer  = NULL;
3519   if (!pSvcParam->bSimulcastAVC) {
3520     eFrameType = PrepareEncodeFrame (pCtx, pLayerBsInfo, iSpatialNum, iCurDid, iCurTid, iLayerNum, iFrameSize,
3521                                      pFbi->uiTimeStamp);
3522     if (eFrameType == videoFrameTypeSkip) {
3523       pFbi->eFrameType = videoFrameTypeSkip;
3524       pLayerBsInfo->eFrameType = videoFrameTypeSkip;
3525       return ENC_RETURN_SUCCESS;
3526     }
3527   } else {
3528     for (int32_t iDidIdx = 0; iDidIdx < pSvcParam->iSpatialLayerNum; iDidIdx++) {
3529       SSpatialLayerInternal* pParamInternal = &pSvcParam->sDependencyLayers[iDidIdx];
3530       int32_t iTemporalId =  GetTemporalLevel (pParamInternal, pParamInternal->iCodingIndex,
3531                              pSvcParam->uiGopSize);
3532       if (iTemporalId == INVALID_TEMPORAL_ID)
3533         pParamInternal->iCodingIndex ++;
3534     }
3535   }
3536 
3537   while (iSpatialIdx < iSpatialNum) {
3538     iCurDid  = (pSpatialIndexMap + iSpatialIdx)->iDid;
3539     SSpatialLayerConfig* pParam = &pSvcParam->sSpatialLayers[iCurDid];
3540     SSpatialLayerInternal* pParamInternal = &pSvcParam->sDependencyLayers[iCurDid];
3541     int32_t  iDecompositionStages = pSvcParam->sDependencyLayers[iCurDid].iDecompositionStages;
3542     pCtx->pCurDqLayer           = pCtx->ppDqLayerList[iCurDid];
3543     pCtx->uiDependencyId        =  iCurDid;
3544 
3545     if (pSvcParam->bSimulcastAVC) {
3546       eFrameType = PrepareEncodeFrame (pCtx, pLayerBsInfo, iSpatialNum, iCurDid, iCurTid, iLayerNum, iFrameSize,
3547                                        pFbi->uiTimeStamp);
3548       if (eFrameType == videoFrameTypeSkip) {
3549         pLayerBsInfo->eFrameType = videoFrameTypeSkip;
3550         ++iSpatialIdx;
3551         continue;
3552       }
3553     }
3554     InitFrameCoding (pCtx, eFrameType, iCurDid);
3555     pCtx->pVpp->AnalyzeSpatialPic (pCtx, iCurDid);
3556 
3557     pCtx->pEncPic               = pEncPic = (pSpatialIndexMap + iSpatialIdx)->pSrc;
3558     pCtx->pEncPic->iPictureType = pCtx->eSliceType;
3559     pCtx->pEncPic->iFramePoc    = pParamInternal->iPOC;
3560 
3561     iCurWidth   = pParam->iVideoWidth;
3562     iCurHeight  = pParam->iVideoHeight;
3563 #if defined(MT_DEBUG)
3564     iDidList[iSpatialIdx]       = iCurDid;
3565 #endif
3566     // Encoding this picture might mulitiple sQualityStat layers potentially be encoded as followed
3567     switch (pParam->sSliceArgument.uiSliceMode) {
3568     case SM_FIXEDSLCNUM_SLICE: {
3569       if ((pSvcParam->iMultipleThreadIdc > 1) &&
3570           (pSvcParam->bUseLoadBalancing
3571            && pSvcParam->iMultipleThreadIdc >= pSvcParam->sSpatialLayers[iCurDid].sSliceArgument.uiSliceNum)
3572          ) {
3573         if (iCurDid > 0)
3574           AdjustEnhanceLayer (pCtx, iCurDid);
3575         else
3576           AdjustBaseLayer (pCtx);
3577       }
3578 
3579       break;
3580     }
3581     case SM_SIZELIMITED_SLICE: {
3582       int32_t iPicIPartitionNum = PicPartitionNumDecision (pCtx);
3583       // MT compatibility
3584       pCtx->iActiveThreadsNum =
3585         iPicIPartitionNum; // we try to active number of threads, equal to number of picture partitions
3586       WelsInitCurrentDlayerMltslc (pCtx, iPicIPartitionNum);
3587       break;
3588     }
3589     default: {
3590       break;
3591     }
3592     }
3593 
3594     /* coding each spatial layer, only one sQualityStat layer within spatial support */
3595     int32_t iSliceCount = 1;
3596     if (iLayerNum >= MAX_LAYER_NUM_OF_FRAME) { // check available layer_bs_info writing as follows
3597       WelsLog (pLogCtx, WELS_LOG_ERROR, "WelsEncoderEncodeExt(), iLayerNum(%d) overflow(max:%d)!", iLayerNum,
3598                MAX_LAYER_NUM_OF_FRAME);
3599       return ENC_RETURN_UNSUPPORTED_PARA;
3600     }
3601 
3602     iNalIdxInLayer  = 0;
3603     bAvcBased       = ((pSvcParam->bSimulcastAVC) || (iCurDid == BASE_DEPENDENCY_ID));
3604     pCtx->bNeedPrefixNalFlag    = ((!pSvcParam->bSimulcastAVC) && (bAvcBased &&
3605                                    (pSvcParam->bPrefixNalAddingCtrl ||
3606                                     (pSvcParam->iSpatialLayerNum > 1))));
3607 
3608     if (eFrameType == videoFrameTypeP) {
3609       eNalType = bAvcBased ? NAL_UNIT_CODED_SLICE : NAL_UNIT_CODED_SLICE_EXT;
3610     } else if (eFrameType == videoFrameTypeIDR) {
3611       eNalType = bAvcBased ? NAL_UNIT_CODED_SLICE_IDR : NAL_UNIT_CODED_SLICE_EXT;
3612     }
3613     if (iCurTid == 0 || pCtx->eSliceType == I_SLICE)
3614       eNalRefIdc = NRI_PRI_HIGHEST;
3615     else if (iCurTid == iDecompositionStages)
3616       eNalRefIdc = NRI_PRI_LOWEST;
3617     else if (1 + iCurTid == iDecompositionStages)
3618       eNalRefIdc = NRI_PRI_LOW;
3619     else if (2 + iCurTid == iDecompositionStages)
3620       eNalRefIdc = NRI_PRI_HIGH;
3621     else // more details for other temporal layers?
3622       eNalRefIdc = NRI_PRI_HIGHEST;
3623     pCtx->eNalType = eNalType;
3624     pCtx->eNalPriority = eNalRefIdc;
3625 
3626     pCtx->pDecPic               = pCtx->ppRefPicListExt[iCurDid]->pNextBuffer;
3627 #if defined(ENABLE_FRAME_DUMP) || defined(ENABLE_PSNR_CALC)
3628     fsnr                        = pCtx->pDecPic;
3629 #endif//#if defined(ENABLE_FRAME_DUMP) || defined(ENABLE_PSNR_CALC)
3630     pCtx->pDecPic->iPictureType = pCtx->eSliceType;
3631     pCtx->pDecPic->iFramePoc    = pParamInternal->iPOC;
3632 
3633     WelsInitCurrentLayer (pCtx, iCurWidth, iCurHeight);
3634 
3635     pCtx->pReferenceStrategy->MarkPic();
3636     if (!pCtx->pReferenceStrategy->BuildRefList (pParamInternal->iPOC, 0)) {
3637       WelsLog (pLogCtx, WELS_LOG_WARNING,
3638                "WelsEncoderEncodeExt(), WelsBuildRefList failed for P frames, pCtx->iNumRef0= %d. ForceCodingIDR!",
3639                pCtx->iNumRef0);
3640       eFrameType = videoFrameTypeIDR;
3641       pCtx->iEncoderError = ENC_RETURN_CORRECTED;
3642       break;
3643     }
3644     if (pCtx->eSliceType != I_SLICE) {
3645       pCtx->pReferenceStrategy->AfterBuildRefList();
3646     }
3647 #ifdef LONG_TERM_REF_DUMP
3648     DumpRef (pCtx);
3649 #endif
3650     if (pSvcParam->iRCMode != RC_OFF_MODE)
3651       pCtx->pVpp->AnalyzePictureComplexity (pCtx, pCtx->pEncPic, ((pCtx->eSliceType == P_SLICE)
3652                                             && (pCtx->iNumRef0 > 0)) ? pCtx->pRefList0[0] : NULL,
3653                                             iCurDid, (pCtx->eSliceType == P_SLICE) && pSvcParam->bEnableBackgroundDetection);
3654     WelsUpdateRefSyntax (pCtx,  pParamInternal->iPOC,
3655                          eFrameType); //get reordering syntax used for writing slice header and transmit to encoder.
3656     PrefetchReferencePicture (pCtx, eFrameType); // update reference picture for current pDq layer
3657     pCtx->pFuncList->pfRc.pfWelsRcPictureInit (pCtx, pFbi->uiTimeStamp);
3658     PreprocessSliceCoding (pCtx); // MUST be called after pfWelsRcPictureInit() and WelsInitCurrentLayer()
3659 
3660     //TODO Complexity Calculation here for screen content
3661     iLayerSize = 0;
3662     if (SM_SINGLE_SLICE == pParam->sSliceArgument.uiSliceMode) { // only one slice within a sQualityStat layer
3663       int32_t iSliceSize   = 0;
3664       int32_t iPayloadSize = 0;
3665       SSlice* pCurSlice    = &pCtx->pCurDqLayer->sSliceBufferInfo[0].pSliceBuffer[0];
3666 
3667       if (pCtx->bNeedPrefixNalFlag) {
3668         pCtx->iEncoderError = AddPrefixNal (pCtx, pLayerBsInfo, &pLayerBsInfo->pNalLengthInByte[0], &iNalIdxInLayer, eNalType,
3669                                             eNalRefIdc,
3670                                             iPayloadSize);
3671         WELS_VERIFY_RETURN_IFNEQ (pCtx->iEncoderError, ENC_RETURN_SUCCESS)
3672         iLayerSize += iPayloadSize;
3673       }
3674 
3675       WelsLoadNal (pCtx->pOut, eNalType, eNalRefIdc);
3676       assert (0 == (int) pCurSlice->iSliceIdx);
3677       pCtx->iEncoderError   = SetSliceBoundaryInfo (pCtx->pCurDqLayer, pCurSlice, 0);
3678       WELS_VERIFY_RETURN_IFNEQ (pCtx->iEncoderError, ENC_RETURN_SUCCESS)
3679 
3680       pCtx->iEncoderError   = WelsCodeOneSlice (pCtx, pCurSlice, eNalType);
3681       WELS_VERIFY_RETURN_IFNEQ (pCtx->iEncoderError, ENC_RETURN_SUCCESS)
3682 
3683       WelsUnloadNal (pCtx->pOut);
3684 
3685       pCtx->iEncoderError = WelsEncodeNal (&pCtx->pOut->sNalList[pCtx->pOut->iNalIndex - 1],
3686                                            &pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt,
3687                                            pCtx->iFrameBsSize - pCtx->iPosBsBuffer,
3688                                            pCtx->pFrameBs + pCtx->iPosBsBuffer,
3689                                            &pLayerBsInfo->pNalLengthInByte[iNalIdxInLayer]);
3690       WELS_VERIFY_RETURN_IFNEQ (pCtx->iEncoderError, ENC_RETURN_SUCCESS)
3691       iSliceSize = pLayerBsInfo->pNalLengthInByte[iNalIdxInLayer];
3692 
3693       iLayerSize += iSliceSize;
3694       pCtx->iPosBsBuffer               += iSliceSize;
3695       pLayerBsInfo->uiLayerType         = VIDEO_CODING_LAYER;
3696       pLayerBsInfo->uiSpatialId         = iCurDid;
3697       pLayerBsInfo->uiTemporalId        = iCurTid;
3698       pLayerBsInfo->uiQualityId         = 0;
3699       pLayerBsInfo->iNalCount           = ++ iNalIdxInLayer;
3700       pLayerBsInfo->eFrameType          = eFrameType;
3701       pLayerBsInfo->iSubSeqId = GetSubSequenceId (pCtx, eFrameType);
3702     }
3703     // for dynamic slicing single threading..
3704     else if ((SM_SIZELIMITED_SLICE == pParam->sSliceArgument.uiSliceMode) && (pSvcParam->iMultipleThreadIdc <= 1)) {
3705       const int32_t kiLastMbInFrame = pCtx->pCurDqLayer->sSliceEncCtx.iMbNumInFrame;
3706       pCtx->iEncoderError = WelsCodeOnePicPartition (pCtx, pFbi, pLayerBsInfo, &iNalIdxInLayer, &iLayerSize, 0,
3707                             kiLastMbInFrame - 1, 0);
3708       pLayerBsInfo->eFrameType = eFrameType;
3709       pLayerBsInfo->iSubSeqId = GetSubSequenceId (pCtx, eFrameType);
3710       WELS_VERIFY_RETURN_IFNEQ (pCtx->iEncoderError, ENC_RETURN_SUCCESS)
3711     } else {
3712       //other multi-slice uiSliceMode
3713       // THREAD_FULLY_FIRE_MODE/THREAD_PICK_UP_MODE for any mode of non-SM_SIZELIMITED_SLICE
3714       if ((SM_SIZELIMITED_SLICE != pParam->sSliceArgument.uiSliceMode) && (pSvcParam->iMultipleThreadIdc > 1)) {
3715         iSliceCount = GetCurrentSliceNum (pCtx->pCurDqLayer);
3716         if (iLayerNum + 1 >= MAX_LAYER_NUM_OF_FRAME) { // check available layer_bs_info for further writing as followed
3717           WelsLog (pLogCtx, WELS_LOG_ERROR,
3718                    "WelsEncoderEncodeExt(), iLayerNum(%d) overflow(max:%d) at iDid= %d uiSliceMode= %d, iSliceCount= %d!",
3719                    iLayerNum, MAX_LAYER_NUM_OF_FRAME, iCurDid, pParam->sSliceArgument.uiSliceMode, iSliceCount);
3720           return ENC_RETURN_UNSUPPORTED_PARA;
3721         }
3722         if (iSliceCount <= 1) {
3723           WelsLog (pLogCtx, WELS_LOG_ERROR,
3724                    "WelsEncoderEncodeExt(), iSliceCount(%d) from GetCurrentSliceNum() is untrusted due stack/heap crupted!",
3725                    iSliceCount);
3726           return ENC_RETURN_UNEXPECTED;
3727         }
3728         //note: the old codes are removed at commit: 3e0ee69
3729         pLayerBsInfo->pBsBuf = pCtx->pFrameBs + pCtx->iPosBsBuffer;
3730         pLayerBsInfo->uiLayerType   = VIDEO_CODING_LAYER;
3731         pLayerBsInfo->uiSpatialId   = pCtx->uiDependencyId;
3732         pLayerBsInfo->uiTemporalId  = pCtx->uiTemporalId;
3733         pLayerBsInfo->uiQualityId   = 0;
3734         pLayerBsInfo->iNalCount     = 0;
3735         pLayerBsInfo->eFrameType    = eFrameType;
3736         pLayerBsInfo->iSubSeqId = GetSubSequenceId (pCtx, eFrameType);
3737 
3738         pCtx->pTaskManage->ExecuteTasks();
3739         if (pCtx->iEncoderError) {
3740           WelsLog (pLogCtx, WELS_LOG_ERROR,
3741                    "WelsEncoderEncodeExt(), multi-slice (mode %d) encoding error!",
3742                    pParam->sSliceArgument.uiSliceMode);
3743           return pCtx->iEncoderError;
3744         }
3745 
3746         iLayerSize = AppendSliceToFrameBs (pCtx, pLayerBsInfo, iSliceCount);
3747       }
3748       // THREAD_FULLY_FIRE_MODE && SM_SIZELIMITED_SLICE
3749       else if ((SM_SIZELIMITED_SLICE == pParam->sSliceArgument.uiSliceMode) && (pSvcParam->iMultipleThreadIdc > 1)) {
3750         const int32_t kiPartitionCnt = pCtx->iActiveThreadsNum;
3751 
3752         //TODO: use a function to remove duplicate code here and ln3994
3753         int32_t iLayerBsIdx       = pCtx->pOut->iLayerBsIndex;
3754         SLayerBSInfo* pLbi        = &pFbi->sLayerInfo[iLayerBsIdx];
3755         pLbi->pBsBuf = pCtx->pFrameBs + pCtx->iPosBsBuffer;
3756         pLbi->uiLayerType   = VIDEO_CODING_LAYER;
3757         pLbi->uiSpatialId   = pCtx->uiDependencyId;
3758         pLbi->uiTemporalId  = pCtx->uiTemporalId;
3759         pLbi->uiQualityId   = 0;
3760         pLbi->iNalCount     = 0;
3761         pLbi->eFrameType = eFrameType;
3762         pLbi->iSubSeqId = GetSubSequenceId (pCtx, eFrameType);
3763         int32_t iIdx = 0;
3764         while (iIdx < kiPartitionCnt) {
3765           pCtx->pSliceThreading->pThreadPEncCtx[iIdx].pFrameBsInfo = pFbi;
3766           pCtx->pSliceThreading->pThreadPEncCtx[iIdx].iSliceIndex  = iIdx;
3767           ++ iIdx;
3768         }
3769 
3770         int32_t iRet = InitAllSlicesInThread (pCtx);
3771         if (iRet) {
3772           WelsLog (pLogCtx, WELS_LOG_ERROR,
3773                    "WelsEncoderEncodeExt(), multi-slice (mode %d) InitAllSlicesInThread() error!",
3774                    pParam->sSliceArgument.uiSliceMode);
3775           return ENC_RETURN_UNEXPECTED;
3776         }
3777         pCtx->pTaskManage->ExecuteTasks();
3778 
3779         if (pCtx->iEncoderError) {
3780           WelsLog (pLogCtx, WELS_LOG_ERROR,
3781                    "WelsEncoderEncodeExt(), multi-slice (mode %d) encoding error = %d!",
3782                    pParam->sSliceArgument.uiSliceMode, pCtx->iEncoderError);
3783           return pCtx->iEncoderError;
3784         }
3785 
3786         iRet = SliceLayerInfoUpdate (pCtx, pFbi, pLayerBsInfo, pParam->sSliceArgument.uiSliceMode);
3787         if (iRet) {
3788           WelsLog (pLogCtx, WELS_LOG_ERROR,
3789                    "WelsEncoderEncodeExt(), multi-slice (mode %d) InitAllSlicesInThread() error!",
3790                    pParam->sSliceArgument.uiSliceMode);
3791           return ENC_RETURN_UNEXPECTED;
3792         }
3793 
3794         iSliceCount = GetCurrentSliceNum (pCtx->pCurDqLayer);
3795         iLayerSize  = AppendSliceToFrameBs (pCtx, pLayerBsInfo, iSliceCount);
3796       } else { // for non-dynamic-slicing mode single threading branch..
3797         const bool bNeedPrefix = pCtx->bNeedPrefixNalFlag;
3798         int32_t iSliceIdx    = 0;
3799         SSlice* pCurSlice    = NULL;
3800 
3801         iSliceCount = GetCurrentSliceNum (pCtx->pCurDqLayer);
3802         while (iSliceIdx < iSliceCount) {
3803           int32_t iSliceSize    = 0;
3804           int32_t iPayloadSize  = 0;
3805 
3806           if (bNeedPrefix) {
3807             pCtx->iEncoderError = AddPrefixNal (pCtx, pLayerBsInfo, &pLayerBsInfo->pNalLengthInByte[0], &iNalIdxInLayer, eNalType,
3808                                                 eNalRefIdc,
3809                                                 iPayloadSize);
3810             WELS_VERIFY_RETURN_IFNEQ (pCtx->iEncoderError, ENC_RETURN_SUCCESS)
3811             iLayerSize += iPayloadSize;
3812           }
3813 
3814           WelsLoadNal (pCtx->pOut, eNalType, eNalRefIdc);
3815 
3816           pCurSlice = &pCtx->pCurDqLayer->sSliceBufferInfo[0].pSliceBuffer[iSliceIdx];
3817           assert (iSliceIdx == pCurSlice->iSliceIdx);
3818           pCtx->iEncoderError   = SetSliceBoundaryInfo (pCtx->pCurDqLayer, pCurSlice, iSliceIdx);
3819 
3820           pCtx->iEncoderError = WelsCodeOneSlice (pCtx, pCurSlice, eNalType);
3821           WELS_VERIFY_RETURN_IFNEQ (pCtx->iEncoderError, ENC_RETURN_SUCCESS)
3822 
3823           WelsUnloadNal (pCtx->pOut);
3824 
3825           pCtx->iEncoderError = WelsEncodeNal (&pCtx->pOut->sNalList[pCtx->pOut->iNalIndex - 1],
3826                                                &pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt,
3827                                                pCtx->iFrameBsSize - pCtx->iPosBsBuffer,
3828                                                pCtx->pFrameBs + pCtx->iPosBsBuffer, &pLayerBsInfo->pNalLengthInByte[iNalIdxInLayer]);
3829           WELS_VERIFY_RETURN_IFNEQ (pCtx->iEncoderError, ENC_RETURN_SUCCESS)
3830           iSliceSize = pLayerBsInfo->pNalLengthInByte[iNalIdxInLayer];
3831 
3832           pCtx->iPosBsBuffer += iSliceSize;
3833           iLayerSize         += iSliceSize;
3834 
3835 #if defined(SLICE_INFO_OUTPUT)
3836           fprintf (stderr,
3837                    "@slice=%-6d sliceType:%c idc:%d size:%-6d\n",
3838                    iSliceIdx,
3839                    (pCtx->eSliceType == P_SLICE ? 'P' : 'I'),
3840                    eNalRefIdc,
3841                    iSliceSize);
3842 #endif//SLICE_INFO_OUTPUT
3843           ++ iNalIdxInLayer;
3844           ++ iSliceIdx;
3845         }
3846 
3847         pLayerBsInfo->uiLayerType       = VIDEO_CODING_LAYER;
3848         pLayerBsInfo->uiSpatialId       = iCurDid;
3849         pLayerBsInfo->uiTemporalId      = iCurTid;
3850         pLayerBsInfo->uiQualityId       = 0;
3851         pLayerBsInfo->iNalCount         = iNalIdxInLayer;
3852         pLayerBsInfo->eFrameType        = eFrameType;
3853         pLayerBsInfo->iSubSeqId         = GetSubSequenceId (pCtx, eFrameType);
3854       }
3855     }
3856 
3857     if (NULL != pCtx->pFuncList->pfRc.pfWelsRcPostFrameSkipping
3858         && pCtx->pFuncList->pfRc.pfWelsRcPostFrameSkipping (pCtx, iCurDid, pFbi->uiTimeStamp)) {
3859 
3860       StackBackEncoderStatus (pCtx, eFrameType);
3861       ClearFrameBsInfo (pCtx, pFbi);
3862 
3863       iFrameSize = 0;
3864       iLayerSize = 0;
3865       iLayerNum = 0;
3866 
3867       if (pCtx->pFuncList->pfRc.pfWelsUpdateBufferWhenSkip) {
3868         pCtx->pFuncList->pfRc.pfWelsUpdateBufferWhenSkip (pCtx, iSpatialNum);
3869       }
3870 
3871       WelsRcPostFrameSkippedUpdate (pCtx, iCurDid);
3872       pCtx->iEncoderError = ENC_RETURN_SUCCESS;
3873       return ENC_RETURN_SUCCESS;
3874     }
3875 
3876     // deblocking filter
3877     if (
3878       (!pCtx->pCurDqLayer->bDeblockingParallelFlag) &&
3879 #if !defined(ENABLE_FRAME_DUMP)
3880       ((eNalRefIdc != NRI_PRI_LOWEST) && (pSvcParam->sDependencyLayers[iCurDid].iHighestTemporalId == 0
3881                                           || iCurTid < pSvcParam->sDependencyLayers[iCurDid].iHighestTemporalId)) &&
3882 #endif//!ENABLE_FRAME_DUMP
3883       true
3884     ) {
3885       PerformDeblockingFilter (pCtx);
3886     }
3887 
3888     pCtx->pFuncList->pfRc.pfWelsRcPictureInfoUpdate (pCtx, iLayerSize);
3889     iFrameSize += iLayerSize;
3890     RcTraceFrameBits (pCtx, pFbi->uiTimeStamp, iFrameSize);
3891     pCtx->pDecPic->iFrameAverageQp = pCtx->pWelsSvcRc[iCurDid].iAverageFrameQp;
3892 
3893     //update scc related
3894     pCtx->pFuncList->pfUpdateFMESwitch (pCtx->pCurDqLayer);
3895 
3896     // reference picture list update
3897     if (eNalRefIdc != NRI_PRI_LOWEST) {
3898       if (!pCtx->pReferenceStrategy->UpdateRefList()) {
3899         WelsLog (pLogCtx, WELS_LOG_WARNING, "WelsEncoderEncodeExt(), WelsUpdateRefList failed. ForceCodingIDR!");
3900         //the above is to set the next frame to be IDR
3901         pCtx->iEncoderError = ENC_RETURN_CORRECTED;
3902         break;
3903       }
3904     }
3905 
3906 
3907     //check MinCr
3908     {
3909       int32_t iMinCrFrameSize = (pParam->iVideoWidth * pParam->iVideoHeight * 3) >> 2; //MinCr = 2;
3910       if (pParam->uiLevelIdc == LEVEL_3_1 || pParam->uiLevelIdc == LEVEL_3_2 || pParam->uiLevelIdc == LEVEL_4_0)
3911         iMinCrFrameSize >>= 1; //MinCr = 4
3912       if (iFrameSize > iMinCrFrameSize)
3913         WelsLog (pLogCtx, WELS_LOG_WARNING,
3914                  "WelsEncoderEncodeExt()MinCr Checking,codec bitstream size is larger than Level limitation");
3915     }
3916 #ifdef ENABLE_FRAME_DUMP
3917     {
3918       DumpDependencyRec (fsnr, &pSvcParam->sDependencyLayers[iCurDid].sRecFileName[0], iCurDid,
3919                          pCtx->bDependencyRecFlag[iCurDid], pCtx->pCurDqLayer, pSvcParam->bSimulcastAVC);
3920       pCtx->bDependencyRecFlag[iCurDid] = true;
3921     }
3922 #endif//ENABLE_FRAME_DUMP
3923 
3924 #if defined(ENABLE_PSNR_CALC)
3925     fSnrY = WelsCalcPsnr (fsnr->pData[0],
3926                           fsnr->iLineSize[0],
3927                           pEncPic->pData[0],
3928                           pEncPic->iLineSize[0],
3929                           iCurWidth,
3930                           iCurHeight);
3931     fSnrU = WelsCalcPsnr (fsnr->pData[1],
3932                           fsnr->iLineSize[1],
3933                           pEncPic->pData[1],
3934                           pEncPic->iLineSize[1],
3935                           (iCurWidth >> 1),
3936                           (iCurHeight >> 1));
3937     fSnrV = WelsCalcPsnr (fsnr->pData[2],
3938                           fsnr->iLineSize[2],
3939                           pEncPic->pData[2],
3940                           pEncPic->iLineSize[2],
3941                           (iCurWidth >> 1),
3942                           (iCurHeight >> 1));
3943 #endif//ENABLE_PSNR_CALC
3944 
3945 #if defined(LAYER_INFO_OUTPUT)
3946     fprintf (stderr, "%2s %5d: %-5d %2s   T%1d D%1d Q%-2d  QP%3d   Y%2.2f  U%2.2f  V%2.2f  %8d bits\n",
3947              (iSpatialIdx == 0) ? "#AU" : "   ",
3948              pParamInternal->iPOC,
3949              pParamInternal->iFrameNum,
3950              (eFrameType == videoFrameTypeI || eFrameType == videoFrameTypeIDR) ? "I" : "P",
3951              iCurTid,
3952              iCurDid,
3953              0,
3954              pCtx->pWelsSvcRc[pCtx->uiDependencyId].iAverageFrameQp,
3955              fSnrY,
3956              fSnrU,
3957              fSnrV,
3958              (iLayerSize << 3));
3959 #endif//LAYER_INFO_OUTPUT
3960 
3961 #if defined(STAT_OUTPUT)
3962 
3963 #if defined(ENABLE_PSNR_CALC)
3964     {
3965       pCtx->sStatData[iCurDid][0].sQualityStat.rYPsnr[pCtx->eSliceType] += fSnrY;
3966       pCtx->sStatData[iCurDid][0].sQualityStat.rUPsnr[pCtx->eSliceType] += fSnrU;
3967       pCtx->sStatData[iCurDid][0].sQualityStat.rVPsnr[pCtx->eSliceType] += fSnrV;
3968     }
3969 #endif//ENABLE_PSNR_CALC
3970 
3971 #if defined(MB_TYPES_CHECK) //091025, frame output
3972     if (pCtx->eSliceType == P_SLICE) {
3973       pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][Intra4x4] += pCtx->sPerInfo.iMbCount[P_SLICE][Intra4x4];
3974       pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][Intra16x16] += pCtx->sPerInfo.iMbCount[P_SLICE][Intra16x16];
3975       pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][Inter16x16] += pCtx->sPerInfo.iMbCount[P_SLICE][Inter16x16];
3976       pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][Inter16x8] += pCtx->sPerInfo.iMbCount[P_SLICE][Inter16x8];
3977       pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][Inter8x16] += pCtx->sPerInfo.iMbCount[P_SLICE][Inter8x16];
3978       pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][Inter8x8] += pCtx->sPerInfo.iMbCount[P_SLICE][Inter8x8];
3979       pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][PSkip] += pCtx->sPerInfo.iMbCount[P_SLICE][PSkip];
3980       pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][8] += pCtx->sPerInfo.iMbCount[P_SLICE][8];
3981       pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][9] += pCtx->sPerInfo.iMbCount[P_SLICE][9];
3982       pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][10] += pCtx->sPerInfo.iMbCount[P_SLICE][10];
3983       pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[P_SLICE][11] += pCtx->sPerInfo.iMbCount[P_SLICE][11];
3984     } else if (pCtx->eSliceType == I_SLICE) {
3985       pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[I_SLICE][Intra4x4] += pCtx->sPerInfo.iMbCount[I_SLICE][Intra4x4];
3986       pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[I_SLICE][Intra16x16] += pCtx->sPerInfo.iMbCount[I_SLICE][Intra16x16];
3987       pCtx->sStatData[iCurDid][0].sSliceData.iMbCount[I_SLICE][7] += pCtx->sPerInfo.iMbCount[I_SLICE][7];
3988     }
3989 
3990     memset (pCtx->sPerInfo.iMbCount[P_SLICE], 0, 18 * sizeof (int32_t));
3991     memset (pCtx->sPerInfo.iMbCount[I_SLICE], 0, 18 * sizeof (int32_t));
3992 
3993 #endif//MB_TYPES_CHECK
3994     {
3995       ++ pCtx->sStatData[iCurDid][0].sSliceData.iSliceCount[pCtx->eSliceType]; // for multiple slices coding
3996       pCtx->sStatData[iCurDid][0].sSliceData.iSliceSize[pCtx->eSliceType] += (iLayerSize << 3); // bits
3997     }
3998 #endif//STAT_OUTPUT
3999 
4000     iCountNal = pLayerBsInfo->iNalCount;
4001     ++ iLayerNum;
4002     ++ pLayerBsInfo;
4003     ++ pCtx->pOut->iLayerBsIndex;
4004     pLayerBsInfo->pBsBuf = pCtx->pFrameBs + pCtx->iPosBsBuffer;
4005     pLayerBsInfo->pNalLengthInByte = (pLayerBsInfo - 1)->pNalLengthInByte + iCountNal;
4006 
4007     if (pSvcParam->iPaddingFlag && pCtx->pWelsSvcRc[pCtx->uiDependencyId].iPaddingSize > 0) {
4008       int32_t iPaddingNalSize = 0;
4009       pCtx->iEncoderError =  WritePadding (pCtx, pCtx->pWelsSvcRc[pCtx->uiDependencyId].iPaddingSize, iPaddingNalSize);
4010       WELS_VERIFY_RETURN_IFNEQ (pCtx->iEncoderError, ENC_RETURN_SUCCESS)
4011 
4012 #if GOM_TRACE_FLAG
4013       WelsLog (pLogCtx, WELS_LOG_INFO, "[RC] dependency ID = %d,encoding_qp = %d Padding: %d", pCtx->uiDependencyId,
4014                pCtx->iGlobalQp,
4015                pCtx->pWelsSvcRc[pCtx->uiDependencyId].iPaddingSize);
4016 #endif
4017       if (iPaddingNalSize <= 0)
4018         return ENC_RETURN_UNEXPECTED;
4019 
4020       pCtx->pWelsSvcRc[pCtx->uiDependencyId].iPaddingBitrateStat += pCtx->pWelsSvcRc[pCtx->uiDependencyId].iPaddingSize;
4021 
4022       pCtx->pWelsSvcRc[pCtx->uiDependencyId].iPaddingSize = 0;
4023 
4024       pLayerBsInfo->uiSpatialId         = 0;
4025       pLayerBsInfo->uiTemporalId        = 0;
4026       pLayerBsInfo->uiQualityId         = 0;
4027       pLayerBsInfo->uiLayerType         = NON_VIDEO_CODING_LAYER;
4028       pLayerBsInfo->iNalCount           = 1;
4029       pLayerBsInfo->pNalLengthInByte[0] = iPaddingNalSize;
4030       pLayerBsInfo->eFrameType          = eFrameType;
4031       pLayerBsInfo->iSubSeqId = GetSubSequenceId (pCtx, eFrameType);
4032       ++ pLayerBsInfo;
4033       ++ pCtx->pOut->iLayerBsIndex;
4034       pLayerBsInfo->pBsBuf           = pCtx->pFrameBs + pCtx->iPosBsBuffer;
4035       pLayerBsInfo->pNalLengthInByte = (pLayerBsInfo - 1)->pNalLengthInByte + 1;
4036       ++ iLayerNum;
4037 
4038       iFrameSize += iPaddingNalSize;
4039     }
4040 
4041     if ((pParam->sSliceArgument.uiSliceMode == SM_FIXEDSLCNUM_SLICE)
4042         && pSvcParam->bUseLoadBalancing
4043         && pSvcParam->iMultipleThreadIdc > 1 &&
4044         pSvcParam->iMultipleThreadIdc >= pParam->sSliceArgument.uiSliceNum) {
4045       CalcSliceComplexRatio (pCtx->pCurDqLayer);
4046 #if defined(MT_DEBUG)
4047       TrackSliceComplexities (pCtx, iCurDid);
4048 #endif//#if defined(MT_DEBUG)
4049     }
4050 
4051     pCtx->eLastNalPriority[iCurDid] = eNalRefIdc;
4052     ++ iSpatialIdx;
4053 
4054     if (iCurDid + 1 < pSvcParam->iSpatialLayerNum) {
4055       //for next layer, note that iSpatialIdx has been ++ so it is pointer to next layer
4056       WelsSwapDqLayers (pCtx, (pSpatialIndexMap + iSpatialIdx)->iDid);
4057     }
4058 
4059     if (pCtx->pVpp->UpdateSpatialPictures (pCtx, pSvcParam, iCurTid, iCurDid) != 0) {
4060       ForceCodingIDR (pCtx, iCurDid);
4061       WelsLog (pLogCtx, WELS_LOG_WARNING,
4062                "WelsEncoderEncodeExt(), Logic Error Found in Preprocess updating. ForceCodingIDR!");
4063       //the above is to set the next frame IDR
4064       pFbi->eFrameType = eFrameType;
4065       pLayerBsInfo->eFrameType = eFrameType;
4066       return ENC_RETURN_CORRECTED;
4067     }
4068 
4069     if (pSvcParam->bEnableLongTermReference && ((pCtx->pLtr[pCtx->uiDependencyId].bLTRMarkingFlag
4070         && (pCtx->pLtr[pCtx->uiDependencyId].iLTRMarkMode == LTR_DIRECT_MARK)) || eFrameType == videoFrameTypeIDR)) {
4071       pCtx->bRefOfCurTidIsLtr[iCurDid][iCurTid] = true;
4072     }
4073     if (pSvcParam->bSimulcastAVC)
4074       ++ pParamInternal->iCodingIndex;
4075   }//end of (iSpatialIdx/iSpatialNum)
4076 
4077   if (!pSvcParam->bSimulcastAVC) {
4078     for (int32_t i = 0; i < pSvcParam->iSpatialLayerNum; i++) {
4079       SSpatialLayerInternal* pParamInternal = &pSvcParam->sDependencyLayers[i];
4080       pParamInternal->iCodingIndex ++;
4081     }
4082   }
4083 
4084   if (ENC_RETURN_CORRECTED == pCtx->iEncoderError) {
4085     pCtx->pVpp->UpdateSpatialPictures (pCtx, pSvcParam, iCurTid, (pSpatialIndexMap + iSpatialIdx)->iDid);
4086     ForceCodingIDR (pCtx, (pSpatialIndexMap + iSpatialIdx)->iDid);
4087     WelsLog (pLogCtx, WELS_LOG_ERROR, "WelsEncoderEncodeExt(), Logic Error Found in temporal level. ForceCodingIDR!");
4088     //the above is to set the next frame IDR
4089     pFbi->eFrameType = eFrameType;
4090     pLayerBsInfo->eFrameType = eFrameType;
4091     return ENC_RETURN_CORRECTED;
4092   }
4093 
4094 #if defined(MT_DEBUG)
4095   TrackSliceConsumeTime (pCtx, iDidList, iSpatialNum);
4096 #endif//MT_DEBUG
4097 
4098   // to check number of layers / nals / slices dependencies
4099   if (iLayerNum > MAX_LAYER_NUM_OF_FRAME) {
4100     WelsLog (& pCtx->sLogCtx, WELS_LOG_ERROR, "WelsEncoderEncodeExt(), iLayerNum(%d) > MAX_LAYER_NUM_OF_FRAME(%d)!",
4101              iLayerNum, MAX_LAYER_NUM_OF_FRAME);
4102     return 1;
4103   }
4104 
4105 
4106   pFbi->iLayerNum = iLayerNum;
4107 
4108   WelsLog (pLogCtx, WELS_LOG_DEBUG, "WelsEncoderEncodeExt() OutputInfo iLayerNum = %d,iFrameSize = %d",
4109            iLayerNum, iFrameSize);
4110   for (int32_t i = 0; i < iLayerNum; i++)
4111     WelsLog (pLogCtx, WELS_LOG_DEBUG,
4112              "WelsEncoderEncodeExt() OutputInfo iLayerId = %d,iNalType = %d,iNalCount = %d, first Nal Length=%d,uiSpatialId = %d,uiTemporalId = %d,iSubSeqId = %d",
4113              i,
4114              pFbi->sLayerInfo[i].uiLayerType, pFbi->sLayerInfo[i].iNalCount, pFbi->sLayerInfo[i].pNalLengthInByte[0],
4115              pFbi->sLayerInfo[i].uiSpatialId, pFbi->sLayerInfo[i].uiTemporalId, pFbi->sLayerInfo[i].iSubSeqId);
4116   WelsEmms();
4117 
4118   pLayerBsInfo->eFrameType = eFrameType;
4119   pFbi->iFrameSizeInBytes = iFrameSize;
4120   pFbi->eFrameType = eFrameType;
4121   for (int32_t k = 0; k < pFbi->iLayerNum; k++) {
4122     if (pFbi->eFrameType != pFbi->sLayerInfo[k].eFrameType) {
4123       pFbi->eFrameType = videoFrameTypeIPMixed;
4124     }
4125   }
4126 #ifdef _DEBUG
4127   if (pFbi->iLayerNum > MAX_LAYER_NUM_OF_FRAME) {
4128     WelsLog (& pCtx->sLogCtx, WELS_LOG_ERROR, "WelsEncoderEncodeExt(), iLayerNum(%d) > MAX_LAYER_NUM_OF_FRAME(%d)!",
4129              pFbi->iLayerNum, MAX_LAYER_NUM_OF_FRAME);
4130     return ENC_RETURN_UNEXPECTED;
4131   }
4132 
4133   int32_t iTotalNal = 0;
4134   for (int32_t k = 0; k < pFbi->iLayerNum; k++) {
4135     iTotalNal += pFbi->sLayerInfo[k].iNalCount;
4136 
4137     if ((pCtx->iActiveThreadsNum > 1) && (MAX_NAL_UNITS_IN_LAYER < pFbi->sLayerInfo[k].iNalCount)) {
4138       WelsLog (& pCtx->sLogCtx, WELS_LOG_ERROR,
4139                "WelsEncoderEncodeExt(), iCountNumNals(%d) > MAX_NAL_UNITS_IN_LAYER(%d) under multi-thread(%d) NOT supported!",
4140                pFbi->sLayerInfo[k].iNalCount, MAX_NAL_UNITS_IN_LAYER, pCtx->iActiveThreadsNum);
4141       return ENC_RETURN_UNEXPECTED;
4142     }
4143   }
4144 
4145   if (iTotalNal > pCtx->pOut->iCountNals) {
4146     WelsLog (& pCtx->sLogCtx, WELS_LOG_ERROR, "WelsEncoderEncodeExt(), iTotalNal(%d) > iCountNals(%d)!",
4147              iTotalNal, pCtx->pOut->iCountNals);
4148     return ENC_RETURN_UNEXPECTED;
4149   }
4150 #endif
4151   return ENC_RETURN_SUCCESS;
4152 }
4153 
4154 /*!
4155  * \brief   Wels SVC encoder parameters adjustment
4156  *          SVC adjustment results in new requirement in memory blocks adjustment
4157  */
WelsEncoderParamAdjust(sWelsEncCtx ** ppCtx,SWelsSvcCodingParam * pNewParam)4158 int32_t WelsEncoderParamAdjust (sWelsEncCtx** ppCtx, SWelsSvcCodingParam* pNewParam) {
4159   SWelsSvcCodingParam* pOldParam = NULL;
4160   int32_t iReturn = ENC_RETURN_SUCCESS;
4161   int8_t iIndexD = 0;
4162   bool bNeedReset = false;
4163   int16_t iSliceNum = 1; // number of slices used
4164   int32_t iCacheLineSize = 16; // on chip cache line size in byte
4165   uint32_t uiCpuFeatureFlags = 0;
4166 
4167   if (NULL == ppCtx || NULL == *ppCtx || NULL == pNewParam) return 1;
4168 
4169   /* Check validation in new parameters */
4170   iReturn = ParamValidationExt (& (*ppCtx)->sLogCtx, pNewParam);
4171   if (iReturn != ENC_RETURN_SUCCESS) return iReturn;
4172 
4173   iReturn = GetMultipleThreadIdc (& (*ppCtx)->sLogCtx, pNewParam, iSliceNum, iCacheLineSize, uiCpuFeatureFlags);
4174   if (iReturn != ENC_RETURN_SUCCESS) {
4175     WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_ERROR, "WelsEncoderParamAdjust(), GetMultipleThreadIdc failed return %d.",
4176              iReturn);
4177     return iReturn;
4178   }
4179 
4180   pOldParam = (*ppCtx)->pSvcParam;
4181 
4182   if (pOldParam->iUsageType != pNewParam->iUsageType) {
4183     WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_ERROR,
4184              "WelsEncoderParamAdjust(), does not expect in-middle change of iUsgaeType from %d to %d", pOldParam->iUsageType,
4185              pNewParam->iUsageType);
4186     return ENC_RETURN_UNSUPPORTED_PARA;
4187   }
4188 
4189   /* Decide whether need reset for IDR frame based on adjusting prarameters changed */
4190   /* Temporal levels, spatial settings and/ or quality settings changed need update parameter sets related. */
4191   bNeedReset = (pOldParam == NULL) ||
4192                (pOldParam->bSimulcastAVC != pNewParam->bSimulcastAVC) ||
4193                (pOldParam->iSpatialLayerNum != pNewParam->iSpatialLayerNum) ||
4194                (pOldParam->iPicWidth != pNewParam->iPicWidth
4195                 || pOldParam->iPicHeight != pNewParam->iPicHeight) ||
4196                (pOldParam->SUsedPicRect.iWidth != pNewParam->SUsedPicRect.iWidth
4197                 || pOldParam->SUsedPicRect.iHeight != pNewParam->SUsedPicRect.iHeight) ||
4198                (pOldParam->bEnableLongTermReference != pNewParam->bEnableLongTermReference) ||
4199                (pOldParam->iLTRRefNum != pNewParam->iLTRRefNum) ||
4200                (pOldParam->iMultipleThreadIdc != pNewParam->iMultipleThreadIdc) ||
4201                (pOldParam->bEnableBackgroundDetection != pNewParam->bEnableBackgroundDetection) ||
4202                (pOldParam->bEnableAdaptiveQuant != pNewParam->bEnableAdaptiveQuant) ||
4203                (pOldParam->eSpsPpsIdStrategy != pNewParam->eSpsPpsIdStrategy);
4204   if ((pNewParam->iMaxNumRefFrame > pOldParam->iMaxNumRefFrame) ||
4205       ((pOldParam->iMaxNumRefFrame == 1) && (pOldParam->iTemporalLayerNum == 1) && (pNewParam->iTemporalLayerNum == 2))) {
4206     bNeedReset = true;
4207   }
4208   if (bNeedReset) {
4209     WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_INFO,
4210              "WelsEncoderParamAdjust(),bSimulcastAVC(%d,%d),iSpatialLayerNum(%d,%d),iPicWidth(%d,%d),iPicHeight(%d,%d),Rect.iWidth(%d,%d),Rect.iHeight(%d,%d)",
4211              pOldParam->bSimulcastAVC, pNewParam->bSimulcastAVC,
4212              pOldParam->iSpatialLayerNum, pNewParam->iSpatialLayerNum,
4213              pOldParam->iPicWidth, pNewParam->iPicWidth,
4214              pOldParam->iPicHeight, pNewParam->iPicHeight,
4215              pOldParam->SUsedPicRect.iWidth, pNewParam->SUsedPicRect.iWidth,
4216              pOldParam->SUsedPicRect.iHeight, pNewParam->SUsedPicRect.iHeight);
4217 
4218     WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_INFO,
4219              "WelsEncoderParamAdjust(),bEnableLongTermReference(%d,%d),iLTRRefNum(%d,%d),iMultipleThreadIdc(%d,%d),bEnableBackgroundDetection(%d,%d),bEnableAdaptiveQuant(%d,%d),eSpsPpsIdStrategy(%d,%d),iMaxNumRefFrame(%d,%d),iTemporalLayerNum(%d,%d)",
4220              pOldParam->bEnableLongTermReference, pNewParam->bEnableLongTermReference,
4221              pOldParam->iLTRRefNum, pNewParam->iLTRRefNum,
4222              pOldParam->iMultipleThreadIdc, pNewParam->iMultipleThreadIdc,
4223              pOldParam->bEnableBackgroundDetection, pNewParam->bEnableBackgroundDetection,
4224              pOldParam->bEnableAdaptiveQuant, pNewParam->bEnableAdaptiveQuant,
4225              pOldParam->eSpsPpsIdStrategy, pNewParam->eSpsPpsIdStrategy,
4226              pOldParam->iMaxNumRefFrame, pNewParam->iMaxNumRefFrame,
4227              pOldParam->iTemporalLayerNum, pNewParam->iTemporalLayerNum);
4228   }
4229   if (!bNeedReset) { // Check its picture resolutions/quality settings respectively in each dependency layer
4230     iIndexD = 0;
4231     assert (pOldParam->iSpatialLayerNum == pNewParam->iSpatialLayerNum);
4232     do {
4233       const SSpatialLayerInternal* kpOldDlp     = &pOldParam->sDependencyLayers[iIndexD];
4234       const SSpatialLayerInternal* kpNewDlp     = &pNewParam->sDependencyLayers[iIndexD];
4235       float fT1 = .0f;
4236       float fT2 = .0f;
4237 
4238       // check frame size settings
4239       if (pOldParam->sSpatialLayers[iIndexD].iVideoWidth != pNewParam->sSpatialLayers[iIndexD].iVideoWidth ||
4240           pOldParam->sSpatialLayers[iIndexD].iVideoHeight != pNewParam->sSpatialLayers[iIndexD].iVideoHeight ||
4241           kpOldDlp->iActualWidth != kpNewDlp->iActualWidth ||
4242           kpOldDlp->iActualHeight != kpNewDlp->iActualHeight) {
4243         bNeedReset = true;
4244         WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_INFO,
4245                  "WelsEncoderParamAdjust(),iIndexD = %d,sSpatialLayers.wxh_old(%d,%d),sSpatialLayers.wxh_new(%d,%d),iActualwxh_old(%d,%d),iActualwxh_new(%d,%d)",
4246                  iIndexD, pOldParam->sSpatialLayers[iIndexD].iVideoWidth, pOldParam->sSpatialLayers[iIndexD].iVideoHeight,
4247                  pNewParam->sSpatialLayers[iIndexD].iVideoWidth, pNewParam->sSpatialLayers[iIndexD].iVideoHeight,
4248                  kpOldDlp->iActualWidth, kpOldDlp->iActualHeight,
4249                  kpNewDlp->iActualWidth, kpNewDlp->iActualHeight);
4250         break;
4251       }
4252 
4253       if (pOldParam->sSpatialLayers[iIndexD].sSliceArgument.uiSliceMode !=
4254           pNewParam->sSpatialLayers[iIndexD].sSliceArgument.uiSliceMode
4255           ||
4256           pOldParam->sSpatialLayers[iIndexD].sSliceArgument.uiSliceNum !=
4257           pNewParam->sSpatialLayers[iIndexD].sSliceArgument.uiSliceNum) {
4258 
4259         bNeedReset = true;
4260         WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_INFO,
4261                  "WelsEncoderParamAdjust(),iIndexD = %d,uiSliceMode (%d,%d),uiSliceNum(%d,%d)", iIndexD,
4262                  pOldParam->sSpatialLayers[iIndexD].sSliceArgument.uiSliceMode,
4263                  pNewParam->sSpatialLayers[iIndexD].sSliceArgument.uiSliceMode,
4264                  pOldParam->sSpatialLayers[iIndexD].sSliceArgument.uiSliceNum,
4265                  pNewParam->sSpatialLayers[iIndexD].sSliceArgument.uiSliceNum);
4266 
4267         break;
4268       }
4269 
4270       // check frame rate
4271       // we can not check whether corresponding fFrameRate is equal or not,
4272       // only need to check d_max/d_min and max_fr/d_max whether it is equal or not
4273       if (kpNewDlp->fInputFrameRate > EPSN && kpOldDlp->fInputFrameRate > EPSN)
4274         fT1 = kpNewDlp->fOutputFrameRate / kpNewDlp->fInputFrameRate - kpOldDlp->fOutputFrameRate / kpOldDlp->fInputFrameRate;
4275       if (kpNewDlp->fOutputFrameRate > EPSN && kpOldDlp->fOutputFrameRate > EPSN)
4276         fT2 = pNewParam->fMaxFrameRate / kpNewDlp->fOutputFrameRate - pOldParam->fMaxFrameRate / kpOldDlp->fOutputFrameRate;
4277       if (fT1 > EPSN || fT1 < -EPSN || fT2 > EPSN || fT2 < -EPSN) {
4278         bNeedReset = true;
4279         WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_INFO,
4280                  "WelsEncoderParamAdjust() iIndexD = %d,fInputFrameRate(%f,%f),fOutputFrameRate(%f,%f),fMaxFrameRate(%f,%f)", iIndexD,
4281                  kpOldDlp->fInputFrameRate, kpNewDlp->fInputFrameRate,
4282                  kpOldDlp->fOutputFrameRate, kpNewDlp->fOutputFrameRate,
4283                  pOldParam->fMaxFrameRate, pNewParam->fMaxFrameRate);
4284         break;
4285       }
4286       if (pOldParam->sSpatialLayers[iIndexD].uiProfileIdc != pNewParam->sSpatialLayers[iIndexD].uiProfileIdc) {
4287         bNeedReset = true;
4288         WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_INFO,
4289                  "WelsEncoderParamAdjust(),iIndexD = %d,uiProfileIdc(%d,%d)", iIndexD,
4290                  pOldParam->sSpatialLayers[iIndexD].uiProfileIdc, pNewParam->sSpatialLayers[iIndexD].uiProfileIdc);
4291         break;
4292       }
4293       //check level change,if new level is smaller than old level,don't reset encoder. still use old level.
4294 
4295       if (pNewParam->sSpatialLayers[iIndexD].uiLevelIdc > pOldParam->sSpatialLayers[iIndexD].uiLevelIdc) {
4296         bNeedReset = true;
4297         WelsLog (& (*ppCtx)->sLogCtx, WELS_LOG_INFO,
4298                  "WelsEncoderParamAdjust(),iIndexD = %d,uiLevelIdc(%d,%d)", iIndexD,
4299                  pOldParam->sSpatialLayers[iIndexD].uiLevelIdc, pNewParam->sSpatialLayers[iIndexD].uiLevelIdc);
4300         break;
4301       }
4302       ++ iIndexD;
4303     } while (iIndexD < pOldParam->iSpatialLayerNum);
4304   }
4305 
4306   if (bNeedReset) {
4307     SLogContext sLogCtx = (*ppCtx)->sLogCtx;
4308 
4309     int32_t iOldSpsPpsIdStrategy = pOldParam->eSpsPpsIdStrategy;
4310     SParaSetOffsetVariable sTmpPsoVariable[PARA_SET_TYPE];
4311     int32_t  iTmpPpsIdList[MAX_DQ_LAYER_NUM * MAX_PPS_COUNT];
4312     //for LTR or SPS,PPS ID update
4313     uint16_t uiMaxIdrPicId = 0;
4314     for (iIndexD = 0; iIndexD < pOldParam->iSpatialLayerNum; iIndexD++) {
4315       if (pOldParam->sDependencyLayers[iIndexD].uiIdrPicId > uiMaxIdrPicId)
4316         uiMaxIdrPicId = pOldParam->sDependencyLayers[iIndexD].uiIdrPicId;
4317     }
4318 
4319     //for sEncoderStatistics
4320     SEncoderStatistics sTempEncoderStatistics[MAX_DEPENDENCY_LAYER];
4321     memcpy (sTempEncoderStatistics, (*ppCtx)->sEncoderStatistics, sizeof (sTempEncoderStatistics));
4322     int64_t            uiStartTimestamp = (*ppCtx)->uiStartTimestamp;
4323     int32_t            iStatisticsLogInterval = (*ppCtx)->iStatisticsLogInterval;
4324     int64_t            iLastStatisticsLogTs = (*ppCtx)->iLastStatisticsLogTs;
4325     //for sEncoderStatistics
4326 
4327     SExistingParasetList sExistingParasetList;
4328     SExistingParasetList* pExistingParasetList = NULL;
4329 
4330     if (((CONSTANT_ID != iOldSpsPpsIdStrategy) && (CONSTANT_ID != pNewParam->eSpsPpsIdStrategy))) {
4331       (*ppCtx)->pFuncList->pParametersetStrategy->OutputCurrentStructure (sTmpPsoVariable, iTmpPpsIdList, (*ppCtx),
4332           &sExistingParasetList);
4333 
4334       if ((SPS_LISTING & iOldSpsPpsIdStrategy)
4335           && (SPS_LISTING & pNewParam->eSpsPpsIdStrategy)) {
4336         pExistingParasetList = &sExistingParasetList;
4337       }
4338     }
4339 
4340     WelsUninitEncoderExt (ppCtx);
4341 
4342     /* Update new parameters */
4343     if (WelsInitEncoderExt (ppCtx, pNewParam, &sLogCtx, pExistingParasetList))
4344       return 1;
4345     //if WelsInitEncoderExt succeed
4346     //for LTR or SPS,PPS ID update
4347     for (iIndexD = 0; iIndexD < pNewParam->iSpatialLayerNum; iIndexD++) {
4348       (*ppCtx)->pSvcParam->sDependencyLayers[iIndexD].uiIdrPicId = uiMaxIdrPicId;
4349     }
4350 
4351     //for sEncoderStatistics
4352     memcpy ((*ppCtx)->sEncoderStatistics, sTempEncoderStatistics, sizeof (sTempEncoderStatistics));
4353     (*ppCtx)->uiStartTimestamp = uiStartTimestamp;
4354     (*ppCtx)->iStatisticsLogInterval = iStatisticsLogInterval;
4355     (*ppCtx)->iLastStatisticsLogTs = iLastStatisticsLogTs;
4356     //for sEncoderStatistics
4357 
4358     //load back the needed structure for eSpsPpsIdStrategy
4359     if (((CONSTANT_ID != iOldSpsPpsIdStrategy) && (CONSTANT_ID != pNewParam->eSpsPpsIdStrategy))
4360         || ((SPS_PPS_LISTING == iOldSpsPpsIdStrategy)
4361             && (SPS_PPS_LISTING == pNewParam->eSpsPpsIdStrategy))) {
4362       (*ppCtx)->pFuncList->pParametersetStrategy->LoadPreviousStructure (sTmpPsoVariable, iTmpPpsIdList);
4363     }
4364   } else {
4365     /* maybe adjustment introduced in bitrate or little settings adjustment and so on.. */
4366     pNewParam->iNumRefFrame                     = WELS_CLIP3 (pNewParam->iNumRefFrame, MIN_REF_PIC_COUNT,
4367         (pNewParam->iUsageType == CAMERA_VIDEO_REAL_TIME ? MAX_REFERENCE_PICTURE_COUNT_NUM_CAMERA :
4368          MAX_REFERENCE_PICTURE_COUNT_NUM_SCREEN));
4369     pNewParam->iLoopFilterDisableIdc            = WELS_CLIP3 (pNewParam->iLoopFilterDisableIdc, 0, 6);
4370     pNewParam->iLoopFilterAlphaC0Offset         = WELS_CLIP3 (pNewParam->iLoopFilterAlphaC0Offset, -6, 6);
4371     pNewParam->iLoopFilterBetaOffset            = WELS_CLIP3 (pNewParam->iLoopFilterBetaOffset, -6, 6);
4372     pNewParam->fMaxFrameRate                    = WELS_CLIP3 (pNewParam->fMaxFrameRate, MIN_FRAME_RATE, MAX_FRAME_RATE);
4373 
4374     // we can not use direct struct based memcpy due some fields need keep unchanged as before
4375     pOldParam->fMaxFrameRate    = pNewParam->fMaxFrameRate;             // maximal frame rate [Hz / fps]
4376     pOldParam->iComplexityMode  = pNewParam->iComplexityMode;                   // color space of input sequence
4377     pOldParam->uiIntraPeriod    = pNewParam->uiIntraPeriod;             // intra period (multiple of GOP size as desired)
4378     pOldParam->eSpsPpsIdStrategy = pNewParam->eSpsPpsIdStrategy;
4379     pOldParam->bPrefixNalAddingCtrl = pNewParam->bPrefixNalAddingCtrl;
4380     pOldParam->iNumRefFrame     = pNewParam->iNumRefFrame;              // number of reference frame used
4381     pOldParam->uiGopSize = pNewParam->uiGopSize;
4382     if (pOldParam->iTemporalLayerNum != pNewParam->iTemporalLayerNum) {
4383       pOldParam->iTemporalLayerNum = pNewParam->iTemporalLayerNum;
4384       for (int32_t iIndexD = 0; iIndexD < MAX_DEPENDENCY_LAYER; iIndexD++)
4385         pOldParam->sDependencyLayers[iIndexD].iCodingIndex = 0;
4386     }
4387     pOldParam->iDecompStages = pNewParam->iDecompStages;
4388     /* denoise control */
4389     pOldParam->bEnableDenoise = pNewParam->bEnableDenoise;
4390 
4391     /* background detection control */
4392     pOldParam->bEnableBackgroundDetection = pNewParam->bEnableBackgroundDetection;
4393 
4394     /* adaptive quantization control */
4395     pOldParam->bEnableAdaptiveQuant = pNewParam->bEnableAdaptiveQuant;
4396 
4397     /* int32_t term reference control */
4398     pOldParam->bEnableLongTermReference = pNewParam->bEnableLongTermReference;
4399     pOldParam->iLtrMarkPeriod = pNewParam->iLtrMarkPeriod;
4400 
4401     // keep below values unchanged as before
4402     pOldParam->bEnableSSEI              = pNewParam->bEnableSSEI;
4403     pOldParam->bSimulcastAVC            = pNewParam->bSimulcastAVC;
4404     pOldParam->bEnableFrameCroppingFlag = pNewParam->bEnableFrameCroppingFlag;  // enable frame cropping flag
4405 
4406     /* Motion search */
4407 
4408     /* Deblocking loop filter */
4409     pOldParam->iLoopFilterDisableIdc    =
4410       pNewParam->iLoopFilterDisableIdc;     // 0: on, 1: off, 2: on except for slice boundaries
4411     pOldParam->iLoopFilterAlphaC0Offset = pNewParam->iLoopFilterAlphaC0Offset;// AlphaOffset: valid range [-6, 6], default 0
4412     pOldParam->iLoopFilterBetaOffset    =
4413       pNewParam->iLoopFilterBetaOffset;     // BetaOffset:  valid range [-6, 6], default 0
4414 
4415     /* Rate Control */
4416     pOldParam->iRCMode          = pNewParam->iRCMode;
4417     pOldParam->iTargetBitrate   =
4418       pNewParam->iTargetBitrate;                    // overall target bitrate introduced in RC module
4419     pOldParam->iPaddingFlag     = pNewParam->iPaddingFlag;
4420 
4421     /* Layer definition */
4422     pOldParam->bPrefixNalAddingCtrl = pNewParam->bPrefixNalAddingCtrl;
4423 
4424     // d
4425     iIndexD = 0;
4426     do {
4427       SSpatialLayerInternal* pOldDlpInternal    = &pOldParam->sDependencyLayers[iIndexD];
4428       SSpatialLayerInternal* pNewDlpInternal    = &pNewParam->sDependencyLayers[iIndexD];
4429 
4430       SSpatialLayerConfig* pOldDlp      = &pOldParam->sSpatialLayers[iIndexD];
4431       SSpatialLayerConfig* pNewDlp      = &pNewParam->sSpatialLayers[iIndexD];
4432 
4433       pOldDlpInternal->fInputFrameRate  = pNewDlpInternal->fInputFrameRate;     // input frame rate
4434       pOldDlpInternal->fOutputFrameRate = pNewDlpInternal->fOutputFrameRate;    // output frame rate
4435       pOldDlp->iSpatialBitrate          = pNewDlp->iSpatialBitrate;
4436       pOldDlp->iMaxSpatialBitrate       = pNewDlp->iMaxSpatialBitrate;
4437       pOldDlp->uiProfileIdc             =
4438         pNewDlp->uiProfileIdc;                        // value of profile IDC (0 for auto-detection)
4439       pOldDlp->iDLayerQp                = pNewDlp->iDLayerQp;
4440 
4441       /* Derived variants below */
4442       pOldDlpInternal->iTemporalResolution      = pNewDlpInternal->iTemporalResolution;
4443       pOldDlpInternal->iDecompositionStages     = pNewDlpInternal->iDecompositionStages;
4444       memcpy (pOldDlpInternal->uiCodingIdx2TemporalId, pNewDlpInternal->uiCodingIdx2TemporalId,
4445               sizeof (pOldDlpInternal->uiCodingIdx2TemporalId)); // confirmed_safe_unsafe_usage
4446       ++ iIndexD;
4447     } while (iIndexD < pOldParam->iSpatialLayerNum);
4448   }
4449 
4450   /* Any else initialization/reset for rate control here? */
4451 
4452   return 0;
4453 }
4454 
WelsEncoderApplyLTR(SLogContext * pLogCtx,sWelsEncCtx ** ppCtx,SLTRConfig * pLTRValue)4455 int32_t WelsEncoderApplyLTR (SLogContext* pLogCtx, sWelsEncCtx** ppCtx, SLTRConfig* pLTRValue) {
4456   SWelsSvcCodingParam sConfig;
4457   int32_t iNumRefFrame = 1;
4458   int32_t iRet = 0;
4459   memcpy (&sConfig, (*ppCtx)->pSvcParam, sizeof (SWelsSvcCodingParam));
4460   sConfig.bEnableLongTermReference = pLTRValue->bEnableLongTermReference;
4461   sConfig.iLTRRefNum = pLTRValue->iLTRRefNum;
4462   int32_t uiGopSize = 1 << (sConfig.iTemporalLayerNum - 1);
4463   if (sConfig.iUsageType == SCREEN_CONTENT_REAL_TIME) {
4464     if (sConfig.bEnableLongTermReference) {
4465       sConfig.iLTRRefNum = LONG_TERM_REF_NUM_SCREEN;//WELS_CLIP3 (sConfig.iLTRRefNum, 1, LONG_TERM_REF_NUM_SCREEN);
4466       iNumRefFrame = WELS_MAX (1, WELS_LOG2 (uiGopSize)) + sConfig.iLTRRefNum;
4467     } else {
4468       sConfig.iLTRRefNum = 0;
4469       iNumRefFrame = WELS_MAX (1, uiGopSize >> 1);
4470     }
4471   } else {
4472     if (sConfig.bEnableLongTermReference) {
4473       sConfig.iLTRRefNum = LONG_TERM_REF_NUM;//WELS_CLIP3 (sConfig.iLTRRefNum, 1, LONG_TERM_REF_NUM);
4474     } else {
4475       sConfig.iLTRRefNum = 0;
4476     }
4477     iNumRefFrame = ((uiGopSize >> 1) > 1) ? ((uiGopSize >> 1) + sConfig.iLTRRefNum) : (MIN_REF_PIC_COUNT +
4478                    sConfig.iLTRRefNum);
4479     iNumRefFrame = WELS_CLIP3 (iNumRefFrame, MIN_REF_PIC_COUNT, MAX_REFERENCE_PICTURE_COUNT_NUM_CAMERA);
4480 
4481   }
4482   if (iNumRefFrame > sConfig.iMaxNumRefFrame) {
4483     WelsLog (pLogCtx, WELS_LOG_WARNING,
4484              " CWelsH264SVCEncoder::SetOption LTR flag = %d and number = %d: Required number of reference increased to %d and iMaxNumRefFrame is adjusted (from %d)",
4485              sConfig.bEnableLongTermReference, sConfig.iLTRRefNum, iNumRefFrame, sConfig.iMaxNumRefFrame);
4486     sConfig.iMaxNumRefFrame = iNumRefFrame;
4487   }
4488 
4489   if (sConfig.iNumRefFrame < iNumRefFrame) {
4490     WelsLog (pLogCtx, WELS_LOG_WARNING,
4491              " CWelsH264SVCEncoder::SetOption LTR flag = %d and number = %d, Required number of reference increased from Old = %d to New = %d because of LTR setting",
4492              sConfig.bEnableLongTermReference, sConfig.iLTRRefNum, sConfig.iNumRefFrame, iNumRefFrame);
4493     sConfig.iNumRefFrame = iNumRefFrame;
4494   }
4495   WelsLog (pLogCtx, WELS_LOG_INFO, "CWelsH264SVCEncoder::SetOption enable LTR = %d,ltrnum = %d",
4496            sConfig.bEnableLongTermReference, sConfig.iLTRRefNum);
4497   iRet = WelsEncoderParamAdjust (ppCtx, &sConfig);
4498   return iRet;
4499 }
4500 
DynSliceRealloc(sWelsEncCtx * pCtx,SFrameBSInfo * pFrameBsInfo,SLayerBSInfo * pLayerBsInfo)4501 int32_t DynSliceRealloc (sWelsEncCtx* pCtx,
4502                          SFrameBSInfo* pFrameBsInfo,
4503                          SLayerBSInfo* pLayerBsInfo) {
4504   int32_t iRet = 0;
4505 
4506   iRet = FrameBsRealloc (pCtx, pFrameBsInfo, pLayerBsInfo, pCtx->pCurDqLayer->iMaxSliceNum);
4507   if (ENC_RETURN_SUCCESS != iRet) {
4508     return iRet;
4509   }
4510 
4511   iRet = ReallocSliceBuffer (pCtx);
4512   if (ENC_RETURN_SUCCESS != iRet) {
4513     return iRet;
4514   }
4515 
4516   return iRet;
4517 }
4518 
WelsCodeOnePicPartition(sWelsEncCtx * pCtx,SFrameBSInfo * pFrameBSInfo,SLayerBSInfo * pLayerBsInfo,int32_t * pNalIdxInLayer,int32_t * pLayerSize,int32_t iFirstMbIdxInPartition,int32_t iEndMbIdxInPartition,int32_t iStartSliceIdx)4519 int32_t WelsCodeOnePicPartition (sWelsEncCtx* pCtx,
4520                                  SFrameBSInfo* pFrameBSInfo,
4521                                  SLayerBSInfo* pLayerBsInfo,
4522                                  int32_t* pNalIdxInLayer,
4523                                  int32_t* pLayerSize,
4524                                  int32_t iFirstMbIdxInPartition,
4525                                  int32_t iEndMbIdxInPartition,
4526                                  int32_t iStartSliceIdx
4527                                 ) {
4528 
4529   SDqLayer* pCurLayer                   = pCtx->pCurDqLayer;
4530   uint32_t uSlcBuffIdx                  = 0;
4531   SSlice* pStartSlice                   = &pCurLayer->sSliceBufferInfo[uSlcBuffIdx].pSliceBuffer[iStartSliceIdx];
4532   int32_t iNalIdxInLayer                = *pNalIdxInLayer;
4533   int32_t iSliceIdx                     = iStartSliceIdx;
4534   const int32_t kiSliceStep             = pCtx->iActiveThreadsNum;
4535   const int32_t kiPartitionId           = iStartSliceIdx % kiSliceStep;
4536   int32_t iPartitionBsSize              = 0;
4537   int32_t iAnyMbLeftInPartition         = iEndMbIdxInPartition - iFirstMbIdxInPartition + 1;
4538   const EWelsNalUnitType keNalType      = pCtx->eNalType;
4539   const EWelsNalRefIdc keNalRefIdc      = pCtx->eNalPriority;
4540   const bool kbNeedPrefix               = pCtx->bNeedPrefixNalFlag;
4541   const int32_t kiSliceIdxStep          = pCtx->iActiveThreadsNum;
4542   int32_t iReturn = ENC_RETURN_SUCCESS;
4543 
4544   pStartSlice->sSliceHeaderExt.sSliceHeader.iFirstMbInSlice = iFirstMbIdxInPartition;
4545 
4546   while (iAnyMbLeftInPartition > 0) {
4547     int32_t iSliceSize      = 0;
4548     int32_t iPayloadSize    = 0;
4549     SSlice* pCurSlice = NULL;
4550 
4551     if (iSliceIdx >= (pCurLayer->sSliceBufferInfo[uSlcBuffIdx].iMaxSliceNum -
4552                       kiSliceIdxStep)) { // insufficient memory in pSliceInLayer[]
4553       if (pCtx->iActiveThreadsNum == 1) {
4554         //only single thread support re-alloc now
4555         if (DynSliceRealloc (pCtx, pFrameBSInfo, pLayerBsInfo)) {
4556           WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR,
4557                    "CWelsH264SVCEncoder::WelsCodeOnePicPartition: DynSliceRealloc not successful");
4558           return ENC_RETURN_MEMALLOCERR;
4559         }
4560       } else if (iSliceIdx >= pCurLayer->iMaxSliceNum) {
4561         WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR,
4562                  "CWelsH264SVCEncoder::WelsCodeOnePicPartition: iSliceIdx(%d) over iMaxSliceNum(%d)", iSliceIdx,
4563                  pCurLayer->iMaxSliceNum);
4564         return ENC_RETURN_MEMALLOCERR;
4565       }
4566     }
4567 
4568     if (kbNeedPrefix) {
4569       iReturn = AddPrefixNal (pCtx, pLayerBsInfo, &pLayerBsInfo->pNalLengthInByte[0], &iNalIdxInLayer, keNalType, keNalRefIdc,
4570                               iPayloadSize);
4571       WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS)
4572       iPartitionBsSize += iPayloadSize;
4573     }
4574 
4575     WelsLoadNal (pCtx->pOut, keNalType, keNalRefIdc);
4576     pCurSlice = &pCtx->pCurDqLayer->sSliceBufferInfo[uSlcBuffIdx].pSliceBuffer[iSliceIdx];
4577     pCurSlice->iSliceIdx = iSliceIdx;
4578 
4579     iReturn = WelsCodeOneSlice (pCtx, pCurSlice, keNalType);
4580     WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS)
4581     WelsUnloadNal (pCtx->pOut);
4582 
4583     iReturn = WelsEncodeNal (&pCtx->pOut->sNalList[pCtx->pOut->iNalIndex - 1],
4584                              &pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt,
4585                              pCtx->iFrameBsSize - pCtx->iPosBsBuffer,
4586                              pCtx->pFrameBs + pCtx->iPosBsBuffer,
4587                              &pLayerBsInfo->pNalLengthInByte[iNalIdxInLayer]);
4588     WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS)
4589     iSliceSize = pLayerBsInfo->pNalLengthInByte[iNalIdxInLayer];
4590 
4591     pCtx->iPosBsBuffer  += iSliceSize;
4592     iPartitionBsSize    += iSliceSize;
4593 
4594 #if defined(SLICE_INFO_OUTPUT)
4595     fprintf (stderr,
4596              "@slice=%-6d sliceType:%c idc:%d size:%-6d\n",
4597              iSliceIdx,
4598              (pCtx->eSliceType == P_SLICE ? 'P' : 'I'),
4599              keNalRefIdc,
4600              iSliceSize);
4601 #endif//SLICE_INFO_OUTPUT
4602 
4603     ++ iNalIdxInLayer;
4604     iSliceIdx += kiSliceStep; //if iSliceIdx is not continuous
4605     iAnyMbLeftInPartition = iEndMbIdxInPartition - pCurLayer->LastCodedMbIdxOfPartition[kiPartitionId];
4606   }
4607 
4608   *pLayerSize           = iPartitionBsSize;
4609   *pNalIdxInLayer       = iNalIdxInLayer;
4610 
4611   // slice based packing???
4612   pLayerBsInfo->uiLayerType     = VIDEO_CODING_LAYER;
4613   pLayerBsInfo->uiSpatialId     = pCtx->uiDependencyId;
4614   pLayerBsInfo->uiTemporalId    = pCtx->uiTemporalId;
4615   pLayerBsInfo->uiQualityId     = 0;
4616   pLayerBsInfo->iNalCount       = iNalIdxInLayer;
4617   return ENC_RETURN_SUCCESS;
4618 }
4619 } // namespace WelsEnc
4620