1 /* -----------------------------------------------------------------------------
2 The copyright in this software is being made available under the BSD
3 License, included below. No patent rights, trademark rights and/or
4 other Intellectual Property Rights other than the copyrights concerning
5 the Software are granted under this license.
6
7 For any license concerning other Intellectual Property rights than the software,
8 especially patent licenses, a separate Agreement needs to be closed.
9 For more information please contact:
10
11 Fraunhofer Heinrich Hertz Institute
12 Einsteinufer 37
13 10587 Berlin, Germany
14 www.hhi.fraunhofer.de/vvc
15 vvc@hhi.fraunhofer.de
16
17 Copyright (c) 2018-2021, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V.
18 All rights reserved.
19
20 Redistribution and use in source and binary forms, with or without
21 modification, are permitted provided that the following conditions are met:
22
23 * Redistributions of source code must retain the above copyright notice,
24 this list of conditions and the following disclaimer.
25 * Redistributions in binary form must reproduce the above copyright notice,
26 this list of conditions and the following disclaimer in the documentation
27 and/or other materials provided with the distribution.
28 * Neither the name of Fraunhofer nor the names of its contributors may
29 be used to endorse or promote products derived from this software without
30 specific prior written permission.
31
32 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
33 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
36 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
37 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
38 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
40 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
42 THE POSSIBILITY OF SUCH DAMAGE.
43
44
45 ------------------------------------------------------------------------------------------- */
46
47 /** \file Reshape.cpp
48 \brief common reshaper class
49 */
50 #include "Reshape.h"
51 #include <stdio.h>
52 #include <string.h>
53 #include <math.h>
54 #include <UnitTools.h>
55 #include "CommonLib/TimeProfiler.h"
56
57 namespace vvdec
58 {
59
60 // ====================================================================================================================
61 // Constructor / destructor / create / destroy
62 // ====================================================================================================================
63
Reshape()64 Reshape::Reshape()
65 {
66 m_fwdLUT = nullptr;
67 m_invLUT = nullptr;
68 m_chromaScale = 1 << CSCALE_FP_PREC;
69 m_vpduX = -1;
70 m_vpduY = -1;
71 }
72
~Reshape()73 Reshape::~Reshape()
74 {
75 destroy();
76 }
77
createDec(int bitDepth)78 void Reshape::createDec(int bitDepth)
79 {
80 m_lumaBD = bitDepth;
81 m_reshapeLUTSize = 1 << m_lumaBD;
82 m_initCW = m_reshapeLUTSize / PIC_CODE_CW_BINS;
83 if( !m_fwdLUT )
84 {
85 m_fwdLUT = ( Pel* ) xMalloc( Pel, m_reshapeLUTSize + 1 );
86 memset( m_fwdLUT, 0, ( m_reshapeLUTSize + 1 ) * sizeof( Pel ) );
87 }
88 if( !m_invLUT )
89 {
90 m_invLUT = ( Pel* ) xMalloc( Pel, m_reshapeLUTSize + 1 );
91 memset( m_invLUT, 0, ( m_reshapeLUTSize + 1 ) * sizeof( Pel ) );
92 }
93 if (m_binCW.empty())
94 m_binCW.resize(PIC_CODE_CW_BINS, 0);
95 if (m_inputPivot.empty())
96 m_inputPivot.resize(PIC_CODE_CW_BINS + 1, 0);
97 if (m_fwdScaleCoef.empty())
98 m_fwdScaleCoef.resize(PIC_CODE_CW_BINS, 1 << FP_PREC);
99 if (m_invScaleCoef.empty())
100 m_invScaleCoef.resize(PIC_CODE_CW_BINS, 1 << FP_PREC);
101 if (m_reshapePivot.empty())
102 m_reshapePivot.resize(PIC_CODE_CW_BINS + 1, 0);
103 if (m_chromaAdjHelpLUT.empty())
104 m_chromaAdjHelpLUT.resize(PIC_CODE_CW_BINS, 1<<CSCALE_FP_PREC);
105 }
106
destroy()107 void Reshape::destroy()
108 {
109 xFree( m_fwdLUT );
110 m_fwdLUT = nullptr;
111 xFree( m_invLUT );
112 m_invLUT = nullptr;
113 }
114
initSlice(int nalUnitLayerId,const PicHeader & picHeader,const VPS & vps)115 void Reshape::initSlice( int nalUnitLayerId, const PicHeader& picHeader, const VPS& vps )
116 {
117 if( picHeader.getLmcsEnabledFlag() )
118 {
119 if( nalUnitLayerId != picHeader.getLmcsAPS()->getLayerId() )
120 {
121 for (int i = 0; i < vps.getNumOutputLayerSets(); i++ )
122 {
123 bool isCurrLayerInOls = false;
124 bool isRefLayerInOls = false;
125 for( int j = vps.getNumLayersInOls(i) - 1; j >= 0; j-- )
126 {
127 if( vps.getLayerIdInOls(i, j) == nalUnitLayerId )
128 {
129 isCurrLayerInOls = true;
130 }
131 if( vps.getLayerIdInOls(i, j) == picHeader.getLmcsAPS()->getLayerId() )
132 {
133 isRefLayerInOls = true;
134 }
135 }
136 CHECK( isCurrLayerInOls && !isRefLayerInOls, "When VCL NAl unit in layer A refers to APS in layer B, all OLS that contains layer A shall also contains layer B" );
137 }
138 }
139
140 SliceReshapeInfo& sInfo = picHeader.getLmcsAPS()->getReshaperAPSInfo();
141 m_sliceReshapeInfo.sliceReshaperEnableFlag = true;
142 m_sliceReshapeInfo.sliceReshaperModelPresentFlag = true;
143 m_sliceReshapeInfo.enableChromaAdj = picHeader.getLmcsChromaResidualScaleFlag();
144 m_sliceReshapeInfo.reshaperModelMaxBinIdx = sInfo.reshaperModelMaxBinIdx;
145 m_sliceReshapeInfo.reshaperModelMinBinIdx = sInfo.reshaperModelMinBinIdx;
146 m_sliceReshapeInfo.maxNbitsNeededDeltaCW = sInfo.maxNbitsNeededDeltaCW;
147 m_sliceReshapeInfo.chrResScalingOffset = sInfo.chrResScalingOffset;
148 memcpy( m_sliceReshapeInfo.reshaperModelBinCWDelta, sInfo.reshaperModelBinCWDelta, sizeof( int ) * ( PIC_CODE_CW_BINS ) );
149 constructReshaper();
150 }
151 else
152 {
153 m_sliceReshapeInfo.sliceReshaperEnableFlag = false;
154 m_sliceReshapeInfo.enableChromaAdj = false;
155 m_sliceReshapeInfo.sliceReshaperModelPresentFlag = false;
156 }
157 m_vpduX = -1;
158 m_vpduY = -1;
159 }
160
getCTUFlag(const Slice & slice) const161 bool Reshape::getCTUFlag( const Slice& slice ) const
162 {
163 if( (slice.getSliceType() == I_SLICE) && m_sliceReshapeInfo.sliceReshaperEnableFlag )
164 {
165 return false;
166 }
167 else
168 {
169 return m_sliceReshapeInfo.sliceReshaperEnableFlag;
170 }
171 }
172
rspLine(CodingStructure & cs,int ln,const int offset) const173 void Reshape::rspLine( CodingStructure &cs, int ln, const int offset ) const
174 {
175 if( !( cs.sps->getUseReshaper() && m_sliceReshapeInfo.sliceReshaperEnableFlag ) )
176 {
177 return;
178 }
179 PROFILER_SCOPE_AND_STAGE_EXT( 1, g_timeProfiler, P_RESHAPER, cs, CH_L );
180
181 const PreCalcValues &pcv = *cs.pcv;
182
183 const bool firstLine = ln == 0;
184
185 // const int lh = frstLine ? pcv.maxCUHeight + ( offset ) : pcv.maxCUHeight;
186
187 int lw = pcv.lumaWidth;
188 int yPos = firstLine ? 0 : ln * pcv.maxCUHeight + offset;
189 int lh = firstLine ? pcv.maxCUHeight + offset : std::min( pcv.lumaHeight - yPos, pcv.maxCUHeight );
190 PelBuf picYuvRec = cs.getRecoBuf( COMPONENT_Y ).subBuf( Position( 0, yPos ), Size( lw, lh ) );
191 picYuvRec.rspSignal( m_invLUT );
192 }
193
rspCtu(CodingStructure & cs,int col,int ln,const int offset) const194 void Reshape::rspCtu( CodingStructure &cs, int col, int ln, const int offset ) const
195 {
196 if( !( cs.sps->getUseReshaper() && m_sliceReshapeInfo.sliceReshaperEnableFlag ) )
197 {
198 return;
199 }
200
201 const Slice* slice = cs.getCtuData( col, ln ).cuPtr[0][0]->slice;
202 if( !slice->getLmcsEnabledFlag() )
203
204 {
205 return;
206 }
207
208 PROFILER_SCOPE_AND_STAGE_EXT( 1, g_timeProfiler, P_RESHAPER, cs, CH_L );
209
210 const PreCalcValues &pcv = *cs.pcv;
211
212 const bool firstLine = ln == 0;
213
214 // const int lh = frstLine ? pcv.maxCUHeight + ( offset ) : pcv.maxCUHeight;
215
216 int xPos = pcv.maxCUWidth * col;
217 int lw = std::min( pcv.lumaWidth - xPos, pcv.maxCUWidth );
218
219 int yPos = firstLine ? 0 : ln * pcv.maxCUHeight + offset;
220 int lh = firstLine ? pcv.maxCUHeight + offset : std::min( pcv.lumaHeight - yPos, pcv.maxCUHeight );
221
222 PelBuf picYuvRec = cs.getRecoBuf( COMPONENT_Y ).subBuf( Position( xPos, yPos ), Size( lw, lh ) );
223 picYuvRec.rspSignal( m_invLUT );
224 }
225
226
227
228 /** compute chroma residuce scale for TU
229 * \param average luma pred of TU
230 * \return chroma residue scale
231 */
calculateChromaAdj(Pel avgLuma) const232 int Reshape::calculateChromaAdj(Pel avgLuma) const
233 {
234 int iAdj = m_chromaAdjHelpLUT[getPWLIdxInv(avgLuma)];
235 return(iAdj);
236 }
237
238 /** compute chroma residuce scale for TU
239 * \param average luma pred of TU
240 * \return chroma residue scale
241 */
calculateChromaAdjVpduNei(TransformUnit & tu,const Position pos)242 int Reshape::calculateChromaAdjVpduNei(TransformUnit &tu, const Position pos)
243 {
244 CodingStructure &cs = *tu.cu->cs;
245 int xPos = pos.x;
246 int yPos = pos.y;
247 int ctuSize = cs.sps->getCTUSize();
248 int numNeighbor = std::min(64, ctuSize);
249 int numNeighborLog = getLog2(numNeighbor);
250 if (ctuSize == 128)
251 {
252 xPos &= ~63;
253 yPos &= ~63;
254 }
255 else
256 {
257 xPos &= ~( ctuSize - 1 );
258 yPos &= ~( ctuSize - 1 );
259 }
260
261 if( isVPDUprocessed( xPos, yPos ) )
262 {
263 return getChromaScale();
264 }
265 else
266 {
267 setVPDULoc(xPos, yPos);
268 Position topLeft(xPos, yPos);
269 CodingUnit *topLeftLuma;
270 const CodingUnit *cuAbove, *cuLeft;
271
272 topLeftLuma = cs.getCU( topLeft, CHANNEL_TYPE_LUMA );
273 cuAbove = cs.getCURestricted( topLeftLuma->lumaPos().offset( 0, -1 ), *topLeftLuma, CHANNEL_TYPE_LUMA, topLeftLuma->ly() == yPos ? topLeftLuma : topLeftLuma->above );
274 cuLeft = cs.getCURestricted( topLeftLuma->lumaPos().offset( -1, 0 ), *topLeftLuma, CHANNEL_TYPE_LUMA, topLeftLuma->lx() == xPos ? topLeftLuma : topLeftLuma->left );
275
276 xPos = topLeftLuma->lumaPos().x;
277 yPos = topLeftLuma->lumaPos().y;
278
279 CompArea lumaArea = CompArea(COMPONENT_Y, topLeftLuma->lumaPos(), topLeftLuma->lumaSize());
280 PelBuf piRecoY = cs.picture->getRecoBuf(lumaArea);
281 ptrdiff_t strideY = piRecoY.stride;
282 int chromaScale = (1 << CSCALE_FP_PREC);
283 int lumaValue = -1;
284
285 Pel* recSrc0 = piRecoY.bufAt(0, 0);
286 const uint32_t picH = tu.cu->cs->picture->lheight();
287 const uint32_t picW = tu.cu->cs->picture->lwidth();
288 const Pel valueDC = 1 << (tu.cu->sps->getBitDepth(CHANNEL_TYPE_LUMA) - 1);
289 int32_t recLuma = 0;
290 int pelnum = 0;
291 if (cuLeft != nullptr)
292 {
293 for (int i = 0; i < numNeighbor; i++)
294 {
295 int k = (yPos + i) >= picH ? (picH - yPos - 1) : i;
296 recLuma += recSrc0[-1 + k * strideY];
297 pelnum++;
298 }
299 }
300 if (cuAbove != nullptr)
301 {
302 for (int i = 0; i < numNeighbor; i++)
303 {
304 int k = (xPos + i) >= picW ? (picW - xPos - 1) : i;
305 recLuma += recSrc0[-strideY + k];
306 pelnum++;
307 }
308 }
309 if (pelnum == numNeighbor)
310 {
311 lumaValue = (recLuma + (1 << (numNeighborLog - 1))) >> numNeighborLog;
312 }
313 else if (pelnum == (numNeighbor << 1))
314 {
315 lumaValue = (recLuma + (1 << numNeighborLog)) >> (numNeighborLog + 1);
316 }
317 else
318 {
319 CHECK(pelnum != 0, "");
320 lumaValue = valueDC;
321 }
322 chromaScale = calculateChromaAdj(lumaValue);
323 setChromaScale(chromaScale);
324 return(chromaScale);
325 }
326 }
327 /** find inx of PWL for inverse mapping
328 * \param average luma pred of TU
329 * \return idx of PWL for inverse mapping
330 */
getPWLIdxInv(int lumaVal) const331 int Reshape::getPWLIdxInv(int lumaVal) const
332 {
333 int idxS = 0;
334 for (idxS = m_sliceReshapeInfo.reshaperModelMinBinIdx; (idxS <= m_sliceReshapeInfo.reshaperModelMaxBinIdx); idxS++)
335 {
336 if (lumaVal < m_reshapePivot[idxS + 1]) break;
337 }
338 return std::min(idxS, PIC_CODE_CW_BINS-1);
339 }
340
341 /**
342 -copy Slice reshaper info structure
343 \param tInfo describing the target Slice reshaper info structure
344 \param sInfo describing the source Slice reshaper info structure
345 */
copySliceReshaperInfo(SliceReshapeInfo & tInfo,SliceReshapeInfo & sInfo)346 void Reshape::copySliceReshaperInfo(SliceReshapeInfo& tInfo, SliceReshapeInfo& sInfo)
347 {
348 tInfo.sliceReshaperModelPresentFlag = sInfo.sliceReshaperModelPresentFlag;
349 if (sInfo.sliceReshaperModelPresentFlag)
350 {
351 tInfo.reshaperModelMaxBinIdx = sInfo.reshaperModelMaxBinIdx;
352 tInfo.reshaperModelMinBinIdx = sInfo.reshaperModelMinBinIdx;
353 memcpy(tInfo.reshaperModelBinCWDelta, sInfo.reshaperModelBinCWDelta, sizeof(int)*(PIC_CODE_CW_BINS));
354 tInfo.maxNbitsNeededDeltaCW = sInfo.maxNbitsNeededDeltaCW;
355 tInfo.chrResScalingOffset = sInfo.chrResScalingOffset;
356 }
357 tInfo.sliceReshaperEnableFlag = sInfo.sliceReshaperEnableFlag;
358 if (sInfo.sliceReshaperEnableFlag)
359 tInfo.enableChromaAdj = sInfo.enableChromaAdj;
360 else
361 tInfo.enableChromaAdj = 0;
362 }
363
364 /** Construct reshaper from syntax
365 * \param void
366 * \return void
367 */
constructReshaper()368 void Reshape::constructReshaper()
369 {
370 int pwlFwdLUTsize = PIC_CODE_CW_BINS;
371 int pwlFwdBinLen = m_reshapeLUTSize / PIC_CODE_CW_BINS;
372
373 for (int i = 0; i < m_sliceReshapeInfo.reshaperModelMinBinIdx; i++)
374 m_binCW[i] = 0;
375 for (int i = m_sliceReshapeInfo.reshaperModelMaxBinIdx + 1; i < PIC_CODE_CW_BINS; i++)
376 m_binCW[i] = 0;
377 for (int i = m_sliceReshapeInfo.reshaperModelMinBinIdx; i <= m_sliceReshapeInfo.reshaperModelMaxBinIdx; i++)
378 m_binCW[i] = (uint16_t)(m_sliceReshapeInfo.reshaperModelBinCWDelta[i] + (int)m_initCW);
379
380 for (int i = 0; i < pwlFwdLUTsize; i++)
381 {
382 m_reshapePivot[i + 1] = m_reshapePivot[i] + m_binCW[i];
383 m_inputPivot[i + 1] = m_inputPivot[i] + m_initCW;
384 m_fwdScaleCoef[i] = ((int32_t)m_binCW[i] * (1 << FP_PREC) + (1 << (getLog2(pwlFwdBinLen) - 1))) >> getLog2(pwlFwdBinLen);
385 if (m_binCW[i] == 0)
386 {
387 m_invScaleCoef[i] = 0;
388 m_chromaAdjHelpLUT[i] = 1 << CSCALE_FP_PREC;
389 }
390 else
391 {
392 m_invScaleCoef[i] = (int32_t)(m_initCW * (1 << FP_PREC) / m_binCW[i]);
393 m_chromaAdjHelpLUT[i] = (int32_t)(m_initCW * (1 << FP_PREC) / ( m_binCW[i] + m_sliceReshapeInfo.chrResScalingOffset ) );
394 }
395 }
396 for (int lumaSample = 0; lumaSample < m_reshapeLUTSize; lumaSample++)
397 {
398 int idxY = lumaSample / m_initCW;
399 int tempVal = m_reshapePivot[idxY] + ((m_fwdScaleCoef[idxY] * (lumaSample - m_inputPivot[idxY]) + (1 << (FP_PREC - 1))) >> FP_PREC);
400 m_fwdLUT[lumaSample] = Clip3((Pel)0, (Pel)((1 << m_lumaBD) - 1), (Pel)(tempVal));
401
402 int idxYInv = getPWLIdxInv(lumaSample);
403 int invSample = m_inputPivot[idxYInv] + ((m_invScaleCoef[idxYInv] * (lumaSample - m_reshapePivot[idxYInv]) + (1 << (FP_PREC - 1))) >> FP_PREC);
404 m_invLUT[lumaSample] = Clip3((Pel)0, (Pel)((1 << m_lumaBD) - 1), (Pel)(invSample));
405 }
406 }
407
408 }
409