source: 3DVCSoftware/trunk/source/Lib/TLibEncoder/TEncSampleAdaptiveOffset.cpp @ 980

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