Coverage Report

Created: 2026-10-17 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvdec/source/Lib/CommonLib/Picture.h
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) 2018-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVdeC 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
/** \file     Picture.h
44
 *  \brief    Description of a coded picture
45
 */
46
47
#pragma once
48
49
#include "CommonDef.h"
50
51
#include "Common.h"
52
#include "Unit.h"
53
#include "Buffer.h"
54
#include "Unit.h"
55
#include "Slice.h"
56
#include "CodingStructure.h"
57
#include "SEI_internal.h"
58
59
#include "vvdec/sei.h"
60
61
namespace vvdec
62
{
63
#if  ENABLE_SIMD_OPT_PICTURE && defined( TARGET_SIMD_X86 )
64
using namespace x86_simd;
65
#endif
66
67
#if ENABLE_SIMD_OPT_PICTURE && defined( TARGET_SIMD_ARM )
68
using namespace arm_simd;
69
#endif
70
71
struct Picture;
72
73
typedef std::list<Picture*> PicList;
74
75
struct SubPicExtTask
76
{
77
  Picture*    picture   = nullptr;
78
  PelStorage* subPicBuf = nullptr;
79
  Area        subPicArea;
80
};
81
82
struct PicListRange
83
{
84
  PicList::const_iterator m_begin;
85
  PicList::const_iterator m_end;
86
87
0
  const PicList::const_iterator begin() const { return m_begin; }
88
0
  const PicList::const_iterator end  () const { return m_end;   }
89
};
90
91
92
struct Picture : public UnitArea
93
{
94
  explicit Picture( bool enableOpt = true );
95
0
  ~Picture() = default;
96
  CLASS_COPY_MOVE_DELETE( Picture )
97
98
  void create(const ChromaFormat &_chromaFormat, const Size &size, const unsigned _maxCUSize, const unsigned margin, const int layerId, UserAllocator* userAlloc = nullptr );
99
  void createWrapAroundBuf( const bool isWrapAround, const unsigned _maxCUSize );
100
  void resetForUse( int _layerId );
101
  void destroy();
102
103
0
         Pel*      getRecoBufPtr   (const ComponentID compID, bool wrap=false)       { return m_bufs[wrap ? PIC_RECON_WRAP : PIC_RECONSTRUCTION].bufs[compID].buf; }
104
0
  const  Pel*      getRecoBufPtr   (const ComponentID compID, bool wrap=false) const { return m_bufs[wrap ? PIC_RECON_WRAP : PIC_RECONSTRUCTION].bufs[compID].buf; }
105
0
         ptrdiff_t getRecoBufStride(const ComponentID compID, bool wrap=false)       { return m_bufs[wrap ? PIC_RECON_WRAP : PIC_RECONSTRUCTION].bufs[compID].stride; }
106
0
  const  ptrdiff_t getRecoBufStride(const ComponentID compID, bool wrap=false) const { return m_bufs[wrap ? PIC_RECON_WRAP : PIC_RECONSTRUCTION].bufs[compID].stride; }
107
         PelBuf     getRecoBuf(const ComponentID compID, bool wrap=false);
108
  const CPelBuf     getRecoBuf(const ComponentID compID, bool wrap=false) const;
109
         PelBuf     getRecoBuf(const CompArea &blk,      bool wrap=false);
110
  const CPelBuf     getRecoBuf(const CompArea &blk,      bool wrap=false) const;
111
         PelUnitBuf getRecoBuf(const UnitArea &unit,     bool wrap=false);
112
  const CPelUnitBuf getRecoBuf(const UnitArea &unit,     bool wrap=false) const;
113
         PelUnitBuf getRecoBuf(bool wrap=false);
114
  const CPelUnitBuf getRecoBuf(bool wrap=false) const;
115
116
  // This returns a CPelBuf, with the origin at the picture origin (0,0), but the actual storage size of the sub picture.
117
  // It can be used the same way as the full picture buffer, but you should only reference the data within the actual sub picture.
118
  // Also, handle with care, because stride < width.
119
  const CPelBuf getSubPicBuf( int subPicIdx, const ComponentID compID, bool wrap = false ) const
120
0
  {
121
0
    CHECK( wrap, "wraparound for subpics not supported yet" );
122
123
0
    Position subPicPos( subPictures[subPicIdx].getSubPicLeft() >> getComponentScaleX( compID, m_subPicRefBufs[subPicIdx].chromaFormat ),
124
0
                        subPictures[subPicIdx].getSubPicTop()  >> getComponentScaleY( compID, m_subPicRefBufs[subPicIdx].chromaFormat ) );
125
126
0
    Size targetSize( m_bufs[PIC_RECONSTRUCTION].get( compID ) );
127
128
0
    const auto& subPicComp = m_subPicRefBufs[subPicIdx].bufs[compID];
129
0
    return CPelBuf( subPicComp.bufAt( -subPicPos.x, -subPicPos.y ), subPicComp.stride, targetSize );
130
0
  }
131
0
  const Pel*      getSubPicBufPtr   ( int subPicIdx, const ComponentID compID, bool wrap = false ) const { return getSubPicBuf( subPicIdx, compID, wrap ).buf;    }
132
0
  const ptrdiff_t getSubPicBufStride( int subPicIdx, const ComponentID compID, bool wrap = false ) const { return getSubPicBuf( subPicIdx, compID, wrap ).stride; }
133
134
private:
135
0
         PelBuf     getBuf(const ComponentID compID, const PictureType &type)       { return m_bufs[type].bufs[ compID ]; }
136
0
  const CPelBuf     getBuf(const ComponentID compID, const PictureType &type) const { return m_bufs[type].bufs[ compID ]; }
137
         PelBuf     getBuf(const CompArea &blk,      const PictureType &type);
138
  const CPelBuf     getBuf(const CompArea &blk,      const PictureType &type) const;
139
         PelUnitBuf getBuf(const UnitArea &unit,     const PictureType &type);
140
  const CPelUnitBuf getBuf(const UnitArea &unit,     const PictureType &type) const;
141
142
public:
143
  void extendPicBorder    (                  bool top = true, bool bottom = true, bool leftrightT = true, bool leftrightB = true, ChannelType chType = MAX_NUM_CHANNEL_TYPE );
144
  void extendPicBorderBuf ( PelStorage& buf, bool top = true, bool bottom = true, bool leftrightT = true, bool leftrightB = true, ChannelType chType = MAX_NUM_CHANNEL_TYPE );
145
  void extendPicBorderWrap(                  bool top = true, bool bottom = true, bool leftrightT = true, bool leftrightB = true, ChannelType chType = MAX_NUM_CHANNEL_TYPE );
146
147
  void (*paddPicBorderBot) (Pel *pi, ptrdiff_t stride,int width,int xmargin,int ymargin);
148
  void (*paddPicBorderTop) (Pel *pi, ptrdiff_t stride,int width,int xmargin,int ymargin);
149
  void (*paddPicBorderLeftRight) (Pel *pi, ptrdiff_t stride,int width,int xmargin,int height);
150
151
  void finalInit( CUChunkCache* cuChunkCache, TUChunkCache* tuChunkCache, CUMapCache* cuMapCache, CUMapCache* chromaCuMapCache, const SPS * sps, const PPS * pps, const std::shared_ptr<PicHeader>& ph, const APS* const alfApss[ALF_CTB_MAX_NUM_APS], const APS * lmcsAps, const APS* scalingListAps, bool phPSupdate = true );
152
153
0
  int      getPOC()                           const { return poc; }
154
0
  uint64_t getCts()                           const { return cts; }
155
0
  uint64_t getDts()                           const { return dts; }
156
0
  uint32_t getTLayer()                        const { return tempLayer; }
157
0
  uint32_t getNaluBits()                      const { return bits; }
158
0
  bool     getRap()                           const { return rap; }
159
160
0
  bool     isCLVSS()                          const { return !slices.empty() && slices[0]->isClvssPu(); }
161
162
  Pel*   getOrigin( const PictureType &type, const ComponentID compID ) const;
163
  PelBuf getOriginBuf( const PictureType &type, const ComponentID compID );
164
165
  Size   getBufSize( const PictureType &type, const ComponentID compID ) const;
166
  void*  getBufAllocator( const ComponentID compID );
167
  bool   isExternAllocator() const;
168
  const  UserAllocator* getUserAllocator() const;
169
170
0
  int  getDecodingOrderNumber()               const { return decodingOrderNumber; }
171
0
  void setDecodingOrderNumber(const int val)        { decodingOrderNumber = val;  }
172
173
0
  bool getMixedNaluTypesInPicFlag()           const { return slices[0]->getPPS()->getMixedNaluTypesInPicFlag(); }
174
175
  std::vector<Picture*> buildAllRefPicsVec();
176
177
public:
178
  void startProcessingTimer();
179
  void stopProcessingTimer();
180
0
  void resetProcessingTime() { m_dProcessingTime = 0; }
181
0
  double getProcessingTime() const { return m_dProcessingTime; }
182
183
  std::chrono::time_point<std::chrono::steady_clock> m_processingStartTime;
184
  double                                             m_dProcessingTime = 0;
185
  std::mutex                                         m_timerMutex;
186
187
  enum PicStateEnum
188
  {
189
    init,
190
    parsing,
191
    parsed,
192
    reconstructing,
193
    reconstructed,
194
    finished
195
  };
196
  using PicState = std::atomic<PicStateEnum>;
197
  PicState progress{ init };
198
199
  enum RefMark : uint8_t
200
  {
201
    unreferenced = 0,
202
    ShortTerm,
203
    LongTerm
204
  };
205
206
  bool             subPicExtStarted        = false;
207
  bool             borderExtStarted        = false;
208
  RefMark          dpbReferenceMark        = unreferenced;   // only used during parsing, manage the DPB and to build the reference picture lists
209
  bool             neededForOutput         = false;
210
  std::atomic_bool stillReferenced         { false };        // set as long as there is a picture in progress, that references this one. ('referenced' might be unset during parsing)
211
  bool             isReferencePic          = false;          // mainly for setting vvdecPicAttributes::isRefPic for the library output frame
212
  bool             wasLost                 = false;
213
  std::atomic_bool error                   { false };
214
  bool             exceptionThrownOut      = false;
215
  bool             topField                = false;
216
  bool             fieldPic                = false;
217
  bool             nonReferencePictureFlag = false;
218
  int              skippedDecCount         = 0;
219
220
  bool              picCheckedDPH = false;
221
  std::vector<bool> subpicsCheckedDPH;
222
  bool              dphMismatch   = false;
223
224
  // As long as this field is nonzero, the picture will not be reused or deleted.
225
  // An external application needs to call DecLib::releasePicture(), when it is done using the picture buffer.
226
  enum : int8_t
227
  {
228
    UNLOCKED = 0,
229
    WAITING,   // the picture has not yet been passed to the application
230
    LOCKED     // the picture has been passed to the application and is still in use
231
  } lockedByApplication = UNLOCKED;
232
233
  int         poc          = 0;
234
  uint64_t    cts          = 0;   // composition time stamp
235
  uint64_t    dts          = 0;   // decoding time stamp
236
  uint32_t    tempLayer    = std::numeric_limits<uint32_t>::max();
237
  uint32_t    depth        = 0;
238
  int         layerId      = NOT_VALID;
239
  NalUnitType eNalUnitType = NAL_UNIT_INVALID;
240
  uint32_t    bits         = 0;   // input nal bit count
241
  bool        rap          = 0;   // random access point flag
242
  void       *userData     = nullptr;      ///< opaque user data
243
  int         decodingOrderNumber = 0;
244
245
  std::vector<int>        sliceSubpicIdx;
246
  std::vector<SubPic>     subPictures;
247
  std::vector<PelStorage> m_subPicRefBufs;   // used as reference for subpictures, that are treated as pictures
248
  // SubPicExtTasks need to live as long as the buffers they point to. The tasks can still be pending,
249
  // when the next picture is decoded.
250
  std::vector<SubPicExtTask> m_subPicExtTasks;
251
252
  bool subLayerNonReferencePictureDueToSTSA = 0;
253
254
  PelStorage     m_bufs[NUM_PIC_TYPES];
255
  uint32_t       margin      = 0;
256
257
  WaitCounter     m_divTasksCounter;        // for all tasks, that are not covered by the other WaitCounters => only needed for cleanup during exception handling
258
  WaitCounter     m_ctuTaskCounter;
259
  WaitCounter     m_borderExtTaskCounter;
260
  Barrier         m_copyWrapBufDone;
261
  BlockingBarrier parseDone;
262
  BlockingBarrier reconDone;
263
#if RECO_WHILE_PARSE
264
  std::vector<Barrier> ctuParsedBarrier;
265
#endif
266
#if ALLOW_MIDER_LF_DURING_PICEXT
267
  CBarrierVec     refPicExtDepBarriers;
268
#endif
269
270
  std::unique_ptr<CodingStructure> cs;
271
  std::vector<Slice*>              slices;
272
273
  seiMessages        seiMessageList;
274
275
  bool               isRefScaled( const PPS* pps ) const
276
0
  {
277
0
    const PPS*  pps0     = slices[0]->getPPS();
278
0
    const Size& recoSize = m_bufs[PIC_RECONSTRUCTION].bufs[COMPONENT_Y];
279
0
    return ( recoSize.width  != pps->getPicWidthInLumaSamples()    ||
280
0
             recoSize.height != pps->getPicHeightInLumaSamples() ) ||
281
0
           ( ( pps0->getScalingWindow().getWindowEnabledFlag()   || pps->getScalingWindow().getWindowEnabledFlag() ) && (
282
0
               pps0->getScalingWindow().getWindowLeftOffset()    != pps->getScalingWindow().getWindowLeftOffset()  ||
283
0
               pps0->getScalingWindow().getWindowRightOffset()   != pps->getScalingWindow().getWindowRightOffset() ||
284
0
               pps0->getScalingWindow().getWindowTopOffset()     != pps->getScalingWindow().getWindowTopOffset()   ||
285
0
               pps0->getScalingWindow().getWindowBottomOffset()  != pps->getScalingWindow().getWindowBottomOffset() ) );
286
0
  }
287
288
0
  bool         isWrapAroundEnabled( const PPS* pps ) const  { return  pps->getUseWrapAround() && !isRefScaled( pps ); }
289
290
  Slice*       allocateNewSlice( Slice** pilot = nullptr );
291
  void         clearSliceBuffer();
292
  bool         lastSliceOfPicPresent() const;
293
  void         setParseError( std::exception_ptr e );
294
295
  void         waitForAllTasks();
296
  void         ensureUsableAsRef();
297
  void         fillGrey( const SPS* fallbackSPS = nullptr );
298
299
#if TRACE_ENABLE_ITT
300
  __itt_domain* m_itt_decLibInst;
301
#endif
302
303
public:
304
305
#if  ENABLE_SIMD_OPT_PICTURE && defined( TARGET_SIMD_X86 )
306
  void initPictureX86();
307
  template <X86_VEXT vext>
308
  void _initPictureX86();
309
#endif
310
311
#if ENABLE_SIMD_OPT_PICTURE && defined( TARGET_SIMD_ARM )
312
  void initPictureARM();
313
  template <ARM_VEXT vext>
314
  void _initPictureARM();
315
#endif
316
};
317
318
int calcAndPrintHashStatus(const CPelUnitBuf& pic, const vvdecSEIDecodedPictureHash* pictureHashSEI, const BitDepths &bitDepths, const MsgLevel msgl);
319
320
}   // namespace vvdec