Coverage Report

Created: 2026-10-28 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvenc/source/Lib/EncoderLib/EncPicture.cpp
Line
Count
Source
1
/* -----------------------------------------------------------------------------
2
The copyright in this software is being made available under the Clear 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
The Clear BSD License
8
9
Copyright (c) 2019-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVenC Authors.
10
All rights reserved.
11
12
Redistribution and use in source and binary forms, with or without modification,
13
are permitted (subject to the limitations in the disclaimer below) provided that
14
the following conditions are met:
15
16
     * Redistributions of source code must retain the above copyright notice,
17
     this list of conditions and the following disclaimer.
18
19
     * Redistributions in binary form must reproduce the above copyright
20
     notice, this list of conditions and the following disclaimer in the
21
     documentation and/or other materials provided with the distribution.
22
23
     * Neither the name of the copyright holder nor the names of its
24
     contributors may be used to endorse or promote products derived from this
25
     software without specific prior written permission.
26
27
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
28
THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
29
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
31
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
32
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
34
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
35
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
36
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38
POSSIBILITY OF SUCH DAMAGE.
39
40
41
------------------------------------------------------------------------------------------- */
42
43
44
/** \file     EncPicture.cpp
45
    \brief    encode picture
46
*/
47
48
#include "EncPicture.h"
49
#include "EncGOP.h"
50
#include "CommonLib/UnitTools.h"
51
#include "CommonLib/CommonDef.h"
52
#include "CommonLib/dtrace_buffer.h"
53
#include "CommonLib/dtrace_codingstruct.h"
54
55
//! \ingroup EncoderLib
56
//! \{
57
58
namespace vvenc {
59
60
#ifdef TRACE_ENABLE_ITT
61
static __itt_string_handle* itt_handle_start = __itt_string_handle_create( "PicEnc" );
62
static __itt_domain* itt_domain_picEncoder   = __itt_domain_create( "PictureEncoder" );
63
#endif
64
65
// ---------------------------------------------------------------------------------------------------------------------
66
67
void EncPicture::init( const VVEncCfg& encCfg,
68
                       std::vector<int>* const globalCtuQpVector,
69
                       const SPS& sps,
70
                       const PPS& pps,
71
                       RateCtrl& rateCtrl,
72
                       NoMallocThreadPool* threadPool,
73
                       ThreadRsrcPool& threadRsrc )
74
5.97k
{
75
5.97k
  m_pcEncCfg = &encCfg;
76
77
5.97k
  if( encCfg.m_alf || encCfg.m_ccalf )
78
5.97k
    m_ALF       .init( encCfg, pps, m_CABACEstimator, m_CtxCache, threadPool );
79
80
5.97k
  m_SliceEncoder.init( encCfg, sps, pps, globalCtuQpVector, m_LoopFilter, m_ALF, rateCtrl, threadPool, threadRsrc, &m_ctuTasksDoneCounter );
81
5.97k
  m_pcRateCtrl = &rateCtrl;
82
5.97k
}
83
84
85
void EncPicture::compressPicture( Picture& pic, EncGOP& gopEncoder )
86
1.49k
{
87
1.49k
  PROFILER_SCOPE_TOP_LEVEL_EXT( 1, g_timeProfiler, P_TOP_LEVEL, pic.cs );
88
1.49k
  ITT_TASKSTART( itt_domain_picEncoder, itt_handle_start );
89
90
1.49k
  pic.encTime.startTimer();
91
92
1.49k
  pic.createEncodingBuffers();
93
  // Reserve the picture-level CU and TU lists for one unit per 4x4 block, which avoids growing them
94
  // while the CTU results are appended. They are only needed while the picture is encoded, and
95
  // finalizePicture releases them.
96
1.49k
  pic.cs->allocateVectorsAtPicLevel();
97
1.49k
  pic.cs->createCoeffs();
98
1.49k
  pic.cs->createTempBuffers( true );
99
1.49k
  pic.cs->initStructData( MAX_INT, false, nullptr );
100
101
  // compress picture
102
1.49k
  xInitPicEncoder( pic );
103
104
  // compress current slice
105
1.49k
  pic.cs->slice = pic.slices[0];
106
1.49k
  std::fill( pic.ctuSlice.begin(), pic.ctuSlice.end(), pic.slices[0] );
107
1.49k
  m_SliceEncoder.compressSlice( &pic );
108
109
1.49k
  ITT_TASKEND( itt_domain_picEncoder, itt_handle_start );
110
1.49k
}
111
112
void EncPicture::finalizePicture( Picture& pic )
113
1.49k
{
114
1.49k
  PROFILER_SCOPE_TOP_LEVEL_EXT( 1, g_timeProfiler, P_TOP_LEVEL, pic.cs );
115
1.49k
  CodingStructure& cs = *(pic.cs);
116
1.49k
  Slice* slice        = pic.slices[0];
117
  // ALF
118
1.49k
  if( slice->sps->alfEnabled )
119
1.49k
  {
120
#ifdef TRACE_ENABLE_ITT
121
    std::stringstream ss;
122
    ss << "ALF_post_" << slice->poc;
123
    __itt_string_handle* itt_handle_post = __itt_string_handle_create( ss.str().c_str() );
124
#endif
125
1.49k
    pic.picApsMap.setApsIdStart( m_ALF.getApsIdStart() );
126
127
1.49k
    cs.slice->ccAlfFilterParam      = m_ALF.getCcAlfFilterParam();
128
1.49k
    cs.slice->ccAlfFilterControl[0] = m_ALF.getCcAlfControlIdc(COMP_Cb);
129
1.49k
    cs.slice->ccAlfFilterControl[1] = m_ALF.getCcAlfControlIdc(COMP_Cr);
130
131
1.49k
    DTRACE( g_trace_ctx, D_CRC, "ALF" );
132
1.49k
    DTRACE_CRC( g_trace_ctx, D_CRC, cs, cs.getRecoBuf() );
133
1.49k
    DTRACE_PIC_COMP( D_REC_CB_LUMA_ALF,   cs, cs.getRecoBuf(), COMP_Y  );
134
1.49k
    DTRACE_PIC_COMP( D_REC_CB_CHROMA_ALF, cs, cs.getRecoBuf(), COMP_Cb );
135
1.49k
    DTRACE_PIC_COMP( D_REC_CB_CHROMA_ALF, cs, cs.getRecoBuf(), COMP_Cr );
136
1.49k
  }
137
138
  // write picture
139
1.49k
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "bsfinal", 1 ) );
140
1.49k
  xWriteSliceData( pic );
141
1.49k
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "bsfinal", 0 ) );
142
143
1.49k
  xCalcDistortion( pic, *slice->sps );
144
145
  // finalize
146
1.49k
  if ( m_pcEncCfg->m_useAMaxBT )
147
0
  {
148
0
    pic.picBlkStat.storeBlkSize( pic );
149
0
  }
150
151
  // copy ALF APSs to global list
152
1.49k
  CHECK( m_pcEncCfg->m_alf && m_pcEncCfg->m_alfTempPred && !pic.picApsGlobal, "Missing APS from top level" );
153
1.49k
  if( pic.picApsGlobal )
154
1.49k
  {
155
1.49k
    CHECK( pic.picApsGlobal->poc != pic.poc, "Global APS POC must be consistent with picture poc" );
156
1.49k
    const ParameterSetMap<APS>& src = pic.picApsMap;
157
1.49k
    ParameterSetMap<APS>&       dst = pic.picApsGlobal->apsMap;
158
13.4k
    for( int i = 0; i < ALF_CTB_MAX_NUM_APS; i++ )
159
11.9k
    {
160
11.9k
      const int apsMapIdx = ( i << NUM_APS_TYPE_LEN ) + ALF_APS;
161
11.9k
      const APS* srcAPS = src.getPS( apsMapIdx );
162
11.9k
      if( srcAPS )
163
0
      {
164
0
        APS* dstAPS = dst.allocatePS( apsMapIdx );
165
0
        *dstAPS = *srcAPS;
166
0
      }
167
11.9k
    }
168
1.49k
    dst.setApsIdStart( src.getApsIdStart() );
169
1.49k
  }
170
171
  // cleanup
172
1.49k
  pic.cs->releaseIntermediateData();
173
1.49k
  pic.cs->releaseVectorsAtPicLevel();
174
1.49k
  pic.cs->destroyTempBuffers();
175
1.49k
  pic.cs->destroyCoeffs();
176
  // Later pictures read only the colocated motion field of this one.
177
1.49k
  pic.cs->destroyFullMotionBuf();
178
179
1.49k
  pic.encTime.stopTimer();
180
1.49k
}
181
182
uint64_t findDistortionPlane( const CPelBuf& pic0, const CPelBuf& pic1, uint32_t rshift )
183
4.47k
{
184
4.47k
  uint64_t uiTotalDiff;
185
4.47k
  const  Pel*  pSrc0 = pic0.bufAt(0, 0);
186
4.47k
  const  Pel*  pSrc1 = pic1.bufAt(0, 0);
187
188
4.47k
  CHECK(pic0.width  != pic1.width , "Unspecified error");
189
4.47k
  CHECK(pic0.height != pic1.height, "Unspecified error");
190
191
4.47k
  if( rshift > 0 )
192
0
  {
193
0
    uiTotalDiff = 0;
194
0
    for (int y = 0; y < pic0.height; y++)
195
0
    {
196
0
      for (int x = 0; x < pic0.width; x++)
197
0
      {
198
0
        Intermediate_Int iTemp = pSrc0[x] - pSrc1[x];
199
0
        uiTotalDiff += uint64_t((iTemp * iTemp) >> rshift);
200
0
      }
201
0
      pSrc0 += pic0.stride;
202
0
      pSrc1 += pic1.stride;
203
0
    }
204
0
  }
205
4.47k
  else
206
4.47k
  {
207
4.47k
    uiTotalDiff = g_pelBufOP.sumSquaredError( pSrc0, pic0.stride, pSrc1, pic1.stride, pic0.width, pic0.height );
208
4.47k
  }
209
210
4.47k
  return uiTotalDiff;
211
4.47k
}
212
213
void EncPicture::xCalcDistortion( Picture& pic, const SPS& sps )
214
1.49k
{
215
1.49k
  const CPelUnitBuf cPicD = pic.getRecoBuf();
216
1.49k
  const CPelUnitBuf org   = pic.getOrigBuf();
217
1.49k
  const ChromaFormat formatD = cPicD.chromaFormat;
218
1.49k
  const ChromaFormat format  = sps.chromaFormatIdc;
219
220
5.97k
  for (int comp = 0; comp < getNumberValidComponents(formatD); comp++)
221
4.47k
  {
222
4.47k
    const ComponentID compID = ComponentID(comp);
223
4.47k
    const CPelBuf&    p = cPicD.get(compID);
224
4.47k
    const CPelBuf&    o = org.get(compID);
225
226
4.47k
    CHECK(!( p.width  == o.width), "Unspecified error");
227
4.47k
    CHECK(!( p.height == o.height), "Unspecified error");
228
229
4.47k
    const uint32_t   width  = p.width  - (m_pcEncCfg->m_aiPad[ 0 ] >> getComponentScaleX(compID, format));
230
4.47k
    const uint32_t   height = p.height - (m_pcEncCfg->m_aiPad[ 1 ] >> getComponentScaleY(compID, format));
231
232
    // create new buffers with correct dimensions
233
4.47k
    const CPelBuf recPB(p.bufAt(0, 0), p.stride, width, height);
234
4.47k
    const CPelBuf orgPB(o.bufAt(0, 0), o.stride, width, height);
235
4.47k
    const uint32_t    bitDepth = sps.bitDepths[toChannelType(compID)];
236
    //pic.ssd[comp] = findDistortionPlane(recPB, orgPB, 0);
237
4.47k
    const uint64_t uiSSDtemp = findDistortionPlane(recPB, orgPB, 0);
238
4.47k
    const uint32_t maxval = 255 << (bitDepth - 8);
239
4.47k
    const uint32_t size   = width * height;
240
4.47k
    const double fRefValue = (double)maxval * maxval * size;
241
4.47k
    pic.psnr[comp] = uiSSDtemp ? 10.0 * log10(fRefValue / (double)uiSSDtemp) : MAX_DOUBLE;
242
4.47k
    pic.mse [comp] = (double)uiSSDtemp / size;
243
4.47k
  }
244
1.49k
}
245
246
void EncPicture::xInitPicEncoder( Picture& pic )
247
1.49k
{
248
1.49k
  Slice* slice = pic.cs->slice;
249
250
1.49k
  CHECK( slice != pic.slices[0], "Slice pointers don't match!" );
251
252
1.49k
  m_SliceEncoder.initPic( &pic );
253
254
1.49k
  xInitSliceColFromL0Flag( slice );
255
1.49k
  xInitSliceCheckLDC     ( slice );
256
257
1.49k
  if( slice->sps->alfEnabled )
258
1.49k
  {
259
2.98k
    for (int s = 0; s < (int)pic.slices.size(); s++)
260
1.49k
    {
261
1.49k
      pic.slices[s]->alfEnabled[COMP_Y] = false;
262
1.49k
    }
263
1.49k
  }
264
1.49k
}
265
266
267
void EncPicture::xInitSliceColFromL0Flag( Slice* slice ) const
268
1.49k
{
269
1.49k
  if( m_pcEncCfg->m_rprRASLtoolSwitch )
270
0
  {
271
0
    return;
272
0
  }
273
274
1.49k
  if ( slice->sliceType == VVENC_B_SLICE )
275
0
  {
276
0
    const int refIdx = 0; // Zero always assumed
277
0
    const Picture* refPicL0 = slice->getRefPic( REF_PIC_LIST_0, refIdx );
278
0
    const Picture* refPicL1 = slice->getRefPic( REF_PIC_LIST_1, refIdx );
279
0
    slice->colFromL0Flag = ( refPicL0->slices[ 0 ]->sliceQp > refPicL1->slices[ 0 ]->sliceQp );
280
0
  }
281
1.49k
}
282
283
284
void EncPicture::xInitSliceCheckLDC( Slice* slice ) const
285
1.49k
{
286
1.49k
  if ( slice->sliceType == VVENC_B_SLICE )
287
0
  {
288
0
    bool bLowDelay = true;
289
0
    int  iCurrPOC  = slice->poc;
290
0
    int  iRefIdx   = 0;
291
292
0
    for ( iRefIdx = 0; iRefIdx < slice->numRefIdx[ REF_PIC_LIST_0 ] && bLowDelay; iRefIdx++ )
293
0
    {
294
0
      if ( slice->getRefPic( REF_PIC_LIST_0, iRefIdx )->getPOC() > iCurrPOC )
295
0
      {
296
0
        bLowDelay = false;
297
0
      }
298
0
    }
299
0
    for ( iRefIdx = 0; iRefIdx < slice->numRefIdx[ REF_PIC_LIST_1 ] && bLowDelay; iRefIdx++ )
300
0
    {
301
0
      if ( slice->getRefPic( REF_PIC_LIST_1, iRefIdx )->getPOC() > iCurrPOC )
302
0
      {
303
0
        bLowDelay = false;
304
0
      }
305
0
    }
306
307
0
    slice->checkLDC = bLowDelay;
308
0
  }
309
1.49k
  else
310
1.49k
  {
311
1.49k
    slice->checkLDC = true;
312
1.49k
  }
313
1.49k
}
314
315
void EncPicture::xWriteSliceData( Picture& pic )
316
1.49k
{
317
1.49k
  const int numSlices = (int)pic.slices.size();
318
319
1.49k
  pic.sliceDataStreams.clear();
320
1.49k
  pic.sliceDataStreams.resize( numSlices );
321
1.49k
  pic.sliceDataNumBins = 0;
322
323
2.98k
  for ( int i = 0; i < numSlices; i++ )
324
1.49k
  {
325
    // set current slice
326
1.49k
    pic.cs->slice = pic.slices[i];
327
1.49k
    m_SliceEncoder.encodeSliceData( &pic );
328
1.49k
  }
329
1.49k
}
330
331
} // namespace vvenc
332
333
//! \}
334