Coverage Report

Created: 2026-05-30 06:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/libde265/libde265/refpic.cc
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
#include "refpic.h"
22
#include "decctx.h"
23
#include "util.h"
24
25
#include <assert.h>
26
#include <stdlib.h>
27
#if defined(_MSC_VER) || defined(__MINGW32__)
28
# include <malloc.h>
29
#elif defined(HAVE_ALLOCA_H)
30
# include <alloca.h>
31
#endif
32
33
34
void ref_pic_set::reset()
35
380
{
36
380
  NumNegativePics = 0;
37
380
  NumPositivePics = 0;
38
380
  NumDeltaPocs = 0;
39
380
  NumPocTotalCurr_shortterm_only = 0;
40
41
6.46k
  for (int i=0;i<MAX_NUM_REF_PICS;i++) {
42
6.08k
    DeltaPocS0[i] = 0;
43
6.08k
    DeltaPocS1[i] = 0;
44
45
6.08k
    UsedByCurrPicS0[i] = 0;
46
6.08k
    UsedByCurrPicS1[i] = 0;
47
6.08k
  }
48
380
}
49
50
51
void ref_pic_set::compute_derived_values()
52
0
{
53
0
  NumPocTotalCurr_shortterm_only = 0;
54
55
0
  for (int i=0; i<NumNegativePics; i++)
56
0
    if (UsedByCurrPicS0[i])
57
0
      NumPocTotalCurr_shortterm_only++;
58
59
0
  for (int i=0; i<NumPositivePics; i++)
60
0
    if (UsedByCurrPicS1[i])
61
0
      NumPocTotalCurr_shortterm_only++;
62
63
0
  NumDeltaPocs = NumNegativePics + NumPositivePics;
64
65
66
  /*
67
    NOTE: this is done when reading the slice header.
68
    The value numPocTotalCurr is then stored in the slice header.
69
70
  for (int i = 0; i < num_long_term_sps + num_long_term_pics; i++ )
71
            if( UsedByCurrPicLt[i] )
72
              NumPocTotalCurr++
73
                }
74
  */
75
0
}
76
77
78
/* A ref-pic-set is coded either coded
79
   - as a list of the relative POC deltas themselves, or
80
   - by shifting an existing ref-pic-set by some number of frames
81
   When shifting an existing set, the frame 0 is also shifted as an additional reference frame.
82
   When coding the ref-pic-sets in the SPS, prediction is always from the previous set.
83
   In the slice header, the ref-pic-set can use any previous set as reference.
84
 */
85
bool read_short_term_ref_pic_set(error_queue* errqueue,
86
                                 const seq_parameter_set* sps,
87
                                 bitreader* br,
88
                                 ref_pic_set* out_set, // where to store the read set
89
                                 uint32_t idxRps,  // index of the set to be read
90
                                 const std::vector<ref_pic_set>& sets, // previously read sets
91
                                 bool sliceRefPicSet) // is this in the slice header?
92
2
{
93
  // --- is this set coded in prediction mode (not possible for the first set)
94
95
2
  char inter_ref_pic_set_prediction_flag;
96
97
2
  if (idxRps != 0) {
98
0
    inter_ref_pic_set_prediction_flag = br->get_bits(1);
99
0
  }
100
2
  else {
101
2
    inter_ref_pic_set_prediction_flag = 0;
102
2
  }
103
104
105
106
2
  if (inter_ref_pic_set_prediction_flag) {
107
0
    uint32_t vlc;
108
109
    /* Only for the last ref_pic_set (that's the one coded in the slice header),
110
       we can specify relative to which reference set we code the set. */
111
112
0
    uint32_t delta_idx;
113
0
    if (sliceRefPicSet) { // idxRps == num_short_term_ref_pic_sets) {
114
0
      vlc = br->get_uvlc();
115
0
      if (vlc==UVLC_ERROR || vlc >= idxRps) {
116
0
        return false;
117
0
      }
118
0
      delta_idx = vlc;
119
120
0
      delta_idx++;
121
0
    } else {
122
0
      delta_idx = 1;
123
0
    }
124
125
0
    assert(idxRps >= delta_idx);
126
0
    int RIdx = idxRps - delta_idx; // this is our source set, which we will modify (TODO: change type to uint8_t)
127
128
0
    int delta_rps_sign = br->get_bits(1);
129
0
    vlc = br->get_uvlc();
130
    // abs_delta_rps_minus1 shall be in [0, 2^15-1] (Sec. 7.4.8)
131
0
    if (vlc==UVLC_ERROR || vlc > 32767) { return false; }
132
0
    uint16_t abs_delta_rps = vlc + 1;
133
0
    int DeltaRPS = (delta_rps_sign ? -abs_delta_rps : abs_delta_rps);
134
135
    // bits are stored in this order:
136
    // - all bits for negative Pocs (forward),
137
    // - then all bits for positive Pocs (forward),
138
    // - then bits for '0', shifting of the current picture
139
    // in total, these are 'nDeltaPocsRIdx'+1 bits
140
141
0
    logtrace(LogHeaders,"predicted from %d with delta %d\n",RIdx,DeltaRPS);
142
143
0
    int nDeltaPocsRIdx= sets[RIdx].NumDeltaPocs; // size of source set
144
0
    char *const used_by_curr_pic_flag = (char *)alloca((nDeltaPocsRIdx+1) * sizeof(char));
145
0
    char *const use_delta_flag = (char *)alloca((nDeltaPocsRIdx+1) * sizeof(char));
146
147
0
    for (int j=0;j<=nDeltaPocsRIdx;j++) {
148
0
      used_by_curr_pic_flag[j] = br->get_bits(1);
149
0
      if (used_by_curr_pic_flag[j]) {
150
0
        use_delta_flag[j] = 1;  // if this frame is used, we also have to apply the delta
151
0
      } else {
152
0
        use_delta_flag[j] = br->get_bits(1);  // otherwise, it is only optionally included
153
0
      }
154
0
    }
155
156
0
    logtrace(LogHeaders,"flags: ");
157
0
    for (int j=0;j<=nDeltaPocsRIdx;j++) {
158
0
      logtrace(LogHeaders,"%d ", use_delta_flag[j]);
159
0
    }
160
0
    logtrace(LogHeaders,"\n");
161
162
0
    int nNegativeRIdx = sets[RIdx].NumNegativePics;
163
0
    int nPositiveRIdx = sets[RIdx].NumPositivePics;
164
165
    // --- update list 0 (negative Poc) ---
166
    // Iterate through all Pocs in decreasing value order (positive reverse, 0, negative forward).
167
168
0
    int i=0; // target index
169
170
    // positive list
171
0
    for (int j=nPositiveRIdx-1;j>=0;j--) {
172
0
      assert(RIdx >= 0 && static_cast<size_t>(RIdx) < sets.size());
173
0
      assert(j>=0 && j < MAX_NUM_REF_PICS);
174
175
0
      int dPoc = sets[RIdx].DeltaPocS1[j] + DeltaRPS; // new delta
176
0
      if (dPoc<0 && use_delta_flag[nNegativeRIdx+j]) {
177
0
        if (i>= MAX_NUM_REF_PICS) { return false; }
178
179
0
        out_set->DeltaPocS0[i] = dPoc;
180
0
        out_set->UsedByCurrPicS0[i] = used_by_curr_pic_flag[nNegativeRIdx+j];
181
0
        i++;
182
0
      }
183
0
    }
184
185
    // frame 0
186
0
    if (DeltaRPS<0 && use_delta_flag[nDeltaPocsRIdx]) {
187
0
      if (i>= MAX_NUM_REF_PICS) { return false; }
188
189
0
      out_set->DeltaPocS0[i] = DeltaRPS;
190
0
      out_set->UsedByCurrPicS0[i] = used_by_curr_pic_flag[nDeltaPocsRIdx];
191
0
      i++;
192
0
    }
193
194
    // negative list
195
0
    for (int j=0;j<nNegativeRIdx;j++) {
196
0
      int dPoc = sets[RIdx].DeltaPocS0[j] + DeltaRPS;
197
0
      if (dPoc<0 && use_delta_flag[j]) {
198
0
        if (i>= MAX_NUM_REF_PICS) { return false; }
199
200
0
        out_set->DeltaPocS0[i] = dPoc;
201
0
        out_set->UsedByCurrPicS0[i] = used_by_curr_pic_flag[j];
202
0
        i++;
203
0
      }
204
0
    }
205
206
0
    out_set->NumNegativePics = i;
207
208
209
    // --- update list 1 (positive Poc) ---
210
    // Iterate through all Pocs in increasing value order (negative reverse, 0, positive forward)
211
212
0
    i=0; // target index
213
214
    // negative list
215
0
    for (int j=nNegativeRIdx-1;j>=0;j--) {
216
0
      int dPoc = sets[RIdx].DeltaPocS0[j] + DeltaRPS;
217
0
      if (dPoc>0 && use_delta_flag[j]) {
218
0
        if (i>= MAX_NUM_REF_PICS) { return false; }
219
220
0
        out_set->DeltaPocS1[i] = dPoc;
221
0
        out_set->UsedByCurrPicS1[i] = used_by_curr_pic_flag[j];
222
0
        i++;
223
0
      }
224
0
    }
225
226
    // frame 0
227
0
    if (DeltaRPS>0 && use_delta_flag[nDeltaPocsRIdx]) {
228
0
      if (i>= MAX_NUM_REF_PICS) { return false; }
229
230
0
      out_set->DeltaPocS1[i] = DeltaRPS;
231
0
      out_set->UsedByCurrPicS1[i] = used_by_curr_pic_flag[nDeltaPocsRIdx];
232
0
      i++;
233
0
    }
234
235
    // positive list
236
0
    for (int j=0;j<nPositiveRIdx;j++) {
237
0
      int dPoc = sets[RIdx].DeltaPocS1[j] + DeltaRPS;
238
0
      if (dPoc>0 && use_delta_flag[nNegativeRIdx+j]) {
239
0
        if (i>= MAX_NUM_REF_PICS) { return false; }
240
241
0
        out_set->DeltaPocS1[i] = dPoc;
242
0
        out_set->UsedByCurrPicS1[i] = used_by_curr_pic_flag[nNegativeRIdx+j];
243
0
        i++;
244
0
      }
245
0
    }
246
247
0
    out_set->NumPositivePics = i;
248
249
2
  } else {
250
251
    // --- first, read the number of past and future frames in this set ---
252
253
2
    uint32_t num_negative_pics = br->get_uvlc();
254
2
    uint32_t num_positive_pics = br->get_uvlc();
255
256
2
    if (num_negative_pics == UVLC_ERROR ||
257
1
        num_positive_pics == UVLC_ERROR ||
258
0
        num_negative_pics > MAX_NUM_REF_PICS ||
259
2
        num_positive_pics > MAX_NUM_REF_PICS) {
260
2
      errqueue->add_warning(DE265_WARNING_MAX_NUM_REF_PICS_EXCEEDED, false);
261
2
      return false;
262
2
    }
263
264
    // total number of reference pictures may not exceed buffer capacity
265
0
    if (num_negative_pics + num_positive_pics >
266
0
        static_cast<uint32_t>(sps->sps_max_dec_pic_buffering[ sps->sps_max_sub_layers-1 ])) {
267
268
0
      out_set->NumNegativePics = 0;
269
0
      out_set->NumPositivePics = 0;
270
0
      out_set->NumDeltaPocs = 0;
271
0
      out_set->NumPocTotalCurr_shortterm_only = 0;
272
273
0
      errqueue->add_warning(DE265_WARNING_MAX_NUM_REF_PICS_EXCEEDED, false);
274
0
      return false;
275
0
    }
276
277
0
    out_set->NumNegativePics = num_negative_pics;
278
0
    out_set->NumPositivePics = num_positive_pics;
279
280
    // --- now, read the deltas between the reference frames to fill the lists ---
281
282
    // past frames
283
284
0
    int16_t lastPocS=0;
285
0
    for (uint32_t i=0;i<num_negative_pics;i++) {
286
0
      uint32_t delta_poc_s0 = br->get_uvlc();
287
0
      if (delta_poc_s0==UVLC_ERROR) { return false; }
288
0
      delta_poc_s0++;
289
0
      char used_by_curr_pic_s0_flag = br->get_bits(1);
290
291
0
      if (delta_poc_s0 > static_cast<uint32_t>(lastPocS - INT16_MIN)) {
292
0
        errqueue->add_warning(DE265_ERROR_CODED_PARAMETER_OUT_OF_RANGE, false);
293
0
        return false;
294
0
      }
295
      // cast to int because delta_poc_s0 can be up to 32768 when lastPocS==0
296
0
      int16_t pocS = lastPocS - static_cast<int>(delta_poc_s0);
297
0
      out_set->DeltaPocS0[i]      = pocS;
298
0
      out_set->UsedByCurrPicS0[i] = used_by_curr_pic_s0_flag;
299
0
      lastPocS = pocS;
300
0
    }
301
302
    // future frames
303
304
0
    lastPocS = 0;
305
0
    for (uint32_t i=0;i<num_positive_pics;i++) {
306
0
      uint32_t delta_poc_s1 = br->get_uvlc();
307
0
      if (delta_poc_s1==UVLC_ERROR) { return false; }
308
0
      delta_poc_s1++;
309
0
      char used_by_curr_pic_s1_flag = br->get_bits(1);
310
311
0
      if (delta_poc_s1 > static_cast<uint32_t>(INT16_MAX - lastPocS)) {
312
0
        errqueue->add_warning(DE265_ERROR_CODED_PARAMETER_OUT_OF_RANGE, false);
313
0
        return false;
314
0
      }
315
0
      int16_t pocS = lastPocS + static_cast<int16_t>(delta_poc_s1);
316
0
      out_set->DeltaPocS1[i]      = pocS;
317
0
      out_set->UsedByCurrPicS1[i] = used_by_curr_pic_s1_flag;
318
0
      lastPocS = pocS;
319
0
    }
320
0
  }
321
322
323
0
  out_set->compute_derived_values();
324
325
  // The unused short-term references are all collected into a single PocStFoll array
326
  // of MAX_NUM_REF_PICS entries (see decoder_context::process_reference_picture_set).
327
  // While each individual list is bounded above, the predicted-RPS construction can
328
  // append the current-picture delta to an already-full source set, pushing the
329
  // combined count past MAX_NUM_REF_PICS. Reject such sets to avoid an out-of-bounds
330
  // write when filling PocStFoll.
331
0
  if (out_set->NumDeltaPocs > MAX_NUM_REF_PICS) {
332
0
    out_set->NumNegativePics = 0;
333
0
    out_set->NumPositivePics = 0;
334
0
    out_set->NumDeltaPocs = 0;
335
0
    out_set->NumPocTotalCurr_shortterm_only = 0;
336
337
0
    errqueue->add_warning(DE265_WARNING_MAX_NUM_REF_PICS_EXCEEDED, false);
338
0
    return false;
339
0
  }
340
341
0
  return true;
342
0
}
343
344
345
bool write_short_term_ref_pic_set_nopred(error_queue* errqueue,
346
                                         const seq_parameter_set* sps,
347
                                         CABAC_encoder& out,
348
                                         const ref_pic_set* in_set, // which set to write
349
                                         uint32_t idxRps,  // index of the set to be written
350
                                         const std::vector<ref_pic_set>& sets, // previously read sets
351
                                         bool sliceRefPicSet) // is this in the slice header?
352
0
{
353
0
  if (idxRps != 0) {
354
    // inter_ref_pic_set_prediction_flag
355
0
    out.write_bit(0);
356
0
  }
357
358
359
  // --- first, write the number of past and future frames in this set ---
360
361
0
  out.write_uvlc(in_set->NumNegativePics);
362
0
  out.write_uvlc(in_set->NumPositivePics);
363
364
  // --- now, write the deltas between the reference frames to fill the lists ---
365
366
  // past frames
367
368
0
  int lastPocS=0;
369
0
  for (int i=0;i<in_set->NumNegativePics;i++) {
370
0
    int  delta_poc_s0 = lastPocS - in_set->DeltaPocS0[i];
371
0
    char used_by_curr_pic_s0_flag = in_set->UsedByCurrPicS0[i];
372
373
0
    assert(delta_poc_s0 >= 1);
374
0
    out.write_uvlc(delta_poc_s0-1);
375
0
    out.write_bit(used_by_curr_pic_s0_flag);
376
0
    lastPocS = in_set->DeltaPocS0[i];
377
0
  }
378
379
  // future frames
380
381
0
  lastPocS=0;
382
0
  for (int i=0;i<in_set->NumPositivePics;i++) {
383
0
    int  delta_poc_s1 = in_set->DeltaPocS1[i] - lastPocS;
384
0
    char used_by_curr_pic_s1_flag = in_set->UsedByCurrPicS1[i];
385
386
0
    assert(delta_poc_s1 >= 1);
387
0
    out.write_uvlc(delta_poc_s1-1);
388
0
    out.write_bit(used_by_curr_pic_s1_flag);
389
0
    lastPocS = in_set->DeltaPocS1[i];
390
0
  }
391
392
0
  return true;
393
0
}
394
395
396
bool write_short_term_ref_pic_set(error_queue* errqueue,
397
                                  const seq_parameter_set* sps,
398
                                  CABAC_encoder& out,
399
                                  const ref_pic_set* in_set, // which set to write
400
                                  uint32_t idxRps,  // index of the set to be read
401
                                  const std::vector<ref_pic_set>& sets, // previously read sets
402
                                  bool sliceRefPicSet) // is this in the slice header?
403
0
{
404
0
  return write_short_term_ref_pic_set_nopred(errqueue, sps, out, in_set, idxRps, sets,
405
0
                                             sliceRefPicSet);
406
0
}
407
408
409
void dump_short_term_ref_pic_set(const ref_pic_set* set, FILE* fh)
410
0
{
411
0
  log2fh(fh,"NumDeltaPocs: %d [-:%d +:%d]\n", set->NumDeltaPocs,
412
0
         set->NumNegativePics, set->NumPositivePics);
413
414
0
  log2fh(fh,"DeltaPocS0:");
415
0
  for (int i=0;i<set->NumNegativePics;i++) {
416
0
    if (i) { log2fh(fh,","); }
417
0
    log2fh(fh," %d/%d",set->DeltaPocS0[i],set->UsedByCurrPicS0[i]);
418
0
  }
419
0
  log2fh(fh,"\n");
420
421
0
  log2fh(fh,"DeltaPocS1:");
422
0
  for (int i=0;i<set->NumPositivePics;i++) {
423
0
    if (i) { log2fh(fh,","); }
424
0
    log2fh(fh," %d/%d",set->DeltaPocS1[i],set->UsedByCurrPicS1[i]);
425
0
  }
426
0
  log2fh(fh,"\n");
427
0
}
428
429
430
void dump_compact_short_term_ref_pic_set(const ref_pic_set* set, int range, FILE* fh)
431
0
{
432
0
  char *const log = (char *)alloca((range+1+range+1) * sizeof(char));
433
0
  log[2*range+1] = 0;
434
0
  for (int i=0;i<2*range+1;i++) log[i]='.';
435
0
  log[range]='|';
436
437
0
  for (int i=set->NumNegativePics-1;i>=0;i--) {
438
0
    int n = set->DeltaPocS0[i];
439
0
    if (n>=-range && n<=range) {
440
0
      if (set->UsedByCurrPicS0[i]) log[n+range] = 'X';
441
0
      else log[n+range] = 'o';
442
0
    } else { log2fh(fh,"*%d%c ",n, set->UsedByCurrPicS0[i] ? 'X':'o'); }
443
0
  }
444
445
0
  for (int i=set->NumPositivePics-1;i>=0;i--) {
446
0
    int n = set->DeltaPocS1[i];
447
0
    if (n>=-range && n<=range) {
448
0
      if (set->UsedByCurrPicS1[i]) log[n+range] = 'X';
449
0
      else log[n+range] = 'o';
450
0
    } else { log2fh(fh,"*%d%c ",n, set->UsedByCurrPicS1[i] ? 'X':'o'); }
451
0
  }
452
453
0
  log2fh(fh,"*%s\n",log);
454
0
}