• 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    svc_mode_decision.c
33  *
34  * \brief Algorithmetic MD for:
35  * - multi-spatial Enhancement Layer MD;
36  * - Scrolling PSkip Decision for screen content
37  *
38  * \date    2009.7.29
39  *
40 
41  **************************************************************************************
42  */
43 #include "mv_pred.h"
44 #include "ls_defines.h"
45 #include "svc_base_layer_md.h"
46 #include "svc_mode_decision.h"
47 
48 namespace WelsEnc {
49 
50 //////////////
51 // MD for enhancement layers
52 //////////////
WelsMdSpatialelInterMbIlfmdNoilp(sWelsEncCtx * pEncCtx,SWelsMD * pWelsMd,SSlice * pSlice,SMB * pCurMb,const Mb_Type kuiRefMbType)53 void WelsMdSpatialelInterMbIlfmdNoilp (sWelsEncCtx* pEncCtx, SWelsMD* pWelsMd, SSlice* pSlice,
54                                        SMB* pCurMb, const Mb_Type kuiRefMbType) {
55   SDqLayer* pCurDqLayer = pEncCtx->pCurDqLayer;
56   SMbCache* pMbCache = &pSlice->sMbCacheInfo;
57 
58   const uint32_t kuiNeighborAvail = pCurMb->uiNeighborAvail;
59   const int32_t kiMbWidth = pCurDqLayer->iMbWidth;
60   const  SMB* kpTopMb = pCurMb - kiMbWidth;
61   const bool kbMbLeftAvailPskip = ((kuiNeighborAvail & LEFT_MB_POS) ? IS_SKIP ((pCurMb - 1)->uiMbType) : false);
62   const bool kbMbTopAvailPskip  = ((kuiNeighborAvail & TOP_MB_POS) ? IS_SKIP (kpTopMb->uiMbType) : false);
63   const bool kbMbTopLeftAvailPskip  = ((kuiNeighborAvail & TOPLEFT_MB_POS) ? IS_SKIP ((kpTopMb - 1)->uiMbType) : false);
64   const bool kbMbTopRightAvailPskip = ((kuiNeighborAvail & TOPRIGHT_MB_POS) ? IS_SKIP ((kpTopMb + 1)->uiMbType) : false);
65 
66   bool bTrySkip  = kbMbLeftAvailPskip | kbMbTopAvailPskip | kbMbTopLeftAvailPskip | kbMbTopRightAvailPskip;
67   bool bKeepSkip = kbMbLeftAvailPskip & kbMbTopAvailPskip & kbMbTopRightAvailPskip;
68   bool bSkip = false;
69 
70   if (pEncCtx->pFuncList->pfInterMdBackgroundDecision (pEncCtx, pWelsMd, pSlice, pCurMb, pMbCache, &bKeepSkip)) {
71     return;
72   }
73 
74   //step 1: try SKIP
75   bSkip = WelsMdInterJudgePskip (pEncCtx, pWelsMd, pSlice, pCurMb, pMbCache, bTrySkip);
76 
77   if (bSkip && bKeepSkip) {
78     WelsMdInterDecidedPskip (pEncCtx,  pSlice,  pCurMb, pMbCache);
79     return;
80   }
81 
82   if (! IS_SVC_INTRA (kuiRefMbType)) {
83     if (!bSkip) {
84       PredictSad (pMbCache->sMvComponents.iRefIndexCache, pMbCache->iSadCost, 0, &pWelsMd->iSadPredMb);
85 
86       //step 2: P_16x16
87       pWelsMd->iCostLuma = WelsMdP16x16 (pEncCtx->pFuncList, pCurDqLayer, pWelsMd, pSlice, pCurMb);
88       pCurMb->uiMbType = MB_TYPE_16x16;
89     }
90 
91     WelsMdInterSecondaryModesEnc (pEncCtx, pWelsMd, pSlice, pCurMb, pMbCache, bSkip);
92   } else { //BLMODE == SVC_INTRA
93     //initial prediction memory for I_16x16
94     const int32_t kiCostI16x16 = WelsMdI16x16 (pEncCtx->pFuncList, pEncCtx->pCurDqLayer, pMbCache, pWelsMd->iLambda);
95     if (bSkip && (pWelsMd->iCostLuma <= kiCostI16x16)) {
96       WelsMdInterDecidedPskip (pEncCtx,  pSlice,  pCurMb, pMbCache);
97     } else {
98       pWelsMd->iCostLuma = kiCostI16x16;
99       pCurMb->uiMbType = MB_TYPE_INTRA16x16;
100 
101       WelsMdIntraSecondaryModesEnc (pEncCtx, pWelsMd, pCurMb, pMbCache);
102     }
103   }
104 }
105 
106 
107 
WelsMdInterMbEnhancelayer(sWelsEncCtx * pEncCtx,SWelsMD * pMd,SSlice * pSlice,SMB * pCurMb,SMbCache * pMbCache)108 void WelsMdInterMbEnhancelayer (sWelsEncCtx* pEncCtx, SWelsMD* pMd, SSlice* pSlice, SMB* pCurMb, SMbCache* pMbCache) {
109   SDqLayer* pCurLayer                   = pEncCtx->pCurDqLayer;
110   SWelsMD* pWelsMd                      = (SWelsMD*)pMd;
111   const SMB* kpInterLayerRefMb          = GetRefMb (pCurLayer, pCurMb);
112   const Mb_Type kuiInterLayerRefMbType  = kpInterLayerRefMb->uiMbType;
113 
114   SetMvBaseEnhancelayer (pWelsMd, pCurMb,
115                          kpInterLayerRefMb); // initial sMvBase here only when pRef mb type is inter, if not sMvBase will be not used!
116   //step (3): do the MD process
117   WelsMdSpatialelInterMbIlfmdNoilp (pEncCtx, pWelsMd, pSlice, pCurMb, kuiInterLayerRefMbType); //MD process
118 }
119 
120 
121 // do initiation for noILP (needed by ILFMD)
GetRefMb(SDqLayer * pCurLayer,SMB * pCurMb)122 SMB* GetRefMb (SDqLayer* pCurLayer, SMB* pCurMb) {
123   const SDqLayer*  kpRefLayer = pCurLayer->pRefLayer;
124   const int32_t  kiRefMbIdx = (pCurMb->iMbY >> 1) * kpRefLayer->iMbWidth + (pCurMb->iMbX >>
125                               1); //because current lower layer is half size on both vertical and horizontal
126   return (&kpRefLayer->sMbDataP[kiRefMbIdx]);
127 }
128 
SetMvBaseEnhancelayer(SWelsMD * pMd,SMB * pCurMb,const SMB * kpRefMb)129 void SetMvBaseEnhancelayer (SWelsMD* pMd, SMB* pCurMb, const SMB* kpRefMb) {
130   const Mb_Type kuiRefMbType = kpRefMb->uiMbType;
131 
132   if (! IS_SVC_INTRA (kuiRefMbType)) {
133     SMVUnitXY sMv;
134     int32_t iRefMbPartIdx = ((pCurMb->iMbY & 0x01) << 1) + (pCurMb->iMbX & 0x01); //may be need modified
135     int32_t iScan4RefPartIdx = g_kuiMbCountScan4Idx[ (iRefMbPartIdx << 2)];
136     sMv.iMvX = kpRefMb->sMv[iScan4RefPartIdx].iMvX * (1 << 1);
137     sMv.iMvY = kpRefMb->sMv[iScan4RefPartIdx].iMvY * (1 << 1);
138 
139     pMd->sMe.sMe16x16.sMvBase = sMv;
140 
141     pMd->sMe.sMe8x8[0].sMvBase =
142       pMd->sMe.sMe8x8[1].sMvBase =
143         pMd->sMe.sMe8x8[2].sMvBase =
144           pMd->sMe.sMe8x8[3].sMvBase = sMv;
145 
146     pMd->sMe.sMe16x8[0].sMvBase =
147       pMd->sMe.sMe16x8[1].sMvBase =
148         pMd->sMe.sMe8x16[0].sMvBase =
149           pMd->sMe.sMe8x16[1].sMvBase = sMv;
150   }
151 }
152 
153 
154 
155 //////////////
156 // MD for Background decision
157 //////////////
158 //////
159 //  try the BGD Pskip
160 //////
GetChromaCost(PSampleSadSatdCostFunc * pCalculateFunc,uint8_t * pSrcChroma,int32_t iSrcStride,uint8_t * pRefChroma,int32_t iRefStride)161 inline int32_t GetChromaCost (PSampleSadSatdCostFunc* pCalculateFunc,
162                               uint8_t* pSrcChroma, int32_t iSrcStride, uint8_t* pRefChroma, int32_t iRefStride) {
163   return pCalculateFunc[BLOCK_8x8] (pSrcChroma, iSrcStride, pRefChroma, iRefStride);
164 }
IsCostLessEqualSkipCost(int32_t iCurCost,const int32_t iPredPskipSad,const int32_t iRefMbType,const SPicture * pRef,const int32_t iMbXy,const int32_t iSmallestInvisibleTh)165 inline bool IsCostLessEqualSkipCost (int32_t iCurCost, const int32_t iPredPskipSad, const int32_t iRefMbType,
166                                      const SPicture* pRef, const int32_t iMbXy,  const int32_t iSmallestInvisibleTh) {
167   return ((iPredPskipSad > iSmallestInvisibleTh && iCurCost >= iPredPskipSad)  ||
168           (pRef->iPictureType == P_SLICE     &&
169            iRefMbType == MB_TYPE_SKIP    &&
170            pRef->pMbSkipSad[iMbXy] > iSmallestInvisibleTh &&
171            iCurCost >= (pRef->pMbSkipSad[iMbXy])));
172 }
CheckChromaCost(sWelsEncCtx * pEncCtx,SWelsMD * pWelsMd,SMbCache * pMbCache,const int32_t iCurMbXy)173 bool CheckChromaCost (sWelsEncCtx* pEncCtx, SWelsMD* pWelsMd, SMbCache* pMbCache, const int32_t iCurMbXy) {
174 #define KNOWN_CHROMA_TOO_LARGE 640
175 #define SMALLEST_INVISIBLE 128 //2*64, 2 in pixel maybe the smallest not visible for luma
176 
177   PSampleSadSatdCostFunc* pSad = pEncCtx->pFuncList->sSampleDealingFuncs.pfSampleSad;
178   SDqLayer* pCurDqLayer = pEncCtx->pCurDqLayer;
179 
180   uint8_t* pCbEnc = pMbCache->SPicData.pEncMb[1];
181   uint8_t* pCrEnc = pMbCache->SPicData.pEncMb[2];
182   uint8_t* pCbRef = pMbCache->SPicData.pRefMb[1];
183   uint8_t* pCrRef = pMbCache->SPicData.pRefMb[2];
184 
185   const int32_t iCbEncStride         = pCurDqLayer->iEncStride[1];
186   const int32_t iCrEncStride         = pCurDqLayer->iEncStride[2];
187   const int32_t iChromaRefStride     = pCurDqLayer->pRefPic->iLineSize[1];
188 
189   const int32_t iCbSad = GetChromaCost (pSad, pCbEnc, iCbEncStride, pCbRef, iChromaRefStride);
190   const int32_t iCrSad = GetChromaCost (pSad, pCrEnc, iCrEncStride, pCrRef, iChromaRefStride);
191 
192   //01/17/13
193   //the in-question error area is
194   //from: (yellow) Y=212, V=023, U=145
195   //to:     (grey)    Y=213, V=136, U=124
196   //visible difference can be seen on the U plane
197   //so the allowing chroma difference should be at least no larger than
198   //20*8*8 = 1280 for U or V
199   //one local test case show that "either one >640" will become a too strict criteria, which will appear when QP is large(36) and maybe no much harm for visual
200   //another local test case show that "either one >960" will be a moderate criteria, an area is changed from light green to light pink, but without careful observation it won't be obvious, but people will feel the unclean area (and note that, the color visible criteria is also related to the luma of them!)
201   //another case show that color changed from black to very dark red can be visible even under the threshold 960, the color difference is about 13*64=832 (U123V145->U129V132)
202   //TODO:
203   //OPTI-ABLE: the visible color criteria may be related to luma (very bright or very dark), or related to the ratio of U/V rather than the absolute value
204   const bool bChromaTooLarge = (iCbSad > KNOWN_CHROMA_TOO_LARGE || iCrSad > KNOWN_CHROMA_TOO_LARGE);
205 
206   const int32_t iChromaSad = iCbSad + iCrSad;
207   PredictSadSkip (pMbCache->sMvComponents.iRefIndexCache, pMbCache->bMbTypeSkip, pMbCache->iSadCostSkip, 0,
208                   & (pWelsMd->iSadPredSkip));
209   const bool bChromaCostCannotSkip = IsCostLessEqualSkipCost (iChromaSad, pWelsMd->iSadPredSkip, pMbCache->uiRefMbType,
210                                      pCurDqLayer->pRefPic, iCurMbXy, SMALLEST_INVISIBLE);
211 
212   return (!bChromaCostCannotSkip && !bChromaTooLarge);
213 }
214 
215 //01/17/2013. USE the NEW BGD Pskip with COLOR CHECK for screen content and camera because of color artifact seen in test
WelsMdInterJudgeBGDPskip(sWelsEncCtx * pEncCtx,SWelsMD * pWelsMd,SSlice * pSlice,SMB * pCurMb,SMbCache * pMbCache,bool * bKeepSkip)216 bool WelsMdInterJudgeBGDPskip (sWelsEncCtx* pEncCtx, SWelsMD* pWelsMd, SSlice* pSlice, SMB* pCurMb, SMbCache* pMbCache,
217                                bool* bKeepSkip) {
218   SDqLayer* pCurDqLayer = pEncCtx->pCurDqLayer;
219 
220   const int32_t kiRefMbQp = pCurDqLayer->pRefPic->pRefMbQp[pCurMb->iMbXY];
221   const int32_t kiCurMbQp = pCurMb->uiLumaQp;// unsigned -> signed
222   int8_t* pVaaBgMbFlag    = pEncCtx->pVaa->pVaaBackgroundMbFlag + pCurMb->iMbXY;
223 
224   const int32_t kiMbWidth = pCurDqLayer->iMbWidth;
225 
226   *bKeepSkip = (*bKeepSkip) &&
227                ((!pVaaBgMbFlag[-1]) &&
228                 (!pVaaBgMbFlag[-kiMbWidth]) &&
229                 (!pVaaBgMbFlag[-kiMbWidth + 1]));
230 
231   if (
232     *pVaaBgMbFlag
233     && !IS_INTRA (pMbCache->uiRefMbType)
234     && (kiRefMbQp - kiCurMbQp <= DELTA_QP_BGD_THD || kiRefMbQp <= 26)
235   ) {
236     //01/16/13
237     //the current BGD method uses luma SAD in first step judging of Background blocks
238     //and uses chroma edges to confirm the Background blocks
239     //HOWEVER, there is such case in SCC,
240     //that the luma of two collocated blocks (block in reference frame and in current frame) is very similar
241     //but the chroma are very different, at the same time the chroma are plain and without edge
242     //IN SUCH A CASE,
243     //it will be not proper to just use Pskip
244     //TODO: consider reusing this result of ChromaCheck when SCDSkip needs this as well
245 
246     if (CheckChromaCost (pEncCtx, pWelsMd, pMbCache, pCurMb->iMbXY)) {
247       SMVUnitXY sVaaPredSkipMv = { 0 };
248       PredSkipMv (pMbCache, &sVaaPredSkipMv);
249       WelsMdBackgroundMbEnc (pEncCtx, pWelsMd, pCurMb, pMbCache, pSlice, (LD32 (&sVaaPredSkipMv) == 0));
250       return true;
251     }
252   }
253 
254   return false;
255 }
256 
WelsMdInterJudgeBGDPskipFalse(sWelsEncCtx * pCtx,SWelsMD * pMd,SSlice * pSlice,SMB * pCurMb,SMbCache * pMbCache,bool * bKeepSkip)257 bool WelsMdInterJudgeBGDPskipFalse (sWelsEncCtx* pCtx, SWelsMD* pMd, SSlice* pSlice, SMB* pCurMb, SMbCache* pMbCache,
258                                     bool* bKeepSkip) {
259   return false;
260 }
261 
262 
263 
264 //////
265 //  update BGD related info
266 //////
WelsMdUpdateBGDInfo(SDqLayer * pCurLayer,SMB * pCurMb,const bool bCollocatedPredFlag,const int32_t iRefPictureType)267 void WelsMdUpdateBGDInfo (SDqLayer* pCurLayer,  SMB* pCurMb, const bool bCollocatedPredFlag,
268                           const int32_t iRefPictureType) {
269   uint8_t* pTargetRefMbQpList = (pCurLayer->pDecPic->pRefMbQp);
270   const int32_t kiMbXY = pCurMb->iMbXY;
271 
272   if (pCurMb->uiCbp || I_SLICE == iRefPictureType || 0 == bCollocatedPredFlag) {
273     pTargetRefMbQpList[kiMbXY] = pCurMb->uiLumaQp;
274   } else { //unchange, do not need to evaluation?
275     uint8_t* pRefPicRefMbQpList = (pCurLayer->pRefPic->pRefMbQp);
276     pTargetRefMbQpList[kiMbXY] = pRefPicRefMbQpList[kiMbXY];
277   }
278 
279   if (pCurMb->uiMbType == MB_TYPE_BACKGROUND) {
280     pCurMb->uiMbType = MB_TYPE_SKIP;
281   }
282 }
283 
WelsMdUpdateBGDInfoNULL(SDqLayer * pCurLayer,SMB * pCurMb,const bool bCollocatedPredFlag,const int32_t iRefPictureType)284 void WelsMdUpdateBGDInfoNULL (SDqLayer* pCurLayer, SMB* pCurMb, const bool bCollocatedPredFlag,
285                               const int32_t iRefPictureType) {
286   WelsMdUpdateBGDInfo (pCurLayer, pCurMb, bCollocatedPredFlag, iRefPictureType);
287 }
288 
289 
290 //////////////
291 // MD for screen contents
292 //////////////
IsMbStatic(int32_t * pBlockType,EStaticBlockIdc eType)293 inline bool IsMbStatic (int32_t* pBlockType, EStaticBlockIdc eType) {
294   return (pBlockType != NULL &&
295           eType == pBlockType[0] &&
296           eType == pBlockType[1] &&
297           eType == pBlockType[2] &&
298           eType == pBlockType[3]);
299 }
IsMbCollocatedStatic(int32_t * pBlockType)300 inline bool IsMbCollocatedStatic (int32_t* pBlockType) {
301   return IsMbStatic (pBlockType, COLLOCATED_STATIC);
302 }
303 
IsMbScrolledStatic(int32_t * pBlockType)304 inline bool IsMbScrolledStatic (int32_t* pBlockType) {
305   return IsMbStatic (pBlockType, SCROLLED_STATIC);
306 }
307 
CalUVSadCost(SWelsFuncPtrList * pFunc,uint8_t * pEncOri,int32_t iStrideUV,uint8_t * pRefOri,int32_t iRefLineSize)308 inline int32_t CalUVSadCost (SWelsFuncPtrList* pFunc, uint8_t* pEncOri, int32_t iStrideUV, uint8_t* pRefOri,
309                              int32_t iRefLineSize) {
310   return pFunc->sSampleDealingFuncs.pfSampleSad[BLOCK_8x8] (pEncOri, iStrideUV, pRefOri, iRefLineSize);
311 }
312 
CheckBorder(int32_t iMbX,int32_t iMbY,int32_t iScrollMvX,int32_t iScrollMvY,int32_t iMbWidth,int32_t iMbHeight)313 inline bool CheckBorder (int32_t iMbX, int32_t iMbY, int32_t iScrollMvX, int32_t iScrollMvY, int32_t iMbWidth,
314                          int32_t iMbHeight) {
315   return ((iMbX << 4) + iScrollMvX < 0 ||
316           (iMbX << 4) + iScrollMvX > (iMbWidth - 1) << 4 ||
317           (iMbY << 4) + iScrollMvY < 0 ||
318           (iMbY << 4) + iScrollMvY > (iMbHeight - 1) << 4
319          ); //border check for safety
320 }
321 
322 
JudgeStaticSkip(sWelsEncCtx * pEncCtx,SMB * pCurMb,SMbCache * pMbCache,SWelsMD * pWelsMd)323 bool JudgeStaticSkip (sWelsEncCtx* pEncCtx, SMB* pCurMb, SMbCache* pMbCache, SWelsMD* pWelsMd) {
324   SDqLayer* pCurDqLayer = pEncCtx->pCurDqLayer;
325   const int32_t kiMbX = pCurMb->iMbX;
326   const int32_t kiMbY = pCurMb->iMbY;
327 
328   bool bTryStaticSkip = IsMbCollocatedStatic (pWelsMd->iBlock8x8StaticIdc);
329   if (bTryStaticSkip) {
330     int32_t iStrideUV, iOffsetUV;
331     SWelsFuncPtrList* pFunc = pEncCtx->pFuncList;
332     SPicture* pRefOri = pCurDqLayer->pRefOri[0];
333     if (pRefOri != NULL) {
334       iStrideUV = pCurDqLayer->iEncStride[1];
335       iOffsetUV = (kiMbX + kiMbY * iStrideUV) << 3;
336 
337       int32_t iSadCostCb = CalUVSadCost (pFunc, pMbCache->SPicData.pEncMb[1], iStrideUV, pRefOri->pData[1] + iOffsetUV,
338                                          pRefOri->iLineSize[1]);
339       if (iSadCostCb == 0) {
340         int32_t iSadCostCr = CalUVSadCost (pFunc, pMbCache->SPicData.pEncMb[2], iStrideUV, pRefOri->pData[2] + iOffsetUV,
341                                            pRefOri->iLineSize[1]);
342         bTryStaticSkip = (0 == iSadCostCr);
343       } else bTryStaticSkip = false;
344     } else {
345       bTryStaticSkip = false;
346     }
347   }
348   return bTryStaticSkip;
349 }
350 
JudgeScrollSkip(sWelsEncCtx * pEncCtx,SMB * pCurMb,SMbCache * pMbCache,SWelsMD * pWelsMd)351 bool JudgeScrollSkip (sWelsEncCtx* pEncCtx, SMB* pCurMb, SMbCache* pMbCache, SWelsMD* pWelsMd) {
352   SDqLayer* pCurDqLayer = pEncCtx->pCurDqLayer;
353   const int32_t kiMbX = pCurMb->iMbX;
354   const int32_t kiMbY = pCurMb->iMbY;
355   const int32_t kiMbWidth = pCurDqLayer->iMbWidth;
356   const int32_t kiMbHeight = pCurDqLayer->iMbHeight;
357   // const int32_t block_width = mb_width << 1;
358   SVAAFrameInfoExt_t* pVaaExt = static_cast<SVAAFrameInfoExt_t*> (pEncCtx->pVaa);
359 
360   bool bTryScrollSkip = false;
361 
362   if (pVaaExt->sScrollDetectInfo.bScrollDetectFlag)
363     bTryScrollSkip = IsMbScrolledStatic (pWelsMd->iBlock8x8StaticIdc);
364   else return 0;
365 
366   if (bTryScrollSkip) {
367     int32_t iStrideUV, iOffsetUV;
368     SWelsFuncPtrList* pFunc = pEncCtx->pFuncList;
369     SPicture* pRefOri = pCurDqLayer->pRefOri[0];
370     if (pRefOri != NULL) {
371       int32_t iScrollMvX = pVaaExt->sScrollDetectInfo.iScrollMvX;
372       int32_t iScrollMvY = pVaaExt->sScrollDetectInfo.iScrollMvY;
373       if (CheckBorder (kiMbX, kiMbY, iScrollMvX, iScrollMvY, kiMbWidth, kiMbHeight)) {
374         bTryScrollSkip =  false;
375       } else {
376         iStrideUV = pCurDqLayer->iEncStride[1];
377         iOffsetUV = (kiMbX << 3) + (iScrollMvX >> 1) + ((kiMbY << 3) + (iScrollMvY >> 1)) * iStrideUV;
378 
379         int32_t iSadCostCb = CalUVSadCost (pFunc, pMbCache->SPicData.pEncMb[1], iStrideUV, pRefOri->pData[1] + iOffsetUV,
380                                            pRefOri->iLineSize[1]);
381         if (iSadCostCb == 0) {
382           int32_t iSadCostCr = CalUVSadCost (pFunc, pMbCache->SPicData.pEncMb[2], iStrideUV, pRefOri->pData[2] + iOffsetUV,
383                                              pRefOri->iLineSize[1]);
384           bTryScrollSkip = (0 == iSadCostCr);
385         } else bTryScrollSkip = false;
386       }
387     }
388   }
389   return bTryScrollSkip;
390 }
391 
SvcMdSCDMbEnc(sWelsEncCtx * pEncCtx,SWelsMD * pWelsMd,SMB * pCurMb,SMbCache * pMbCache,SSlice * pSlice,bool bQpSimilarFlag,bool bMbSkipFlag,SMVUnitXY sCurMbMv[],ESkipModes eSkipMode)392 void SvcMdSCDMbEnc (sWelsEncCtx* pEncCtx, SWelsMD* pWelsMd, SMB* pCurMb, SMbCache* pMbCache, SSlice* pSlice,
393                     bool bQpSimilarFlag,
394                     bool bMbSkipFlag, SMVUnitXY sCurMbMv[], ESkipModes eSkipMode) {
395   SDqLayer* pCurDqLayer         = pEncCtx->pCurDqLayer;
396   SWelsFuncPtrList* pFunc       = pEncCtx->pFuncList;
397   SMVUnitXY sMvp = { 0};
398   ST16 (&sMvp.iMvX, sCurMbMv[eSkipMode].iMvX);
399   ST16 (&sMvp.iMvY, sCurMbMv[eSkipMode].iMvY);
400   uint8_t* pRefLuma             = pMbCache->SPicData.pRefMb[0];
401   uint8_t* pRefCb               = pMbCache->SPicData.pRefMb[1];
402   uint8_t* pRefCr               = pMbCache->SPicData.pRefMb[2];
403   int32_t iLineSizeY            = pCurDqLayer->pRefPic->iLineSize[0];
404   int32_t iLineSizeUV           = pCurDqLayer->pRefPic->iLineSize[1];
405   uint8_t* pDstLuma             = pMbCache->pSkipMb;
406   uint8_t* pDstCb               = pMbCache->pSkipMb + 256;
407   uint8_t* pDstCr               = pMbCache->pSkipMb + 256 + 64;
408 
409   const int32_t iOffsetY  = (sCurMbMv[eSkipMode].iMvX >> 2) + (sCurMbMv[eSkipMode].iMvY >> 2) * iLineSizeY;
410   const int32_t iOffsetUV = (sCurMbMv[eSkipMode].iMvX >> 3) + (sCurMbMv[eSkipMode].iMvY >> 3) * iLineSizeUV;
411 
412   if (!bQpSimilarFlag || !bMbSkipFlag) {
413     pDstLuma = pMbCache->pMemPredLuma;
414     pDstCb   = pMbCache->pMemPredChroma;
415     pDstCr   = pMbCache->pMemPredChroma + 64;
416   }
417   //MC
418   pFunc->sMcFuncs.pMcLumaFunc (pRefLuma + iOffsetY, iLineSizeY, pDstLuma, 16, 0, 0, 16, 16);
419   pFunc->sMcFuncs.pMcChromaFunc (pRefCb + iOffsetUV, iLineSizeUV, pDstCb, 8, sMvp.iMvX, sMvp.iMvY, 8, 8);
420   pFunc->sMcFuncs.pMcChromaFunc (pRefCr + iOffsetUV, iLineSizeUV, pDstCr, 8, sMvp.iMvX, sMvp.iMvY, 8, 8);
421 
422   pCurMb->uiCbp = 0;
423   pWelsMd->iCostLuma = 0;
424   pCurMb->pSadCost[0] = pFunc->sSampleDealingFuncs.pfSampleSad[BLOCK_16x16] (pMbCache->SPicData.pEncMb[0],
425                         pCurDqLayer->iEncStride[0], pRefLuma + iOffsetY, iLineSizeY);
426 
427   pWelsMd->iCostSkipMb = pCurMb->pSadCost[0];
428 
429   ST16 (& (pCurMb->sP16x16Mv.iMvX), sCurMbMv[eSkipMode].iMvX);
430   ST16 (& (pCurMb->sP16x16Mv.iMvY), sCurMbMv[eSkipMode].iMvY);
431 
432   ST16 (& (pCurDqLayer->pDecPic->sMvList[pCurMb->iMbXY].iMvX), sCurMbMv[eSkipMode].iMvX);
433   ST16 (& (pCurDqLayer->pDecPic->sMvList[pCurMb->iMbXY].iMvY), sCurMbMv[eSkipMode].iMvY);
434 
435   if (bQpSimilarFlag && bMbSkipFlag) {
436     //update motion info to current MB
437     ST32 (pCurMb->pRefIndex, 0);
438     pFunc->pfUpdateMbMv (pCurMb->sMv, sMvp);
439     pCurMb->uiMbType = MB_TYPE_SKIP;
440     WelsRecPskip (pCurDqLayer, pEncCtx->pFuncList, pCurMb, pMbCache);
441     WelsMdInterUpdatePskip (pCurDqLayer, pSlice, pCurMb, pMbCache);
442     return;
443   }
444 
445   pCurMb->uiMbType = MB_TYPE_16x16;
446 
447   pWelsMd->sMe.sMe16x16.sMv.iMvX = sCurMbMv[eSkipMode].iMvX;
448   pWelsMd->sMe.sMe16x16.sMv.iMvY = sCurMbMv[eSkipMode].iMvY;
449   PredMv (&pMbCache->sMvComponents, 0, 4, 0, &pWelsMd->sMe.sMe16x16.sMvp);
450   pMbCache->sMbMvp[0] = pWelsMd->sMe.sMe16x16.sMvp;
451 
452   UpdateP16x16MotionInfo (pMbCache, pCurMb, 0, &pWelsMd->sMe.sMe16x16.sMv);
453 
454   if (pWelsMd->bMdUsingSad)
455     pWelsMd->iCostLuma = pCurMb->pSadCost[0];
456   else
457     pWelsMd->iCostLuma = pFunc->sSampleDealingFuncs.pfSampleSad[BLOCK_16x16] (pMbCache->SPicData.pEncMb[0],
458                          pCurDqLayer->iEncStride[0], pRefLuma, iLineSizeY);
459 
460   WelsInterMbEncode (pEncCtx, pSlice, pCurMb);
461   WelsPMbChromaEncode (pEncCtx, pSlice, pCurMb);
462 
463   pFunc->pfCopy16x16Aligned (pMbCache->SPicData.pCsMb[0], pCurDqLayer->iCsStride[0], pMbCache->pMemPredLuma, 16);
464   pFunc->pfCopy8x8Aligned (pMbCache->SPicData.pCsMb[1], pCurDqLayer->iCsStride[1], pMbCache->pMemPredChroma, 8);
465   pFunc->pfCopy8x8Aligned (pMbCache->SPicData.pCsMb[2], pCurDqLayer->iCsStride[1], pMbCache->pMemPredChroma + 64, 8);
466 }
467 
MdInterSCDPskipProcess(sWelsEncCtx * pEncCtx,SWelsMD * pWelsMd,SSlice * pSlice,SMB * pCurMb,SMbCache * pMbCache,ESkipModes eSkipMode)468 bool MdInterSCDPskipProcess (sWelsEncCtx* pEncCtx, SWelsMD* pWelsMd, SSlice* pSlice, SMB* pCurMb, SMbCache* pMbCache,
469                              ESkipModes eSkipMode) {
470   SVAAFrameInfoExt_t* pVaaExt   = static_cast<SVAAFrameInfoExt_t*> (pEncCtx->pVaa);
471   SDqLayer* pCurDqLayer         = pEncCtx->pCurDqLayer;
472 
473   const int32_t kiRefMbQp = pCurDqLayer->pRefPic->pRefMbQp[pCurMb->iMbXY];
474   const int32_t kiCurMbQp = pCurMb->uiLumaQp;// unsigned -> signed
475 
476   pJudgeSkipFun pJudeSkip[2] = {JudgeStaticSkip, JudgeScrollSkip};
477   bool bSkipFlag = pJudeSkip[eSkipMode] (pEncCtx, pCurMb, pMbCache, pWelsMd);
478 
479   if (bSkipFlag) {
480     bool bQpSimilarFlag = (kiRefMbQp - kiCurMbQp <= DELTA_QP_SCD_THD || kiRefMbQp <= 26);
481     SMVUnitXY sVaaPredSkipMv = {0, 0}, sCurMbMv[2] = {{0, 0}, {0, 0}};
482     PredSkipMv (pMbCache, &sVaaPredSkipMv);
483 
484     if (eSkipMode == SCROLLED) {
485       sCurMbMv[1].iMvX = static_cast<int16_t> (pVaaExt->sScrollDetectInfo.iScrollMvX << 2);
486       sCurMbMv[1].iMvY = static_cast<int16_t> (pVaaExt->sScrollDetectInfo.iScrollMvY << 2);
487     }
488 
489     bool bMbSkipFlag = (LD32 (&sVaaPredSkipMv) ==  LD32 (&sCurMbMv[eSkipMode])) ;
490     SvcMdSCDMbEnc (pEncCtx, pWelsMd, pCurMb, pMbCache, pSlice, bQpSimilarFlag, bMbSkipFlag, sCurMbMv, eSkipMode);
491 
492     return true;
493   }
494 
495   return false;
496 }
497 
SetBlockStaticIdcToMd(void * pVaa,SWelsMD * pWelsMd,SMB * pCurMb,SDqLayer * pDqLayer)498 void SetBlockStaticIdcToMd (void* pVaa, SWelsMD* pWelsMd, SMB* pCurMb, SDqLayer* pDqLayer) {
499   SVAAFrameInfoExt_t* pVaaExt = static_cast<SVAAFrameInfoExt_t*> (pVaa);
500 
501   const int32_t kiMbX = pCurMb->iMbX;
502   const int32_t kiMbY = pCurMb->iMbY;
503   const int32_t kiMbWidth = pDqLayer->iMbWidth;
504   const int32_t kiWidth = kiMbWidth << 1;
505 
506   const int32_t kiBlockIndexUp = (kiMbY << 1) * kiWidth + (kiMbX << 1);
507   const int32_t kiBlockIndexLow = ((kiMbY << 1) + 1) * kiWidth + (kiMbX << 1);
508 
509   //fill_blockstaticidc with pVaaExt->pVaaBestBlockStaticIdc
510   pWelsMd->iBlock8x8StaticIdc[0] = pVaaExt->pVaaBestBlockStaticIdc[kiBlockIndexUp];
511   pWelsMd->iBlock8x8StaticIdc[1] = pVaaExt->pVaaBestBlockStaticIdc[kiBlockIndexUp + 1];
512   pWelsMd->iBlock8x8StaticIdc[2] = pVaaExt->pVaaBestBlockStaticIdc[kiBlockIndexLow];
513   pWelsMd->iBlock8x8StaticIdc[3] = pVaaExt->pVaaBestBlockStaticIdc[kiBlockIndexLow + 1];
514 
515 }
516 
517 ///////////////////////
518 // Scene Change Detection (SCD) PSkip Decision for screen content
519 ////////////////////////
WelsMdInterJudgeSCDPskip(sWelsEncCtx * pEncCtx,SWelsMD * pWelsMd,SSlice * slice,SMB * pCurMb,SMbCache * pMbCache)520 bool WelsMdInterJudgeSCDPskip (sWelsEncCtx* pEncCtx, SWelsMD* pWelsMd, SSlice* slice, SMB* pCurMb, SMbCache* pMbCache) {
521   SDqLayer* pCurDqLayer = pEncCtx->pCurDqLayer;
522 
523   SetBlockStaticIdcToMd (pEncCtx->pVaa, pWelsMd, pCurMb, pCurDqLayer);
524 
525   //try static Pskip;
526   if (MdInterSCDPskipProcess (pEncCtx, pWelsMd, slice, pCurMb, pMbCache, STATIC)) {
527     return true;
528   }
529 
530   //try scrolled Pskip
531   if (MdInterSCDPskipProcess (pEncCtx, pWelsMd, slice, pCurMb, pMbCache, SCROLLED)) {
532     return true;
533   }
534 
535   return false;
536 }
WelsMdInterJudgeSCDPskipFalse(sWelsEncCtx * pEncCtx,SWelsMD * pWelsMd,SSlice * slice,SMB * pCurMb,SMbCache * pMbCache)537 bool WelsMdInterJudgeSCDPskipFalse (sWelsEncCtx* pEncCtx, SWelsMD* pWelsMd, SSlice* slice, SMB* pCurMb,
538                                     SMbCache* pMbCache) {
539   return false;
540 }
541 
542 
WelsInitSCDPskipFunc(SWelsFuncPtrList * pFuncList,const bool bScrollingDetection)543 void WelsInitSCDPskipFunc (SWelsFuncPtrList* pFuncList, const bool bScrollingDetection) {
544   if (bScrollingDetection) {
545     pFuncList->pfSCDPSkipDecision = WelsMdInterJudgeSCDPskip;
546   } else {
547     pFuncList->pfSCDPSkipDecision = WelsMdInterJudgeSCDPskipFalse;
548   }
549 }
550 
551 ///////////////////////
552 // SubP16x16 Mode Decision for screen content
553 ////////////////////////
554 //
555 //func pointer of inter MD for sub16x16 INTER MD for screen content coding
556 //
MergeSub16Me(const SWelsME & sSrcMe0,const SWelsME & sSrcMe1,SWelsME * pTarMe)557 static inline void MergeSub16Me (const SWelsME& sSrcMe0, const SWelsME& sSrcMe1, SWelsME* pTarMe) {
558   memcpy (pTarMe, &sSrcMe0, sizeof (sSrcMe0)); // confirmed_safe_unsafe_usage
559 
560   pTarMe->uiSadCost = sSrcMe0.uiSadCost + sSrcMe1.uiSadCost;//not precise cost since MVD cost is not the same
561   pTarMe->uiSatdCost = sSrcMe0.uiSatdCost + sSrcMe1.uiSatdCost;//not precise cost since MVD cost is not the same
562 }
IsSameMv(const SMVUnitXY & sMv0,const SMVUnitXY & sMv1)563 static inline bool IsSameMv (const SMVUnitXY& sMv0, const SMVUnitXY& sMv1) {
564   return ((sMv0.iMvX == sMv1.iMvX) && (sMv0.iMvY == sMv1.iMvY));
565 }
TryModeMerge(SMbCache * pMbCache,SWelsMD * pWelsMd,SMB * pCurMb)566 bool TryModeMerge (SMbCache* pMbCache, SWelsMD* pWelsMd, SMB* pCurMb) {
567   SWelsME* pMe8x8 = & (pWelsMd->sMe.sMe8x8[0]);
568   const bool bSameMv16x8_0 = IsSameMv (pMe8x8[0].sMv, pMe8x8[1].sMv);
569   const bool bSameMv16x8_1 = IsSameMv (pMe8x8[2].sMv, pMe8x8[3].sMv);
570 
571   const bool bSameMv8x16_0 = IsSameMv (pMe8x8[0].sMv, pMe8x8[2].sMv);
572   const bool bSameMv8x16_1 = IsSameMv (pMe8x8[1].sMv, pMe8x8[3].sMv);
573   //need to consider iRefIdx when multi ref is available
574   const bool bSameRefIdx16x8_0 = true; //pMe8x8[0].iRefIdx == pMe8x8[1].iRefIdx;
575   const bool bSameRefIdx16x8_1 = true; //pMe8x8[2].iRefIdx == pMe8x8[3].iRefIdx;
576   const bool bSameRefIdx8x16_0 = true; //pMe8x8[0].iRefIdx == pMe8x8[2].iRefIdx;
577   const bool bSameRefIdx8x16_1 = true; //pMe8x8[1].iRefIdx == pMe8x8[3].iRefIdx;
578   const int32_t iSameMv = ((bSameMv16x8_0 && bSameRefIdx16x8_0  && bSameMv16x8_1 && bSameRefIdx16x8_1) << 1) |
579                           (bSameMv8x16_0 && bSameRefIdx8x16_0 && bSameMv8x16_1 && bSameRefIdx8x16_1);
580 
581   //TODO: did not consider the MVD cost here, may consider later
582   switch (iSameMv) {
583   case 3:
584     //MERGE_16x16
585     //from test results of multiple sequences show that using the following 0x0F to merge 16x16
586     //for some seq there is BR saving some loss
587     //on the whole the BR will increase little bit
588     //to save complexity we decided not to merge 16x16 at present (10/12/2012)
589     //TODO: agjusted order, consider re-test later
590     break;
591   case 2:
592     pCurMb->uiMbType = MB_TYPE_16x8;
593     MergeSub16Me (pMe8x8[0], pMe8x8[1], & (pWelsMd->sMe.sMe16x8[0]));
594     MergeSub16Me (pMe8x8[2], pMe8x8[3], & (pWelsMd->sMe.sMe16x8[1]));
595     PredInter16x8Mv (pMbCache, 0, 0, & (pWelsMd->sMe.sMe16x8[0].sMvp));
596     PredInter16x8Mv (pMbCache, 8, 0, & (pWelsMd->sMe.sMe16x8[1].sMvp));
597     break;
598   case 1:
599     pCurMb->uiMbType = MB_TYPE_8x16;
600     MergeSub16Me (pMe8x8[0], pMe8x8[2], & (pWelsMd->sMe.sMe8x16[0]));
601     MergeSub16Me (pMe8x8[1], pMe8x8[3], & (pWelsMd->sMe.sMe8x16[1]));
602     PredInter8x16Mv (pMbCache, 0, 0, & (pWelsMd->sMe.sMe8x16[0].sMvp));
603     PredInter8x16Mv (pMbCache, 4, 0, & (pWelsMd->sMe.sMe8x16[1].sMvp));
604     break;
605   default:
606     break;
607   }
608   return (MB_TYPE_8x8 != pCurMb->uiMbType);
609 }
610 
611 
WelsMdInterFinePartitionVaaOnScreen(sWelsEncCtx * pEncCtx,SWelsMD * pWelsMd,SSlice * pSlice,SMB * pCurMb,int32_t iBestCost)612 void WelsMdInterFinePartitionVaaOnScreen (sWelsEncCtx* pEncCtx, SWelsMD* pWelsMd, SSlice* pSlice, SMB* pCurMb,
613     int32_t iBestCost) {
614   SMbCache* pMbCache = &pSlice->sMbCacheInfo;
615   SDqLayer* pCurDqLayer = pEncCtx->pCurDqLayer;
616   int32_t iCostP8x8;
617   uint8_t uiMbSign = pEncCtx->pFuncList->pfGetMbSignFromInterVaa (&pEncCtx->pVaa->sVaaCalcInfo.pSad8x8[pCurMb->iMbXY][0]);
618 
619   if (MBVAASIGN_FLAT == uiMbSign) {
620     return;
621   }
622 
623   iCostP8x8 = WelsMdP8x8 (pEncCtx->pFuncList, pCurDqLayer, pWelsMd, pSlice);
624   if (iCostP8x8 < iBestCost) {
625     iBestCost = iCostP8x8;
626     pCurMb->uiMbType = MB_TYPE_8x8;
627     memset (pCurMb->uiSubMbType, SUB_MB_TYPE_8x8, 4);
628 #if 0 //Disable for sub8x8 modes for now
629     iBestCost = 0;
630     //reset neighbor info for sub8x8
631     pMbCache->sMvComponents.iRefIndexCache [9] = pMbCache->sMvComponents.iRefIndexCache [21] = REF_NOT_AVAIL;
632     for (int32_t i8x8Idx = 0; i8x8Idx < 4; ++i8x8Idx) {
633       int32_t iCurCostSub8x8, iBestCostSub8x8 = pWelsMd->sMe.sMe8x8[i8x8Idx].uiSatdCost;
634       //4x4
635       iCurCostSub8x8 = WelsMdP4x4 (pEncCtx->pFuncList, pCurDqLayer, pWelsMd, pSlice, i8x8Idx);
636       if (iCurCostSub8x8 < iBestCostSub8x8) {
637         pCurMb->uiSubMbType[i8x8Idx] = SUB_MB_TYPE_4x4;
638         iBestCostSub8x8 = iCurCostSub8x8;
639       }
640       //8x4
641       iCurCostSub8x8 = WelsMdP8x4 (pEncCtx->pFuncList, pCurDqLayer, pWelsMd, pSlice, i8x8Idx);
642       if (iCurCostSub8x8 < iBestCostSub8x8) {
643         pCurMb->uiSubMbType[i8x8Idx] = SUB_MB_TYPE_8x4;
644         iBestCostSub8x8 = iCurCostSub8x8;
645       }
646       //4x8
647       iCurCostSub8x8 = WelsMdP4x8 (pEncCtx->pFuncList, pCurDqLayer, pWelsMd, pSlice, i8x8Idx);
648       if (iCurCostSub8x8 < iBestCostSub8x8) {
649         pCurMb->uiSubMbType[i8x8Idx] = SUB_MB_TYPE_4x8;
650         iBestCostSub8x8 = iCurCostSub8x8;
651       }
652       iBestCost += iBestCostSub8x8;
653     }
654     if ((pCurMb->uiSubMbType[0] == SUB_MB_TYPE_8x8) && (pCurMb->uiSubMbType[1] == SUB_MB_TYPE_8x8)
655         && (pCurMb->uiSubMbType[2] == SUB_MB_TYPE_8x8) && (pCurMb->uiSubMbType[3] == SUB_MB_TYPE_8x8)) //all 8x8
656 #endif
657       TryModeMerge (pMbCache, pWelsMd, pCurMb);
658   }
659   pWelsMd->iCostLuma = iBestCost;
660 }
661 
662 
663 
664 
665 
666 //
667 // SetScrollingMvToMd
668 //
SetScrollingMvToMd(SVAAFrameInfo * pVaa,SWelsMD * pWelsMd)669 void SetScrollingMvToMd (SVAAFrameInfo* pVaa, SWelsMD* pWelsMd) {
670   SVAAFrameInfoExt* pVaaExt = static_cast<SVAAFrameInfoExt*> (pVaa);
671 
672   SMVUnitXY          sTempMv;
673   sTempMv.iMvX = pVaaExt->sScrollDetectInfo.iScrollMvX;
674   sTempMv.iMvY = pVaaExt->sScrollDetectInfo.iScrollMvY;
675 
676   (pWelsMd->sMe.sMe16x16).sDirectionalMv =
677     (pWelsMd->sMe.sMe8x8[0]).sDirectionalMv =
678       (pWelsMd->sMe.sMe8x8[1]).sDirectionalMv =
679         (pWelsMd->sMe.sMe8x8[2]).sDirectionalMv =
680           (pWelsMd->sMe.sMe8x8[3]).sDirectionalMv = sTempMv;
681 }
682 
SetScrollingMvToMdNull(SVAAFrameInfo * pVaa,SWelsMD * pWelsMd)683 void SetScrollingMvToMdNull (SVAAFrameInfo* pVaa, SWelsMD* pWelsMd) {
684 }
685 
686 } // namespace WelsEnc
687