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