source: 3DVCSoftware/trunk/source/Lib/TLibCommon/TComSampleAdaptiveOffset.cpp @ 1097

Last change on this file since 1097 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: 25.6 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
34/** \file     TComSampleAdaptiveOffset.cpp
35    \brief    sample adaptive offset class
36*/
37
38#include "TComSampleAdaptiveOffset.h"
39#include <string.h>
40#include <stdlib.h>
41#include <stdio.h>
42#include <math.h>
43
44//! \ingroup TLibCommon
45//! \{
[872]46UInt g_saoMaxOffsetQVal[NUM_SAO_COMPONENTS];
[56]47
[872]48SAOOffset::SAOOffset()
49{ 
50  reset();
[56]51}
52
[872]53SAOOffset::~SAOOffset()
[56]54{
55
56}
57
[872]58Void SAOOffset::reset()
[56]59{
[872]60  modeIdc = SAO_MODE_OFF;
61  typeIdc = -1;
62  typeAuxInfo = -1;
63  ::memset(offset, 0, sizeof(Int)* MAX_NUM_SAO_CLASSES);
[56]64}
65
[872]66const SAOOffset& SAOOffset::operator= (const SAOOffset& src)
[56]67{
[872]68  modeIdc = src.modeIdc;
69  typeIdc = src.typeIdc;
70  typeAuxInfo = src.typeAuxInfo;
71  ::memcpy(offset, src.offset, sizeof(Int)* MAX_NUM_SAO_CLASSES);
[56]72
[872]73  return *this;
74}
75
76
77SAOBlkParam::SAOBlkParam()
[56]78{
[872]79  reset();
80}
[56]81
[872]82SAOBlkParam::~SAOBlkParam()
[56]83{
84
[872]85}
[56]86
[872]87Void SAOBlkParam::reset()
[56]88{
[872]89  for(Int compIdx=0; compIdx< 3; compIdx++)
[56]90  {
[872]91    offsetParam[compIdx].reset();
[56]92  }
93}
[608]94
[872]95const SAOBlkParam& SAOBlkParam::operator= (const SAOBlkParam& src)
[56]96{
[872]97  for(Int compIdx=0; compIdx< 3; compIdx++)
[56]98  {
[872]99    offsetParam[compIdx] = src.offsetParam[compIdx];
[56]100  }
[872]101  return *this;
[608]102
[872]103}
[608]104
[872]105TComSampleAdaptiveOffset::TComSampleAdaptiveOffset()
106{
107  m_tempPicYuv = NULL;
108  for(Int compIdx=0; compIdx < NUM_SAO_COMPONENTS; compIdx++)
[608]109  {
[872]110    m_offsetClipTable[compIdx] = NULL;
[608]111  }
[964]112#if !SAO_SGN_FUNC
[872]113  m_signTable = NULL; 
[964]114#endif
[872]115 
116  m_lineBufWidth = 0;
117  m_signLineBuf1 = NULL;
118  m_signLineBuf2 = NULL;
119}
[56]120
121
[872]122TComSampleAdaptiveOffset::~TComSampleAdaptiveOffset()
123{
124  destroy();
125 
126  if (m_signLineBuf1) delete[] m_signLineBuf1; m_signLineBuf1 = NULL;
127  if (m_signLineBuf2) delete[] m_signLineBuf2; m_signLineBuf2 = NULL;
128}
[56]129
[872]130Void TComSampleAdaptiveOffset::create( Int picWidth, Int picHeight, UInt maxCUWidth, UInt maxCUHeight, UInt maxCUDepth )
131{
132  destroy();
[56]133
[872]134  m_picWidth = picWidth;   
135  m_picHeight= picHeight;
136  m_maxCUWidth= maxCUWidth; 
137  m_maxCUHeight= maxCUHeight;
[56]138
[872]139  m_numCTUInWidth = (m_picWidth/m_maxCUWidth) + ((m_picWidth % m_maxCUWidth)?1:0);
140  m_numCTUInHeight= (m_picHeight/m_maxCUHeight) + ((m_picHeight % m_maxCUHeight)?1:0);
141  m_numCTUsPic = m_numCTUInHeight*m_numCTUInWidth;
[56]142
[872]143  //temporary picture buffer
144  if ( !m_tempPicYuv )
[56]145  {
[872]146    m_tempPicYuv = new TComPicYuv;
147    m_tempPicYuv->create( m_picWidth, m_picHeight, m_maxCUWidth, m_maxCUHeight, maxCUDepth );
[56]148  }
149
[872]150  //bit-depth related
151  for(Int compIdx =0; compIdx < NUM_SAO_COMPONENTS; compIdx++)
[56]152  {
[872]153    Int bitDepthSample = (compIdx == SAO_Y)?g_bitDepthY:g_bitDepthC;
154    m_offsetStepLog2  [compIdx] = max(bitDepthSample - MAX_SAO_TRUNCATED_BITDEPTH, 0);
155    g_saoMaxOffsetQVal[compIdx] = (1<<(min(bitDepthSample,MAX_SAO_TRUNCATED_BITDEPTH)-5))-1; //Table 9-32, inclusive
[56]156  }
157
[964]158#if !SAO_SGN_FUNC
[872]159  //look-up table for clipping
[964]160  Int overallMaxSampleValue=0;
161#endif
[872]162  for(Int compIdx =0; compIdx < NUM_SAO_COMPONENTS; compIdx++)
[608]163  {
[872]164    Int bitDepthSample = (compIdx == SAO_Y)?g_bitDepthY:g_bitDepthC; //exclusive
165    Int maxSampleValue = (1<< bitDepthSample); //exclusive
166    Int maxOffsetValue = (g_saoMaxOffsetQVal[compIdx] << m_offsetStepLog2[compIdx]); 
[964]167#if !SAO_SGN_FUNC
168    if (maxSampleValue>overallMaxSampleValue) overallMaxSampleValue=maxSampleValue;
169#endif
[608]170
[872]171    m_offsetClipTable[compIdx] = new Int[(maxSampleValue + maxOffsetValue -1)+ (maxOffsetValue)+1 ]; //positive & negative range plus 0
172    m_offsetClip[compIdx] = &(m_offsetClipTable[compIdx][maxOffsetValue]);
[608]173
[872]174    //assign clipped values
175    Int* offsetClipPtr = m_offsetClip[compIdx];
176    for(Int k=0; k< maxSampleValue; k++)
177    {
178      *(offsetClipPtr + k) = k;
179    }
180    for(Int k=0; k< maxOffsetValue; k++ )
181    {
182      *(offsetClipPtr + maxSampleValue+ k) = maxSampleValue-1;
183      *(offsetClipPtr -k -1 )              = 0;
184    }
[964]185  }
[608]186
[964]187#if !SAO_SGN_FUNC
188  m_signTable = new Short[ 2*(overallMaxSampleValue-1) + 1 ];
189  m_sign = &(m_signTable[overallMaxSampleValue-1]);
190
[872]191      m_sign[0] = 0;
[964]192  for(Int k=1; k< overallMaxSampleValue; k++)
[872]193      {
194        m_sign[k] = 1;
195        m_sign[-k]= -1;
196      }
[964]197#endif
[56]198}
199
200Void TComSampleAdaptiveOffset::destroy()
201{
[872]202  if ( m_tempPicYuv )
[56]203  {
[872]204    m_tempPicYuv->destroy();
205    delete m_tempPicYuv;
206    m_tempPicYuv = NULL;
[56]207  }
208
[872]209  for(Int compIdx=0; compIdx < NUM_SAO_COMPONENTS; compIdx++)
[443]210  {
[872]211    if(m_offsetClipTable[compIdx])
212    {
213      delete[] m_offsetClipTable[compIdx]; m_offsetClipTable[compIdx] = NULL;
214    }
[443]215  }
[964]216#if !SAO_SGN_FUNC
[872]217  if( m_signTable )
[443]218  {
[872]219    delete[] m_signTable; m_signTable = NULL;
[443]220  }
[964]221#endif
[872]222}
[56]223
[872]224Void TComSampleAdaptiveOffset::invertQuantOffsets(Int compIdx, Int typeIdc, Int typeAuxInfo, Int* dstOffsets, Int* srcOffsets)
225{
226  Int codedOffset[MAX_NUM_SAO_CLASSES];
227
228  ::memcpy(codedOffset, srcOffsets, sizeof(Int)*MAX_NUM_SAO_CLASSES);
229  ::memset(dstOffsets, 0, sizeof(Int)*MAX_NUM_SAO_CLASSES);
230
231  if(typeIdc == SAO_TYPE_START_BO)
[56]232  {
[872]233    for(Int i=0; i< 4; i++)
234    {
235      dstOffsets[(typeAuxInfo+ i)%NUM_SAO_BO_CLASSES] = codedOffset[(typeAuxInfo+ i)%NUM_SAO_BO_CLASSES]*(1<<m_offsetStepLog2[compIdx]);
236    }
[56]237  }
[872]238  else //EO
[56]239  {
[872]240    for(Int i=0; i< NUM_SAO_EO_CLASSES; i++)
241    {
242      dstOffsets[i] = codedOffset[i] *(1<<m_offsetStepLog2[compIdx]);
243    }
244    assert(dstOffsets[SAO_CLASS_EO_PLAIN] == 0); //keep EO plain offset as zero
[56]245  }
246
247}
248
[872]249Int TComSampleAdaptiveOffset::getMergeList(TComPic* pic, Int ctu, SAOBlkParam* blkParams, std::vector<SAOBlkParam*>& mergeList)
[56]250{
[872]251  Int ctuX = ctu % m_numCTUInWidth;
252  Int ctuY = ctu / m_numCTUInWidth;
253  Int mergedCTUPos;
254  Int numValidMergeCandidates = 0;
[56]255
[872]256  for(Int mergeType=0; mergeType< NUM_SAO_MERGE_TYPES; mergeType++)
257  {
258    SAOBlkParam* mergeCandidate = NULL;
[56]259
[872]260    switch(mergeType)
261    {
262    case SAO_MERGE_ABOVE:
263      {
264        if(ctuY > 0)
265        {
266          mergedCTUPos = ctu- m_numCTUInWidth;
267          if( pic->getSAOMergeAvailability(ctu, mergedCTUPos) )
268          {
269            mergeCandidate = &(blkParams[mergedCTUPos]);
270          }
271        }
272      }
273      break;
274    case SAO_MERGE_LEFT:
275      {
276        if(ctuX > 0)
277        {
278          mergedCTUPos = ctu- 1;
279          if( pic->getSAOMergeAvailability(ctu, mergedCTUPos) )
280          {
281            mergeCandidate = &(blkParams[mergedCTUPos]);
282          }
283        }
284      }
285      break;
286    default:
287      {
288        printf("not a supported merge type");
289        assert(0);
290        exit(-1);
291      }
292    }
[56]293
[872]294    mergeList.push_back(mergeCandidate);
295    if (mergeCandidate != NULL)
296    {
297      numValidMergeCandidates++;
298    }
299  }
[56]300
[872]301  return numValidMergeCandidates;
302}
[56]303
304
[872]305Void TComSampleAdaptiveOffset::reconstructBlkSAOParam(SAOBlkParam& recParam, std::vector<SAOBlkParam*>& mergeList)
306{
307  for(Int compIdx=0; compIdx< NUM_SAO_COMPONENTS; compIdx++)
[56]308  {
[872]309    SAOOffset& offsetParam = recParam[compIdx];
[56]310
[872]311    if(offsetParam.modeIdc == SAO_MODE_OFF)
312    {
313      continue;
314    }
[56]315
[872]316    switch(offsetParam.modeIdc)
317    {
318    case SAO_MODE_NEW:
319      {
320        invertQuantOffsets(compIdx, offsetParam.typeIdc, offsetParam.typeAuxInfo, offsetParam.offset, offsetParam.offset);
321      }
322      break;
323    case SAO_MODE_MERGE:
324      {
325        SAOBlkParam* mergeTarget = mergeList[offsetParam.typeIdc];
326        assert(mergeTarget != NULL);
[56]327
[872]328        offsetParam = (*mergeTarget)[compIdx];
329      }
330      break;
331    default:
332      {
333        printf("Not a supported mode");
334        assert(0);
335        exit(-1);
336      }
337    }
[56]338  }
339}
340
[872]341Void TComSampleAdaptiveOffset::reconstructBlkSAOParams(TComPic* pic, SAOBlkParam* saoBlkParams)
[56]342{
[872]343  m_picSAOEnabled[SAO_Y] = m_picSAOEnabled[SAO_Cb] = m_picSAOEnabled[SAO_Cr] = false;
344
345  for(Int ctu=0; ctu< m_numCTUsPic; ctu++)
[56]346  {
[872]347    std::vector<SAOBlkParam*> mergeList;
348    getMergeList(pic, ctu, saoBlkParams, mergeList);
[56]349
[872]350    reconstructBlkSAOParam(saoBlkParams[ctu], mergeList);
351
352    for(Int compIdx=0; compIdx< NUM_SAO_COMPONENTS; compIdx++)
[56]353    {
[872]354      if(saoBlkParams[ctu][compIdx].modeIdc != SAO_MODE_OFF)
[56]355      {
[872]356        m_picSAOEnabled[compIdx] = true;
[56]357      }
358    }
359  }
360
361
362}
363
364
[872]365Void TComSampleAdaptiveOffset::offsetBlock(Int compIdx, Int typeIdx, Int* offset 
366                                          , Pel* srcBlk, Pel* resBlk, Int srcStride, Int resStride,  Int width, Int height
367                                          , Bool isLeftAvail,  Bool isRightAvail, Bool isAboveAvail, Bool isBelowAvail, Bool isAboveLeftAvail, Bool isAboveRightAvail, Bool isBelowLeftAvail, Bool isBelowRightAvail)
[56]368{
[872]369  if(m_lineBufWidth != m_maxCUWidth)
[56]370  {
[872]371    m_lineBufWidth = m_maxCUWidth;
372   
373    if (m_signLineBuf1) delete[] m_signLineBuf1; m_signLineBuf1 = NULL;
374    m_signLineBuf1 = new Char[m_lineBufWidth+1];
375   
376    if (m_signLineBuf2) delete[] m_signLineBuf2; m_signLineBuf2 = NULL;
377    m_signLineBuf2 = new Char[m_lineBufWidth+1];
[56]378  }
379
[872]380  Int* offsetClip = m_offsetClip[compIdx];
[56]381
[872]382  Int x,y, startX, startY, endX, endY, edgeType;
383  Int firstLineStartX, firstLineEndX, lastLineStartX, lastLineEndX;
384  Char signLeft, signRight, signDown;
[56]385
[872]386  Pel* srcLine = srcBlk;
387  Pel* resLine = resBlk;
[56]388
[872]389  switch(typeIdx)
[56]390  {
[872]391  case SAO_TYPE_EO_0:
[56]392    {
[872]393      offset += 2;
394      startX = isLeftAvail ? 0 : 1;
395      endX   = isRightAvail ? width : (width -1);
[56]396      for (y=0; y< height; y++)
397      {
[964]398#if SAO_SGN_FUNC
399        signLeft = (Char)sgn(srcLine[startX] - srcLine[startX-1]);
400#else
[872]401        signLeft = (Char)m_sign[srcLine[startX] - srcLine[startX-1]];
[964]402#endif
[56]403        for (x=startX; x< endX; x++)
404        {
[964]405#if SAO_SGN_FUNC
406          signRight = (Char)sgn(srcLine[x] - srcLine[x+1]); 
407#else
[872]408          signRight = (Char)m_sign[srcLine[x] - srcLine[x+1]]; 
[964]409#endif
[872]410          edgeType =  signRight + signLeft;
[56]411          signLeft  = -signRight;
412
[872]413          resLine[x] = offsetClip[srcLine[x] + offset[edgeType]];
[56]414        }
[872]415        srcLine  += srcStride;
416        resLine += resStride;
[56]417      }
[872]418
[56]419    }
[872]420    break;
421  case SAO_TYPE_EO_90:
[56]422    {
[872]423      offset += 2;
424      Char *signUpLine = m_signLineBuf1;
425
426      startY = isAboveAvail ? 0 : 1;
427      endY   = isBelowAvail ? height : height-1;
428      if (!isAboveAvail)
[56]429      {
[872]430        srcLine += srcStride;
431        resLine += resStride;
[56]432      }
[872]433
434      Pel* srcLineAbove= srcLine- srcStride;
[56]435      for (x=0; x< width; x++)
436      {
[964]437#if SAO_SGN_FUNC
438        signUpLine[x] = (Char)sgn(srcLine[x] - srcLineAbove[x]);
439#else
[872]440        signUpLine[x] = (Char)m_sign[srcLine[x] - srcLineAbove[x]];
[964]441#endif
[56]442      }
[872]443
444      Pel* srcLineBelow;
[56]445      for (y=startY; y<endY; y++)
446      {
[872]447        srcLineBelow= srcLine+ srcStride;
448
[56]449        for (x=0; x< width; x++)
450        {
[964]451#if SAO_SGN_FUNC
452          signDown  = (Char)sgn(srcLine[x] - srcLineBelow[x]);
453#else
[872]454          signDown  = (Char)m_sign[srcLine[x] - srcLineBelow[x]]; 
[964]455#endif
[872]456          edgeType = signDown + signUpLine[x];
457          signUpLine[x]= -signDown;
[56]458
[872]459          resLine[x] = offsetClip[srcLine[x] + offset[edgeType]];
[56]460        }
[872]461        srcLine += srcStride;
462        resLine += resStride;
[56]463      }
[872]464
[56]465    }
[872]466    break;
467  case SAO_TYPE_EO_135:
[56]468    {
[872]469      offset += 2;
470      Char *signUpLine, *signDownLine, *signTmpLine;
[56]471
[872]472      signUpLine  = m_signLineBuf1;
473      signDownLine= m_signLineBuf2;
[56]474
[872]475      startX = isLeftAvail ? 0 : 1 ;
476      endX   = isRightAvail ? width : (width-1);
477
478      //prepare 2nd line's upper sign
479      Pel* srcLineBelow= srcLine+ srcStride;
[56]480      for (x=startX; x< endX+1; x++)
481      {
[964]482#if SAO_SGN_FUNC
483        signUpLine[x] = (Char)sgn(srcLineBelow[x] - srcLine[x- 1]);
484#else
[872]485        signUpLine[x] = (Char)m_sign[srcLineBelow[x] - srcLine[x- 1]];
[964]486#endif
[56]487      }
488
489      //1st line
[872]490      Pel* srcLineAbove= srcLine- srcStride;
491      firstLineStartX = isAboveLeftAvail ? 0 : 1;
492      firstLineEndX   = isAboveAvail? endX: 1;
493      for(x= firstLineStartX; x< firstLineEndX; x++)
[56]494      {
[964]495#if SAO_SGN_FUNC
496        edgeType  =  sgn(srcLine[x] - srcLineAbove[x- 1]) - signUpLine[x+1];
497#else
[872]498        edgeType  =  m_sign[srcLine[x] - srcLineAbove[x- 1]] - signUpLine[x+1];
[964]499#endif
[872]500        resLine[x] = offsetClip[srcLine[x] + offset[edgeType]];
[56]501      }
[872]502      srcLine  += srcStride;
503      resLine  += resStride;
[56]504
505
506      //middle lines
507      for (y= 1; y< height-1; y++)
508      {
[872]509        srcLineBelow= srcLine+ srcStride;
510
[56]511        for (x=startX; x<endX; x++)
512        {
[964]513#if SAO_SGN_FUNC
514          signDown =  (Char)sgn(srcLine[x] - srcLineBelow[x+ 1]);
515#else
[872]516          signDown =  (Char)m_sign[srcLine[x] - srcLineBelow[x+ 1]] ;
[964]517#endif
[872]518          edgeType =  signDown + signUpLine[x];
519          resLine[x] = offsetClip[srcLine[x] + offset[edgeType]];
[56]520
[872]521          signDownLine[x+1] = -signDown; 
[56]522        }
[964]523#if SAO_SGN_FUNC
524        signDownLine[startX] = (Char)sgn(srcLineBelow[startX] - srcLine[startX-1]);
525#else
[872]526        signDownLine[startX] = (Char)m_sign[srcLineBelow[startX] - srcLine[startX-1]];
[964]527#endif
[56]528
[872]529        signTmpLine  = signUpLine;
530        signUpLine   = signDownLine;
531        signDownLine = signTmpLine;
[56]532
[872]533        srcLine += srcStride;
534        resLine += resStride;
[56]535      }
536
537      //last line
[872]538      srcLineBelow= srcLine+ srcStride;
539      lastLineStartX = isBelowAvail ? startX : (width -1);
540      lastLineEndX   = isBelowRightAvail ? width : (width -1);
541      for(x= lastLineStartX; x< lastLineEndX; x++)
[56]542      {
[964]543#if SAO_SGN_FUNC
544        edgeType =  sgn(srcLine[x] - srcLineBelow[x+ 1]) + signUpLine[x];
545#else
[872]546        edgeType =  m_sign[srcLine[x] - srcLineBelow[x+ 1]] + signUpLine[x];
[964]547#endif
[872]548        resLine[x] = offsetClip[srcLine[x] + offset[edgeType]];
549
[56]550      }
[872]551    }
552    break;
553  case SAO_TYPE_EO_45:
[56]554    {
[872]555      offset += 2;
556      Char *signUpLine = m_signLineBuf1+1;
[56]557
[872]558      startX = isLeftAvail ? 0 : 1;
559      endX   = isRightAvail ? width : (width -1);
560
[56]561      //prepare 2nd line upper sign
[872]562      Pel* srcLineBelow= srcLine+ srcStride;
[56]563      for (x=startX-1; x< endX; x++)
564      {
[964]565#if SAO_SGN_FUNC
566        signUpLine[x] = (Char)sgn(srcLineBelow[x] - srcLine[x+1]);
567#else
[872]568        signUpLine[x] = (Char)m_sign[srcLineBelow[x] - srcLine[x+1]];
[964]569#endif
[56]570      }
571
572
573      //first line
[872]574      Pel* srcLineAbove= srcLine- srcStride;
575      firstLineStartX = isAboveAvail ? startX : (width -1 );
576      firstLineEndX   = isAboveRightAvail ? width : (width-1);
577      for(x= firstLineStartX; x< firstLineEndX; x++)
[56]578      {
[964]579#if SAO_SGN_FUNC
580        edgeType = sgn(srcLine[x] - srcLineAbove[x+1]) -signUpLine[x-1];
581#else
[872]582        edgeType = m_sign[srcLine[x] - srcLineAbove[x+1]] -signUpLine[x-1];
[964]583#endif
[872]584        resLine[x] = offsetClip[srcLine[x] + offset[edgeType]];
[56]585      }
[872]586      srcLine += srcStride;
587      resLine += resStride;
[56]588
589      //middle lines
590      for (y= 1; y< height-1; y++)
591      {
[872]592        srcLineBelow= srcLine+ srcStride;
593
[56]594        for(x= startX; x< endX; x++)
595        {
[964]596#if SAO_SGN_FUNC
597          signDown =  (Char)sgn(srcLine[x] - srcLineBelow[x-1]);
598#else
[872]599          signDown =  (Char)m_sign[srcLine[x] - srcLineBelow[x-1]] ;
[964]600#endif
[872]601          edgeType =  signDown + signUpLine[x];
602          resLine[x] = offsetClip[srcLine[x] + offset[edgeType]];
603          signUpLine[x-1] = -signDown; 
[56]604        }
[964]605#if SAO_SGN_FUNC
606        signUpLine[endX-1] = (Char)sgn(srcLineBelow[endX-1] - srcLine[endX]);
607#else
[872]608        signUpLine[endX-1] = (Char)m_sign[srcLineBelow[endX-1] - srcLine[endX]];
[964]609#endif
[872]610        srcLine  += srcStride;
611        resLine += resStride;
[56]612      }
613
614      //last line
[872]615      srcLineBelow= srcLine+ srcStride;
616      lastLineStartX = isBelowLeftAvail ? 0 : 1;
617      lastLineEndX   = isBelowAvail ? endX : 1;
618      for(x= lastLineStartX; x< lastLineEndX; x++)
[56]619      {
[964]620#if SAO_SGN_FUNC
621        edgeType = sgn(srcLine[x] - srcLineBelow[x-1]) + signUpLine[x];
622#else
[872]623        edgeType = m_sign[srcLine[x] - srcLineBelow[x-1]] + signUpLine[x];
[964]624#endif
[872]625        resLine[x] = offsetClip[srcLine[x] + offset[edgeType]];
[56]626
627      }
[872]628    }
629    break;
630  case SAO_TYPE_BO:
[56]631    {
[872]632      Int shiftBits = ((compIdx == SAO_Y)?g_bitDepthY:g_bitDepthC)- NUM_SAO_BO_CLASSES_LOG2;
[56]633      for (y=0; y< height; y++)
634      {
635        for (x=0; x< width; x++)
636        {
[872]637          resLine[x] = offsetClip[ srcLine[x] + offset[srcLine[x] >> shiftBits] ];
[56]638        }
[872]639        srcLine += srcStride;
640        resLine += resStride;
[56]641      }
642    }
[872]643    break;
644  default:
645    {
646      printf("Not a supported SAO types\n");
647      assert(0);
648      exit(-1);
649    }
[56]650  }
651
[872]652
[56]653}
654
[872]655Void TComSampleAdaptiveOffset::offsetCTU(Int ctu, TComPicYuv* srcYuv, TComPicYuv* resYuv, SAOBlkParam& saoblkParam, TComPic* pPic)
[56]656{
[872]657  Bool isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail;
[56]658
[872]659  if( 
660    (saoblkParam[SAO_Y ].modeIdc == SAO_MODE_OFF) &&
661    (saoblkParam[SAO_Cb].modeIdc == SAO_MODE_OFF) &&
662    (saoblkParam[SAO_Cr].modeIdc == SAO_MODE_OFF)
663    )
[56]664  {
665    return;
666  }
667
[872]668  //block boundary availability
669  pPic->getPicSym()->deriveLoopFilterBoundaryAvailibility(ctu, isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail);
[56]670
[872]671  Int yPos   = (ctu / m_numCTUInWidth)*m_maxCUHeight;
672  Int xPos   = (ctu % m_numCTUInWidth)*m_maxCUWidth;
673  Int height = (yPos + m_maxCUHeight > m_picHeight)?(m_picHeight- yPos):m_maxCUHeight;
674  Int width  = (xPos + m_maxCUWidth  > m_picWidth )?(m_picWidth - xPos):m_maxCUWidth;
[56]675
[872]676  for(Int compIdx= 0; compIdx < NUM_SAO_COMPONENTS; compIdx++)
[56]677  {
[872]678    SAOOffset& ctbOffset = saoblkParam[compIdx];
[56]679
[872]680    if(ctbOffset.modeIdc != SAO_MODE_OFF)
[56]681    {
[872]682      Bool isLuma     = (compIdx == SAO_Y);
683      Int  formatShift= isLuma?0:1;
[608]684
[872]685      Int  blkWidth   = (width  >> formatShift);
686      Int  blkHeight  = (height >> formatShift);
687      Int  blkYPos    = (yPos   >> formatShift);
688      Int  blkXPos    = (xPos   >> formatShift);
[56]689
[872]690      Int  srcStride = isLuma?srcYuv->getStride():srcYuv->getCStride();
691      Pel* srcBlk    = getPicBuf(srcYuv, compIdx)+ (yPos >> formatShift)*srcStride+ (xPos >> formatShift);
[56]692
[872]693      Int  resStride  = isLuma?resYuv->getStride():resYuv->getCStride();
694      Pel* resBlk     = getPicBuf(resYuv, compIdx)+ blkYPos*resStride+ blkXPos;
[56]695
[872]696      offsetBlock( compIdx, ctbOffset.typeIdc, ctbOffset.offset
697                  , srcBlk, resBlk, srcStride, resStride, blkWidth, blkHeight
698                  , isLeftAvail, isRightAvail
699                  , isAboveAvail, isBelowAvail
700                  , isAboveLeftAvail, isAboveRightAvail
701                  , isBelowLeftAvail, isBelowRightAvail
702                  );
703    }
704  } //compIdx
[56]705
[872]706}
[56]707
708
[872]709Void TComSampleAdaptiveOffset::SAOProcess(TComPic* pDecPic)
710{
711  if(!m_picSAOEnabled[SAO_Y] && !m_picSAOEnabled[SAO_Cb] && !m_picSAOEnabled[SAO_Cr])
712  {
713    return;
[56]714  }
[872]715  TComPicYuv* resYuv = pDecPic->getPicYuvRec();
716  TComPicYuv* srcYuv = m_tempPicYuv;
717  resYuv->copyToPic(srcYuv);
718  for(Int ctu= 0; ctu < m_numCTUsPic; ctu++)
[56]719  {
[872]720    offsetCTU(ctu, srcYuv, resYuv, (pDecPic->getPicSym()->getSAOBlkParam())[ctu], pDecPic);
721  } //ctu
[56]722}
[872]723
724
725Pel* TComSampleAdaptiveOffset::getPicBuf(TComPicYuv* pPicYuv, Int compIdx)
[56]726{
[872]727  Pel* pBuf = NULL;
728  switch(compIdx)
[56]729  {
[872]730  case SAO_Y:
[56]731    {
[872]732      pBuf = pPicYuv->getLumaAddr();
[56]733    }
[872]734    break;
735  case SAO_Cb:
[56]736    {
[872]737      pBuf = pPicYuv->getCbAddr();
[56]738    }
[872]739    break;
740  case SAO_Cr:
[443]741    {
[872]742      pBuf = pPicYuv->getCrAddr();
[443]743    }
[56]744    break;
745  default:
746    {
[872]747      printf("Not a legal component ID for SAO\n");
748      assert(0);
749      exit(-1);
[56]750    }
751  }
752
[872]753  return pBuf;
[56]754}
755
[872]756/** PCM LF disable process.
[443]757 * \param pcPic picture (TComPic) pointer
758 * \returns Void
759 *
760 * \note Replace filtered sample values of PCM mode blocks with the transmitted and reconstructed ones.
761 */
762Void TComSampleAdaptiveOffset::PCMLFDisableProcess (TComPic* pcPic)
763{
764  xPCMRestoration(pcPic);
765}
766
767/** Picture-level PCM restoration.
768 * \param pcPic picture (TComPic) pointer
769 * \returns Void
770 */
771Void TComSampleAdaptiveOffset::xPCMRestoration(TComPic* pcPic)
772{
773  Bool  bPCMFilter = (pcPic->getSlice(0)->getSPS()->getUsePCM() && pcPic->getSlice(0)->getSPS()->getPCMFilterDisableFlag())? true : false;
[608]774
775  if(bPCMFilter || pcPic->getSlice(0)->getPPS()->getTransquantBypassEnableFlag())
[443]776  {
[608]777    for( UInt uiCUAddr = 0; uiCUAddr < pcPic->getNumCUsInFrame() ; uiCUAddr++ )
778    {
779      TComDataCU* pcCU = pcPic->getCU(uiCUAddr);
780
781      xPCMCURestoration(pcCU, 0, 0); 
782    } 
[443]783  }
784}
785
786/** PCM CU restoration.
787 * \param pcCU pointer to current CU
788 * \param uiAbsPartIdx part index
789 * \param uiDepth CU depth
790 * \returns Void
791 */
792Void TComSampleAdaptiveOffset::xPCMCURestoration ( TComDataCU* pcCU, UInt uiAbsZorderIdx, UInt uiDepth )
793{
794  TComPic* pcPic     = pcCU->getPic();
795  UInt uiCurNumParts = pcPic->getNumPartInCU() >> (uiDepth<<1);
796  UInt uiQNumParts   = uiCurNumParts>>2;
797
798  // go to sub-CU
799  if( pcCU->getDepth(uiAbsZorderIdx) > uiDepth )
800  {
801    for ( UInt uiPartIdx = 0; uiPartIdx < 4; uiPartIdx++, uiAbsZorderIdx+=uiQNumParts )
802    {
803      UInt uiLPelX   = pcCU->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsZorderIdx] ];
804      UInt uiTPelY   = pcCU->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsZorderIdx] ];
805      if( ( uiLPelX < pcCU->getSlice()->getSPS()->getPicWidthInLumaSamples() ) && ( uiTPelY < pcCU->getSlice()->getSPS()->getPicHeightInLumaSamples() ) )
806        xPCMCURestoration( pcCU, uiAbsZorderIdx, uiDepth+1 );
807    }
808    return;
809  }
810
811  // restore PCM samples
812  if ((pcCU->getIPCMFlag(uiAbsZorderIdx)&& pcPic->getSlice(0)->getSPS()->getPCMFilterDisableFlag()) || pcCU->isLosslessCoded( uiAbsZorderIdx))
813  {
814    xPCMSampleRestoration (pcCU, uiAbsZorderIdx, uiDepth, TEXT_LUMA    );
815    xPCMSampleRestoration (pcCU, uiAbsZorderIdx, uiDepth, TEXT_CHROMA_U);
816    xPCMSampleRestoration (pcCU, uiAbsZorderIdx, uiDepth, TEXT_CHROMA_V);
817  }
818}
819
820/** PCM sample restoration.
821 * \param pcCU pointer to current CU
822 * \param uiAbsPartIdx part index
823 * \param uiDepth CU depth
824 * \param ttText texture component type
825 * \returns Void
826 */
827Void TComSampleAdaptiveOffset::xPCMSampleRestoration (TComDataCU* pcCU, UInt uiAbsZorderIdx, UInt uiDepth, TextType ttText)
828{
829  TComPicYuv* pcPicYuvRec = pcCU->getPic()->getPicYuvRec();
830  Pel* piSrc;
831  Pel* piPcm;
832  UInt uiStride;
833  UInt uiWidth;
834  UInt uiHeight;
835  UInt uiPcmLeftShiftBit; 
836  UInt uiX, uiY;
837  UInt uiMinCoeffSize = pcCU->getPic()->getMinCUWidth()*pcCU->getPic()->getMinCUHeight();
838  UInt uiLumaOffset   = uiMinCoeffSize*uiAbsZorderIdx;
839  UInt uiChromaOffset = uiLumaOffset>>2;
840
841  if( ttText == TEXT_LUMA )
842  {
843    piSrc = pcPicYuvRec->getLumaAddr( pcCU->getAddr(), uiAbsZorderIdx);
844    piPcm = pcCU->getPCMSampleY() + uiLumaOffset;
845    uiStride  = pcPicYuvRec->getStride();
846    uiWidth  = (g_uiMaxCUWidth >> uiDepth);
847    uiHeight = (g_uiMaxCUHeight >> uiDepth);
[608]848    if ( pcCU->isLosslessCoded(uiAbsZorderIdx) && !pcCU->getIPCMFlag(uiAbsZorderIdx) )
[443]849    {
850      uiPcmLeftShiftBit = 0;
851    }
852    else
853    {
[608]854      uiPcmLeftShiftBit = g_bitDepthY - pcCU->getSlice()->getSPS()->getPCMBitDepthLuma();
[443]855    }
856  }
857  else
858  {
859    if( ttText == TEXT_CHROMA_U )
860    {
861      piSrc = pcPicYuvRec->getCbAddr( pcCU->getAddr(), uiAbsZorderIdx );
862      piPcm = pcCU->getPCMSampleCb() + uiChromaOffset;
863    }
864    else
865    {
866      piSrc = pcPicYuvRec->getCrAddr( pcCU->getAddr(), uiAbsZorderIdx );
867      piPcm = pcCU->getPCMSampleCr() + uiChromaOffset;
868    }
869
870    uiStride = pcPicYuvRec->getCStride();
871    uiWidth  = ((g_uiMaxCUWidth >> uiDepth)/2);
872    uiHeight = ((g_uiMaxCUWidth >> uiDepth)/2);
[608]873    if ( pcCU->isLosslessCoded(uiAbsZorderIdx) && !pcCU->getIPCMFlag(uiAbsZorderIdx) )
[443]874    {
875      uiPcmLeftShiftBit = 0;
876    }
877    else
878    {
[608]879      uiPcmLeftShiftBit = g_bitDepthC - pcCU->getSlice()->getSPS()->getPCMBitDepthChroma();
[443]880    }
881  }
882
883  for( uiY = 0; uiY < uiHeight; uiY++ )
884  {
885    for( uiX = 0; uiX < uiWidth; uiX++ )
886    {
887      piSrc[uiX] = (piPcm[uiX] << uiPcmLeftShiftBit);
888    }
889    piPcm += uiWidth;
890    piSrc += uiStride;
891  }
892}
[608]893
[56]894//! \}
Note: See TracBrowser for help on using the repository browser.