• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*!
2  * \copy
3  *     Copyright (c)  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 
33 #include "wels_preprocess.h"
34 #include "picture_handle.h"
35 #include "encoder_context.h"
36 #include "utils.h"
37 #include "encoder.h"
38 
39 namespace {
40 
ClearEndOfLinePadding(uint8_t * pData,int32_t iStride,int32_t iWidth,int32_t iHeight)41 void ClearEndOfLinePadding (uint8_t* pData, int32_t iStride, int32_t iWidth, int32_t iHeight) {
42   if (iWidth < iStride) {
43     for (int32_t i = 0; i < iHeight; ++i)
44       memset (pData + i * iStride + iWidth, 0, iStride - iWidth);
45   }
46 }
47 
48 } // anon ns.
49 
50 namespace WelsEnc {
51 
52 
53 
54 //***** entry API declaration ************************************************************************//
55 
56 int32_t WelsInitScaledPic (SWelsSvcCodingParam* pParam,  Scaled_Picture*  pScaledPic, CMemoryAlign* pMemoryAlign);
57 bool  JudgeNeedOfScaling (SWelsSvcCodingParam* pParam, Scaled_Picture* pScaledPic);
58 void    FreeScaledPic (Scaled_Picture*  pScaledPic, CMemoryAlign* pMemoryAlign);
59 void  WelsMoveMemory_c (uint8_t* pDstY, uint8_t* pDstU, uint8_t* pDstV,  int32_t iDstStrideY, int32_t iDstStrideUV,
60                         uint8_t* pSrcY, uint8_t* pSrcU, uint8_t* pSrcV, int32_t iSrcStrideY, int32_t iSrcStrideUV, int32_t iWidth,
61                         int32_t iHeight);
62 
63 //******* table definition ***********************************************************************//
64 const uint8_t g_kuiRefTemporalIdx[MAX_TEMPORAL_LEVEL][MAX_GOP_SIZE] = {
65   {  0, }, // 0
66   {  0,  0, }, // 1
67   {  0,  0,  0,  1, }, // 2
68   {  0,  0,  0,  2,  0,  1,  1,  2, }, // 3
69 };
70 
71 const int32_t g_kiPixMapSizeInBits = sizeof (uint8_t) * 8;
72 
73 
WelsUpdateSpatialIdxMap(sWelsEncCtx * pEncCtx,const int32_t iPos,SPicture * const pPic,const int32_t iDidx)74 inline  void   WelsUpdateSpatialIdxMap (sWelsEncCtx* pEncCtx, const int32_t iPos, SPicture* const pPic,
75                                         const int32_t iDidx) {
76   pEncCtx->sSpatialIndexMap[iPos].pSrc = pPic;
77   pEncCtx->sSpatialIndexMap[iPos].iDid = iDidx;
78 }
79 
80 
81 /***************************************************************************
82 *
83 *   implement of the interface
84 *
85 ***************************************************************************/
86 
87 
88 
CreatePreProcess(sWelsEncCtx * pEncCtx)89 CWelsPreProcess* CWelsPreProcess::CreatePreProcess (sWelsEncCtx* pEncCtx) {
90 
91   CWelsPreProcess* pPreProcess = NULL;
92   switch (pEncCtx->pSvcParam->iUsageType) {
93   case SCREEN_CONTENT_REAL_TIME:
94     pPreProcess = WELS_NEW_OP (CWelsPreProcessScreen (pEncCtx),
95                                CWelsPreProcessScreen);
96     break;
97   default:
98     pPreProcess = WELS_NEW_OP (CWelsPreProcessVideo (pEncCtx),
99                                CWelsPreProcessVideo);
100     break;
101 
102   }
103   WELS_VERIFY_RETURN_IF (NULL, NULL == pPreProcess)
104   return pPreProcess;
105 }
106 
107 
CWelsPreProcess(sWelsEncCtx * pEncCtx)108 CWelsPreProcess::CWelsPreProcess (sWelsEncCtx* pEncCtx) {
109   m_pInterfaceVp = NULL;
110   m_bInitDone = false;
111   m_pEncCtx = pEncCtx;
112   memset (&m_sScaledPicture, 0, sizeof (m_sScaledPicture));
113   memset (m_pSpatialPic, 0, sizeof (m_pSpatialPic));
114   memset (m_uiSpatialLayersInTemporal, 0, sizeof (m_uiSpatialLayersInTemporal));
115   memset (m_uiSpatialPicNum, 0, sizeof (m_uiSpatialPicNum));
116 }
117 
~CWelsPreProcess()118 CWelsPreProcess::~CWelsPreProcess() {
119   FreeScaledPic (&m_sScaledPicture,  m_pEncCtx->pMemAlign);
120   WelsPreprocessDestroy();
121 }
122 
WelsPreprocessCreate()123 int32_t CWelsPreProcess::WelsPreprocessCreate() {
124   if (m_pInterfaceVp == NULL) {
125     WelsCreateVpInterface ((void**) &m_pInterfaceVp, WELSVP_INTERFACE_VERION);
126     if (!m_pInterfaceVp)
127       goto exit;
128   } else
129     goto exit;
130 
131   return 0;
132 
133 exit:
134   WelsPreprocessDestroy();
135   return 1;
136 }
137 
WelsPreprocessDestroy()138 int32_t CWelsPreProcess::WelsPreprocessDestroy() {
139   WelsDestroyVpInterface (m_pInterfaceVp, WELSVP_INTERFACE_VERION);
140   m_pInterfaceVp = NULL;
141 
142   return 0;
143 }
144 
WelsPreprocessReset(sWelsEncCtx * pCtx,int32_t iWidth,int32_t iHeight)145 int32_t CWelsPreProcess::WelsPreprocessReset (sWelsEncCtx* pCtx, int32_t iWidth, int32_t iHeight) {
146   int32_t iRet = -1;
147   SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam;
148   //init source width and height
149   pSvcParam->SUsedPicRect.iLeft = 0;
150   pSvcParam->SUsedPicRect.iTop  = 0;
151   pSvcParam->SUsedPicRect.iWidth =  iWidth;
152   pSvcParam->SUsedPicRect.iHeight = iHeight;
153   if ((iWidth < 16) || ((iHeight < 16))) {
154     WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR, "Don't support width(%d) or height(%d) which is less than 16 ", iWidth,
155              iHeight);
156     return iRet;
157   }
158   if (pCtx) {
159     FreeScaledPic (&m_sScaledPicture, pCtx->pMemAlign);
160     iRet = InitLastSpatialPictures (pCtx);
161     iRet = WelsInitScaledPic (pCtx->pSvcParam, &m_sScaledPicture, pCtx->pMemAlign);
162   }
163 
164   return iRet;
165 }
166 
AllocSpatialPictures(sWelsEncCtx * pCtx,SWelsSvcCodingParam * pParam)167 int32_t CWelsPreProcess::AllocSpatialPictures (sWelsEncCtx* pCtx, SWelsSvcCodingParam* pParam) {
168   CMemoryAlign* pMa             = pCtx->pMemAlign;
169   const int32_t kiDlayerCount   = pParam->iSpatialLayerNum;
170   int32_t iDlayerIndex          = 0;
171 
172   // spatial pictures
173   iDlayerIndex = 0;
174   do {
175     const int32_t kiPicWidth = pParam->sSpatialLayers[iDlayerIndex].iVideoWidth;
176     const int32_t kiPicHeight   = pParam->sSpatialLayers[iDlayerIndex].iVideoHeight;
177     const uint8_t kuiLayerInTemporal = 2 + WELS_MAX (pParam->sDependencyLayers[iDlayerIndex].iHighestTemporalId, 1);
178     const uint8_t kuiRefNumInTemporal = kuiLayerInTemporal + pParam->iLTRRefNum;
179     uint8_t i = 0;
180 
181     m_uiSpatialPicNum[iDlayerIndex] = kuiRefNumInTemporal;
182     do {
183       SPicture* pPic = AllocPicture (pMa, kiPicWidth, kiPicHeight, false, 0);
184       WELS_VERIFY_RETURN_IF (1, (NULL == pPic))
185       m_pSpatialPic[iDlayerIndex][i] = pPic;
186       ++ i;
187     } while (i < kuiRefNumInTemporal);
188 
189     if (pParam->iUsageType == SCREEN_CONTENT_REAL_TIME)
190       m_uiSpatialLayersInTemporal[iDlayerIndex] = 1;
191     else
192       m_uiSpatialLayersInTemporal[iDlayerIndex] = kuiLayerInTemporal;
193 
194     ++ iDlayerIndex;
195   } while (iDlayerIndex < kiDlayerCount);
196 
197   return 0;
198 }
199 
FreeSpatialPictures(sWelsEncCtx * pCtx)200 void CWelsPreProcess::FreeSpatialPictures (sWelsEncCtx* pCtx) {
201   CMemoryAlign* pMa = pCtx->pMemAlign;
202   int32_t j = 0;
203   while (j < pCtx->pSvcParam->iSpatialLayerNum) {
204     uint8_t i = 0;
205     uint8_t uiRefNumInTemporal = m_uiSpatialPicNum[j];
206 
207     while (i < uiRefNumInTemporal) {
208       if (NULL != m_pSpatialPic[j][i]) {
209         FreePicture (pMa, &m_pSpatialPic[j][i]);
210       }
211       ++ i;
212     }
213     m_uiSpatialLayersInTemporal[j] = 0;
214     ++ j;
215   }
216 }
217 
BuildSpatialPicList(sWelsEncCtx * pCtx,const SSourcePicture * kpSrcPic)218 int32_t CWelsPreProcess::BuildSpatialPicList (sWelsEncCtx* pCtx, const SSourcePicture* kpSrcPic) {
219   SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam;
220   int32_t iSpatialNum = 0;
221   int32_t iWidth = ((kpSrcPic->iPicWidth >> 1) << 1);
222   int32_t iHeight = ((kpSrcPic->iPicHeight >> 1) << 1);
223 
224   if (!m_bInitDone) {
225     if (WelsPreprocessCreate() != 0)
226       return -1;
227 
228     if (WelsPreprocessReset (pCtx, iWidth, iHeight) != 0)
229       return -1;
230 
231     m_iAvaliableRefInSpatialPicList = pSvcParam->iNumRefFrame;
232 
233     m_bInitDone = true;
234   } else {
235     if ((iWidth != pSvcParam->SUsedPicRect.iWidth) || (iHeight != pSvcParam->SUsedPicRect.iHeight)) {
236       if (WelsPreprocessReset (pCtx, iWidth, iHeight) != 0)
237         return -1;
238     }
239   }
240 
241   if (m_pInterfaceVp == NULL)
242     return -1;
243 
244   pCtx->pVaa->bSceneChangeFlag = pCtx->pVaa->bIdrPeriodFlag = false;
245 
246   iSpatialNum = SingleLayerPreprocess (pCtx, kpSrcPic, &m_sScaledPicture);
247 
248   return iSpatialNum;
249 }
250 
GetBestRefPic(EUsageType iUsageType,bool bSceneLtr,EWelsSliceType eSliceType,int32_t kiDidx,int32_t iRefTemporalIdx)251 SPicture* CWelsPreProcess::GetBestRefPic (EUsageType iUsageType, bool bSceneLtr, EWelsSliceType eSliceType,
252     int32_t kiDidx, int32_t iRefTemporalIdx) {
253   assert (iUsageType == SCREEN_CONTENT_REAL_TIME);
254   SVAAFrameInfoExt* pVaaExt = static_cast<SVAAFrameInfoExt*> (m_pEncCtx->pVaa);
255   SRefInfoParam* BestRefCandidateParam = (bSceneLtr) ? (& (pVaaExt->sVaaLtrBestRefCandidate[0])) :
256                                          (& (pVaaExt->sVaaStrBestRefCandidate[0]));
257   return m_pSpatialPic[0][BestRefCandidateParam->iSrcListIdx];
258 
259 }
GetBestRefPic(const int32_t kiDidx,const int32_t iRefTemporalIdx)260 SPicture* CWelsPreProcess::GetBestRefPic (const int32_t kiDidx, const int32_t iRefTemporalIdx) {
261 
262   return m_pSpatialPic[kiDidx][iRefTemporalIdx];
263 }
264 
AnalyzeSpatialPic(sWelsEncCtx * pCtx,const int32_t kiDidx)265 int32_t CWelsPreProcess::AnalyzeSpatialPic (sWelsEncCtx* pCtx, const int32_t kiDidx) {
266   SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam;
267   bool bNeededMbAq = (pSvcParam->bEnableAdaptiveQuant && (pCtx->eSliceType == P_SLICE));
268   bool bCalculateBGD = (pCtx->eSliceType == P_SLICE && pSvcParam->bEnableBackgroundDetection);
269   SSpatialLayerInternal* pParamInternal = &pSvcParam->sDependencyLayers[kiDidx];
270   int32_t iCurTemporalIdx  = m_uiSpatialLayersInTemporal[kiDidx] - 1;
271 
272   int32_t iRefTemporalIdx = (int32_t)g_kuiRefTemporalIdx[pSvcParam->iDecompStages][pParamInternal->iCodingIndex &
273                             (pSvcParam->uiGopSize - 1)];
274   if (pCtx->uiTemporalId == 0 && pCtx->pLtr[pCtx->uiDependencyId].bReceivedT0LostFlag)
275     iRefTemporalIdx = m_uiSpatialLayersInTemporal[kiDidx] + pCtx->pVaa->uiValidLongTermPicIdx;
276 
277   SPicture* pCurPic = m_pSpatialPic[kiDidx][iCurTemporalIdx];
278   bool bCalculateVar = (pSvcParam->iRCMode >= RC_BITRATE_MODE && pCtx->eSliceType == I_SLICE);
279 
280   if (pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME) {
281     SPicture* pRefPic = GetBestRefPic (pSvcParam->iUsageType, pCtx->bCurFrameMarkedAsSceneLtr, pCtx->eSliceType, kiDidx,
282                                        iRefTemporalIdx);
283 
284     VaaCalculation (pCtx->pVaa, pCurPic, pRefPic, false, bCalculateVar, bCalculateBGD);
285 
286     if (pSvcParam->bEnableBackgroundDetection) {
287       BackgroundDetection (pCtx->pVaa, pCurPic, pRefPic, bCalculateBGD && pRefPic->iPictureType != I_SLICE);
288     }
289     if (bNeededMbAq) {
290       AdaptiveQuantCalculation (pCtx->pVaa, pCurPic, pRefPic);
291     }
292   } else {
293     SPicture* pRefPic = GetBestRefPic (kiDidx, iRefTemporalIdx);
294     SPicture* pLastPic = m_pLastSpatialPicture[kiDidx][0];
295     bool bCalculateSQDiff = ((pLastPic->pData[0] == pRefPic->pData[0]) && bNeededMbAq);
296 
297     VaaCalculation (pCtx->pVaa, pCurPic, pRefPic, bCalculateSQDiff, bCalculateVar, bCalculateBGD);
298 
299     if (pSvcParam->bEnableBackgroundDetection) {
300       BackgroundDetection (pCtx->pVaa, pCurPic, pRefPic, bCalculateBGD && pRefPic->iPictureType != I_SLICE);
301     }
302 
303     if (bNeededMbAq) {
304       AdaptiveQuantCalculation (pCtx->pVaa, m_pLastSpatialPicture[kiDidx][1], m_pLastSpatialPicture[kiDidx][0]);
305     }
306   }
307   return 0;
308 }
309 
GetCurPicPosition(const int32_t kiDidx)310 int32_t CWelsPreProcess::GetCurPicPosition (const int32_t kiDidx) {
311   return (m_uiSpatialLayersInTemporal[kiDidx] - 1);
312 }
313 
UpdateSpatialPictures(sWelsEncCtx * pCtx,SWelsSvcCodingParam * pParam,const int8_t iCurTid,const int32_t kiDidx)314 int32_t CWelsPreProcess::UpdateSpatialPictures (sWelsEncCtx* pCtx, SWelsSvcCodingParam* pParam,
315     const int8_t iCurTid, const int32_t kiDidx) {
316   if (pCtx->pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME)
317     return 0;
318 
319   WelsExchangeSpatialPictures (&m_pLastSpatialPicture[kiDidx][1], &m_pLastSpatialPicture[kiDidx][0]);
320 
321   const int32_t kiCurPos = GetCurPicPosition (kiDidx);
322   if (iCurTid < kiCurPos || pParam->iDecompStages == 0) {
323     if ((iCurTid >= MAX_TEMPORAL_LEVEL) || (kiCurPos > MAX_TEMPORAL_LEVEL)) {
324       InitLastSpatialPictures (pCtx);
325       return 1;
326     }
327     if (pCtx->bRefOfCurTidIsLtr[kiDidx][iCurTid]) {
328       const int32_t kiAvailableLtrPos = m_uiSpatialLayersInTemporal[kiDidx] + pCtx->pVaa->uiMarkLongTermPicIdx;
329       WelsExchangeSpatialPictures (&m_pSpatialPic[kiDidx][kiAvailableLtrPos],
330                                    &m_pSpatialPic[kiDidx][iCurTid]);
331       pCtx->bRefOfCurTidIsLtr[kiDidx][iCurTid] = false;
332     }
333     WelsExchangeSpatialPictures (&m_pSpatialPic[kiDidx][kiCurPos],
334                                  &m_pSpatialPic[kiDidx][iCurTid]);
335 
336 
337   }
338   return 0;
339 }
340 
341 
342 /*
343  *   SingleLayerPreprocess: down sampling if applicable
344  *  @return: exact number of spatial layers need to encoder indeed
345  */
SingleLayerPreprocess(sWelsEncCtx * pCtx,const SSourcePicture * kpSrc,Scaled_Picture * pScaledPicture)346 int32_t CWelsPreProcess::SingleLayerPreprocess (sWelsEncCtx* pCtx, const SSourcePicture* kpSrc,
347     Scaled_Picture* pScaledPicture) {
348   SWelsSvcCodingParam* pSvcParam    = pCtx->pSvcParam;
349   int8_t  iDependencyId             = pSvcParam->iSpatialLayerNum - 1;
350 
351   SPicture* pSrcPic                 = NULL; // large
352   SPicture* pDstPic                 = NULL; // small
353   SSpatialLayerConfig* pDlayerParam = NULL;
354   SSpatialLayerInternal* pDlayerParamInternal = NULL;
355   int32_t iSpatialNum               = 0;
356   int32_t iSrcWidth                 = 0;
357   int32_t iSrcHeight                = 0;
358   int32_t iTargetWidth              = 0;
359   int32_t iTargetHeight             = 0;
360   int32_t iTemporalId = 0;
361   int32_t iClosestDid =  iDependencyId;
362   pDlayerParamInternal = &pSvcParam->sDependencyLayers[iDependencyId];
363   pDlayerParam = &pSvcParam->sSpatialLayers[iDependencyId];
364   iTargetWidth   = pDlayerParam->iVideoWidth;
365   iTargetHeight  = pDlayerParam->iVideoHeight;
366 
367   iSrcWidth   = pSvcParam->SUsedPicRect.iWidth;
368   iSrcHeight  = pSvcParam->SUsedPicRect.iHeight;
369   if (pSvcParam->uiIntraPeriod) {
370     pCtx->pVaa->bIdrPeriodFlag = (1 + pDlayerParamInternal->iFrameIndex >= (int32_t)pSvcParam->uiIntraPeriod) ? true :
371                                  false;
372     if (pCtx->pVaa->bIdrPeriodFlag) {
373       WelsLog (& (pCtx->sLogCtx), WELS_LOG_DEBUG,
374            "pSvcParam->uiIntraPeriod=%d, pCtx->pVaa->bIdrPeriodFlag=%d",
375              pSvcParam->uiIntraPeriod,
376              pCtx->pVaa->bIdrPeriodFlag);
377     }
378   }
379 
380   pSrcPic = pScaledPicture->pScaledInputPicture ? pScaledPicture->pScaledInputPicture : GetCurrentOrigFrame (
381               iDependencyId);
382 
383   WelsMoveMemoryWrapper (pSvcParam, pSrcPic, kpSrc, iSrcWidth, iSrcHeight);
384 
385   if (pSvcParam->bEnableDenoise)
386     BilateralDenoising (pSrcPic, iSrcWidth, iSrcHeight);
387 
388   // different scaling in between input picture and dst highest spatial picture.
389   int32_t iShrinkWidth  = iSrcWidth;
390   int32_t iShrinkHeight = iSrcHeight;
391   pDstPic = pSrcPic;
392   if (pScaledPicture->pScaledInputPicture) {
393     // for highest downsampling
394     pDstPic = GetCurrentOrigFrame (iDependencyId);
395     iShrinkWidth = pScaledPicture->iScaledWidth[iDependencyId];
396     iShrinkHeight = pScaledPicture->iScaledHeight[iDependencyId];
397   }
398   DownsamplePadding (pSrcPic, pDstPic, iSrcWidth, iSrcHeight, iShrinkWidth, iShrinkHeight, iTargetWidth, iTargetHeight,
399                      false);
400 
401   if (pSvcParam->bEnableSceneChangeDetect && !pCtx->pVaa->bIdrPeriodFlag) {
402     if (pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME) {
403       pCtx->pVaa->eSceneChangeIdc = (pDlayerParamInternal->bEncCurFrmAsIdrFlag ? LARGE_CHANGED_SCENE :
404                                      DetectSceneChange (pDstPic));
405       pCtx->pVaa->bSceneChangeFlag = (LARGE_CHANGED_SCENE == pCtx->pVaa->eSceneChangeIdc);
406     } else {
407       if ((!pDlayerParamInternal->bEncCurFrmAsIdrFlag)
408           && ! (pDlayerParamInternal->iCodingIndex & (pSvcParam->uiGopSize - 1))) {
409         SPicture* pRefPic = pCtx->pLtr[iDependencyId].bReceivedT0LostFlag ?
410                             m_pSpatialPic[iDependencyId][m_uiSpatialLayersInTemporal[iDependencyId] +
411                                 pCtx->pVaa->uiValidLongTermPicIdx] : m_pLastSpatialPicture[iDependencyId][0];
412         //pCtx->pVaa->eSceneChangeIdc = DetectSceneChange (pDstPic, pRefPic);
413         pCtx->pVaa->bSceneChangeFlag = GetSceneChangeFlag (DetectSceneChange (pDstPic, pRefPic));
414       }
415     }
416   }
417 
418   for (int32_t i = 0; i < pSvcParam->iSpatialLayerNum; i++) {
419     pDlayerParamInternal = &pSvcParam->sDependencyLayers[i];
420     iTemporalId    = pDlayerParamInternal->uiCodingIdx2TemporalId[pDlayerParamInternal->iCodingIndex &
421                      (pSvcParam->uiGopSize - 1)];
422     if (iTemporalId != INVALID_TEMPORAL_ID) {
423       ++ iSpatialNum;
424     }
425   }
426   pDlayerParamInternal = &pSvcParam->sDependencyLayers[iDependencyId];
427   iTemporalId    = pDlayerParamInternal->uiCodingIdx2TemporalId[pDlayerParamInternal->iCodingIndex &
428                    (pSvcParam->uiGopSize - 1)];
429   int iActualSpatialNum = iSpatialNum - 1;
430   if (iTemporalId != INVALID_TEMPORAL_ID) {
431     WelsUpdateSpatialIdxMap (pCtx, iActualSpatialNum, pDstPic, iDependencyId);
432     -- iActualSpatialNum;
433   }
434 
435   m_pLastSpatialPicture[iDependencyId][1] = GetCurrentOrigFrame (iDependencyId);
436   -- iDependencyId;
437 
438 
439   // generate other spacial layer
440   // pSrc is
441   //    -- padded input pic, if downsample should be applied to generate highest layer, [if] block above
442   //    -- highest layer, if no downsampling, [else] block above
443   if (pSvcParam->iSpatialLayerNum > 1) {
444     while (iDependencyId >= 0) {
445       pDlayerParamInternal = &pSvcParam->sDependencyLayers[iDependencyId];
446       pDlayerParam = &pSvcParam->sSpatialLayers[iDependencyId];
447       SPicture* pSrcPic  = m_pLastSpatialPicture[iClosestDid][1]; // large
448       iTargetWidth  = pDlayerParam->iVideoWidth;
449       iTargetHeight = pDlayerParam->iVideoHeight;
450       iTemporalId = pDlayerParamInternal->uiCodingIdx2TemporalId[pDlayerParamInternal->iCodingIndex &
451                     (pSvcParam->uiGopSize - 1)];
452 
453       // down sampling performed
454       int32_t iSrcWidth                 = pScaledPicture->iScaledWidth[iClosestDid];
455       int32_t iSrcHeight                = pScaledPicture->iScaledHeight[iClosestDid];
456       pDstPic = GetCurrentOrigFrame (iDependencyId); // small
457       iShrinkWidth = pScaledPicture->iScaledWidth[iDependencyId];
458       iShrinkHeight = pScaledPicture->iScaledHeight[iDependencyId];
459       DownsamplePadding (pSrcPic, pDstPic, iSrcWidth, iSrcHeight, iShrinkWidth, iShrinkHeight, iTargetWidth, iTargetHeight,
460                          true);
461 
462       if ((iTemporalId != INVALID_TEMPORAL_ID)) {
463         WelsUpdateSpatialIdxMap (pCtx, iActualSpatialNum, pDstPic, iDependencyId);
464         iActualSpatialNum--;
465       }
466 
467       m_pLastSpatialPicture[iDependencyId][1] = pDstPic;
468 
469       iClosestDid = iDependencyId;
470       -- iDependencyId;
471 
472     }
473   }
474   return iSpatialNum;
475 
476 }
477 
478 
479 /*!
480  * \brief   Whether input picture need be scaled?
481  */
JudgeNeedOfScaling(SWelsSvcCodingParam * pParam,Scaled_Picture * pScaledPicture)482 bool JudgeNeedOfScaling (SWelsSvcCodingParam* pParam, Scaled_Picture* pScaledPicture) {
483   const int32_t kiInputPicWidth  = pParam->SUsedPicRect.iWidth;
484   const int32_t kiInputPicHeight = pParam->SUsedPicRect.iHeight;
485   const int32_t kiDstPicWidth    = pParam->sDependencyLayers[pParam->iSpatialLayerNum - 1].iActualWidth;
486   const int32_t kiDstPicHeight   = pParam->sDependencyLayers[pParam->iSpatialLayerNum - 1].iActualHeight;
487   bool bNeedDownsampling = true;
488 
489   int32_t iSpatialIdx = pParam->iSpatialLayerNum - 1;
490 
491   if (kiDstPicWidth >= kiInputPicWidth && kiDstPicHeight >= kiInputPicHeight) {
492     bNeedDownsampling = false;
493   }
494 
495   for (; iSpatialIdx >= 0; iSpatialIdx --) {
496     SSpatialLayerInternal* pCurLayer = &pParam->sDependencyLayers[iSpatialIdx];
497     int32_t iCurDstWidth             = pCurLayer->iActualWidth;
498     int32_t iCurDstHeight            = pCurLayer->iActualHeight;
499     int32_t iInputWidthXDstHeight    = kiInputPicWidth * iCurDstHeight;
500     int32_t iInputHeightXDstWidth    = kiInputPicHeight * iCurDstWidth;
501 
502     if (iInputWidthXDstHeight > iInputHeightXDstWidth) {
503       pScaledPicture->iScaledWidth[iSpatialIdx] = WELS_MAX (iCurDstWidth, 4);
504       pScaledPicture->iScaledHeight[iSpatialIdx] = WELS_MAX (iInputHeightXDstWidth / kiInputPicWidth, 4);
505     } else {
506       pScaledPicture->iScaledWidth[iSpatialIdx] = WELS_MAX (iInputWidthXDstHeight / kiInputPicHeight, 4);
507       pScaledPicture->iScaledHeight[iSpatialIdx] = WELS_MAX (iCurDstHeight, 4);
508     }
509   }
510 
511   return bNeedDownsampling;
512 }
513 
WelsInitScaledPic(SWelsSvcCodingParam * pParam,Scaled_Picture * pScaledPicture,CMemoryAlign * pMemoryAlign)514 int32_t  WelsInitScaledPic (SWelsSvcCodingParam* pParam,  Scaled_Picture*  pScaledPicture, CMemoryAlign* pMemoryAlign) {
515   bool bInputPicNeedScaling = JudgeNeedOfScaling (pParam, pScaledPicture);
516   if (bInputPicNeedScaling) {
517     pScaledPicture->pScaledInputPicture = AllocPicture (pMemoryAlign, pParam->SUsedPicRect.iWidth,
518                                           pParam->SUsedPicRect.iHeight, false, 0);
519     if (pScaledPicture->pScaledInputPicture == NULL)
520       return -1;
521 
522     // Avoid valgrind false positives.
523     //
524     // X86 SIMD downsampling routines may, for convenience, read slightly beyond
525     // the input data and into the alignment padding area beyond each line. This
526     // causes valgrind to warn about uninitialized values even if these values
527     // only affect lanes of a SIMD vector that are effectively never used.
528     //
529     // Avoid these false positives by zero-initializing the padding area beyond
530     // each line of the source buffer used for downsampling.
531     SPicture* pPic = pScaledPicture->pScaledInputPicture;
532     ClearEndOfLinePadding (pPic->pData[0], pPic->iLineSize[0], pPic->iWidthInPixel, pPic->iHeightInPixel);
533     ClearEndOfLinePadding (pPic->pData[1], pPic->iLineSize[1], pPic->iWidthInPixel >> 1, pPic->iHeightInPixel >> 1);
534     ClearEndOfLinePadding (pPic->pData[2], pPic->iLineSize[2], pPic->iWidthInPixel >> 1, pPic->iHeightInPixel >> 1);
535   }
536   return 0;
537 }
538 
FreeScaledPic(Scaled_Picture * pScaledPicture,CMemoryAlign * pMemoryAlign)539 void  FreeScaledPic (Scaled_Picture*  pScaledPicture, CMemoryAlign* pMemoryAlign) {
540   if (pScaledPicture->pScaledInputPicture) {
541     FreePicture (pMemoryAlign, &pScaledPicture->pScaledInputPicture);
542     pScaledPicture->pScaledInputPicture = NULL;
543   }
544 }
545 
InitLastSpatialPictures(sWelsEncCtx * pCtx)546 int32_t CWelsPreProcess::InitLastSpatialPictures (sWelsEncCtx* pCtx) {
547   SWelsSvcCodingParam* pParam   = pCtx->pSvcParam;
548   const int32_t kiDlayerCount   = pParam->iSpatialLayerNum;
549   int32_t iDlayerIndex          = 0;
550   if (pParam->iUsageType == SCREEN_CONTENT_REAL_TIME) {
551     for (; iDlayerIndex < MAX_DEPENDENCY_LAYER; iDlayerIndex++) {
552       m_pLastSpatialPicture[iDlayerIndex][0] = m_pLastSpatialPicture[iDlayerIndex][1] = NULL;
553     }
554   } else {
555     for (; iDlayerIndex < kiDlayerCount; iDlayerIndex++) {
556       const int32_t kiLayerInTemporal = m_uiSpatialLayersInTemporal[iDlayerIndex];
557       m_pLastSpatialPicture[iDlayerIndex][0] = m_pSpatialPic[iDlayerIndex][kiLayerInTemporal - 2];
558       m_pLastSpatialPicture[iDlayerIndex][1] = NULL;
559     }
560     for (; iDlayerIndex < MAX_DEPENDENCY_LAYER; iDlayerIndex++) {
561       m_pLastSpatialPicture[iDlayerIndex][0] = m_pLastSpatialPicture[iDlayerIndex][1] = NULL;
562     }
563   }
564   return 0;
565 }
566 //*********************************************************************************************************/
567 
ColorspaceConvert(SWelsSvcCodingParam * pSvcParam,SPicture * pDstPic,const SSourcePicture * kpSrc,const int32_t kiWidth,const int32_t kiHeight)568 int32_t CWelsPreProcess::ColorspaceConvert (SWelsSvcCodingParam* pSvcParam, SPicture* pDstPic,
569     const SSourcePicture* kpSrc, const int32_t kiWidth, const int32_t kiHeight) {
570   return 1;
571   //not support yet
572 }
573 
BilateralDenoising(SPicture * pSrc,const int32_t kiWidth,const int32_t kiHeight)574 void CWelsPreProcess::BilateralDenoising (SPicture* pSrc, const int32_t kiWidth, const int32_t kiHeight) {
575   int32_t iMethodIdx = METHOD_DENOISE;
576   SPixMap sSrcPixMap;
577   memset (&sSrcPixMap, 0, sizeof (sSrcPixMap));
578   sSrcPixMap.pPixel[0] = pSrc->pData[0];
579   sSrcPixMap.pPixel[1] = pSrc->pData[1];
580   sSrcPixMap.pPixel[2] = pSrc->pData[2];
581   sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
582   sSrcPixMap.sRect.iRectWidth = kiWidth;
583   sSrcPixMap.sRect.iRectHeight = kiHeight;
584   sSrcPixMap.iStride[0] = pSrc->iLineSize[0];
585   sSrcPixMap.iStride[1] = pSrc->iLineSize[1];
586   sSrcPixMap.iStride[2] = pSrc->iLineSize[2];
587   sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
588 
589   m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, NULL);
590 }
591 
DetectSceneChange(SPicture * pCurPicture,SPicture * pRefPicture)592 ESceneChangeIdc CWelsPreProcessVideo::DetectSceneChange (SPicture* pCurPicture, SPicture* pRefPicture) {
593   int32_t iMethodIdx = METHOD_SCENE_CHANGE_DETECTION_VIDEO;
594   SSceneChangeResult sSceneChangeDetectResult = { SIMILAR_SCENE };
595   SPixMap sSrcPixMap;
596   SPixMap sRefPixMap;
597   memset (&sSrcPixMap, 0, sizeof (sSrcPixMap));
598   memset (&sRefPixMap, 0, sizeof (sRefPixMap));
599   sSrcPixMap.pPixel[0] = pCurPicture->pData[0];
600   sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
601   sSrcPixMap.iStride[0] = pCurPicture->iLineSize[0];
602   sSrcPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
603   sSrcPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
604   sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
605 
606   sRefPixMap.pPixel[0] = pRefPicture->pData[0];
607   sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
608   sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
609   sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
610   sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
611   sRefPixMap.eFormat = VIDEO_FORMAT_I420;
612 
613   int32_t iRet = m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sRefPixMap);
614   if (iRet == 0) {
615     m_pInterfaceVp->Get (iMethodIdx, (void*)&sSceneChangeDetectResult);
616     //bSceneChangeFlag = (sSceneChangeDetectResult.eSceneChangeIdc == LARGE_CHANGED_SCENE) ? true : false;
617   }
618   return sSceneChangeDetectResult.eSceneChangeIdc;
619 }
620 
GetCurrentOrigFrame(int32_t iDIdx)621 SPicture* CWelsPreProcessVideo::GetCurrentOrigFrame (int32_t iDIdx) {
622   return m_pSpatialPic[iDIdx][GetCurPicPosition (iDIdx)];
623 }
624 
DownsamplePadding(SPicture * pSrc,SPicture * pDstPic,int32_t iSrcWidth,int32_t iSrcHeight,int32_t iShrinkWidth,int32_t iShrinkHeight,int32_t iTargetWidth,int32_t iTargetHeight,bool bForceCopy)625 int32_t CWelsPreProcess::DownsamplePadding (SPicture* pSrc, SPicture* pDstPic,  int32_t iSrcWidth, int32_t iSrcHeight,
626     int32_t iShrinkWidth, int32_t iShrinkHeight, int32_t iTargetWidth, int32_t iTargetHeight, bool bForceCopy) {
627   int32_t iRet = 0;
628   SPixMap sSrcPixMap;
629   SPixMap sDstPicMap;
630   memset (&sSrcPixMap, 0, sizeof (sSrcPixMap));
631   memset (&sDstPicMap, 0, sizeof (sDstPicMap));
632   sSrcPixMap.pPixel[0]   = pSrc->pData[0];
633   sSrcPixMap.pPixel[1]   = pSrc->pData[1];
634   sSrcPixMap.pPixel[2]   = pSrc->pData[2];
635   sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
636   sSrcPixMap.sRect.iRectWidth  = iSrcWidth;
637   sSrcPixMap.sRect.iRectHeight = iSrcHeight;
638   sSrcPixMap.iStride[0]  = pSrc->iLineSize[0];
639   sSrcPixMap.iStride[1]  = pSrc->iLineSize[1];
640   sSrcPixMap.iStride[2]  = pSrc->iLineSize[2];
641   sSrcPixMap.eFormat     = VIDEO_FORMAT_I420;
642 
643   if (iSrcWidth != iShrinkWidth || iSrcHeight != iShrinkHeight || bForceCopy) {
644     int32_t iMethodIdx = METHOD_DOWNSAMPLE;
645     sDstPicMap.pPixel[0]   = pDstPic->pData[0];
646     sDstPicMap.pPixel[1]   = pDstPic->pData[1];
647     sDstPicMap.pPixel[2]   = pDstPic->pData[2];
648     sDstPicMap.iSizeInBits = g_kiPixMapSizeInBits;
649     sDstPicMap.sRect.iRectWidth  = iShrinkWidth;
650     sDstPicMap.sRect.iRectHeight = iShrinkHeight;
651     sDstPicMap.iStride[0]  = pDstPic->iLineSize[0];
652     sDstPicMap.iStride[1]  = pDstPic->iLineSize[1];
653     sDstPicMap.iStride[2]  = pDstPic->iLineSize[2];
654     sDstPicMap.eFormat     = VIDEO_FORMAT_I420;
655 
656     if (iSrcWidth != iShrinkWidth || iSrcHeight != iShrinkHeight) {
657       iRet = m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sDstPicMap);
658     } else {
659       WelsMoveMemory_c (pDstPic->pData[0], pDstPic->pData[1], pDstPic->pData[2], pDstPic->iLineSize[0], pDstPic->iLineSize[1],
660                         pSrc->pData[0], pSrc->pData[1], pSrc->pData[2], pSrc->iLineSize[0], pSrc->iLineSize[1],
661                         iSrcWidth, iSrcHeight);
662     }
663   } else {
664     memcpy (&sDstPicMap, &sSrcPixMap, sizeof (sDstPicMap)); // confirmed_safe_unsafe_usage
665   }
666 
667   // get rid of odd line
668   iShrinkWidth -= (iShrinkWidth & 1);
669   iShrinkHeight -= (iShrinkHeight & 1);
670   Padding ((uint8_t*)sDstPicMap.pPixel[0], (uint8_t*)sDstPicMap.pPixel[1], (uint8_t*)sDstPicMap.pPixel[2],
671            sDstPicMap.iStride[0], sDstPicMap.iStride[1], iShrinkWidth, iTargetWidth, iShrinkHeight, iTargetHeight);
672 
673   return iRet;
674 }
675 
676 //*********************************************************************************************************/
VaaCalculation(SVAAFrameInfo * pVaaInfo,SPicture * pCurPicture,SPicture * pRefPicture,bool bCalculateSQDiff,bool bCalculateVar,bool bCalculateBGD)677 void CWelsPreProcess::VaaCalculation (SVAAFrameInfo* pVaaInfo, SPicture* pCurPicture, SPicture* pRefPicture,
678                                       bool bCalculateSQDiff, bool bCalculateVar, bool bCalculateBGD) {
679   pVaaInfo->sVaaCalcInfo.pCurY = pCurPicture->pData[0];
680   pVaaInfo->sVaaCalcInfo.pRefY = pRefPicture->pData[0];
681   {
682     int32_t iMethodIdx = METHOD_VAA_STATISTICS;
683     SPixMap sCurPixMap;
684     SPixMap sRefPixMap;
685     memset (&sCurPixMap, 0, sizeof (sCurPixMap));
686     memset (&sRefPixMap, 0, sizeof (sRefPixMap));
687     SVAACalcParam calc_param = {0};
688 
689     sCurPixMap.pPixel[0] = pCurPicture->pData[0];
690     sCurPixMap.iSizeInBits = g_kiPixMapSizeInBits;
691     sCurPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
692     sCurPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
693     sCurPixMap.iStride[0] = pCurPicture->iLineSize[0];
694     sCurPixMap.eFormat = VIDEO_FORMAT_I420;
695 
696     sRefPixMap.pPixel[0] = pRefPicture->pData[0];
697     sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
698     sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
699     sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
700     sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
701     sRefPixMap.eFormat = VIDEO_FORMAT_I420;
702 
703     calc_param.iCalcVar = bCalculateVar;
704     calc_param.iCalcBgd = bCalculateBGD;
705     calc_param.iCalcSsd = bCalculateSQDiff;
706     calc_param.pCalcResult = &pVaaInfo->sVaaCalcInfo;
707 
708     m_pInterfaceVp->Set (iMethodIdx, &calc_param);
709     m_pInterfaceVp->Process (iMethodIdx, &sCurPixMap, &sRefPixMap);
710   }
711 }
712 
BackgroundDetection(SVAAFrameInfo * pVaaInfo,SPicture * pCurPicture,SPicture * pRefPicture,bool bDetectFlag)713 void CWelsPreProcess::BackgroundDetection (SVAAFrameInfo* pVaaInfo, SPicture* pCurPicture, SPicture* pRefPicture,
714     bool bDetectFlag) {
715   if (bDetectFlag) {
716     pVaaInfo->iPicWidth     = pCurPicture->iWidthInPixel;
717     pVaaInfo->iPicHeight    = pCurPicture->iHeightInPixel;
718 
719     pVaaInfo->iPicStride    = pCurPicture->iLineSize[0];
720     pVaaInfo->iPicStrideUV  = pCurPicture->iLineSize[1];
721     pVaaInfo->pCurY         = pCurPicture->pData[0];
722     pVaaInfo->pRefY         = pRefPicture->pData[0];
723     pVaaInfo->pCurU         = pCurPicture->pData[1];
724     pVaaInfo->pRefU         = pRefPicture->pData[1];
725     pVaaInfo->pCurV         = pCurPicture->pData[2];
726     pVaaInfo->pRefV         = pRefPicture->pData[2];
727 
728     int32_t iMethodIdx = METHOD_BACKGROUND_DETECTION;
729     SPixMap sSrcPixMap;
730     SPixMap sRefPixMap;
731     memset (&sSrcPixMap, 0, sizeof (sSrcPixMap));
732     memset (&sRefPixMap, 0, sizeof (sRefPixMap));
733     SBGDInterface BGDParam = {0};
734 
735     sSrcPixMap.pPixel[0] = pCurPicture->pData[0];
736     sSrcPixMap.pPixel[1] = pCurPicture->pData[1];
737     sSrcPixMap.pPixel[2] = pCurPicture->pData[2];
738     sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
739     sSrcPixMap.iStride[0] = pCurPicture->iLineSize[0];
740     sSrcPixMap.iStride[1] = pCurPicture->iLineSize[1];
741     sSrcPixMap.iStride[2] = pCurPicture->iLineSize[2];
742     sSrcPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
743     sSrcPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
744     sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
745 
746     sRefPixMap.pPixel[0] = pRefPicture->pData[0];
747     sRefPixMap.pPixel[1] = pRefPicture->pData[1];
748     sRefPixMap.pPixel[2] = pRefPicture->pData[2];
749     sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
750     sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
751     sRefPixMap.iStride[1] = pRefPicture->iLineSize[1];
752     sRefPixMap.iStride[2] = pRefPicture->iLineSize[2];
753     sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
754     sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
755     sRefPixMap.eFormat = VIDEO_FORMAT_I420;
756 
757     BGDParam.pBackgroundMbFlag = pVaaInfo->pVaaBackgroundMbFlag;
758     BGDParam.pCalcRes = & (pVaaInfo->sVaaCalcInfo);
759     m_pInterfaceVp->Set (iMethodIdx, (void*)&BGDParam);
760     m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sRefPixMap);
761   } else {
762     int32_t iPicWidthInMb  = (pCurPicture->iWidthInPixel  + 15) >> 4;
763     int32_t iPicHeightInMb = (pCurPicture->iHeightInPixel + 15) >> 4;
764     memset (pVaaInfo->pVaaBackgroundMbFlag, 0, iPicWidthInMb * iPicHeightInMb);
765   }
766 }
767 
AdaptiveQuantCalculation(SVAAFrameInfo * pVaaInfo,SPicture * pCurPicture,SPicture * pRefPicture)768 void CWelsPreProcess::AdaptiveQuantCalculation (SVAAFrameInfo* pVaaInfo, SPicture* pCurPicture, SPicture* pRefPicture) {
769   pVaaInfo->sAdaptiveQuantParam.pCalcResult = & (pVaaInfo->sVaaCalcInfo);
770   pVaaInfo->sAdaptiveQuantParam.iAverMotionTextureIndexToDeltaQp = 0;
771 
772   {
773     int32_t iMethodIdx = METHOD_ADAPTIVE_QUANT;
774     SPixMap pSrc;
775     SPixMap pRef;
776     memset (&pSrc, 0, sizeof (pSrc));
777     memset (&pRef, 0, sizeof (pRef));
778     int32_t iRet = 0;
779 
780     pSrc.pPixel[0] = pCurPicture->pData[0];
781     pSrc.iSizeInBits = g_kiPixMapSizeInBits;
782     pSrc.iStride[0] = pCurPicture->iLineSize[0];
783     pSrc.sRect.iRectWidth = pCurPicture->iWidthInPixel;
784     pSrc.sRect.iRectHeight = pCurPicture->iHeightInPixel;
785     pSrc.eFormat = VIDEO_FORMAT_I420;
786 
787     pRef.pPixel[0] = pRefPicture->pData[0];
788     pRef.iSizeInBits = g_kiPixMapSizeInBits;
789     pRef.iStride[0] = pRefPicture->iLineSize[0];
790     pRef.sRect.iRectWidth = pRefPicture->iWidthInPixel;
791     pRef.sRect.iRectHeight = pRefPicture->iHeightInPixel;
792     pRef.eFormat = VIDEO_FORMAT_I420;
793 
794     iRet = m_pInterfaceVp->Set (iMethodIdx, (void*) & (pVaaInfo->sAdaptiveQuantParam));
795     iRet = m_pInterfaceVp->Process (iMethodIdx, &pSrc, &pRef);
796     if (iRet == 0)
797       m_pInterfaceVp->Get (iMethodIdx, (void*) & (pVaaInfo->sAdaptiveQuantParam));
798   }
799 }
800 
SetRefMbType(sWelsEncCtx * pCtx,uint32_t ** pRefMbTypeArray,int32_t iRefPicType)801 void CWelsPreProcess::SetRefMbType (sWelsEncCtx* pCtx, uint32_t** pRefMbTypeArray, int32_t iRefPicType) {
802   const uint8_t uiTid       = pCtx->uiTemporalId;
803   const uint8_t uiDid       = pCtx->uiDependencyId;
804   SRefList* pRefPicLlist    = pCtx->ppRefPicListExt[uiDid];
805   SLTRState* pLtr           = &pCtx->pLtr[uiDid];
806   uint8_t i = 0;
807 
808   if (pCtx->pSvcParam->bEnableLongTermReference && pLtr->bReceivedT0LostFlag && uiTid == 0) {
809     for (i = 0; i < pRefPicLlist->uiLongRefCount; i++) {
810       SPicture* pRef = pRefPicLlist->pLongRefList[i];
811       if (pRef != NULL && pRef->uiRecieveConfirmed == 1/*RECIEVE_SUCCESS*/) {
812         *pRefMbTypeArray = pRef->uiRefMbType;
813         break;
814       }
815     }
816   } else {
817     for (i = 0; i < pRefPicLlist->uiShortRefCount; i++) {
818       SPicture* pRef = pRefPicLlist->pShortRefList[i];
819       if (pRef != NULL && pRef->bUsedAsRef && pRef->iFramePoc >= 0 && pRef->uiTemporalId <= uiTid) {
820         *pRefMbTypeArray = pRef->uiRefMbType;
821         break;
822       }
823     }
824   }
825 }
826 
827 
AnalyzePictureComplexity(sWelsEncCtx * pCtx,SPicture * pCurPicture,SPicture * pRefPicture,const int32_t kiDependencyId,const bool bCalculateBGD)828 void CWelsPreProcess::AnalyzePictureComplexity (sWelsEncCtx* pCtx, SPicture* pCurPicture, SPicture* pRefPicture,
829     const int32_t kiDependencyId, const bool bCalculateBGD) {
830   SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam;
831   int32_t iComplexityAnalysisMode = 0;
832 
833   if (pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME) {
834     SVAAFrameInfoExt* pVaaExt = static_cast<SVAAFrameInfoExt*> (pCtx->pVaa);
835     SComplexityAnalysisScreenParam* sComplexityAnalysisParam = &pVaaExt->sComplexityScreenParam;
836     SWelsSvcRc* pWelsSvcRc = &pCtx->pWelsSvcRc[kiDependencyId];
837 
838     if (pCtx->eSliceType == P_SLICE)
839       iComplexityAnalysisMode = GOM_SAD;
840     else if (pCtx->eSliceType == I_SLICE)
841       iComplexityAnalysisMode = GOM_VAR;
842     else
843       return;
844 
845     memset (pWelsSvcRc->pGomForegroundBlockNum, 0, pWelsSvcRc->iGomSize * sizeof (int32_t));
846     memset (pWelsSvcRc->pCurrentFrameGomSad, 0, pWelsSvcRc->iGomSize * sizeof (int32_t));
847 
848     sComplexityAnalysisParam->iFrameComplexity = 0;
849     sComplexityAnalysisParam->pGomComplexity = pWelsSvcRc->pCurrentFrameGomSad;
850     sComplexityAnalysisParam->iGomNumInFrame = pWelsSvcRc->iGomSize;
851     sComplexityAnalysisParam->iIdrFlag = (pCtx->eSliceType == I_SLICE);
852     sComplexityAnalysisParam->iMbRowInGom = GOM_H_SCC;
853     sComplexityAnalysisParam->sScrollResult.bScrollDetectFlag = false;
854     sComplexityAnalysisParam->sScrollResult.iScrollMvX = 0;
855     sComplexityAnalysisParam->sScrollResult.iScrollMvY = 0;
856 
857     const int32_t iMethodIdx = METHOD_COMPLEXITY_ANALYSIS_SCREEN;
858     SPixMap sSrcPixMap;
859     SPixMap sRefPixMap;
860     memset (&sSrcPixMap, 0, sizeof (SPixMap));
861     memset (&sRefPixMap, 0, sizeof (SPixMap));
862     int32_t iRet = 0;
863 
864     sSrcPixMap.pPixel[0] = pCurPicture->pData[0];
865     sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
866     sSrcPixMap.iStride[0] = pCurPicture->iLineSize[0];
867     sSrcPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
868     sSrcPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
869     sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
870 
871     if (pRefPicture != NULL) {
872       sRefPixMap.pPixel[0] = pRefPicture->pData[0];
873       sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
874       sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
875       sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
876       sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
877       sRefPixMap.eFormat = VIDEO_FORMAT_I420;
878     }
879 
880     iRet = m_pInterfaceVp->Set (iMethodIdx, (void*)sComplexityAnalysisParam);
881     iRet = m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sRefPixMap);
882     if (iRet == 0)
883       m_pInterfaceVp->Get (iMethodIdx, (void*)sComplexityAnalysisParam);
884 
885   } else {
886     SVAAFrameInfo* pVaaInfo = pCtx->pVaa;
887     SComplexityAnalysisParam* sComplexityAnalysisParam = & (pVaaInfo->sComplexityAnalysisParam);
888     SWelsSvcRc* SWelsSvcRc = &pCtx->pWelsSvcRc[kiDependencyId];
889 
890     if (pSvcParam->iRCMode == RC_QUALITY_MODE && pCtx->eSliceType == P_SLICE) {
891       iComplexityAnalysisMode = FRAME_SAD;
892     } else if (((pSvcParam->iRCMode == RC_BITRATE_MODE) || (pSvcParam->iRCMode == RC_TIMESTAMP_MODE))
893                && pCtx->eSliceType == P_SLICE) {
894       iComplexityAnalysisMode = GOM_SAD;
895     } else if (((pSvcParam->iRCMode == RC_BITRATE_MODE) || (pSvcParam->iRCMode == RC_TIMESTAMP_MODE))
896                && pCtx->eSliceType == I_SLICE) {
897       iComplexityAnalysisMode = GOM_VAR;
898     } else {
899       return;
900     }
901 
902     sComplexityAnalysisParam->iComplexityAnalysisMode = iComplexityAnalysisMode;
903     sComplexityAnalysisParam->pCalcResult = & (pVaaInfo->sVaaCalcInfo);
904     sComplexityAnalysisParam->pBackgroundMbFlag = pVaaInfo->pVaaBackgroundMbFlag;
905     if (pRefPicture)
906       SetRefMbType (pCtx, & (sComplexityAnalysisParam->uiRefMbType), pRefPicture->iPictureType);
907     sComplexityAnalysisParam->iCalcBgd = bCalculateBGD;
908     sComplexityAnalysisParam->iFrameComplexity = 0;
909 
910     memset (SWelsSvcRc->pGomForegroundBlockNum, 0, SWelsSvcRc->iGomSize * sizeof (int32_t));
911     if (iComplexityAnalysisMode != FRAME_SAD)
912       memset (SWelsSvcRc->pCurrentFrameGomSad, 0, SWelsSvcRc->iGomSize * sizeof (int32_t));
913 
914     sComplexityAnalysisParam->pGomComplexity = SWelsSvcRc->pCurrentFrameGomSad;
915     sComplexityAnalysisParam->pGomForegroundBlockNum = SWelsSvcRc->pGomForegroundBlockNum;
916     sComplexityAnalysisParam->iMbNumInGom = SWelsSvcRc->iNumberMbGom;
917 
918     {
919       int32_t iMethodIdx = METHOD_COMPLEXITY_ANALYSIS;
920       SPixMap sSrcPixMap;
921       SPixMap sRefPixMap;
922       memset (&sSrcPixMap, 0, sizeof (SPixMap));
923       memset (&sRefPixMap, 0, sizeof (SPixMap));
924       int32_t iRet = 0;
925 
926       sSrcPixMap.pPixel[0] = pCurPicture->pData[0];
927       sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
928       sSrcPixMap.iStride[0] = pCurPicture->iLineSize[0];
929       sSrcPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
930       sSrcPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
931       sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
932 
933       if (pRefPicture) {
934         sRefPixMap.pPixel[0] = pRefPicture->pData[0];
935         sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
936         sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
937         sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
938         sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
939       }
940       sRefPixMap.eFormat = VIDEO_FORMAT_I420;
941 
942       iRet = m_pInterfaceVp->Set (iMethodIdx, (void*)sComplexityAnalysisParam);
943       iRet = m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sRefPixMap);
944       if (iRet == 0)
945         m_pInterfaceVp->Get (iMethodIdx, (void*)sComplexityAnalysisParam);
946     }
947   }
948 }
949 
950 
InitPixMap(const SPicture * pPicture,SPixMap * pPixMap)951 void CWelsPreProcess::InitPixMap (const SPicture* pPicture, SPixMap* pPixMap) {
952   pPixMap->pPixel[0] = pPicture->pData[0];
953   pPixMap->pPixel[1] = pPicture->pData[1];
954   pPixMap->pPixel[2] = pPicture->pData[2];
955   pPixMap->iSizeInBits = sizeof (uint8_t);
956   pPixMap->iStride[0] = pPicture->iLineSize[0];
957   pPixMap->iStride[1] = pPicture->iLineSize[1];
958   pPixMap->sRect.iRectWidth = pPicture->iWidthInPixel;
959   pPixMap->sRect.iRectHeight = pPicture->iHeightInPixel;
960 
961   pPixMap->eFormat = VIDEO_FORMAT_I420;
962 }
963 
GetReferenceSrcPicList(int32_t iTargetDid)964 SPicture** CWelsPreProcessScreen::GetReferenceSrcPicList (int32_t iTargetDid) {
965   return (&m_pSpatialPic[iTargetDid][1]);
966 }
967 
GetAvailableRefListLosslessScreenRefSelection(SPicture ** pRefPicList,uint8_t iCurTid,const int32_t iClosestLtrFrameNum,SRefInfoParam * pAvailableRefParam,int32_t & iAvailableRefNum,int32_t & iAvailableSceneRefNum)968 void CWelsPreProcessScreen::GetAvailableRefListLosslessScreenRefSelection (SPicture** pRefPicList, uint8_t iCurTid,
969     const int32_t iClosestLtrFrameNum,
970     SRefInfoParam* pAvailableRefParam, int32_t& iAvailableRefNum, int32_t& iAvailableSceneRefNum) {
971   const int32_t iSourcePicNum = m_iAvaliableRefInSpatialPicList;
972   if (0 >= iSourcePicNum) {
973     iAvailableRefNum = 0;
974     iAvailableSceneRefNum = 0;
975     return ;
976   }
977   const bool bCurFrameMarkedAsSceneLtr = m_pEncCtx->bCurFrameMarkedAsSceneLtr;
978   SPicture* pRefPic = NULL;
979   uint8_t uiRefTid = 0;
980   bool bRefRealLtr = false;
981 
982   iAvailableRefNum = 1; //zero is left for the closest frame
983   iAvailableSceneRefNum = 0;
984 
985   //the saving order will be depend on pSrcPicList
986   //TODO: use a frame_idx to find the closer ref in time distance, and correctly sort the ref list
987   for (int32_t i = iSourcePicNum - 1; i >= 0; --i) {
988     pRefPic = pRefPicList[i];
989     if (NULL == pRefPic || !pRefPic->bUsedAsRef || !pRefPic->bIsLongRef || (bCurFrameMarkedAsSceneLtr
990         && (!pRefPic->bIsSceneLTR))) {
991       continue;
992     }
993     uiRefTid = pRefPic->uiTemporalId;
994     bRefRealLtr = pRefPic->bIsSceneLTR;
995 
996     if (bRefRealLtr || (0 == iCurTid && 0 == uiRefTid) || (uiRefTid < iCurTid)) {
997       int32_t idx = (pRefPic->iLongTermPicNum == iClosestLtrFrameNum) ? (0) : (iAvailableRefNum++);
998       pAvailableRefParam[idx].pRefPicture = pRefPic;
999       pAvailableRefParam[idx].iSrcListIdx = i + 1; //in SrcList, the idx 0 is reserved for CurPic
1000       iAvailableSceneRefNum += bRefRealLtr;
1001     }
1002   }
1003 
1004   if (pAvailableRefParam[0].pRefPicture == NULL) {
1005     for (int32_t i = 1; i < iAvailableRefNum ; ++i) {
1006       pAvailableRefParam[i - 1].pRefPicture = pAvailableRefParam[i].pRefPicture;
1007       pAvailableRefParam[i - 1].iSrcListIdx = pAvailableRefParam[i].iSrcListIdx;
1008     }
1009 
1010     pAvailableRefParam[iAvailableRefNum - 1].pRefPicture = NULL;
1011     pAvailableRefParam[iAvailableRefNum - 1].iSrcListIdx = 0;
1012     --iAvailableRefNum;
1013   }
1014 }
1015 
1016 
GetAvailableRefList(SPicture ** pSrcPicList,uint8_t iCurTid,const int32_t iClosestLtrFrameNum,SRefInfoParam * pAvailableRefList,int32_t & iAvailableRefNum,int32_t & iAvailableSceneRefNum)1017 void CWelsPreProcessScreen::GetAvailableRefList (SPicture** pSrcPicList, uint8_t iCurTid,
1018     const int32_t iClosestLtrFrameNum,
1019     SRefInfoParam* pAvailableRefList, int32_t& iAvailableRefNum, int32_t& iAvailableSceneRefNum) {
1020   const int32_t iSourcePicNum = m_iAvaliableRefInSpatialPicList;
1021   if (0 >= iSourcePicNum) {
1022     iAvailableRefNum = 0;
1023     iAvailableSceneRefNum = 0;
1024     return ;
1025   }
1026   SPicture* pRefPic = NULL;
1027   uint8_t uiRefTid = 0;
1028   iAvailableRefNum = 0;
1029   iAvailableSceneRefNum = 0;
1030 
1031   //the saving order will be depend on pSrcPicList
1032   //TODO: use a frame_idx to find the closer ref in time distance, and correctly sort the ref list
1033   for (int32_t i = iSourcePicNum - 1; i >= 0; --i) {
1034     pRefPic = pSrcPicList[i];
1035     if (NULL == pRefPic || !pRefPic->bUsedAsRef) {
1036       continue;
1037     }
1038     uiRefTid = pRefPic->uiTemporalId;
1039 
1040     if (uiRefTid <= iCurTid) {
1041       pAvailableRefList[iAvailableRefNum].pRefPicture = pRefPic;
1042       pAvailableRefList[iAvailableRefNum].iSrcListIdx = i + 1; //in SrcList, the idx 0 is reserved for CurPic
1043       iAvailableRefNum ++;
1044     }
1045   }
1046 }
1047 
1048 
InitRefJudgement(SRefJudgement * pRefJudgement)1049 void CWelsPreProcessScreen::InitRefJudgement (SRefJudgement* pRefJudgement) {
1050   pRefJudgement->iMinFrameComplexity = INT_MAX;
1051   pRefJudgement->iMinFrameComplexity08 = INT_MAX;
1052   pRefJudgement->iMinFrameComplexity11 = INT_MAX;
1053 
1054   pRefJudgement->iMinFrameNumGap = INT_MAX;
1055   pRefJudgement->iMinFrameQp = INT_MAX;
1056 }
JudgeBestRef(SPicture * pRefPic,const SRefJudgement & sRefJudgement,const int64_t iFrameComplexity,const bool bIsClosestLtrFrame)1057 bool CWelsPreProcessScreen::JudgeBestRef (SPicture* pRefPic, const SRefJudgement& sRefJudgement,
1058     const int64_t iFrameComplexity, const bool bIsClosestLtrFrame) {
1059   return (bIsClosestLtrFrame ? (iFrameComplexity < sRefJudgement.iMinFrameComplexity11) :
1060           ((iFrameComplexity < sRefJudgement.iMinFrameComplexity08) || ((iFrameComplexity <= sRefJudgement.iMinFrameComplexity11)
1061               && (pRefPic->iFrameAverageQp < sRefJudgement.iMinFrameQp))));
1062 }
1063 
SaveBestRefToJudgement(const int32_t iRefPictureAvQP,const int64_t iComplexity,SRefJudgement * pRefJudgement)1064 void CWelsPreProcessScreen::SaveBestRefToJudgement (const int32_t iRefPictureAvQP, const int64_t iComplexity,
1065     SRefJudgement* pRefJudgement) {
1066   pRefJudgement->iMinFrameQp = iRefPictureAvQP;
1067   pRefJudgement->iMinFrameComplexity =  iComplexity;
1068   pRefJudgement->iMinFrameComplexity08 = static_cast<int32_t> (iComplexity * 0.8);
1069   pRefJudgement->iMinFrameComplexity11 = static_cast<int32_t> (iComplexity * 1.1);
1070 }
SaveBestRefToLocal(SRefInfoParam * pRefPicInfo,const SSceneChangeResult & sSceneChangeResult,SRefInfoParam * pRefSaved)1071 void CWelsPreProcessScreen::SaveBestRefToLocal (SRefInfoParam* pRefPicInfo,
1072     const SSceneChangeResult& sSceneChangeResult,
1073     SRefInfoParam* pRefSaved) {
1074   memcpy (pRefSaved, pRefPicInfo, sizeof (SRefInfoParam));
1075   pRefSaved->pBestBlockStaticIdc = sSceneChangeResult.pStaticBlockIdc;
1076 }
1077 
SaveBestRefToVaa(SRefInfoParam & sRefSaved,SRefInfoParam * pVaaBestRef)1078 void CWelsPreProcessScreen::SaveBestRefToVaa (SRefInfoParam& sRefSaved, SRefInfoParam* pVaaBestRef) {
1079   (*pVaaBestRef) = sRefSaved;
1080 }
1081 
GetCurrentOrigFrame(int32_t iDIdx)1082 SPicture* CWelsPreProcessScreen::GetCurrentOrigFrame (int32_t iDIdx) {
1083   return m_pSpatialPic[iDIdx][0];
1084 }
1085 
DetectSceneChange(SPicture * pCurPicture,SPicture * pRef)1086 ESceneChangeIdc CWelsPreProcessScreen::DetectSceneChange (SPicture* pCurPicture, SPicture* pRef) {
1087   sWelsEncCtx* pCtx = m_pEncCtx;
1088 #define STATIC_SCENE_MOTION_RATIO 0.01f
1089   SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam;
1090   SVAAFrameInfoExt* pVaaExt = static_cast<SVAAFrameInfoExt*> (pCtx->pVaa);
1091   SSpatialLayerInternal* pParamInternal = &pSvcParam->sDependencyLayers[0];
1092   if (NULL == pCtx || NULL == pVaaExt || NULL == pCurPicture) {
1093     return LARGE_CHANGED_SCENE;
1094   }
1095 
1096   const int32_t iTargetDid = pSvcParam->iSpatialLayerNum - 1;
1097   if (0 != iTargetDid) {
1098     return LARGE_CHANGED_SCENE;
1099   }
1100 
1101   ESceneChangeIdc iVaaFrameSceneChangeIdc = LARGE_CHANGED_SCENE;
1102   SPicture** pRefPicList = GetReferenceSrcPicList (iTargetDid);
1103   if (NULL == pRefPicList) {
1104     return LARGE_CHANGED_SCENE;
1105   }
1106 
1107   SRefInfoParam sAvailableRefParam[MAX_REF_PIC_COUNT] = { { 0 } };
1108   int32_t iAvailableRefNum = 0;
1109   int32_t iAvailableSceneRefNum = 0;
1110 
1111   int32_t iSceneChangeMethodIdx = METHOD_SCENE_CHANGE_DETECTION_SCREEN;
1112   SSceneChangeResult sSceneChangeResult = {SIMILAR_SCENE, 0, 0, NULL};
1113 
1114   SPixMap sSrcMap = { { 0 } };
1115   SPixMap sRefMap = { { 0 } };
1116   SRefJudgement sLtrJudgement;
1117   SRefJudgement sSceneLtrJudgement;
1118   SRefInfoParam sLtrSaved = {0};
1119   SRefInfoParam sSceneLtrSaved = {0};
1120 
1121   int32_t iNumOfLargeChange = 0, iNumOfMediumChangeToLtr = 0;
1122 
1123   bool bIsClosestLtrFrame = false;
1124   int32_t ret = 1, iScdIdx = 0;
1125 
1126   SPicture* pRefPic = NULL;
1127   SRefInfoParam* pRefPicInfo = NULL;
1128   uint8_t*  pCurBlockStaticPointer = NULL;
1129   SLogContext* pLogCtx = & (pCtx->sLogCtx);
1130   const int32_t iNegligibleMotionBlocks = (static_cast<int32_t> ((pCurPicture->iWidthInPixel >> 3) *
1131                                           (pCurPicture->iHeightInPixel >> 3) * STATIC_SCENE_MOTION_RATIO));
1132   const uint8_t iCurTid = GetTemporalLevel (&pSvcParam->sDependencyLayers[m_pEncCtx->sSpatialIndexMap[0].iDid],
1133                           pParamInternal->iCodingIndex, pSvcParam->uiGopSize);
1134   if (iCurTid == INVALID_TEMPORAL_ID) {
1135     return LARGE_CHANGED_SCENE;
1136   }
1137   const int32_t iClosestLtrFrameNum = pCtx->pLtr[iTargetDid].iLastLtrIdx[iCurTid];
1138   if (pSvcParam->bEnableLongTermReference) {
1139     GetAvailableRefListLosslessScreenRefSelection (pRefPicList, iCurTid, iClosestLtrFrameNum, &sAvailableRefParam[0],
1140         iAvailableRefNum,
1141         iAvailableSceneRefNum);
1142   } else {
1143     GetAvailableRefList (pRefPicList, iCurTid, iClosestLtrFrameNum, &sAvailableRefParam[0], iAvailableRefNum,
1144                          iAvailableSceneRefNum);
1145   }
1146   //after this build, pAvailableRefList[idx].iSrcListIdx is the idx of the ref in h->spatial_pic
1147   if (0 == iAvailableRefNum) {
1148     WelsLog (pLogCtx, WELS_LOG_ERROR, "SceneChangeDetect() iAvailableRefNum=0 but not I.");
1149     return LARGE_CHANGED_SCENE;
1150   }
1151 
1152   InitPixMap (pCurPicture, &sSrcMap);
1153   InitRefJudgement (&sLtrJudgement);
1154   InitRefJudgement (&sSceneLtrJudgement);
1155 
1156   for (iScdIdx = 0; iScdIdx < iAvailableRefNum; iScdIdx ++) {
1157     pCurBlockStaticPointer = pVaaExt->pVaaBlockStaticIdc[iScdIdx];
1158     sSceneChangeResult.eSceneChangeIdc = SIMILAR_SCENE;
1159     sSceneChangeResult.pStaticBlockIdc = pCurBlockStaticPointer;
1160     sSceneChangeResult.sScrollResult.bScrollDetectFlag = false;
1161 
1162     pRefPicInfo = & (sAvailableRefParam[iScdIdx]);
1163     assert (NULL != pRefPicInfo);
1164     pRefPic = pRefPicInfo->pRefPicture;
1165     InitPixMap (pRefPic, &sRefMap);
1166 
1167     bIsClosestLtrFrame = (pRefPic->iLongTermPicNum == iClosestLtrFrameNum);
1168     if (0 == iScdIdx) {
1169       int32_t ret = 1;
1170       SScrollDetectionParam* pScrollDetectInfo = & (pVaaExt->sScrollDetectInfo);
1171       memset (pScrollDetectInfo, 0, sizeof (SScrollDetectionParam));
1172 
1173       int32_t iMethodIdx = METHOD_SCROLL_DETECTION;
1174 
1175       m_pInterfaceVp->Set (iMethodIdx, (void*) (pScrollDetectInfo));
1176       ret = m_pInterfaceVp->Process (iMethodIdx, &sSrcMap, &sRefMap);
1177 
1178       if (ret == 0) {
1179         m_pInterfaceVp->Get (iMethodIdx, (void*) (pScrollDetectInfo));
1180       }
1181       sSceneChangeResult.sScrollResult = pVaaExt->sScrollDetectInfo;
1182     }
1183 
1184     m_pInterfaceVp->Set (iSceneChangeMethodIdx, (void*) (&sSceneChangeResult));
1185     ret = m_pInterfaceVp->Process (iSceneChangeMethodIdx, &sSrcMap, &sRefMap);
1186 
1187     if (ret == 0) {
1188       m_pInterfaceVp->Get (iSceneChangeMethodIdx, (void*)&sSceneChangeResult);
1189 
1190       const int64_t iFrameComplexity = sSceneChangeResult.iFrameComplexity;
1191       const int32_t iSceneDetectIdc = sSceneChangeResult.eSceneChangeIdc;
1192       const int32_t iMotionBlockNum = sSceneChangeResult.iMotionBlockNum;
1193 
1194       const bool bCurRefIsSceneLtr = pRefPic->bIsSceneLTR;
1195       const int32_t iRefPicAvQP = pRefPic->iFrameAverageQp;
1196 
1197       //for scene change detection
1198       iNumOfLargeChange += (static_cast<int32_t> (LARGE_CHANGED_SCENE == iSceneDetectIdc));
1199       iNumOfMediumChangeToLtr += (static_cast<int32_t> ((bCurRefIsSceneLtr) && (iSceneDetectIdc != SIMILAR_SCENE)));
1200 
1201       //for reference selection
1202       //this judge can only be saved when iAvailableRefNum==1, which is very limit
1203       //when LTR is OFF, it can still judge from all available STR
1204       if (JudgeBestRef (pRefPic, sLtrJudgement, iFrameComplexity, bIsClosestLtrFrame)) {
1205         SaveBestRefToJudgement (iRefPicAvQP, iFrameComplexity, &sLtrJudgement);
1206         SaveBestRefToLocal (pRefPicInfo, sSceneChangeResult, &sLtrSaved);
1207       }
1208       if (bCurRefIsSceneLtr && JudgeBestRef (pRefPic, sSceneLtrJudgement, iFrameComplexity, bIsClosestLtrFrame)) {
1209         SaveBestRefToJudgement (iRefPicAvQP, iFrameComplexity, &sSceneLtrJudgement);
1210         SaveBestRefToLocal (pRefPicInfo, sSceneChangeResult, &sSceneLtrSaved);
1211       }
1212 
1213       if (iMotionBlockNum <= iNegligibleMotionBlocks) {
1214         break;
1215       }
1216     }
1217   }
1218 
1219   if (iNumOfLargeChange == iAvailableRefNum) {
1220     iVaaFrameSceneChangeIdc = LARGE_CHANGED_SCENE;
1221   } else if ((iNumOfMediumChangeToLtr == iAvailableSceneRefNum) && (0 != iAvailableSceneRefNum)) {
1222     iVaaFrameSceneChangeIdc = MEDIUM_CHANGED_SCENE;
1223   } else {
1224     iVaaFrameSceneChangeIdc = SIMILAR_SCENE;
1225   }
1226 
1227   WelsLog (pLogCtx, WELS_LOG_DEBUG, "iVaaFrameSceneChangeIdc = %d,codingIdx = %d", iVaaFrameSceneChangeIdc,
1228            pParamInternal->iCodingIndex);
1229 
1230   SaveBestRefToVaa (sLtrSaved, & (pVaaExt->sVaaStrBestRefCandidate[0]));
1231   pVaaExt->iVaaBestRefFrameNum = sLtrSaved.pRefPicture->iFrameNum;
1232   pVaaExt->pVaaBestBlockStaticIdc = sLtrSaved.pBestBlockStaticIdc;
1233 
1234   if (0 < iAvailableSceneRefNum) {
1235     SaveBestRefToVaa (sSceneLtrSaved, & (pVaaExt->sVaaLtrBestRefCandidate[0]));
1236   }
1237 
1238   pVaaExt->iNumOfAvailableRef = 1;
1239   return static_cast<ESceneChangeIdc> (iVaaFrameSceneChangeIdc);
1240 }
1241 
GetRefFrameInfo(int32_t iRefIdx,bool bCurrentFrameIsSceneLtr,SPicture * & pRefOri)1242 int32_t CWelsPreProcess::GetRefFrameInfo (int32_t iRefIdx, bool bCurrentFrameIsSceneLtr, SPicture*& pRefOri) {
1243   const int32_t iTargetDid = m_pEncCtx->pSvcParam->iSpatialLayerNum - 1;
1244   SVAAFrameInfoExt* pVaaExt = static_cast<SVAAFrameInfoExt*> (m_pEncCtx->pVaa);
1245   SRefInfoParam* pBestRefCandidateParam = (bCurrentFrameIsSceneLtr) ? (& (pVaaExt->sVaaLtrBestRefCandidate[iRefIdx])) :
1246                                           (& (pVaaExt->sVaaStrBestRefCandidate[iRefIdx]));
1247   pRefOri = m_pSpatialPic[iTargetDid][pBestRefCandidateParam->iSrcListIdx];
1248   return (m_pSpatialPic[iTargetDid][pBestRefCandidateParam->iSrcListIdx]->iLongTermPicNum);
1249 }
Padding(uint8_t * pSrcY,uint8_t * pSrcU,uint8_t * pSrcV,int32_t iStrideY,int32_t iStrideUV,int32_t iActualWidth,int32_t iPaddingWidth,int32_t iActualHeight,int32_t iPaddingHeight)1250 void  CWelsPreProcess::Padding (uint8_t* pSrcY, uint8_t* pSrcU, uint8_t* pSrcV, int32_t iStrideY, int32_t iStrideUV,
1251                                 int32_t iActualWidth, int32_t iPaddingWidth, int32_t iActualHeight, int32_t iPaddingHeight) {
1252   int32_t i;
1253 
1254   if (iPaddingHeight > iActualHeight) {
1255     for (i = iActualHeight; i < iPaddingHeight; i++) {
1256       memset (pSrcY + i * iStrideY, 0, iActualWidth);
1257 
1258       if (! (i & 1)) {
1259         memset (pSrcU + i / 2 * iStrideUV, 0x80, iActualWidth / 2);
1260         memset (pSrcV + i / 2 * iStrideUV, 0x80, iActualWidth / 2);
1261       }
1262     }
1263   }
1264 
1265   if (iPaddingWidth > iActualWidth) {
1266     for (i = 0; i < iPaddingHeight; i++) {
1267       memset (pSrcY + i * iStrideY + iActualWidth, 0, iPaddingWidth - iActualWidth);
1268       if (! (i & 1)) {
1269         memset (pSrcU + i / 2 * iStrideUV + iActualWidth / 2, 0x80, (iPaddingWidth - iActualWidth) / 2);
1270         memset (pSrcV + i / 2 * iStrideUV + iActualWidth / 2, 0x80, (iPaddingWidth - iActualWidth) / 2);
1271       }
1272     }
1273   }
1274 }
1275 
1276 
UpdateBlockIdcForScreen(uint8_t * pCurBlockStaticPointer,const SPicture * kpRefPic,const SPicture * kpSrcPic)1277 int32_t CWelsPreProcess::UpdateBlockIdcForScreen (uint8_t*  pCurBlockStaticPointer, const SPicture* kpRefPic,
1278     const SPicture* kpSrcPic) {
1279   int32_t iSceneChangeMethodIdx = METHOD_SCENE_CHANGE_DETECTION_SCREEN;
1280   SSceneChangeResult sSceneChangeResult = {SIMILAR_SCENE, 0, 0, NULL};
1281   sSceneChangeResult.pStaticBlockIdc = pCurBlockStaticPointer;
1282   sSceneChangeResult.sScrollResult.bScrollDetectFlag = false;
1283 
1284   SPixMap sSrcMap = { { 0 } };
1285   SPixMap sRefMap = { { 0 } };
1286   InitPixMap (kpSrcPic, &sSrcMap);
1287   InitPixMap (kpRefPic, &sRefMap);
1288 
1289   m_pInterfaceVp->Set (iSceneChangeMethodIdx, (void*) (&sSceneChangeResult));
1290   int32_t iRet = m_pInterfaceVp->Process (iSceneChangeMethodIdx, &sSrcMap, &sRefMap);
1291   if (iRet == 0) {
1292     m_pInterfaceVp->Get (iSceneChangeMethodIdx, (void*)&sSceneChangeResult);
1293     return 0;
1294   }
1295   return iRet;
1296 }
1297 
1298 /*!
1299 * \brief    exchange two picture pData planes
1300 * \param    ppPic1      picture pointer to picture 1
1301 * \param    ppPic2      picture pointer to picture 2
1302 * \return   none
1303 */
WelsExchangeSpatialPictures(SPicture ** ppPic1,SPicture ** ppPic2)1304 void CWelsPreProcess::WelsExchangeSpatialPictures (SPicture** ppPic1, SPicture** ppPic2) {
1305   SPicture* tmp = *ppPic1;
1306 
1307   assert (*ppPic1 != *ppPic2);
1308 
1309   *ppPic1 = *ppPic2;
1310   *ppPic2 = tmp;
1311 }
1312 
UpdateSrcListLosslessScreenRefSelectionWithLtr(SPicture * pCurPicture,const int32_t kiCurDid,const int32_t kuiMarkLongTermPicIdx,SPicture ** pLongRefList)1313 void CWelsPreProcess::UpdateSrcListLosslessScreenRefSelectionWithLtr (SPicture* pCurPicture, const int32_t kiCurDid,
1314     const int32_t kuiMarkLongTermPicIdx, SPicture** pLongRefList) {
1315   SPicture** pLongRefSrcList = &m_pSpatialPic[kiCurDid][0];
1316   for (int32_t i = 0; i < MAX_REF_PIC_COUNT; ++i) {
1317     if (NULL == pLongRefSrcList[i + 1] || (NULL != pLongRefList[i] && pLongRefList[i]->bUsedAsRef
1318                                            && pLongRefList[i]->bIsLongRef)) {
1319       continue;
1320     } else {
1321       pLongRefSrcList[i + 1]->SetUnref();
1322     }
1323   }
1324   WelsExchangeSpatialPictures (&m_pSpatialPic[kiCurDid][0],
1325                                &m_pSpatialPic[kiCurDid][1 + kuiMarkLongTermPicIdx]);
1326   m_iAvaliableRefInSpatialPicList = MAX_REF_PIC_COUNT;
1327   (GetCurrentOrigFrame (kiCurDid))->SetUnref();
1328 }
UpdateSrcList(SPicture * pCurPicture,const int32_t kiCurDid,SPicture ** pShortRefList,const uint32_t kuiShortRefCount)1329 void CWelsPreProcess::UpdateSrcList (SPicture* pCurPicture, const int32_t kiCurDid, SPicture** pShortRefList,
1330                                      const uint32_t kuiShortRefCount) {
1331   SPicture** pRefSrcList = &m_pSpatialPic[kiCurDid][0];
1332 
1333   //pRefSrcList[0] is for current frame
1334   if (pCurPicture->bUsedAsRef || pCurPicture->bIsLongRef) {
1335     if (pCurPicture->iPictureType == P_SLICE && pCurPicture->uiTemporalId != 0) {
1336       for (int iRefIdx = kuiShortRefCount - 1; iRefIdx >= 0; --iRefIdx) {
1337         WelsExchangeSpatialPictures (&pRefSrcList[iRefIdx + 1],
1338                                      &pRefSrcList[iRefIdx]);
1339       }
1340       m_iAvaliableRefInSpatialPicList = kuiShortRefCount;
1341     } else {
1342       WelsExchangeSpatialPictures (&pRefSrcList[0], &pRefSrcList[1]);
1343       for (int32_t i = MAX_SHORT_REF_COUNT - 1; i > 0  ; --i) {
1344         if (pRefSrcList[i + 1] != NULL) {
1345           pRefSrcList[i + 1]->SetUnref();
1346         }
1347       }
1348       m_iAvaliableRefInSpatialPicList = 1;
1349     }
1350   }
1351   (GetCurrentOrigFrame (kiCurDid))->SetUnref();
1352 }
1353 
1354 //TODO: may opti later
1355 //TODO: not use this func?
WelsMemcpy(void * dst,const void * kpSrc,uint32_t uiSize)1356 void* WelsMemcpy (void* dst, const void* kpSrc, uint32_t uiSize) {
1357   return ::memcpy (dst, kpSrc, uiSize);
1358 }
WelsMemset(void * p,int32_t val,uint32_t uiSize)1359 void* WelsMemset (void* p, int32_t val, uint32_t uiSize) {
1360   return ::memset (p, val, uiSize);
1361 }
1362 
1363 //i420_to_i420_c
WelsMoveMemory_c(uint8_t * pDstY,uint8_t * pDstU,uint8_t * pDstV,int32_t iDstStrideY,int32_t iDstStrideUV,uint8_t * pSrcY,uint8_t * pSrcU,uint8_t * pSrcV,int32_t iSrcStrideY,int32_t iSrcStrideUV,int32_t iWidth,int32_t iHeight)1364 void  WelsMoveMemory_c (uint8_t* pDstY, uint8_t* pDstU, uint8_t* pDstV,  int32_t iDstStrideY, int32_t iDstStrideUV,
1365                         uint8_t* pSrcY, uint8_t* pSrcU, uint8_t* pSrcV, int32_t iSrcStrideY, int32_t iSrcStrideUV, int32_t iWidth,
1366                         int32_t iHeight) {
1367   int32_t   iWidth2 = iWidth >> 1;
1368   int32_t   iHeight2 = iHeight >> 1;
1369   int32_t   j;
1370 
1371   for (j = iHeight; j; j--) {
1372     WelsMemcpy (pDstY, pSrcY, iWidth);
1373     pDstY += iDstStrideY;
1374     pSrcY += iSrcStrideY;
1375   }
1376 
1377   for (j = iHeight2; j; j--) {
1378     WelsMemcpy (pDstU, pSrcU, iWidth2);
1379     WelsMemcpy (pDstV, pSrcV, iWidth2);
1380     pDstU += iDstStrideUV;
1381     pDstV += iDstStrideUV;
1382     pSrcU += iSrcStrideUV;
1383     pSrcV += iSrcStrideUV;
1384   }
1385 }
1386 
WelsMoveMemoryWrapper(SWelsSvcCodingParam * pSvcParam,SPicture * pDstPic,const SSourcePicture * kpSrc,const int32_t kiTargetWidth,const int32_t kiTargetHeight)1387 void  CWelsPreProcess::WelsMoveMemoryWrapper (SWelsSvcCodingParam* pSvcParam, SPicture* pDstPic,
1388     const SSourcePicture* kpSrc,
1389     const int32_t kiTargetWidth, const int32_t kiTargetHeight) {
1390   if (VIDEO_FORMAT_I420 != (kpSrc->iColorFormat & (~VIDEO_FORMAT_VFlip)))
1391     return;
1392 
1393   int32_t  iSrcWidth       = kpSrc->iPicWidth;
1394   int32_t  iSrcHeight      = kpSrc->iPicHeight;
1395 
1396   if (iSrcHeight > kiTargetHeight) iSrcHeight = kiTargetHeight;
1397   if (iSrcWidth > kiTargetWidth)   iSrcWidth  = kiTargetWidth;
1398 
1399   // copy from fr26 to fix the odd uiSize failed issue
1400   if (iSrcWidth & 0x1)  -- iSrcWidth;
1401   if (iSrcHeight & 0x1) -- iSrcHeight;
1402 
1403   const int32_t kiSrcTopOffsetY = pSvcParam->SUsedPicRect.iTop;
1404   const int32_t kiSrcTopOffsetUV = (kiSrcTopOffsetY >> 1);
1405   const int32_t kiSrcLeftOffsetY = pSvcParam->SUsedPicRect.iLeft;
1406   const int32_t kiSrcLeftOffsetUV = (kiSrcLeftOffsetY >> 1);
1407   int32_t  iSrcOffset[3]       = {0, 0, 0};
1408   iSrcOffset[0] = kpSrc->iStride[0] * kiSrcTopOffsetY + kiSrcLeftOffsetY;
1409   iSrcOffset[1] = kpSrc->iStride[1] * kiSrcTopOffsetUV + kiSrcLeftOffsetUV ;
1410   iSrcOffset[2] = kpSrc->iStride[2] * kiSrcTopOffsetUV + kiSrcLeftOffsetUV;
1411 
1412   uint8_t* pSrcY = kpSrc->pData[0] + iSrcOffset[0];
1413   uint8_t* pSrcU = kpSrc->pData[1] + iSrcOffset[1];
1414   uint8_t* pSrcV = kpSrc->pData[2] + iSrcOffset[2];
1415   const int32_t kiSrcStrideY = kpSrc->iStride[0];
1416   const int32_t kiSrcStrideUV = kpSrc->iStride[1];
1417 
1418   uint8_t* pDstY = pDstPic->pData[0];
1419   uint8_t* pDstU = pDstPic->pData[1];
1420   uint8_t* pDstV = pDstPic->pData[2];
1421   const int32_t kiDstStrideY = pDstPic->iLineSize[0];
1422   const int32_t kiDstStrideUV = pDstPic->iLineSize[1];
1423 
1424   if (pSrcY) {
1425     if (iSrcWidth <= 0 || iSrcHeight <= 0 || (iSrcWidth * iSrcHeight > (MAX_MBS_PER_FRAME << 8)))
1426       return;
1427     if (kiSrcTopOffsetY >= iSrcHeight || kiSrcLeftOffsetY >= iSrcWidth || iSrcWidth > kiSrcStrideY)
1428       return;
1429   }
1430   if (pDstY) {
1431     if (kiTargetWidth <= 0 || kiTargetHeight <= 0 || (kiTargetWidth * kiTargetHeight > (MAX_MBS_PER_FRAME << 8)))
1432       return;
1433     if (kiTargetWidth > kiDstStrideY)
1434       return;
1435   }
1436 
1437   if (pSrcY == NULL || pSrcU == NULL || pSrcV == NULL || pDstY == NULL || pDstU == NULL || pDstV == NULL
1438       || (iSrcWidth & 1) || (iSrcHeight & 1)) {
1439   } else {
1440     //i420_to_i420_c
1441     WelsMoveMemory_c (pDstY,  pDstU,  pDstV,  kiDstStrideY, kiDstStrideUV,
1442                       pSrcY,  pSrcU,  pSrcV, kiSrcStrideY, kiSrcStrideUV, iSrcWidth, iSrcHeight);
1443 
1444     //in VP Process
1445     if (kiTargetWidth > iSrcWidth || kiTargetHeight > iSrcHeight) {
1446       Padding (pDstY, pDstU, pDstV, kiDstStrideY, kiDstStrideUV, iSrcWidth, kiTargetWidth, iSrcHeight, kiTargetHeight);
1447     }
1448   }
1449 
1450 }
1451 
GetSceneChangeFlag(ESceneChangeIdc eSceneChangeIdc)1452 bool CWelsPreProcess::GetSceneChangeFlag (ESceneChangeIdc eSceneChangeIdc) {
1453   return ((eSceneChangeIdc == LARGE_CHANGED_SCENE) ? true : false);
1454 }
1455 
1456 
1457 //*********************************************************************************************************/
1458 } // namespace WelsEnc
1459