1 /* The copyright in this software is being made available under the BSD
2 * License, included below. This software may be subject to other third party
3 * and contributor rights, including patent rights, and no such rights are
4 * granted under this license.
5 *
6 * Copyright (c) 2010-2014, ITU/ISO/IEC
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
18 * be used to endorse or promote products derived from this software without
19 * specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31 * THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /** \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
47 UInt g_saoMaxOffsetQVal[MAX_NUM_COMPONENT];
48
SAOOffset()49 SAOOffset::SAOOffset()
50 {
51 reset();
52 }
53
~SAOOffset()54 SAOOffset::~SAOOffset()
55 {
56
57 }
58
reset()59 Void SAOOffset::reset()
60 {
61 modeIdc = SAO_MODE_OFF;
62 typeIdc = -1;
63 typeAuxInfo = -1;
64 ::memset(offset, 0, sizeof(Int)* MAX_NUM_SAO_CLASSES);
65 }
66
operator =(const SAOOffset & src)67 const SAOOffset& SAOOffset::operator= (const SAOOffset& src)
68 {
69 modeIdc = src.modeIdc;
70 typeIdc = src.typeIdc;
71 typeAuxInfo = src.typeAuxInfo;
72 ::memcpy(offset, src.offset, sizeof(Int)* MAX_NUM_SAO_CLASSES);
73
74 return *this;
75 }
76
77
SAOBlkParam()78 SAOBlkParam::SAOBlkParam()
79 {
80 reset();
81 }
82
~SAOBlkParam()83 SAOBlkParam::~SAOBlkParam()
84 {
85
86 }
87
reset()88 Void SAOBlkParam::reset()
89 {
90 for(Int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++)
91 {
92 offsetParam[compIdx].reset();
93 }
94 }
95
operator =(const SAOBlkParam & src)96 const SAOBlkParam& SAOBlkParam::operator= (const SAOBlkParam& src)
97 {
98 for(Int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++)
99 {
100 offsetParam[compIdx] = src.offsetParam[compIdx];
101 }
102 return *this;
103
104 }
105
TComSampleAdaptiveOffset()106 TComSampleAdaptiveOffset::TComSampleAdaptiveOffset()
107 {
108 m_tempPicYuv = NULL;
109 m_lineBufWidth = 0;
110 m_signLineBuf1 = NULL;
111 m_signLineBuf2 = NULL;
112 }
113
114
~TComSampleAdaptiveOffset()115 TComSampleAdaptiveOffset::~TComSampleAdaptiveOffset()
116 {
117 destroy();
118
119 if (m_signLineBuf1) delete[] m_signLineBuf1; m_signLineBuf1 = NULL;
120 if (m_signLineBuf2) delete[] m_signLineBuf2; m_signLineBuf2 = NULL;
121 }
122
create(Int picWidth,Int picHeight,ChromaFormat format,UInt maxCUWidth,UInt maxCUHeight,UInt maxCUDepth,UInt lumaBitShift,UInt chromaBitShift)123 Void TComSampleAdaptiveOffset::create( Int picWidth, Int picHeight, ChromaFormat format, UInt maxCUWidth, UInt maxCUHeight, UInt maxCUDepth, UInt lumaBitShift, UInt chromaBitShift )
124 {
125 destroy();
126
127 m_picWidth = picWidth;
128 m_picHeight = picHeight;
129 m_chromaFormatIDC = format;
130 m_maxCUWidth = maxCUWidth;
131 m_maxCUHeight = maxCUHeight;
132
133 m_numCTUInWidth = (m_picWidth/m_maxCUWidth) + ((m_picWidth % m_maxCUWidth)?1:0);
134 m_numCTUInHeight = (m_picHeight/m_maxCUHeight) + ((m_picHeight % m_maxCUHeight)?1:0);
135 m_numCTUsPic = m_numCTUInHeight*m_numCTUInWidth;
136
137 //temporary picture buffer
138 if ( !m_tempPicYuv )
139 {
140 m_tempPicYuv = new TComPicYuv;
141 m_tempPicYuv->create( m_picWidth, m_picHeight, m_chromaFormatIDC, m_maxCUWidth, m_maxCUHeight, maxCUDepth );
142 }
143
144 //bit-depth related
145 for(Int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++)
146 {
147 Int bitDepthSample = g_bitDepth[toChannelType(ComponentID(compIdx))];
148 m_offsetStepLog2 [compIdx] = isLuma(ComponentID(compIdx))? lumaBitShift : chromaBitShift;
149 g_saoMaxOffsetQVal[compIdx] = (1<<(min(bitDepthSample,MAX_SAO_TRUNCATED_BITDEPTH)-5))-1; //Table 9-32, inclusive
150 }
151 }
152
destroy()153 Void TComSampleAdaptiveOffset::destroy()
154 {
155 if ( m_tempPicYuv )
156 {
157 m_tempPicYuv->destroy();
158 delete m_tempPicYuv;
159 m_tempPicYuv = NULL;
160 }
161 }
162
invertQuantOffsets(ComponentID compIdx,Int typeIdc,Int typeAuxInfo,Int * dstOffsets,Int * srcOffsets)163 Void TComSampleAdaptiveOffset::invertQuantOffsets(ComponentID compIdx, Int typeIdc, Int typeAuxInfo, Int* dstOffsets, Int* srcOffsets)
164 {
165 Int codedOffset[MAX_NUM_SAO_CLASSES];
166
167 ::memcpy(codedOffset, srcOffsets, sizeof(Int)*MAX_NUM_SAO_CLASSES);
168 ::memset(dstOffsets, 0, sizeof(Int)*MAX_NUM_SAO_CLASSES);
169
170 if(typeIdc == SAO_TYPE_START_BO)
171 {
172 for(Int i=0; i< 4; i++)
173 {
174 dstOffsets[(typeAuxInfo+ i)%NUM_SAO_BO_CLASSES] = codedOffset[(typeAuxInfo+ i)%NUM_SAO_BO_CLASSES]*(1<<m_offsetStepLog2[compIdx]);
175 }
176 }
177 else //EO
178 {
179 for(Int i=0; i< NUM_SAO_EO_CLASSES; i++)
180 {
181 dstOffsets[i] = codedOffset[i] *(1<<m_offsetStepLog2[compIdx]);
182 }
183 assert(dstOffsets[SAO_CLASS_EO_PLAIN] == 0); //keep EO plain offset as zero
184 }
185
186 }
187
getMergeList(TComPic * pic,Int ctuRsAddr,SAOBlkParam * blkParams,SAOBlkParam * mergeList[NUM_SAO_MERGE_TYPES])188 Int TComSampleAdaptiveOffset::getMergeList(TComPic* pic, Int ctuRsAddr, SAOBlkParam* blkParams, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES])
189 {
190 Int ctuX = ctuRsAddr % m_numCTUInWidth;
191 Int ctuY = ctuRsAddr / m_numCTUInWidth;
192 Int mergedCTUPos;
193 Int numValidMergeCandidates = 0;
194
195 for(Int mergeType=0; mergeType< NUM_SAO_MERGE_TYPES; mergeType++)
196 {
197 SAOBlkParam* mergeCandidate = NULL;
198
199 switch(mergeType)
200 {
201 case SAO_MERGE_ABOVE:
202 {
203 if(ctuY > 0)
204 {
205 mergedCTUPos = ctuRsAddr- m_numCTUInWidth;
206 if( pic->getSAOMergeAvailability(ctuRsAddr, mergedCTUPos) )
207 {
208 mergeCandidate = &(blkParams[mergedCTUPos]);
209 }
210 }
211 }
212 break;
213 case SAO_MERGE_LEFT:
214 {
215 if(ctuX > 0)
216 {
217 mergedCTUPos = ctuRsAddr- 1;
218 if( pic->getSAOMergeAvailability(ctuRsAddr, mergedCTUPos) )
219 {
220 mergeCandidate = &(blkParams[mergedCTUPos]);
221 }
222 }
223 }
224 break;
225 default:
226 {
227 printf("not a supported merge type");
228 assert(0);
229 exit(-1);
230 }
231 }
232
233 mergeList[mergeType]=mergeCandidate;
234 if (mergeCandidate != NULL)
235 {
236 numValidMergeCandidates++;
237 }
238 }
239
240 return numValidMergeCandidates;
241 }
242
243
reconstructBlkSAOParam(SAOBlkParam & recParam,SAOBlkParam * mergeList[NUM_SAO_MERGE_TYPES])244 Void TComSampleAdaptiveOffset::reconstructBlkSAOParam(SAOBlkParam& recParam, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES])
245 {
246 const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC);
247 for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++)
248 {
249 const ComponentID component = ComponentID(compIdx);
250 SAOOffset& offsetParam = recParam[component];
251
252 if(offsetParam.modeIdc == SAO_MODE_OFF)
253 {
254 continue;
255 }
256
257 switch(offsetParam.modeIdc)
258 {
259 case SAO_MODE_NEW:
260 {
261 invertQuantOffsets(component, offsetParam.typeIdc, offsetParam.typeAuxInfo, offsetParam.offset, offsetParam.offset);
262 }
263 break;
264 case SAO_MODE_MERGE:
265 {
266 SAOBlkParam* mergeTarget = mergeList[offsetParam.typeIdc];
267 assert(mergeTarget != NULL);
268
269 offsetParam = (*mergeTarget)[component];
270 }
271 break;
272 default:
273 {
274 printf("Not a supported mode");
275 assert(0);
276 exit(-1);
277 }
278 }
279 }
280 }
281
reconstructBlkSAOParams(TComPic * pic,SAOBlkParam * saoBlkParams)282 Void TComSampleAdaptiveOffset::reconstructBlkSAOParams(TComPic* pic, SAOBlkParam* saoBlkParams)
283 {
284 for(Int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++)
285 {
286 m_picSAOEnabled[compIdx] = false;
287 }
288
289 const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC);
290
291 for(Int ctuRsAddr=0; ctuRsAddr< m_numCTUsPic; ctuRsAddr++)
292 {
293 SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES] = { NULL };
294 getMergeList(pic, ctuRsAddr, saoBlkParams, mergeList);
295
296 reconstructBlkSAOParam(saoBlkParams[ctuRsAddr], mergeList);
297
298 for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++)
299 {
300 if(saoBlkParams[ctuRsAddr][compIdx].modeIdc != SAO_MODE_OFF)
301 {
302 m_picSAOEnabled[compIdx] = true;
303 }
304 }
305 }
306 }
307
308
offsetBlock(ComponentID compIdx,Int typeIdx,Int * offset,Pel * srcBlk,Pel * resBlk,Int srcStride,Int resStride,Int width,Int height,Bool isLeftAvail,Bool isRightAvail,Bool isAboveAvail,Bool isBelowAvail,Bool isAboveLeftAvail,Bool isAboveRightAvail,Bool isBelowLeftAvail,Bool isBelowRightAvail)309 Void TComSampleAdaptiveOffset::offsetBlock(ComponentID compIdx, Int typeIdx, Int* offset
310 , Pel* srcBlk, Pel* resBlk, Int srcStride, Int resStride, Int width, Int height
311 , Bool isLeftAvail, Bool isRightAvail, Bool isAboveAvail, Bool isBelowAvail, Bool isAboveLeftAvail, Bool isAboveRightAvail, Bool isBelowLeftAvail, Bool isBelowRightAvail)
312 {
313 if(m_lineBufWidth != m_maxCUWidth)
314 {
315 m_lineBufWidth = m_maxCUWidth;
316
317 if (m_signLineBuf1) delete[] m_signLineBuf1; m_signLineBuf1 = NULL;
318 m_signLineBuf1 = new Char[m_lineBufWidth+1];
319
320 if (m_signLineBuf2) delete[] m_signLineBuf2; m_signLineBuf2 = NULL;
321 m_signLineBuf2 = new Char[m_lineBufWidth+1];
322 }
323
324 const Int maxSampleValueIncl = (1<< g_bitDepth[toChannelType(compIdx)] )-1;
325
326 Int x,y, startX, startY, endX, endY, edgeType;
327 Int firstLineStartX, firstLineEndX, lastLineStartX, lastLineEndX;
328 Char signLeft, signRight, signDown;
329
330 Pel* srcLine = srcBlk;
331 Pel* resLine = resBlk;
332
333 switch(typeIdx)
334 {
335 case SAO_TYPE_EO_0:
336 {
337 offset += 2;
338 startX = isLeftAvail ? 0 : 1;
339 endX = isRightAvail ? width : (width -1);
340 for (y=0; y< height; y++)
341 {
342 signLeft = (Char)sgn(srcLine[startX] - srcLine[startX-1]);
343 for (x=startX; x< endX; x++)
344 {
345 signRight = (Char)sgn(srcLine[x] - srcLine[x+1]);
346 edgeType = signRight + signLeft;
347 signLeft = -signRight;
348
349 resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
350 }
351 srcLine += srcStride;
352 resLine += resStride;
353 }
354
355 }
356 break;
357 case SAO_TYPE_EO_90:
358 {
359 offset += 2;
360 Char *signUpLine = m_signLineBuf1;
361
362 startY = isAboveAvail ? 0 : 1;
363 endY = isBelowAvail ? height : height-1;
364 if (!isAboveAvail)
365 {
366 srcLine += srcStride;
367 resLine += resStride;
368 }
369
370 Pel* srcLineAbove= srcLine- srcStride;
371 for (x=0; x< width; x++)
372 {
373 signUpLine[x] = (Char)sgn(srcLine[x] - srcLineAbove[x]);
374 }
375
376 Pel* srcLineBelow;
377 for (y=startY; y<endY; y++)
378 {
379 srcLineBelow= srcLine+ srcStride;
380
381 for (x=0; x< width; x++)
382 {
383 signDown = (Char)sgn(srcLine[x] - srcLineBelow[x]);
384 edgeType = signDown + signUpLine[x];
385 signUpLine[x]= -signDown;
386
387 resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
388 }
389 srcLine += srcStride;
390 resLine += resStride;
391 }
392
393 }
394 break;
395 case SAO_TYPE_EO_135:
396 {
397 offset += 2;
398 Char *signUpLine, *signDownLine, *signTmpLine;
399
400 signUpLine = m_signLineBuf1;
401 signDownLine= m_signLineBuf2;
402
403 startX = isLeftAvail ? 0 : 1 ;
404 endX = isRightAvail ? width : (width-1);
405
406 //prepare 2nd line's upper sign
407 Pel* srcLineBelow= srcLine+ srcStride;
408 for (x=startX; x< endX+1; x++)
409 {
410 signUpLine[x] = (Char)sgn(srcLineBelow[x] - srcLine[x- 1]);
411 }
412
413 //1st line
414 Pel* srcLineAbove= srcLine- srcStride;
415 firstLineStartX = isAboveLeftAvail ? 0 : 1;
416 firstLineEndX = isAboveAvail? endX: 1;
417 for(x= firstLineStartX; x< firstLineEndX; x++)
418 {
419 edgeType = sgn(srcLine[x] - srcLineAbove[x- 1]) - signUpLine[x+1];
420
421 resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
422 }
423 srcLine += srcStride;
424 resLine += resStride;
425
426
427 //middle lines
428 for (y= 1; y< height-1; y++)
429 {
430 srcLineBelow= srcLine+ srcStride;
431
432 for (x=startX; x<endX; x++)
433 {
434 signDown = (Char)sgn(srcLine[x] - srcLineBelow[x+ 1]);
435 edgeType = signDown + signUpLine[x];
436 resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
437
438 signDownLine[x+1] = -signDown;
439 }
440 signDownLine[startX] = (Char)sgn(srcLineBelow[startX] - srcLine[startX-1]);
441
442 signTmpLine = signUpLine;
443 signUpLine = signDownLine;
444 signDownLine = signTmpLine;
445
446 srcLine += srcStride;
447 resLine += resStride;
448 }
449
450 //last line
451 srcLineBelow= srcLine+ srcStride;
452 lastLineStartX = isBelowAvail ? startX : (width -1);
453 lastLineEndX = isBelowRightAvail ? width : (width -1);
454 for(x= lastLineStartX; x< lastLineEndX; x++)
455 {
456 edgeType = sgn(srcLine[x] - srcLineBelow[x+ 1]) + signUpLine[x];
457 resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
458
459 }
460 }
461 break;
462 case SAO_TYPE_EO_45:
463 {
464 offset += 2;
465 Char *signUpLine = m_signLineBuf1+1;
466
467 startX = isLeftAvail ? 0 : 1;
468 endX = isRightAvail ? width : (width -1);
469
470 //prepare 2nd line upper sign
471 Pel* srcLineBelow= srcLine+ srcStride;
472 for (x=startX-1; x< endX; x++)
473 {
474 signUpLine[x] = (Char)sgn(srcLineBelow[x] - srcLine[x+1]);
475 }
476
477
478 //first line
479 Pel* srcLineAbove= srcLine- srcStride;
480 firstLineStartX = isAboveAvail ? startX : (width -1 );
481 firstLineEndX = isAboveRightAvail ? width : (width-1);
482 for(x= firstLineStartX; x< firstLineEndX; x++)
483 {
484 edgeType = sgn(srcLine[x] - srcLineAbove[x+1]) -signUpLine[x-1];
485 resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
486 }
487 srcLine += srcStride;
488 resLine += resStride;
489
490 //middle lines
491 for (y= 1; y< height-1; y++)
492 {
493 srcLineBelow= srcLine+ srcStride;
494
495 for(x= startX; x< endX; x++)
496 {
497 signDown = (Char)sgn(srcLine[x] - srcLineBelow[x-1]);
498 edgeType = signDown + signUpLine[x];
499 resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
500 signUpLine[x-1] = -signDown;
501 }
502 signUpLine[endX-1] = (Char)sgn(srcLineBelow[endX-1] - srcLine[endX]);
503 srcLine += srcStride;
504 resLine += resStride;
505 }
506
507 //last line
508 srcLineBelow= srcLine+ srcStride;
509 lastLineStartX = isBelowLeftAvail ? 0 : 1;
510 lastLineEndX = isBelowAvail ? endX : 1;
511 for(x= lastLineStartX; x< lastLineEndX; x++)
512 {
513 edgeType = sgn(srcLine[x] - srcLineBelow[x-1]) + signUpLine[x];
514 resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[edgeType]);
515
516 }
517 }
518 break;
519 case SAO_TYPE_BO:
520 {
521 const Int shiftBits = g_bitDepth[toChannelType(compIdx)] - NUM_SAO_BO_CLASSES_LOG2;
522 for (y=0; y< height; y++)
523 {
524 for (x=0; x< width; x++)
525 {
526 resLine[x] = Clip3<Int>(0, maxSampleValueIncl, srcLine[x] + offset[srcLine[x] >> shiftBits] );
527 }
528 srcLine += srcStride;
529 resLine += resStride;
530 }
531 }
532 break;
533 default:
534 {
535 printf("Not a supported SAO types\n");
536 assert(0);
537 exit(-1);
538 }
539 }
540 }
541
offsetCTU(Int ctuRsAddr,TComPicYuv * srcYuv,TComPicYuv * resYuv,SAOBlkParam & saoblkParam,TComPic * pPic)542 Void TComSampleAdaptiveOffset::offsetCTU(Int ctuRsAddr, TComPicYuv* srcYuv, TComPicYuv* resYuv, SAOBlkParam& saoblkParam, TComPic* pPic)
543 {
544 Bool isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail;
545
546 const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC);
547 Bool bAllOff=true;
548 for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++)
549 {
550 if (saoblkParam[compIdx].modeIdc != SAO_MODE_OFF) bAllOff=false;
551 }
552 if (bAllOff) return;
553
554 //block boundary availability
555 pPic->getPicSym()->deriveLoopFilterBoundaryAvailibility(ctuRsAddr, isLeftAvail,isRightAvail,isAboveAvail,isBelowAvail,isAboveLeftAvail,isAboveRightAvail,isBelowLeftAvail,isBelowRightAvail);
556
557 Int yPos = (ctuRsAddr / m_numCTUInWidth)*m_maxCUHeight;
558 Int xPos = (ctuRsAddr % m_numCTUInWidth)*m_maxCUWidth;
559 Int height = (yPos + m_maxCUHeight > m_picHeight)?(m_picHeight- yPos):m_maxCUHeight;
560 Int width = (xPos + m_maxCUWidth > m_picWidth )?(m_picWidth - xPos):m_maxCUWidth;
561
562 for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++)
563 {
564 const ComponentID component = ComponentID(compIdx);
565 SAOOffset& ctbOffset = saoblkParam[compIdx];
566
567 if(ctbOffset.modeIdc != SAO_MODE_OFF)
568 {
569 const UInt componentScaleX = getComponentScaleX(component, pPic->getChromaFormat());
570 const UInt componentScaleY = getComponentScaleY(component, pPic->getChromaFormat());
571
572 Int blkWidth = (width >> componentScaleX);
573 Int blkHeight = (height >> componentScaleY);
574 Int blkXPos = (xPos >> componentScaleX);
575 Int blkYPos = (yPos >> componentScaleY);
576
577 Int srcStride = srcYuv->getStride(component);
578 Pel* srcBlk = srcYuv->getAddr(component) + blkYPos*srcStride + blkXPos;
579
580 Int resStride = resYuv->getStride(component);
581 Pel* resBlk = resYuv->getAddr(component) + blkYPos*resStride + blkXPos;
582
583 offsetBlock( component, ctbOffset.typeIdc, ctbOffset.offset
584 , srcBlk, resBlk, srcStride, resStride, blkWidth, blkHeight
585 , isLeftAvail, isRightAvail
586 , isAboveAvail, isBelowAvail
587 , isAboveLeftAvail, isAboveRightAvail
588 , isBelowLeftAvail, isBelowRightAvail
589 );
590 }
591 } //compIdx
592
593 }
594
595
SAOProcess(TComPic * pDecPic)596 Void TComSampleAdaptiveOffset::SAOProcess(TComPic* pDecPic)
597 {
598 const Int numberOfComponents = getNumberValidComponents(m_chromaFormatIDC);
599 Bool bAllDisabled=true;
600 for(Int compIdx = 0; compIdx < numberOfComponents; compIdx++)
601 {
602 if (m_picSAOEnabled[compIdx]) bAllDisabled=false;
603 }
604 if (bAllDisabled) return;
605
606 TComPicYuv* resYuv = pDecPic->getPicYuvRec();
607 TComPicYuv* srcYuv = m_tempPicYuv;
608 resYuv->copyToPic(srcYuv);
609 for(Int ctuRsAddr= 0; ctuRsAddr < m_numCTUsPic; ctuRsAddr++)
610 {
611 offsetCTU(ctuRsAddr, srcYuv, resYuv, (pDecPic->getPicSym()->getSAOBlkParam())[ctuRsAddr], pDecPic);
612 } //ctu
613 }
614
615
616 /** PCM LF disable process.
617 * \param pcPic picture (TComPic) pointer
618 * \returns Void
619 *
620 * \note Replace filtered sample values of PCM mode blocks with the transmitted and reconstructed ones.
621 */
PCMLFDisableProcess(TComPic * pcPic)622 Void TComSampleAdaptiveOffset::PCMLFDisableProcess (TComPic* pcPic)
623 {
624 xPCMRestoration(pcPic);
625 }
626
627 /** Picture-level PCM restoration.
628 * \param pcPic picture (TComPic) pointer
629 * \returns Void
630 */
xPCMRestoration(TComPic * pcPic)631 Void TComSampleAdaptiveOffset::xPCMRestoration(TComPic* pcPic)
632 {
633 Bool bPCMFilter = (pcPic->getSlice(0)->getSPS()->getUsePCM() && pcPic->getSlice(0)->getSPS()->getPCMFilterDisableFlag())? true : false;
634
635 if(bPCMFilter || pcPic->getSlice(0)->getPPS()->getTransquantBypassEnableFlag())
636 {
637 for( UInt ctuRsAddr = 0; ctuRsAddr < pcPic->getNumberOfCtusInFrame() ; ctuRsAddr++ )
638 {
639 TComDataCU* pcCU = pcPic->getCtu(ctuRsAddr);
640
641 xPCMCURestoration(pcCU, 0, 0);
642 }
643 }
644 }
645
646 /** PCM CU restoration.
647 * \param pcCU pointer to current CU
648 * \param uiAbsPartIdx part index
649 * \param uiDepth CU depth
650 * \returns Void
651 */
xPCMCURestoration(TComDataCU * pcCU,UInt uiAbsZorderIdx,UInt uiDepth)652 Void TComSampleAdaptiveOffset::xPCMCURestoration ( TComDataCU* pcCU, UInt uiAbsZorderIdx, UInt uiDepth )
653 {
654 TComPic* pcPic = pcCU->getPic();
655 UInt uiCurNumParts = pcPic->getNumPartitionsInCtu() >> (uiDepth<<1);
656 UInt uiQNumParts = uiCurNumParts>>2;
657
658 // go to sub-CU
659 if( pcCU->getDepth(uiAbsZorderIdx) > uiDepth )
660 {
661 for ( UInt uiPartIdx = 0; uiPartIdx < 4; uiPartIdx++, uiAbsZorderIdx+=uiQNumParts )
662 {
663 UInt uiLPelX = pcCU->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsZorderIdx] ];
664 UInt uiTPelY = pcCU->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsZorderIdx] ];
665 if( ( uiLPelX < pcCU->getSlice()->getSPS()->getPicWidthInLumaSamples() ) && ( uiTPelY < pcCU->getSlice()->getSPS()->getPicHeightInLumaSamples() ) )
666 xPCMCURestoration( pcCU, uiAbsZorderIdx, uiDepth+1 );
667 }
668 return;
669 }
670
671 // restore PCM samples
672 if ((pcCU->getIPCMFlag(uiAbsZorderIdx)&& pcPic->getSlice(0)->getSPS()->getPCMFilterDisableFlag()) || pcCU->isLosslessCoded( uiAbsZorderIdx))
673 {
674 const UInt numComponents=pcPic->getNumberValidComponents();
675 for(UInt comp=0; comp<numComponents; comp++)
676 {
677 xPCMSampleRestoration (pcCU, uiAbsZorderIdx, uiDepth, ComponentID(comp));
678 }
679 }
680 }
681
682 /** PCM sample restoration.
683 * \param pcCU pointer to current CU
684 * \param uiAbsPartIdx part index
685 * \param uiDepth CU depth
686 * \param ttText texture component type
687 * \returns Void
688 */
xPCMSampleRestoration(TComDataCU * pcCU,UInt uiAbsZorderIdx,UInt uiDepth,const ComponentID compID)689 Void TComSampleAdaptiveOffset::xPCMSampleRestoration (TComDataCU* pcCU, UInt uiAbsZorderIdx, UInt uiDepth, const ComponentID compID)
690 {
691 TComPicYuv* pcPicYuvRec = pcCU->getPic()->getPicYuvRec();
692 UInt uiPcmLeftShiftBit;
693 const UInt uiMinCoeffSize = pcCU->getPic()->getMinCUWidth()*pcCU->getPic()->getMinCUHeight();
694 const UInt csx=pcPicYuvRec->getComponentScaleX(compID);
695 const UInt csy=pcPicYuvRec->getComponentScaleY(compID);
696 const UInt uiOffset = (uiMinCoeffSize*uiAbsZorderIdx)>>(csx+csy);
697
698 Pel *piSrc = pcPicYuvRec->getAddr(compID, pcCU->getCtuRsAddr(), uiAbsZorderIdx);
699 const Pel *piPcm = pcCU->getPCMSample(compID) + uiOffset;
700 const UInt uiStride = pcPicYuvRec->getStride(compID);
701 const UInt uiWidth = ((g_uiMaxCUWidth >> uiDepth) >> csx);
702 const UInt uiHeight = ((g_uiMaxCUWidth >> uiDepth) >> csy);
703
704 if ( pcCU->isLosslessCoded(uiAbsZorderIdx) && !pcCU->getIPCMFlag(uiAbsZorderIdx) )
705 {
706 uiPcmLeftShiftBit = 0;
707 }
708 else
709 {
710 uiPcmLeftShiftBit = g_bitDepth[toChannelType(compID)] - pcCU->getSlice()->getSPS()->getPCMBitDepth(toChannelType(compID));
711 }
712
713 for(UInt uiY = 0; uiY < uiHeight; uiY++ )
714 {
715 for(UInt uiX = 0; uiX < uiWidth; uiX++ )
716 {
717 piSrc[uiX] = (piPcm[uiX] << uiPcmLeftShiftBit);
718 }
719 piPcm += uiWidth;
720 piSrc += uiStride;
721 }
722 }
723
724 //! \}
725