1 /* The copyright in this software is being made available under the BSD
2  * License, included below. This software may be subject to other third party
3  * and contributor rights, including patent rights, and no such rights are
4  * granted under this license.
5  *
6  * Copyright (c) 2010-2014, ITU/ISO/IEC
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  *
12  *  * Redistributions of source code must retain the above copyright notice,
13  *    this list of conditions and the following disclaimer.
14  *  * Redistributions in binary form must reproduce the above copyright notice,
15  *    this list of conditions and the following disclaimer in the documentation
16  *    and/or other materials provided with the distribution.
17  *  * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
18  *    be used to endorse or promote products derived from this software without
19  *    specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31  * THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /** \file     TComSampleAdaptiveOffset.cpp
35     \brief    sample adaptive offset class
36 */
37 
38 #include "TComSampleAdaptiveOffset.h"
39 #include <string.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <math.h>
43 
44 //! \ingroup TLibCommon
45 //! \{
46 
47 UInt g_saoMaxOffsetQVal[MAX_NUM_COMPONENT];
48 
SAOOffset()49 SAOOffset::SAOOffset()
50 {
51   reset();
52 }
53 
~SAOOffset()54 SAOOffset::~SAOOffset()
55 {
56 
57 }
58 
reset()59 Void SAOOffset::reset()
60 {
61   modeIdc = SAO_MODE_OFF;
62   typeIdc = -1;
63   typeAuxInfo = -1;
64   ::memset(offset, 0, sizeof(Int)* MAX_NUM_SAO_CLASSES);
65 }
66 
operator =(const SAOOffset & src)67 const SAOOffset& SAOOffset::operator= (const SAOOffset& src)
68 {
69   modeIdc = src.modeIdc;
70   typeIdc = src.typeIdc;
71   typeAuxInfo = src.typeAuxInfo;
72   ::memcpy(offset, src.offset, sizeof(Int)* MAX_NUM_SAO_CLASSES);
73 
74   return *this;
75 }
76 
77 
SAOBlkParam()78 SAOBlkParam::SAOBlkParam()
79 {
80   reset();
81 }
82 
~SAOBlkParam()83 SAOBlkParam::~SAOBlkParam()
84 {
85 
86 }
87 
reset()88 Void SAOBlkParam::reset()
89 {
90   for(Int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++)
91   {
92     offsetParam[compIdx].reset();
93   }
94 }
95 
operator =(const SAOBlkParam & src)96 const SAOBlkParam& SAOBlkParam::operator= (const SAOBlkParam& src)
97 {
98   for(Int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++)
99   {
100     offsetParam[compIdx] = src.offsetParam[compIdx];
101   }
102   return *this;
103 
104 }
105 
TComSampleAdaptiveOffset()106 TComSampleAdaptiveOffset::TComSampleAdaptiveOffset()
107 {
108   m_tempPicYuv = NULL;
109   m_lineBufWidth = 0;
110   m_signLineBuf1 = NULL;
111   m_signLineBuf2 = NULL;
112 }
113 
114 
~TComSampleAdaptiveOffset()115 TComSampleAdaptiveOffset::~TComSampleAdaptiveOffset()
116 {
117   destroy();
118 
119   if (m_signLineBuf1) delete[] m_signLineBuf1; m_signLineBuf1 = NULL;
120   if (m_signLineBuf2) delete[] m_signLineBuf2; m_signLineBuf2 = NULL;
121 }
122 
create(Int picWidth,Int picHeight,ChromaFormat format,UInt maxCUWidth,UInt maxCUHeight,UInt maxCUDepth,UInt lumaBitShift,UInt chromaBitShift)123 Void TComSampleAdaptiveOffset::create( Int picWidth, Int picHeight, ChromaFormat format, UInt maxCUWidth, UInt maxCUHeight, UInt maxCUDepth, UInt lumaBitShift, UInt chromaBitShift )
124 {
125   destroy();
126 
127   m_picWidth        = picWidth;
128   m_picHeight       = picHeight;
129   m_chromaFormatIDC = format;
130   m_maxCUWidth      = maxCUWidth;
131   m_maxCUHeight     = maxCUHeight;
132 
133   m_numCTUInWidth   = (m_picWidth/m_maxCUWidth) + ((m_picWidth % m_maxCUWidth)?1:0);
134   m_numCTUInHeight  = (m_picHeight/m_maxCUHeight) + ((m_picHeight % m_maxCUHeight)?1:0);
135   m_numCTUsPic      = m_numCTUInHeight*m_numCTUInWidth;
136 
137   //temporary picture buffer
138   if ( !m_tempPicYuv )
139   {
140     m_tempPicYuv = new TComPicYuv;
141     m_tempPicYuv->create( m_picWidth, m_picHeight, m_chromaFormatIDC, m_maxCUWidth, m_maxCUHeight, maxCUDepth );
142   }
143 
144   //bit-depth related
145   for(Int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++)
146   {
147     Int bitDepthSample = g_bitDepth[toChannelType(ComponentID(compIdx))];
148     m_offsetStepLog2  [compIdx] = isLuma(ComponentID(compIdx))? lumaBitShift : chromaBitShift;
149     g_saoMaxOffsetQVal[compIdx] = (1<<(min(bitDepthSample,MAX_SAO_TRUNCATED_BITDEPTH)-5))-1; //Table 9-32, inclusive
150   }
151 }
152 
destroy()153 Void TComSampleAdaptiveOffset::destroy()
154 {
155   if ( m_tempPicYuv )
156   {
157     m_tempPicYuv->destroy();
158     delete m_tempPicYuv;
159     m_tempPicYuv = NULL;
160   }
161 }
162 
invertQuantOffsets(ComponentID compIdx,Int typeIdc,Int typeAuxInfo,Int * dstOffsets,Int * srcOffsets)163 Void TComSampleAdaptiveOffset::invertQuantOffsets(ComponentID compIdx, Int typeIdc, Int typeAuxInfo, Int* dstOffsets, Int* srcOffsets)
164 {
165   Int codedOffset[MAX_NUM_SAO_CLASSES];
166 
167   ::memcpy(codedOffset, srcOffsets, sizeof(Int)*MAX_NUM_SAO_CLASSES);
168   ::memset(dstOffsets, 0, sizeof(Int)*MAX_NUM_SAO_CLASSES);
169 
170   if(typeIdc == SAO_TYPE_START_BO)
171   {
172     for(Int i=0; i< 4; i++)
173     {
174       dstOffsets[(typeAuxInfo+ i)%NUM_SAO_BO_CLASSES] = codedOffset[(typeAuxInfo+ i)%NUM_SAO_BO_CLASSES]*(1<<m_offsetStepLog2[compIdx]);
175     }
176   }
177   else //EO
178   {
179     for(Int i=0; i< NUM_SAO_EO_CLASSES; i++)
180     {
181       dstOffsets[i] = codedOffset[i] *(1<<m_offsetStepLog2[compIdx]);
182     }
183     assert(dstOffsets[SAO_CLASS_EO_PLAIN] == 0); //keep EO plain offset as zero
184   }
185 
186 }
187 
getMergeList(TComPic * pic,Int ctuRsAddr,SAOBlkParam * blkParams,SAOBlkParam * mergeList[NUM_SAO_MERGE_TYPES])188 Int TComSampleAdaptiveOffset::getMergeList(TComPic* pic, Int ctuRsAddr, SAOBlkParam* blkParams, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES])
189 {
190   Int ctuX = ctuRsAddr % m_numCTUInWidth;
191   Int ctuY = ctuRsAddr / m_numCTUInWidth;
192   Int mergedCTUPos;
193   Int numValidMergeCandidates = 0;
194 
195   for(Int mergeType=0; mergeType< NUM_SAO_MERGE_TYPES; mergeType++)
196   {
197     SAOBlkParam* mergeCandidate = NULL;
198 
199     switch(mergeType)
200     {
201     case SAO_MERGE_ABOVE:
202       {
203         if(ctuY > 0)
204         {
205           mergedCTUPos = ctuRsAddr- m_numCTUInWidth;
206           if( pic->getSAOMergeAvailability(ctuRsAddr, mergedCTUPos) )
207           {
208             mergeCandidate = &(blkParams[mergedCTUPos]);
209           }
210         }
211       }
212       break;
213     case SAO_MERGE_LEFT:
214       {
215         if(ctuX > 0)
216         {
217           mergedCTUPos = ctuRsAddr- 1;
218           if( pic->getSAOMergeAvailability(ctuRsAddr, mergedCTUPos) )
219           {
220             mergeCandidate = &(blkParams[mergedCTUPos]);
221           }
222         }
223       }
224       break;
225     default:
226       {
227         printf("not a supported merge type");
228         assert(0);
229         exit(-1);
230       }
231     }
232 
233     mergeList[mergeType]=mergeCandidate;
234     if (mergeCandidate != NULL)
235     {
236       numValidMergeCandidates++;
237     }
238   }
239 
240   return numValidMergeCandidates;
241 }
242 
243 
reconstructBlkSAOParam(SAOBlkParam & recParam,SAOBlkParam * mergeList[NUM_SAO_MERGE_TYPES])244 Void TComSampleAdaptiveOffset::reconstructBlkSAOParam(SAOBlkParam& recParam, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES])
245 {
246   const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC);
247   for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++)
248   {
249     const ComponentID component = ComponentID(compIdx);
250     SAOOffset& offsetParam = recParam[component];
251 
252     if(offsetParam.modeIdc == SAO_MODE_OFF)
253     {
254       continue;
255     }
256 
257     switch(offsetParam.modeIdc)
258     {
259     case SAO_MODE_NEW:
260       {
261         invertQuantOffsets(component, offsetParam.typeIdc, offsetParam.typeAuxInfo, offsetParam.offset, offsetParam.offset);
262       }
263       break;
264     case SAO_MODE_MERGE:
265       {
266         SAOBlkParam* mergeTarget = mergeList[offsetParam.typeIdc];
267         assert(mergeTarget != NULL);
268 
269         offsetParam = (*mergeTarget)[component];
270       }
271       break;
272     default:
273       {
274         printf("Not a supported mode");
275         assert(0);
276         exit(-1);
277       }
278     }
279   }
280 }
281 
reconstructBlkSAOParams(TComPic * pic,SAOBlkParam * saoBlkParams)282 Void TComSampleAdaptiveOffset::reconstructBlkSAOParams(TComPic* pic, SAOBlkParam* saoBlkParams)
283 {
284   for(Int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++)
285   {
286     m_picSAOEnabled[compIdx] = false;
287   }
288 
289   const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC);
290 
291   for(Int ctuRsAddr=0; ctuRsAddr< m_numCTUsPic; ctuRsAddr++)
292   {
293     SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES] = { NULL };
294     getMergeList(pic, ctuRsAddr, saoBlkParams, mergeList);
295 
296     reconstructBlkSAOParam(saoBlkParams[ctuRsAddr], mergeList);
297 
298     for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++)
299     {
300       if(saoBlkParams[ctuRsAddr][compIdx].modeIdc != SAO_MODE_OFF)
301       {
302         m_picSAOEnabled[compIdx] = true;
303       }
304     }
305   }
306 }
307 
308 
offsetBlock(ComponentID compIdx,Int typeIdx,Int * offset,Pel * srcBlk,Pel * resBlk,Int srcStride,Int resStride,Int width,Int height,Bool isLeftAvail,Bool isRightAvail,Bool isAboveAvail,Bool isBelowAvail,Bool isAboveLeftAvail,Bool isAboveRightAvail,Bool isBelowLeftAvail,Bool isBelowRightAvail)309 Void TComSampleAdaptiveOffset::offsetBlock(ComponentID compIdx, Int typeIdx, Int* offset
310                                           , Pel* srcBlk, Pel* resBlk, Int srcStride, Int resStride,  Int width, Int height
311                                           , Bool isLeftAvail,  Bool isRightAvail, Bool isAboveAvail, Bool isBelowAvail, Bool isAboveLeftAvail, Bool isAboveRightAvail, Bool isBelowLeftAvail, Bool isBelowRightAvail)
312 {
313   if(m_lineBufWidth != m_maxCUWidth)
314   {
315     m_lineBufWidth = m_maxCUWidth;
316 
317     if (m_signLineBuf1) delete[] m_signLineBuf1; m_signLineBuf1 = NULL;
318     m_signLineBuf1 = new Char[m_lineBufWidth+1];
319 
320     if (m_signLineBuf2) delete[] m_signLineBuf2; m_signLineBuf2 = NULL;
321     m_signLineBuf2 = new Char[m_lineBufWidth+1];
322   }
323 
324   const Int maxSampleValueIncl = (1<< g_bitDepth[toChannelType(compIdx)] )-1;
325 
326   Int x,y, startX, startY, endX, endY, edgeType;
327   Int firstLineStartX, firstLineEndX, lastLineStartX, lastLineEndX;
328   Char signLeft, signRight, signDown;
329 
330   Pel* srcLine = srcBlk;
331   Pel* resLine = resBlk;
332 
333   switch(typeIdx)
334   {
335   case SAO_TYPE_EO_0:
336     {
337       offset += 2;
338       startX = isLeftAvail ? 0 : 1;
339       endX   = isRightAvail ? width : (width -1);
340       for (y=0; y< height; y++)
341       {
342         signLeft = (Char)sgn(srcLine[startX] - srcLine[startX-1]);
343         for (x=startX; x< endX; x++)
344         {
345           signRight = (Char)sgn(srcLine[x] - srcLine[x+1]);
346           edgeType =  signRight + signLeft;
347           signLeft  = -signRight;
348 
349           resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
350         }
351         srcLine  += srcStride;
352         resLine += resStride;
353       }
354 
355     }
356     break;
357   case SAO_TYPE_EO_90:
358     {
359       offset += 2;
360       Char *signUpLine = m_signLineBuf1;
361 
362       startY = isAboveAvail ? 0 : 1;
363       endY   = isBelowAvail ? height : height-1;
364       if (!isAboveAvail)
365       {
366         srcLine += srcStride;
367         resLine += resStride;
368       }
369 
370       Pel* srcLineAbove= srcLine- srcStride;
371       for (x=0; x< width; x++)
372       {
373         signUpLine[x] = (Char)sgn(srcLine[x] - srcLineAbove[x]);
374       }
375 
376       Pel* srcLineBelow;
377       for (y=startY; y<endY; y++)
378       {
379         srcLineBelow= srcLine+ srcStride;
380 
381         for (x=0; x< width; x++)
382         {
383           signDown  = (Char)sgn(srcLine[x] - srcLineBelow[x]);
384           edgeType = signDown + signUpLine[x];
385           signUpLine[x]= -signDown;
386 
387           resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
388         }
389         srcLine += srcStride;
390         resLine += resStride;
391       }
392 
393     }
394     break;
395   case SAO_TYPE_EO_135:
396     {
397       offset += 2;
398       Char *signUpLine, *signDownLine, *signTmpLine;
399 
400       signUpLine  = m_signLineBuf1;
401       signDownLine= m_signLineBuf2;
402 
403       startX = isLeftAvail ? 0 : 1 ;
404       endX   = isRightAvail ? width : (width-1);
405 
406       //prepare 2nd line's upper sign
407       Pel* srcLineBelow= srcLine+ srcStride;
408       for (x=startX; x< endX+1; x++)
409       {
410         signUpLine[x] = (Char)sgn(srcLineBelow[x] - srcLine[x- 1]);
411       }
412 
413       //1st line
414       Pel* srcLineAbove= srcLine- srcStride;
415       firstLineStartX = isAboveLeftAvail ? 0 : 1;
416       firstLineEndX   = isAboveAvail? endX: 1;
417       for(x= firstLineStartX; x< firstLineEndX; x++)
418       {
419         edgeType  =  sgn(srcLine[x] - srcLineAbove[x- 1]) - signUpLine[x+1];
420 
421         resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
422       }
423       srcLine  += srcStride;
424       resLine  += resStride;
425 
426 
427       //middle lines
428       for (y= 1; y< height-1; y++)
429       {
430         srcLineBelow= srcLine+ srcStride;
431 
432         for (x=startX; x<endX; x++)
433         {
434           signDown =  (Char)sgn(srcLine[x] - srcLineBelow[x+ 1]);
435           edgeType =  signDown + signUpLine[x];
436           resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
437 
438           signDownLine[x+1] = -signDown;
439         }
440         signDownLine[startX] = (Char)sgn(srcLineBelow[startX] - srcLine[startX-1]);
441 
442         signTmpLine  = signUpLine;
443         signUpLine   = signDownLine;
444         signDownLine = signTmpLine;
445 
446         srcLine += srcStride;
447         resLine += resStride;
448       }
449 
450       //last line
451       srcLineBelow= srcLine+ srcStride;
452       lastLineStartX = isBelowAvail ? startX : (width -1);
453       lastLineEndX   = isBelowRightAvail ? width : (width -1);
454       for(x= lastLineStartX; x< lastLineEndX; x++)
455       {
456         edgeType =  sgn(srcLine[x] - srcLineBelow[x+ 1]) + signUpLine[x];
457         resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
458 
459       }
460     }
461     break;
462   case SAO_TYPE_EO_45:
463     {
464       offset += 2;
465       Char *signUpLine = m_signLineBuf1+1;
466 
467       startX = isLeftAvail ? 0 : 1;
468       endX   = isRightAvail ? width : (width -1);
469 
470       //prepare 2nd line upper sign
471       Pel* srcLineBelow= srcLine+ srcStride;
472       for (x=startX-1; x< endX; x++)
473       {
474         signUpLine[x] = (Char)sgn(srcLineBelow[x] - srcLine[x+1]);
475       }
476 
477 
478       //first line
479       Pel* srcLineAbove= srcLine- srcStride;
480       firstLineStartX = isAboveAvail ? startX : (width -1 );
481       firstLineEndX   = isAboveRightAvail ? width : (width-1);
482       for(x= firstLineStartX; x< firstLineEndX; x++)
483       {
484         edgeType = sgn(srcLine[x] - srcLineAbove[x+1]) -signUpLine[x-1];
485         resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
486       }
487       srcLine += srcStride;
488       resLine += resStride;
489 
490       //middle lines
491       for (y= 1; y< height-1; y++)
492       {
493         srcLineBelow= srcLine+ srcStride;
494 
495         for(x= startX; x< endX; x++)
496         {
497           signDown =  (Char)sgn(srcLine[x] - srcLineBelow[x-1]);
498           edgeType =  signDown + signUpLine[x];
499           resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
500           signUpLine[x-1] = -signDown;
501         }
502         signUpLine[endX-1] = (Char)sgn(srcLineBelow[endX-1] - srcLine[endX]);
503         srcLine  += srcStride;
504         resLine += resStride;
505       }
506 
507       //last line
508       srcLineBelow= srcLine+ srcStride;
509       lastLineStartX = isBelowLeftAvail ? 0 : 1;
510       lastLineEndX   = isBelowAvail ? endX : 1;
511       for(x= lastLineStartX; x< lastLineEndX; x++)
512       {
513         edgeType = sgn(srcLine[x] - srcLineBelow[x-1]) + signUpLine[x];
514         resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
515 
516       }
517     }
518     break;
519   case SAO_TYPE_BO:
520     {
521       const Int shiftBits = g_bitDepth[toChannelType(compIdx)] - NUM_SAO_BO_CLASSES_LOG2;
522       for (y=0; y< height; y++)
523       {
524         for (x=0; x< width; x++)
525         {
526           resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[srcLine[x] >> shiftBits] );
527         }
528         srcLine += srcStride;
529         resLine += resStride;
530       }
531     }
532     break;
533   default:
534     {
535       printf("Not a supported SAO types\n");
536       assert(0);
537       exit(-1);
538     }
539   }
540 }
541 
offsetCTU(Int ctuRsAddr,TComPicYuv * srcYuv,TComPicYuv * resYuv,SAOBlkParam & saoblkParam,TComPic * pPic)542 Void TComSampleAdaptiveOffset::offsetCTU(Int ctuRsAddr, TComPicYuv* srcYuv, TComPicYuv* resYuv, SAOBlkParam& saoblkParam, TComPic* pPic)
543 {
544   Bool isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail;
545 
546   const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC);
547   Bool bAllOff=true;
548   for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++)
549   {
550     if (saoblkParam[compIdx].modeIdc != SAO_MODE_OFF) bAllOff=false;
551   }
552   if (bAllOff) return;
553 
554   //block boundary availability
555   pPic->getPicSym()->deriveLoopFilterBoundaryAvailibility(ctuRsAddr, isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail);
556 
557   Int yPos   = (ctuRsAddr / m_numCTUInWidth)*m_maxCUHeight;
558   Int xPos   = (ctuRsAddr % m_numCTUInWidth)*m_maxCUWidth;
559   Int height = (yPos + m_maxCUHeight > m_picHeight)?(m_picHeight- yPos):m_maxCUHeight;
560   Int width  = (xPos + m_maxCUWidth  > m_picWidth )?(m_picWidth - xPos):m_maxCUWidth;
561 
562   for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++)
563   {
564     const ComponentID component = ComponentID(compIdx);
565     SAOOffset& ctbOffset = saoblkParam[compIdx];
566 
567     if(ctbOffset.modeIdc != SAO_MODE_OFF)
568     {
569       const UInt componentScaleX = getComponentScaleX(component, pPic->getChromaFormat());
570       const UInt componentScaleY = getComponentScaleY(component, pPic->getChromaFormat());
571 
572       Int  blkWidth   = (width  >> componentScaleX);
573       Int  blkHeight  = (height >> componentScaleY);
574       Int  blkXPos    = (xPos   >> componentScaleX);
575       Int  blkYPos    = (yPos   >> componentScaleY);
576 
577       Int  srcStride  = srcYuv->getStride(component);
578       Pel* srcBlk     = srcYuv->getAddr(component) + blkYPos*srcStride + blkXPos;
579 
580       Int  resStride  = resYuv->getStride(component);
581       Pel* resBlk     = resYuv->getAddr(component) + blkYPos*resStride + blkXPos;
582 
583       offsetBlock( component, ctbOffset.typeIdc, ctbOffset.offset
584                   , srcBlk, resBlk, srcStride, resStride, blkWidth, blkHeight
585                   , isLeftAvail, isRightAvail
586                   , isAboveAvail, isBelowAvail
587                   , isAboveLeftAvail, isAboveRightAvail
588                   , isBelowLeftAvail, isBelowRightAvail
589                   );
590     }
591   } //compIdx
592 
593 }
594 
595 
SAOProcess(TComPic * pDecPic)596 Void TComSampleAdaptiveOffset::SAOProcess(TComPic* pDecPic)
597 {
598   const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC);
599   Bool bAllDisabled=true;
600   for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++)
601   {
602     if (m_picSAOEnabled[compIdx]) bAllDisabled=false;
603   }
604   if (bAllDisabled) return;
605 
606   TComPicYuv* resYuv = pDecPic->getPicYuvRec();
607   TComPicYuv* srcYuv = m_tempPicYuv;
608   resYuv->copyToPic(srcYuv);
609   for(Int ctuRsAddr= 0; ctuRsAddr < m_numCTUsPic; ctuRsAddr++)
610   {
611     offsetCTU(ctuRsAddr, srcYuv, resYuv, (pDecPic->getPicSym()->getSAOBlkParam())[ctuRsAddr], pDecPic);
612   } //ctu
613 }
614 
615 
616 /** PCM LF disable process.
617  * \param pcPic picture (TComPic) pointer
618  * \returns Void
619  *
620  * \note Replace filtered sample values of PCM mode blocks with the transmitted and reconstructed ones.
621  */
PCMLFDisableProcess(TComPic * pcPic)622 Void TComSampleAdaptiveOffset::PCMLFDisableProcess (TComPic* pcPic)
623 {
624   xPCMRestoration(pcPic);
625 }
626 
627 /** Picture-level PCM restoration.
628  * \param pcPic picture (TComPic) pointer
629  * \returns Void
630  */
xPCMRestoration(TComPic * pcPic)631 Void TComSampleAdaptiveOffset::xPCMRestoration(TComPic* pcPic)
632 {
633   Bool  bPCMFilter = (pcPic->getSlice(0)->getSPS()->getUsePCM() && pcPic->getSlice(0)->getSPS()->getPCMFilterDisableFlag())? true : false;
634 
635   if(bPCMFilter || pcPic->getSlice(0)->getPPS()->getTransquantBypassEnableFlag())
636   {
637     for( UInt ctuRsAddr = 0; ctuRsAddr < pcPic->getNumberOfCtusInFrame() ; ctuRsAddr++ )
638     {
639       TComDataCU* pcCU = pcPic->getCtu(ctuRsAddr);
640 
641       xPCMCURestoration(pcCU, 0, 0);
642     }
643   }
644 }
645 
646 /** PCM CU restoration.
647  * \param pcCU pointer to current CU
648  * \param uiAbsPartIdx part index
649  * \param uiDepth CU depth
650  * \returns Void
651  */
xPCMCURestoration(TComDataCU * pcCU,UInt uiAbsZorderIdx,UInt uiDepth)652 Void TComSampleAdaptiveOffset::xPCMCURestoration ( TComDataCU* pcCU, UInt uiAbsZorderIdx, UInt uiDepth )
653 {
654   TComPic* pcPic     = pcCU->getPic();
655   UInt uiCurNumParts = pcPic->getNumPartitionsInCtu() >> (uiDepth<<1);
656   UInt uiQNumParts   = uiCurNumParts>>2;
657 
658   // go to sub-CU
659   if( pcCU->getDepth(uiAbsZorderIdx) > uiDepth )
660   {
661     for ( UInt uiPartIdx = 0; uiPartIdx < 4; uiPartIdx++, uiAbsZorderIdx+=uiQNumParts )
662     {
663       UInt uiLPelX   = pcCU->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsZorderIdx] ];
664       UInt uiTPelY   = pcCU->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsZorderIdx] ];
665       if( ( uiLPelX < pcCU->getSlice()->getSPS()->getPicWidthInLumaSamples() ) && ( uiTPelY < pcCU->getSlice()->getSPS()->getPicHeightInLumaSamples() ) )
666         xPCMCURestoration( pcCU, uiAbsZorderIdx, uiDepth+1 );
667     }
668     return;
669   }
670 
671   // restore PCM samples
672   if ((pcCU->getIPCMFlag(uiAbsZorderIdx)&& pcPic->getSlice(0)->getSPS()->getPCMFilterDisableFlag()) || pcCU->isLosslessCoded( uiAbsZorderIdx))
673   {
674     const UInt numComponents=pcPic->getNumberValidComponents();
675     for(UInt comp=0; comp<numComponents; comp++)
676     {
677       xPCMSampleRestoration (pcCU, uiAbsZorderIdx, uiDepth, ComponentID(comp));
678     }
679   }
680 }
681 
682 /** PCM sample restoration.
683  * \param pcCU pointer to current CU
684  * \param uiAbsPartIdx part index
685  * \param uiDepth CU depth
686  * \param ttText texture component type
687  * \returns Void
688  */
xPCMSampleRestoration(TComDataCU * pcCU,UInt uiAbsZorderIdx,UInt uiDepth,const ComponentID compID)689 Void TComSampleAdaptiveOffset::xPCMSampleRestoration (TComDataCU* pcCU, UInt uiAbsZorderIdx, UInt uiDepth, const ComponentID compID)
690 {
691         TComPicYuv* pcPicYuvRec = pcCU->getPic()->getPicYuvRec();
692         UInt uiPcmLeftShiftBit;
693   const UInt uiMinCoeffSize = pcCU->getPic()->getMinCUWidth()*pcCU->getPic()->getMinCUHeight();
694   const UInt csx=pcPicYuvRec->getComponentScaleX(compID);
695   const UInt csy=pcPicYuvRec->getComponentScaleY(compID);
696   const UInt uiOffset   = (uiMinCoeffSize*uiAbsZorderIdx)>>(csx+csy);
697 
698         Pel *piSrc = pcPicYuvRec->getAddr(compID, pcCU->getCtuRsAddr(), uiAbsZorderIdx);
699   const Pel *piPcm = pcCU->getPCMSample(compID) + uiOffset;
700   const UInt uiStride  = pcPicYuvRec->getStride(compID);
701   const UInt uiWidth  = ((g_uiMaxCUWidth >> uiDepth) >> csx);
702   const UInt uiHeight = ((g_uiMaxCUWidth >> uiDepth) >> csy);
703 
704   if ( pcCU->isLosslessCoded(uiAbsZorderIdx) && !pcCU->getIPCMFlag(uiAbsZorderIdx) )
705   {
706     uiPcmLeftShiftBit = 0;
707   }
708   else
709   {
710     uiPcmLeftShiftBit = g_bitDepth[toChannelType(compID)] - pcCU->getSlice()->getSPS()->getPCMBitDepth(toChannelType(compID));
711   }
712 
713   for(UInt uiY = 0; uiY < uiHeight; uiY++ )
714   {
715     for(UInt uiX = 0; uiX < uiWidth; uiX++ )
716     {
717       piSrc[uiX] = (piPcm[uiX] << uiPcmLeftShiftBit);
718     }
719     piPcm += uiWidth;
720     piSrc += uiStride;
721   }
722 }
723 
724 //! \}
725