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 16static INLINE int scaled_x(int val, const struct scale_factors *sf) { 17 return (int)((int64_t)val * sf->x_scale_fp >> REF_SCALE_SHIFT); 18} 19 20static INLINE int scaled_y(int val, const struct scale_factors *sf) { 21 return (int)((int64_t)val * sf->y_scale_fp >> REF_SCALE_SHIFT); 22} 23 24static int unscaled_value(int val, const struct scale_factors *sf) { 25 (void)sf; 26 return val; 27} 28 29static 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 return (other_size << REF_SCALE_SHIFT) / this_size; 35} 36 37MV32 vp9_scale_mv(const MV *mv, int x, int y, const struct scale_factors *sf) { 38 const int x_off_q4 = scaled_x(x << SUBPEL_BITS, sf) & SUBPEL_MASK; 39 const int y_off_q4 = scaled_y(y << SUBPEL_BITS, sf) & SUBPEL_MASK; 40 const MV32 res = { scaled_y(mv->row, sf) + y_off_q4, 41 scaled_x(mv->col, sf) + x_off_q4 }; 42 return res; 43} 44 45#if CONFIG_VP9_HIGHBITDEPTH 46void vp9_setup_scale_factors_for_frame(struct scale_factors *sf, int other_w, 47 int other_h, int this_w, int this_h, 48 int use_highbd) { 49#else 50void 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 if (!valid_ref_frame_size(other_w, other_h, this_w, this_h)) { 54 sf->x_scale_fp = REF_INVALID_SCALE; 55 sf->y_scale_fp = REF_INVALID_SCALE; 56 return; 57 } 58 59 sf->x_scale_fp = get_fixed_point_scale_factor(other_w, this_w); 60 sf->y_scale_fp = get_fixed_point_scale_factor(other_h, this_h); 61 sf->x_step_q4 = scaled_x(16, sf); 62 sf->y_step_q4 = scaled_y(16, sf); 63 64 if (vp9_is_scaled(sf)) { 65 sf->scale_value_x = scaled_x; 66 sf->scale_value_y = scaled_y; 67 } else { 68 sf->scale_value_x = unscaled_value; 69 sf->scale_value_y = unscaled_value; 70 } 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 if (sf->x_step_q4 == 16) { 80 if (sf->y_step_q4 == 16) { 81 // No scaling in either direction. 82 sf->predict[0][0][0] = vpx_convolve_copy; 83 sf->predict[0][0][1] = vpx_convolve_avg; 84 sf->predict[0][1][0] = vpx_convolve8_vert; 85 sf->predict[0][1][1] = vpx_convolve8_avg_vert; 86 sf->predict[1][0][0] = vpx_convolve8_horiz; 87 sf->predict[1][0][1] = vpx_convolve8_avg_horiz; 88 } else { 89 // No scaling in x direction. Must always scale in the y direction. 90 sf->predict[0][0][0] = vpx_scaled_vert; 91 sf->predict[0][0][1] = vpx_scaled_avg_vert; 92 sf->predict[0][1][0] = vpx_scaled_vert; 93 sf->predict[0][1][1] = vpx_scaled_avg_vert; 94 sf->predict[1][0][0] = vpx_scaled_2d; 95 sf->predict[1][0][1] = vpx_scaled_avg_2d; 96 } 97 } else { 98 if (sf->y_step_q4 == 16) { 99 // No scaling in the y direction. Must always scale in the x direction. 100 sf->predict[0][0][0] = vpx_scaled_horiz; 101 sf->predict[0][0][1] = vpx_scaled_avg_horiz; 102 sf->predict[0][1][0] = vpx_scaled_2d; 103 sf->predict[0][1][1] = vpx_scaled_avg_2d; 104 sf->predict[1][0][0] = vpx_scaled_horiz; 105 sf->predict[1][0][1] = vpx_scaled_avg_horiz; 106 } else { 107 // Must always scale in both directions. 108 sf->predict[0][0][0] = vpx_scaled_2d; 109 sf->predict[0][0][1] = vpx_scaled_avg_2d; 110 sf->predict[0][1][0] = vpx_scaled_2d; 111 sf->predict[0][1][1] = vpx_scaled_avg_2d; 112 sf->predict[1][0][0] = vpx_scaled_2d; 113 sf->predict[1][0][1] = vpx_scaled_avg_2d; 114 } 115 } 116 117 // 2D subpel motion always gets filtered in both directions 118 119 if ((sf->x_step_q4 != 16) || (sf->y_step_q4 != 16)) { 120 sf->predict[1][1][0] = vpx_scaled_2d; 121 sf->predict[1][1][1] = vpx_scaled_avg_2d; 122 } else { 123 sf->predict[1][1][0] = vpx_convolve8; 124 sf->predict[1][1][1] = vpx_convolve8_avg; 125 } 126 127#if CONFIG_VP9_HIGHBITDEPTH 128 if (use_highbd) { 129 if (sf->x_step_q4 == 16) { 130 if (sf->y_step_q4 == 16) { 131 // No scaling in either direction. 132 sf->highbd_predict[0][0][0] = vpx_highbd_convolve_copy; 133 sf->highbd_predict[0][0][1] = vpx_highbd_convolve_avg; 134 sf->highbd_predict[0][1][0] = vpx_highbd_convolve8_vert; 135 sf->highbd_predict[0][1][1] = vpx_highbd_convolve8_avg_vert; 136 sf->highbd_predict[1][0][0] = vpx_highbd_convolve8_horiz; 137 sf->highbd_predict[1][0][1] = vpx_highbd_convolve8_avg_horiz; 138 } else { 139 // No scaling in x direction. Must always scale in the y direction. 140 sf->highbd_predict[0][0][0] = vpx_highbd_convolve8_vert; 141 sf->highbd_predict[0][0][1] = vpx_highbd_convolve8_avg_vert; 142 sf->highbd_predict[0][1][0] = vpx_highbd_convolve8_vert; 143 sf->highbd_predict[0][1][1] = vpx_highbd_convolve8_avg_vert; 144 sf->highbd_predict[1][0][0] = vpx_highbd_convolve8; 145 sf->highbd_predict[1][0][1] = vpx_highbd_convolve8_avg; 146 } 147 } else { 148 if (sf->y_step_q4 == 16) { 149 // No scaling in the y direction. Must always scale in the x direction. 150 sf->highbd_predict[0][0][0] = vpx_highbd_convolve8_horiz; 151 sf->highbd_predict[0][0][1] = vpx_highbd_convolve8_avg_horiz; 152 sf->highbd_predict[0][1][0] = vpx_highbd_convolve8; 153 sf->highbd_predict[0][1][1] = vpx_highbd_convolve8_avg; 154 sf->highbd_predict[1][0][0] = vpx_highbd_convolve8_horiz; 155 sf->highbd_predict[1][0][1] = vpx_highbd_convolve8_avg_horiz; 156 } else { 157 // Must always scale in both directions. 158 sf->highbd_predict[0][0][0] = vpx_highbd_convolve8; 159 sf->highbd_predict[0][0][1] = vpx_highbd_convolve8_avg; 160 sf->highbd_predict[0][1][0] = vpx_highbd_convolve8; 161 sf->highbd_predict[0][1][1] = vpx_highbd_convolve8_avg; 162 sf->highbd_predict[1][0][0] = vpx_highbd_convolve8; 163 sf->highbd_predict[1][0][1] = vpx_highbd_convolve8_avg; 164 } 165 } 166 // 2D subpel motion always gets filtered in both directions. 167 sf->highbd_predict[1][1][0] = vpx_highbd_convolve8; 168 sf->highbd_predict[1][1][1] = vpx_highbd_convolve8_avg; 169 } 170#endif 171} 172