vp9_reconinter.c 17.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
 */

11
#include <assert.h>
John Koleszar's avatar
John Koleszar committed
12

13
#include "./vpx_scale_rtcd.h"
14
#include "./vpx_config.h"
15

16
#include "vpx/vpx_integer.h"
17

18
#include "vp9/common/vp9_blockd.h"
19
#include "vp9/common/vp9_filter.h"
20
#include "vp9/common/vp9_reconinter.h"
21
#include "vp9/common/vp9_reconintra.h"
22

23
24
25
static void build_mc_border(const uint8_t *src, int src_stride,
                            uint8_t *dst, int dst_stride,
                            int x, int y, int b_w, int b_h, int w, int h) {
26
  // Get a pointer to the start of the real data for this row.
27
  const uint8_t *ref_row = src - x - y * src_stride;
28
29

  if (y >= h)
30
    ref_row += (h - 1) * src_stride;
31
  else if (y > 0)
32
    ref_row += y * src_stride;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

  do {
    int right = 0, copy;
    int left = x < 0 ? -x : 0;

    if (left > b_w)
      left = b_w;

    if (x + b_w > w)
      right = x + b_w - w;

    if (right > b_w)
      right = b_w;

    copy = b_w - left - right;

    if (left)
      memset(dst, ref_row[0], left);

    if (copy)
53
      memcpy(dst + left, ref_row + x + left, copy);
54
55
56
57

    if (right)
      memset(dst + left + copy, ref_row[w - 1], right);

58
    dst += dst_stride;
59
60
61
    ++y;

    if (y > 0 && y < h)
62
      ref_row += src_stride;
63
64
  } while (--b_h);
}
65

Yunqing Wang's avatar
Yunqing Wang committed
66
67
static void inter_predictor(const uint8_t *src, int src_stride,
                            uint8_t *dst, int dst_stride,
hkuang's avatar
hkuang committed
68
69
                            const int subpel_x,
                            const int subpel_y,
70
                            const struct scale_factors *sf,
Yunqing Wang's avatar
Yunqing Wang committed
71
                            int w, int h, int ref,
72
                            const InterpKernel *kernel,
Yunqing Wang's avatar
Yunqing Wang committed
73
                            int xs, int ys) {
74
  sf->predict[subpel_x != 0][subpel_y != 0][ref](
Yunqing Wang's avatar
Yunqing Wang committed
75
      src, src_stride, dst, dst_stride,
76
      kernel[subpel_x], xs, kernel[subpel_y], ys, w, h);
Yunqing Wang's avatar
Yunqing Wang committed
77
78
}

79
80
void vp9_build_inter_predictor(const uint8_t *src, int src_stride,
                               uint8_t *dst, int dst_stride,
81
                               const MV *src_mv,
82
                               const struct scale_factors *sf,
83
                               int w, int h, int ref,
84
                               const InterpKernel *kernel,
85
86
                               enum mv_precision precision,
                               int x, int y) {
87
  const int is_q4 = precision == MV_PRECISION_Q4;
Yaowu Xu's avatar
Yaowu Xu committed
88
89
  const MV mv_q4 = { is_q4 ? src_mv->row : src_mv->row * 2,
                     is_q4 ? src_mv->col : src_mv->col * 2 };
90
91
92
  MV32 mv = vp9_scale_mv(&mv_q4, x, y, sf);
  const int subpel_x = mv.col & SUBPEL_MASK;
  const int subpel_y = mv.row & SUBPEL_MASK;
93

hkuang's avatar
hkuang committed
94
  src += (mv.row >> SUBPEL_BITS) * src_stride + (mv.col >> SUBPEL_BITS);
95

hkuang's avatar
hkuang committed
96
  inter_predictor(src, src_stride, dst, dst_stride, subpel_x, subpel_y,
97
                  sf, w, h, ref, kernel, sf->x_step_q4, sf->y_step_q4);
98
99
}

100
101
static INLINE int round_mv_comp_q4(int value) {
  return (value < 0 ? value - 2 : value + 2) / 4;
John Koleszar's avatar
John Koleszar committed
102
103
}

104
105
106
107
108
109
110
111
112
113
static MV mi_mv_pred_q4(const MODE_INFO *mi, int idx) {
  MV res = { round_mv_comp_q4(mi->bmi[0].as_mv[idx].as_mv.row +
                              mi->bmi[1].as_mv[idx].as_mv.row +
                              mi->bmi[2].as_mv[idx].as_mv.row +
                              mi->bmi[3].as_mv[idx].as_mv.row),
             round_mv_comp_q4(mi->bmi[0].as_mv[idx].as_mv.col +
                              mi->bmi[1].as_mv[idx].as_mv.col +
                              mi->bmi[2].as_mv[idx].as_mv.col +
                              mi->bmi[3].as_mv[idx].as_mv.col) };
  return res;
114
115
}

116
// TODO(jkoleszar): yet another mv clamping function :-(
117
118
MV clamp_mv_to_umv_border_sb(const MACROBLOCKD *xd, const MV *src_mv,
                             int bw, int bh, int ss_x, int ss_y) {
119
120
121
  // If the MV points so far into the UMV border that no visible pixels
  // are used for reconstruction, the subpel part of the MV can be
  // discarded and the MV limited to 16 pixels with equivalent results.
122
123
124
125
  const int spel_left = (VP9_INTERP_EXTEND + bw) << SUBPEL_BITS;
  const int spel_right = spel_left - SUBPEL_SHIFTS;
  const int spel_top = (VP9_INTERP_EXTEND + bh) << SUBPEL_BITS;
  const int spel_bottom = spel_top - SUBPEL_SHIFTS;
126
  MV clamped_mv = {
Yaowu Xu's avatar
Yaowu Xu committed
127
128
    src_mv->row * (1 << (1 - ss_y)),
    src_mv->col * (1 << (1 - ss_x))
129
  };
130
131
  assert(ss_x <= 1);
  assert(ss_y <= 1);
132

Yaowu Xu's avatar
Yaowu Xu committed
133
134
135
136
137
  clamp_mv(&clamped_mv,
           xd->mb_to_left_edge * (1 << (1 - ss_x)) - spel_left,
           xd->mb_to_right_edge * (1 << (1 - ss_x)) + spel_right,
           xd->mb_to_top_edge * (1 << (1 - ss_y)) - spel_top,
           xd->mb_to_bottom_edge * (1 << (1 - ss_y)) + spel_bottom);
138

139
140
141
  return clamped_mv;
}

142
static void build_inter_predictors(MACROBLOCKD *xd, int plane, int block,
143
144
                                   int bw, int bh,
                                   int x, int y, int w, int h,
145
                                   int mi_x, int mi_y) {
146
  struct macroblockd_plane *const pd = &xd->plane[plane];
147
  const MODE_INFO *mi = xd->mi_8x8[0];
148
  const int is_compound = has_second_ref(&mi->mbmi);
149
  int ref;
150

151
  for (ref = 0; ref < 1 + is_compound; ++ref) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
152
    const struct scale_factors *const sf = &xd->block_refs[ref]->sf;
153
154
    struct buf_2d *const pre_buf = &pd->pre[ref];
    struct buf_2d *const dst_buf = &pd->dst;
155
    uint8_t *const dst = dst_buf->buf + dst_buf->stride * y + x;
156

157
158
159
160
    // TODO(jkoleszar): All chroma MVs in SPLITMV mode are taken as the
    // same MV (the average of the 4 luma MVs) but we could do something
    // smarter for non-4:2:0. Just punt for now, pending the changes to get
    // rid of SPLITMV mode entirely.
161
    const MV mv = mi->mbmi.sb_type < BLOCK_8X8
162
163
164
               ? (plane == 0 ? mi->bmi[block].as_mv[ref].as_mv
                             : mi_mv_pred_q4(mi, ref))
               : mi->mbmi.mv[ref].as_mv;
165
166
167
168
169

    // TODO(jkoleszar): This clamping is done in the incorrect place for the
    // scaling case. It needs to be done on the scaled MV, not the pre-scaling
    // MV. Note however that it performs the subsampling aware scaling so
    // that the result is always q4.
170
171
172
173
    // mv_precision precision is MV_PRECISION_Q4.
    const MV mv_q4 = clamp_mv_to_umv_border_sb(xd, &mv, bw, bh,
                                               pd->subsampling_x,
                                               pd->subsampling_y);
174

Yunqing Wang's avatar
Yunqing Wang committed
175
176
    uint8_t *pre;
    MV32 scaled_mv;
hkuang's avatar
hkuang committed
177
    int xs, ys, subpel_x, subpel_y;
Yunqing Wang's avatar
Yunqing Wang committed
178

179
180
181
182
183
    if (vp9_is_scaled(sf)) {
      pre = pre_buf->buf + scaled_buffer_offset(x, y, pre_buf->stride, sf);
      scaled_mv = vp9_scale_mv(&mv_q4, mi_x + x, mi_y + y, sf);
      xs = sf->x_step_q4;
      ys = sf->y_step_q4;
Yunqing Wang's avatar
Yunqing Wang committed
184
185
186
187
188
189
    } else {
      pre = pre_buf->buf + (y * pre_buf->stride + x);
      scaled_mv.row = mv_q4.row;
      scaled_mv.col = mv_q4.col;
      xs = ys = 16;
    }
hkuang's avatar
hkuang committed
190
191
192
193
    subpel_x = scaled_mv.col & SUBPEL_MASK;
    subpel_y = scaled_mv.row & SUBPEL_MASK;
    pre += (scaled_mv.row >> SUBPEL_BITS) * pre_buf->stride
           + (scaled_mv.col >> SUBPEL_BITS);
Yunqing Wang's avatar
Yunqing Wang committed
194
195

    inter_predictor(pre, pre_buf->stride, dst, dst_buf->stride,
196
197
                    subpel_x, subpel_y, sf, w, h, ref, xd->interp_kernel,
                    xs, ys);
198
199
  }
}
200

201
static void build_inter_predictors_for_planes(MACROBLOCKD *xd, BLOCK_SIZE bsize,
202
203
204
                                              int mi_row, int mi_col,
                                              int plane_from, int plane_to) {
  int plane;
205
206
  const int mi_x = mi_col * MI_SIZE;
  const int mi_y = mi_row * MI_SIZE;
207
  for (plane = plane_from; plane <= plane_to; ++plane) {
208
209
210
211
212
213
    const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize,
                                                        &xd->plane[plane]);
    const int num_4x4_w = num_4x4_blocks_wide_lookup[plane_bsize];
    const int num_4x4_h = num_4x4_blocks_high_lookup[plane_bsize];
    const int bw = 4 * num_4x4_w;
    const int bh = 4 * num_4x4_h;
214
215
216
217

    if (xd->mi_8x8[0]->mbmi.sb_type < BLOCK_8X8) {
      int i = 0, x, y;
      assert(bsize == BLOCK_8X8);
218
219
220
221
      for (y = 0; y < num_4x4_h; ++y)
        for (x = 0; x < num_4x4_w; ++x)
           build_inter_predictors(xd, plane, i++, bw, bh,
                                  4 * x, 4 * y, 4, 4, mi_x, mi_y);
222
    } else {
223
224
      build_inter_predictors(xd, plane, 0, bw, bh,
                             0, 0, bw, bh, mi_x, mi_y);
225
    }
226
227
228
  }
}

229
void vp9_build_inter_predictors_sby(MACROBLOCKD *xd, int mi_row, int mi_col,
230
                                    BLOCK_SIZE bsize) {
231
  build_inter_predictors_for_planes(xd, bsize, mi_row, mi_col, 0, 0);
232
}
233
void vp9_build_inter_predictors_sbuv(MACROBLOCKD *xd, int mi_row, int mi_col,
234
                                     BLOCK_SIZE bsize) {
235
236
  build_inter_predictors_for_planes(xd, bsize, mi_row, mi_col, 1,
                                    MAX_MB_PLANE - 1);
237
}
238
void vp9_build_inter_predictors_sb(MACROBLOCKD *xd, int mi_row, int mi_col,
239
                                   BLOCK_SIZE bsize) {
240
241
  build_inter_predictors_for_planes(xd, bsize, mi_row, mi_col, 0,
                                    MAX_MB_PLANE - 1);
242
}
243

244
245
246
// TODO(jingning): This function serves as a placeholder for decoder prediction
// using on demand border extension. It should be moved to /decoder/ directory.
static void dec_build_inter_predictors(MACROBLOCKD *xd, int plane, int block,
247
                                       int bw, int bh,
248
                                       int x, int y, int w, int h,
249
250
251
252
253
254
255
                                       int mi_x, int mi_y) {
  struct macroblockd_plane *const pd = &xd->plane[plane];
  const MODE_INFO *mi = xd->mi_8x8[0];
  const int is_compound = has_second_ref(&mi->mbmi);
  int ref;

  for (ref = 0; ref < 1 + is_compound; ++ref) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
256
    const struct scale_factors *const sf = &xd->block_refs[ref]->sf;
257
258
259
260
261
262
263
264
265
266
267
268
    struct buf_2d *const pre_buf = &pd->pre[ref];
    struct buf_2d *const dst_buf = &pd->dst;
    uint8_t *const dst = dst_buf->buf + dst_buf->stride * y + x;

    // TODO(jkoleszar): All chroma MVs in SPLITMV mode are taken as the
    // same MV (the average of the 4 luma MVs) but we could do something
    // smarter for non-4:2:0. Just punt for now, pending the changes to get
    // rid of SPLITMV mode entirely.
    const MV mv = mi->mbmi.sb_type < BLOCK_8X8
               ? (plane == 0 ? mi->bmi[block].as_mv[ref].as_mv
                             : mi_mv_pred_q4(mi, ref))
               : mi->mbmi.mv[ref].as_mv;
269
270
271
272
273
274
275
276
277
278

    // TODO(jkoleszar): This clamping is done in the incorrect place for the
    // scaling case. It needs to be done on the scaled MV, not the pre-scaling
    // MV. Note however that it performs the subsampling aware scaling so
    // that the result is always q4.
    // mv_precision precision is MV_PRECISION_Q4.
    const MV mv_q4 = clamp_mv_to_umv_border_sb(xd, &mv, bw, bh,
                                               pd->subsampling_x,
                                               pd->subsampling_y);

279
    MV32 scaled_mv;
280
281
    int xs, ys, x0, y0, x0_16, y0_16, frame_width, frame_height, buf_stride,
        subpel_x, subpel_y;
hkuang's avatar
hkuang committed
282
    uint8_t *ref_frame, *buf_ptr;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
283
    const YV12_BUFFER_CONFIG *ref_buf = xd->block_refs[ref]->buf;
284
285
286
287
288
289
290
291
292
293
294
295

    // Get reference frame pointer, width and height.
    if (plane == 0) {
      frame_width = ref_buf->y_crop_width;
      frame_height = ref_buf->y_crop_height;
      ref_frame = ref_buf->y_buffer;
    } else {
      frame_width = ref_buf->uv_crop_width;
      frame_height = ref_buf->uv_crop_height;
      ref_frame = plane == 1 ? ref_buf->u_buffer : ref_buf->v_buffer;
    }

296
297
298
299
    if (vp9_is_scaled(sf)) {
      // Co-ordinate of containing block to pixel precision.
      int x_start = (-xd->mb_to_left_edge >> (3 + pd->subsampling_x));
      int y_start = (-xd->mb_to_top_edge >> (3 + pd->subsampling_y));
300

301
302
303
      // Co-ordinate of the block to 1/16th pixel precision.
      x0_16 = (x_start + x) << SUBPEL_BITS;
      y0_16 = (y_start + y) << SUBPEL_BITS;
304

305
306
307
308
309
310
311
312
313
314
315
316
317
      // Co-ordinate of current block in reference frame
      // to 1/16th pixel precision.
      x0_16 = sf->scale_value_x(x0_16, sf);
      y0_16 = sf->scale_value_y(y0_16, sf);

      // Map the top left corner of the block into the reference frame.
      // NOTE: This must be done in this way instead of
      // sf->scale_value_x(x_start + x, sf).
      x0 = sf->scale_value_x(x_start, sf) + sf->scale_value_x(x, sf);
      y0 = sf->scale_value_y(y_start, sf) + sf->scale_value_y(y, sf);

      // Scale the MV and incorporate the sub-pixel offset of the block
      // in the reference frame.
318
319
320
      scaled_mv = vp9_scale_mv(&mv_q4, mi_x + x, mi_y + y, sf);
      xs = sf->x_step_q4;
      ys = sf->y_step_q4;
321
    } else {
322
323
324
325
326
327
328
329
      // Co-ordinate of containing block to pixel precision.
      x0 = (-xd->mb_to_left_edge >> (3 + pd->subsampling_x)) + x;
      y0 = (-xd->mb_to_top_edge >> (3 + pd->subsampling_y)) + y;

      // Co-ordinate of the block to 1/16th pixel precision.
      x0_16 = x0 << SUBPEL_BITS;
      y0_16 = y0 << SUBPEL_BITS;

330
331
332
333
      scaled_mv.row = mv_q4.row;
      scaled_mv.col = mv_q4.col;
      xs = ys = 16;
    }
hkuang's avatar
hkuang committed
334
335
    subpel_x = scaled_mv.col & SUBPEL_MASK;
    subpel_y = scaled_mv.row & SUBPEL_MASK;
336

337
    // Calculate the top left corner of the best matching block in the reference frame.
338
339
340
341
342
    x0 += scaled_mv.col >> SUBPEL_BITS;
    y0 += scaled_mv.row >> SUBPEL_BITS;
    x0_16 += scaled_mv.col;
    y0_16 += scaled_mv.row;

hkuang's avatar
hkuang committed
343
344
    // Get reference block pointer.
    buf_ptr = ref_frame + y0 * pre_buf->stride + x0;
345
    buf_stride = pre_buf->stride;
hkuang's avatar
hkuang committed
346

347
    // Do border extension if there is motion or the
348
349
350
    // width/height is not a multiple of 8 pixels.
    if (scaled_mv.col || scaled_mv.row ||
        (frame_width & 0x7) || (frame_height & 0x7)) {
351
352
353
      // Get reference block bottom right coordinate.
      int x1 = ((x0_16 + (w - 1) * xs) >> SUBPEL_BITS) + 1;
      int y1 = ((y0_16 + (h - 1) * ys) >> SUBPEL_BITS) + 1;
354
      int x_pad = 0, y_pad = 0;
355

356
      if (subpel_x || (sf->x_step_q4 & SUBPEL_MASK)) {
357
358
        x0 -= VP9_INTERP_EXTEND - 1;
        x1 += VP9_INTERP_EXTEND;
359
        x_pad = 1;
360
361
      }

362
      if (subpel_y || (sf->y_step_q4 & SUBPEL_MASK)) {
363
364
        y0 -= VP9_INTERP_EXTEND - 1;
        y1 += VP9_INTERP_EXTEND;
365
        y_pad = 1;
366
367
368
369
370
      }

      // Skip border extension if block is inside the frame.
      if (x0 < 0 || x0 > frame_width - 1 || x1 < 0 || x1 > frame_width ||
          y0 < 0 || y0 > frame_height - 1 || y1 < 0 || y1 > frame_height - 1) {
hkuang's avatar
hkuang committed
371
        uint8_t *buf_ptr1 = ref_frame + y0 * pre_buf->stride + x0;
372
        // Extend the border.
373
374
375
376
        build_mc_border(buf_ptr1, pre_buf->stride, xd->mc_buf, x1 - x0 + 1,
                        x0, y0, x1 - x0 + 1, y1 - y0 + 1, frame_width,
                        frame_height);
        buf_stride = x1 - x0 + 1;
377
        buf_ptr = xd->mc_buf + y_pad * 3 * buf_stride + x_pad * 3;
378
379
380
      }
    }

381
    inter_predictor(buf_ptr, buf_stride, dst, dst_buf->stride, subpel_x,
382
                    subpel_y, sf, w, h, ref, xd->interp_kernel, xs, ys);
383
384
385
386
387
388
  }
}

void vp9_dec_build_inter_predictors_sb(MACROBLOCKD *xd, int mi_row, int mi_col,
                                       BLOCK_SIZE bsize) {
  int plane;
389
390
  const int mi_x = mi_col * MI_SIZE;
  const int mi_y = mi_row * MI_SIZE;
391
  for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
392
393
394
395
396
397
    const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize,
                                                        &xd->plane[plane]);
    const int num_4x4_w = num_4x4_blocks_wide_lookup[plane_bsize];
    const int num_4x4_h = num_4x4_blocks_high_lookup[plane_bsize];
    const int bw = 4 * num_4x4_w;
    const int bh = 4 * num_4x4_h;
398
399
400
401

    if (xd->mi_8x8[0]->mbmi.sb_type < BLOCK_8X8) {
      int i = 0, x, y;
      assert(bsize == BLOCK_8X8);
402
403
      for (y = 0; y < num_4x4_h; ++y)
        for (x = 0; x < num_4x4_w; ++x)
404
          dec_build_inter_predictors(xd, plane, i++, bw, bh,
405
                                     4 * x, 4 * y, 4, 4, mi_x, mi_y);
406
    } else {
407
      dec_build_inter_predictors(xd, plane, 0, bw, bh,
408
                                 0, 0, bw, bh, mi_x, mi_y);
409
410
411
    }
  }
}
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446

void vp9_setup_dst_planes(MACROBLOCKD *xd,
                          const YV12_BUFFER_CONFIG *src,
                          int mi_row, int mi_col) {
  uint8_t *const buffers[4] = {src->y_buffer, src->u_buffer, src->v_buffer,
                               src->alpha_buffer};
  const int strides[4] = {src->y_stride, src->uv_stride, src->uv_stride,
                          src->alpha_stride};
  int i;

  for (i = 0; i < MAX_MB_PLANE; ++i) {
    struct macroblockd_plane *const pd = &xd->plane[i];
    setup_pred_plane(&pd->dst, buffers[i], strides[i], mi_row, mi_col, NULL,
                     pd->subsampling_x, pd->subsampling_y);
  }
}

void vp9_setup_pre_planes(MACROBLOCKD *xd, int idx,
                          const YV12_BUFFER_CONFIG *src,
                          int mi_row, int mi_col,
                          const struct scale_factors *sf) {
  if (src != NULL) {
    int i;
    uint8_t *const buffers[4] = {src->y_buffer, src->u_buffer, src->v_buffer,
                                 src->alpha_buffer};
    const int strides[4] = {src->y_stride, src->uv_stride, src->uv_stride,
                            src->alpha_stride};

    for (i = 0; i < MAX_MB_PLANE; ++i) {
      struct macroblockd_plane *const pd = &xd->plane[i];
      setup_pred_plane(&pd->pre[idx], buffers[i], strides[i], mi_row, mi_col,
                       sf, pd->subsampling_x, pd->subsampling_y);
    }
  }
}