vp9_decoder.c 11.9 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 63 64 65 66 67 68

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

69
  pbi->need_resync = 1;
70
  initialize_dec();
John Koleszar's avatar
John Koleszar committed
71

72 73 74 75
  // 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
76
  pbi->ready_for_new_data = 1;
77
  cm->bit_depth = VPX_BITS_8;
78
  cm->dequant_bit_depth = VPX_BITS_8;
John Koleszar's avatar
John Koleszar committed
79

80
  // vp9_init_dequantizer() is first called here. Add check in
81
  // frame_init_dequantizer() to avoid unnecessary calling of
82
  // vp9_init_dequantizer() for every frame.
83
  vp9_init_dequantizer(cm);
John Koleszar's avatar
John Koleszar committed
84

85
  vp9_loop_filter_init(cm);
John Koleszar's avatar
John Koleszar committed
86

87
  cm->error.setjmp = 0;
88

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

91
  return pbi;
John Koleszar's avatar
John Koleszar committed
92 93
}

94
void vp9_decoder_remove(VP9Decoder *pbi) {
95
  VP9_COMMON *const cm = &pbi->common;
96
  int i;
John Koleszar's avatar
John Koleszar committed
97

98 99 100 101 102
  vpx_free(cm->fc);
  cm->fc = NULL;
  vpx_free(cm->frame_contexts);
  cm->frame_contexts = NULL;

James Zern's avatar
James Zern committed
103
  vp9_get_worker_interface()->end(&pbi->lf_worker);
104
  vpx_free(pbi->lf_worker.data1);
105
  vpx_free(pbi->tile_data);
106 107
  for (i = 0; i < pbi->num_tile_workers; ++i) {
    VP9Worker *const worker = &pbi->tile_workers[i];
James Zern's avatar
James Zern committed
108
    vp9_get_worker_interface()->end(worker);
109 110 111 112
    vpx_free(worker->data1);
    vpx_free(worker->data2);
  }
  vpx_free(pbi->tile_workers);
113

114 115
  if (pbi->num_tile_workers > 0) {
    vp9_loop_filter_dealloc(&pbi->lf_row_sync);
116 117
  }

118
  vp9_remove_common(cm);
John Koleszar's avatar
John Koleszar committed
119
  vpx_free(pbi);
John Koleszar's avatar
John Koleszar committed
120 121
}

122 123
static int equal_dimensions(const YV12_BUFFER_CONFIG *a,
                            const YV12_BUFFER_CONFIG *b) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
124 125 126
    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
127

128
vpx_codec_err_t vp9_copy_reference_dec(VP9Decoder *pbi,
John Koleszar's avatar
John Koleszar committed
129 130
                                       VP9_REFFRAME ref_frame_flag,
                                       YV12_BUFFER_CONFIG *sd) {
131
  VP9_COMMON *cm = &pbi->common;
John Koleszar's avatar
John Koleszar committed
132

133 134 135 136 137
  /* 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
138
  if (ref_frame_flag == VP9_LAST_FLAG) {
139 140 141 142 143 144
    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;
    }
145 146 147 148 149
    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
150
  } else {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
151
    vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
John Koleszar's avatar
John Koleszar committed
152
                       "Invalid reference frame");
Dmitry Kovalev's avatar
Dmitry Kovalev committed
153
  }
154

Dmitry Kovalev's avatar
Dmitry Kovalev committed
155
  return cm->error.error_code;
John Koleszar's avatar
John Koleszar committed
156
}
157 158


159
vpx_codec_err_t vp9_set_reference_dec(VP9_COMMON *cm,
Dmitry Kovalev's avatar
Dmitry Kovalev committed
160
                                      VP9_REFFRAME ref_frame_flag,
161
                                      YV12_BUFFER_CONFIG *sd) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
162
  RefBuffer *ref_buf = NULL;
John Koleszar's avatar
John Koleszar committed
163

164 165 166 167
  // 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.
168
  if (ref_frame_flag == VP9_LAST_FLAG) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
169
    ref_buf = &cm->frame_refs[0];
170
  } else if (ref_frame_flag == VP9_GOLD_FLAG) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
171
    ref_buf = &cm->frame_refs[1];
172
  } else if (ref_frame_flag == VP9_ALT_FLAG) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
173
    ref_buf = &cm->frame_refs[2];
174
  } else {
175
    vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
John Koleszar's avatar
John Koleszar committed
176
                       "Invalid reference frame");
177
    return cm->error.error_code;
John Koleszar's avatar
John Koleszar committed
178
  }
179

Dmitry Kovalev's avatar
Dmitry Kovalev committed
180
  if (!equal_dimensions(ref_buf->buf, sd)) {
181
    vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
John Koleszar's avatar
John Koleszar committed
182 183
                       "Incorrect buffer dimensions");
  } else {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
184 185
    int *ref_fb_ptr = &ref_buf->idx;

Dmitry Kovalev's avatar
Dmitry Kovalev committed
186 187
    // Find an empty frame buffer.
    const int free_fb = get_free_fb(cm);
188
    // Decrease ref_count since it will be increased again in
Dmitry Kovalev's avatar
Dmitry Kovalev committed
189
    // ref_cnt_fb() below.
190
    cm->frame_bufs[free_fb].ref_count--;
John Koleszar's avatar
John Koleszar committed
191

Dmitry Kovalev's avatar
Dmitry Kovalev committed
192
    // Manage the reference counters and copy image.
193 194
    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
195
    vp8_yv12_copy_frame(sd, ref_buf->buf);
John Koleszar's avatar
John Koleszar committed
196
  }
197

198
  return cm->error.error_code;
John Koleszar's avatar
John Koleszar committed
199 200
}

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

206
  for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) {
207 208
    if (mask & 1) {
      const int old_idx = cm->ref_frame_map[ref_index];
209
      ref_cnt_fb(cm->frame_bufs, &cm->ref_frame_map[ref_index],
Dmitry Kovalev's avatar
Dmitry Kovalev committed
210
                 cm->new_fb_idx);
211 212 213 214
      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);
    }
215 216
    ++ref_index;
  }
217

218
  cm->frame_to_show = get_frame_new_buffer(cm);
219
  cm->frame_bufs[cm->new_fb_idx].ref_count--;
220

Dmitry Kovalev's avatar
Dmitry Kovalev committed
221
  // Invalidate these references until the next frame starts.
222
  for (ref_index = 0; ref_index < 3; ref_index++)
Dmitry Kovalev's avatar
Dmitry Kovalev committed
223
    cm->frame_refs[ref_index].idx = INT_MAX;
224 225
}

226
int vp9_receive_compressed_data(VP9Decoder *pbi,
227
                                size_t size, const uint8_t **psource) {
228
  VP9_COMMON *const cm = &pbi->common;
229
  const uint8_t *source = *psource;
John Koleszar's avatar
John Koleszar committed
230
  int retcode = 0;
John Koleszar's avatar
John Koleszar committed
231

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

234
  if (size == 0) {
235 236 237 238 239 240 241 242
    // 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
243 244
    if (cm->frame_refs[0].idx != INT_MAX)
      cm->frame_refs[0].buf->corrupted = 1;
John Koleszar's avatar
John Koleszar committed
245
  }
246

247
  // Check if the previous frame was a frame without any references to it.
248
  if (cm->new_fb_idx >= 0 && cm->frame_bufs[cm->new_fb_idx].ref_count == 0)
249 250
    cm->release_fb_cb(cm->cb_priv,
                      &cm->frame_bufs[cm->new_fb_idx].raw_frame_buffer);
John Koleszar's avatar
John Koleszar committed
251
  cm->new_fb_idx = get_free_fb(cm);
252

Dmitry Kovalev's avatar
Dmitry Kovalev committed
253
  if (setjmp(cm->error.jmp)) {
254
    pbi->need_resync = 1;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
255
    cm->error.setjmp = 0;
256
    vp9_clear_system_state();
John Koleszar's avatar
John Koleszar committed
257

258 259 260 261 262 263 264
    // 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.
265
    if (cm->frame_refs[0].idx != INT_MAX && cm->frame_refs[0].buf != NULL)
Dmitry Kovalev's avatar
Dmitry Kovalev committed
266
      cm->frame_refs[0].buf->corrupted = 1;
John Koleszar's avatar
John Koleszar committed
267

268
    if (cm->new_fb_idx > 0 && cm->frame_bufs[cm->new_fb_idx].ref_count > 0)
269
      cm->frame_bufs[cm->new_fb_idx].ref_count--;
270

John Koleszar's avatar
John Koleszar committed
271 272
    return -1;
  }
John Koleszar's avatar
John Koleszar committed
273

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

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

278
  swap_frame_buffers(pbi);
John Koleszar's avatar
John Koleszar committed
279

280
  vp9_clear_system_state();
John Koleszar's avatar
John Koleszar committed
281

282 283 284
  cm->last_width = cm->width;
  cm->last_height = cm->height;

285 286
  if (!cm->show_existing_frame)
    cm->last_show_frame = cm->show_frame;
John Koleszar's avatar
John Koleszar committed
287
  if (cm->show_frame) {
288 289 290
    if (!cm->show_existing_frame)
      vp9_swap_mi_and_prev_mi(cm);

291
    cm->current_video_frame++;
John Koleszar's avatar
John Koleszar committed
292
  }
293

John Koleszar's avatar
John Koleszar committed
294
  pbi->ready_for_new_data = 0;
John Koleszar's avatar
John Koleszar committed
295

Dmitry Kovalev's avatar
Dmitry Kovalev committed
296
  cm->error.setjmp = 0;
John Koleszar's avatar
John Koleszar committed
297
  return retcode;
John Koleszar's avatar
John Koleszar committed
298
}
299

300
int vp9_get_raw_frame(VP9Decoder *pbi, YV12_BUFFER_CONFIG *sd,
301
                      vp9_ppflags_t *flags) {
302
  VP9_COMMON *const cm = &pbi->common;
John Koleszar's avatar
John Koleszar committed
303
  int ret = -1;
Yaowu Xu's avatar
Yaowu Xu committed
304 305 306
#if !CONFIG_VP9_POSTPROC
  (void)*flags;
#endif
John Koleszar's avatar
John Koleszar committed
307

John Koleszar's avatar
John Koleszar committed
308 309
  if (pbi->ready_for_new_data == 1)
    return ret;
John Koleszar's avatar
John Koleszar committed
310

Yaowu Xu's avatar
Yaowu Xu committed
311
  /* no raw frame to show!!! */
312
  if (!cm->show_frame)
John Koleszar's avatar
John Koleszar committed
313
    return ret;
John Koleszar's avatar
John Koleszar committed
314

John Koleszar's avatar
John Koleszar committed
315
  pbi->ready_for_new_data = 1;
John Koleszar's avatar
John Koleszar committed
316

317
#if CONFIG_VP9_POSTPROC
318 319 320 321 322 323
  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
324
#else
325
  *sd = *cm->frame_to_show;
Yaowu Xu's avatar
Yaowu Xu committed
326
  ret = 0;
327
#endif /*!CONFIG_POSTPROC*/
328
  vp9_clear_system_state();
John Koleszar's avatar
John Koleszar committed
329
  return ret;
John Koleszar's avatar
John Koleszar committed
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 383 384 385 386 387 388 389 390 391 392 393 394

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