source: 3DVCSoftware/branches/HTM-3.0-LG/source/Lib/TLibCommon/TComSampleAdaptiveOffset.cpp @ 605

Last change on this file since 605 was 56, checked in by hschwarz, 13 years ago

updated trunk (move to HM6.1)

File size: 48.4 KB
Line 
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-2012, ITU/ISO/IEC
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 *  * Redistributions of source code must retain the above copyright notice,
13 *    this list of conditions and the following disclaimer.
14 *  * Redistributions in binary form must reproduce the above copyright notice,
15 *    this list of conditions and the following disclaimer in the documentation
16 *    and/or other materials provided with the distribution.
17 *  * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
18 *    be used to endorse or promote products derived from this software without
19 *    specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31 * THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34/** \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//! \{
46
47SAOParam::~SAOParam()
48{
49  for (Int i = 0 ; i<3; i++)
50  {
51    if (psSaoPart[i])
52    {
53      delete [] psSaoPart[i];
54    }
55  }
56}
57
58// ====================================================================================================================
59// Tables
60// ====================================================================================================================
61
62TComSampleAdaptiveOffset::TComSampleAdaptiveOffset()
63{
64  m_pcPic = NULL;
65  m_iOffsetBo = NULL;
66  m_pClipTable = NULL;
67  m_pClipTableBase = NULL;
68#if SAO_UNIT_INTERLEAVING
69  m_lumaTableBo = NULL;
70#else
71  m_ppLumaTableBo0 = NULL;
72  m_ppLumaTableBo1 = NULL;
73#endif
74  m_iUpBuff1 = NULL;
75  m_iUpBuff2 = NULL;
76  m_iUpBufft = NULL;
77  ipSwap = NULL;
78  m_pcYuvTmp = NULL;
79
80  m_pTmpU1 = NULL;
81  m_pTmpU2 = NULL;
82  m_pTmpL1 = NULL;
83  m_pTmpL2 = NULL;
84  m_iLcuPartIdx = NULL;
85}
86
87TComSampleAdaptiveOffset::~TComSampleAdaptiveOffset()
88{
89
90}
91
92const Int TComSampleAdaptiveOffset::m_aiNumPartsInRow[5] =
93{
94  1,   //level 0
95  2,   //level 1
96  4,   //level 2
97  8,   //level 3
98  16   //level 4
99};
100
101const Int TComSampleAdaptiveOffset::m_aiNumPartsLevel[5] =
102{
103  1,   //level 0
104  4,   //level 1
105  16,  //level 2
106  64,  //level 3
107  256  //level 4
108};
109
110const Int TComSampleAdaptiveOffset::m_aiNumCulPartsLevel[5] =
111{
112  1,   //level 0
113  5,   //level 1
114  21,  //level 2
115  85,  //level 3
116  341, //level 4
117};
118
119const UInt TComSampleAdaptiveOffset::m_auiEoTable[9] =
120{
121  1, //0   
122  2, //1   
123  0, //2
124  3, //3
125  4, //4
126  0, //5 
127  0, //6 
128  0, //7
129  0
130};
131
132const UInt TComSampleAdaptiveOffset::m_iWeightSao[MAX_NUM_SAO_TYPE] =
133{
134  2,
135  2,
136  2,
137  2,
138#if !SAO_UNIT_INTERLEAVING
139  1,
140#endif
141  1
142};
143
144const UInt TComSampleAdaptiveOffset::m_auiEoTable2D[9] =
145{
146  1, //0   
147  2, //1   
148  3, //2
149  0, //3
150  0, //4
151  0, //5 
152  4, //6 
153  5, //7
154  6
155};
156
157Int TComSampleAdaptiveOffset::m_iNumClass[MAX_NUM_SAO_TYPE] =
158{
159  SAO_EO_LEN,
160  SAO_EO_LEN,
161  SAO_EO_LEN,
162  SAO_EO_LEN,
163#if !SAO_UNIT_INTERLEAVING
164  SAO_BO_LEN,
165#endif
166  SAO_BO_LEN
167};
168
169UInt TComSampleAdaptiveOffset::m_uiMaxDepth = SAO_MAX_DEPTH;
170
171
172/** convert Level Row Col to Idx
173 * \param   level,  row,  col
174 */
175Int  TComSampleAdaptiveOffset::convertLevelRowCol2Idx(int level, int row, int col)
176{
177  Int idx;
178  if (level == 0)
179  {
180    idx = 0;
181  }
182  else if (level == 1)
183  {
184    idx = 1 + row*2 + col;
185  }
186  else if (level == 2)
187  {
188    idx = 5 + row*4 + col;
189  }
190  else if (level == 3)
191  {
192    idx = 21 + row*8 + col;
193  }
194  else // (level == 4)
195  {
196    idx = 85 + row*16 + col;
197  }
198  return idx;
199}
200/** convert quadtree Idx to Level, Row, and Col
201 * \param  idx,  *level,  *row,  *col
202 */
203void TComSampleAdaptiveOffset::convertIdx2LevelRowCol(int idx, int *level, int *row, int *col)
204{
205  if (idx == 0)
206  {
207    *level = 0;
208    *row = 0;
209    *col = 0;
210  }
211  else if (idx>=1 && idx<=4)
212  {
213    *level = 1;
214    *row = (idx-1) / 2;
215    *col = (idx-1) % 2;
216  }
217  else if (idx>=5 && idx<=20)
218  {
219    *level = 2;
220    *row = (idx-5) / 4;
221    *col = (idx-5) % 4;
222  }
223  else if (idx>=21 && idx<=84)
224  {
225    *level = 3;
226    *row = (idx-21) / 8;
227    *col = (idx-21) % 8;
228  }
229  else // (idx>=85 && idx<=340)
230  {
231    *level = 4;
232    *row = (idx-85) / 16;
233    *col = (idx-85) % 16;
234  }
235}
236/** create SampleAdaptiveOffset memory.
237 * \param
238 */
239Void TComSampleAdaptiveOffset::create( UInt uiSourceWidth, UInt uiSourceHeight, UInt uiMaxCUWidth, UInt uiMaxCUHeight, UInt uiMaxCUDepth)
240{
241  m_iPicWidth  = uiSourceWidth;
242  m_iPicHeight = uiSourceHeight;
243
244  m_uiMaxCUWidth  = uiMaxCUWidth;
245  m_uiMaxCUHeight = uiMaxCUHeight;
246
247  m_iNumCuInWidth  = m_iPicWidth / m_uiMaxCUWidth;
248  m_iNumCuInWidth += ( m_iPicWidth % m_uiMaxCUWidth ) ? 1 : 0;
249
250  m_iNumCuInHeight  = m_iPicHeight / m_uiMaxCUHeight;
251  m_iNumCuInHeight += ( m_iPicHeight % m_uiMaxCUHeight ) ? 1 : 0;
252
253  Int iMaxSplitLevelHeight = (Int)(logf((float)m_iNumCuInHeight)/logf(2.0));
254  Int iMaxSplitLevelWidth  = (Int)(logf((float)m_iNumCuInWidth )/logf(2.0));
255
256  m_uiMaxSplitLevel = (iMaxSplitLevelHeight < iMaxSplitLevelWidth)?(iMaxSplitLevelHeight):(iMaxSplitLevelWidth);
257  m_uiMaxSplitLevel = (m_uiMaxSplitLevel< m_uiMaxDepth)?(m_uiMaxSplitLevel):(m_uiMaxDepth);
258  /* various structures are overloaded to store per component data.
259   * m_iNumTotalParts must allow for sufficient storage in any allocated arrays */
260  m_iNumTotalParts  = max(3,m_aiNumCulPartsLevel[m_uiMaxSplitLevel]);
261#if !SAO_UNIT_INTERLEAVING
262  UInt auiTable[2][LUMA_GROUP_NUM] = 
263  {{0, 0, 0, 0, 0, 0, 0, 0,
264  1, 2, 3, 4, 5, 6, 7, 8,
265  9,10,11,12,13,14,15,16,
266  0, 0, 0, 0, 0, 0, 0, 0},
267
268  {1, 2, 3, 4, 5, 6, 7, 8,
269  0, 0, 0, 0, 0, 0, 0, 0,
270  0, 0, 0, 0, 0, 0, 0, 0,
271  9,10,11,12,13,14,15,16}};
272#endif
273
274  UInt uiInternalBitDepth = g_uiBitDepth+g_uiBitIncrement;
275  UInt uiPixelRange = 1<<uiInternalBitDepth;
276  UInt uiBoRangeShift = uiInternalBitDepth - SAO_BO_BITS;
277
278#if SAO_UNIT_INTERLEAVING
279  m_lumaTableBo = new Pel [uiPixelRange];
280  for (Int k2=0; k2<uiPixelRange; k2++)
281  {
282    m_lumaTableBo[k2] = 1 + (k2>>uiBoRangeShift);
283  }
284#else
285  m_ppLumaTableBo0 = new Pel [uiPixelRange];
286  m_ppLumaTableBo1 = new Pel [uiPixelRange];
287  for (Int k2=0; k2<uiPixelRange; k2++)
288  {
289    m_ppLumaTableBo0[k2] = auiTable[0][k2>>uiBoRangeShift];
290    m_ppLumaTableBo1[k2] = auiTable[1][k2>>uiBoRangeShift];
291  }
292#endif
293  m_iUpBuff1 = new Int[m_iPicWidth+2];
294  m_iUpBuff2 = new Int[m_iPicWidth+2];
295  m_iUpBufft = new Int[m_iPicWidth+2];
296
297  m_iUpBuff1++;
298  m_iUpBuff2++;
299  m_iUpBufft++;
300  Pel i;
301
302  UInt uiMaxY  = g_uiIBDI_MAX;
303  UInt uiMinY  = 0;
304
305  Int iCRangeExt = uiMaxY>>1;
306
307  m_pClipTableBase = new Pel[uiMaxY+2*iCRangeExt];
308  m_iOffsetBo      = new Int[uiMaxY+2*iCRangeExt];
309
310  for(i=0;i<(uiMinY+iCRangeExt);i++)
311  {
312    m_pClipTableBase[i] = uiMinY;
313  }
314
315  for(i=uiMinY+iCRangeExt;i<(uiMaxY+  iCRangeExt);i++)
316  {
317    m_pClipTableBase[i] = i-iCRangeExt;
318  }
319
320  for(i=uiMaxY+iCRangeExt;i<(uiMaxY+2*iCRangeExt);i++)
321  {
322    m_pClipTableBase[i] = uiMaxY;
323  }
324
325  m_pClipTable = &(m_pClipTableBase[iCRangeExt]);
326
327  m_iLcuPartIdx = new Int [m_iNumCuInHeight*m_iNumCuInWidth];
328  m_pTmpL1 = new Pel [m_uiMaxCUHeight+1];
329  m_pTmpL2 = new Pel [m_uiMaxCUHeight+1];
330  m_pTmpU1 = new Pel [m_iPicWidth];
331  m_pTmpU2 = new Pel [m_iPicWidth];
332}
333
334/** destroy SampleAdaptiveOffset memory.
335 * \param
336 */
337Void TComSampleAdaptiveOffset::destroy()
338{
339  if (m_pClipTableBase)
340  {
341    delete [] m_pClipTableBase; m_pClipTableBase = NULL;
342  }
343  if (m_iOffsetBo)
344  {
345    delete [] m_iOffsetBo; m_iOffsetBo = NULL;
346  }
347#if SAO_UNIT_INTERLEAVING
348  if (m_lumaTableBo)
349  {
350    delete[] m_lumaTableBo; m_lumaTableBo = NULL;
351  }
352#else
353  if (m_ppLumaTableBo0)
354  {
355    delete[] m_ppLumaTableBo0; m_ppLumaTableBo0 = NULL;
356  }
357  if (m_ppLumaTableBo1)
358  {
359    delete[] m_ppLumaTableBo1; m_ppLumaTableBo1 = NULL;
360  }
361#endif
362
363
364  m_iUpBuff1--;
365  m_iUpBuff2--;
366  m_iUpBufft--;
367
368  if (m_iUpBuff1)
369  {
370    delete [] m_iUpBuff1; m_iUpBuff1 = NULL;
371  }
372  if (m_iUpBuff2)
373  {
374    delete [] m_iUpBuff2; m_iUpBuff2 = NULL;
375  }
376  if (m_iUpBufft)
377  {
378    delete [] m_iUpBufft; m_iUpBufft = NULL;
379  }
380  if (m_pTmpL1)
381  {
382    delete [] m_pTmpL1; m_pTmpL1 = NULL;
383  }
384  if (m_pTmpL2)
385  {
386    delete [] m_pTmpL2; m_pTmpL2 = NULL;
387  }
388  if (m_pTmpU1)
389  {
390    delete [] m_pTmpU1; m_pTmpU1 = NULL;
391  }
392  if (m_pTmpU2)
393  {
394    delete [] m_pTmpU2; m_pTmpU2 = NULL;
395  }
396  if(m_iLcuPartIdx)
397  {
398    delete []m_iLcuPartIdx; m_iLcuPartIdx = NULL;
399  }
400}
401
402/** allocate memory for SAO parameters
403 * \param    *pcSaoParam
404 */
405Void TComSampleAdaptiveOffset::allocSaoParam(SAOParam *pcSaoParam)
406{
407  pcSaoParam->iMaxSplitLevel = m_uiMaxSplitLevel;
408  pcSaoParam->psSaoPart[0] = new SAOQTPart[ m_aiNumCulPartsLevel[pcSaoParam->iMaxSplitLevel] ];
409  initSAOParam(pcSaoParam, 0, 0, 0, -1, 0, m_iNumCuInWidth-1,  0, m_iNumCuInHeight-1,0);
410  pcSaoParam->psSaoPart[1] = new SAOQTPart[ m_aiNumCulPartsLevel[pcSaoParam->iMaxSplitLevel] ];
411  pcSaoParam->psSaoPart[2] = new SAOQTPart[ m_aiNumCulPartsLevel[pcSaoParam->iMaxSplitLevel] ];
412  initSAOParam(pcSaoParam, 0, 0, 0, -1, 0, m_iNumCuInWidth-1,  0, m_iNumCuInHeight-1,1);
413  initSAOParam(pcSaoParam, 0, 0, 0, -1, 0, m_iNumCuInWidth-1,  0, m_iNumCuInHeight-1,2);
414  for(Int j=0;j<MAX_NUM_SAO_TYPE;j++)
415  {
416    pcSaoParam->iNumClass[j] = m_iNumClass[j];
417  }
418#if SAO_UNIT_INTERLEAVING
419  pcSaoParam->numCuInWidth  = m_iNumCuInWidth;
420  pcSaoParam->numCuInHeight = m_iNumCuInHeight;
421  pcSaoParam->saoLcuParam[0] = new SaoLcuParam [m_iNumCuInHeight*m_iNumCuInWidth];
422  pcSaoParam->saoLcuParam[1] = new SaoLcuParam [m_iNumCuInHeight*m_iNumCuInWidth];
423  pcSaoParam->saoLcuParam[2] = new SaoLcuParam [m_iNumCuInHeight*m_iNumCuInWidth];
424#endif
425}
426
427/** initialize SAO parameters
428 * \param    *pcSaoParam,  iPartLevel,  iPartRow,  iPartCol,  iParentPartIdx,  StartCUX,  EndCUX,  StartCUY,  EndCUY,  iYCbCr
429 */
430Void TComSampleAdaptiveOffset::initSAOParam(SAOParam *pcSaoParam, Int iPartLevel, Int iPartRow, Int iPartCol, Int iParentPartIdx, Int StartCUX, Int EndCUX, Int StartCUY, Int EndCUY, Int iYCbCr)
431{
432  Int j;
433  Int iPartIdx = convertLevelRowCol2Idx(iPartLevel, iPartRow, iPartCol);
434
435  SAOQTPart* pSaoPart;
436
437  pSaoPart = &(pcSaoParam->psSaoPart[iYCbCr][iPartIdx]);
438
439  pSaoPart->PartIdx   = iPartIdx;
440  pSaoPart->PartLevel = iPartLevel;
441  pSaoPart->PartRow   = iPartRow;
442  pSaoPart->PartCol   = iPartCol;
443
444  pSaoPart->StartCUX  = StartCUX;
445  pSaoPart->EndCUX    = EndCUX;
446  pSaoPart->StartCUY  = StartCUY;
447  pSaoPart->EndCUY    = EndCUY;
448
449  pSaoPart->UpPartIdx = iParentPartIdx;
450#if !SAO_UNIT_INTERLEAVING
451  pSaoPart->bEnableFlag =  0;
452#endif
453  pSaoPart->iBestType   = -1;
454  pSaoPart->iLength     =  0;
455
456#if SAO_UNIT_INTERLEAVING
457  pSaoPart->bandPosition = 0;
458
459  for (j=0;j<MAX_NUM_SAO_OFFSETS;j++)
460#else
461  for (j=0;j<MAX_NUM_SAO_CLASS;j++)
462#endif
463  {
464    pSaoPart->iOffset[j] = 0;
465  }
466
467  if(pSaoPart->PartLevel != m_uiMaxSplitLevel)
468  {
469    Int DownLevel    = (iPartLevel+1 );
470    Int DownRowStart = (iPartRow << 1);
471    Int DownColStart = (iPartCol << 1);
472
473    Int iDownRowIdx, iDownColIdx;
474    Int NumCUWidth,  NumCUHeight;
475    Int NumCULeft;
476    Int NumCUTop;
477
478    Int DownStartCUX, DownStartCUY;
479    Int DownEndCUX, DownEndCUY;
480
481    NumCUWidth  = EndCUX - StartCUX +1;
482    NumCUHeight = EndCUY - StartCUY +1;
483    NumCULeft   = (NumCUWidth  >> 1);
484    NumCUTop    = (NumCUHeight >> 1);
485
486    DownStartCUX= StartCUX;
487    DownEndCUX  = DownStartCUX + NumCULeft - 1;
488    DownStartCUY= StartCUY;
489    DownEndCUY  = DownStartCUY + NumCUTop  - 1;
490    iDownRowIdx = DownRowStart + 0;
491    iDownColIdx = DownColStart + 0;
492
493    pSaoPart->DownPartsIdx[0]= convertLevelRowCol2Idx(DownLevel, iDownRowIdx, iDownColIdx);
494
495    initSAOParam(pcSaoParam, DownLevel, iDownRowIdx, iDownColIdx, iPartIdx, DownStartCUX, DownEndCUX, DownStartCUY, DownEndCUY, iYCbCr);
496
497    DownStartCUX = StartCUX + NumCULeft;
498    DownEndCUX   = EndCUX;
499    DownStartCUY = StartCUY;
500    DownEndCUY   = DownStartCUY + NumCUTop -1;
501    iDownRowIdx  = DownRowStart + 0;
502    iDownColIdx  = DownColStart + 1;
503
504    pSaoPart->DownPartsIdx[1] = convertLevelRowCol2Idx(DownLevel, iDownRowIdx, iDownColIdx);
505
506    initSAOParam(pcSaoParam, DownLevel, iDownRowIdx, iDownColIdx, iPartIdx,  DownStartCUX, DownEndCUX, DownStartCUY, DownEndCUY, iYCbCr);
507
508    DownStartCUX = StartCUX;
509    DownEndCUX   = DownStartCUX + NumCULeft -1;
510    DownStartCUY = StartCUY + NumCUTop;
511    DownEndCUY   = EndCUY;
512    iDownRowIdx  = DownRowStart + 1;
513    iDownColIdx  = DownColStart + 0;
514
515    pSaoPart->DownPartsIdx[2] = convertLevelRowCol2Idx(DownLevel, iDownRowIdx, iDownColIdx);
516
517    initSAOParam(pcSaoParam, DownLevel, iDownRowIdx, iDownColIdx, iPartIdx, DownStartCUX, DownEndCUX, DownStartCUY, DownEndCUY, iYCbCr);
518
519    DownStartCUX = StartCUX+ NumCULeft;
520    DownEndCUX   = EndCUX;
521    DownStartCUY = StartCUY + NumCUTop;
522    DownEndCUY   = EndCUY;
523    iDownRowIdx  = DownRowStart + 1;
524    iDownColIdx  = DownColStart + 1;
525
526    pSaoPart->DownPartsIdx[3] = convertLevelRowCol2Idx(DownLevel, iDownRowIdx, iDownColIdx);
527
528    initSAOParam(pcSaoParam, DownLevel, iDownRowIdx, iDownColIdx, iPartIdx,DownStartCUX, DownEndCUX, DownStartCUY, DownEndCUY, iYCbCr);
529  }
530  else
531  {
532    pSaoPart->DownPartsIdx[0]=pSaoPart->DownPartsIdx[1]= pSaoPart->DownPartsIdx[2]= pSaoPart->DownPartsIdx[3]= -1; 
533  }
534}
535
536/** free memory of SAO parameters
537 * \param   pcSaoParam
538 */
539Void TComSampleAdaptiveOffset::freeSaoParam(SAOParam *pcSaoParam)
540{
541  delete [] pcSaoParam->psSaoPart[0];
542  delete [] pcSaoParam->psSaoPart[1];
543  delete [] pcSaoParam->psSaoPart[2];
544  pcSaoParam->psSaoPart[0] = 0;
545  pcSaoParam->psSaoPart[1] = 0;
546  pcSaoParam->psSaoPart[2] = 0;
547#if SAO_UNIT_INTERLEAVING
548  if( pcSaoParam->saoLcuParam[0]) 
549  {
550    delete [] pcSaoParam->saoLcuParam[0]; pcSaoParam->saoLcuParam[0] = NULL;
551  }
552  if( pcSaoParam->saoLcuParam[1]) 
553  {
554    delete [] pcSaoParam->saoLcuParam[1]; pcSaoParam->saoLcuParam[1] = NULL;
555  }
556  if( pcSaoParam->saoLcuParam[2]) 
557  {
558    delete [] pcSaoParam->saoLcuParam[2]; pcSaoParam->saoLcuParam[2] = NULL;
559  }
560#endif
561} 
562
563/** reset SAO parameters
564 * \param   pcSaoParam
565 */
566Void TComSampleAdaptiveOffset::resetSAOParam(SAOParam *pcSaoParam)
567{
568  Int iNumComponet = 3;
569  for(Int c=0; c<iNumComponet; c++)
570  {
571    pcSaoParam->bSaoFlag[c] = 0;
572    for(Int i=0; i< m_aiNumCulPartsLevel[m_uiMaxSplitLevel]; i++)
573    {
574#if !SAO_UNIT_INTERLEAVING
575      pcSaoParam->psSaoPart[c][i].bEnableFlag   =  0;
576#endif
577      pcSaoParam->psSaoPart[c][i].iBestType     = -1;
578      pcSaoParam->psSaoPart[c][i].iLength       =  0;
579      pcSaoParam->psSaoPart[c][i].bSplit        = false; 
580      pcSaoParam->psSaoPart[c][i].bProcessed    = false;
581      pcSaoParam->psSaoPart[c][i].dMinCost      = MAX_DOUBLE;
582      pcSaoParam->psSaoPart[c][i].iMinDist      = MAX_INT;
583      pcSaoParam->psSaoPart[c][i].iMinRate      = MAX_INT;
584#if SAO_UNIT_INTERLEAVING
585      pcSaoParam->psSaoPart[c][i].bandPosition = 0;
586      for (Int j=0;j<MAX_NUM_SAO_OFFSETS;j++)
587#else
588      for (Int j=0;j<MAX_NUM_SAO_CLASS;j++)
589#endif
590      {
591        pcSaoParam->psSaoPart[c][i].iOffset[j] = 0;
592        pcSaoParam->psSaoPart[c][i].iOffset[j] = 0;
593        pcSaoParam->psSaoPart[c][i].iOffset[j] = 0;
594      }
595    }
596#if SAO_UNIT_INTERLEAVING
597    pcSaoParam->oneUnitFlag[0]   = 0;
598    pcSaoParam->oneUnitFlag[1]   = 0;
599    pcSaoParam->oneUnitFlag[2]   = 0;
600    resetLcuPart(pcSaoParam->saoLcuParam[0]);
601    resetLcuPart(pcSaoParam->saoLcuParam[1]);
602    resetLcuPart(pcSaoParam->saoLcuParam[2]);
603#endif
604  }
605}
606
607/** get the sign of input variable
608 * \param   x
609 */
610inline int xSign(int x)
611{
612  return ((x >> 31) | ((int)( (((unsigned int) -x)) >> 31)));
613}
614
615/** initialize variables for SAO process
616 * \param  pcPic picture data pointer
617 * \param  numSlicesInPic number of slices in picture
618 */
619Void TComSampleAdaptiveOffset::createPicSaoInfo(TComPic* pcPic, Int numSlicesInPic)
620{
621  m_pcPic   = pcPic;
622  m_uiNumSlicesInPic = numSlicesInPic;
623  m_iSGDepth         = pcPic->getSliceGranularityForNDBFilter();
624  m_bUseNIF = ( pcPic->getIndependentSliceBoundaryForNDBFilter() || pcPic->getIndependentTileBoundaryForNDBFilter() );
625  if(m_bUseNIF)
626  {
627    m_pcYuvTmp = pcPic->getYuvPicBufferForIndependentBoundaryProcessing();
628  }
629}
630
631Void TComSampleAdaptiveOffset::destroyPicSaoInfo()
632{
633
634}
635
636/** sample adaptive offset process for one LCU
637 * \param   iAddr, iSaoType, iYCbCr
638 */
639Void TComSampleAdaptiveOffset::processSaoCu(Int iAddr, Int iSaoType, Int iYCbCr)
640{
641  if(!m_bUseNIF)
642  {
643    processSaoCuOrg( iAddr, iSaoType, iYCbCr);
644  }
645  else
646  { 
647    Int  isChroma = (iYCbCr != 0)? 1:0;
648    Int  stride   = (iYCbCr != 0)?(m_pcPic->getCStride()):(m_pcPic->getStride());
649    Pel* pPicRest = getPicYuvAddr(m_pcPic->getPicYuvRec(), iYCbCr);
650    Pel* pPicDec  = getPicYuvAddr(m_pcYuvTmp, iYCbCr);
651
652    std::vector<NDBFBlockInfo>& vFilterBlocks = *(m_pcPic->getCU(iAddr)->getNDBFilterBlocks());
653
654    //variables
655    UInt  xPos, yPos, width, height;
656    Bool* pbBorderAvail;
657    UInt  posOffset;
658
659    for(Int i=0; i< vFilterBlocks.size(); i++)
660    {
661      xPos        = vFilterBlocks[i].posX   >> isChroma;
662      yPos        = vFilterBlocks[i].posY   >> isChroma;
663      width       = vFilterBlocks[i].width  >> isChroma;
664      height      = vFilterBlocks[i].height >> isChroma;
665      pbBorderAvail = vFilterBlocks[i].isBorderAvailable;
666
667      posOffset = (yPos* stride) + xPos;
668
669      processSaoBlock(pPicDec+ posOffset, pPicRest+ posOffset, stride, iSaoType, xPos, yPos, width, height, pbBorderAvail);
670    }
671  }
672}
673
674/** Perform SAO for non-cross-slice or non-cross-tile process
675 * \param  pDec to-be-filtered block buffer pointer
676 * \param  pRest filtered block buffer pointer
677 * \param  stride picture buffer stride
678 * \param  saoType SAO offset type
679 * \param  xPos x coordinate
680 * \param  yPos y coordinate
681 * \param  width block width
682 * \param  height block height
683 * \param  pbBorderAvail availabilities of block border pixels
684 */
685Void TComSampleAdaptiveOffset::processSaoBlock(Pel* pDec, Pel* pRest, Int stride, Int saoType, UInt xPos, UInt yPos, UInt width, UInt height, Bool* pbBorderAvail)
686{
687  //variables
688  Int startX, startY, endX, endY, x, y;
689  Int signLeft,signRight,signDown,signDown1;
690  UInt edgeType;
691
692  switch (saoType)
693  {
694  case SAO_EO_0: // dir: -
695    {
696
697      startX = (pbBorderAvail[SGU_L]) ? 0 : 1;
698      endX   = (pbBorderAvail[SGU_R]) ? width : (width -1);
699      for (y=0; y< height; y++)
700      {
701        signLeft = xSign(pDec[startX] - pDec[startX-1]);
702        for (x=startX; x< endX; x++)
703        {
704          signRight =  xSign(pDec[x] - pDec[x+1]); 
705          edgeType =  signRight + signLeft + 2;
706          signLeft  = -signRight;
707
708          pRest[x] = m_pClipTable[pDec[x] + m_iOffsetEo[edgeType]];
709        }
710        pDec  += stride;
711        pRest += stride;
712      }
713      break;
714    }
715  case SAO_EO_1: // dir: |
716    {
717      startY = (pbBorderAvail[SGU_T]) ? 0 : 1;
718      endY   = (pbBorderAvail[SGU_B]) ? height : height-1;
719      if (!pbBorderAvail[SGU_T])
720      {
721        pDec  += stride;
722        pRest += stride;
723      }
724      for (x=0; x< width; x++)
725      {
726        m_iUpBuff1[x] = xSign(pDec[x] - pDec[x-stride]);
727      }
728      for (y=startY; y<endY; y++)
729      {
730        for (x=0; x< width; x++)
731        {
732          signDown  = xSign(pDec[x] - pDec[x+stride]); 
733          edgeType = signDown + m_iUpBuff1[x] + 2;
734          m_iUpBuff1[x]= -signDown;
735
736          pRest[x] = m_pClipTable[pDec[x] + m_iOffsetEo[edgeType]];
737        }
738        pDec  += stride;
739        pRest += stride;
740      }
741      break;
742    }
743  case SAO_EO_2: // dir: 135
744    {
745      Int posShift= stride + 1;
746
747      startX = (pbBorderAvail[SGU_L]) ? 0 : 1 ;
748      endX   = (pbBorderAvail[SGU_R]) ? width : (width-1);
749
750      //prepare 2nd line upper sign
751      pDec += stride;
752      for (x=startX; x< endX+1; x++)
753      {
754        m_iUpBuff1[x] = xSign(pDec[x] - pDec[x- posShift]);
755      }
756
757      //1st line
758      pDec -= stride;
759      if(pbBorderAvail[SGU_TL])
760      {
761        x= 0;
762        edgeType      =  xSign(pDec[x] - pDec[x- posShift]) - m_iUpBuff1[x+1] + 2;
763        pRest[x] = m_pClipTable[pDec[x] + m_iOffsetEo[edgeType]];
764
765      }
766      if(pbBorderAvail[SGU_T])
767      {
768        for(x= 1; x< endX; x++)
769        {
770          edgeType      =  xSign(pDec[x] - pDec[x- posShift]) - m_iUpBuff1[x+1] + 2;
771          pRest[x] = m_pClipTable[pDec[x] + m_iOffsetEo[edgeType]];
772        }
773      }
774      pDec   += stride;
775      pRest  += stride;
776
777
778      //middle lines
779      for (y= 1; y< height-1; y++)
780      {
781        for (x=startX; x<endX; x++)
782        {
783          signDown1      =  xSign(pDec[x] - pDec[x+ posShift]) ;
784          edgeType      =  signDown1 + m_iUpBuff1[x] + 2;
785          pRest[x] = m_pClipTable[pDec[x] + m_iOffsetEo[edgeType]];
786
787          m_iUpBufft[x+1] = -signDown1; 
788        }
789        m_iUpBufft[startX] = xSign(pDec[stride+startX] - pDec[startX-1]);
790
791        ipSwap     = m_iUpBuff1;
792        m_iUpBuff1 = m_iUpBufft;
793        m_iUpBufft = ipSwap;
794
795        pDec  += stride;
796        pRest += stride;
797      }
798
799      //last line
800      if(pbBorderAvail[SGU_B])
801      {
802        for(x= startX; x< width-1; x++)
803        {
804          edgeType =  xSign(pDec[x] - pDec[x+ posShift]) + m_iUpBuff1[x] + 2;
805          pRest[x] = m_pClipTable[pDec[x] + m_iOffsetEo[edgeType]];
806        }
807      }
808      if(pbBorderAvail[SGU_BR])
809      {
810        x= width -1;
811        edgeType =  xSign(pDec[x] - pDec[x+ posShift]) + m_iUpBuff1[x] + 2;
812        pRest[x] = m_pClipTable[pDec[x] + m_iOffsetEo[edgeType]];
813      }
814      break;
815    } 
816  case SAO_EO_3: // dir: 45
817    {
818      Int  posShift     = stride - 1;
819      startX = (pbBorderAvail[SGU_L]) ? 0 : 1;
820      endX   = (pbBorderAvail[SGU_R]) ? width : (width -1);
821
822      //prepare 2nd line upper sign
823      pDec += stride;
824      for (x=startX-1; x< endX; x++)
825      {
826        m_iUpBuff1[x] = xSign(pDec[x] - pDec[x- posShift]);
827      }
828
829
830      //first line
831      pDec -= stride;
832      if(pbBorderAvail[SGU_T])
833      {
834        for(x= startX; x< width -1; x++)
835        {
836          edgeType = xSign(pDec[x] - pDec[x- posShift]) -m_iUpBuff1[x-1] + 2;
837          pRest[x] = m_pClipTable[pDec[x] + m_iOffsetEo[edgeType]];
838        }
839      }
840      if(pbBorderAvail[SGU_TR])
841      {
842        x= width-1;
843        edgeType = xSign(pDec[x] - pDec[x- posShift]) -m_iUpBuff1[x-1] + 2;
844        pRest[x] = m_pClipTable[pDec[x] + m_iOffsetEo[edgeType]];
845      }
846      pDec  += stride;
847      pRest += stride;
848
849      //middle lines
850      for (y= 1; y< height-1; y++)
851      {
852        for(x= startX; x< endX; x++)
853        {
854          signDown1      =  xSign(pDec[x] - pDec[x+ posShift]) ;
855          edgeType      =  signDown1 + m_iUpBuff1[x] + 2;
856
857          pRest[x] = m_pClipTable[pDec[x] + m_iOffsetEo[edgeType]];
858          m_iUpBuff1[x-1] = -signDown1; 
859        }
860        m_iUpBuff1[endX-1] = xSign(pDec[endX-1 + stride] - pDec[endX]);
861
862        pDec  += stride;
863        pRest += stride;
864      }
865
866      //last line
867      if(pbBorderAvail[SGU_BL])
868      {
869        x= 0;
870        edgeType = xSign(pDec[x] - pDec[x+ posShift]) + m_iUpBuff1[x] + 2;
871        pRest[x] = m_pClipTable[pDec[x] + m_iOffsetEo[edgeType]];
872
873      }
874      if(pbBorderAvail[SGU_B])
875      {
876        for(x= 1; x< endX; x++)
877        {
878          edgeType = xSign(pDec[x] - pDec[x+ posShift]) + m_iUpBuff1[x] + 2;
879          pRest[x] = m_pClipTable[pDec[x] + m_iOffsetEo[edgeType]];
880        }
881      }
882      break;
883    }   
884#if SAO_UNIT_INTERLEAVING
885  case SAO_BO:
886#else
887  case SAO_BO_0:
888  case SAO_BO_1:
889#endif
890    {
891      for (y=0; y< height; y++)
892      {
893        for (x=0; x< width; x++)
894        {
895          pRest[x] = m_iOffsetBo[pDec[x]];
896        }
897        pRest += stride;
898        pDec  += stride;
899      }
900      break;
901    }
902  default: break;
903  }
904
905}
906
907/** sample adaptive offset process for one LCU crossing LCU boundary
908 * \param   iAddr, iSaoType, iYCbCr
909 */
910Void TComSampleAdaptiveOffset::processSaoCuOrg(Int iAddr, Int iSaoType, Int iYCbCr)
911{
912  Int x,y;
913  TComDataCU *pTmpCu = m_pcPic->getCU(iAddr);
914  Pel* pRec;
915  Int  iStride;
916  Int  iLcuWidth  = m_uiMaxCUWidth;
917  Int  iLcuHeight = m_uiMaxCUHeight;
918  UInt uiLPelX    = pTmpCu->getCUPelX();
919  UInt uiTPelY    = pTmpCu->getCUPelY();
920  UInt uiRPelX;
921  UInt uiBPelY;
922  Int  iSignLeft;
923  Int  iSignRight;
924  Int  iSignDown;
925  Int  iSignDown1;
926  Int  iSignDown2;
927  UInt uiEdgeType;
928  Int iPicWidthTmp;
929  Int iPicHeightTmp;
930  Int iStartX;
931  Int iStartY;
932  Int iEndX;
933  Int iEndY;
934  Int iIsChroma = (iYCbCr!=0)? 1:0;
935  Int iShift;
936  Int iCuHeightTmp;
937  Pel *pTmpLSwap;
938  Pel *pTmpL;
939  Pel *pTmpU;
940
941  iPicWidthTmp  = m_iPicWidth  >> iIsChroma;
942  iPicHeightTmp = m_iPicHeight >> iIsChroma;
943  iLcuWidth     = iLcuWidth    >> iIsChroma;
944  iLcuHeight    = iLcuHeight   >> iIsChroma;
945  uiLPelX       = uiLPelX      >> iIsChroma;
946  uiTPelY       = uiTPelY      >> iIsChroma;
947  uiRPelX       = uiLPelX + iLcuWidth  ;
948  uiBPelY       = uiTPelY + iLcuHeight ;
949  uiRPelX       = uiRPelX > iPicWidthTmp  ? iPicWidthTmp  : uiRPelX;
950  uiBPelY       = uiBPelY > iPicHeightTmp ? iPicHeightTmp : uiBPelY;
951  iLcuWidth     = uiRPelX - uiLPelX;
952  iLcuHeight    = uiBPelY - uiTPelY;
953
954  if(pTmpCu->getPic()==0)
955  {
956    return;
957  }
958  if (iYCbCr == 0)
959  {
960    pRec       = m_pcPic->getPicYuvRec()->getLumaAddr(iAddr);
961    iStride    = m_pcPic->getStride();
962  } 
963  else if (iYCbCr == 1)
964  {
965    pRec       = m_pcPic->getPicYuvRec()->getCbAddr(iAddr);
966    iStride    = m_pcPic->getCStride();
967  }
968  else 
969  {
970    pRec       = m_pcPic->getPicYuvRec()->getCrAddr(iAddr);
971    iStride    = m_pcPic->getCStride();
972  }
973
974//   if (iSaoType!=SAO_BO_0 || iSaoType!=SAO_BO_1)
975  {
976    iCuHeightTmp = (m_uiMaxCUHeight >> iIsChroma);
977    iShift = (m_uiMaxCUWidth>> iIsChroma)-1;
978    for (Int i=0;i<iCuHeightTmp+1;i++)
979    {
980      m_pTmpL2[i] = pRec[iShift];
981      pRec += iStride;
982    }
983    pRec -= (iStride*(iCuHeightTmp+1));
984
985    pTmpL = m_pTmpL1; 
986    pTmpU = &(m_pTmpU1[uiLPelX]); 
987  }
988
989  switch (iSaoType)
990  {
991  case SAO_EO_0: // dir: -
992    {
993      iStartX = (uiLPelX == 0) ? 1 : 0;
994      iEndX   = (uiRPelX == iPicWidthTmp) ? iLcuWidth-1 : iLcuWidth;
995      for (y=0; y<iLcuHeight; y++)
996      {
997        iSignLeft = xSign(pRec[iStartX] - pTmpL[y]);
998        for (x=iStartX; x< iEndX; x++)
999        {
1000          iSignRight =  xSign(pRec[x] - pRec[x+1]); 
1001          uiEdgeType =  iSignRight + iSignLeft + 2;
1002          iSignLeft  = -iSignRight;
1003
1004          pRec[x] = m_pClipTable[pRec[x] + m_iOffsetEo[uiEdgeType]];
1005        }
1006        pRec += iStride;
1007      }
1008      break;
1009    }
1010  case SAO_EO_1: // dir: |
1011    {
1012      iStartY = (uiTPelY == 0) ? 1 : 0;
1013      iEndY   = (uiBPelY == iPicHeightTmp) ? iLcuHeight-1 : iLcuHeight;
1014      if (uiTPelY == 0)
1015      {
1016        pRec += iStride;
1017      }
1018      for (x=0; x< iLcuWidth; x++)
1019      {
1020        m_iUpBuff1[x] = xSign(pRec[x] - pTmpU[x]);
1021      }
1022      for (y=iStartY; y<iEndY; y++)
1023      {
1024        for (x=0; x<iLcuWidth; x++)
1025        {
1026          iSignDown  = xSign(pRec[x] - pRec[x+iStride]); 
1027          uiEdgeType = iSignDown + m_iUpBuff1[x] + 2;
1028          m_iUpBuff1[x]= -iSignDown;
1029
1030          pRec[x] = m_pClipTable[pRec[x] + m_iOffsetEo[uiEdgeType]];
1031        }
1032        pRec += iStride;
1033      }
1034      break;
1035    }
1036  case SAO_EO_2: // dir: 135
1037    {
1038      iStartX = (uiLPelX == 0)            ? 1 : 0;
1039      iEndX   = (uiRPelX == iPicWidthTmp) ? iLcuWidth-1 : iLcuWidth;
1040
1041      iStartY = (uiTPelY == 0) ?             1 : 0;
1042      iEndY   = (uiBPelY == iPicHeightTmp) ? iLcuHeight-1 : iLcuHeight;
1043
1044      if (uiTPelY == 0)
1045      {
1046        pRec += iStride;
1047      }
1048
1049      for (x=iStartX; x<iEndX; x++)
1050      {
1051        m_iUpBuff1[x] = xSign(pRec[x] - pTmpU[x-1]);
1052      }
1053      for (y=iStartY; y<iEndY; y++)
1054      {
1055        iSignDown2 = xSign(pRec[iStride+iStartX] - pTmpL[y]);
1056        for (x=iStartX; x<iEndX; x++)
1057        {
1058          iSignDown1      =  xSign(pRec[x] - pRec[x+iStride+1]) ;
1059          uiEdgeType      =  iSignDown1 + m_iUpBuff1[x] + 2;
1060          m_iUpBufft[x+1] = -iSignDown1; 
1061          pRec[x] = m_pClipTable[pRec[x] + m_iOffsetEo[uiEdgeType]];
1062        }
1063        m_iUpBufft[iStartX] = iSignDown2;
1064
1065        ipSwap     = m_iUpBuff1;
1066        m_iUpBuff1 = m_iUpBufft;
1067        m_iUpBufft = ipSwap;
1068
1069        pRec += iStride;
1070      }
1071      break;
1072    } 
1073  case SAO_EO_3: // dir: 45
1074    {
1075      iStartX = (uiLPelX == 0) ? 1 : 0;
1076      iEndX   = (uiRPelX == iPicWidthTmp) ? iLcuWidth-1 : iLcuWidth;
1077
1078      iStartY = (uiTPelY == 0) ? 1 : 0;
1079      iEndY   = (uiBPelY == iPicHeightTmp) ? iLcuHeight-1 : iLcuHeight;
1080
1081      if (iStartY == 1)
1082      {
1083        pRec += iStride;
1084      }
1085
1086      for (x=iStartX-1; x<iEndX; x++)
1087      {
1088        m_iUpBuff1[x] = xSign(pRec[x] - pTmpU[x+1]);
1089      }
1090      for (y=iStartY; y<iEndY; y++)
1091      {
1092        x=iStartX;
1093        iSignDown1      =  xSign(pRec[x] - pTmpL[y+1]) ;
1094        uiEdgeType      =  iSignDown1 + m_iUpBuff1[x] + 2;
1095        m_iUpBuff1[x-1] = -iSignDown1; 
1096        pRec[x] = m_pClipTable[pRec[x] + m_iOffsetEo[uiEdgeType]];
1097        for (x=iStartX+1; x<iEndX; x++)
1098        {
1099          iSignDown1      =  xSign(pRec[x] - pRec[x+iStride-1]) ;
1100          uiEdgeType      =  iSignDown1 + m_iUpBuff1[x] + 2;
1101          m_iUpBuff1[x-1] = -iSignDown1; 
1102          pRec[x] = m_pClipTable[pRec[x] + m_iOffsetEo[uiEdgeType]];
1103        }
1104        m_iUpBuff1[iEndX-1] = xSign(pRec[iEndX-1 + iStride] - pRec[iEndX]);
1105
1106        pRec += iStride;
1107      } 
1108      break;
1109    }   
1110#if SAO_UNIT_INTERLEAVING
1111  case SAO_BO:
1112#else
1113  case SAO_BO_0:
1114  case SAO_BO_1:
1115#endif
1116    {
1117      for (y=0; y<iLcuHeight; y++)
1118      {
1119        for (x=0; x<iLcuWidth; x++)
1120        {
1121          pRec[x] = m_iOffsetBo[pRec[x]];
1122        }
1123        pRec += iStride;
1124      }
1125      break;
1126    }
1127  default: break;
1128  }
1129//   if (iSaoType!=SAO_BO_0 || iSaoType!=SAO_BO_1)
1130  {
1131    pTmpLSwap = m_pTmpL1;
1132    m_pTmpL1  = m_pTmpL2;
1133    m_pTmpL2  = pTmpLSwap;
1134  }
1135}
1136#if !SAO_UNIT_INTERLEAVING
1137/** sample adaptive offset process for one partition
1138 * \param   *psQTPart,  uiPartIdx,  iYCbCr
1139 */
1140Void TComSampleAdaptiveOffset::processSaoOnePart(SAOQTPart *psQTPart, UInt uiPartIdx, Int iYCbCr)
1141{
1142  int  i;
1143  UInt uiEdgeType, uiTypeIdx;
1144  Pel* ppLumaTable = NULL;
1145  SAOQTPart*  pOnePart= &(psQTPart[uiPartIdx]);
1146
1147  static Int iOffset[LUMA_GROUP_NUM];
1148  Int LcuIdxX;
1149  Int LcuIdxY;
1150  Int iAddr;
1151  Int iFrameWidthInCU = m_pcPic->getFrameWidthInCU();
1152
1153  if(pOnePart->bEnableFlag)
1154  {
1155    uiTypeIdx = pOnePart->iBestType;
1156    if (uiTypeIdx == SAO_BO_0 || uiTypeIdx == SAO_BO_1)
1157    {
1158      for (i=0;i<pOnePart->iLength;i++)
1159        iOffset[i+1] = pOnePart->iOffset[i] << m_uiSaoBitIncrease;
1160
1161      if (uiTypeIdx == SAO_BO_0 )
1162      {
1163        ppLumaTable = m_ppLumaTableBo0;
1164      }
1165      if (uiTypeIdx == SAO_BO_1 )
1166      {
1167        ppLumaTable = m_ppLumaTableBo1;
1168      }
1169
1170#if FULL_NBIT
1171      for (i=0;i<(1<<(g_uiBitDepth));i++)
1172#else
1173      for (i=0;i<(1<<(g_uiBitIncrement+8));i++)
1174#endif
1175      {
1176        m_iOffsetBo[i] = m_pClipTable[i + iOffset[ppLumaTable[i]]];
1177      }
1178
1179    }
1180    if (uiTypeIdx == SAO_EO_0 || uiTypeIdx == SAO_EO_1 || uiTypeIdx == SAO_EO_2 || uiTypeIdx == SAO_EO_3)
1181    {
1182      for (i=0;i<pOnePart->iLength;i++)
1183      {
1184        iOffset[i+1] = pOnePart->iOffset[i] << m_uiSaoBitIncrease;
1185      }
1186      for (uiEdgeType=0;uiEdgeType<6;uiEdgeType++)
1187      {
1188        m_iOffsetEo[uiEdgeType]= iOffset[m_auiEoTable[uiEdgeType]];
1189      }
1190    }
1191    for (LcuIdxY = pOnePart->StartCUY; LcuIdxY<= pOnePart->EndCUY; LcuIdxY++)
1192    {
1193      for (LcuIdxX = pOnePart->StartCUX; LcuIdxX<= pOnePart->EndCUX; LcuIdxX++)
1194      {
1195        iAddr = LcuIdxY * iFrameWidthInCU + LcuIdxX;
1196        processSaoCu(iAddr, uiTypeIdx, iYCbCr);
1197      }
1198    }
1199  }
1200}
1201
1202/** Process quadtree sample adaptive offset
1203 * \param  psQTPart, uiPartIdx, iYCbCr
1204 */
1205Void TComSampleAdaptiveOffset::processSaoQuadTree(SAOQTPart *psQTPart, UInt uiPartIdx, Int iYCbCr)
1206{
1207  SAOQTPart*  pSaoPart= &(psQTPart[uiPartIdx]);
1208
1209  if (uiPartIdx == 0)
1210  {
1211    initTmpSaoQuadTree(psQTPart, iYCbCr);
1212    xSaoAllPart(psQTPart, iYCbCr);
1213    return;
1214  }
1215
1216  if (!pSaoPart->bSplit)
1217  {
1218    if (pSaoPart->bEnableFlag)
1219    {
1220      processSaoOnePart(psQTPart, uiPartIdx, iYCbCr);
1221    }
1222    return;
1223  }
1224
1225  if (pSaoPart->PartLevel < m_uiMaxSplitLevel)
1226  {
1227    processSaoQuadTree(psQTPart, pSaoPart->DownPartsIdx[0], iYCbCr);
1228    processSaoQuadTree(psQTPart, pSaoPart->DownPartsIdx[1], iYCbCr);
1229    processSaoQuadTree(psQTPart, pSaoPart->DownPartsIdx[2], iYCbCr);
1230    processSaoQuadTree(psQTPart, pSaoPart->DownPartsIdx[3], iYCbCr);
1231  }
1232}
1233
1234/** run SAO processing in LCU order
1235 * \param *psQTPart,  iYCbCr
1236 */
1237Void TComSampleAdaptiveOffset::xSaoAllPart(SAOQTPart *psQTPart, Int iYCbCr)
1238{
1239  int  i;
1240  UInt uiEdgeType;
1241  Pel* ppLumaTable = NULL;
1242  Int  iTypeIdx;
1243
1244  static Int iOffset[LUMA_GROUP_NUM];
1245  Int LcuIdxX;
1246  Int LcuIdxY;
1247  Int iAddr;
1248  Int iFrameWidthInCU = m_pcPic->getFrameWidthInCU();
1249  Int iFrameHeightInCU = m_pcPic->getFrameHeightInCU();
1250  Int iPartIdx;
1251  Pel *pRec;
1252  Int iPicWidthTmp;
1253  Int iStride;
1254  Pel *pTmpUSwap;
1255  Int iIsChroma = (iYCbCr == 0) ? 0:1;
1256
1257  SAOQTPart*  pOnePart;
1258
1259  for (LcuIdxY = 0; LcuIdxY< iFrameHeightInCU; LcuIdxY++)
1260  { 
1261    iAddr = LcuIdxY * iFrameWidthInCU;
1262    if (iYCbCr == 0)
1263    {
1264      pRec  = m_pcPic->getPicYuvRec()->getLumaAddr(iAddr);
1265      iStride = m_pcPic->getStride();
1266      iPicWidthTmp = m_iPicWidth;
1267    }
1268    else if (iYCbCr == 1)
1269    {
1270      pRec  = m_pcPic->getPicYuvRec()->getCbAddr(iAddr);
1271      iStride = m_pcPic->getCStride();
1272      iPicWidthTmp = m_iPicWidth>>1;
1273    }
1274    else
1275    {
1276      pRec  = m_pcPic->getPicYuvRec()->getCrAddr(iAddr);
1277      iStride = m_pcPic->getCStride();
1278      iPicWidthTmp = m_iPicWidth>>1;
1279    }
1280
1281//     pRec += iStride*(m_uiMaxCUHeight-1);
1282    for (i=0;i<(m_uiMaxCUHeight>>iIsChroma)+1;i++)
1283    {
1284      m_pTmpL1[i] = pRec[0];
1285      pRec+=iStride;
1286    }
1287    pRec-=(iStride<<1);
1288
1289    memcpy(m_pTmpU2, pRec, sizeof(Pel)*iPicWidthTmp);
1290
1291    for (LcuIdxX = 0; LcuIdxX< iFrameWidthInCU; LcuIdxX++)
1292    {
1293      iAddr = LcuIdxY * iFrameWidthInCU + LcuIdxX;
1294      iPartIdx = m_iLcuPartIdx[iAddr];
1295      if (iPartIdx>=0)
1296      {
1297        pOnePart = &(psQTPart[iPartIdx]);
1298        iTypeIdx = pOnePart->iBestType;
1299        if (iTypeIdx>=0)
1300        {
1301          if (iTypeIdx == SAO_BO_0 || iTypeIdx == SAO_BO_1)
1302          {
1303            for (i=0;i<pOnePart->iLength;i++)
1304              iOffset[i+1] = pOnePart->iOffset[i] << m_uiSaoBitIncrease;
1305
1306            if (iTypeIdx == SAO_BO_0 )
1307            {
1308              ppLumaTable = m_ppLumaTableBo0;
1309            }
1310            if (iTypeIdx == SAO_BO_1 )
1311            {
1312              ppLumaTable = m_ppLumaTableBo1;
1313            }
1314
1315#if FULL_NBIT
1316            for (i=0;i<(1<<(g_uiBitDepth));i++)
1317#else
1318            for (i=0;i<(1<<(g_uiBitIncrement+8));i++)
1319#endif
1320            {
1321              m_iOffsetBo[i] = m_pClipTable[i + iOffset[ppLumaTable[i]]];
1322            }
1323
1324          }
1325          if (iTypeIdx == SAO_EO_0 || iTypeIdx == SAO_EO_1 || iTypeIdx == SAO_EO_2 || iTypeIdx == SAO_EO_3)
1326          {
1327            for (i=0;i<pOnePart->iLength;i++)
1328            {
1329              iOffset[i+1] = pOnePart->iOffset[i] << m_uiSaoBitIncrease;
1330            }
1331            for (uiEdgeType=0;uiEdgeType<6;uiEdgeType++)
1332            {
1333              m_iOffsetEo[uiEdgeType]= iOffset[m_auiEoTable[uiEdgeType]];
1334            }
1335          }
1336          processSaoCu(iAddr, iTypeIdx, iYCbCr);
1337        }
1338      }
1339      else
1340      {
1341        if (LcuIdxX != (iFrameWidthInCU-1))
1342        {
1343          if( m_iLcuPartIdx[iAddr+1] >=0) 
1344          {
1345            if (iYCbCr == 0)
1346            {
1347              pRec  = m_pcPic->getPicYuvRec()->getLumaAddr(iAddr);
1348              iStride = m_pcPic->getStride();
1349            }
1350            else if (iYCbCr == 1)
1351            {
1352              pRec  = m_pcPic->getPicYuvRec()->getCbAddr(iAddr);
1353              iStride = m_pcPic->getCStride();
1354            }
1355            else
1356            {
1357              pRec  = m_pcPic->getPicYuvRec()->getCrAddr(iAddr);
1358              iStride = m_pcPic->getCStride();
1359            }
1360            Int iWidthShift = m_uiMaxCUWidth>>iIsChroma;
1361            for (i=0;i<(m_uiMaxCUHeight>>iIsChroma)+1;i++)
1362            {
1363              m_pTmpL1[i] = pRec[iWidthShift-1];
1364              pRec+=iStride;
1365            }
1366          }
1367        }
1368      }
1369    }
1370    pTmpUSwap = m_pTmpU1;
1371    m_pTmpU1  = m_pTmpU2;
1372    m_pTmpU2  = pTmpUSwap;
1373  }
1374}
1375
1376/** initialize buffer for quadtree boundary
1377 * \param *psQTPart,  iYCbCr
1378 */
1379Void TComSampleAdaptiveOffset::initTmpSaoQuadTree(SAOQTPart *psQTPart, Int iYCbCr)
1380{
1381  Pel *pRec;
1382  Int iPicWidthTmp;
1383 
1384
1385  memset(m_iLcuPartIdx,-1, sizeof(Int)*m_iNumCuInWidth*m_iNumCuInHeight);
1386  convertSaoQt2Lcu(psQTPart, 0);
1387
1388  if (iYCbCr == 0)
1389  {
1390    pRec       = m_pcPic->getPicYuvRec()->getLumaAddr();
1391    iPicWidthTmp = m_iPicWidth;
1392  } 
1393  else if (iYCbCr == 1)
1394  {
1395    pRec       = m_pcPic->getPicYuvRec()->getCbAddr();
1396    iPicWidthTmp =  m_iPicWidth>>1;
1397  }
1398  else 
1399  {
1400    pRec       = m_pcPic->getPicYuvRec()->getCrAddr();
1401    iPicWidthTmp =  m_iPicWidth>>1;
1402  }
1403
1404  memcpy(m_pTmpU1, pRec, sizeof(Pel)*iPicWidthTmp);
1405}
1406
1407/** recursive covert quadtree partition index to each LCU
1408 * \param psQTPart, uiPartIdx 
1409 */
1410Void TComSampleAdaptiveOffset::convertSaoQt2Lcu(SAOQTPart *psQTPart,UInt uiPartIdx)
1411{
1412
1413  SAOQTPart*  pSaoPart= &(psQTPart[uiPartIdx]);
1414
1415  if (!pSaoPart->bSplit)
1416  {
1417    xSaoQt2Lcu(psQTPart, uiPartIdx);
1418    return;
1419  }
1420
1421  if (pSaoPart->PartLevel < m_uiMaxSplitLevel)
1422  {
1423    convertSaoQt2Lcu(psQTPart, pSaoPart->DownPartsIdx[0]);
1424    convertSaoQt2Lcu(psQTPart, pSaoPart->DownPartsIdx[1]);
1425    convertSaoQt2Lcu(psQTPart, pSaoPart->DownPartsIdx[2]);
1426    convertSaoQt2Lcu(psQTPart, pSaoPart->DownPartsIdx[3]);
1427  }
1428}
1429
1430/** assign quadtree partition index to each LCU
1431 * \param psQTPart, uiPartIdx 
1432 */
1433
1434Void TComSampleAdaptiveOffset::xSaoQt2Lcu(SAOQTPart *psQTPart,UInt uiPartIdx)
1435{
1436  Int LcuIdxX;
1437  Int LcuIdxY;
1438  Int iAddr;
1439  Int iFrameWidthInCU = m_iNumCuInWidth;
1440
1441  for (LcuIdxY = psQTPart[uiPartIdx].StartCUY; LcuIdxY<= psQTPart[uiPartIdx].EndCUY; LcuIdxY++)
1442  {
1443    for (LcuIdxX = psQTPart[uiPartIdx].StartCUX; LcuIdxX<= psQTPart[uiPartIdx].EndCUX; LcuIdxX++)
1444    {
1445      iAddr = LcuIdxY * iFrameWidthInCU + LcuIdxX;
1446      if (psQTPart[uiPartIdx].bEnableFlag)
1447      {
1448        m_iLcuPartIdx[iAddr] = (Int)uiPartIdx; 
1449      }
1450      else
1451      {
1452        m_iLcuPartIdx[iAddr] = -1;
1453      } 
1454    }
1455  }
1456}
1457#endif
1458/** Sample adaptive offset process
1459 * \param pcPic, pcSaoParam 
1460 */
1461Void TComSampleAdaptiveOffset::SAOProcess(TComPic* pcPic, SAOParam* pcSaoParam)
1462{
1463  if (pcSaoParam->bSaoFlag[0])
1464  {
1465#if FULL_NBIT
1466    m_uiSaoBitIncrease = g_uiBitDepth + (g_uiBitDepth-8) - min((Int)(g_uiBitDepth + (g_uiBitDepth-8)), 10);
1467#else
1468    m_uiSaoBitIncrease = g_uiBitDepth + g_uiBitIncrement - min((Int)(g_uiBitDepth + g_uiBitIncrement), 10);
1469#endif
1470
1471    if(m_bUseNIF)
1472    {
1473      m_pcPic->getPicYuvRec()->copyToPic(m_pcYuvTmp);
1474    }
1475
1476#if SAO_UNIT_INTERLEAVING
1477    if (m_saoInterleavingFlag)
1478    {
1479      pcSaoParam->oneUnitFlag[0] = 0; 
1480      pcSaoParam->oneUnitFlag[1] = 0; 
1481      pcSaoParam->oneUnitFlag[2] = 0; 
1482    }
1483    Int iY  = 0;
1484    processSaoUnitAll( pcSaoParam->saoLcuParam[iY], pcSaoParam->oneUnitFlag[iY], iY);
1485
1486    Int iCb = 1;
1487    Int iCr = 2;
1488    if (pcSaoParam->bSaoFlag[iCb])
1489    {
1490      processSaoUnitAll( pcSaoParam->saoLcuParam[iCb], pcSaoParam->oneUnitFlag[iCb], iCb);
1491    }
1492    if (pcSaoParam->bSaoFlag[iCr])
1493    {
1494      processSaoUnitAll( pcSaoParam->saoLcuParam[iCr], pcSaoParam->oneUnitFlag[iCr], iCr);
1495    }
1496
1497
1498#else
1499    Int iY  = 0;
1500    processSaoQuadTree( pcSaoParam->psSaoPart[iY], 0 , iY);
1501
1502    Int iCb = 1;
1503    Int iCr = 2;
1504    if (pcSaoParam->bSaoFlag[iCb])
1505    {
1506      processSaoQuadTree( pcSaoParam->psSaoPart[iCb], 0 , iCb);
1507    }
1508    if (pcSaoParam->bSaoFlag[iCr])
1509    {
1510      processSaoQuadTree( pcSaoParam->psSaoPart[iCr], 0 , iCr);
1511    }
1512#endif
1513    m_pcPic = NULL;
1514  }
1515}
1516
1517Pel* TComSampleAdaptiveOffset::getPicYuvAddr(TComPicYuv* pcPicYuv, Int iYCbCr, Int iAddr)
1518{
1519  switch (iYCbCr)
1520  {
1521  case 0:
1522    return pcPicYuv->getLumaAddr(iAddr);
1523    break;
1524  case 1:
1525    return pcPicYuv->getCbAddr(iAddr);
1526    break;
1527  case 2:
1528    return pcPicYuv->getCrAddr(iAddr);
1529    break;
1530  default:
1531    return NULL;
1532    break;
1533  }
1534}
1535#if SAO_UNIT_INTERLEAVING
1536/** Process SAO all units
1537 * \param saoLcuParam SAO LCU parameters
1538 * \param oneUnitFlag one unit flag
1539 * \param yCbCr color componet index
1540 */
1541Void TComSampleAdaptiveOffset::processSaoUnitAll(SaoLcuParam* saoLcuParam, Bool oneUnitFlag, Int yCbCr)
1542{
1543  Pel *pRec;
1544  Int picWidthTmp;
1545
1546  if (yCbCr == 0)
1547  {
1548    pRec        = m_pcPic->getPicYuvRec()->getLumaAddr();
1549    picWidthTmp = m_iPicWidth;
1550  } 
1551  else if (yCbCr == 1)
1552  {
1553    pRec        = m_pcPic->getPicYuvRec()->getCbAddr();
1554    picWidthTmp = m_iPicWidth>>1;
1555  }
1556  else 
1557  {
1558    pRec        = m_pcPic->getPicYuvRec()->getCrAddr();
1559    picWidthTmp = m_iPicWidth>>1;
1560  }
1561
1562  memcpy(m_pTmpU1, pRec, sizeof(Pel)*picWidthTmp);
1563
1564  int  i;
1565  UInt edgeType;
1566  Pel* ppLumaTable = NULL;
1567  Int  typeIdx;
1568
1569  static Int offset[LUMA_GROUP_NUM+1];
1570  Int idxX;
1571  Int idxY;
1572  Int addr;
1573  Int frameWidthInCU = m_pcPic->getFrameWidthInCU();
1574  Int frameHeightInCU = m_pcPic->getFrameHeightInCU();
1575  Int stride;
1576  Pel *tmpUSwap;
1577  Int isChroma = (yCbCr == 0) ? 0:1;
1578  Bool mergeLeftFlag;
1579
1580
1581  for (idxY = 0; idxY< frameHeightInCU; idxY++)
1582  { 
1583    addr = idxY * frameWidthInCU;
1584    if (yCbCr == 0)
1585    {
1586      pRec  = m_pcPic->getPicYuvRec()->getLumaAddr(addr);
1587      stride = m_pcPic->getStride();
1588      picWidthTmp = m_iPicWidth;
1589    }
1590    else if (yCbCr == 1)
1591    {
1592      pRec  = m_pcPic->getPicYuvRec()->getCbAddr(addr);
1593      stride = m_pcPic->getCStride();
1594      picWidthTmp = m_iPicWidth>>1;
1595    }
1596    else
1597    {
1598      pRec  = m_pcPic->getPicYuvRec()->getCrAddr(addr);
1599      stride = m_pcPic->getCStride();
1600      picWidthTmp = m_iPicWidth>>1;
1601    }
1602
1603    //     pRec += iStride*(m_uiMaxCUHeight-1);
1604    for (i=0;i<(m_uiMaxCUHeight>>isChroma)+1;i++)
1605    {
1606      m_pTmpL1[i] = pRec[0];
1607      pRec+=stride;
1608    }
1609    pRec-=(stride<<1);
1610
1611    memcpy(m_pTmpU2, pRec, sizeof(Pel)*picWidthTmp);
1612
1613    for (idxX = 0; idxX < frameWidthInCU; idxX++)
1614    {
1615      addr = idxY * frameWidthInCU + idxX;
1616
1617      if (oneUnitFlag)
1618      {
1619        typeIdx = saoLcuParam[0].typeIdx;
1620        mergeLeftFlag = (addr == 0)? 0:1;
1621      }
1622      else
1623      {
1624        typeIdx = saoLcuParam[addr].typeIdx;
1625        mergeLeftFlag = saoLcuParam[addr].mergeLeftFlag;
1626      }
1627      if (typeIdx>=0)
1628      {
1629        if (!mergeLeftFlag)
1630        {
1631
1632          if (typeIdx == SAO_BO)
1633          {
1634            for (i=0; i<SAO_MAX_BO_CLASSES+1;i++)
1635            {
1636              offset[i] = 0;
1637            }
1638            for (i=0; i<saoLcuParam[addr].length; i++)
1639            {
1640              offset[ (saoLcuParam[addr].bandPosition +i)%SAO_MAX_BO_CLASSES  +1] = saoLcuParam[addr].offset[i] << m_uiSaoBitIncrease;
1641            }
1642
1643            ppLumaTable = m_lumaTableBo;
1644
1645#if FULL_NBIT
1646            for (i=0;i<(1<<(g_uiBitDepth));i++)
1647#else
1648            for (i=0;i<(1<<(g_uiBitIncrement+8));i++)
1649#endif
1650            {
1651              m_iOffsetBo[i] = m_pClipTable[i + offset[ppLumaTable[i]]];
1652            }
1653
1654          }
1655          if (typeIdx == SAO_EO_0 || typeIdx == SAO_EO_1 || typeIdx == SAO_EO_2 || typeIdx == SAO_EO_3)
1656          {
1657            for (i=0;i<saoLcuParam[addr].length;i++)
1658            {
1659              offset[i+1] = saoLcuParam[addr].offset[i] << m_uiSaoBitIncrease;
1660            }
1661            for (edgeType=0;edgeType<6;edgeType++)
1662            {
1663              m_iOffsetEo[edgeType]= offset[m_auiEoTable[edgeType]];
1664            }
1665          }
1666        }
1667        processSaoCu(addr, typeIdx, yCbCr);
1668      }
1669      else
1670      {
1671        if (idxX != (frameWidthInCU-1))
1672        {
1673          if (yCbCr == 0)
1674          {
1675            pRec  = m_pcPic->getPicYuvRec()->getLumaAddr(addr);
1676            stride = m_pcPic->getStride();
1677          }
1678          else if (yCbCr == 1)
1679          {
1680            pRec  = m_pcPic->getPicYuvRec()->getCbAddr(addr);
1681            stride = m_pcPic->getCStride();
1682          }
1683          else
1684          {
1685            pRec  = m_pcPic->getPicYuvRec()->getCrAddr(addr);
1686            stride = m_pcPic->getCStride();
1687          }
1688          Int widthShift = m_uiMaxCUWidth>>isChroma;
1689          for (i=0;i<(m_uiMaxCUHeight>>isChroma)+1;i++)
1690          {
1691            m_pTmpL1[i] = pRec[widthShift-1];
1692            pRec+=stride;
1693          }
1694        }
1695      }
1696    }
1697    tmpUSwap = m_pTmpU1;
1698    m_pTmpU1 = m_pTmpU2;
1699    m_pTmpU2 = tmpUSwap;
1700  }
1701
1702}
1703/** Reset SAO LCU part
1704 * \param saoLcuParam
1705 */
1706Void TComSampleAdaptiveOffset::resetLcuPart(SaoLcuParam* saoLcuParam)
1707{
1708  Int i,j;
1709  for (i=0;i<m_iNumCuInWidth*m_iNumCuInHeight;i++)
1710  {
1711    saoLcuParam[i].mergeUpFlag     =  1;
1712    saoLcuParam[i].mergeLeftFlag =  0;
1713    saoLcuParam[i].partIdx   =  0;
1714    saoLcuParam[i].typeIdx      = -1;
1715    for (j=0;j<MAX_NUM_SAO_OFFSETS;j++)
1716    {
1717      saoLcuParam[i].offset[j] = 0;
1718    }
1719    saoLcuParam[i].bandPosition = 0;
1720  }
1721}
1722
1723/** convert QP part to SAO unit
1724* \param saoParam SAO parameter
1725* \param partIdx SAO part index
1726* \param yCbCr color component index
1727 */
1728Void TComSampleAdaptiveOffset::convertQT2SaoUnit(SAOParam *saoParam, UInt partIdx, Int yCbCr)
1729{
1730
1731  SAOQTPart*  saoPart= &(saoParam->psSaoPart[yCbCr][partIdx]);
1732  if (!saoPart->bSplit)
1733  {
1734    convertOnePart2SaoUnit(saoParam, partIdx, yCbCr);
1735    return;
1736  }
1737
1738  if (saoPart->PartLevel < m_uiMaxSplitLevel)
1739  {
1740    convertQT2SaoUnit(saoParam, saoPart->DownPartsIdx[0], yCbCr);
1741    convertQT2SaoUnit(saoParam, saoPart->DownPartsIdx[1], yCbCr);
1742    convertQT2SaoUnit(saoParam, saoPart->DownPartsIdx[2], yCbCr);
1743    convertQT2SaoUnit(saoParam, saoPart->DownPartsIdx[3], yCbCr);
1744  }
1745}
1746/** convert one SAO part to SAO unit
1747* \param saoParam SAO parameter
1748* \param partIdx SAO part index
1749* \param yCbCr color component index
1750 */
1751Void TComSampleAdaptiveOffset::convertOnePart2SaoUnit(SAOParam *saoParam, UInt partIdx, Int yCbCr)
1752{
1753  Int j;
1754  Int idxX;
1755  Int idxY;
1756  Int addr;
1757  Int frameWidthInCU = m_pcPic->getFrameWidthInCU();
1758  SAOQTPart* saoQTPart = saoParam->psSaoPart[yCbCr];
1759  SaoLcuParam* saoLcuParam = saoParam->saoLcuParam[yCbCr];
1760
1761  for (idxY = saoQTPart[partIdx].StartCUY; idxY<= saoQTPart[partIdx].EndCUY; idxY++)
1762  {
1763    for (idxX = saoQTPart[partIdx].StartCUX; idxX<= saoQTPart[partIdx].EndCUX; idxX++)
1764    {
1765      addr = idxY * frameWidthInCU + idxX;
1766      saoLcuParam[addr].partIdxTmp = (Int)partIdx; 
1767      saoLcuParam[addr].typeIdx    = saoQTPart[partIdx].iBestType;
1768      saoLcuParam[addr].bandPosition = saoQTPart[partIdx].bandPosition;
1769      if (saoLcuParam[addr].typeIdx!=-1)
1770      {
1771        saoLcuParam[addr].length    = saoQTPart[partIdx].iLength;
1772        for (j=0;j<MAX_NUM_SAO_OFFSETS;j++)
1773        {
1774          saoLcuParam[addr].offset[j] = saoQTPart[partIdx].iOffset[j];
1775        }
1776      }
1777      else
1778      {
1779        saoLcuParam[addr].length    = 0;
1780        saoLcuParam[addr].bandPosition = saoQTPart[partIdx].bandPosition;
1781        for (j=0;j<MAX_NUM_SAO_OFFSETS;j++)
1782        {
1783          saoLcuParam[addr].offset[j] = 0;
1784        }
1785      }
1786    }
1787  }
1788}
1789
1790
1791#endif
1792
1793//! \}
Note: See TracBrowser for help on using the repository browser.