Coverage Report

Created: 2026-10-17 06:56

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
4.62k
{
75
4.62k
  m_pcEncCfg = &encCfg;
76
77
4.62k
  if( encCfg.m_alf || encCfg.m_ccalf )
78
4.62k
    m_ALF       .init( encCfg, pps, m_CABACEstimator, m_CtxCache, threadPool );
79
80
4.62k
  m_SliceEncoder.init( encCfg, sps, pps, globalCtuQpVector, m_LoopFilter, m_ALF, rateCtrl, threadPool, threadRsrc, &m_ctuTasksDoneCounter );
81
4.62k
  m_pcRateCtrl = &rateCtrl;
82
4.62k
}
83
84
85
void EncPicture::compressPicture( Picture& pic, EncGOP& gopEncoder )
86
1.15k
{
87
1.15k
  PROFILER_SCOPE_TOP_LEVEL_EXT( 1, g_timeProfiler, P_TOP_LEVEL, pic.cs );
88
1.15k
  ITT_TASKSTART( itt_domain_picEncoder, itt_handle_start );
89
90
1.15k
  pic.encTime.startTimer();
91
92
1.15k
  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.15k
  pic.cs->allocateVectorsAtPicLevel();
97
1.15k
  pic.cs->createCoeffs();
98
1.15k
  pic.cs->createTempBuffers( true );
99
1.15k
  pic.cs->initStructData( MAX_INT, false, nullptr );
100
101
  // compress picture
102
1.15k
  xInitPicEncoder( pic );
103
104
  // compress current slice
105
1.15k
  pic.cs->slice = pic.slices[0];
106
1.15k
  std::fill( pic.ctuSlice.begin(), pic.ctuSlice.end(), pic.slices[0] );
107
1.15k
  m_SliceEncoder.compressSlice( &pic );
108
109
1.15k
  ITT_TASKEND( itt_domain_picEncoder, itt_handle_start );
110
1.15k
}
111
112
void EncPicture::finalizePicture( Picture& pic )
113
1.15k
{
114
1.15k
  PROFILER_SCOPE_TOP_LEVEL_EXT( 1, g_timeProfiler, P_TOP_LEVEL, pic.cs );
115
1.15k
  CodingStructure& cs = *(pic.cs);
116
1.15k
  Slice* slice        = pic.slices[0];
117
  // ALF
118
1.15k
  if( slice->sps->alfEnabled )
119
1.15k
  {
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.15k
    pic.picApsMap.setApsIdStart( m_ALF.getApsIdStart() );
126
127
1.15k
    cs.slice->ccAlfFilterParam      = m_ALF.getCcAlfFilterParam();
128
1.15k
    cs.slice->ccAlfFilterControl[0] = m_ALF.getCcAlfControlIdc(COMP_Cb);
129
1.15k
    cs.slice->ccAlfFilterControl[1] = m_ALF.getCcAlfControlIdc(COMP_Cr);
130
131
1.15k
    DTRACE( g_trace_ctx, D_CRC, "ALF" );
132
1.15k
    DTRACE_CRC( g_trace_ctx, D_CRC, cs, cs.getRecoBuf() );
133
1.15k
    DTRACE_PIC_COMP( D_REC_CB_LUMA_ALF,   cs, cs.getRecoBuf(), COMP_Y  );
134
1.15k
    DTRACE_PIC_COMP( D_REC_CB_CHROMA_ALF, cs, cs.getRecoBuf(), COMP_Cb );
135
1.15k
    DTRACE_PIC_COMP( D_REC_CB_CHROMA_ALF, cs, cs.getRecoBuf(), COMP_Cr );
136
1.15k
  }
137
138
  // write picture
139
1.15k
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "bsfinal", 1 ) );
140
1.15k
  xWriteSliceData( pic );
141
1.15k
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "bsfinal", 0 ) );
142
143
1.15k
  xCalcDistortion( pic, *slice->sps );
144
145
  // finalize
146
1.15k
  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.15k
  CHECK( m_pcEncCfg->m_alf && m_pcEncCfg->m_alfTempPred && !pic.picApsGlobal, "Missing APS from top level" );
153
1.15k
  if( pic.picApsGlobal )
154
1.15k
  {
155
1.15k
    CHECK( pic.picApsGlobal->poc != pic.poc, "Global APS POC must be consistent with picture poc" );
156
1.15k
    const ParameterSetMap<APS>& src = pic.picApsMap;
157
1.15k
    ParameterSetMap<APS>&       dst = pic.picApsGlobal->apsMap;
158
10.4k
    for( int i = 0; i < ALF_CTB_MAX_NUM_APS; i++ )
159
9.24k
    {
160
9.24k
      const int apsMapIdx = ( i << NUM_APS_TYPE_LEN ) + ALF_APS;
161
9.24k
      const APS* srcAPS = src.getPS( apsMapIdx );
162
9.24k
      if( srcAPS )
163
0
      {
164
0
        APS* dstAPS = dst.allocatePS( apsMapIdx );
165
0
        *dstAPS = *srcAPS;
166
0
      }
167
9.24k
    }
168
1.15k
    dst.setApsIdStart( src.getApsIdStart() );
169
1.15k
  }
170
171
  // cleanup
172
1.15k
  pic.cs->releaseIntermediateData();
173
1.15k
  pic.cs->releaseVectorsAtPicLevel();
174
1.15k
  pic.cs->destroyTempBuffers();
175
1.15k
  pic.cs->destroyCoeffs();
176
  // Later pictures read only the colocated motion field of this one.
177
1.15k
  pic.cs->destroyFullMotionBuf();
178
179
1.15k
  pic.encTime.stopTimer();
180
1.15k
}
181
182
uint64_t findDistortionPlane( const CPelBuf& pic0, const CPelBuf& pic1, uint32_t rshift )
183
3.46k
{
184
3.46k
  uint64_t uiTotalDiff;
185
3.46k
  const  Pel*  pSrc0 = pic0.bufAt(0, 0);
186
3.46k
  const  Pel*  pSrc1 = pic1.bufAt(0, 0);
187
188
3.46k
  CHECK(pic0.width  != pic1.width , "Unspecified error");
189
3.46k
  CHECK(pic0.height != pic1.height, "Unspecified error");
190
191
3.46k
  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
3.46k
  else
206
3.46k
  {
207
3.46k
    uiTotalDiff = 0;
208
354k
    for (int y = 0; y < pic0.height; y++)
209
351k
    {
210
40.2M
      for (int x = 0; x < pic0.width; x++)
211
39.9M
      {
212
39.9M
        Intermediate_Int iTemp = pSrc0[x] - pSrc1[x];
213
39.9M
        uiTotalDiff += uint64_t(iTemp * iTemp);
214
39.9M
      }
215
351k
      pSrc0 += pic0.stride;
216
351k
      pSrc1 += pic1.stride;
217
351k
    }
218
3.46k
  }
219
220
3.46k
  return uiTotalDiff;
221
3.46k
}
222
223
void EncPicture::xCalcDistortion( Picture& pic, const SPS& sps )
224
1.15k
{
225
1.15k
  const CPelUnitBuf cPicD = pic.getRecoBuf();
226
1.15k
  const CPelUnitBuf org   = pic.getOrigBuf();
227
1.15k
  const ChromaFormat formatD = cPicD.chromaFormat;
228
1.15k
  const ChromaFormat format  = sps.chromaFormatIdc;
229
230
4.62k
  for (int comp = 0; comp < getNumberValidComponents(formatD); comp++)
231
3.46k
  {
232
3.46k
    const ComponentID compID = ComponentID(comp);
233
3.46k
    const CPelBuf&    p = cPicD.get(compID);
234
3.46k
    const CPelBuf&    o = org.get(compID);
235
236
3.46k
    CHECK(!( p.width  == o.width), "Unspecified error");
237
3.46k
    CHECK(!( p.height == o.height), "Unspecified error");
238
239
3.46k
    const uint32_t   width  = p.width  - (m_pcEncCfg->m_aiPad[ 0 ] >> getComponentScaleX(compID, format));
240
3.46k
    const uint32_t   height = p.height - (m_pcEncCfg->m_aiPad[ 1 ] >> getComponentScaleY(compID, format));
241
242
    // create new buffers with correct dimensions
243
3.46k
    const CPelBuf recPB(p.bufAt(0, 0), p.stride, width, height);
244
3.46k
    const CPelBuf orgPB(o.bufAt(0, 0), o.stride, width, height);
245
3.46k
    const uint32_t    bitDepth = sps.bitDepths[toChannelType(compID)];
246
    //pic.ssd[comp] = findDistortionPlane(recPB, orgPB, 0);
247
3.46k
    const uint64_t uiSSDtemp = findDistortionPlane(recPB, orgPB, 0);
248
3.46k
    const uint32_t maxval = 255 << (bitDepth - 8);
249
3.46k
    const uint32_t size   = width * height;
250
3.46k
    const double fRefValue = (double)maxval * maxval * size;
251
3.46k
    pic.psnr[comp] = uiSSDtemp ? 10.0 * log10(fRefValue / (double)uiSSDtemp) : MAX_DOUBLE;
252
3.46k
    pic.mse [comp] = (double)uiSSDtemp / size;
253
3.46k
  }
254
1.15k
}
255
256
void EncPicture::xInitPicEncoder( Picture& pic )
257
1.15k
{
258
1.15k
  Slice* slice = pic.cs->slice;
259
260
1.15k
  CHECK( slice != pic.slices[0], "Slice pointers don't match!" );
261
262
1.15k
  m_SliceEncoder.initPic( &pic );
263
264
1.15k
  xInitSliceColFromL0Flag( slice );
265
1.15k
  xInitSliceCheckLDC     ( slice );
266
267
1.15k
  if( slice->sps->alfEnabled )
268
1.15k
  {
269
2.31k
    for (int s = 0; s < (int)pic.slices.size(); s++)
270
1.15k
    {
271
1.15k
      pic.slices[s]->alfEnabled[COMP_Y] = false;
272
1.15k
    }
273
1.15k
  }
274
1.15k
}
275
276
277
void EncPicture::xInitSliceColFromL0Flag( Slice* slice ) const
278
1.15k
{
279
1.15k
  if( m_pcEncCfg->m_rprRASLtoolSwitch )
280
0
  {
281
0
    return;
282
0
  }
283
284
1.15k
  if ( slice->sliceType == VVENC_B_SLICE )
285
0
  {
286
0
    const int refIdx = 0; // Zero always assumed
287
0
    const Picture* refPicL0 = slice->getRefPic( REF_PIC_LIST_0, refIdx );
288
0
    const Picture* refPicL1 = slice->getRefPic( REF_PIC_LIST_1, refIdx );
289
0
    slice->colFromL0Flag = ( refPicL0->slices[ 0 ]->sliceQp > refPicL1->slices[ 0 ]->sliceQp );
290
0
  }
291
1.15k
}
292
293
294
void EncPicture::xInitSliceCheckLDC( Slice* slice ) const
295
1.15k
{
296
1.15k
  if ( slice->sliceType == VVENC_B_SLICE )
297
0
  {
298
0
    bool bLowDelay = true;
299
0
    int  iCurrPOC  = slice->poc;
300
0
    int  iRefIdx   = 0;
301
302
0
    for ( iRefIdx = 0; iRefIdx < slice->numRefIdx[ REF_PIC_LIST_0 ] && bLowDelay; iRefIdx++ )
303
0
    {
304
0
      if ( slice->getRefPic( REF_PIC_LIST_0, iRefIdx )->getPOC() > iCurrPOC )
305
0
      {
306
0
        bLowDelay = false;
307
0
      }
308
0
    }
309
0
    for ( iRefIdx = 0; iRefIdx < slice->numRefIdx[ REF_PIC_LIST_1 ] && bLowDelay; iRefIdx++ )
310
0
    {
311
0
      if ( slice->getRefPic( REF_PIC_LIST_1, iRefIdx )->getPOC() > iCurrPOC )
312
0
      {
313
0
        bLowDelay = false;
314
0
      }
315
0
    }
316
317
0
    slice->checkLDC = bLowDelay;
318
0
  }
319
1.15k
  else
320
1.15k
  {
321
1.15k
    slice->checkLDC = true;
322
1.15k
  }
323
1.15k
}
324
325
void EncPicture::xWriteSliceData( Picture& pic )
326
1.15k
{
327
1.15k
  const int numSlices = (int)pic.slices.size();
328
329
1.15k
  pic.sliceDataStreams.clear();
330
1.15k
  pic.sliceDataStreams.resize( numSlices );
331
1.15k
  pic.sliceDataNumBins = 0;
332
333
2.31k
  for ( int i = 0; i < numSlices; i++ )
334
1.15k
  {
335
    // set current slice
336
1.15k
    pic.cs->slice = pic.slices[i];
337
1.15k
    m_SliceEncoder.encodeSliceData( &pic );
338
1.15k
  }
339
1.15k
}
340
341
} // namespace vvenc
342
343
//! \}
344