Coverage Report

Created: 2026-09-13 06:28

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