vp9_decodemv.c 29.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
 */

11
12
#include <assert.h>

13
14
#include "vp9/common/vp9_common.h"
#include "vp9/common/vp9_entropy.h"
15
#include "vp9/common/vp9_entropymode.h"
16
17
#include "vp9/common/vp9_entropymv.h"
#include "vp9/common/vp9_mvref_common.h"
18
#include "vp9/common/vp9_pred_common.h"
19
20
21
#include "vp9/common/vp9_reconinter.h"
#include "vp9/common/vp9_seg_common.h"

22
#include "vp9/decoder/vp9_decodemv.h"
Yaowu Xu's avatar
Yaowu Xu committed
23
#include "vp9/decoder/vp9_decodeframe.h"
24

25
26
#include "vpx_dsp/vpx_dsp_common.h"

Yaowu Xu's avatar
Yaowu Xu committed
27
28
static PREDICTION_MODE read_intra_mode(vpx_reader *r, const vpx_prob *p) {
  return (PREDICTION_MODE)vpx_read_tree(r, vp9_intra_mode_tree, p);
29
30
}

Scott LaVarnway's avatar
Scott LaVarnway committed
31
static PREDICTION_MODE read_intra_mode_y(VP9_COMMON *cm, MACROBLOCKD *xd,
Yaowu Xu's avatar
Yaowu Xu committed
32
                                         vpx_reader *r, int size_group) {
33
  const PREDICTION_MODE y_mode =
34
      read_intra_mode(r, cm->fc->y_mode_prob[size_group]);
Scott LaVarnway's avatar
Scott LaVarnway committed
35
36
  FRAME_COUNTS *counts = xd->counts;
  if (counts)
37
    ++counts->y_mode[size_group][y_mode];
38
39
40
  return y_mode;
}

Scott LaVarnway's avatar
Scott LaVarnway committed
41
static PREDICTION_MODE read_intra_mode_uv(VP9_COMMON *cm, MACROBLOCKD *xd,
Yaowu Xu's avatar
Yaowu Xu committed
42
                                          vpx_reader *r,
43
44
                                          PREDICTION_MODE y_mode) {
  const PREDICTION_MODE uv_mode = read_intra_mode(r,
45
                                         cm->fc->uv_mode_prob[y_mode]);
Scott LaVarnway's avatar
Scott LaVarnway committed
46
47
  FRAME_COUNTS *counts = xd->counts;
  if (counts)
48
    ++counts->uv_mode[y_mode][uv_mode];
49
50
51
  return uv_mode;
}

Scott LaVarnway's avatar
Scott LaVarnway committed
52
static PREDICTION_MODE read_inter_mode(VP9_COMMON *cm, MACROBLOCKD *xd,
Yaowu Xu's avatar
Yaowu Xu committed
53
54
                                       vpx_reader *r, int ctx) {
  const int mode = vpx_read_tree(r, vp9_inter_mode_tree,
55
                                 cm->fc->inter_mode_probs[ctx]);
Scott LaVarnway's avatar
Scott LaVarnway committed
56
57
  FRAME_COUNTS *counts = xd->counts;
  if (counts)
58
    ++counts->inter_mode[ctx][mode];
59
60

  return NEARESTMV + mode;
61
62
}

Yaowu Xu's avatar
Yaowu Xu committed
63
64
static int read_segment_id(vpx_reader *r, const struct segmentation *seg) {
  return vpx_read_tree(r, vp9_segment_tree, seg->tree_probs);
Scott LaVarnway's avatar
Scott LaVarnway committed
65
}
66

67
static TX_SIZE read_selected_tx_size(VP9_COMMON *cm, MACROBLOCKD *xd,
Yaowu Xu's avatar
Yaowu Xu committed
68
                                     TX_SIZE max_tx_size, vpx_reader *r) {
Scott LaVarnway's avatar
Scott LaVarnway committed
69
  FRAME_COUNTS *counts = xd->counts;
70
  const int ctx = get_tx_size_context(xd);
Yaowu Xu's avatar
Yaowu Xu committed
71
72
  const vpx_prob *tx_probs = get_tx_probs(max_tx_size, ctx, &cm->fc->tx_probs);
  int tx_size = vpx_read(r, tx_probs[0]);
73
  if (tx_size != TX_4X4 && max_tx_size >= TX_16X16) {
Yaowu Xu's avatar
Yaowu Xu committed
74
    tx_size += vpx_read(r, tx_probs[1]);
75
    if (tx_size != TX_8X8 && max_tx_size >= TX_32X32)
Yaowu Xu's avatar
Yaowu Xu committed
76
      tx_size += vpx_read(r, tx_probs[2]);
77
78
  }

Scott LaVarnway's avatar
Scott LaVarnway committed
79
  if (counts)
80
    ++get_tx_counts(max_tx_size, ctx, &counts->tx)[tx_size];
Dmitry Kovalev's avatar
Dmitry Kovalev committed
81
  return (TX_SIZE)tx_size;
82
83
}

84
static TX_SIZE read_tx_size(VP9_COMMON *cm, MACROBLOCKD *xd,
Yaowu Xu's avatar
Yaowu Xu committed
85
                            int allow_select, vpx_reader *r) {
86
  TX_MODE tx_mode = cm->tx_mode;
87
  BLOCK_SIZE bsize = xd->mi[0]->mbmi.sb_type;
88
89
  const TX_SIZE max_tx_size = max_txsize_lookup[bsize];
  if (allow_select && tx_mode == TX_MODE_SELECT && bsize >= BLOCK_8X8)
Scott LaVarnway's avatar
Scott LaVarnway committed
90
    return read_selected_tx_size(cm, xd, max_tx_size, r);
91
  else
92
    return VPXMIN(max_tx_size, tx_mode_to_biggest_tx_size[tx_mode]);
93
94
}

95
96
97
98
99
100
static int dec_get_segment_id(const VP9_COMMON *cm, const uint8_t *segment_ids,
                              int mi_offset, int x_mis, int y_mis) {
  int x, y, segment_id = INT_MAX;

  for (y = 0; y < y_mis; y++)
    for (x = 0; x < x_mis; x++)
101
102
      segment_id =
          VPXMIN(segment_id, segment_ids[mi_offset + y * cm->mi_cols + x]);
103
104
105
106
107
108
109

  assert(segment_id >= 0 && segment_id < MAX_SEGMENTS);
  return segment_id;
}

static void set_segment_id(VP9_COMMON *cm, int mi_offset,
                           int x_mis, int y_mis, int segment_id) {
110
111
112
113
  int x, y;

  assert(segment_id >= 0 && segment_id < MAX_SEGMENTS);

114
115
  for (y = 0; y < y_mis; y++)
    for (x = 0; x < x_mis; x++)
116
117
118
119
120
121
      cm->current_frame_seg_map[mi_offset + y * cm->mi_cols + x] = segment_id;
}

static void copy_segment_id(const VP9_COMMON *cm,
                           const uint8_t *last_segment_ids,
                           uint8_t *current_segment_ids,
122
                           int mi_offset, int x_mis, int y_mis) {
123
124
  int x, y;

125
126
  for (y = 0; y < y_mis; y++)
    for (x = 0; x < x_mis; x++)
127
128
      current_segment_ids[mi_offset + y * cm->mi_cols + x] =  last_segment_ids ?
          last_segment_ids[mi_offset + y * cm->mi_cols + x] : 0;
129
130
}

131
132
static int read_intra_segment_id(VP9_COMMON *const cm, int mi_offset,
                                 int x_mis, int y_mis,
Yaowu Xu's avatar
Yaowu Xu committed
133
                                 vpx_reader *r) {
134
  struct segmentation *const seg = &cm->seg;
135
  int segment_id;
136

137
138
139
  if (!seg->enabled)
    return 0;  // Default for disabled segmentation

140
141
  if (!seg->update_map) {
    copy_segment_id(cm, cm->last_frame_seg_map, cm->current_frame_seg_map,
142
                    mi_offset, x_mis, y_mis);
143
    return 0;
144
  }
145

146
  segment_id = read_segment_id(r, seg);
147
  set_segment_id(cm, mi_offset, x_mis, y_mis, segment_id);
148
  return segment_id;
149
150
}

151
static int read_inter_segment_id(VP9_COMMON *const cm, MACROBLOCKD *const xd,
Yaowu Xu's avatar
Yaowu Xu committed
152
                                 int mi_row, int mi_col, vpx_reader *r) {
153
  struct segmentation *const seg = &cm->seg;
154
  MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
155
  int predicted_segment_id, segment_id;
156
157
158
159
160
  const int mi_offset = mi_row * cm->mi_cols + mi_col;
  const int bw = xd->plane[0].n4_w >> 1;
  const int bh = xd->plane[0].n4_h >> 1;

  // TODO(slavarnway): move x_mis, y_mis into xd ?????
161
162
  const int x_mis = VPXMIN(cm->mi_cols - mi_col, bw);
  const int y_mis = VPXMIN(cm->mi_rows - mi_row, bh);
163
164
165
166

  if (!seg->enabled)
    return 0;  // Default for disabled segmentation

167
  predicted_segment_id = cm->last_frame_seg_map ?
168
169
      dec_get_segment_id(cm, cm->last_frame_seg_map, mi_offset, x_mis, y_mis) :
      0;
170
171
172

  if (!seg->update_map) {
    copy_segment_id(cm, cm->last_frame_seg_map, cm->current_frame_seg_map,
173
                    mi_offset, x_mis, y_mis);
174
    return predicted_segment_id;
175
  }
176
177

  if (seg->temporal_update) {
Yaowu Xu's avatar
Yaowu Xu committed
178
179
    const vpx_prob pred_prob = vp9_get_pred_prob_seg_id(seg, xd);
    mbmi->seg_id_predicted = vpx_read(r, pred_prob);
180
181
    segment_id = mbmi->seg_id_predicted ? predicted_segment_id
                                        : read_segment_id(r, seg);
182
  } else {
183
    segment_id = read_segment_id(r, seg);
184
  }
185
  set_segment_id(cm, mi_offset, x_mis, y_mis, segment_id);
186
  return segment_id;
187
188
}

189
static int read_skip(VP9_COMMON *cm, const MACROBLOCKD *xd,
Yaowu Xu's avatar
Yaowu Xu committed
190
                     int segment_id, vpx_reader *r) {
191
  if (segfeature_active(&cm->seg, segment_id, SEG_LVL_SKIP)) {
192
193
    return 1;
  } else {
194
    const int ctx = vp9_get_skip_context(xd);
Yaowu Xu's avatar
Yaowu Xu committed
195
    const int skip = vpx_read(r, cm->fc->skip_probs[ctx]);
Scott LaVarnway's avatar
Scott LaVarnway committed
196
197
    FRAME_COUNTS *counts = xd->counts;
    if (counts)
198
      ++counts->skip[ctx][skip];
199
    return skip;
Deb Mukherjee's avatar
Deb Mukherjee committed
200
  }
201
}
John Koleszar's avatar
John Koleszar committed
202

203
204
static void read_intra_frame_mode_info(VP9_COMMON *const cm,
                                       MACROBLOCKD *const xd,
Yaowu Xu's avatar
Yaowu Xu committed
205
                                       int mi_row, int mi_col, vpx_reader *r) {
206
  MODE_INFO *const mi = xd->mi[0];
207
  MB_MODE_INFO *const mbmi = &mi->mbmi;
208
209
  const MODE_INFO *above_mi = xd->above_mi;
  const MODE_INFO *left_mi  = xd->left_mi;
210
  const BLOCK_SIZE bsize = mbmi->sb_type;
211
  int i;
212
213
214
215
216
  const int mi_offset = mi_row * cm->mi_cols + mi_col;
  const int bw = xd->plane[0].n4_w >> 1;
  const int bh = xd->plane[0].n4_h >> 1;

  // TODO(slavarnway): move x_mis, y_mis into xd ?????
217
218
  const int x_mis = VPXMIN(cm->mi_cols - mi_col, bw);
  const int y_mis = VPXMIN(cm->mi_rows - mi_row, bh);
219

220
  mbmi->segment_id = read_intra_segment_id(cm, mi_offset, x_mis, y_mis, r);
Scott LaVarnway's avatar
Scott LaVarnway committed
221
222
  mbmi->skip = read_skip(cm, xd, mbmi->segment_id, r);
  mbmi->tx_size = read_tx_size(cm, xd, 1, r);
223
  mbmi->ref_frame[0] = INTRA_FRAME;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
224
  mbmi->ref_frame[1] = NONE;
225

226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
  switch (bsize) {
    case BLOCK_4X4:
      for (i = 0; i < 4; ++i)
        mi->bmi[i].as_mode =
            read_intra_mode(r, get_y_mode_probs(mi, above_mi, left_mi, i));
      mbmi->mode = mi->bmi[3].as_mode;
      break;
    case BLOCK_4X8:
      mi->bmi[0].as_mode = mi->bmi[2].as_mode =
          read_intra_mode(r, get_y_mode_probs(mi, above_mi, left_mi, 0));
      mi->bmi[1].as_mode = mi->bmi[3].as_mode = mbmi->mode =
          read_intra_mode(r, get_y_mode_probs(mi, above_mi, left_mi, 1));
      break;
    case BLOCK_8X4:
      mi->bmi[0].as_mode = mi->bmi[1].as_mode =
          read_intra_mode(r, get_y_mode_probs(mi, above_mi, left_mi, 0));
      mi->bmi[2].as_mode = mi->bmi[3].as_mode = mbmi->mode =
          read_intra_mode(r, get_y_mode_probs(mi, above_mi, left_mi, 2));
      break;
    default:
      mbmi->mode = read_intra_mode(r,
                                   get_y_mode_probs(mi, above_mi, left_mi, 0));
John Koleszar's avatar
John Koleszar committed
248
  }
Dmitry Kovalev's avatar
Dmitry Kovalev committed
249

250
  mbmi->uv_mode = read_intra_mode(r, vp9_kf_uv_mode_prob[mbmi->mode]);
Scott LaVarnway's avatar
Scott LaVarnway committed
251
}
John Koleszar's avatar
John Koleszar committed
252

Yaowu Xu's avatar
Yaowu Xu committed
253
static int read_mv_component(vpx_reader *r,
254
255
                             const nmv_component *mvcomp, int usehp) {
  int mag, d, fr, hp;
Yaowu Xu's avatar
Yaowu Xu committed
256
257
  const int sign = vpx_read(r, mvcomp->sign);
  const int mv_class = vpx_read_tree(r, vp9_mv_class_tree, mvcomp->classes);
258
  const int class0 = mv_class == MV_CLASS_0;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
259

260
  // Integer part
261
  if (class0) {
Yaowu Xu's avatar
Yaowu Xu committed
262
    d = vpx_read_tree(r, vp9_mv_class0_tree, mvcomp->class0);
263
    mag = 0;
264
  } else {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
265
    int i;
266
    const int n = mv_class + CLASS0_BITS - 1;  // number of bits
Dmitry Kovalev's avatar
Dmitry Kovalev committed
267

268
    d = 0;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
269
    for (i = 0; i < n; ++i)
Yaowu Xu's avatar
Yaowu Xu committed
270
      d |= vpx_read(r, mvcomp->bits[i]) << i;
271
    mag = CLASS0_SIZE << (mv_class + 2);
272
273
  }

274
  // Fractional part
Yaowu Xu's avatar
Yaowu Xu committed
275
  fr = vpx_read_tree(r, vp9_mv_fp_tree, class0 ? mvcomp->class0_fp[d]
276
                                               : mvcomp->fp);
277

278
  // High precision part (if hp is not used, the default value of the hp is 1)
Yaowu Xu's avatar
Yaowu Xu committed
279
  hp = usehp ? vpx_read(r, class0 ? mvcomp->class0_hp : mvcomp->hp)
280
             : 1;
281

282
  // Result
283
  mag += ((d << 3) | (fr << 1) | hp) + 1;
284
  return sign ? -mag : mag;
285
286
}

287
288
289
290
291
292
293
// TODO(slavarnway): move to vp9_entropymv.h and replace vp9_use_mv_hp
#define COMPANDED_MVREF_THRESH 8
static int use_mv_hp(const MV *ref) {
  return (abs(ref->row) >> 3) < COMPANDED_MVREF_THRESH &&
         (abs(ref->col) >> 3) < COMPANDED_MVREF_THRESH;
}

Yaowu Xu's avatar
Yaowu Xu committed
294
static INLINE void read_mv(vpx_reader *r, MV *mv, const MV *ref,
295
                           const nmv_context *ctx,
296
                           nmv_context_counts *counts, int allow_hp) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
297
  const MV_JOINT_TYPE joint_type =
Yaowu Xu's avatar
Yaowu Xu committed
298
      (MV_JOINT_TYPE)vpx_read_tree(r, vp9_mv_joint_tree, ctx->joints);
299
  const int use_hp = allow_hp && use_mv_hp(ref);
300
301
  MV diff = {0, 0};

Dmitry Kovalev's avatar
Dmitry Kovalev committed
302
  if (mv_joint_vertical(joint_type))
303
    diff.row = read_mv_component(r, &ctx->comps[0], use_hp);
304

Dmitry Kovalev's avatar
Dmitry Kovalev committed
305
  if (mv_joint_horizontal(joint_type))
306
    diff.col = read_mv_component(r, &ctx->comps[1], use_hp);
307

308
  vp9_inc_mv(&diff, counts);
309
310
311
312
313

  mv->row = ref->row + diff.row;
  mv->col = ref->col + diff.col;
}

314
315
static REFERENCE_MODE read_block_reference_mode(VP9_COMMON *cm,
                                                const MACROBLOCKD *xd,
Yaowu Xu's avatar
Yaowu Xu committed
316
                                                vpx_reader *r) {
317
318
  if (cm->reference_mode == REFERENCE_MODE_SELECT) {
    const int ctx = vp9_get_reference_mode_context(cm, xd);
319
    const REFERENCE_MODE mode =
Yaowu Xu's avatar
Yaowu Xu committed
320
        (REFERENCE_MODE)vpx_read(r, cm->fc->comp_inter_prob[ctx]);
Scott LaVarnway's avatar
Scott LaVarnway committed
321
322
    FRAME_COUNTS *counts = xd->counts;
    if (counts)
323
      ++counts->comp_inter[ctx][mode];
324
325
326
327
    return mode;  // SINGLE_REFERENCE or COMPOUND_REFERENCE
  } else {
    return cm->reference_mode;
  }
328
329
}

330
// Read the referncence frame
331
static void read_ref_frames(VP9_COMMON *const cm, MACROBLOCKD *const xd,
Yaowu Xu's avatar
Yaowu Xu committed
332
                            vpx_reader *r,
Dmitry Kovalev's avatar
Dmitry Kovalev committed
333
                            int segment_id, MV_REFERENCE_FRAME ref_frame[2]) {
334
  FRAME_CONTEXT *const fc = cm->fc;
Scott LaVarnway's avatar
Scott LaVarnway committed
335
  FRAME_COUNTS *counts = xd->counts;
336

337
  if (segfeature_active(&cm->seg, segment_id, SEG_LVL_REF_FRAME)) {
Scott LaVarnway's avatar
Scott LaVarnway committed
338
339
    ref_frame[0] = (MV_REFERENCE_FRAME)get_segdata(&cm->seg, segment_id,
                                                   SEG_LVL_REF_FRAME);
340
341
    ref_frame[1] = NONE;
  } else {
Scott LaVarnway's avatar
Scott LaVarnway committed
342
    const REFERENCE_MODE mode = read_block_reference_mode(cm, xd, r);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
343
    // FIXME(rbultje) I'm pretty sure this breaks segmentation ref frame coding
344
    if (mode == COMPOUND_REFERENCE) {
345
346
      const int idx = cm->ref_frame_sign_bias[cm->comp_fixed_ref];
      const int ctx = vp9_get_pred_context_comp_ref_p(cm, xd);
Yaowu Xu's avatar
Yaowu Xu committed
347
      const int bit = vpx_read(r, fc->comp_ref_prob[ctx]);
Scott LaVarnway's avatar
Scott LaVarnway committed
348
      if (counts)
349
350
351
        ++counts->comp_ref[ctx][bit];
      ref_frame[idx] = cm->comp_fixed_ref;
      ref_frame[!idx] = cm->comp_var_ref[bit];
352
    } else if (mode == SINGLE_REFERENCE) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
353
      const int ctx0 = vp9_get_pred_context_single_ref_p1(xd);
Yaowu Xu's avatar
Yaowu Xu committed
354
      const int bit0 = vpx_read(r, fc->single_ref_prob[ctx0][0]);
Scott LaVarnway's avatar
Scott LaVarnway committed
355
      if (counts)
356
        ++counts->single_ref[ctx0][0][bit0];
Dmitry Kovalev's avatar
Dmitry Kovalev committed
357
358
      if (bit0) {
        const int ctx1 = vp9_get_pred_context_single_ref_p2(xd);
Yaowu Xu's avatar
Yaowu Xu committed
359
        const int bit1 = vpx_read(r, fc->single_ref_prob[ctx1][1]);
Scott LaVarnway's avatar
Scott LaVarnway committed
360
        if (counts)
361
          ++counts->single_ref[ctx1][1][bit1];
362
        ref_frame[0] = bit1 ? ALTREF_FRAME : GOLDEN_FRAME;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
363
364
      } else {
        ref_frame[0] = LAST_FRAME;
John Koleszar's avatar
John Koleszar committed
365
      }
Dmitry Kovalev's avatar
Dmitry Kovalev committed
366
367

      ref_frame[1] = NONE;
368
    } else {
James Zern's avatar
James Zern committed
369
      assert(0 && "Invalid prediction mode.");
370
    }
John Koleszar's avatar
John Koleszar committed
371
  }
372
}
John Koleszar's avatar
John Koleszar committed
373

374

375
static INLINE INTERP_FILTER read_switchable_interp_filter(
376
    VP9_COMMON *const cm, MACROBLOCKD *const xd,
Yaowu Xu's avatar
Yaowu Xu committed
377
    vpx_reader *r) {
378
  const int ctx = vp9_get_pred_context_switchable_interp(xd);
379
  const INTERP_FILTER type =
Yaowu Xu's avatar
Yaowu Xu committed
380
      (INTERP_FILTER)vpx_read_tree(r, vp9_switchable_interp_tree,
381
                                   cm->fc->switchable_interp_prob[ctx]);
Scott LaVarnway's avatar
Scott LaVarnway committed
382
383
  FRAME_COUNTS *counts = xd->counts;
  if (counts)
384
    ++counts->switchable_interp[ctx][type];
385
  return type;
386
387
}

388
static void read_intra_block_mode_info(VP9_COMMON *const cm,
Scott LaVarnway's avatar
Scott LaVarnway committed
389
                                       MACROBLOCKD *const xd, MODE_INFO *mi,
Yaowu Xu's avatar
Yaowu Xu committed
390
                                       vpx_reader *r) {
391
  MB_MODE_INFO *const mbmi = &mi->mbmi;
392
  const BLOCK_SIZE bsize = mi->mbmi.sb_type;
393
  int i;
394

Dmitry Kovalev's avatar
Dmitry Kovalev committed
395
396
397
  mbmi->ref_frame[0] = INTRA_FRAME;
  mbmi->ref_frame[1] = NONE;

398
399
400
  switch (bsize) {
    case BLOCK_4X4:
      for (i = 0; i < 4; ++i)
Scott LaVarnway's avatar
Scott LaVarnway committed
401
        mi->bmi[i].as_mode = read_intra_mode_y(cm, xd, r, 0);
402
403
404
      mbmi->mode = mi->bmi[3].as_mode;
      break;
    case BLOCK_4X8:
Scott LaVarnway's avatar
Scott LaVarnway committed
405
      mi->bmi[0].as_mode = mi->bmi[2].as_mode = read_intra_mode_y(cm, xd,
406
                                                                  r, 0);
407
      mi->bmi[1].as_mode = mi->bmi[3].as_mode = mbmi->mode =
Scott LaVarnway's avatar
Scott LaVarnway committed
408
          read_intra_mode_y(cm, xd, r, 0);
409
410
      break;
    case BLOCK_8X4:
Scott LaVarnway's avatar
Scott LaVarnway committed
411
      mi->bmi[0].as_mode = mi->bmi[1].as_mode = read_intra_mode_y(cm, xd,
412
                                                                  r, 0);
413
      mi->bmi[2].as_mode = mi->bmi[3].as_mode = mbmi->mode =
Scott LaVarnway's avatar
Scott LaVarnway committed
414
          read_intra_mode_y(cm, xd, r, 0);
415
416
      break;
    default:
Scott LaVarnway's avatar
Scott LaVarnway committed
417
      mbmi->mode = read_intra_mode_y(cm, xd, r, size_group_lookup[bsize]);
418
419
  }

Scott LaVarnway's avatar
Scott LaVarnway committed
420
  mbmi->uv_mode = read_intra_mode_uv(cm, xd, r, mbmi->mode);
421
422
}

423
424
425
426
427
static INLINE int is_mv_valid(const MV *mv) {
  return mv->row > MV_LOW && mv->row < MV_UPP &&
         mv->col > MV_LOW && mv->col < MV_UPP;
}

Scott LaVarnway's avatar
Scott LaVarnway committed
428
static INLINE int assign_mv(VP9_COMMON *cm, MACROBLOCKD *xd,
429
                            PREDICTION_MODE mode,
430
431
                            int_mv mv[2], int_mv ref_mv[2],
                            int_mv nearest_mv[2], int_mv near_mv[2],
Yaowu Xu's avatar
Yaowu Xu committed
432
                            int is_compound, int allow_hp, vpx_reader *r) {
433
  int i;
Yaowu Xu's avatar
Yaowu Xu committed
434
  int ret = 1;
435
436

  switch (mode) {
437
    case NEWMV: {
Scott LaVarnway's avatar
Scott LaVarnway committed
438
439
      FRAME_COUNTS *counts = xd->counts;
      nmv_context_counts *const mv_counts = counts ? &counts->mv : NULL;
440
      for (i = 0; i < 1 + is_compound; ++i) {
441
        read_mv(r, &mv[i].as_mv, &ref_mv[i].as_mv, &cm->fc->nmvc, mv_counts,
442
443
                allow_hp);
        ret = ret && is_mv_valid(&mv[i].as_mv);
444
445
446
447
448
      }
      break;
    }
    case NEARESTMV: {
      mv[0].as_int = nearest_mv[0].as_int;
449
450
      if (is_compound)
        mv[1].as_int = nearest_mv[1].as_int;
451
      break;
452
453
    }
    case NEARMV: {
454
      mv[0].as_int = near_mv[0].as_int;
455
456
      if (is_compound)
        mv[1].as_int = near_mv[1].as_int;
457
      break;
458
459
    }
    case ZEROMV: {
460
      mv[0].as_int = 0;
461
462
      if (is_compound)
        mv[1].as_int = 0;
463
      break;
464
465
    }
    default: {
Yaowu Xu's avatar
Yaowu Xu committed
466
      return 0;
467
    }
468
  }
Yaowu Xu's avatar
Yaowu Xu committed
469
  return ret;
470
471
}

472
static int read_is_inter_block(VP9_COMMON *const cm, MACROBLOCKD *const xd,
Yaowu Xu's avatar
Yaowu Xu committed
473
                               int segment_id, vpx_reader *r) {
474
  if (segfeature_active(&cm->seg, segment_id, SEG_LVL_REF_FRAME)) {
Scott LaVarnway's avatar
Scott LaVarnway committed
475
    return get_segdata(&cm->seg, segment_id, SEG_LVL_REF_FRAME) != INTRA_FRAME;
476
  } else {
477
    const int ctx = vp9_get_intra_inter_context(xd);
Yaowu Xu's avatar
Yaowu Xu committed
478
    const int is_inter = vpx_read(r, cm->fc->intra_inter_prob[ctx]);
Scott LaVarnway's avatar
Scott LaVarnway committed
479
480
    FRAME_COUNTS *counts = xd->counts;
    if (counts)
481
      ++counts->intra_inter[ctx][is_inter];
Dmitry Kovalev's avatar
Dmitry Kovalev committed
482
    return is_inter;
483
484
485
  }
}

486
487
488
489
490
491
492
493
494
495
496
497
498
499
static void dec_find_best_ref_mvs(MACROBLOCKD *xd, int allow_hp, int_mv *mvlist,
                                  int_mv *nearest_mv, int_mv *near_mv,
                                  int refmv_count) {
  int i;

  // Make sure all the candidates are properly clamped etc
  for (i = 0; i < refmv_count; ++i) {
    lower_mv_precision(&mvlist[i].as_mv, allow_hp);
    clamp_mv2(&mvlist[i].as_mv, xd);
  }
  *nearest_mv = mvlist[0];
  *near_mv = mvlist[1];
}

500
501
static void fpm_sync(void *const data, int mi_row) {
  VP9Decoder *const pbi = (VP9Decoder *)data;
502
  vp9_frameworker_wait(pbi->frame_worker_owner, pbi->common.prev_frame,
503
504
505
                       mi_row << MI_BLOCK_SIZE_LOG2);
}

506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
// This macro is used to add a motion vector mv_ref list if it isn't
// already in the list.  If it's the second motion vector or early_break
// it will also skip all additional processing and jump to Done!
#define ADD_MV_REF_LIST_EB(mv, refmv_count, mv_ref_list, Done) \
  do { \
    if (refmv_count) { \
      if ((mv).as_int != (mv_ref_list)[0].as_int) { \
        (mv_ref_list)[(refmv_count)] = (mv); \
        refmv_count++; \
        goto Done; \
      } \
    } else { \
      (mv_ref_list)[(refmv_count)++] = (mv); \
      if (early_break) \
        goto Done; \
    } \
  } while (0)

// If either reference frame is different, not INTRA, and they
// are different from each other scale and add the mv to our list.
#define IF_DIFF_REF_FRAME_ADD_MV_EB(mbmi, ref_frame, ref_sign_bias, \
                                    refmv_count, mv_ref_list, Done) \
  do { \
    if (is_inter_block(mbmi)) { \
      if ((mbmi)->ref_frame[0] != ref_frame) \
        ADD_MV_REF_LIST_EB(scale_mv((mbmi), 0, ref_frame, ref_sign_bias), \
                           refmv_count, mv_ref_list, Done); \
      if (has_second_ref(mbmi) && \
          (mbmi)->ref_frame[1] != ref_frame && \
          (mbmi)->mv[1].as_int != (mbmi)->mv[0].as_int) \
        ADD_MV_REF_LIST_EB(scale_mv((mbmi), 1, ref_frame, ref_sign_bias), \
                           refmv_count, mv_ref_list, Done); \
    } \
  } while (0)

// This function searches the neighborhood of a given MB/SB
// to try and find candidate reference vectors.
static int dec_find_mv_refs(const VP9_COMMON *cm, const MACROBLOCKD *xd,
                            MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
                            const POSITION *const mv_ref_search,
                            int_mv *mv_ref_list,
                            int mi_row, int mi_col,
                            find_mv_refs_sync sync, void *const data) {
  const int *ref_sign_bias = cm->ref_frame_sign_bias;
  int i, refmv_count = 0;
  int different_ref_found = 0;
  const MV_REF *const prev_frame_mvs = cm->use_prev_frame_mvs ?
      cm->prev_frame->mvs + mi_row * cm->mi_cols + mi_col : NULL;
  const TileInfo *const tile = &xd->tile;
  // If mode is nearestmv or newmv (uses nearestmv as a reference) then stop
  // searching after the first mv is found.
  const int early_break = (mi->mbmi.mode == NEARESTMV) ||
                          (mi->mbmi.mode == NEWMV);

  // Blank the reference vector list
  memset(mv_ref_list, 0, sizeof(*mv_ref_list) * MAX_MV_REF_CANDIDATES);

  // Check the rest of the neighbors in much the same way
  // as before except we don't need to keep track of sub blocks or
  // mode counts.
  for (i = 0; i < MVREF_NEIGHBOURS; ++i) {
    const POSITION *const mv_ref = &mv_ref_search[i];
    if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
      const MB_MODE_INFO *const candidate =
          &xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride]->mbmi;
      different_ref_found = 1;

      if (candidate->ref_frame[0] == ref_frame)
        ADD_MV_REF_LIST_EB(candidate->mv[0], refmv_count, mv_ref_list, Done);
      else if (candidate->ref_frame[1] == ref_frame)
        ADD_MV_REF_LIST_EB(candidate->mv[1], refmv_count, mv_ref_list, Done);
    }
  }

  // TODO(hkuang): Remove this sync after fixing pthread_cond_broadcast
  // on windows platform. The sync here is unnecessary if use_prev_frame_mvs
  // is 0. But after removing it, there will be hang in the unit test on windows
  // due to several threads waiting for a thread's signal.
#if defined(_WIN32) && !HAVE_PTHREAD_H
    if (cm->frame_parallel_decode && sync != NULL) {
      sync(data, mi_row);
    }
#endif

  // Check the last frame's mode and mv info.
  if (prev_frame_mvs) {
    // Synchronize here for frame parallel decode if sync function is provided.
    if (cm->frame_parallel_decode && sync != NULL) {
      sync(data, mi_row);
    }

    if (prev_frame_mvs->ref_frame[0] == ref_frame) {
      ADD_MV_REF_LIST_EB(prev_frame_mvs->mv[0], refmv_count, mv_ref_list, Done);
    } else if (prev_frame_mvs->ref_frame[1] == ref_frame) {
      ADD_MV_REF_LIST_EB(prev_frame_mvs->mv[1], refmv_count, mv_ref_list, Done);
    }
  }

  // Since we couldn't find 2 mvs from the same reference frame
  // go back through the neighbors and find motion vectors from
  // different reference frames.
  if (different_ref_found) {
    for (i = 0; i < MVREF_NEIGHBOURS; ++i) {
      const POSITION *mv_ref = &mv_ref_search[i];
      if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
        const MB_MODE_INFO *const candidate =
            &xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride]->mbmi;

        // If the candidate is INTRA we don't want to consider its mv.
        IF_DIFF_REF_FRAME_ADD_MV_EB(candidate, ref_frame, ref_sign_bias,
                                    refmv_count, mv_ref_list, Done);
      }
    }
  }

  // Since we still don't have a candidate we'll try the last frame.
  if (prev_frame_mvs) {
    if (prev_frame_mvs->ref_frame[0] != ref_frame &&
        prev_frame_mvs->ref_frame[0] > INTRA_FRAME) {
      int_mv mv = prev_frame_mvs->mv[0];
      if (ref_sign_bias[prev_frame_mvs->ref_frame[0]] !=
          ref_sign_bias[ref_frame]) {
        mv.as_mv.row *= -1;
        mv.as_mv.col *= -1;
      }
      ADD_MV_REF_LIST_EB(mv, refmv_count, mv_ref_list, Done);
    }

    if (prev_frame_mvs->ref_frame[1] > INTRA_FRAME &&
        prev_frame_mvs->ref_frame[1] != ref_frame &&
        prev_frame_mvs->mv[1].as_int != prev_frame_mvs->mv[0].as_int) {
      int_mv mv = prev_frame_mvs->mv[1];
      if (ref_sign_bias[prev_frame_mvs->ref_frame[1]] !=
          ref_sign_bias[ref_frame]) {
        mv.as_mv.row *= -1;
        mv.as_mv.col *= -1;
      }
      ADD_MV_REF_LIST_EB(mv, refmv_count, mv_ref_list, Done);
    }
  }

  if (mi->mbmi.mode == NEARMV)
    refmv_count = MAX_MV_REF_CANDIDATES;
  else
    // we only care about the nearestmv for the remaining modes
    refmv_count = 1;

 Done:
  // Clamp vectors
  for (i = 0; i < refmv_count; ++i)
    clamp_mv_ref(&mv_ref_list[i].as_mv, xd);

  return refmv_count;
}

static uint8_t get_mode_context(const VP9_COMMON *cm, const MACROBLOCKD *xd,
                                const POSITION *const mv_ref_search,
                                int mi_row, int mi_col) {
  int i;
  int context_counter = 0;
  const TileInfo *const tile = &xd->tile;

  // Get mode count from nearest 2 blocks
  for (i = 0; i < 2; ++i) {
    const POSITION *const mv_ref = &mv_ref_search[i];
    if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
      const MODE_INFO *const candidate_mi = xd->mi[mv_ref->col + mv_ref->row *
                                                   xd->mi_stride];
      const MB_MODE_INFO *const candidate = &candidate_mi->mbmi;
      // Keep counts for entropy encoding.
      context_counter += mode_2_counter[candidate->mode];
    }
  }

  return counter_to_context[context_counter];
}

683
static void read_inter_block_mode_info(VP9Decoder *const pbi,
684
685
                                       MACROBLOCKD *const xd,
                                       MODE_INFO *const mi,
Yaowu Xu's avatar
Yaowu Xu committed
686
                                       int mi_row, int mi_col, vpx_reader *r) {
687
  VP9_COMMON *const cm = &pbi->common;
688
  MB_MODE_INFO *const mbmi = &mi->mbmi;
689
  const BLOCK_SIZE bsize = mbmi->sb_type;
690
  const int allow_hp = cm->allow_high_precision_mv;
691
  int_mv nearestmv[2], nearmv[2];
692
  int ref, is_compound;
693
694
  uint8_t inter_mode_ctx;
  const POSITION *const mv_ref_search = mv_ref_blocks[bsize];
Dmitry Kovalev's avatar
Dmitry Kovalev committed
695

Scott LaVarnway's avatar
Scott LaVarnway committed
696
  read_ref_frames(cm, xd, r, mbmi->segment_id, mbmi->ref_frame);
697
  is_compound = has_second_ref(mbmi);
698
  inter_mode_ctx = get_mode_context(cm, xd, mv_ref_search, mi_row, mi_col);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
699

700
  if (segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) {
701
    mbmi->mode = ZEROMV;
702
    if (bsize < BLOCK_8X8) {
703
        vpx_internal_error(xd->error_info, VPX_CODEC_UNSUP_BITSTREAM,
704
705
706
                           "Invalid usage of segement feature on small blocks");
        return;
    }
707
708
  } else {
    if (bsize >= BLOCK_8X8)
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
      mbmi->mode = read_inter_mode(cm, xd, r, inter_mode_ctx);
    else
      // Sub 8x8 blocks use the nearestmv as a ref_mv if the b_mode is NEWMV.
      // Setting mode to NEARESTMV forces the search to stop after the nearestmv
      // has been found. After b_modes have been read, mode will be overwritten
      // by the last b_mode.
      mbmi->mode = NEARESTMV;

    if (mbmi->mode != ZEROMV) {
      for (ref = 0; ref < 1 + is_compound; ++ref) {
        int_mv ref_mvs[MAX_MV_REF_CANDIDATES];
        const MV_REFERENCE_FRAME frame = mbmi->ref_frame[ref];
        int refmv_count;

        refmv_count = dec_find_mv_refs(cm, xd, mi, frame, mv_ref_search,
                                       ref_mvs, mi_row, mi_col, fpm_sync,
                                       (void *)pbi);

        dec_find_best_ref_mvs(xd, allow_hp, ref_mvs, &nearestmv[ref],
                              &nearmv[ref], refmv_count);
      }
730
    }
731
  }
732

733
  mbmi->interp_filter = (cm->interp_filter == SWITCHABLE)
Scott LaVarnway's avatar
Scott LaVarnway committed
734
                      ? read_switchable_interp_filter(cm, xd, r)
735
                      : cm->interp_filter;
736

737
  if (bsize < BLOCK_8X8) {
738
739
    const int num_4x4_w = 1 << xd->bmode_blocks_wl;
    const int num_4x4_h = 1 << xd->bmode_blocks_hl;
740
    int idx, idy;
741
    PREDICTION_MODE b_mode;
742
    int_mv nearest_sub8x8[2], near_sub8x8[2];
Dmitry Kovalev's avatar
Dmitry Kovalev committed
743
744
    for (idy = 0; idy < 2; idy += num_4x4_h) {
      for (idx = 0; idx < 2; idx += num_4x4_w) {
745
        int_mv block[2];
746
        const int j = idy * 2 + idx;
747
        b_mode = read_inter_mode(cm, xd, r, inter_mode_ctx);
748

749
750
        if (b_mode == NEARESTMV || b_mode == NEARMV) {
          uint8_t dummy_mode_ctx[MAX_REF_FRAMES];
751
          for (ref = 0; ref < 1 + is_compound; ++ref)
Scott LaVarnway's avatar
Scott LaVarnway committed
752
            vp9_append_sub8x8_mvs_for_idx(cm, xd, j, ref, mi_row, mi_col,
753
                                          &nearest_sub8x8[ref],
754
755
756
                                          &near_sub8x8[ref],
                                          dummy_mode_ctx);
        }
757

Scott LaVarnway's avatar
Scott LaVarnway committed
758
        if (!assign_mv(cm, xd, b_mode, block, nearestmv,
759
                       nearest_sub8x8, near_sub8x8,
Yaowu Xu's avatar
Yaowu Xu committed
760
761
762
                       is_compound, allow_hp, r)) {
          xd->corrupted |= 1;
          break;
Jingning Han's avatar
Jingning Han committed
763
        }
Yaowu Xu's avatar
Yaowu Xu committed
764

765
766
        mi->bmi[j].as_mv[0].as_int = block[0].as_int;
        if (is_compound)
767
          mi->bmi[j].as_mv[1].as_int = block[1].as_int;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
768

Dmitry Kovalev's avatar
Dmitry Kovalev committed
769
        if (num_4x4_h == 2)
770
          mi->bmi[j + 2] = mi->bmi[j];
Dmitry Kovalev's avatar
Dmitry Kovalev committed
771
        if (num_4x4_w == 2)
772
          mi->bmi[j + 1] = mi->bmi[j];
Ronald S. Bultje's avatar
Ronald S. Bultje committed
773
      }
Scott LaVarnway's avatar
Scott LaVarnway committed
774
    }
775

776
    mi->mbmi.mode = b_mode;
777

778
779
780
    mbmi->mv[0].as_int = mi->bmi[3].as_mv[0].as_int;
    mbmi->mv[1].as_int = mi->bmi[3].as_mv[1].as_int;
  } else {
Scott LaVarnway's avatar
Scott LaVarnway committed
781
    xd->corrupted |= !assign_mv(cm, xd, mbmi->mode, mbmi->mv, nearestmv,
782
                                nearestmv, nearmv, is_compound, allow_hp, r);
John Koleszar's avatar
John Koleszar committed
783
  }
Scott LaVarnway's avatar
Scott LaVarnway committed
784
}
John Koleszar's avatar
John Koleszar committed
785

786
static void read_inter_frame_mode_info(VP9Decoder *const pbi,
787
                                       MACROBLOCKD *const xd,
Yaowu Xu's avatar
Yaowu Xu committed
788
                                       int mi_row, int mi_col, vpx_reader *r) {
789
  VP9_COMMON *const cm = &pbi->common;
790
  MODE_INFO *const mi = xd->mi[0];
791
  MB_MODE_INFO *const mbmi = &mi->mbmi;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
792
  int inter_block;
793

Dmitry Kovalev's avatar
Dmitry Kovalev committed
794
795
  mbmi->mv[0].as_int = 0;
  mbmi->mv[1].as_int = 0;
796
  mbmi->segment_id = read_inter_segment_id(cm, xd, mi_row, mi_col, r);
Scott LaVarnway's avatar
Scott LaVarnway committed
797
798
799
  mbmi->skip = read_skip(cm, xd, mbmi->segment_id, r);
  inter_block = read_is_inter_block(cm, xd, mbmi->segment_id, r);
  mbmi->tx_size = read_tx_size(cm, xd, !mbmi->skip || !inter_block, r);
800

Dmitry Kovalev's avatar
Dmitry Kovalev committed
801
  if (inter_block)
Scott LaVarnway's avatar
Scott LaVarnway committed
802
    read_inter_block_mode_info(pbi, xd, mi, mi_row, mi_col, r);
803
  else
Scott LaVarnway's avatar
Scott LaVarnway committed
804
    read_intra_block_mode_info(cm, xd, mi, r);
805
806
}

Yaowu Xu's avatar
Yaowu Xu committed
807
808
void vpx_read_mode_info(VP9Decoder *const pbi, MACROBLOCKD *xd,
                        int mi_row, int mi_col, vpx_reader *r,
809
                        int x_mis, int y_mis) {
810
  VP9_COMMON *const cm = &pbi->common;
811
  MODE_INFO *const mi = xd->mi[0];
812
813
814
  MV_REF* frame_mvs = cm->cur_frame->mvs + mi_row * cm->mi_cols + mi_col;
  int w, h;

815
  if (frame_is_intra_only(cm)) {
Scott LaVarnway's avatar
Scott LaVarnway committed
816
    read_intra_frame_mode_info(cm, xd, mi_row, mi_col, r);
817
  } else {
Scott LaVarnway's avatar
Scott LaVarnway committed
818
    read_inter_frame_mode_info(pbi, xd, mi_row, mi_col, r);
819

820
821
822
823
824
825
826
827
828
    for (h = 0; h < y_mis; ++h) {
      MV_REF *const frame_mv = frame_mvs + h * cm->mi_cols;
      for (w = 0; w < x_mis; ++w) {
        MV_REF *const mv = frame_mv + w;
        mv->ref_frame[0] = mi->mbmi.ref_frame[0];
        mv->ref_frame[1] = mi->mbmi.ref_frame[1];
        mv->mv[0].as_int = mi->mbmi.mv[0].as_int;
        mv->mv[1].as_int = mi->mbmi.mv[1].as_int;
      }
829
830
    }
  }
831
}