vp9_decoder.c 11.5 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
18
19
20
21
22
#include "./vpx_scale_rtcd.h"

#include "vpx_mem/vpx_mem.h"
#include "vpx_ports/vpx_timer.h"
#include "vpx_scale/vpx_scale.h"

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

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

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

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

Dmitry Kovalev's avatar
Dmitry Kovalev committed
46
VP9Decoder *vp9_decoder_create() {
47
  VP9Decoder *const pbi = vpx_memalign(32, sizeof(*pbi));
48
  VP9_COMMON *const cm = pbi ? &pbi->common : NULL;
John Koleszar's avatar
John Koleszar committed
49

50
  if (!cm)
John Koleszar's avatar
John Koleszar committed
51
    return NULL;
John Koleszar's avatar
John Koleszar committed
52

Dmitry Kovalev's avatar
Dmitry Kovalev committed
53
  vp9_zero(*pbi);
John Koleszar's avatar
John Koleszar committed
54

55
56
  if (setjmp(cm->error.jmp)) {
    cm->error.setjmp = 0;
57
    vp9_decoder_remove(pbi);
58
    return NULL;
John Koleszar's avatar
John Koleszar committed
59
  }
John Koleszar's avatar
John Koleszar committed
60

61
  cm->error.setjmp = 1;
62
  pbi->need_resync = 1;
63
  initialize_dec();
John Koleszar's avatar
John Koleszar committed
64

65
66
67
68
  // 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
69
  pbi->ready_for_new_data = 1;
70
  cm->bit_depth = VPX_BITS_8;
71
  cm->dequant_bit_depth = VPX_BITS_8;
John Koleszar's avatar
John Koleszar committed
72

73
  // vp9_init_dequantizer() is first called here. Add check in
74
  // frame_init_dequantizer() to avoid unnecessary calling of
75
  // vp9_init_dequantizer() for every frame.
76
  vp9_init_dequantizer(cm);
John Koleszar's avatar
John Koleszar committed
77

78
  vp9_loop_filter_init(cm);
John Koleszar's avatar
John Koleszar committed
79

80
  cm->error.setjmp = 0;
81

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

84
  return pbi;
John Koleszar's avatar
John Koleszar committed
85
86
}

87
void vp9_decoder_remove(VP9Decoder *pbi) {
88
  VP9_COMMON *const cm = &pbi->common;
89
  int i;
John Koleszar's avatar
John Koleszar committed
90

James Zern's avatar
James Zern committed
91
  vp9_get_worker_interface()->end(&pbi->lf_worker);
92
  vpx_free(pbi->lf_worker.data1);
93
  vpx_free(pbi->tile_data);
94
95
  for (i = 0; i < pbi->num_tile_workers; ++i) {
    VP9Worker *const worker = &pbi->tile_workers[i];
James Zern's avatar
James Zern committed
96
    vp9_get_worker_interface()->end(worker);
97
98
99
100
    vpx_free(worker->data1);
    vpx_free(worker->data2);
  }
  vpx_free(pbi->tile_workers);
101

102
103
  if (pbi->num_tile_workers > 0) {
    vp9_loop_filter_dealloc(&pbi->lf_row_sync);
104
105
  }

106
  vp9_remove_common(cm);
John Koleszar's avatar
John Koleszar committed
107
  vpx_free(pbi);
John Koleszar's avatar
John Koleszar committed
108
109
}

110
111
static int equal_dimensions(const YV12_BUFFER_CONFIG *a,
                            const YV12_BUFFER_CONFIG *b) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
112
113
114
    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
115

116
vpx_codec_err_t vp9_copy_reference_dec(VP9Decoder *pbi,
John Koleszar's avatar
John Koleszar committed
117
118
                                       VP9_REFFRAME ref_frame_flag,
                                       YV12_BUFFER_CONFIG *sd) {
119
  VP9_COMMON *cm = &pbi->common;
John Koleszar's avatar
John Koleszar committed
120

121
122
123
124
125
  /* 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
126
  if (ref_frame_flag == VP9_LAST_FLAG) {
127
128
129
130
131
132
    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;
    }
133
134
135
136
137
    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
138
  } else {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
139
    vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
John Koleszar's avatar
John Koleszar committed
140
                       "Invalid reference frame");
Dmitry Kovalev's avatar
Dmitry Kovalev committed
141
  }
142

Dmitry Kovalev's avatar
Dmitry Kovalev committed
143
  return cm->error.error_code;
John Koleszar's avatar
John Koleszar committed
144
}
145
146


147
vpx_codec_err_t vp9_set_reference_dec(VP9_COMMON *cm,
Dmitry Kovalev's avatar
Dmitry Kovalev committed
148
                                      VP9_REFFRAME ref_frame_flag,
149
                                      YV12_BUFFER_CONFIG *sd) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
150
  RefBuffer *ref_buf = NULL;
John Koleszar's avatar
John Koleszar committed
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.
156
  if (ref_frame_flag == VP9_LAST_FLAG) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
157
    ref_buf = &cm->frame_refs[0];
158
  } else if (ref_frame_flag == VP9_GOLD_FLAG) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
159
    ref_buf = &cm->frame_refs[1];
160
  } else if (ref_frame_flag == VP9_ALT_FLAG) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
161
    ref_buf = &cm->frame_refs[2];
162
  } else {
163
    vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
John Koleszar's avatar
John Koleszar committed
164
                       "Invalid reference frame");
165
    return cm->error.error_code;
John Koleszar's avatar
John Koleszar committed
166
  }
167

Dmitry Kovalev's avatar
Dmitry Kovalev committed
168
  if (!equal_dimensions(ref_buf->buf, sd)) {
169
    vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
John Koleszar's avatar
John Koleszar committed
170
171
                       "Incorrect buffer dimensions");
  } else {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
172
173
    int *ref_fb_ptr = &ref_buf->idx;

Dmitry Kovalev's avatar
Dmitry Kovalev committed
174
175
    // Find an empty frame buffer.
    const int free_fb = get_free_fb(cm);
176
    // Decrease ref_count since it will be increased again in
Dmitry Kovalev's avatar
Dmitry Kovalev committed
177
    // ref_cnt_fb() below.
178
    cm->frame_bufs[free_fb].ref_count--;
John Koleszar's avatar
John Koleszar committed
179

Dmitry Kovalev's avatar
Dmitry Kovalev committed
180
    // Manage the reference counters and copy image.
181
182
    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
183
    vp8_yv12_copy_frame(sd, ref_buf->buf);
John Koleszar's avatar
John Koleszar committed
184
  }
185

186
  return cm->error.error_code;
John Koleszar's avatar
John Koleszar committed
187
188
}

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

194
  for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) {
195
196
    if (mask & 1) {
      const int old_idx = cm->ref_frame_map[ref_index];
197
      ref_cnt_fb(cm->frame_bufs, &cm->ref_frame_map[ref_index],
Dmitry Kovalev's avatar
Dmitry Kovalev committed
198
                 cm->new_fb_idx);
199
200
201
202
      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);
    }
203
204
    ++ref_index;
  }
205

206
  cm->frame_to_show = get_frame_new_buffer(cm);
207
  cm->frame_bufs[cm->new_fb_idx].ref_count--;
208

Dmitry Kovalev's avatar
Dmitry Kovalev committed
209
  // Invalidate these references until the next frame starts.
210
  for (ref_index = 0; ref_index < 3; ref_index++)
Dmitry Kovalev's avatar
Dmitry Kovalev committed
211
    cm->frame_refs[ref_index].idx = INT_MAX;
212
213
}

214
int vp9_receive_compressed_data(VP9Decoder *pbi,
215
                                size_t size, const uint8_t **psource) {
216
  VP9_COMMON *const cm = &pbi->common;
217
  const uint8_t *source = *psource;
John Koleszar's avatar
John Koleszar committed
218
  int retcode = 0;
John Koleszar's avatar
John Koleszar committed
219

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

222
  if (size == 0) {
223
224
225
226
227
228
229
230
    // 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.
Dmitry Kovalev's avatar
Dmitry Kovalev committed
231
232
    if (cm->frame_refs[0].idx != INT_MAX)
      cm->frame_refs[0].buf->corrupted = 1;
John Koleszar's avatar
John Koleszar committed
233
  }
234

235
236
  pbi->ready_for_new_data = 0;

237
  // Check if the previous frame was a frame without any references to it.
238
  if (cm->new_fb_idx >= 0 && cm->frame_bufs[cm->new_fb_idx].ref_count == 0)
239
240
    cm->release_fb_cb(cm->cb_priv,
                      &cm->frame_bufs[cm->new_fb_idx].raw_frame_buffer);
John Koleszar's avatar
John Koleszar committed
241
  cm->new_fb_idx = get_free_fb(cm);
242

Dmitry Kovalev's avatar
Dmitry Kovalev committed
243
  if (setjmp(cm->error.jmp)) {
244
    pbi->need_resync = 1;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
245
    cm->error.setjmp = 0;
246
    vp9_clear_system_state();
John Koleszar's avatar
John Koleszar committed
247

248
249
250
251
252
253
254
    // 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.
255
    if (cm->frame_refs[0].idx != INT_MAX && cm->frame_refs[0].buf != NULL)
Dmitry Kovalev's avatar
Dmitry Kovalev committed
256
      cm->frame_refs[0].buf->corrupted = 1;
John Koleszar's avatar
John Koleszar committed
257

258
    if (cm->new_fb_idx > 0 && cm->frame_bufs[cm->new_fb_idx].ref_count > 0)
259
      cm->frame_bufs[cm->new_fb_idx].ref_count--;
260

John Koleszar's avatar
John Koleszar committed
261
262
    return -1;
  }
John Koleszar's avatar
John Koleszar committed
263

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

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

268
  swap_frame_buffers(pbi);
John Koleszar's avatar
John Koleszar committed
269

270
  vp9_clear_system_state();
John Koleszar's avatar
John Koleszar committed
271

272
273
274
  cm->last_width = cm->width;
  cm->last_height = cm->height;

275
276
  if (!cm->show_existing_frame)
    cm->last_show_frame = cm->show_frame;
John Koleszar's avatar
John Koleszar committed
277
  if (cm->show_frame) {
278
279
280
    if (!cm->show_existing_frame)
      vp9_swap_mi_and_prev_mi(cm);

281
    cm->current_video_frame++;
John Koleszar's avatar
John Koleszar committed
282
  }
283

Dmitry Kovalev's avatar
Dmitry Kovalev committed
284
  cm->error.setjmp = 0;
John Koleszar's avatar
John Koleszar committed
285
  return retcode;
John Koleszar's avatar
John Koleszar committed
286
}
287

288
int vp9_get_raw_frame(VP9Decoder *pbi, YV12_BUFFER_CONFIG *sd,
289
                      vp9_ppflags_t *flags) {
290
  VP9_COMMON *const cm = &pbi->common;
John Koleszar's avatar
John Koleszar committed
291
  int ret = -1;
Yaowu Xu's avatar
Yaowu Xu committed
292
293
294
#if !CONFIG_VP9_POSTPROC
  (void)*flags;
#endif
John Koleszar's avatar
John Koleszar committed
295

John Koleszar's avatar
John Koleszar committed
296
297
  if (pbi->ready_for_new_data == 1)
    return ret;
John Koleszar's avatar
John Koleszar committed
298

299
300
  pbi->ready_for_new_data = 1;

Yaowu Xu's avatar
Yaowu Xu committed
301
  /* no raw frame to show!!! */
302
  if (!cm->show_frame)
John Koleszar's avatar
John Koleszar committed
303
    return ret;
John Koleszar's avatar
John Koleszar committed
304

305
#if CONFIG_VP9_POSTPROC
306
307
308
309
310
311
  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
312
#else
313
  *sd = *cm->frame_to_show;
Yaowu Xu's avatar
Yaowu Xu committed
314
  ret = 0;
315
#endif /*!CONFIG_POSTPROC*/
316
  vp9_clear_system_state();
John Koleszar's avatar
John Koleszar committed
317
  return ret;
John Koleszar's avatar
John Koleszar committed
318
}
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
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

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;
}