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 /**
35  \file     TEncSampleAdaptiveOffset.cpp
36  \brief       estimation part of sample adaptive offset class
37  */
38 #include "TEncSampleAdaptiveOffset.h"
39 #include <string.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <math.h>
43 
44 //! \ingroup TLibEncoder
45 //! \{
46 
47 
48 /** rounding with IBDI
49  * \param  x
50  */
xRoundIbdi2(Int bitDepth,Double x)51 inline Double xRoundIbdi2(Int bitDepth, Double x)
52 {
53   return ((x)>0) ? (Int)(((Int)(x)+(1<<(bitDepth-8-1)))/(1<<(bitDepth-8))) : ((Int)(((Int)(x)-(1<<(bitDepth-8-1)))/(1<<(bitDepth-8))));
54 }
55 
xRoundIbdi(Int bitDepth,Double x)56 inline Double xRoundIbdi(Int bitDepth, Double x)
57 {
58   return (bitDepth > 8 ? xRoundIbdi2(bitDepth, (x)) : ((x)>=0 ? ((Int)((x)+0.5)) : ((Int)((x)-0.5)))) ;
59 }
60 
61 
TEncSampleAdaptiveOffset()62 TEncSampleAdaptiveOffset::TEncSampleAdaptiveOffset()
63 {
64   m_pppcRDSbacCoder = NULL;
65   m_pcRDGoOnSbacCoder = NULL;
66   m_pppcBinCoderCABAC = NULL;
67   m_statData = NULL;
68 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
69   m_preDBFstatData = NULL;
70 #endif
71 }
72 
~TEncSampleAdaptiveOffset()73 TEncSampleAdaptiveOffset::~TEncSampleAdaptiveOffset()
74 {
75   destroyEncData();
76 }
77 
78 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
createEncData(Bool isPreDBFSamplesUsed)79 Void TEncSampleAdaptiveOffset::createEncData(Bool isPreDBFSamplesUsed)
80 #else
81 Void TEncSampleAdaptiveOffset::createEncData()
82 #endif
83 {
84 
85   //cabac coder for RDO
86   m_pppcRDSbacCoder = new TEncSbac* [NUM_SAO_CABACSTATE_LABELS];
87 #if FAST_BIT_EST
88   m_pppcBinCoderCABAC = new TEncBinCABACCounter* [NUM_SAO_CABACSTATE_LABELS];
89 #else
90   m_pppcBinCoderCABAC = new TEncBinCABAC* [NUM_SAO_CABACSTATE_LABELS];
91 #endif
92 
93   for(Int cs=0; cs < NUM_SAO_CABACSTATE_LABELS; cs++)
94   {
95     m_pppcRDSbacCoder[cs] = new TEncSbac;
96 #if FAST_BIT_EST
97     m_pppcBinCoderCABAC[cs] = new TEncBinCABACCounter;
98 #else
99     m_pppcBinCoderCABAC[cs] = new TEncBinCABAC;
100 #endif
101     m_pppcRDSbacCoder   [cs]->init( m_pppcBinCoderCABAC [cs] );
102   }
103 
104 
105   //statistics
106   m_statData = new SAOStatData**[m_numCTUsPic];
107   for(Int i=0; i< m_numCTUsPic; i++)
108   {
109     m_statData[i] = new SAOStatData*[MAX_NUM_COMPONENT];
110     for(Int compIdx=0; compIdx < MAX_NUM_COMPONENT; compIdx++)
111     {
112       m_statData[i][compIdx] = new SAOStatData[NUM_SAO_NEW_TYPES];
113     }
114   }
115 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
116   if(isPreDBFSamplesUsed)
117   {
118     m_preDBFstatData = new SAOStatData**[m_numCTUsPic];
119     for(Int i=0; i< m_numCTUsPic; i++)
120     {
121       m_preDBFstatData[i] = new SAOStatData*[MAX_NUM_COMPONENT];
122       for(Int compIdx=0; compIdx < MAX_NUM_COMPONENT; compIdx++)
123       {
124         m_preDBFstatData[i][compIdx] = new SAOStatData[NUM_SAO_NEW_TYPES];
125       }
126     }
127 
128   }
129 #endif
130 
131 #if SAO_ENCODING_CHOICE
132   ::memset(m_saoDisabledRate, 0, sizeof(m_saoDisabledRate));
133 #endif
134 
135   for(Int typeIdc=0; typeIdc < NUM_SAO_NEW_TYPES; typeIdc++)
136   {
137     m_skipLinesR[COMPONENT_Y ][typeIdc]= 5;
138     m_skipLinesR[COMPONENT_Cb][typeIdc]= m_skipLinesR[COMPONENT_Cr][typeIdc]= 3;
139 
140     m_skipLinesB[COMPONENT_Y ][typeIdc]= 4;
141     m_skipLinesB[COMPONENT_Cb][typeIdc]= m_skipLinesB[COMPONENT_Cr][typeIdc]= 2;
142 
143 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
144     if(isPreDBFSamplesUsed)
145     {
146       switch(typeIdc)
147       {
148       case SAO_TYPE_EO_0:
149         {
150           m_skipLinesR[COMPONENT_Y ][typeIdc]= 5;
151           m_skipLinesR[COMPONENT_Cb][typeIdc]= m_skipLinesR[COMPONENT_Cr][typeIdc]= 3;
152 
153           m_skipLinesB[COMPONENT_Y ][typeIdc]= 3;
154           m_skipLinesB[COMPONENT_Cb][typeIdc]= m_skipLinesB[COMPONENT_Cr][typeIdc]= 1;
155         }
156         break;
157       case SAO_TYPE_EO_90:
158         {
159           m_skipLinesR[COMPONENT_Y ][typeIdc]= 4;
160           m_skipLinesR[COMPONENT_Cb][typeIdc]= m_skipLinesR[COMPONENT_Cr][typeIdc]= 2;
161 
162           m_skipLinesB[COMPONENT_Y ][typeIdc]= 4;
163           m_skipLinesB[COMPONENT_Cb][typeIdc]= m_skipLinesB[COMPONENT_Cr][typeIdc]= 2;
164         }
165         break;
166       case SAO_TYPE_EO_135:
167       case SAO_TYPE_EO_45:
168         {
169           m_skipLinesR[COMPONENT_Y ][typeIdc]= 5;
170           m_skipLinesR[COMPONENT_Cb][typeIdc]= m_skipLinesR[COMPONENT_Cr][typeIdc]= 3;
171 
172           m_skipLinesB[COMPONENT_Y ][typeIdc]= 4;
173           m_skipLinesB[COMPONENT_Cb][typeIdc]= m_skipLinesB[COMPONENT_Cr][typeIdc]= 2;
174         }
175         break;
176       case SAO_TYPE_BO:
177         {
178           m_skipLinesR[COMPONENT_Y ][typeIdc]= 4;
179           m_skipLinesR[COMPONENT_Cb][typeIdc]= m_skipLinesR[COMPONENT_Cr][typeIdc]= 2;
180 
181           m_skipLinesB[COMPONENT_Y ][typeIdc]= 3;
182           m_skipLinesB[COMPONENT_Cb][typeIdc]= m_skipLinesB[COMPONENT_Cr][typeIdc]= 1;
183         }
184         break;
185       default:
186         {
187           printf("Not a supported type");
188           assert(0);
189           exit(-1);
190         }
191       }
192     }
193 #endif
194   }
195 
196 }
197 
destroyEncData()198 Void TEncSampleAdaptiveOffset::destroyEncData()
199 {
200   if(m_pppcRDSbacCoder != NULL)
201   {
202     for (Int cs = 0; cs < NUM_SAO_CABACSTATE_LABELS; cs ++ )
203     {
204       delete m_pppcRDSbacCoder[cs];
205     }
206     delete[] m_pppcRDSbacCoder; m_pppcRDSbacCoder = NULL;
207   }
208 
209   if(m_pppcBinCoderCABAC != NULL)
210   {
211     for (Int cs = 0; cs < NUM_SAO_CABACSTATE_LABELS; cs ++ )
212     {
213       delete m_pppcBinCoderCABAC[cs];
214     }
215     delete[] m_pppcBinCoderCABAC; m_pppcBinCoderCABAC = NULL;
216   }
217 
218   if(m_statData != NULL)
219   {
220     for(Int i=0; i< m_numCTUsPic; i++)
221     {
222       for(Int compIdx=0; compIdx< MAX_NUM_COMPONENT; compIdx++)
223       {
224         delete[] m_statData[i][compIdx];
225       }
226       delete[] m_statData[i];
227     }
228     delete[] m_statData; m_statData = NULL;
229   }
230 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
231   if(m_preDBFstatData != NULL)
232   {
233     for(Int i=0; i< m_numCTUsPic; i++)
234     {
235       for(Int compIdx=0; compIdx< MAX_NUM_COMPONENT; compIdx++)
236       {
237         delete[] m_preDBFstatData[i][compIdx];
238       }
239       delete[] m_preDBFstatData[i];
240     }
241     delete[] m_preDBFstatData; m_preDBFstatData = NULL;
242   }
243 
244 #endif
245 }
246 
initRDOCabacCoder(TEncSbac * pcRDGoOnSbacCoder,TComSlice * pcSlice)247 Void TEncSampleAdaptiveOffset::initRDOCabacCoder(TEncSbac* pcRDGoOnSbacCoder, TComSlice* pcSlice)
248 {
249   m_pcRDGoOnSbacCoder = pcRDGoOnSbacCoder;
250   m_pcRDGoOnSbacCoder->setSlice(pcSlice);
251   m_pcRDGoOnSbacCoder->resetEntropy();
252   m_pcRDGoOnSbacCoder->resetBits();
253 
254   m_pcRDGoOnSbacCoder->store( m_pppcRDSbacCoder[SAO_CABACSTATE_PIC_INIT]);
255 }
256 
257 
258 
SAOProcess(TComPic * pPic,Bool * sliceEnabled,const Double * lambdas,Bool isPreDBFSamplesUsed)259 Void TEncSampleAdaptiveOffset::SAOProcess(TComPic* pPic, Bool* sliceEnabled, const Double *lambdas
260 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
261                                          , Bool isPreDBFSamplesUsed
262 #endif
263                                           )
264 {
265   TComPicYuv* orgYuv= pPic->getPicYuvOrg();
266   TComPicYuv* resYuv= pPic->getPicYuvRec();
267   memcpy(m_lambda, lambdas, sizeof(m_lambda));
268   TComPicYuv* srcYuv = m_tempPicYuv;
269   resYuv->copyToPic(srcYuv);
270   srcYuv->setBorderExtension(false);
271   srcYuv->extendPicBorder();
272 
273   //collect statistics
274   getStatistics(m_statData, orgYuv, srcYuv, pPic);
275 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
276   if(isPreDBFSamplesUsed)
277   {
278     addPreDBFStatistics(m_statData);
279   }
280 #endif
281   //slice on/off
282   decidePicParams(sliceEnabled, pPic->getSlice(0)->getDepth());
283 
284   //block on/off
285   SAOBlkParam* reconParams = new SAOBlkParam[m_numCTUsPic]; //temporary parameter buffer for storing reconstructed SAO parameters
286   decideBlkParams(pPic, sliceEnabled, m_statData, srcYuv, resYuv, reconParams, pPic->getPicSym()->getSAOBlkParam());
287   delete[] reconParams;
288 }
289 
290 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
getPreDBFStatistics(TComPic * pPic)291 Void TEncSampleAdaptiveOffset::getPreDBFStatistics(TComPic* pPic)
292 {
293   getStatistics(m_preDBFstatData, pPic->getPicYuvOrg(), pPic->getPicYuvRec(), pPic, true);
294 }
295 
addPreDBFStatistics(SAOStatData *** blkStats)296 Void TEncSampleAdaptiveOffset::addPreDBFStatistics(SAOStatData*** blkStats)
297 {
298   for(Int n=0; n< m_numCTUsPic; n++)
299   {
300     for(Int compIdx=0; compIdx < MAX_NUM_COMPONENT; compIdx++)
301     {
302       for(Int typeIdc=0; typeIdc < NUM_SAO_NEW_TYPES; typeIdc++)
303       {
304         blkStats[n][compIdx][typeIdc] += m_preDBFstatData[n][compIdx][typeIdc];
305       }
306     }
307   }
308 }
309 
310 #endif
311 
getStatistics(SAOStatData *** blkStats,TComPicYuv * orgYuv,TComPicYuv * srcYuv,TComPic * pPic,Bool isCalculatePreDeblockSamples)312 Void TEncSampleAdaptiveOffset::getStatistics(SAOStatData*** blkStats, TComPicYuv* orgYuv, TComPicYuv* srcYuv, TComPic* pPic
313 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
314                           , Bool isCalculatePreDeblockSamples
315 #endif
316                           )
317 {
318   Bool isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail;
319 
320   const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC);
321 
322   for(Int ctuRsAddr= 0; ctuRsAddr < m_numCTUsPic; ctuRsAddr++)
323   {
324     Int yPos   = (ctuRsAddr / m_numCTUInWidth)*m_maxCUHeight;
325     Int xPos   = (ctuRsAddr % m_numCTUInWidth)*m_maxCUWidth;
326     Int height = (yPos + m_maxCUHeight > m_picHeight)?(m_picHeight- yPos):m_maxCUHeight;
327     Int width  = (xPos + m_maxCUWidth  > m_picWidth )?(m_picWidth - xPos):m_maxCUWidth;
328 
329     pPic->getPicSym()->deriveLoopFilterBoundaryAvailibility(ctuRsAddr, isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail);
330 
331     //NOTE: The number of skipped lines during gathering CTU statistics depends on the slice boundary availabilities.
332     //For simplicity, here only picture boundaries are considered.
333 
334     isRightAvail      = (xPos + m_maxCUWidth  < m_picWidth );
335     isBelowAvail      = (yPos + m_maxCUHeight < m_picHeight);
336     isBelowRightAvail = (isRightAvail && isBelowAvail);
337     isBelowLeftAvail  = ((xPos > 0) && (isBelowAvail));
338     isAboveRightAvail = ((yPos > 0) && (isRightAvail));
339 
340     for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++)
341     {
342       const ComponentID component = ComponentID(compIdx);
343 
344       const UInt componentScaleX = getComponentScaleX(component, pPic->getChromaFormat());
345       const UInt componentScaleY = getComponentScaleY(component, pPic->getChromaFormat());
346 
347       Int  srcStride  = srcYuv->getStride(component);
348       Pel* srcBlk     = srcYuv->getAddr(component) + ((yPos >> componentScaleY) * srcStride) + (xPos >> componentScaleX);
349 
350       Int  orgStride  = orgYuv->getStride(component);
351       Pel* orgBlk     = orgYuv->getAddr(component) + ((yPos >> componentScaleY) * orgStride) + (xPos >> componentScaleX);
352 
353       getBlkStats(component, blkStats[ctuRsAddr][component]
354                 , srcBlk, orgBlk, srcStride, orgStride, (width  >> componentScaleX), (height >> componentScaleY)
355                 , isLeftAvail,  isRightAvail, isAboveAvail, isBelowAvail, isAboveLeftAvail, isAboveRightAvail, isBelowLeftAvail, isBelowRightAvail
356 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
357                 , isCalculatePreDeblockSamples
358 #endif
359                 );
360 
361     }
362   }
363 }
364 
decidePicParams(Bool * sliceEnabled,Int picTempLayer)365 Void TEncSampleAdaptiveOffset::decidePicParams(Bool* sliceEnabled, Int picTempLayer)
366 {
367   //decide sliceEnabled[compIdx]
368   const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC);
369   for (Int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++)
370   {
371     sliceEnabled[compIdx] = false;
372   }
373 
374   for (Int compIdx = 0; compIdx < numberOfComponents; compIdx++)
375   {
376     // reset flags & counters
377     sliceEnabled[compIdx] = true;
378 
379 #if SAO_ENCODING_CHOICE
380 #if SAO_ENCODING_CHOICE_CHROMA
381     // decide slice-level on/off based on previous results
382     if( (picTempLayer > 0)
383       && (m_saoDisabledRate[compIdx][picTempLayer-1] > ((compIdx==COMPONENT_Y) ? SAO_ENCODING_RATE : SAO_ENCODING_RATE_CHROMA)) )
384     {
385       sliceEnabled[compIdx] = false;
386     }
387 #else
388     // decide slice-level on/off based on previous results
389     if( (picTempLayer > 0)
390       && (m_saoDisabledRate[COMPONENT_Y][0] > SAO_ENCODING_RATE) )
391     {
392       sliceEnabled[compIdx] = false;
393     }
394 #endif
395 #endif
396   }
397 }
398 
getDistortion(ComponentID compIdx,Int typeIdc,Int typeAuxInfo,Int * invQuantOffset,SAOStatData & statData)399 Int64 TEncSampleAdaptiveOffset::getDistortion(ComponentID compIdx, Int typeIdc, Int typeAuxInfo, Int* invQuantOffset, SAOStatData& statData)
400 {
401   Int64 dist        = 0;
402   Int shift         = 2 * DISTORTION_PRECISION_ADJUSTMENT(g_bitDepth[toChannelType(compIdx)] - 8);
403 
404   switch(typeIdc)
405   {
406     case SAO_TYPE_EO_0:
407     case SAO_TYPE_EO_90:
408     case SAO_TYPE_EO_135:
409     case SAO_TYPE_EO_45:
410       {
411         for (Int offsetIdx=0; offsetIdx<NUM_SAO_EO_CLASSES; offsetIdx++)
412         {
413           dist += estSaoDist( statData.count[offsetIdx], invQuantOffset[offsetIdx], statData.diff[offsetIdx], shift);
414         }
415       }
416       break;
417     case SAO_TYPE_BO:
418       {
419         for (Int offsetIdx=typeAuxInfo; offsetIdx<typeAuxInfo+4; offsetIdx++)
420         {
421           Int bandIdx = offsetIdx % NUM_SAO_BO_CLASSES ;
422           dist += estSaoDist( statData.count[bandIdx], invQuantOffset[bandIdx], statData.diff[bandIdx], shift);
423         }
424       }
425       break;
426     default:
427       {
428         printf("Not a supported type");
429         assert(0);
430         exit(-1);
431       }
432   }
433 
434   return dist;
435 }
436 
estSaoDist(Int64 count,Int64 offset,Int64 diffSum,Int shift)437 inline Int64 TEncSampleAdaptiveOffset::estSaoDist(Int64 count, Int64 offset, Int64 diffSum, Int shift)
438 {
439   return (( count*offset*offset-diffSum*offset*2 ) >> shift);
440 }
441 
442 
estIterOffset(Int typeIdx,Int classIdx,Double lambda,Int offsetInput,Int64 count,Int64 diffSum,Int shift,Int bitIncrease,Int64 & bestDist,Double & bestCost,Int offsetTh)443 inline Int TEncSampleAdaptiveOffset::estIterOffset(Int typeIdx, Int classIdx, Double lambda, Int offsetInput, Int64 count, Int64 diffSum, Int shift, Int bitIncrease, Int64& bestDist, Double& bestCost, Int offsetTh )
444 {
445   Int iterOffset, tempOffset;
446   Int64 tempDist, tempRate;
447   Double tempCost, tempMinCost;
448   Int offsetOutput = 0;
449   iterOffset = offsetInput;
450   // Assuming sending quantized value 0 results in zero offset and sending the value zero needs 1 bit. entropy coder can be used to measure the exact rate here.
451   tempMinCost = lambda;
452   while (iterOffset != 0)
453   {
454     // Calculate the bits required for signaling the offset
455     tempRate = (typeIdx == SAO_TYPE_BO) ? (abs((Int)iterOffset)+2) : (abs((Int)iterOffset)+1);
456     if (abs((Int)iterOffset)==offsetTh) //inclusive
457     {
458       tempRate --;
459     }
460     // Do the dequantization before distortion calculation
461     tempOffset  = iterOffset << bitIncrease;
462     tempDist    = estSaoDist( count, tempOffset, diffSum, shift);
463     tempCost    = ((Double)tempDist + lambda * (Double) tempRate);
464     if(tempCost < tempMinCost)
465     {
466       tempMinCost = tempCost;
467       offsetOutput = iterOffset;
468       bestDist = tempDist;
469       bestCost = tempCost;
470     }
471     iterOffset = (iterOffset > 0) ? (iterOffset-1):(iterOffset+1);
472   }
473   return offsetOutput;
474 }
475 
deriveOffsets(ComponentID compIdx,Int typeIdc,SAOStatData & statData,Int * quantOffsets,Int & typeAuxInfo)476 Void TEncSampleAdaptiveOffset::deriveOffsets(ComponentID compIdx, Int typeIdc, SAOStatData& statData, Int* quantOffsets, Int& typeAuxInfo)
477 {
478   Int bitDepth = g_bitDepth[toChannelType(compIdx)];
479   Int shift    = 2 * DISTORTION_PRECISION_ADJUSTMENT(bitDepth-8);
480   Int offsetTh = g_saoMaxOffsetQVal[compIdx];  //inclusive
481 
482   ::memset(quantOffsets, 0, sizeof(Int)*MAX_NUM_SAO_CLASSES);
483 
484   //derive initial offsets
485   Int numClasses = (typeIdc == SAO_TYPE_BO)?((Int)NUM_SAO_BO_CLASSES):((Int)NUM_SAO_EO_CLASSES);
486   for(Int classIdx=0; classIdx< numClasses; classIdx++)
487   {
488     if( (typeIdc != SAO_TYPE_BO) && (classIdx==SAO_CLASS_EO_PLAIN)  )
489     {
490       continue; //offset will be zero
491     }
492 
493     if(statData.count[classIdx] == 0)
494     {
495       continue; //offset will be zero
496     }
497 
498     quantOffsets[classIdx] = (Int) xRoundIbdi(bitDepth, (Double)( statData.diff[classIdx]<<(bitDepth-8))
499                                                                   /
500                                                           (Double)( statData.count[classIdx]<< m_offsetStepLog2[compIdx])
501                                                );
502     quantOffsets[classIdx] = Clip3(-offsetTh, offsetTh, quantOffsets[classIdx]);
503   }
504 
505   // adjust offsets
506   switch(typeIdc)
507   {
508     case SAO_TYPE_EO_0:
509     case SAO_TYPE_EO_90:
510     case SAO_TYPE_EO_135:
511     case SAO_TYPE_EO_45:
512       {
513         Int64 classDist;
514         Double classCost;
515         for(Int classIdx=0; classIdx<NUM_SAO_EO_CLASSES; classIdx++)
516         {
517           if(classIdx==SAO_CLASS_EO_FULL_VALLEY && quantOffsets[classIdx] < 0) quantOffsets[classIdx] =0;
518           if(classIdx==SAO_CLASS_EO_HALF_VALLEY && quantOffsets[classIdx] < 0) quantOffsets[classIdx] =0;
519           if(classIdx==SAO_CLASS_EO_HALF_PEAK   && quantOffsets[classIdx] > 0) quantOffsets[classIdx] =0;
520           if(classIdx==SAO_CLASS_EO_FULL_PEAK   && quantOffsets[classIdx] > 0) quantOffsets[classIdx] =0;
521 
522           if( quantOffsets[classIdx] != 0 ) //iterative adjustment only when derived offset is not zero
523           {
524             quantOffsets[classIdx] = estIterOffset( typeIdc, classIdx, m_lambda[compIdx], quantOffsets[classIdx], statData.count[classIdx], statData.diff[classIdx], shift, m_offsetStepLog2[compIdx], classDist , classCost , offsetTh );
525           }
526         }
527 
528         typeAuxInfo =0;
529       }
530       break;
531     case SAO_TYPE_BO:
532       {
533         Int64  distBOClasses[NUM_SAO_BO_CLASSES];
534         Double costBOClasses[NUM_SAO_BO_CLASSES];
535         ::memset(distBOClasses, 0, sizeof(Int64)*NUM_SAO_BO_CLASSES);
536         for(Int classIdx=0; classIdx< NUM_SAO_BO_CLASSES; classIdx++)
537         {
538           costBOClasses[classIdx]= m_lambda[compIdx];
539           if( quantOffsets[classIdx] != 0 ) //iterative adjustment only when derived offset is not zero
540           {
541             quantOffsets[classIdx] = estIterOffset( typeIdc, classIdx, m_lambda[compIdx], quantOffsets[classIdx], statData.count[classIdx], statData.diff[classIdx], shift, m_offsetStepLog2[compIdx], distBOClasses[classIdx], costBOClasses[classIdx], offsetTh );
542           }
543         }
544 
545         //decide the starting band index
546         Double minCost = MAX_DOUBLE, cost;
547         for(Int band=0; band< NUM_SAO_BO_CLASSES- 4+ 1; band++)
548         {
549           cost  = costBOClasses[band  ];
550           cost += costBOClasses[band+1];
551           cost += costBOClasses[band+2];
552           cost += costBOClasses[band+3];
553 
554           if(cost < minCost)
555           {
556             minCost = cost;
557             typeAuxInfo = band;
558           }
559         }
560         //clear those unused classes
561         Int clearQuantOffset[NUM_SAO_BO_CLASSES];
562         ::memset(clearQuantOffset, 0, sizeof(Int)*NUM_SAO_BO_CLASSES);
563         for(Int i=0; i< 4; i++)
564         {
565           Int band = (typeAuxInfo+i)%NUM_SAO_BO_CLASSES;
566           clearQuantOffset[band] = quantOffsets[band];
567         }
568         ::memcpy(quantOffsets, clearQuantOffset, sizeof(Int)*NUM_SAO_BO_CLASSES);
569       }
570       break;
571     default:
572       {
573         printf("Not a supported type");
574         assert(0);
575         exit(-1);
576       }
577 
578   }
579 
580 
581 }
582 
deriveModeNewRDO(Int ctuRsAddr,SAOBlkParam * mergeList[NUM_SAO_MERGE_TYPES],Bool * sliceEnabled,SAOStatData *** blkStats,SAOBlkParam & modeParam,Double & modeNormCost,TEncSbac ** cabacCoderRDO,Int inCabacLabel)583 Void TEncSampleAdaptiveOffset::deriveModeNewRDO(Int ctuRsAddr, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES], Bool* sliceEnabled, SAOStatData*** blkStats, SAOBlkParam& modeParam, Double& modeNormCost, TEncSbac** cabacCoderRDO, Int inCabacLabel)
584 {
585   Double minCost, cost;
586   UInt previousWrittenBits;
587   const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC);
588 
589   Int64 dist[MAX_NUM_COMPONENT], modeDist[MAX_NUM_COMPONENT];
590   SAOOffset testOffset[MAX_NUM_COMPONENT];
591   Int invQuantOffset[MAX_NUM_SAO_CLASSES];
592   for(Int comp=0; comp < MAX_NUM_COMPONENT; comp++)
593   {
594     modeDist[comp] = 0;
595   }
596 
597   //pre-encode merge flags
598   modeParam[COMPONENT_Y].modeIdc = SAO_MODE_OFF;
599   m_pcRDGoOnSbacCoder->load(cabacCoderRDO[inCabacLabel]);
600   m_pcRDGoOnSbacCoder->codeSAOBlkParam(modeParam, sliceEnabled, (mergeList[SAO_MERGE_LEFT]!= NULL), (mergeList[SAO_MERGE_ABOVE]!= NULL), true);
601   m_pcRDGoOnSbacCoder->store(cabacCoderRDO[SAO_CABACSTATE_BLK_MID]);
602 
603     //------ luma --------//
604   {
605     ComponentID compIdx = COMPONENT_Y;
606     //"off" case as initial cost
607     modeParam[compIdx].modeIdc = SAO_MODE_OFF;
608     m_pcRDGoOnSbacCoder->resetBits();
609     m_pcRDGoOnSbacCoder->codeSAOOffsetParam(compIdx, modeParam[compIdx], sliceEnabled[compIdx]);
610     modeDist[compIdx] = 0;
611     minCost= m_lambda[compIdx]*((Double)m_pcRDGoOnSbacCoder->getNumberOfWrittenBits());
612     m_pcRDGoOnSbacCoder->store(cabacCoderRDO[SAO_CABACSTATE_BLK_TEMP]);
613     if(sliceEnabled[compIdx])
614     {
615       for(Int typeIdc=0; typeIdc< NUM_SAO_NEW_TYPES; typeIdc++)
616       {
617         testOffset[compIdx].modeIdc = SAO_MODE_NEW;
618         testOffset[compIdx].typeIdc = typeIdc;
619 
620         //derive coded offset
621         deriveOffsets(compIdx, typeIdc, blkStats[ctuRsAddr][compIdx][typeIdc], testOffset[compIdx].offset, testOffset[compIdx].typeAuxInfo);
622 
623         //inversed quantized offsets
624         invertQuantOffsets(compIdx, typeIdc, testOffset[compIdx].typeAuxInfo, invQuantOffset, testOffset[compIdx].offset);
625 
626         //get distortion
627         dist[compIdx] = getDistortion(compIdx, testOffset[compIdx].typeIdc, testOffset[compIdx].typeAuxInfo, invQuantOffset, blkStats[ctuRsAddr][compIdx][typeIdc]);
628 
629         //get rate
630         m_pcRDGoOnSbacCoder->load(cabacCoderRDO[SAO_CABACSTATE_BLK_MID]);
631         m_pcRDGoOnSbacCoder->resetBits();
632         m_pcRDGoOnSbacCoder->codeSAOOffsetParam(compIdx, testOffset[compIdx], sliceEnabled[compIdx]);
633         Int rate = m_pcRDGoOnSbacCoder->getNumberOfWrittenBits();
634         cost = (Double)dist[compIdx] + m_lambda[compIdx]*((Double)rate);
635         if(cost < minCost)
636         {
637           minCost = cost;
638           modeDist[compIdx] = dist[compIdx];
639           modeParam[compIdx]= testOffset[compIdx];
640           m_pcRDGoOnSbacCoder->store(cabacCoderRDO[SAO_CABACSTATE_BLK_TEMP]);
641         }
642       }
643     }
644     m_pcRDGoOnSbacCoder->load(cabacCoderRDO[SAO_CABACSTATE_BLK_TEMP]);
645     m_pcRDGoOnSbacCoder->store(cabacCoderRDO[SAO_CABACSTATE_BLK_MID]);
646   }
647 
648   //------ chroma --------//
649 //"off" case as initial cost
650   cost = 0;
651   previousWrittenBits = 0;
652   m_pcRDGoOnSbacCoder->resetBits();
653   for(UInt componentIndex = COMPONENT_Cb; componentIndex < numberOfComponents; componentIndex++)
654   {
655     const ComponentID component = ComponentID(componentIndex);
656 
657     modeParam[component].modeIdc = SAO_MODE_OFF;
658     modeDist [component]         = 0;
659     m_pcRDGoOnSbacCoder->codeSAOOffsetParam(component, modeParam[component], sliceEnabled[component]);
660 
661     const UInt currentWrittenBits = m_pcRDGoOnSbacCoder->getNumberOfWrittenBits();
662     cost += m_lambda[component] * (currentWrittenBits - previousWrittenBits);
663     previousWrittenBits = currentWrittenBits;
664   }
665 
666   minCost = cost;
667 
668   //doesn't need to store cabac status here since the whole CTU parameters will be re-encoded at the end of this function
669 
670   for(Int typeIdc=0; typeIdc< NUM_SAO_NEW_TYPES; typeIdc++)
671   {
672     m_pcRDGoOnSbacCoder->load(cabacCoderRDO[SAO_CABACSTATE_BLK_MID]);
673     m_pcRDGoOnSbacCoder->resetBits();
674     previousWrittenBits = 0;
675     cost = 0;
676 
677     for(UInt componentIndex = COMPONENT_Cb; componentIndex < numberOfComponents; componentIndex++)
678     {
679       const ComponentID component = ComponentID(componentIndex);
680       if(!sliceEnabled[component])
681       {
682         testOffset[component].modeIdc = SAO_MODE_OFF;
683         dist[component]= 0;
684         continue;
685       }
686       testOffset[component].modeIdc = SAO_MODE_NEW;
687       testOffset[component].typeIdc = typeIdc;
688 
689       //derive offset & get distortion
690       deriveOffsets(component, typeIdc, blkStats[ctuRsAddr][component][typeIdc], testOffset[component].offset, testOffset[component].typeAuxInfo);
691       invertQuantOffsets(component, typeIdc, testOffset[component].typeAuxInfo, invQuantOffset, testOffset[component].offset);
692       dist[component] = getDistortion(component, typeIdc, testOffset[component].typeAuxInfo, invQuantOffset, blkStats[ctuRsAddr][component][typeIdc]);
693 
694       m_pcRDGoOnSbacCoder->codeSAOOffsetParam(component, testOffset[component], sliceEnabled[component]);
695 
696       const UInt currentWrittenBits = m_pcRDGoOnSbacCoder->getNumberOfWrittenBits();
697       cost += dist[component] + (m_lambda[component] * (currentWrittenBits - previousWrittenBits));
698       previousWrittenBits = currentWrittenBits;
699     }
700 
701     if(cost < minCost)
702     {
703       minCost = cost;
704       for(UInt componentIndex = COMPONENT_Cb; componentIndex < numberOfComponents; componentIndex++)
705       {
706         modeDist[componentIndex]  = dist[componentIndex];
707         modeParam[componentIndex] = testOffset[componentIndex];
708       }
709     }
710 
711   } // SAO_TYPE loop
712 
713   //----- re-gen rate & normalized cost----//
714   modeNormCost = 0;
715   for(UInt componentIndex = COMPONENT_Y; componentIndex < numberOfComponents; componentIndex++)
716   {
717     modeNormCost += (Double)modeDist[componentIndex] / m_lambda[componentIndex];
718   }
719 
720   m_pcRDGoOnSbacCoder->load(cabacCoderRDO[inCabacLabel]);
721   m_pcRDGoOnSbacCoder->resetBits();
722   m_pcRDGoOnSbacCoder->codeSAOBlkParam(modeParam, sliceEnabled, (mergeList[SAO_MERGE_LEFT]!= NULL), (mergeList[SAO_MERGE_ABOVE]!= NULL), false);
723   modeNormCost += (Double)m_pcRDGoOnSbacCoder->getNumberOfWrittenBits();
724 }
725 
deriveModeMergeRDO(Int ctuRsAddr,SAOBlkParam * mergeList[NUM_SAO_MERGE_TYPES],Bool * sliceEnabled,SAOStatData *** blkStats,SAOBlkParam & modeParam,Double & modeNormCost,TEncSbac ** cabacCoderRDO,Int inCabacLabel)726 Void TEncSampleAdaptiveOffset::deriveModeMergeRDO(Int ctuRsAddr, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES], Bool* sliceEnabled, SAOStatData*** blkStats, SAOBlkParam& modeParam, Double& modeNormCost, TEncSbac** cabacCoderRDO, Int inCabacLabel)
727 {
728   modeNormCost = MAX_DOUBLE;
729 
730   Double cost;
731   SAOBlkParam testBlkParam;
732   const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC);
733 
734   for(Int mergeType=0; mergeType< NUM_SAO_MERGE_TYPES; mergeType++)
735   {
736     if(mergeList[mergeType] == NULL)
737     {
738       continue;
739     }
740 
741     testBlkParam = *(mergeList[mergeType]);
742     //normalized distortion
743     Double normDist=0;
744     for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++)
745     {
746       testBlkParam[compIdx].modeIdc = SAO_MODE_MERGE;
747       testBlkParam[compIdx].typeIdc = mergeType;
748 
749       SAOOffset& mergedOffsetParam = (*(mergeList[mergeType]))[compIdx];
750 
751       if( mergedOffsetParam.modeIdc != SAO_MODE_OFF)
752       {
753         //offsets have been reconstructed. Don't call inversed quantization function.
754         normDist += (((Double)getDistortion(ComponentID(compIdx), mergedOffsetParam.typeIdc, mergedOffsetParam.typeAuxInfo, mergedOffsetParam.offset, blkStats[ctuRsAddr][compIdx][mergedOffsetParam.typeIdc]))
755                        /m_lambda[compIdx]
756                     );
757       }
758 
759     }
760 
761     //rate
762     m_pcRDGoOnSbacCoder->load(cabacCoderRDO[inCabacLabel]);
763     m_pcRDGoOnSbacCoder->resetBits();
764     m_pcRDGoOnSbacCoder->codeSAOBlkParam(testBlkParam, sliceEnabled, (mergeList[SAO_MERGE_LEFT]!= NULL), (mergeList[SAO_MERGE_ABOVE]!= NULL), false);
765     Int rate = m_pcRDGoOnSbacCoder->getNumberOfWrittenBits();
766 
767     cost = normDist+(Double)rate;
768 
769     if(cost < modeNormCost)
770     {
771       modeNormCost = cost;
772       modeParam    = testBlkParam;
773       m_pcRDGoOnSbacCoder->store(cabacCoderRDO[SAO_CABACSTATE_BLK_TEMP]);
774     }
775   }
776 
777   m_pcRDGoOnSbacCoder->load(cabacCoderRDO[SAO_CABACSTATE_BLK_TEMP]);
778 }
779 
decideBlkParams(TComPic * pic,Bool * sliceEnabled,SAOStatData *** blkStats,TComPicYuv * srcYuv,TComPicYuv * resYuv,SAOBlkParam * reconParams,SAOBlkParam * codedParams)780 Void TEncSampleAdaptiveOffset::decideBlkParams(TComPic* pic, Bool* sliceEnabled, SAOStatData*** blkStats, TComPicYuv* srcYuv, TComPicYuv* resYuv, SAOBlkParam* reconParams, SAOBlkParam* codedParams)
781 {
782   Bool allBlksDisabled = true;
783   const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC);
784   for(Int compId = COMPONENT_Y; compId < numberOfComponents; compId++)
785   {
786     if (sliceEnabled[compId])
787       allBlksDisabled = false;
788   }
789 
790   m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[ SAO_CABACSTATE_PIC_INIT ]);
791 
792   SAOBlkParam modeParam;
793   Double minCost, modeCost;
794 
795 
796 #if RD_TEST_SAO_DISABLE_AT_PICTURE_LEVEL
797   Double totalCost = 0;
798 #endif
799 
800   for(Int ctuRsAddr=0; ctuRsAddr< m_numCTUsPic; ctuRsAddr++)
801   {
802     if(allBlksDisabled)
803     {
804       codedParams[ctuRsAddr].reset();
805       continue;
806     }
807 
808     m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[ SAO_CABACSTATE_BLK_CUR ]);
809 
810     //get merge list
811     SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES] = { NULL };
812     getMergeList(pic, ctuRsAddr, reconParams, mergeList);
813 
814     minCost = MAX_DOUBLE;
815     for(Int mode=0; mode < NUM_SAO_MODES; mode++)
816     {
817       switch(mode)
818       {
819       case SAO_MODE_OFF:
820         {
821           continue; //not necessary, since all-off case will be tested in SAO_MODE_NEW case.
822         }
823         break;
824       case SAO_MODE_NEW:
825         {
826           deriveModeNewRDO(ctuRsAddr, mergeList, sliceEnabled, blkStats, modeParam, modeCost, m_pppcRDSbacCoder, SAO_CABACSTATE_BLK_CUR);
827 
828         }
829         break;
830       case SAO_MODE_MERGE:
831         {
832           deriveModeMergeRDO(ctuRsAddr, mergeList, sliceEnabled, blkStats , modeParam, modeCost, m_pppcRDSbacCoder, SAO_CABACSTATE_BLK_CUR);
833         }
834         break;
835       default:
836         {
837           printf("Not a supported SAO mode\n");
838           assert(0);
839           exit(-1);
840         }
841       }
842 
843       if(modeCost < minCost)
844       {
845         minCost = modeCost;
846         codedParams[ctuRsAddr] = modeParam;
847         m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[ SAO_CABACSTATE_BLK_NEXT ]);
848       }
849     } //mode
850 
851 #if RD_TEST_SAO_DISABLE_AT_PICTURE_LEVEL
852     totalCost += minCost;
853 #endif
854 
855     m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[ SAO_CABACSTATE_BLK_NEXT ]);
856 
857     //apply reconstructed offsets
858     reconParams[ctuRsAddr] = codedParams[ctuRsAddr];
859     reconstructBlkSAOParam(reconParams[ctuRsAddr], mergeList);
860     offsetCTU(ctuRsAddr, srcYuv, resYuv, reconParams[ctuRsAddr], pic);
861   } //ctuRsAddr
862 
863 #if RD_TEST_SAO_DISABLE_AT_PICTURE_LEVEL
864   if (!allBlksDisabled && (totalCost >= 0)) //SAO is not beneficial - disable it
865   {
866     for(Int ctuRsAddr = 0; ctuRsAddr < m_numCTUsPic; ctuRsAddr++)
867     {
868       codedParams[ctuRsAddr].reset();
869     }
870 
871     for (UInt componentIndex = 0; componentIndex < MAX_NUM_COMPONENT; componentIndex++)
872     {
873       sliceEnabled[componentIndex] = false;
874     }
875 
876     m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[ SAO_CABACSTATE_PIC_INIT ]);
877   }
878 #endif
879 
880 #if SAO_ENCODING_CHOICE
881   Int picTempLayer = pic->getSlice(0)->getDepth();
882   Int numCtusForSAOOff[MAX_NUM_COMPONENT];
883 
884   for (Int compIdx = 0; compIdx < numberOfComponents; compIdx++)
885   {
886     numCtusForSAOOff[compIdx] = 0;
887     for(Int ctuRsAddr=0; ctuRsAddr< m_numCTUsPic; ctuRsAddr++)
888     {
889       if( reconParams[ctuRsAddr][compIdx].modeIdc == SAO_MODE_OFF)
890       {
891         numCtusForSAOOff[compIdx]++;
892       }
893     }
894   }
895 #if SAO_ENCODING_CHOICE_CHROMA
896   for (Int compIdx = 0; compIdx < numberOfComponents; compIdx++)
897   {
898     m_saoDisabledRate[compIdx][picTempLayer] = (Double)numCtusForSAOOff[compIdx]/(Double)m_numCTUsPic;
899   }
900 #else
901   if (picTempLayer == 0)
902   {
903     m_saoDisabledRate[COMPONENT_Y][0] = (Double)(numCtusForSAOOff[COMPONENT_Y]+numCtusForSAOOff[COMPONENT_Cb]+numCtusForSAOOff[COMPONENT_Cr])/(Double)(m_numCTUsPic*3);
904   }
905 #endif
906 #endif
907 }
908 
909 
getBlkStats(ComponentID compIdx,SAOStatData * statsDataTypes,Pel * srcBlk,Pel * orgBlk,Int srcStride,Int orgStride,Int width,Int height,Bool isLeftAvail,Bool isRightAvail,Bool isAboveAvail,Bool isBelowAvail,Bool isAboveLeftAvail,Bool isAboveRightAvail,Bool isBelowLeftAvail,Bool isBelowRightAvail,Bool isCalculatePreDeblockSamples)910 Void TEncSampleAdaptiveOffset::getBlkStats(ComponentID compIdx, SAOStatData* statsDataTypes
911                         , Pel* srcBlk, Pel* orgBlk, Int srcStride, Int orgStride, Int width, Int height
912                         , Bool isLeftAvail,  Bool isRightAvail, Bool isAboveAvail, Bool isBelowAvail, Bool isAboveLeftAvail, Bool isAboveRightAvail, Bool isBelowLeftAvail, Bool isBelowRightAvail
913 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
914                         , Bool isCalculatePreDeblockSamples
915 #endif
916                         )
917 {
918   if(m_lineBufWidth != m_maxCUWidth)
919   {
920     m_lineBufWidth = m_maxCUWidth;
921 
922     if (m_signLineBuf1) delete[] m_signLineBuf1; m_signLineBuf1 = NULL;
923     m_signLineBuf1 = new Char[m_lineBufWidth+1];
924 
925     if (m_signLineBuf2) delete[] m_signLineBuf2; m_signLineBuf2 = NULL;
926     m_signLineBuf2 = new Char[m_lineBufWidth+1];
927   }
928 
929   Int x,y, startX, startY, endX, endY, edgeType, firstLineStartX, firstLineEndX;
930   Char signLeft, signRight, signDown;
931   Int64 *diff, *count;
932   Pel *srcLine, *orgLine;
933   Int* skipLinesR = m_skipLinesR[compIdx];
934   Int* skipLinesB = m_skipLinesB[compIdx];
935 
936   for(Int typeIdx=0; typeIdx< NUM_SAO_NEW_TYPES; typeIdx++)
937   {
938     SAOStatData& statsData= statsDataTypes[typeIdx];
939     statsData.reset();
940 
941     srcLine = srcBlk;
942     orgLine = orgBlk;
943     diff    = statsData.diff;
944     count   = statsData.count;
945     switch(typeIdx)
946     {
947     case SAO_TYPE_EO_0:
948       {
949         diff +=2;
950         count+=2;
951         endY   = (isBelowAvail) ? (height - skipLinesB[typeIdx]) : height;
952 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
953         startX = (!isCalculatePreDeblockSamples) ? (isLeftAvail  ? 0 : 1)
954                                                  : (isRightAvail ? (width - skipLinesR[typeIdx]) : (width - 1))
955                                                  ;
956 #else
957         startX = isLeftAvail ? 0 : 1;
958 #endif
959 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
960         endX   = (!isCalculatePreDeblockSamples) ? (isRightAvail ? (width - skipLinesR[typeIdx]) : (width - 1))
961                                                  : (isRightAvail ? width : (width - 1))
962                                                  ;
963 #else
964         endX   = isRightAvail ? (width - skipLinesR[typeIdx]): (width - 1);
965 #endif
966         for (y=0; y<endY; y++)
967         {
968           signLeft = (Char)sgn(srcLine[startX] - srcLine[startX-1]);
969           for (x=startX; x<endX; x++)
970           {
971             signRight =  (Char)sgn(srcLine[x] - srcLine[x+1]);
972             edgeType  =  signRight + signLeft;
973             signLeft  = -signRight;
974 
975             diff [edgeType] += (orgLine[x] - srcLine[x]);
976             count[edgeType] ++;
977           }
978           srcLine  += srcStride;
979           orgLine  += orgStride;
980         }
981 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
982         if(isCalculatePreDeblockSamples)
983         {
984           if(isBelowAvail)
985           {
986             startX = isLeftAvail  ? 0 : 1;
987             endX   = isRightAvail ? width : (width -1);
988 
989             for(y=0; y<skipLinesB[typeIdx]; y++)
990             {
991               signLeft = (Char)sgn(srcLine[startX] - srcLine[startX-1]);
992               for (x=startX; x<endX; x++)
993               {
994                 signRight =  (Char)sgn(srcLine[x] - srcLine[x+1]);
995                 edgeType  =  signRight + signLeft;
996                 signLeft  = -signRight;
997 
998                 diff [edgeType] += (orgLine[x] - srcLine[x]);
999                 count[edgeType] ++;
1000               }
1001               srcLine  += srcStride;
1002               orgLine  += orgStride;
1003             }
1004           }
1005         }
1006 #endif
1007       }
1008       break;
1009     case SAO_TYPE_EO_90:
1010       {
1011         diff +=2;
1012         count+=2;
1013         Char *signUpLine = m_signLineBuf1;
1014 
1015 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
1016         startX = (!isCalculatePreDeblockSamples) ? 0
1017                                                  : (isRightAvail ? (width - skipLinesR[typeIdx]) : width)
1018                                                  ;
1019 #endif
1020         startY = isAboveAvail ? 0 : 1;
1021 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
1022         endX   = (!isCalculatePreDeblockSamples) ? (isRightAvail ? (width - skipLinesR[typeIdx]) : width)
1023                                                  : width
1024                                                  ;
1025 #else
1026         endX   = isRightAvail ? (width - skipLinesR[typeIdx]) : width ;
1027 #endif
1028         endY   = isBelowAvail ? (height - skipLinesB[typeIdx]) : (height - 1);
1029         if (!isAboveAvail)
1030         {
1031           srcLine += srcStride;
1032           orgLine += orgStride;
1033         }
1034 
1035         Pel* srcLineAbove = srcLine - srcStride;
1036 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
1037         for (x=startX; x<endX; x++)
1038 #else
1039         for (x=0; x< endX; x++)
1040 #endif
1041         {
1042           signUpLine[x] = (Char)sgn(srcLine[x] - srcLineAbove[x]);
1043         }
1044 
1045         Pel* srcLineBelow;
1046         for (y=startY; y<endY; y++)
1047         {
1048           srcLineBelow = srcLine + srcStride;
1049 
1050 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
1051           for (x=startX; x<endX; x++)
1052 #else
1053           for (x=0; x<endX; x++)
1054 #endif
1055           {
1056             signDown  = (Char)sgn(srcLine[x] - srcLineBelow[x]);
1057             edgeType  = signDown + signUpLine[x];
1058             signUpLine[x]= -signDown;
1059 
1060             diff [edgeType] += (orgLine[x] - srcLine[x]);
1061             count[edgeType] ++;
1062           }
1063           srcLine += srcStride;
1064           orgLine += orgStride;
1065         }
1066 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
1067         if(isCalculatePreDeblockSamples)
1068         {
1069           if(isBelowAvail)
1070           {
1071             startX = 0;
1072             endX   = width;
1073 
1074             for(y=0; y<skipLinesB[typeIdx]; y++)
1075             {
1076               srcLineBelow = srcLine + srcStride;
1077               srcLineAbove = srcLine - srcStride;
1078 
1079               for (x=startX; x<endX; x++)
1080               {
1081                 edgeType = sgn(srcLine[x] - srcLineBelow[x]) + sgn(srcLine[x] - srcLineAbove[x]);
1082                 diff [edgeType] += (orgLine[x] - srcLine[x]);
1083                 count[edgeType] ++;
1084               }
1085               srcLine  += srcStride;
1086               orgLine  += orgStride;
1087             }
1088           }
1089         }
1090 #endif
1091 
1092       }
1093       break;
1094     case SAO_TYPE_EO_135:
1095       {
1096         diff +=2;
1097         count+=2;
1098         Char *signUpLine, *signDownLine, *signTmpLine;
1099 
1100         signUpLine  = m_signLineBuf1;
1101         signDownLine= m_signLineBuf2;
1102 
1103 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
1104         startX = (!isCalculatePreDeblockSamples) ? (isLeftAvail  ? 0 : 1)
1105                                                  : (isRightAvail ? (width - skipLinesR[typeIdx]) : (width - 1))
1106                                                  ;
1107 #else
1108         startX = isLeftAvail ? 0 : 1 ;
1109 #endif
1110 
1111 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
1112         endX   = (!isCalculatePreDeblockSamples) ? (isRightAvail ? (width - skipLinesR[typeIdx]): (width - 1))
1113                                                  : (isRightAvail ? width : (width - 1))
1114                                                  ;
1115 #else
1116         endX   = isRightAvail ? (width - skipLinesR[typeIdx]): (width - 1);
1117 #endif
1118         endY   = isBelowAvail ? (height - skipLinesB[typeIdx]) : (height - 1);
1119 
1120         //prepare 2nd line's upper sign
1121         Pel* srcLineBelow = srcLine + srcStride;
1122         for (x=startX; x<endX+1; x++)
1123         {
1124           signUpLine[x] = (Char)sgn(srcLineBelow[x] - srcLine[x-1]);
1125         }
1126 
1127         //1st line
1128         Pel* srcLineAbove = srcLine - srcStride;
1129 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
1130         firstLineStartX = (!isCalculatePreDeblockSamples) ? (isAboveLeftAvail ? 0    : 1) : startX;
1131         firstLineEndX   = (!isCalculatePreDeblockSamples) ? (isAboveAvail     ? endX : 1) : endX;
1132 #else
1133         firstLineStartX = isAboveLeftAvail ? 0    : 1;
1134         firstLineEndX   = isAboveAvail     ? endX : 1;
1135 #endif
1136         for(x=firstLineStartX; x<firstLineEndX; x++)
1137         {
1138           edgeType = sgn(srcLine[x] - srcLineAbove[x-1]) - signUpLine[x+1];
1139           diff [edgeType] += (orgLine[x] - srcLine[x]);
1140           count[edgeType] ++;
1141         }
1142         srcLine  += srcStride;
1143         orgLine  += orgStride;
1144 
1145 
1146         //middle lines
1147         for (y=1; y<endY; y++)
1148         {
1149           srcLineBelow = srcLine + srcStride;
1150 
1151           for (x=startX; x<endX; x++)
1152           {
1153             signDown = (Char)sgn(srcLine[x] - srcLineBelow[x+1]);
1154             edgeType = signDown + signUpLine[x];
1155             diff [edgeType] += (orgLine[x] - srcLine[x]);
1156             count[edgeType] ++;
1157 
1158             signDownLine[x+1] = -signDown;
1159           }
1160           signDownLine[startX] = (Char)sgn(srcLineBelow[startX] - srcLine[startX-1]);
1161 
1162           signTmpLine  = signUpLine;
1163           signUpLine   = signDownLine;
1164           signDownLine = signTmpLine;
1165 
1166           srcLine += srcStride;
1167           orgLine += orgStride;
1168         }
1169 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
1170         if(isCalculatePreDeblockSamples)
1171         {
1172           if(isBelowAvail)
1173           {
1174             startX = isLeftAvail  ? 0     : 1 ;
1175             endX   = isRightAvail ? width : (width -1);
1176 
1177             for(y=0; y<skipLinesB[typeIdx]; y++)
1178             {
1179               srcLineBelow = srcLine + srcStride;
1180               srcLineAbove = srcLine - srcStride;
1181 
1182               for (x=startX; x< endX; x++)
1183               {
1184                 edgeType = sgn(srcLine[x] - srcLineBelow[x+1]) + sgn(srcLine[x] - srcLineAbove[x-1]);
1185                 diff [edgeType] += (orgLine[x] - srcLine[x]);
1186                 count[edgeType] ++;
1187               }
1188               srcLine  += srcStride;
1189               orgLine  += orgStride;
1190             }
1191           }
1192         }
1193 #endif
1194       }
1195       break;
1196     case SAO_TYPE_EO_45:
1197       {
1198         diff +=2;
1199         count+=2;
1200         Char *signUpLine = m_signLineBuf1+1;
1201 
1202 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
1203         startX = (!isCalculatePreDeblockSamples) ? (isLeftAvail  ? 0 : 1)
1204                                                  : (isRightAvail ? (width - skipLinesR[typeIdx]) : (width - 1))
1205                                                  ;
1206 #else
1207         startX = isLeftAvail ? 0 : 1;
1208 #endif
1209 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
1210         endX   = (!isCalculatePreDeblockSamples) ? (isRightAvail ? (width - skipLinesR[typeIdx]) : (width - 1))
1211                                                  : (isRightAvail ? width : (width - 1))
1212                                                  ;
1213 #else
1214         endX   = isRightAvail ? (width - skipLinesR[typeIdx]) : (width - 1);
1215 #endif
1216         endY   = isBelowAvail ? (height - skipLinesB[typeIdx]) : (height - 1);
1217 
1218         //prepare 2nd line upper sign
1219         Pel* srcLineBelow = srcLine + srcStride;
1220         for (x=startX-1; x<endX; x++)
1221         {
1222           signUpLine[x] = (Char)sgn(srcLineBelow[x] - srcLine[x+1]);
1223         }
1224 
1225 
1226         //first line
1227         Pel* srcLineAbove = srcLine - srcStride;
1228 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
1229         firstLineStartX = (!isCalculatePreDeblockSamples) ? (isAboveAvail ? startX : endX)
1230                                                           : startX
1231                                                           ;
1232         firstLineEndX   = (!isCalculatePreDeblockSamples) ? ((!isRightAvail && isAboveRightAvail) ? width : endX)
1233                                                           : endX
1234                                                           ;
1235 #else
1236         firstLineStartX = isAboveAvail ? startX : endX;
1237         firstLineEndX   = (!isRightAvail && isAboveRightAvail) ? width : endX;
1238 #endif
1239         for(x=firstLineStartX; x<firstLineEndX; x++)
1240         {
1241           edgeType = sgn(srcLine[x] - srcLineAbove[x+1]) - signUpLine[x-1];
1242           diff [edgeType] += (orgLine[x] - srcLine[x]);
1243           count[edgeType] ++;
1244         }
1245 
1246         srcLine += srcStride;
1247         orgLine += orgStride;
1248 
1249         //middle lines
1250         for (y=1; y<endY; y++)
1251         {
1252           srcLineBelow = srcLine + srcStride;
1253 
1254           for(x=startX; x<endX; x++)
1255           {
1256             signDown = (Char)sgn(srcLine[x] - srcLineBelow[x-1]);
1257             edgeType = signDown + signUpLine[x];
1258 
1259             diff [edgeType] += (orgLine[x] - srcLine[x]);
1260             count[edgeType] ++;
1261 
1262             signUpLine[x-1] = -signDown;
1263           }
1264           signUpLine[endX-1] = (Char)sgn(srcLineBelow[endX-1] - srcLine[endX]);
1265           srcLine  += srcStride;
1266           orgLine  += orgStride;
1267         }
1268 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
1269         if(isCalculatePreDeblockSamples)
1270         {
1271           if(isBelowAvail)
1272           {
1273             startX = isLeftAvail  ? 0     : 1 ;
1274             endX   = isRightAvail ? width : (width -1);
1275 
1276             for(y=0; y<skipLinesB[typeIdx]; y++)
1277             {
1278               srcLineBelow = srcLine + srcStride;
1279               srcLineAbove = srcLine - srcStride;
1280 
1281               for (x=startX; x<endX; x++)
1282               {
1283                 edgeType = sgn(srcLine[x] - srcLineBelow[x-1]) + sgn(srcLine[x] - srcLineAbove[x+1]);
1284                 diff [edgeType] += (orgLine[x] - srcLine[x]);
1285                 count[edgeType] ++;
1286               }
1287               srcLine  += srcStride;
1288               orgLine  += orgStride;
1289             }
1290           }
1291         }
1292 #endif
1293       }
1294       break;
1295     case SAO_TYPE_BO:
1296       {
1297 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
1298         startX = (!isCalculatePreDeblockSamples)?0
1299                                                 :( isRightAvail?(width- skipLinesR[typeIdx]):width)
1300                                                 ;
1301         endX   = (!isCalculatePreDeblockSamples)?(isRightAvail ? (width - skipLinesR[typeIdx]) : width )
1302                                                 :width
1303                                                 ;
1304 #else
1305         endX = isRightAvail ? (width- skipLinesR[typeIdx]) : width;
1306 #endif
1307         endY = isBelowAvail ? (height- skipLinesB[typeIdx]) : height;
1308         Int shiftBits = g_bitDepth[toChannelType(compIdx)] - NUM_SAO_BO_CLASSES_LOG2;
1309         for (y=0; y< endY; y++)
1310         {
1311 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
1312           for (x=startX; x< endX; x++)
1313 #else
1314           for (x=0; x< endX; x++)
1315 #endif
1316           {
1317 
1318             Int bandIdx= srcLine[x] >> shiftBits;
1319             diff [bandIdx] += (orgLine[x] - srcLine[x]);
1320             count[bandIdx] ++;
1321           }
1322           srcLine += srcStride;
1323           orgLine += orgStride;
1324         }
1325 #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK
1326         if(isCalculatePreDeblockSamples)
1327         {
1328           if(isBelowAvail)
1329           {
1330             startX = 0;
1331             endX   = width;
1332 
1333             for(y= 0; y< skipLinesB[typeIdx]; y++)
1334             {
1335               for (x=startX; x< endX; x++)
1336               {
1337                 Int bandIdx= srcLine[x] >> shiftBits;
1338                 diff [bandIdx] += (orgLine[x] - srcLine[x]);
1339                 count[bandIdx] ++;
1340               }
1341               srcLine  += srcStride;
1342               orgLine  += orgStride;
1343 
1344             }
1345 
1346           }
1347         }
1348 #endif
1349       }
1350       break;
1351     default:
1352       {
1353         printf("Not a supported SAO types\n");
1354         assert(0);
1355         exit(-1);
1356       }
1357     }
1358   }
1359 }
1360 
1361 
1362 //! \}
1363