Coverage Report

Created: 2025-08-28 06:29

/src/libvpx/vp8/decoder/onyxd_if.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3
 *
4
 *  Use of this source code is governed by a BSD-style license
5
 *  that can be found in the LICENSE file in the root of the source
6
 *  tree. An additional intellectual property rights grant can be found
7
 *  in the file PATENTS.  All contributing project authors may
8
 *  be found in the AUTHORS file in the root of the source tree.
9
 */
10
11
#include "vp8/common/onyxc_int.h"
12
#if CONFIG_POSTPROC
13
#include "vp8/common/postproc.h"
14
#endif
15
#include "vp8/common/onyxd.h"
16
#include "onyxd_int.h"
17
#include "vpx_mem/vpx_mem.h"
18
#include "vp8/common/alloccommon.h"
19
#include "vp8/common/common.h"
20
#include "vp8/common/loopfilter.h"
21
#include "vp8/common/swapyv12buffer.h"
22
#include "vp8/common/threading.h"
23
#include "decoderthreading.h"
24
#include <stdio.h>
25
#include <assert.h>
26
27
#include "vp8/common/quant_common.h"
28
#include "vp8/common/reconintra.h"
29
#include "./vpx_dsp_rtcd.h"
30
#include "./vpx_scale_rtcd.h"
31
#include "vpx_scale/vpx_scale.h"
32
#include "vp8/common/systemdependent.h"
33
#include "vpx_ports/system_state.h"
34
#include "vpx_ports/vpx_once.h"
35
#include "vpx_ports/vpx_timer.h"
36
#include "detokenize.h"
37
#if CONFIG_ERROR_CONCEALMENT
38
#include "error_concealment.h"
39
#endif
40
#if VPX_ARCH_ARM
41
#include "vpx_ports/arm.h"
42
#endif
43
44
extern void vp8_init_loop_filter(VP8_COMMON *cm);
45
static int get_free_fb(VP8_COMMON *cm);
46
static void ref_cnt_fb(int *buf, int *idx, int new_idx);
47
48
1
static void initialize_dec(void) {
49
1
  static volatile int init_done = 0;
50
51
1
  if (!init_done) {
52
1
    vpx_dsp_rtcd();
53
1
    vp8_init_intra_predictors();
54
1
    init_done = 1;
55
1
  }
56
1
}
57
58
7.89k
static void remove_decompressor(VP8D_COMP *pbi) {
59
#if CONFIG_ERROR_CONCEALMENT
60
  vp8_de_alloc_overlap_lists(pbi);
61
#endif
62
7.89k
  vp8_remove_common(&pbi->common);
63
7.89k
  vpx_free(pbi);
64
7.89k
}
65
66
7.89k
static struct VP8D_COMP *create_decompressor(VP8D_CONFIG *oxcf) {
67
7.89k
  VP8D_COMP *pbi = vpx_memalign(32, sizeof(VP8D_COMP));
68
69
7.89k
  if (!pbi) return NULL;
70
71
7.89k
  memset(pbi, 0, sizeof(VP8D_COMP));
72
73
7.89k
  if (setjmp(pbi->common.error.jmp)) {
74
0
    pbi->common.error.setjmp = 0;
75
0
    remove_decompressor(pbi);
76
0
    return 0;
77
0
  }
78
79
7.89k
  pbi->common.error.setjmp = 1;
80
81
7.89k
  vp8_create_common(&pbi->common);
82
83
7.89k
  pbi->common.current_video_frame = 0;
84
7.89k
  pbi->ready_for_new_data = 1;
85
86
  /* vp8cx_init_de_quantizer() is first called here. Add check in
87
   * frame_init_dequantizer() to avoid
88
   *  unnecessary calling of vp8cx_init_de_quantizer() for every frame.
89
   */
90
7.89k
  vp8cx_init_de_quantizer(pbi);
91
92
7.89k
  vp8_loop_filter_init(&pbi->common);
93
94
7.89k
  pbi->common.error.setjmp = 0;
95
96
#if CONFIG_ERROR_CONCEALMENT
97
  pbi->ec_enabled = oxcf->error_concealment;
98
  pbi->overlaps = NULL;
99
#else
100
7.89k
  (void)oxcf;
101
7.89k
  pbi->ec_enabled = 0;
102
7.89k
#endif
103
  /* Error concealment is activated after a key frame has been
104
   * decoded without errors when error concealment is enabled.
105
   */
106
7.89k
  pbi->ec_active = 0;
107
108
7.89k
  pbi->decoded_key_frame = 0;
109
110
  /* Independent partitions is activated when a frame updates the
111
   * token probability table to have equal probabilities over the
112
   * PREV_COEF context.
113
   */
114
7.89k
  pbi->independent_partitions = 0;
115
116
7.89k
  vp8_setup_block_dptrs(&pbi->mb);
117
118
7.89k
  once(initialize_dec);
119
120
7.89k
  return pbi;
121
7.89k
}
122
123
vpx_codec_err_t vp8dx_get_reference(VP8D_COMP *pbi,
124
                                    enum vpx_ref_frame_type ref_frame_flag,
125
0
                                    YV12_BUFFER_CONFIG *sd) {
126
0
  VP8_COMMON *cm = &pbi->common;
127
0
  int ref_fb_idx;
128
129
0
  if (ref_frame_flag == VP8_LAST_FRAME) {
130
0
    ref_fb_idx = cm->lst_fb_idx;
131
0
  } else if (ref_frame_flag == VP8_GOLD_FRAME) {
132
0
    ref_fb_idx = cm->gld_fb_idx;
133
0
  } else if (ref_frame_flag == VP8_ALTR_FRAME) {
134
0
    ref_fb_idx = cm->alt_fb_idx;
135
0
  } else {
136
0
    vpx_internal_error(&pbi->common.error, VPX_CODEC_ERROR,
137
0
                       "Invalid reference frame");
138
0
    return pbi->common.error.error_code;
139
0
  }
140
141
0
  if (cm->yv12_fb[ref_fb_idx].y_height != sd->y_height ||
142
0
      cm->yv12_fb[ref_fb_idx].y_width != sd->y_width ||
143
0
      cm->yv12_fb[ref_fb_idx].uv_height != sd->uv_height ||
144
0
      cm->yv12_fb[ref_fb_idx].uv_width != sd->uv_width) {
145
0
    vpx_internal_error(&pbi->common.error, VPX_CODEC_ERROR,
146
0
                       "Incorrect buffer dimensions");
147
0
  } else
148
0
    vp8_yv12_copy_frame(&cm->yv12_fb[ref_fb_idx], sd);
149
150
0
  return pbi->common.error.error_code;
151
0
}
152
153
vpx_codec_err_t vp8dx_set_reference(VP8D_COMP *pbi,
154
                                    enum vpx_ref_frame_type ref_frame_flag,
155
0
                                    YV12_BUFFER_CONFIG *sd) {
156
0
  VP8_COMMON *cm = &pbi->common;
157
0
  int *ref_fb_ptr = NULL;
158
0
  int free_fb;
159
160
0
  if (ref_frame_flag == VP8_LAST_FRAME) {
161
0
    ref_fb_ptr = &cm->lst_fb_idx;
162
0
  } else if (ref_frame_flag == VP8_GOLD_FRAME) {
163
0
    ref_fb_ptr = &cm->gld_fb_idx;
164
0
  } else if (ref_frame_flag == VP8_ALTR_FRAME) {
165
0
    ref_fb_ptr = &cm->alt_fb_idx;
166
0
  } else {
167
0
    vpx_internal_error(&pbi->common.error, VPX_CODEC_ERROR,
168
0
                       "Invalid reference frame");
169
0
    return pbi->common.error.error_code;
170
0
  }
171
172
0
  if (cm->yv12_fb[*ref_fb_ptr].y_height != sd->y_height ||
173
0
      cm->yv12_fb[*ref_fb_ptr].y_width != sd->y_width ||
174
0
      cm->yv12_fb[*ref_fb_ptr].uv_height != sd->uv_height ||
175
0
      cm->yv12_fb[*ref_fb_ptr].uv_width != sd->uv_width) {
176
0
    vpx_internal_error(&pbi->common.error, VPX_CODEC_ERROR,
177
0
                       "Incorrect buffer dimensions");
178
0
  } else {
179
    /* Find an empty frame buffer. */
180
0
    free_fb = get_free_fb(cm);
181
    /* Decrease fb_idx_ref_cnt since it will be increased again in
182
     * ref_cnt_fb() below. */
183
0
    cm->fb_idx_ref_cnt[free_fb]--;
184
185
    /* Manage the reference counters and copy image. */
186
0
    ref_cnt_fb(cm->fb_idx_ref_cnt, ref_fb_ptr, free_fb);
187
0
    vp8_yv12_copy_frame(sd, &cm->yv12_fb[*ref_fb_ptr]);
188
0
  }
189
190
0
  return pbi->common.error.error_code;
191
0
}
192
193
85.2k
static int get_free_fb(VP8_COMMON *cm) {
194
85.2k
  int i;
195
161k
  for (i = 0; i < NUM_YV12_BUFFERS; ++i) {
196
161k
    if (cm->fb_idx_ref_cnt[i] == 0) break;
197
161k
  }
198
199
85.2k
  assert(i < NUM_YV12_BUFFERS);
200
85.2k
  cm->fb_idx_ref_cnt[i] = 1;
201
85.2k
  return i;
202
85.2k
}
203
204
125k
static void ref_cnt_fb(int *buf, int *idx, int new_idx) {
205
125k
  if (buf[*idx] > 0) buf[*idx]--;
206
207
125k
  *idx = new_idx;
208
209
125k
  buf[new_idx]++;
210
125k
}
211
212
/* If any buffer copy / swapping is signalled it should be done here. */
213
61.6k
static int swap_frame_buffers(VP8_COMMON *cm) {
214
61.6k
  int err = 0;
215
216
  /* The alternate reference frame or golden frame can be updated
217
   *  using the new, last, or golden/alt ref frame.  If it
218
   *  is updated using the newly decoded frame it is a refresh.
219
   *  An update using the last or golden/alt ref frame is a copy.
220
   */
221
61.6k
  if (cm->copy_buffer_to_arf) {
222
21.5k
    int new_fb = 0;
223
224
21.5k
    if (cm->copy_buffer_to_arf == 1) {
225
3.65k
      new_fb = cm->lst_fb_idx;
226
17.8k
    } else if (cm->copy_buffer_to_arf == 2) {
227
9.10k
      new_fb = cm->gld_fb_idx;
228
9.10k
    } else {
229
8.76k
      err = -1;
230
8.76k
    }
231
232
21.5k
    ref_cnt_fb(cm->fb_idx_ref_cnt, &cm->alt_fb_idx, new_fb);
233
21.5k
  }
234
235
61.6k
  if (cm->copy_buffer_to_gf) {
236
19.3k
    int new_fb = 0;
237
238
19.3k
    if (cm->copy_buffer_to_gf == 1) {
239
3.83k
      new_fb = cm->lst_fb_idx;
240
15.4k
    } else if (cm->copy_buffer_to_gf == 2) {
241
3.78k
      new_fb = cm->alt_fb_idx;
242
11.6k
    } else {
243
11.6k
      err = -1;
244
11.6k
    }
245
246
19.3k
    ref_cnt_fb(cm->fb_idx_ref_cnt, &cm->gld_fb_idx, new_fb);
247
19.3k
  }
248
249
61.6k
  if (cm->refresh_golden_frame) {
250
22.0k
    ref_cnt_fb(cm->fb_idx_ref_cnt, &cm->gld_fb_idx, cm->new_fb_idx);
251
22.0k
  }
252
253
61.6k
  if (cm->refresh_alt_ref_frame) {
254
20.4k
    ref_cnt_fb(cm->fb_idx_ref_cnt, &cm->alt_fb_idx, cm->new_fb_idx);
255
20.4k
  }
256
257
61.6k
  if (cm->refresh_last_frame) {
258
42.1k
    ref_cnt_fb(cm->fb_idx_ref_cnt, &cm->lst_fb_idx, cm->new_fb_idx);
259
260
42.1k
    cm->frame_to_show = &cm->yv12_fb[cm->lst_fb_idx];
261
42.1k
  } else {
262
19.4k
    cm->frame_to_show = &cm->yv12_fb[cm->new_fb_idx];
263
19.4k
  }
264
265
61.6k
  cm->fb_idx_ref_cnt[cm->new_fb_idx]--;
266
267
61.6k
  return err;
268
61.6k
}
269
270
85.2k
static int check_fragments_for_errors(VP8D_COMP *pbi) {
271
85.2k
  if (!pbi->ec_active && pbi->fragments.count <= 1 &&
272
85.2k
      pbi->fragments.sizes[0] == 0) {
273
0
    VP8_COMMON *cm = &pbi->common;
274
275
    /* If error concealment is disabled we won't signal missing frames
276
     * to the decoder.
277
     */
278
0
    if (cm->fb_idx_ref_cnt[cm->lst_fb_idx] > 1) {
279
      /* The last reference shares buffer with another reference
280
       * buffer. Move it to its own buffer before setting it as
281
       * corrupt, otherwise we will make multiple buffers corrupt.
282
       */
283
0
      const int prev_idx = cm->lst_fb_idx;
284
0
      cm->fb_idx_ref_cnt[prev_idx]--;
285
0
      cm->lst_fb_idx = get_free_fb(cm);
286
0
      vp8_yv12_copy_frame(&cm->yv12_fb[prev_idx], &cm->yv12_fb[cm->lst_fb_idx]);
287
0
    }
288
    /* This is used to signal that we are missing frames.
289
     * We do not know if the missing frame(s) was supposed to update
290
     * any of the reference buffers, but we act conservative and
291
     * mark only the last buffer as corrupted.
292
     */
293
0
    cm->yv12_fb[cm->lst_fb_idx].corrupted = 1;
294
295
    /* Signal that we have no frame to show. */
296
0
    cm->show_frame = 0;
297
298
    /* Nothing more to do. */
299
0
    return 0;
300
0
  }
301
302
85.2k
  return 1;
303
85.2k
}
304
305
85.2k
int vp8dx_receive_compressed_data(VP8D_COMP *pbi) {
306
85.2k
  VP8_COMMON *cm = &pbi->common;
307
85.2k
  int retcode = -1;
308
309
85.2k
  pbi->common.error.error_code = VPX_CODEC_OK;
310
311
85.2k
  retcode = check_fragments_for_errors(pbi);
312
85.2k
  if (retcode <= 0) return retcode;
313
314
85.2k
  cm->new_fb_idx = get_free_fb(cm);
315
316
  /* setup reference frames for vp8_decode_frame */
317
85.2k
  pbi->dec_fb_ref[INTRA_FRAME] = &cm->yv12_fb[cm->new_fb_idx];
318
85.2k
  pbi->dec_fb_ref[LAST_FRAME] = &cm->yv12_fb[cm->lst_fb_idx];
319
85.2k
  pbi->dec_fb_ref[GOLDEN_FRAME] = &cm->yv12_fb[cm->gld_fb_idx];
320
85.2k
  pbi->dec_fb_ref[ALTREF_FRAME] = &cm->yv12_fb[cm->alt_fb_idx];
321
322
85.2k
  retcode = vp8_decode_frame(pbi);
323
324
85.2k
  if (retcode < 0) {
325
460
    if (cm->fb_idx_ref_cnt[cm->new_fb_idx] > 0) {
326
460
      cm->fb_idx_ref_cnt[cm->new_fb_idx]--;
327
460
    }
328
329
460
    pbi->common.error.error_code = VPX_CODEC_ERROR;
330
    // Propagate the error info.
331
460
    if (pbi->mb.error_info.error_code != 0) {
332
213
      pbi->common.error.error_code = pbi->mb.error_info.error_code;
333
213
      memcpy(pbi->common.error.detail, pbi->mb.error_info.detail,
334
213
             sizeof(pbi->mb.error_info.detail));
335
213
    }
336
460
    goto decode_exit;
337
460
  }
338
339
84.7k
  if (swap_frame_buffers(cm)) {
340
15.3k
    pbi->common.error.error_code = VPX_CODEC_ERROR;
341
15.3k
    goto decode_exit;
342
15.3k
  }
343
344
69.4k
  vpx_clear_system_state();
345
346
69.4k
  if (cm->show_frame) {
347
29.0k
    cm->current_video_frame++;
348
29.0k
    cm->show_frame_mi = cm->mi;
349
29.0k
  }
350
351
#if CONFIG_ERROR_CONCEALMENT
352
  /* swap the mode infos to storage for future error concealment */
353
  if (pbi->ec_enabled && pbi->common.prev_mi) {
354
    MODE_INFO *tmp = pbi->common.prev_mi;
355
    int row, col;
356
    pbi->common.prev_mi = pbi->common.mi;
357
    pbi->common.mi = tmp;
358
359
    /* Propagate the segment_ids to the next frame */
360
    for (row = 0; row < pbi->common.mb_rows; ++row) {
361
      for (col = 0; col < pbi->common.mb_cols; ++col) {
362
        const int i = row * pbi->common.mode_info_stride + col;
363
        pbi->common.mi[i].mbmi.segment_id =
364
            pbi->common.prev_mi[i].mbmi.segment_id;
365
      }
366
    }
367
  }
368
#endif
369
370
69.4k
  pbi->ready_for_new_data = 0;
371
372
69.4k
decode_exit:
373
62.0k
  vpx_clear_system_state();
374
62.0k
  return retcode;
375
69.4k
}
376
int vp8dx_get_raw_frame(VP8D_COMP *pbi, YV12_BUFFER_CONFIG *sd,
377
93.8k
                        vp8_ppflags_t *flags) {
378
93.8k
  int ret = -1;
379
380
93.8k
  if (pbi->ready_for_new_data == 1) return ret;
381
382
  /* ie no raw frame to show!!! */
383
69.7k
  if (pbi->common.show_frame == 0) return ret;
384
385
30.3k
  pbi->ready_for_new_data = 1;
386
387
30.3k
#if CONFIG_POSTPROC
388
30.3k
  ret = vp8_post_proc_frame(&pbi->common, sd, flags);
389
#else
390
  (void)flags;
391
392
  if (pbi->common.frame_to_show) {
393
    *sd = *pbi->common.frame_to_show;
394
    sd->y_width = pbi->common.Width;
395
    sd->y_height = pbi->common.Height;
396
    sd->uv_height = pbi->common.Height / 2;
397
    ret = 0;
398
  } else {
399
    ret = -1;
400
  }
401
402
#endif /*!CONFIG_POSTPROC*/
403
30.3k
  vpx_clear_system_state();
404
30.3k
  return ret;
405
69.7k
}
406
407
/* This function as written isn't decoder specific, but the encoder has
408
 * much faster ways of computing this, so it's ok for it to live in a
409
 * decode specific file.
410
 */
411
0
int vp8dx_references_buffer(VP8_COMMON *oci, int ref_frame) {
412
0
  const MODE_INFO *mi = oci->mi;
413
0
  int mb_row, mb_col;
414
415
0
  for (mb_row = 0; mb_row < oci->mb_rows; ++mb_row) {
416
0
    for (mb_col = 0; mb_col < oci->mb_cols; mb_col++, mi++) {
417
0
      if (mi->mbmi.ref_frame == ref_frame) return 1;
418
0
    }
419
0
    mi++;
420
0
  }
421
0
  return 0;
422
0
}
423
424
7.89k
int vp8_create_decoder_instances(struct frame_buffers *fb, VP8D_CONFIG *oxcf) {
425
  /* decoder instance for single thread mode */
426
7.89k
  fb->pbi[0] = create_decompressor(oxcf);
427
7.89k
  if (!fb->pbi[0]) return VPX_CODEC_ERROR;
428
429
7.89k
#if CONFIG_MULTITHREAD
430
7.89k
  if (setjmp(fb->pbi[0]->common.error.jmp)) {
431
0
    fb->pbi[0]->common.error.setjmp = 0;
432
0
    vp8_remove_decoder_instances(fb);
433
0
    vp8_zero(fb->pbi);
434
0
    vpx_clear_system_state();
435
0
    return VPX_CODEC_ERROR;
436
0
  }
437
438
7.89k
  fb->pbi[0]->common.error.setjmp = 1;
439
7.89k
  fb->pbi[0]->max_threads = oxcf->max_threads;
440
7.89k
  vp8_decoder_create_threads(fb->pbi[0]);
441
7.89k
  fb->pbi[0]->common.error.setjmp = 0;
442
7.89k
#endif
443
7.89k
  return VPX_CODEC_OK;
444
7.89k
}
445
446
8.02k
int vp8_remove_decoder_instances(struct frame_buffers *fb) {
447
8.02k
  VP8D_COMP *pbi = fb->pbi[0];
448
449
8.02k
  if (!pbi) return VPX_CODEC_ERROR;
450
7.89k
#if CONFIG_MULTITHREAD
451
7.89k
  vp8_decoder_remove_threads(pbi);
452
7.89k
#endif
453
454
  /* decoder instance for single thread mode */
455
7.89k
  remove_decompressor(pbi);
456
7.89k
  fb->pbi[0] = NULL;
457
7.89k
  return VPX_CODEC_OK;
458
8.02k
}
459
460
0
int vp8dx_get_quantizer(const VP8D_COMP *pbi) {
461
0
  return pbi->common.base_qindex;
462
0
}