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() {
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;
}

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,
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) {
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) {
187
    ref_buf = &cm->frame_refs[0];
188
  } else if (ref_frame_flag == VP9_GOLD_FLAG) {
189
    ref_buf = &cm->frame_refs[1];
190
  } else if (ref_frame_flag == VP9_ALT_FLAG) {
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

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 {
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;
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 = INT_MAX;
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 262
    if (cm->frame_refs[0].idx != INT_MAX)
      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)) {
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;
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;
}