Coverage Report

Created: 2026-03-08 06:41

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