vp9_decoder.c 12.3 KB
Newer Older
John Koleszar's avatar
John Koleszar committed
1
/*
2
 *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
John Koleszar's avatar
John Koleszar committed
3
 *
4
 *  Use of this source code is governed by a BSD-style license
5
6
 *  that can be found in the LICENSE file in the root of the source
 *  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.
John Koleszar's avatar
John Koleszar committed
9
10
 */

Dmitry Kovalev's avatar
Dmitry Kovalev committed
11
#include <assert.h>
Dmitry Kovalev's avatar
Dmitry Kovalev committed
12
13
#include <limits.h>
#include <stdio.h>
Dmitry Kovalev's avatar
Dmitry Kovalev committed
14

15
16
17
#include "./vpx_scale_rtcd.h"

#include "vpx_mem/vpx_mem.h"
18
#include "vpx_ports/vpx_once.h"
19
20
21
22
23
#include "vpx_ports/vpx_timer.h"
#include "vpx_scale/vpx_scale.h"

#include "vp9/common/vp9_alloccommon.h"
#include "vp9/common/vp9_loopfilter.h"
24
#include "vp9/common/vp9_onyxc_int.h"
25
#if CONFIG_VP9_POSTPROC
26
#include "vp9/common/vp9_postproc.h"
John Koleszar's avatar
John Koleszar committed
27
#endif
28
#include "vp9/common/vp9_quant_common.h"
29
#include "vp9/common/vp9_reconintra.h"
30
#include "vp9/common/vp9_systemdependent.h"
31

Yaowu Xu's avatar
Yaowu Xu committed
32
#include "vp9/decoder/vp9_decodeframe.h"
33
#include "vp9/decoder/vp9_decoder.h"
34
#include "vp9/decoder/vp9_detokenize.h"
35
#include "vp9/decoder/vp9_dthread.h"
John Koleszar's avatar
John Koleszar committed
36

37
static void initialize_dec(void) {
38
  static volatile int init_done = 0;
John Koleszar's avatar
John Koleszar committed
39

John Koleszar's avatar
John Koleszar committed
40
  if (!init_done) {
41
42
    vp9_rtcd();
    vp9_init_intra_predictors();
John Koleszar's avatar
John Koleszar committed
43
44
    init_done = 1;
  }
John Koleszar's avatar
John Koleszar committed
45
46
}

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
static void vp9_dec_setup_mi(VP9_COMMON *cm) {
  cm->mi = cm->mip + cm->mi_stride + 1;
  vpx_memset(cm->mip, 0, cm->mi_stride * (cm->mi_rows + 1) * sizeof(*cm->mip));
}

static int vp9_dec_alloc_mi(VP9_COMMON *cm, int mi_size) {
  cm->mip = vpx_calloc(mi_size, sizeof(*cm->mip));
  if (!cm->mip)
    return 1;
  cm->mi_alloc_size = mi_size;
  return 0;
}

static void vp9_dec_free_mi(VP9_COMMON *cm) {
  vpx_free(cm->mip);
  cm->mip = NULL;
}

Dmitry Kovalev's avatar
Dmitry Kovalev committed
65
VP9Decoder *vp9_decoder_create() {
66
  VP9Decoder *const pbi = vpx_memalign(32, sizeof(*pbi));
67
  VP9_COMMON *const cm = pbi ? &pbi->common : NULL;
John Koleszar's avatar
John Koleszar committed
68

69
  if (!cm)
John Koleszar's avatar
John Koleszar committed
70
    return NULL;
John Koleszar's avatar
John Koleszar committed
71

Dmitry Kovalev's avatar
Dmitry Kovalev committed
72
  vp9_zero(*pbi);
John Koleszar's avatar
John Koleszar committed
73

74
75
  if (setjmp(cm->error.jmp)) {
    cm->error.setjmp = 0;
76
    vp9_decoder_remove(pbi);
77
    return NULL;
John Koleszar's avatar
John Koleszar committed
78
  }
John Koleszar's avatar
John Koleszar committed
79

80
  cm->error.setjmp = 1;
81
82
83
84
85
86
87

  CHECK_MEM_ERROR(cm, cm->fc,
                  (FRAME_CONTEXT *)vpx_calloc(1, sizeof(*cm->fc)));
  CHECK_MEM_ERROR(cm, cm->frame_contexts,
                  (FRAME_CONTEXT *)vpx_calloc(FRAME_CONTEXTS,
                  sizeof(*cm->frame_contexts)));

88
  pbi->need_resync = 1;
89
  once(initialize_dec);
John Koleszar's avatar
John Koleszar committed
90

91
92
93
94
  // Initialize the references to not point to any frame buffers.
  vpx_memset(&cm->ref_frame_map, -1, sizeof(cm->ref_frame_map));

  cm->current_video_frame = 0;
John Koleszar's avatar
John Koleszar committed
95
  pbi->ready_for_new_data = 1;
96
  cm->bit_depth = VPX_BITS_8;
97
  cm->dequant_bit_depth = VPX_BITS_8;
John Koleszar's avatar
John Koleszar committed
98

99
100
101
102
  cm->alloc_mi = vp9_dec_alloc_mi;
  cm->free_mi = vp9_dec_free_mi;
  cm->setup_mi = vp9_dec_setup_mi;

103
  // vp9_init_dequantizer() is first called here. Add check in
104
  // frame_init_dequantizer() to avoid unnecessary calling of
105
  // vp9_init_dequantizer() for every frame.
106
  vp9_init_dequantizer(cm);
John Koleszar's avatar
John Koleszar committed
107

108
  vp9_loop_filter_init(cm);
John Koleszar's avatar
John Koleszar committed
109

110
  cm->error.setjmp = 0;
111

James Zern's avatar
James Zern committed
112
  vp9_get_worker_interface()->init(&pbi->lf_worker);
113

114
  return pbi;
John Koleszar's avatar
John Koleszar committed
115
116
}

117
void vp9_decoder_remove(VP9Decoder *pbi) {
118
  VP9_COMMON *const cm = &pbi->common;
119
  int i;
John Koleszar's avatar
John Koleszar committed
120

James Zern's avatar
James Zern committed
121
  vp9_get_worker_interface()->end(&pbi->lf_worker);
122
  vpx_free(pbi->lf_worker.data1);
123
  vpx_free(pbi->tile_data);
124
125
  for (i = 0; i < pbi->num_tile_workers; ++i) {
    VP9Worker *const worker = &pbi->tile_workers[i];
James Zern's avatar
James Zern committed
126
    vp9_get_worker_interface()->end(worker);
127
  }
128
129
  vpx_free(pbi->tile_worker_data);
  vpx_free(pbi->tile_worker_info);
130
  vpx_free(pbi->tile_workers);
131

132
133
  if (pbi->num_tile_workers > 0) {
    vp9_loop_filter_dealloc(&pbi->lf_row_sync);
134
135
  }

136
  vp9_remove_common(cm);
John Koleszar's avatar
John Koleszar committed
137
  vpx_free(pbi);
John Koleszar's avatar
John Koleszar committed
138
139
}

140
141
static int equal_dimensions(const YV12_BUFFER_CONFIG *a,
                            const YV12_BUFFER_CONFIG *b) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
142
143
144
    return a->y_height == b->y_height && a->y_width == b->y_width &&
           a->uv_height == b->uv_height && a->uv_width == b->uv_width;
}
John Koleszar's avatar
John Koleszar committed
145

146
vpx_codec_err_t vp9_copy_reference_dec(VP9Decoder *pbi,
John Koleszar's avatar
John Koleszar committed
147
148
                                       VP9_REFFRAME ref_frame_flag,
                                       YV12_BUFFER_CONFIG *sd) {
149
  VP9_COMMON *cm = &pbi->common;
John Koleszar's avatar
John Koleszar committed
150

151
152
153
154
155
  /* TODO(jkoleszar): The decoder doesn't have any real knowledge of what the
   * encoder is using the frame buffers for. This is just a stub to keep the
   * vpxenc --test-decode functionality working, and will be replaced in a
   * later commit that adds VP9-specific controls for this functionality.
   */
Dmitry Kovalev's avatar
Dmitry Kovalev committed
156
  if (ref_frame_flag == VP9_LAST_FLAG) {
157
158
159
160
161
162
    const YV12_BUFFER_CONFIG *const cfg = get_ref_frame(cm, 0);
    if (cfg == NULL) {
      vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
                         "No 'last' reference frame");
      return VPX_CODEC_ERROR;
    }
163
164
165
166
167
    if (!equal_dimensions(cfg, sd))
      vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
                         "Incorrect buffer dimensions");
    else
      vp8_yv12_copy_frame(cfg, sd);
Dmitry Kovalev's avatar
Dmitry Kovalev committed
168
  } else {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
169
    vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
John Koleszar's avatar
John Koleszar committed
170
                       "Invalid reference frame");
Dmitry Kovalev's avatar
Dmitry Kovalev committed
171
  }
172

Dmitry Kovalev's avatar
Dmitry Kovalev committed
173
  return cm->error.error_code;
John Koleszar's avatar
John Koleszar committed
174
}
175
176


177
vpx_codec_err_t vp9_set_reference_dec(VP9_COMMON *cm,
Dmitry Kovalev's avatar
Dmitry Kovalev committed
178
                                      VP9_REFFRAME ref_frame_flag,
179
                                      YV12_BUFFER_CONFIG *sd) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
180
  RefBuffer *ref_buf = NULL;
John Koleszar's avatar
John Koleszar committed
181

182
183
184
185
  // TODO(jkoleszar): The decoder doesn't have any real knowledge of what the
  // encoder is using the frame buffers for. This is just a stub to keep the
  // vpxenc --test-decode functionality working, and will be replaced in a
  // later commit that adds VP9-specific controls for this functionality.
186
  if (ref_frame_flag == VP9_LAST_FLAG) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
187
    ref_buf = &cm->frame_refs[0];
188
  } else if (ref_frame_flag == VP9_GOLD_FLAG) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
189
    ref_buf = &cm->frame_refs[1];
190
  } else if (ref_frame_flag == VP9_ALT_FLAG) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
191
    ref_buf = &cm->frame_refs[2];
192
  } else {
193
    vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
John Koleszar's avatar
John Koleszar committed
194
                       "Invalid reference frame");
195
    return cm->error.error_code;
John Koleszar's avatar
John Koleszar committed
196
  }
197

Dmitry Kovalev's avatar
Dmitry Kovalev committed
198
  if (!equal_dimensions(ref_buf->buf, sd)) {
199
    vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
John Koleszar's avatar
John Koleszar committed
200
201
                       "Incorrect buffer dimensions");
  } else {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
202
203
    int *ref_fb_ptr = &ref_buf->idx;

Dmitry Kovalev's avatar
Dmitry Kovalev committed
204
205
    // Find an empty frame buffer.
    const int free_fb = get_free_fb(cm);
206
    // Decrease ref_count since it will be increased again in
Dmitry Kovalev's avatar
Dmitry Kovalev committed
207
    // ref_cnt_fb() below.
208
    cm->frame_bufs[free_fb].ref_count--;
John Koleszar's avatar
John Koleszar committed
209

Dmitry Kovalev's avatar
Dmitry Kovalev committed
210
    // Manage the reference counters and copy image.
211
212
    ref_cnt_fb(cm->frame_bufs, ref_fb_ptr, free_fb);
    ref_buf->buf = &cm->frame_bufs[*ref_fb_ptr].buf;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
213
    vp8_yv12_copy_frame(sd, ref_buf->buf);
John Koleszar's avatar
John Koleszar committed
214
  }
215

216
  return cm->error.error_code;
John Koleszar's avatar
John Koleszar committed
217
218
}

219
/* If any buffer updating is signaled it should be done here. */
220
static void swap_frame_buffers(VP9Decoder *pbi) {
221
  int ref_index = 0, mask;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
222
  VP9_COMMON *const cm = &pbi->common;
223

224
  for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) {
225
226
    if (mask & 1) {
      const int old_idx = cm->ref_frame_map[ref_index];
227
      ref_cnt_fb(cm->frame_bufs, &cm->ref_frame_map[ref_index],
Dmitry Kovalev's avatar
Dmitry Kovalev committed
228
                 cm->new_fb_idx);
229
230
231
232
      if (old_idx >= 0 && cm->frame_bufs[old_idx].ref_count == 0)
        cm->release_fb_cb(cm->cb_priv,
                          &cm->frame_bufs[old_idx].raw_frame_buffer);
    }
233
234
    ++ref_index;
  }
235

236
  cm->frame_to_show = get_frame_new_buffer(cm);
237
  cm->frame_bufs[cm->new_fb_idx].ref_count--;
238

Dmitry Kovalev's avatar
Dmitry Kovalev committed
239
  // Invalidate these references until the next frame starts.
240
  for (ref_index = 0; ref_index < 3; ref_index++)
241
    cm->frame_refs[ref_index].idx = -1;
242
243
}

244
int vp9_receive_compressed_data(VP9Decoder *pbi,
245
                                size_t size, const uint8_t **psource) {
246
  VP9_COMMON *const cm = &pbi->common;
247
  const uint8_t *source = *psource;
John Koleszar's avatar
John Koleszar committed
248
  int retcode = 0;
John Koleszar's avatar
John Koleszar committed
249

Dmitry Kovalev's avatar
Dmitry Kovalev committed
250
  cm->error.error_code = VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
251

252
  if (size == 0) {
253
254
255
256
257
258
259
260
    // This is used to signal that we are missing frames.
    // We do not know if the missing frame(s) was supposed to update
    // any of the reference buffers, but we act conservative and
    // mark only the last buffer as corrupted.
    //
    // TODO(jkoleszar): Error concealment is undefined and non-normative
    // at this point, but if it becomes so, [0] may not always be the correct
    // thing to do here.
261
    if (cm->frame_refs[0].idx > 0)
Dmitry Kovalev's avatar
Dmitry Kovalev committed
262
      cm->frame_refs[0].buf->corrupted = 1;
John Koleszar's avatar
John Koleszar committed
263
  }
264

265
266
  pbi->ready_for_new_data = 0;

267
  // Check if the previous frame was a frame without any references to it.
268
  if (cm->new_fb_idx >= 0 && cm->frame_bufs[cm->new_fb_idx].ref_count == 0)
269
270
    cm->release_fb_cb(cm->cb_priv,
                      &cm->frame_bufs[cm->new_fb_idx].raw_frame_buffer);
John Koleszar's avatar
John Koleszar committed
271
  cm->new_fb_idx = get_free_fb(cm);
272

273
274
275
  // Assign a MV array to the frame buffer.
  cm->cur_frame = &cm->frame_bufs[cm->new_fb_idx];

Dmitry Kovalev's avatar
Dmitry Kovalev committed
276
  if (setjmp(cm->error.jmp)) {
James Zern's avatar
James Zern committed
277
278
279
    const VP9WorkerInterface *const winterface = vp9_get_worker_interface();
    int i;

280
    pbi->need_resync = 1;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
281
    cm->error.setjmp = 0;
James Zern's avatar
James Zern committed
282
283
284
285
286
287
288
289

    // Synchronize all threads immediately as a subsequent decode call may
    // cause a resize invalidating some allocations.
    winterface->sync(&pbi->lf_worker);
    for (i = 0; i < pbi->num_tile_workers; ++i) {
      winterface->sync(&pbi->tile_workers[i]);
    }

290
    vp9_clear_system_state();
John Koleszar's avatar
John Koleszar committed
291

292
    if (cm->new_fb_idx > 0 && cm->frame_bufs[cm->new_fb_idx].ref_count > 0)
293
      cm->frame_bufs[cm->new_fb_idx].ref_count--;
294

John Koleszar's avatar
John Koleszar committed
295
296
    return -1;
  }
John Koleszar's avatar
John Koleszar committed
297

Dmitry Kovalev's avatar
Dmitry Kovalev committed
298
  cm->error.setjmp = 1;
Paul Wilkins's avatar
Paul Wilkins committed
299

300
  vp9_decode_frame(pbi, source, source + size, psource);
John Koleszar's avatar
John Koleszar committed
301

302
  swap_frame_buffers(pbi);
John Koleszar's avatar
John Koleszar committed
303

304
  vp9_clear_system_state();
John Koleszar's avatar
John Koleszar committed
305

306
307
308
  cm->last_width = cm->width;
  cm->last_height = cm->height;

309
  if (!cm->show_existing_frame) {
310
    cm->last_show_frame = cm->show_frame;
311
312
    cm->prev_frame = cm->cur_frame;
  }
313

314
  if (cm->show_frame)
315
    cm->current_video_frame++;
316

Dmitry Kovalev's avatar
Dmitry Kovalev committed
317
  cm->error.setjmp = 0;
John Koleszar's avatar
John Koleszar committed
318
  return retcode;
John Koleszar's avatar
John Koleszar committed
319
}
320

321
int vp9_get_raw_frame(VP9Decoder *pbi, YV12_BUFFER_CONFIG *sd,
322
                      vp9_ppflags_t *flags) {
323
  VP9_COMMON *const cm = &pbi->common;
John Koleszar's avatar
John Koleszar committed
324
  int ret = -1;
Yaowu Xu's avatar
Yaowu Xu committed
325
326
327
#if !CONFIG_VP9_POSTPROC
  (void)*flags;
#endif
John Koleszar's avatar
John Koleszar committed
328

John Koleszar's avatar
John Koleszar committed
329
330
  if (pbi->ready_for_new_data == 1)
    return ret;
John Koleszar's avatar
John Koleszar committed
331

332
333
  pbi->ready_for_new_data = 1;

Yaowu Xu's avatar
Yaowu Xu committed
334
  /* no raw frame to show!!! */
335
  if (!cm->show_frame)
John Koleszar's avatar
John Koleszar committed
336
    return ret;
John Koleszar's avatar
John Koleszar committed
337

338
#if CONFIG_VP9_POSTPROC
339
340
341
342
343
344
  if (!cm->show_existing_frame) {
    ret = vp9_post_proc_frame(cm, sd, flags);
  } else {
    *sd = *cm->frame_to_show;
    ret = 0;
  }
John Koleszar's avatar
John Koleszar committed
345
#else
346
  *sd = *cm->frame_to_show;
Yaowu Xu's avatar
Yaowu Xu committed
347
  ret = 0;
348
#endif /*!CONFIG_POSTPROC*/
349
  vp9_clear_system_state();
John Koleszar's avatar
John Koleszar committed
350
  return ret;
John Koleszar's avatar
John Koleszar committed
351
}
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415

vpx_codec_err_t vp9_parse_superframe_index(const uint8_t *data,
                                           size_t data_sz,
                                           uint32_t sizes[8], int *count,
                                           vpx_decrypt_cb decrypt_cb,
                                           void *decrypt_state) {
  // A chunk ending with a byte matching 0xc0 is an invalid chunk unless
  // it is a super frame index. If the last byte of real video compression
  // data is 0xc0 the encoder must add a 0 byte. If we have the marker but
  // not the associated matching marker byte at the front of the index we have
  // an invalid bitstream and need to return an error.

  uint8_t marker;

  assert(data_sz);
  marker = read_marker(decrypt_cb, decrypt_state, data + data_sz - 1);
  *count = 0;

  if ((marker & 0xe0) == 0xc0) {
    const uint32_t frames = (marker & 0x7) + 1;
    const uint32_t mag = ((marker >> 3) & 0x3) + 1;
    const size_t index_sz = 2 + mag * frames;

    // This chunk is marked as having a superframe index but doesn't have
    // enough data for it, thus it's an invalid superframe index.
    if (data_sz < index_sz)
      return VPX_CODEC_CORRUPT_FRAME;

    {
      const uint8_t marker2 = read_marker(decrypt_cb, decrypt_state,
                                          data + data_sz - index_sz);

      // This chunk is marked as having a superframe index but doesn't have
      // the matching marker byte at the front of the index therefore it's an
      // invalid chunk.
      if (marker != marker2)
        return VPX_CODEC_CORRUPT_FRAME;
    }

    {
      // Found a valid superframe index.
      uint32_t i, j;
      const uint8_t *x = &data[data_sz - index_sz + 1];

      // Frames has a maximum of 8 and mag has a maximum of 4.
      uint8_t clear_buffer[32];
      assert(sizeof(clear_buffer) >= frames * mag);
      if (decrypt_cb) {
        decrypt_cb(decrypt_state, x, clear_buffer, frames * mag);
        x = clear_buffer;
      }

      for (i = 0; i < frames; ++i) {
        uint32_t this_sz = 0;

        for (j = 0; j < mag; ++j)
          this_sz |= (*x++) << (j * 8);
        sizes[i] = this_sz;
      }
      *count = frames;
    }
  }
  return VPX_CODEC_OK;
}