/src/libvpx/vp9/common/vp9_scale.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2013 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 "./vpx_dsp_rtcd.h" |
12 | | #include "vp9/common/vp9_filter.h" |
13 | | #include "vp9/common/vp9_scale.h" |
14 | | #include "vpx_dsp/vpx_filter.h" |
15 | | |
16 | 337M | static INLINE int scaled_x(int val, const struct scale_factors *sf) { |
17 | 337M | return (int)((int64_t)val * sf->x_scale_fp >> REF_SCALE_SHIFT); |
18 | 337M | } |
19 | | |
20 | 337M | static INLINE int scaled_y(int val, const struct scale_factors *sf) { |
21 | 337M | return (int)((int64_t)val * sf->y_scale_fp >> REF_SCALE_SHIFT); |
22 | 337M | } |
23 | | |
24 | 93.9M | static int unscaled_value(int val, const struct scale_factors *sf) { |
25 | 93.9M | (void)sf; |
26 | 93.9M | return val; |
27 | 93.9M | } |
28 | | |
29 | 242k | static int get_fixed_point_scale_factor(int other_size, int this_size) { |
30 | | // Calculate scaling factor once for each reference frame |
31 | | // and use fixed point scaling factors in decoding and encoding routines. |
32 | | // Hardware implementations can calculate scale factor in device driver |
33 | | // and use multiplication and shifting on hardware instead of division. |
34 | 242k | return (other_size << REF_SCALE_SHIFT) / this_size; |
35 | 242k | } |
36 | | |
37 | 168M | MV32 vp9_scale_mv(const MV *mv, int x, int y, const struct scale_factors *sf) { |
38 | 168M | const int x_off_q4 = scaled_x(x << SUBPEL_BITS, sf) & SUBPEL_MASK; |
39 | 168M | const int y_off_q4 = scaled_y(y << SUBPEL_BITS, sf) & SUBPEL_MASK; |
40 | 168M | const MV32 res = { scaled_y(mv->row, sf) + y_off_q4, |
41 | 168M | scaled_x(mv->col, sf) + x_off_q4 }; |
42 | 168M | return res; |
43 | 168M | } |
44 | | |
45 | | #if CONFIG_VP9_HIGHBITDEPTH |
46 | | void vp9_setup_scale_factors_for_frame(struct scale_factors *sf, int other_w, |
47 | | int other_h, int this_w, int this_h, |
48 | 121k | int use_highbd) { |
49 | | #else |
50 | | void vp9_setup_scale_factors_for_frame(struct scale_factors *sf, int other_w, |
51 | | int other_h, int this_w, int this_h) { |
52 | | #endif |
53 | 121k | if (!valid_ref_frame_size(other_w, other_h, this_w, this_h)) { |
54 | 0 | sf->x_scale_fp = REF_INVALID_SCALE; |
55 | 0 | sf->y_scale_fp = REF_INVALID_SCALE; |
56 | 0 | return; |
57 | 0 | } |
58 | | |
59 | 121k | sf->x_scale_fp = get_fixed_point_scale_factor(other_w, this_w); |
60 | 121k | sf->y_scale_fp = get_fixed_point_scale_factor(other_h, this_h); |
61 | 121k | sf->x_step_q4 = scaled_x(16, sf); |
62 | 121k | sf->y_step_q4 = scaled_y(16, sf); |
63 | | |
64 | 121k | if (vp9_is_scaled(sf)) { |
65 | 0 | sf->scale_value_x = scaled_x; |
66 | 0 | sf->scale_value_y = scaled_y; |
67 | 121k | } else { |
68 | 121k | sf->scale_value_x = unscaled_value; |
69 | 121k | sf->scale_value_y = unscaled_value; |
70 | 121k | } |
71 | | |
72 | | // TODO(agrange): Investigate the best choice of functions to use here |
73 | | // for EIGHTTAP_SMOOTH. Since it is not interpolating, need to choose what |
74 | | // to do at full-pel offsets. The current selection, where the filter is |
75 | | // applied in one direction only, and not at all for 0,0, seems to give the |
76 | | // best quality, but it may be worth trying an additional mode that does |
77 | | // do the filtering on full-pel. |
78 | | |
79 | 121k | if (sf->x_step_q4 == 16) { |
80 | 121k | if (sf->y_step_q4 == 16) { |
81 | | // No scaling in either direction. |
82 | 121k | sf->predict[0][0][0] = vpx_convolve_copy; |
83 | 121k | sf->predict[0][0][1] = vpx_convolve_avg; |
84 | 121k | sf->predict[0][1][0] = vpx_convolve8_vert; |
85 | 121k | sf->predict[0][1][1] = vpx_convolve8_avg_vert; |
86 | 121k | sf->predict[1][0][0] = vpx_convolve8_horiz; |
87 | 121k | sf->predict[1][0][1] = vpx_convolve8_avg_horiz; |
88 | 121k | } else { |
89 | | // No scaling in x direction. Must always scale in the y direction. |
90 | 0 | sf->predict[0][0][0] = vpx_scaled_vert; |
91 | 0 | sf->predict[0][0][1] = vpx_scaled_avg_vert; |
92 | 0 | sf->predict[0][1][0] = vpx_scaled_vert; |
93 | 0 | sf->predict[0][1][1] = vpx_scaled_avg_vert; |
94 | 0 | sf->predict[1][0][0] = vpx_scaled_2d; |
95 | 0 | sf->predict[1][0][1] = vpx_scaled_avg_2d; |
96 | 0 | } |
97 | 121k | } else { |
98 | 0 | if (sf->y_step_q4 == 16) { |
99 | | // No scaling in the y direction. Must always scale in the x direction. |
100 | 0 | sf->predict[0][0][0] = vpx_scaled_horiz; |
101 | 0 | sf->predict[0][0][1] = vpx_scaled_avg_horiz; |
102 | 0 | sf->predict[0][1][0] = vpx_scaled_2d; |
103 | 0 | sf->predict[0][1][1] = vpx_scaled_avg_2d; |
104 | 0 | sf->predict[1][0][0] = vpx_scaled_horiz; |
105 | 0 | sf->predict[1][0][1] = vpx_scaled_avg_horiz; |
106 | 0 | } else { |
107 | | // Must always scale in both directions. |
108 | 0 | sf->predict[0][0][0] = vpx_scaled_2d; |
109 | 0 | sf->predict[0][0][1] = vpx_scaled_avg_2d; |
110 | 0 | sf->predict[0][1][0] = vpx_scaled_2d; |
111 | 0 | sf->predict[0][1][1] = vpx_scaled_avg_2d; |
112 | 0 | sf->predict[1][0][0] = vpx_scaled_2d; |
113 | 0 | sf->predict[1][0][1] = vpx_scaled_avg_2d; |
114 | 0 | } |
115 | 0 | } |
116 | | |
117 | | // 2D subpel motion always gets filtered in both directions |
118 | | |
119 | 121k | if ((sf->x_step_q4 != 16) || (sf->y_step_q4 != 16)) { |
120 | 0 | sf->predict[1][1][0] = vpx_scaled_2d; |
121 | 0 | sf->predict[1][1][1] = vpx_scaled_avg_2d; |
122 | 121k | } else { |
123 | 121k | sf->predict[1][1][0] = vpx_convolve8; |
124 | 121k | sf->predict[1][1][1] = vpx_convolve8_avg; |
125 | 121k | } |
126 | | |
127 | 121k | #if CONFIG_VP9_HIGHBITDEPTH |
128 | 121k | if (use_highbd) { |
129 | 0 | if (sf->x_step_q4 == 16) { |
130 | 0 | if (sf->y_step_q4 == 16) { |
131 | | // No scaling in either direction. |
132 | 0 | sf->highbd_predict[0][0][0] = vpx_highbd_convolve_copy; |
133 | 0 | sf->highbd_predict[0][0][1] = vpx_highbd_convolve_avg; |
134 | 0 | sf->highbd_predict[0][1][0] = vpx_highbd_convolve8_vert; |
135 | 0 | sf->highbd_predict[0][1][1] = vpx_highbd_convolve8_avg_vert; |
136 | 0 | sf->highbd_predict[1][0][0] = vpx_highbd_convolve8_horiz; |
137 | 0 | sf->highbd_predict[1][0][1] = vpx_highbd_convolve8_avg_horiz; |
138 | 0 | } else { |
139 | | // No scaling in x direction. Must always scale in the y direction. |
140 | 0 | sf->highbd_predict[0][0][0] = vpx_highbd_convolve8_vert; |
141 | 0 | sf->highbd_predict[0][0][1] = vpx_highbd_convolve8_avg_vert; |
142 | 0 | sf->highbd_predict[0][1][0] = vpx_highbd_convolve8_vert; |
143 | 0 | sf->highbd_predict[0][1][1] = vpx_highbd_convolve8_avg_vert; |
144 | 0 | sf->highbd_predict[1][0][0] = vpx_highbd_convolve8; |
145 | 0 | sf->highbd_predict[1][0][1] = vpx_highbd_convolve8_avg; |
146 | 0 | } |
147 | 0 | } else { |
148 | 0 | if (sf->y_step_q4 == 16) { |
149 | | // No scaling in the y direction. Must always scale in the x direction. |
150 | 0 | sf->highbd_predict[0][0][0] = vpx_highbd_convolve8_horiz; |
151 | 0 | sf->highbd_predict[0][0][1] = vpx_highbd_convolve8_avg_horiz; |
152 | 0 | sf->highbd_predict[0][1][0] = vpx_highbd_convolve8; |
153 | 0 | sf->highbd_predict[0][1][1] = vpx_highbd_convolve8_avg; |
154 | 0 | sf->highbd_predict[1][0][0] = vpx_highbd_convolve8_horiz; |
155 | 0 | sf->highbd_predict[1][0][1] = vpx_highbd_convolve8_avg_horiz; |
156 | 0 | } else { |
157 | | // Must always scale in both directions. |
158 | 0 | sf->highbd_predict[0][0][0] = vpx_highbd_convolve8; |
159 | 0 | sf->highbd_predict[0][0][1] = vpx_highbd_convolve8_avg; |
160 | 0 | sf->highbd_predict[0][1][0] = vpx_highbd_convolve8; |
161 | 0 | sf->highbd_predict[0][1][1] = vpx_highbd_convolve8_avg; |
162 | 0 | sf->highbd_predict[1][0][0] = vpx_highbd_convolve8; |
163 | 0 | sf->highbd_predict[1][0][1] = vpx_highbd_convolve8_avg; |
164 | 0 | } |
165 | 0 | } |
166 | | // 2D subpel motion always gets filtered in both directions. |
167 | 0 | sf->highbd_predict[1][1][0] = vpx_highbd_convolve8; |
168 | 0 | sf->highbd_predict[1][1][1] = vpx_highbd_convolve8_avg; |
169 | 0 | } |
170 | 121k | #endif |
171 | 121k | } |