Line data Source code
1 : /*
2 : * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3 : *
4 : * Use of this source code is governed by a BSD-style license
5 : * that can be found in the LICENSE file in the root of the source
6 : * 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.
9 : */
10 :
11 : #include <assert.h>
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_reconinter.h"
20 : #include "vp9/common/vp9_reconintra.h"
21 :
22 : #if CONFIG_VP9_HIGHBITDEPTH
23 : void vp9_highbd_build_inter_predictor(
24 : const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride,
25 : const MV *src_mv, const struct scale_factors *sf, int w, int h, int ref,
26 : const InterpKernel *kernel, enum mv_precision precision, int x, int y,
27 : int bd) {
28 : const int is_q4 = precision == MV_PRECISION_Q4;
29 : const MV mv_q4 = { is_q4 ? src_mv->row : src_mv->row * 2,
30 : is_q4 ? src_mv->col : src_mv->col * 2 };
31 : MV32 mv = vp9_scale_mv(&mv_q4, x, y, sf);
32 : const int subpel_x = mv.col & SUBPEL_MASK;
33 : const int subpel_y = mv.row & SUBPEL_MASK;
34 :
35 : src += (mv.row >> SUBPEL_BITS) * src_stride + (mv.col >> SUBPEL_BITS);
36 :
37 : highbd_inter_predictor(src, src_stride, dst, dst_stride, subpel_x, subpel_y,
38 : sf, w, h, ref, kernel, sf->x_step_q4, sf->y_step_q4,
39 : bd);
40 : }
41 : #endif // CONFIG_VP9_HIGHBITDEPTH
42 :
43 0 : void vp9_build_inter_predictor(const uint8_t *src, int src_stride, uint8_t *dst,
44 : int dst_stride, const MV *src_mv,
45 : const struct scale_factors *sf, int w, int h,
46 : int ref, const InterpKernel *kernel,
47 : enum mv_precision precision, int x, int y) {
48 0 : const int is_q4 = precision == MV_PRECISION_Q4;
49 0 : const MV mv_q4 = { is_q4 ? src_mv->row : src_mv->row * 2,
50 0 : is_q4 ? src_mv->col : src_mv->col * 2 };
51 0 : MV32 mv = vp9_scale_mv(&mv_q4, x, y, sf);
52 0 : const int subpel_x = mv.col & SUBPEL_MASK;
53 0 : const int subpel_y = mv.row & SUBPEL_MASK;
54 :
55 0 : src += (mv.row >> SUBPEL_BITS) * src_stride + (mv.col >> SUBPEL_BITS);
56 :
57 0 : inter_predictor(src, src_stride, dst, dst_stride, subpel_x, subpel_y, sf, w,
58 : h, ref, kernel, sf->x_step_q4, sf->y_step_q4);
59 0 : }
60 :
61 0 : static INLINE int round_mv_comp_q4(int value) {
62 0 : return (value < 0 ? value - 2 : value + 2) / 4;
63 : }
64 :
65 0 : static MV mi_mv_pred_q4(const MODE_INFO *mi, int idx) {
66 0 : MV res = {
67 0 : round_mv_comp_q4(
68 0 : mi->bmi[0].as_mv[idx].as_mv.row + mi->bmi[1].as_mv[idx].as_mv.row +
69 0 : mi->bmi[2].as_mv[idx].as_mv.row + mi->bmi[3].as_mv[idx].as_mv.row),
70 0 : round_mv_comp_q4(
71 0 : mi->bmi[0].as_mv[idx].as_mv.col + mi->bmi[1].as_mv[idx].as_mv.col +
72 0 : mi->bmi[2].as_mv[idx].as_mv.col + mi->bmi[3].as_mv[idx].as_mv.col)
73 : };
74 0 : return res;
75 : }
76 :
77 0 : static INLINE int round_mv_comp_q2(int value) {
78 0 : return (value < 0 ? value - 1 : value + 1) / 2;
79 : }
80 :
81 0 : static MV mi_mv_pred_q2(const MODE_INFO *mi, int idx, int block0, int block1) {
82 0 : MV res = { round_mv_comp_q2(mi->bmi[block0].as_mv[idx].as_mv.row +
83 0 : mi->bmi[block1].as_mv[idx].as_mv.row),
84 0 : round_mv_comp_q2(mi->bmi[block0].as_mv[idx].as_mv.col +
85 0 : mi->bmi[block1].as_mv[idx].as_mv.col) };
86 0 : return res;
87 : }
88 :
89 : // TODO(jkoleszar): yet another mv clamping function :-(
90 0 : MV clamp_mv_to_umv_border_sb(const MACROBLOCKD *xd, const MV *src_mv, int bw,
91 : int bh, int ss_x, int ss_y) {
92 : // If the MV points so far into the UMV border that no visible pixels
93 : // are used for reconstruction, the subpel part of the MV can be
94 : // discarded and the MV limited to 16 pixels with equivalent results.
95 0 : const int spel_left = (VP9_INTERP_EXTEND + bw) << SUBPEL_BITS;
96 0 : const int spel_right = spel_left - SUBPEL_SHIFTS;
97 0 : const int spel_top = (VP9_INTERP_EXTEND + bh) << SUBPEL_BITS;
98 0 : const int spel_bottom = spel_top - SUBPEL_SHIFTS;
99 0 : MV clamped_mv = { src_mv->row * (1 << (1 - ss_y)),
100 0 : src_mv->col * (1 << (1 - ss_x)) };
101 0 : assert(ss_x <= 1);
102 0 : assert(ss_y <= 1);
103 :
104 0 : clamp_mv(&clamped_mv, xd->mb_to_left_edge * (1 << (1 - ss_x)) - spel_left,
105 0 : xd->mb_to_right_edge * (1 << (1 - ss_x)) + spel_right,
106 0 : xd->mb_to_top_edge * (1 << (1 - ss_y)) - spel_top,
107 0 : xd->mb_to_bottom_edge * (1 << (1 - ss_y)) + spel_bottom);
108 :
109 0 : return clamped_mv;
110 : }
111 :
112 0 : MV average_split_mvs(const struct macroblockd_plane *pd, const MODE_INFO *mi,
113 : int ref, int block) {
114 0 : const int ss_idx = ((pd->subsampling_x > 0) << 1) | (pd->subsampling_y > 0);
115 0 : MV res = { 0, 0 };
116 0 : switch (ss_idx) {
117 0 : case 0: res = mi->bmi[block].as_mv[ref].as_mv; break;
118 0 : case 1: res = mi_mv_pred_q2(mi, ref, block, block + 2); break;
119 0 : case 2: res = mi_mv_pred_q2(mi, ref, block, block + 1); break;
120 0 : case 3: res = mi_mv_pred_q4(mi, ref); break;
121 0 : default: assert(ss_idx <= 3 && ss_idx >= 0);
122 : }
123 0 : return res;
124 : }
125 :
126 0 : static void build_inter_predictors(MACROBLOCKD *xd, int plane, int block,
127 : int bw, int bh, int x, int y, int w, int h,
128 : int mi_x, int mi_y) {
129 0 : struct macroblockd_plane *const pd = &xd->plane[plane];
130 0 : const MODE_INFO *mi = xd->mi[0];
131 0 : const int is_compound = has_second_ref(mi);
132 0 : const InterpKernel *kernel = vp9_filter_kernels[mi->interp_filter];
133 : int ref;
134 :
135 0 : for (ref = 0; ref < 1 + is_compound; ++ref) {
136 0 : const struct scale_factors *const sf = &xd->block_refs[ref]->sf;
137 0 : struct buf_2d *const pre_buf = &pd->pre[ref];
138 0 : struct buf_2d *const dst_buf = &pd->dst;
139 0 : uint8_t *const dst = dst_buf->buf + dst_buf->stride * y + x;
140 0 : const MV mv = mi->sb_type < BLOCK_8X8
141 : ? average_split_mvs(pd, mi, ref, block)
142 : : mi->mv[ref].as_mv;
143 :
144 : // TODO(jkoleszar): This clamping is done in the incorrect place for the
145 : // scaling case. It needs to be done on the scaled MV, not the pre-scaling
146 : // MV. Note however that it performs the subsampling aware scaling so
147 : // that the result is always q4.
148 : // mv_precision precision is MV_PRECISION_Q4.
149 0 : const MV mv_q4 = clamp_mv_to_umv_border_sb(
150 : xd, &mv, bw, bh, pd->subsampling_x, pd->subsampling_y);
151 :
152 : uint8_t *pre;
153 : MV32 scaled_mv;
154 : int xs, ys, subpel_x, subpel_y;
155 0 : const int is_scaled = vp9_is_scaled(sf);
156 :
157 0 : if (is_scaled) {
158 : // Co-ordinate of containing block to pixel precision.
159 0 : const int x_start = (-xd->mb_to_left_edge >> (3 + pd->subsampling_x));
160 0 : const int y_start = (-xd->mb_to_top_edge >> (3 + pd->subsampling_y));
161 : #if 0 // CONFIG_BETTER_HW_COMPATIBILITY
162 : assert(xd->mi[0]->sb_type != BLOCK_4X8 &&
163 : xd->mi[0]->sb_type != BLOCK_8X4);
164 : assert(mv_q4.row == mv.row * (1 << (1 - pd->subsampling_y)) &&
165 : mv_q4.col == mv.col * (1 << (1 - pd->subsampling_x)));
166 : #endif
167 0 : if (plane == 0)
168 0 : pre_buf->buf = xd->block_refs[ref]->buf->y_buffer;
169 0 : else if (plane == 1)
170 0 : pre_buf->buf = xd->block_refs[ref]->buf->u_buffer;
171 : else
172 0 : pre_buf->buf = xd->block_refs[ref]->buf->v_buffer;
173 :
174 0 : pre_buf->buf +=
175 0 : scaled_buffer_offset(x_start + x, y_start + y, pre_buf->stride, sf);
176 0 : pre = pre_buf->buf;
177 0 : scaled_mv = vp9_scale_mv(&mv_q4, mi_x + x, mi_y + y, sf);
178 0 : xs = sf->x_step_q4;
179 0 : ys = sf->y_step_q4;
180 : } else {
181 0 : pre = pre_buf->buf + (y * pre_buf->stride + x);
182 0 : scaled_mv.row = mv_q4.row;
183 0 : scaled_mv.col = mv_q4.col;
184 0 : xs = ys = 16;
185 : }
186 0 : subpel_x = scaled_mv.col & SUBPEL_MASK;
187 0 : subpel_y = scaled_mv.row & SUBPEL_MASK;
188 0 : pre += (scaled_mv.row >> SUBPEL_BITS) * pre_buf->stride +
189 0 : (scaled_mv.col >> SUBPEL_BITS);
190 :
191 : #if CONFIG_VP9_HIGHBITDEPTH
192 : if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
193 : highbd_inter_predictor(pre, pre_buf->stride, dst, dst_buf->stride,
194 : subpel_x, subpel_y, sf, w, h, ref, kernel, xs, ys,
195 : xd->bd);
196 : } else {
197 : inter_predictor(pre, pre_buf->stride, dst, dst_buf->stride, subpel_x,
198 : subpel_y, sf, w, h, ref, kernel, xs, ys);
199 : }
200 : #else
201 0 : inter_predictor(pre, pre_buf->stride, dst, dst_buf->stride, subpel_x,
202 : subpel_y, sf, w, h, ref, kernel, xs, ys);
203 : #endif // CONFIG_VP9_HIGHBITDEPTH
204 : }
205 0 : }
206 :
207 0 : static void build_inter_predictors_for_planes(MACROBLOCKD *xd, BLOCK_SIZE bsize,
208 : int mi_row, int mi_col,
209 : int plane_from, int plane_to) {
210 : int plane;
211 0 : const int mi_x = mi_col * MI_SIZE;
212 0 : const int mi_y = mi_row * MI_SIZE;
213 0 : for (plane = plane_from; plane <= plane_to; ++plane) {
214 0 : const BLOCK_SIZE plane_bsize =
215 0 : get_plane_block_size(bsize, &xd->plane[plane]);
216 0 : const int num_4x4_w = num_4x4_blocks_wide_lookup[plane_bsize];
217 0 : const int num_4x4_h = num_4x4_blocks_high_lookup[plane_bsize];
218 0 : const int bw = 4 * num_4x4_w;
219 0 : const int bh = 4 * num_4x4_h;
220 :
221 0 : if (xd->mi[0]->sb_type < BLOCK_8X8) {
222 0 : int i = 0, x, y;
223 0 : assert(bsize == BLOCK_8X8);
224 0 : for (y = 0; y < num_4x4_h; ++y)
225 0 : for (x = 0; x < num_4x4_w; ++x)
226 0 : build_inter_predictors(xd, plane, i++, bw, bh, 4 * x, 4 * y, 4, 4,
227 : mi_x, mi_y);
228 : } else {
229 0 : build_inter_predictors(xd, plane, 0, bw, bh, 0, 0, bw, bh, mi_x, mi_y);
230 : }
231 : }
232 0 : }
233 :
234 0 : void vp9_build_inter_predictors_sby(MACROBLOCKD *xd, int mi_row, int mi_col,
235 : BLOCK_SIZE bsize) {
236 0 : build_inter_predictors_for_planes(xd, bsize, mi_row, mi_col, 0, 0);
237 0 : }
238 :
239 0 : void vp9_build_inter_predictors_sbp(MACROBLOCKD *xd, int mi_row, int mi_col,
240 : BLOCK_SIZE bsize, int plane) {
241 0 : build_inter_predictors_for_planes(xd, bsize, mi_row, mi_col, plane, plane);
242 0 : }
243 :
244 0 : void vp9_build_inter_predictors_sbuv(MACROBLOCKD *xd, int mi_row, int mi_col,
245 : BLOCK_SIZE bsize) {
246 0 : build_inter_predictors_for_planes(xd, bsize, mi_row, mi_col, 1,
247 : MAX_MB_PLANE - 1);
248 0 : }
249 :
250 0 : void vp9_build_inter_predictors_sb(MACROBLOCKD *xd, int mi_row, int mi_col,
251 : BLOCK_SIZE bsize) {
252 0 : build_inter_predictors_for_planes(xd, bsize, mi_row, mi_col, 0,
253 : MAX_MB_PLANE - 1);
254 0 : }
255 :
256 0 : void vp9_setup_dst_planes(struct macroblockd_plane planes[MAX_MB_PLANE],
257 : const YV12_BUFFER_CONFIG *src, int mi_row,
258 : int mi_col) {
259 0 : uint8_t *const buffers[MAX_MB_PLANE] = { src->y_buffer, src->u_buffer,
260 0 : src->v_buffer };
261 0 : const int strides[MAX_MB_PLANE] = { src->y_stride, src->uv_stride,
262 0 : src->uv_stride };
263 : int i;
264 :
265 0 : for (i = 0; i < MAX_MB_PLANE; ++i) {
266 0 : struct macroblockd_plane *const pd = &planes[i];
267 0 : setup_pred_plane(&pd->dst, buffers[i], strides[i], mi_row, mi_col, NULL,
268 : pd->subsampling_x, pd->subsampling_y);
269 : }
270 0 : }
271 :
272 0 : void vp9_setup_pre_planes(MACROBLOCKD *xd, int idx,
273 : const YV12_BUFFER_CONFIG *src, int mi_row, int mi_col,
274 : const struct scale_factors *sf) {
275 0 : if (src != NULL) {
276 : int i;
277 0 : uint8_t *const buffers[MAX_MB_PLANE] = { src->y_buffer, src->u_buffer,
278 0 : src->v_buffer };
279 0 : const int strides[MAX_MB_PLANE] = { src->y_stride, src->uv_stride,
280 0 : src->uv_stride };
281 0 : for (i = 0; i < MAX_MB_PLANE; ++i) {
282 0 : struct macroblockd_plane *const pd = &xd->plane[i];
283 0 : setup_pred_plane(&pd->pre[idx], buffers[i], strides[i], mi_row, mi_col,
284 : sf, pd->subsampling_x, pd->subsampling_y);
285 : }
286 : }
287 0 : }
|