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