Coverage Report

Created: 2026-06-10 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/libde265/libde265/image.h
Line
Count
Source
1
/*
2
 * H.265 video codec.
3
 * Copyright (c) 2013-2014 struktur AG, Dirk Farin <farin@struktur.de>
4
 *
5
 * This file is part of libde265.
6
 *
7
 * libde265 is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Lesser General Public License as
9
 * published by the Free Software Foundation, either version 3 of
10
 * the License, or (at your option) any later version.
11
 *
12
 * libde265 is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public License
18
 * along with libde265.  If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
#ifndef DE265_IMAGE_H
22
#define DE265_IMAGE_H
23
24
#ifdef HAVE_CONFIG_H
25
#include <config.h>
26
#endif
27
28
#include <assert.h>
29
#include <stddef.h>
30
#include <stdint.h>
31
#include <stdlib.h>
32
#include <string.h>
33
#include <limits>
34
#include <memory>
35
36
#include "libde265/de265.h"
37
#include "libde265/sps.h"
38
#include "libde265/pps.h"
39
#include "libde265/motion.h"
40
#include "libde265/threads.h"
41
#include "libde265/slice.h"
42
#include "libde265/nal.h"
43
44
struct en265_encoder_context;
45
46
enum PictureState {
47
  UnusedForReference,
48
  UsedForShortTermReference,
49
  UsedForLongTermReference
50
};
51
52
53
/* TODO:
54
   At INTEGRITY_DERIVED_FROM_FAULTY_REFERENCE images, we can check the SEI hash, whether
55
   the output image is correct despite the faulty reference, and set the state back to correct.
56
*/
57
constexpr uint8_t INTEGRITY_CORRECT = 0;
58
constexpr uint8_t INTEGRITY_UNAVAILABLE_REFERENCE = 1;
59
constexpr uint8_t INTEGRITY_NOT_DECODED = 2;
60
constexpr uint8_t INTEGRITY_DECODING_ERRORS = 3;
61
constexpr uint8_t INTEGRITY_DERIVED_FROM_FAULTY_REFERENCE = 4;
62
63
constexpr uint8_t SEI_HASH_UNCHECKED = 0;
64
constexpr uint8_t SEI_HASH_CORRECT   = 1;
65
constexpr uint8_t SEI_HASH_INCORRECT = 2;
66
67
constexpr uint8_t TU_FLAG_NONZERO_COEFF  = (1<<7);
68
constexpr uint8_t TU_FLAG_SPLIT_TRANSFORM_MASK  = 0x1F;
69
70
constexpr uint8_t DEBLOCK_FLAG_VERTI = (1<<4);
71
constexpr uint8_t DEBLOCK_FLAG_HORIZ = (1<<5);
72
constexpr uint8_t DEBLOCK_PB_EDGE_VERTI = (1<<6);
73
constexpr uint8_t DEBLOCK_PB_EDGE_HORIZ = (1<<7);
74
constexpr uint8_t DEBLOCK_BS_MASK     = 0x03;
75
76
constexpr int CTB_PROGRESS_NONE      = 0;
77
constexpr int CTB_PROGRESS_PREFILTER = 1;
78
constexpr int CTB_PROGRESS_DEBLK_V   = 2;
79
constexpr int CTB_PROGRESS_DEBLK_H   = 3;
80
constexpr int CTB_PROGRESS_SAO       = 4;
81
82
class decoder_context;
83
84
template <class DataUnit> class MetaDataArray
85
{
86
 public:
87
0
  MetaDataArray() = default;
Unexecuted instantiation: MetaDataArray<CTB_info>::MetaDataArray()
Unexecuted instantiation: MetaDataArray<CB_ref_info>::MetaDataArray()
Unexecuted instantiation: MetaDataArray<PBMotion>::MetaDataArray()
Unexecuted instantiation: MetaDataArray<unsigned char>::MetaDataArray()
88
0
  ~MetaDataArray() { free(data); }
Unexecuted instantiation: MetaDataArray<CTB_info>::~MetaDataArray()
Unexecuted instantiation: MetaDataArray<CB_ref_info>::~MetaDataArray()
Unexecuted instantiation: MetaDataArray<PBMotion>::~MetaDataArray()
Unexecuted instantiation: MetaDataArray<unsigned char>::~MetaDataArray()
89
90
0
  LIBDE265_CHECK_RESULT bool alloc(int w,int h, uint8_t _log2unitSize) {
91
0
    int size = w*h;
92
93
0
    if (size != data_size) {
94
0
      free(data);
95
0
      data = (DataUnit*)calloc(size, sizeof(DataUnit));
96
0
      if (data == nullptr) {
97
0
        data_size = 0;
98
0
        return false;
99
0
      }
100
0
      data_size = size;
101
0
    }
102
103
0
    width_in_units = w;
104
0
    height_in_units = h;
105
106
0
    log2unitSize = _log2unitSize;
107
108
0
    return data != nullptr;
109
0
  }
Unexecuted instantiation: MetaDataArray<unsigned char>::alloc(int, int, unsigned char)
Unexecuted instantiation: MetaDataArray<CB_ref_info>::alloc(int, int, unsigned char)
Unexecuted instantiation: MetaDataArray<PBMotion>::alloc(int, int, unsigned char)
Unexecuted instantiation: MetaDataArray<CTB_info>::alloc(int, int, unsigned char)
110
111
0
  void clear() {
112
0
    if (data) memset(data, 0, sizeof(DataUnit) * data_size);
113
0
  }
Unexecuted instantiation: MetaDataArray<CB_ref_info>::clear()
Unexecuted instantiation: MetaDataArray<unsigned char>::clear()
Unexecuted instantiation: MetaDataArray<CTB_info>::clear()
114
115
0
  const DataUnit& get(int x,int y) const {
116
0
    int unitX = x>>log2unitSize;
117
0
    int unitY = y>>log2unitSize;
118
119
0
    assert(unitX >= 0 && unitX < width_in_units);
120
0
    assert(unitY >= 0 && unitY < height_in_units);
121
122
0
    return data[ unitX + unitY*width_in_units ];
123
0
  }
Unexecuted instantiation: MetaDataArray<CB_ref_info>::get(int, int) const
Unexecuted instantiation: MetaDataArray<unsigned char>::get(int, int) const
Unexecuted instantiation: MetaDataArray<CTB_info>::get(int, int) const
Unexecuted instantiation: MetaDataArray<PBMotion>::get(int, int) const
124
125
0
  DataUnit& get(int x,int y) {
126
0
    int unitX = x>>log2unitSize;
127
0
    int unitY = y>>log2unitSize;
128
129
0
    assert(unitX >= 0 && unitX < width_in_units);
130
0
    assert(unitY >= 0 && unitY < height_in_units);
131
132
0
    return data[ unitX + unitY*width_in_units ];
133
0
  }
Unexecuted instantiation: MetaDataArray<CTB_info>::get(int, int)
Unexecuted instantiation: MetaDataArray<CB_ref_info>::get(int, int)
Unexecuted instantiation: MetaDataArray<unsigned char>::get(int, int)
134
135
  void set(int x,int y, const DataUnit& d) {
136
    int unitX = x>>log2unitSize;
137
    int unitY = y>>log2unitSize;
138
139
    assert(unitX >= 0 && unitX < width_in_units);
140
    assert(unitY >= 0 && unitY < height_in_units);
141
142
    data[ unitX + unitY*width_in_units ] = d;
143
  }
144
145
0
  DataUnit& operator[](int idx) { return data[idx]; }
Unexecuted instantiation: MetaDataArray<unsigned char>::operator[](int)
Unexecuted instantiation: MetaDataArray<CB_ref_info>::operator[](int)
Unexecuted instantiation: MetaDataArray<CTB_info>::operator[](int)
Unexecuted instantiation: MetaDataArray<PBMotion>::operator[](int)
146
0
  const DataUnit& operator[](int idx) const { return data[idx]; }
Unexecuted instantiation: MetaDataArray<CB_ref_info>::operator[](int) const
Unexecuted instantiation: MetaDataArray<unsigned char>::operator[](int) const
Unexecuted instantiation: MetaDataArray<CTB_info>::operator[](int) const
147
148
0
  int size() const { return data_size; }
149
150
  // private:
151
  DataUnit* data = nullptr;
152
  int data_size = 0;
153
  uint8_t log2unitSize = 0;
154
  int width_in_units = 0;
155
  int height_in_units = 0;
156
};
157
158
159
160
struct CTB_info {
161
  uint16_t SliceAddrRS;
162
  uint16_t SliceHeaderIndex; // index into array to slice header for this CTB
163
164
  sao_info saoInfo;
165
  bool     deblock;         // this CTB has to be deblocked
166
167
  // The following flag helps to quickly check whether we have to
168
  // check all conditions in the SAO filter or whether we can skip them.
169
  bool     has_pcm_or_cu_transquant_bypass; // pcm or transquant_bypass is used in this CTB
170
};
171
172
173
struct CB_ref_info {
174
  uint8_t log2CbSize : 3;   /* [0;6] (1<<log2CbSize) = 64
175
                               This is only set in the top-left corner of the CB.
176
                               The other values should be zero.
177
                               TODO: in the encoder, we have to clear to zero.
178
                               Used in deblocking and QP-scale decoding */
179
  uint8_t PartMode : 3;     // (enum PartMode)  [0;7] set only in top-left of CB
180
                            // Used for spatial merging candidates in current frame
181
                            // and for deriving interSplitFlag in decoding.
182
183
  uint8_t ctDepth : 2;      // [0:3]? (for CTB size 64: 0:64, 1:32, 2:16, 3:8)
184
                            // Used for decoding/encoding split_cu flag.
185
186
  // --- byte boundary ---
187
  uint8_t PredMode : 2;     // (enum PredMode)  [0;2] must be saved for past images
188
                            // Used in motion decoding.
189
  uint8_t pcm_flag : 1;     // Stored for intra-prediction / SAO
190
  uint8_t cu_transquant_bypass : 1; // Stored for SAO
191
  // note: 4 bits left
192
193
  // --- byte boundary ---
194
  int8_t  QP_Y;  // Stored for QP prediction
195
};
196
197
198
199
200
struct de265_image {
201
  de265_image();
202
  ~de265_image();
203
204
205
  de265_error alloc_image(int w,int h, de265_chroma c,
206
                          std::shared_ptr<const seq_parameter_set> sps,
207
                          bool allocMetadata,
208
                          decoder_context* dctx,
209
                          //class encoder_context* ectx,
210
                          de265_PTS pts, void* user_data,
211
                          bool useCustomAllocFunctions);
212
213
  //de265_error alloc_encoder_data(const seq_parameter_set* sps);
214
215
0
  bool is_allocated() const { return pixels[0] != nullptr; }
216
217
  void release();
218
219
  void set_headers(std::shared_ptr<video_parameter_set> _vps,
220
                   std::shared_ptr<seq_parameter_set>   _sps,
221
0
                   std::shared_ptr<pic_parameter_set>   _pps) {
222
0
    vps = _vps;
223
0
    sps = _sps;
224
0
    pps = _pps;
225
0
  }
226
227
  void fill_image(int y,int u,int v);
228
  void fill_plane(int channel, int value);
229
  de265_error copy_image(const de265_image* src);
230
  void copy_lines_from(const de265_image* src, int first, int end);
231
  void exchange_pixel_data_with(de265_image&);
232
233
0
  uint32_t get_ID() const { return ID; }
234
235
236
0
  /* */ uint8_t* get_image_plane(int cIdx)       { return pixels[cIdx]; }
237
0
  const uint8_t* get_image_plane(int cIdx) const { return pixels[cIdx]; }
238
239
  void set_image_plane(int cIdx, uint8_t* mem, ptrdiff_t stride, void *userdata);
240
241
  uint8_t* get_image_plane_at_pos(int cIdx, int xpos,int ypos)
242
0
  {
243
0
    ptrdiff_t stride = get_image_stride(cIdx);
244
0
    return pixels[cIdx] + xpos + ypos*stride;
245
0
  }
246
247
248
  /// xpos;ypos in actual plane resolution
249
  template <class pixel_t>
250
  pixel_t* get_image_plane_at_pos_NEW(int cIdx, int xpos,int ypos)
251
0
  {
252
0
    ptrdiff_t stride = get_image_stride(cIdx);
253
0
    return (pixel_t*)(pixels[cIdx] + (xpos + ypos*stride)*sizeof(pixel_t));
254
0
  }
Unexecuted instantiation: unsigned short* de265_image::get_image_plane_at_pos_NEW<unsigned short>(int, int, int)
Unexecuted instantiation: unsigned char* de265_image::get_image_plane_at_pos_NEW<unsigned char>(int, int, int)
255
256
  const uint8_t* get_image_plane_at_pos(int cIdx, int xpos,int ypos) const
257
0
  {
258
0
    ptrdiff_t stride = get_image_stride(cIdx);
259
0
    return pixels[cIdx] + xpos + ypos*stride;
260
0
  }
261
262
  void* get_image_plane_at_pos_any_depth(int cIdx, int xpos,int ypos)
263
0
  {
264
0
    ptrdiff_t stride = get_image_stride(cIdx);
265
0
    return pixels[cIdx] + ((xpos + ypos*stride) << bpp_shift[cIdx]);
266
0
  }
267
268
  const void* get_image_plane_at_pos_any_depth(int cIdx, int xpos,int ypos) const
269
0
  {
270
0
    ptrdiff_t stride = get_image_stride(cIdx);
271
0
    return pixels[cIdx] + ((xpos + ypos*stride) << bpp_shift[cIdx]);
272
0
  }
273
274
  /* Number of pixels in one row (not number of bytes).
275
   */
276
  ptrdiff_t get_image_stride(int cIdx) const
277
0
  {
278
0
    if (cIdx==0) return stride;
279
0
    else         return chroma_stride;
280
0
  }
281
282
0
  ptrdiff_t get_luma_stride() const { return stride; }
283
0
  ptrdiff_t get_chroma_stride() const { return chroma_stride; }
284
285
0
  int get_width (int cIdx=0) const { return cIdx==0 ? width  : chroma_width;  }
286
0
  int get_height(int cIdx=0) const { return cIdx==0 ? height : chroma_height; }
287
288
0
  de265_chroma get_chroma_format() const { return chroma_format; }
289
290
0
  int get_bit_depth(int cIdx) const {
291
0
    if (cIdx==0) return sps->BitDepth_Y;
292
0
    else         return sps->BitDepth_C;
293
0
  }
294
295
0
  int get_bytes_per_pixel(int cIdx) const {
296
0
    return (get_bit_depth(cIdx)+7)/8;
297
0
  }
298
299
0
  bool high_bit_depth(int cIdx) const {
300
0
    return get_bit_depth(cIdx)>8;
301
0
  }
302
303
0
  bool can_be_released() const { return PicOutputFlag==false && PicState==UnusedForReference; }
304
305
306
0
  void add_slice_segment_header(slice_segment_header* shdr) {
307
0
    shdr->slice_index = slices.size();
308
0
    slices.push_back(shdr);
309
0
  }
310
311
312
  bool available_zscan(int xCurr,int yCurr, int xN,int yN) const;
313
314
  bool available_pred_blk(int xC,int yC, int nCbS,
315
                          int xP, int yP, int nPbW, int nPbH, int partIdx,
316
                          int xN,int yN) const;
317
318
319
  static de265_image_allocation default_image_allocation;
320
321
0
  void printBlk(const char* title, int x0,int y0,int blkSize,int cIdx) const {
322
0
    ::printBlk(title, get_image_plane_at_pos(cIdx,x0,y0),
323
0
               blkSize, get_image_stride(cIdx));
324
0
  }
325
326
private:
327
  uint32_t ID = std::numeric_limits<uint32_t>::max();
328
329
  uint8_t* pixels[3] = { nullptr, nullptr, nullptr };
330
  uint8_t  bpp_shift[3] = {};  // 0 for 8 bit, 1 for 16 bit
331
332
  de265_chroma chroma_format = de265_chroma_mono;
333
334
  int width = 0, height = 0;  // size in luma pixels
335
336
  int chroma_width = 0, chroma_height = 0;
337
  ptrdiff_t stride = 0, chroma_stride = 0;
338
339
public:
340
  uint8_t BitDepth_Y = 0, BitDepth_C = 0;
341
  uint8_t SubWidthC = 0, SubHeightC = 0;
342
  std::vector<slice_segment_header*> slices;
343
344
public:
345
346
  // --- conformance cropping window ---
347
348
  uint8_t* pixels_confwin[3] = { nullptr, nullptr, nullptr };
349
350
  int width_confwin = 0, height_confwin = 0;
351
  int chroma_width_confwin = 0, chroma_height_confwin = 0;
352
353
  // --- decoding info ---
354
355
  // If PicOutputFlag==false && PicState==UnusedForReference, image buffer is free.
356
357
  int  picture_order_cnt_lsb = -1; // undefined
358
  int  PicOrderCntVal = -1; // undefined
359
  PictureState PicState = UnusedForReference;
360
  bool PicOutputFlag = false;
361
362
  uint32_t removed_at_picture_id = 0; // picture not used, so we can assume it has been removed
363
364
0
  const video_parameter_set& get_vps() const { return *vps; }
365
0
  const seq_parameter_set& get_sps() const { return *sps; }
366
0
  const pic_parameter_set& get_pps() const { return *pps; }
367
368
0
  bool has_vps() const { return vps != nullptr; }
369
0
  bool has_sps() const { return sps != nullptr; }
370
0
  bool has_pps() const { return pps != nullptr; }
371
372
0
  std::shared_ptr<const seq_parameter_set> get_shared_sps() { return sps; }
373
374
  //std::shared_ptr<const seq_parameter_set> get_shared_sps() const { return sps; }
375
  //std::shared_ptr<const pic_parameter_set> get_shared_pps() const { return pps; }
376
377
  decoder_context*    decctx = nullptr;
378
379
0
  [[nodiscard]] uint32_t number_of_ctbs() const { return static_cast<uint32_t>(ctb_info.size()); }
380
381
private:
382
  // The image also keeps a reference to VPS/SPS/PPS, because when decoding is delayed,
383
  // the currently active parameter sets in the decctx might already have been replaced
384
  // with new parameters.
385
  std::shared_ptr<const video_parameter_set> vps;
386
  std::shared_ptr<const seq_parameter_set>   sps;  // the SPS used for decoding this image
387
  std::shared_ptr<const pic_parameter_set>   pps;  // the PPS used for decoding this image
388
389
  MetaDataArray<CTB_info>    ctb_info;
390
  MetaDataArray<CB_ref_info> cb_info;
391
  MetaDataArray<PBMotion>    pb_info;
392
  MetaDataArray<uint8_t>     intraPredMode;
393
  MetaDataArray<uint8_t>     intraPredModeC;
394
  MetaDataArray<uint8_t>     tu_info;
395
  MetaDataArray<uint8_t>     deblk_info;
396
397
  template<typename Func>
398
0
  void set_cb_blk(int x, int y, int log2BlkWidth, Func setter) {
399
0
    int cbX = x >> cb_info.log2unitSize;
400
0
    int cbY = y >> cb_info.log2unitSize;
401
0
    int width = 1 << (log2BlkWidth - cb_info.log2unitSize);
402
0
    for (int cby=cbY;cby<cbY+width;cby++)
403
0
      for (int cbx=cbX;cbx<cbX+width;cbx++)
404
0
        setter(cb_info[ cbx + cby*cb_info.width_in_units ]);
405
0
  }
Unexecuted instantiation: void de265_image::set_cb_blk<de265_image::set_pred_mode(int, int, int, PredMode)::{lambda(CB_ref_info&)#1}>(int, int, int, de265_image::set_pred_mode(int, int, int, PredMode)::{lambda(CB_ref_info&)#1})
Unexecuted instantiation: void de265_image::set_cb_blk<de265_image::set_pcm_flag(int, int, int, unsigned char)::{lambda(CB_ref_info&)#1}>(int, int, int, de265_image::set_pcm_flag(int, int, int, unsigned char)::{lambda(CB_ref_info&)#1})
Unexecuted instantiation: void de265_image::set_cb_blk<de265_image::set_cu_transquant_bypass(int, int, int, unsigned char)::{lambda(CB_ref_info&)#1}>(int, int, int, de265_image::set_cu_transquant_bypass(int, int, int, unsigned char)::{lambda(CB_ref_info&)#1})
Unexecuted instantiation: void de265_image::set_cb_blk<de265_image::set_log2CbSize(int, int, int, bool)::{lambda(CB_ref_info&)#1}>(int, int, int, de265_image::set_log2CbSize(int, int, int, bool)::{lambda(CB_ref_info&)#1})
Unexecuted instantiation: void de265_image::set_cb_blk<de265_image::set_ctDepth(int, int, int, int)::{lambda(CB_ref_info&)#1}>(int, int, int, de265_image::set_ctDepth(int, int, int, int)::{lambda(CB_ref_info&)#1})
Unexecuted instantiation: void de265_image::set_cb_blk<de265_image::set_QPY(int, int, int, int)::{lambda(CB_ref_info&)#1}>(int, int, int, de265_image::set_QPY(int, int, int, int)::{lambda(CB_ref_info&)#1})
406
407
0
  void clear_tb_blk(int x, int y, int log2BlkWidth) {
408
0
    int tuX = x >> tu_info.log2unitSize;
409
0
    int tuY = y >> tu_info.log2unitSize;
410
0
    int width = 1 << (log2BlkWidth - tu_info.log2unitSize);
411
0
    for (int tuy=tuY;tuy<tuY+width;tuy++)
412
0
      for (int tux=tuX;tux<tuX+width;tux++)
413
0
        tu_info[ tux + tuy*tu_info.width_in_units ] = 0;
414
0
  }
415
416
public:
417
  // --- meta information ---
418
419
  de265_PTS pts = 0;
420
  void*     user_data = nullptr;
421
  void*     plane_user_data[3] = { nullptr, nullptr, nullptr };
422
  de265_image_allocation image_allocation_functions; // the functions used for memory allocation
423
424
  /*
425
  void (*encoder_image_release_func)(en265_encoder_context*,
426
                                     de265_image*,
427
                                     void* userdata);
428
  */
429
430
  uint8_t integrity = INTEGRITY_NOT_DECODED; /* Whether an error occurred while the image was decoded.
431
                                                When generated, this is initialized to INTEGRITY_CORRECT,
432
                                                and changed on decoding errors.
433
                                              */
434
  bool sei_hash_check_result = false;
435
436
  nal_header nal_hdr;
437
438
  // --- multi core ---
439
440
  de265_progress_lock* ctb_progress = nullptr; // ctb_info_size
441
442
0
  void mark_all_CTB_progress(int progress) {
443
0
    for (int i=0;i<ctb_info.data_size;i++) {
444
0
      ctb_progress[i].set_progress(progress);
445
0
    }
446
0
  }
447
448
449
  void thread_start(int nThreads);
450
  void thread_run(const thread_task*);
451
  void thread_blocks();
452
  void thread_unblocks();
453
  /* NOTE: you should not access any data in the thread_task after
454
     calling this, as this function may unlock other threads that
455
     will push this image to the output queue and free all decoder data. */
456
  void thread_finishes(const thread_task*);
457
458
  void wait_for_progress(thread_task* task, int ctbx,int ctby, int progress);
459
  void wait_for_progress(thread_task* task, int ctbAddrRS, int progress);
460
461
  void wait_for_completion();  // block until image is decoded by background threads
462
  bool debug_is_completed() const;
463
0
  int  num_threads_active() const { return nThreadsRunning + nThreadsBlocked; } // for debug only
464
465
  //private:
466
  int   nThreadsQueued = 0;
467
  int   nThreadsRunning = 0;
468
  int   nThreadsBlocked = 0;
469
  int   nThreadsFinished = 0;
470
  int   nThreadsTotal = 0;
471
472
  // ALIGNED_8(de265_sync_int tasks_pending); // number of tasks pending to complete decoding
473
  std::mutex mutex;
474
  std::condition_variable finished_cond;
475
476
public:
477
478
  /* Clear all CTB/CB/PB decoding data of this image.
479
     All CTB's processing states are set to 'unprocessed'.
480
  */
481
  void clear_metadata();
482
483
484
  // --- CB metadata access ---
485
486
  void set_pred_mode(int x,int y, int log2BlkWidth, PredMode mode)
487
0
  {
488
0
    set_cb_blk(x,y,log2BlkWidth, [mode](CB_ref_info& cb){ cb.PredMode = mode; });
489
0
  }
490
491
  void fill_pred_mode(PredMode mode)
492
0
  {
493
0
    for (int i=0;i<cb_info.data_size;i++)
494
0
      { cb_info[i].PredMode = MODE_INTRA; }
495
0
  }
496
497
  PredMode get_pred_mode(int x,int y) const
498
0
  {
499
0
    return (PredMode)cb_info.get(x,y).PredMode;
500
0
  }
501
502
  uint8_t get_cu_skip_flag(int x,int y) const
503
0
  {
504
0
    return get_pred_mode(x,y)==MODE_SKIP;
505
0
  }
506
507
  void set_pcm_flag(int x,int y, int log2BlkWidth, uint8_t value=1)
508
0
  {
509
0
    set_cb_blk(x,y,log2BlkWidth, [value](CB_ref_info& cb){ cb.pcm_flag = value; });
510
511
    // TODO: in the encoder, we somewhere have to clear this
512
0
    ctb_info.get(x,y).has_pcm_or_cu_transquant_bypass = true;
513
0
  }
514
515
  int  get_pcm_flag(int x,int y) const
516
0
  {
517
0
    return cb_info.get(x,y).pcm_flag;
518
0
  }
519
520
  void set_cu_transquant_bypass(int x,int y, int log2BlkWidth, uint8_t value=1)
521
0
  {
522
0
    set_cb_blk(x,y,log2BlkWidth, [value](CB_ref_info& cb){ cb.cu_transquant_bypass = value; });
523
524
    // TODO: in the encoder, we somewhere have to clear this
525
0
    ctb_info.get(x,y).has_pcm_or_cu_transquant_bypass = true;
526
0
  }
527
528
  int  get_cu_transquant_bypass(int x,int y) const
529
0
  {
530
0
    return cb_info.get(x,y).cu_transquant_bypass;
531
0
  }
532
533
  void set_log2CbSize(int x0, int y0, int log2CbSize, bool fill)
534
0
  {
535
    // In theory, we could assume that remaining cb_info blocks are initialized to zero.
536
    // But in corrupted streams, slices may overlap and set contradicting log2CbSizes.
537
    // We also need this for encoding.
538
0
    if (fill) {
539
0
      set_cb_blk(x0,y0,log2CbSize, [](CB_ref_info& cb){ cb.log2CbSize = 0; });
540
0
    }
541
542
0
    cb_info.get(x0,y0).log2CbSize = log2CbSize;
543
0
  }
544
545
  int  get_log2CbSize(int x0, int y0) const
546
0
  {
547
0
    return cb_info.get(x0,y0).log2CbSize;
548
0
  }
549
550
  // coordinates in CB units
551
  int  get_log2CbSize_cbUnits(int xCb, int yCb) const
552
0
  {
553
0
    return cb_info[ xCb + yCb*cb_info.width_in_units ].log2CbSize;
554
0
  }
555
556
  void set_PartMode(int x,int y, PartMode mode)
557
0
  {
558
0
    cb_info.get(x,y).PartMode = mode;
559
0
  }
560
561
  PartMode get_PartMode(int x,int y) const
562
0
  {
563
0
    return (PartMode)cb_info.get(x,y).PartMode;
564
0
  }
565
566
  void set_ctDepth(int x,int y, int log2BlkWidth, int depth)
567
0
  {
568
0
    set_cb_blk(x,y,log2BlkWidth, [depth](CB_ref_info& cb){ cb.ctDepth = depth; });
569
0
  }
570
571
  int get_ctDepth(int x,int y) const
572
0
  {
573
0
    return cb_info.get(x,y).ctDepth;
574
0
  }
575
576
  void set_QPY(int x,int y, int log2BlkWidth, int QP_Y)
577
0
  {
578
0
    set_cb_blk(x,y,log2BlkWidth, [QP_Y](CB_ref_info& cb){ cb.QP_Y = QP_Y; });
579
0
  }
580
581
  int  get_QPY(int x0,int y0) const
582
0
  {
583
0
    return cb_info.get(x0,y0).QP_Y;
584
0
  }
585
586
  // --- TU metadata access ---
587
588
  void set_split_transform_flag(int x0,int y0,int trafoDepth)
589
0
  {
590
0
    tu_info.get(x0,y0) |= (1<<trafoDepth);
591
0
  }
592
593
  void clear_split_transform_flags(int x0,int y0,int log2CbSize)
594
0
  {
595
0
    clear_tb_blk(x0,y0,log2CbSize);
596
0
  }
597
598
  int  get_split_transform_flag(int x0,int y0,int trafoDepth) const
599
0
  {
600
0
    return (tu_info.get(x0,y0) & (1<<trafoDepth));
601
0
  }
602
603
  void set_nonzero_coefficient(int x,int y, int log2TrafoSize)
604
0
  {
605
0
    const int tuX = x >> tu_info.log2unitSize;
606
0
    const int tuY = y >> tu_info.log2unitSize;
607
0
    const int width = 1 << (log2TrafoSize - tu_info.log2unitSize);
608
609
0
    for (int tuy=tuY;tuy<tuY+width;tuy++)
610
0
      for (int tux=tuX;tux<tuX+width;tux++)
611
0
        {
612
0
          tu_info[ tux + tuy*tu_info.width_in_units ] |= TU_FLAG_NONZERO_COEFF;
613
0
        }
614
0
  }
615
616
  int  get_nonzero_coefficient(int x,int y) const
617
0
  {
618
0
    return tu_info.get(x,y) & TU_FLAG_NONZERO_COEFF;
619
0
  }
620
621
622
  // --- intraPredMode metadata access ---
623
624
  IntraPredMode get_IntraPredMode(int x,int y) const
625
0
  {
626
0
    uint8_t ipm = intraPredMode.get(x,y);
627
628
    // sanitize values if IPM is uninitialized (because of earlier read error)
629
0
    if (ipm > 34) {
630
0
      ipm = 0;
631
0
    }
632
633
0
    return static_cast<IntraPredMode>(ipm);
634
0
  }
635
636
  IntraPredMode get_IntraPredMode_atIndex(int idx) const
637
0
  {
638
0
    uint8_t ipm = intraPredMode[idx];
639
0
    if (ipm > 34) { ipm = 0; }
640
0
    return static_cast<IntraPredMode>(ipm);
641
0
  }
642
643
  void set_IntraPredMode(int PUidx,int log2blkSize, IntraPredMode mode)
644
0
  {
645
0
    int pbSize = 1<<(log2blkSize - intraPredMode.log2unitSize);
646
647
0
    for (int y=0;y<pbSize;y++)
648
0
      for (int x=0;x<pbSize;x++)
649
0
        intraPredMode[PUidx + x + y*intraPredMode.width_in_units] = mode;
650
0
  }
651
652
  void set_IntraPredMode(int x0,int y0,int log2blkSize,
653
                         IntraPredMode mode)
654
0
  {
655
0
    int pbSize = 1<<(log2blkSize - intraPredMode.log2unitSize);
656
0
    int PUidx  = (x0>>sps->Log2MinPUSize) + (y0>>sps->Log2MinPUSize)*sps->PicWidthInMinPUs;
657
0
658
0
    for (int y=0;y<pbSize;y++)
659
0
      for (int x=0;x<pbSize;x++) {
660
0
        assert(x < sps->PicWidthInMinPUs);
661
0
        assert(y < sps->PicHeightInMinPUs);
662
0
663
0
        int idx = PUidx + x + y*intraPredMode.width_in_units;
664
0
        assert(idx<intraPredMode.data_size);
665
0
        intraPredMode[idx] = mode;
666
0
      }
667
0
  }
668
669
670
  IntraPredMode get_IntraPredModeC(int x,int y) const
671
0
  {
672
0
    return (IntraPredMode)(intraPredModeC.get(x,y) & 0x3f);
673
0
  }
674
675
  bool is_IntraPredModeC_Mode4(int x,int y) const
676
0
  {
677
0
    return intraPredModeC.get(x,y) & 0x80;
678
0
  }
679
680
  void set_IntraPredModeC(int x0,int y0,int log2blkSize, IntraPredMode mode,
681
                          bool is_mode4)
682
0
  {
683
0
    uint8_t combinedValue = mode;
684
0
    if (is_mode4) combinedValue |= 0x80;
685
686
0
    int pbSize = 1<<(log2blkSize - intraPredMode.log2unitSize);
687
0
    int PUidx  = (x0>>sps->Log2MinPUSize) + (y0>>sps->Log2MinPUSize)*sps->PicWidthInMinPUs;
688
689
0
    for (int y=0;y<pbSize;y++)
690
0
      for (int x=0;x<pbSize;x++) {
691
0
        assert(x<sps->PicWidthInMinPUs);
692
0
        assert(y<sps->PicHeightInMinPUs);
693
694
0
        int idx = PUidx + x + y*intraPredModeC.width_in_units;
695
0
        assert(idx<intraPredModeC.data_size);
696
0
        intraPredModeC[idx] = combinedValue;
697
0
      }
698
0
  }
699
700
701
702
  // --- CTB metadata access ---
703
704
  // address of first CTB in slice
705
  void set_SliceAddrRS(int ctbX, int ctbY, int SliceAddrRS)
706
0
  {
707
0
    if (ctbX >= ctb_info.width_in_units || ctbY >= ctb_info.height_in_units) {
708
0
      return;
709
0
    }
710
711
0
    int idx = ctbX + ctbY*ctb_info.width_in_units;
712
0
    ctb_info[idx].SliceAddrRS = SliceAddrRS;
713
0
  }
714
715
  int  get_SliceAddrRS(int ctbX, int ctbY) const
716
0
  {
717
0
    return ctb_info[ctbX + ctbY*ctb_info.width_in_units].SliceAddrRS;
718
0
  }
719
720
  int  get_SliceAddrRS_atCtbRS(int ctbRS) const
721
0
  {
722
0
    return ctb_info[ctbRS].SliceAddrRS;
723
0
  }
724
725
726
  void set_SliceHeaderIndex(int x, int y, int SliceHeaderIndex)
727
0
  {
728
0
    ctb_info.get(x,y).SliceHeaderIndex = SliceHeaderIndex;
729
0
  }
730
731
  uint16_t get_SliceHeaderIndex(int x, int y) const
732
0
  {
733
0
    return ctb_info.get(x,y).SliceHeaderIndex;
734
0
  }
735
736
  uint16_t get_SliceHeaderIndexCtb(int ctbX, int ctbY) const
737
0
  {
738
0
    return ctb_info[ctbX + ctbY*ctb_info.width_in_units].SliceHeaderIndex;
739
0
  }
740
741
  uint16_t get_SliceHeaderIndex_atIndex(int ctb) const
742
0
  {
743
0
    return ctb_info[ctb].SliceHeaderIndex;
744
0
  }
745
746
  bool is_SliceHeader_available(int x,int y) const
747
0
  {
748
0
    uint16_t idx = ctb_info.get(x,y).SliceHeaderIndex;
749
0
    return idx < slices.size();
750
0
  }
751
752
  slice_segment_header* get_SliceHeader(int x, int y)
753
0
  {
754
0
    uint16_t idx = get_SliceHeaderIndex(x,y);
755
0
    if (idx >= slices.size()) { return nullptr; }
756
0
    return slices[idx];
757
0
  }
758
759
  slice_segment_header* get_SliceHeaderCtb(int ctbX, int ctbY)
760
0
  {
761
0
    uint16_t idx = get_SliceHeaderIndexCtb(ctbX,ctbY);
762
0
    if (idx >= slices.size()) { return nullptr; }
763
0
    return slices[idx];
764
0
  }
765
766
  const slice_segment_header* get_SliceHeaderCtb(int ctbX, int ctbY) const
767
0
  {
768
0
    uint16_t idx = get_SliceHeaderIndexCtb(ctbX,ctbY);
769
0
    if (idx >= slices.size()) { return nullptr; }
770
0
    return slices[idx];
771
0
  }
772
773
  void set_sao_info(int ctbX,int ctbY,const sao_info* saoinfo)
774
0
  {
775
0
    sao_info* sao = &ctb_info[ctbX + ctbY*ctb_info.width_in_units].saoInfo;
776
777
0
    memcpy(sao,
778
0
           saoinfo,
779
0
           sizeof(sao_info));
780
0
  }
781
782
  const sao_info* get_sao_info(int ctbX,int ctbY) const
783
0
  {
784
0
    return &ctb_info[ctbX + ctbY*ctb_info.width_in_units].saoInfo;
785
0
  }
786
787
788
  void set_CtbDeblockFlag(int ctbX, int ctbY, bool flag)
789
0
  {
790
0
    int idx = ctbX + ctbY*ctb_info.width_in_units;
791
0
    ctb_info[idx].deblock = flag;
792
0
  }
793
794
  bool get_CtbDeblockFlag(int ctbX, int ctbY) const
795
0
  {
796
0
    return ctb_info[ctbX + ctbY*ctb_info.width_in_units].deblock;
797
0
  }
798
799
800
  bool get_CTB_has_pcm_or_cu_transquant_bypass(int ctbX,int ctbY) const
801
0
  {
802
0
    int idx = ctbX + ctbY*ctb_info.width_in_units;
803
0
    return ctb_info[idx].has_pcm_or_cu_transquant_bypass;
804
0
  }
805
806
807
808
  // --- DEBLK metadata access ---
809
810
0
  int  get_deblk_width()  const { return deblk_info.width_in_units; }
811
0
  int  get_deblk_height() const { return deblk_info.height_in_units; }
812
813
  void    set_deblk_flags(int x0,int y0, uint8_t flags)
814
0
  {
815
0
    const int xd = x0/4;
816
0
    const int yd = y0/4;
817
818
0
    if (xd<deblk_info.width_in_units &&
819
0
        yd<deblk_info.height_in_units) {
820
0
      deblk_info[xd + yd*deblk_info.width_in_units] |= flags;
821
0
    }
822
0
  }
823
824
  uint8_t get_deblk_flags(int x0,int y0) const
825
0
  {
826
0
    const int xd = x0/4;
827
0
    const int yd = y0/4;
828
829
0
    return deblk_info[xd + yd*deblk_info.width_in_units];
830
0
  }
831
832
  void    set_deblk_bS(int x0,int y0, uint8_t bS)
833
0
  {
834
0
    uint8_t* data = &deblk_info[x0/4 + y0/4*deblk_info.width_in_units];
835
0
    *data &= ~DEBLOCK_BS_MASK;
836
0
    *data |= bS;
837
0
  }
838
839
  uint8_t get_deblk_bS(int x0,int y0) const
840
0
  {
841
0
    return deblk_info[x0/4 + y0/4*deblk_info.width_in_units] & DEBLOCK_BS_MASK;
842
0
  }
843
844
845
  // --- PB metadata access ---
846
847
  const PBMotion& get_mv_info(int x,int y) const
848
0
  {
849
0
    return pb_info.get(x,y);
850
0
  }
851
852
  void set_mv_info(int x,int y, int nPbW,int nPbH, const PBMotion& mv);
853
854
  // --- value logging ---
855
856
  void printBlk(int x0,int y0, int cIdx, int log2BlkSize);
857
};
858
859
860
#endif