Coverage Report

Created: 2026-06-30 07:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libde265/libde265/dpb.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 "dpb.h"
22
#include "decctx.h"
23
#include <string.h>
24
#include <assert.h>
25
26
27
decoded_picture_buffer::~decoded_picture_buffer()
28
9.02k
{
29
21.9k
  for (size_t i=0;i<dpb.size();i++)
30
12.9k
    delete dpb[i];
31
9.02k
}
32
33
34
void decoded_picture_buffer::log_dpb_content() const
35
23.2k
{
36
54.6k
  for (size_t i=0;i<dpb.size();i++) {
37
31.4k
    loginfo(LogHighlevel, " DPB %d: POC=%d, ID=%d %s %s\n", i,
38
31.4k
            dpb[i]->PicOrderCntVal,
39
31.4k
            dpb[i]->get_ID(),
40
31.4k
            dpb[i]->PicState == UnusedForReference ? "unused" :
41
31.4k
            dpb[i]->PicState == UsedForShortTermReference ? "short-term" : "long-term",
42
31.4k
            dpb[i]->PicOutputFlag ? "output" : "---");
43
31.4k
  }
44
23.2k
}
45
46
47
bool decoded_picture_buffer::has_free_dpb_picture(bool high_priority) const
48
26.8k
{
49
  // we will always adapt the buffer to insert high-priority images
50
26.8k
  if (high_priority) return true;
51
52
  // quick test to check for free slots
53
26.8k
  if (dpb.size() < max_images_in_DPB) return true;
54
55
  // scan for empty slots
56
0
  for (size_t i=0;i<dpb.size();i++) {
57
0
    if (dpb[i]->PicOutputFlag==false && dpb[i]->PicState == UnusedForReference) {
58
0
      return true;
59
0
    }
60
0
  }
61
62
0
  return false;
63
0
}
64
65
66
int decoded_picture_buffer::DPB_index_of_picture_with_POC(int poc, uint32_t currentID, bool preferLongTerm) const
67
8.03k
{
68
8.03k
  logdebug(LogHeaders,"DPB_index_of_picture_with_POC POC=%d\n",poc);
69
70
  //log_dpb_content(ctx);
71
  //loginfo(LogDPB,"searching for short-term reference POC=%d\n",poc);
72
73
8.03k
  if (preferLongTerm) {
74
8.00k
    for (size_t k=0;k<dpb.size();k++) {
75
4.83k
      if (dpb[k]->PicOrderCntVal == poc &&
76
115
          dpb[k]->removed_at_picture_id > currentID &&
77
110
          dpb[k]->PicState == UsedForLongTermReference) {
78
28
        return k;
79
28
      }
80
4.83k
    }
81
3.19k
  }
82
83
22.6k
  for (size_t k=0;k<dpb.size();k++) {
84
14.8k
    if (dpb[k]->PicOrderCntVal == poc &&
85
290
        dpb[k]->removed_at_picture_id > currentID &&
86
283
        dpb[k]->PicState != UnusedForReference) {
87
283
      return k;
88
283
    }
89
14.8k
  }
90
91
7.72k
  return -1;
92
8.00k
}
93
94
95
int decoded_picture_buffer::DPB_index_of_picture_with_LSB(int lsb, uint32_t currentID, bool preferLongTerm) const
96
1.52k
{
97
1.52k
  logdebug(LogHeaders,"get access to picture with LSB %d from DPB\n",lsb);
98
99
1.52k
  if (preferLongTerm) {
100
4.10k
    for (size_t k=0;k<dpb.size();k++) {
101
2.69k
      if (dpb[k]->picture_order_cnt_lsb == lsb &&
102
459
          dpb[k]->removed_at_picture_id > currentID &&
103
452
          dpb[k]->PicState == UsedForLongTermReference) {
104
114
        return k;
105
114
      }
106
2.69k
    }
107
1.52k
  }
108
109
3.35k
  for (size_t k=0;k<dpb.size();k++) {
110
2.27k
    if (dpb[k]->picture_order_cnt_lsb == lsb &&
111
334
        dpb[k]->removed_at_picture_id > currentID &&
112
327
        dpb[k]->PicState != UnusedForReference) {
113
327
      return k;
114
327
    }
115
2.27k
  }
116
117
1.08k
  return -1;
118
1.41k
}
119
120
121
int decoded_picture_buffer::DPB_index_of_picture_with_ID(uint32_t id) const
122
130
{
123
130
  logdebug(LogHeaders,"get access to picture with ID %d from DPB\n",id);
124
125
282
  for (size_t k=0;k<dpb.size();k++) {
126
282
    if (dpb[k]->get_ID() == id) {
127
130
      return k;
128
130
    }
129
282
  }
130
131
0
  return -1;
132
130
}
133
134
135
void decoded_picture_buffer::output_next_picture_in_reorder_buffer()
136
4.40k
{
137
4.40k
  assert(!reorder_output_queue.empty());
138
139
  // search for picture in reorder buffer with minimum POC
140
141
4.40k
  int minPOC = reorder_output_queue[0]->PicOrderCntVal;
142
4.40k
  int minIdx = 0;
143
4.41k
  for (size_t i=1;i<reorder_output_queue.size();i++)
144
18
    {
145
18
      if (reorder_output_queue[i]->PicOrderCntVal < minPOC) {
146
16
        minPOC = reorder_output_queue[i]->PicOrderCntVal;
147
16
        minIdx = i;
148
16
      }
149
18
    }
150
151
152
  // put image into output queue
153
154
4.40k
  image_output_queue.push_back(reorder_output_queue[minIdx]);
155
156
157
  // remove image from reorder buffer
158
159
4.40k
  reorder_output_queue[minIdx] = reorder_output_queue.back();
160
4.40k
  reorder_output_queue.pop_back();
161
4.40k
}
162
163
164
bool decoded_picture_buffer::flush_reorder_buffer()
165
116k
{
166
  // return 'false' when there are no pictures in reorder buffer
167
116k
  if (reorder_output_queue.empty()) return false;
168
169
51
  while (!reorder_output_queue.empty()) {
170
29
    output_next_picture_in_reorder_buffer();
171
29
  }
172
173
22
  return true;
174
116k
}
175
176
177
void decoded_picture_buffer::clear()
178
0
{
179
0
  for (size_t i=0;i<dpb.size();i++) {
180
0
    if (dpb[i]->PicOutputFlag ||
181
0
        dpb[i]->PicState != UnusedForReference)
182
0
      {
183
0
        dpb[i]->PicOutputFlag = false;
184
0
        dpb[i]->PicState = UnusedForReference;
185
0
        dpb[i]->release();
186
0
      }
187
0
  }
188
189
0
  reorder_output_queue.clear();
190
0
  image_output_queue.clear();
191
0
}
192
193
194
int decoded_picture_buffer::new_image(std::shared_ptr<const seq_parameter_set> sps,
195
                                      decoder_context* decctx,
196
                                      de265_PTS pts, void* user_data, bool isOutputImage)
197
12.9k
{
198
12.9k
  loginfo(LogHeaders,"DPB::new_image\n");
199
12.9k
  log_dpb_content();
200
201
  // --- search for a free slot in the DPB ---
202
203
12.9k
  uint8_t free_image_buffer_idx = 0;
204
12.9k
  uint8_t err = DE265_ERROR_IMAGE_BUFFER_FULL;
205
206
25.7k
  for (size_t i=0;i<dpb.size();i++) {
207
12.8k
    if (dpb[i]->can_be_released()) {
208
0
      dpb[i]->release(); /* TODO: this is surely not the best place to free the image, but
209
                            we have to do it here because releasing it in de265_release_image()
210
                            would break the API compatibility. */
211
212
0
      free_image_buffer_idx = i;
213
0
      err = DE265_OK;
214
0
      break;
215
0
    }
216
12.8k
  }
217
218
219
  // Try to free a buffer at the end if the DPB got too large.
220
  /* This should also probably move to a better place as soon as the API allows for this. */
221
222
12.9k
  if (dpb.size() > norm_images_in_DPB &&           // buffer too large
223
0
      free_image_buffer_idx != dpb.size()-1 &&     // last slot not reused in this alloc
224
0
      dpb.back()->can_be_released())               // last slot is free
225
0
    {
226
0
      delete dpb.back();
227
0
      dpb.pop_back();
228
0
    }
229
230
231
  // create a new image slot if no empty slot remaining
232
233
12.9k
  if (err == DE265_ERROR_IMAGE_BUFFER_FULL) {
234
12.9k
    size_t dpb_size = dpb.size();
235
12.9k
    assert(dpb_size < 255);
236
237
12.9k
    free_image_buffer_idx = static_cast<uint8_t>(dpb_size);
238
12.9k
    dpb.push_back(new de265_image);
239
12.9k
    err = DE265_OK;
240
12.9k
  }
241
242
243
  // --- allocate new image ---
244
245
12.9k
  if (err) {
246
0
    return -err;
247
0
  }
248
249
12.9k
  de265_image* img = dpb[free_image_buffer_idx];
250
251
12.9k
  int w = sps->pic_width_in_luma_samples;
252
12.9k
  int h = sps->pic_height_in_luma_samples;
253
254
  // --- enforce maximum image size before allocating the image buffer ---
255
256
12.9k
  uint32_t max_image_size_pixels = decctx->param_security_limits.max_image_size_pixels;
257
12.9k
  if (max_image_size_pixels != 0 &&
258
12.9k
      (uint64_t)w * h > max_image_size_pixels) {
259
84
    return -DE265_ERROR_IMAGE_SIZE_EXCEEDS_SECURITY_LIMIT;
260
84
  }
261
262
12.8k
  enum de265_chroma chroma;
263
12.8k
  switch (sps->chroma_format_idc) {
264
0
  case 0: chroma = de265_chroma_mono; break;
265
6.79k
  case 1: chroma = de265_chroma_420;  break;
266
3.62k
  case 2: chroma = de265_chroma_422;  break;
267
2.43k
  case 3: chroma = de265_chroma_444;  break;
268
0
  default: chroma = de265_chroma_420; assert(0); break; // should never happen
269
12.8k
  }
270
271
12.8k
  de265_error error = img->alloc_image(w,h, chroma, sps, true, decctx, /*nullptr,*/ pts, user_data, isOutputImage);
272
12.8k
  if (error) {
273
1
    return -error;
274
1
  }
275
276
12.8k
  img->integrity = INTEGRITY_CORRECT;
277
278
12.8k
  return free_image_buffer_idx;
279
12.8k
}
280
281
282
void decoded_picture_buffer::pop_next_picture_in_output_queue()
283
4.39k
{
284
4.39k
  image_output_queue.pop_front();
285
286
287
4.39k
  loginfo(LogDPB, "DPB output queue: ");
288
4.40k
  for (size_t i=0;i<image_output_queue.size();i++) {
289
7
    loginfo(LogDPB, "*%d ", image_output_queue[i]->PicOrderCntVal);
290
7
  }
291
4.39k
  loginfo(LogDPB,"*\n");
292
4.39k
}
293
294
295
void decoded_picture_buffer::log_dpb_queues() const
296
5.03k
{
297
5.03k
    loginfo(LogDPB, "DPB reorder queue (after push): ");
298
5.09k
    for (int i=0;i<num_pictures_in_reorder_buffer();i++) {
299
66
      loginfo(LogDPB, "*%d ", reorder_output_queue[i]->PicOrderCntVal);
300
66
    }
301
5.03k
    loginfo(LogDPB,"*\n");
302
303
5.03k
    loginfo(LogDPB, "DPB output queue (after push): ");
304
9.41k
    for (int i=0;i<num_pictures_in_output_queue();i++) {
305
4.38k
      loginfo(LogDPB, "*%d ", image_output_queue[i]->PicOrderCntVal);
306
4.38k
    }
307
5.03k
    loginfo(LogDPB,"*\n");
308
5.03k
}