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