Coverage Report

Created: 2026-05-16 06:27

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