1233d2500723e5594f3e7c70896ffeeef32b9c950ywan/* 2233d2500723e5594f3e7c70896ffeeef32b9c950ywan * Copyright (c) 2013 The WebM project authors. All Rights Reserved. 3233d2500723e5594f3e7c70896ffeeef32b9c950ywan * 4233d2500723e5594f3e7c70896ffeeef32b9c950ywan * Use of this source code is governed by a BSD-style license 5233d2500723e5594f3e7c70896ffeeef32b9c950ywan * that can be found in the LICENSE file in the root of the source 6233d2500723e5594f3e7c70896ffeeef32b9c950ywan * tree. An additional intellectual property rights grant can be found 7233d2500723e5594f3e7c70896ffeeef32b9c950ywan * in the file PATENTS. All contributing project authors may 8233d2500723e5594f3e7c70896ffeeef32b9c950ywan * be found in the AUTHORS file in the root of the source tree. 9233d2500723e5594f3e7c70896ffeeef32b9c950ywan */ 10233d2500723e5594f3e7c70896ffeeef32b9c950ywan 11233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "./vp9_rtcd.h" 12233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "vp9/common/vp9_filter.h" 13233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "vp9/common/vp9_scale.h" 14233d2500723e5594f3e7c70896ffeeef32b9c950ywan 15233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic INLINE int scaled_x(int val, const struct scale_factors *sf) { 16233d2500723e5594f3e7c70896ffeeef32b9c950ywan return (int)((int64_t)val * sf->x_scale_fp >> REF_SCALE_SHIFT); 17233d2500723e5594f3e7c70896ffeeef32b9c950ywan} 18233d2500723e5594f3e7c70896ffeeef32b9c950ywan 19233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic INLINE int scaled_y(int val, const struct scale_factors *sf) { 20233d2500723e5594f3e7c70896ffeeef32b9c950ywan return (int)((int64_t)val * sf->y_scale_fp >> REF_SCALE_SHIFT); 21233d2500723e5594f3e7c70896ffeeef32b9c950ywan} 22233d2500723e5594f3e7c70896ffeeef32b9c950ywan 23233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic int unscaled_value(int val, const struct scale_factors *sf) { 24233d2500723e5594f3e7c70896ffeeef32b9c950ywan (void) sf; 25233d2500723e5594f3e7c70896ffeeef32b9c950ywan return val; 26233d2500723e5594f3e7c70896ffeeef32b9c950ywan} 27233d2500723e5594f3e7c70896ffeeef32b9c950ywan 28233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic int get_fixed_point_scale_factor(int other_size, int this_size) { 29233d2500723e5594f3e7c70896ffeeef32b9c950ywan // Calculate scaling factor once for each reference frame 30233d2500723e5594f3e7c70896ffeeef32b9c950ywan // and use fixed point scaling factors in decoding and encoding routines. 31233d2500723e5594f3e7c70896ffeeef32b9c950ywan // Hardware implementations can calculate scale factor in device driver 32233d2500723e5594f3e7c70896ffeeef32b9c950ywan // and use multiplication and shifting on hardware instead of division. 33233d2500723e5594f3e7c70896ffeeef32b9c950ywan return (other_size << REF_SCALE_SHIFT) / this_size; 34233d2500723e5594f3e7c70896ffeeef32b9c950ywan} 35233d2500723e5594f3e7c70896ffeeef32b9c950ywan 36233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic int check_scale_factors(int other_w, int other_h, 37233d2500723e5594f3e7c70896ffeeef32b9c950ywan int this_w, int this_h) { 38233d2500723e5594f3e7c70896ffeeef32b9c950ywan return 2 * this_w >= other_w && 39233d2500723e5594f3e7c70896ffeeef32b9c950ywan 2 * this_h >= other_h && 40233d2500723e5594f3e7c70896ffeeef32b9c950ywan this_w <= 16 * other_w && 41233d2500723e5594f3e7c70896ffeeef32b9c950ywan this_h <= 16 * other_h; 42233d2500723e5594f3e7c70896ffeeef32b9c950ywan} 43233d2500723e5594f3e7c70896ffeeef32b9c950ywan 44233d2500723e5594f3e7c70896ffeeef32b9c950ywanMV32 vp9_scale_mv(const MV *mv, int x, int y, const struct scale_factors *sf) { 45233d2500723e5594f3e7c70896ffeeef32b9c950ywan const int x_off_q4 = scaled_x(x << SUBPEL_BITS, sf) & SUBPEL_MASK; 46233d2500723e5594f3e7c70896ffeeef32b9c950ywan const int y_off_q4 = scaled_y(y << SUBPEL_BITS, sf) & SUBPEL_MASK; 47233d2500723e5594f3e7c70896ffeeef32b9c950ywan const MV32 res = { 48233d2500723e5594f3e7c70896ffeeef32b9c950ywan scaled_y(mv->row, sf) + y_off_q4, 49233d2500723e5594f3e7c70896ffeeef32b9c950ywan scaled_x(mv->col, sf) + x_off_q4 50233d2500723e5594f3e7c70896ffeeef32b9c950ywan }; 51233d2500723e5594f3e7c70896ffeeef32b9c950ywan return res; 52233d2500723e5594f3e7c70896ffeeef32b9c950ywan} 53233d2500723e5594f3e7c70896ffeeef32b9c950ywan 54233d2500723e5594f3e7c70896ffeeef32b9c950ywanvoid vp9_setup_scale_factors_for_frame(struct scale_factors *sf, 55233d2500723e5594f3e7c70896ffeeef32b9c950ywan int other_w, int other_h, 56233d2500723e5594f3e7c70896ffeeef32b9c950ywan int this_w, int this_h) { 57233d2500723e5594f3e7c70896ffeeef32b9c950ywan if (!check_scale_factors(other_w, other_h, this_w, this_h)) { 58233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->x_scale_fp = REF_INVALID_SCALE; 59233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->y_scale_fp = REF_INVALID_SCALE; 60233d2500723e5594f3e7c70896ffeeef32b9c950ywan return; 61233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 62233d2500723e5594f3e7c70896ffeeef32b9c950ywan 63233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->x_scale_fp = get_fixed_point_scale_factor(other_w, this_w); 64233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->y_scale_fp = get_fixed_point_scale_factor(other_h, this_h); 65233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->x_step_q4 = scaled_x(16, sf); 66233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->y_step_q4 = scaled_y(16, sf); 67233d2500723e5594f3e7c70896ffeeef32b9c950ywan 68233d2500723e5594f3e7c70896ffeeef32b9c950ywan if (vp9_is_scaled(sf)) { 69233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->scale_value_x = scaled_x; 70233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->scale_value_y = scaled_y; 71233d2500723e5594f3e7c70896ffeeef32b9c950ywan } else { 72233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->scale_value_x = unscaled_value; 73233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->scale_value_y = unscaled_value; 74233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 75233d2500723e5594f3e7c70896ffeeef32b9c950ywan 76233d2500723e5594f3e7c70896ffeeef32b9c950ywan // TODO(agrange): Investigate the best choice of functions to use here 77233d2500723e5594f3e7c70896ffeeef32b9c950ywan // for EIGHTTAP_SMOOTH. Since it is not interpolating, need to choose what 78233d2500723e5594f3e7c70896ffeeef32b9c950ywan // to do at full-pel offsets. The current selection, where the filter is 79233d2500723e5594f3e7c70896ffeeef32b9c950ywan // applied in one direction only, and not at all for 0,0, seems to give the 80233d2500723e5594f3e7c70896ffeeef32b9c950ywan // best quality, but it may be worth trying an additional mode that does 81233d2500723e5594f3e7c70896ffeeef32b9c950ywan // do the filtering on full-pel. 82233d2500723e5594f3e7c70896ffeeef32b9c950ywan if (sf->x_step_q4 == 16) { 83233d2500723e5594f3e7c70896ffeeef32b9c950ywan if (sf->y_step_q4 == 16) { 84233d2500723e5594f3e7c70896ffeeef32b9c950ywan // No scaling in either direction. 85233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[0][0][0] = vp9_convolve_copy; 86233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[0][0][1] = vp9_convolve_avg; 87233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[0][1][0] = vp9_convolve8_vert; 88233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[0][1][1] = vp9_convolve8_avg_vert; 89233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[1][0][0] = vp9_convolve8_horiz; 90233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[1][0][1] = vp9_convolve8_avg_horiz; 91233d2500723e5594f3e7c70896ffeeef32b9c950ywan } else { 92233d2500723e5594f3e7c70896ffeeef32b9c950ywan // No scaling in x direction. Must always scale in the y direction. 93233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[0][0][0] = vp9_convolve8_vert; 94233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[0][0][1] = vp9_convolve8_avg_vert; 95233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[0][1][0] = vp9_convolve8_vert; 96233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[0][1][1] = vp9_convolve8_avg_vert; 97233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[1][0][0] = vp9_convolve8; 98233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[1][0][1] = vp9_convolve8_avg; 99233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 100233d2500723e5594f3e7c70896ffeeef32b9c950ywan } else { 101233d2500723e5594f3e7c70896ffeeef32b9c950ywan if (sf->y_step_q4 == 16) { 102233d2500723e5594f3e7c70896ffeeef32b9c950ywan // No scaling in the y direction. Must always scale in the x direction. 103233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[0][0][0] = vp9_convolve8_horiz; 104233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[0][0][1] = vp9_convolve8_avg_horiz; 105233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[0][1][0] = vp9_convolve8; 106233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[0][1][1] = vp9_convolve8_avg; 107233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[1][0][0] = vp9_convolve8_horiz; 108233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[1][0][1] = vp9_convolve8_avg_horiz; 109233d2500723e5594f3e7c70896ffeeef32b9c950ywan } else { 110233d2500723e5594f3e7c70896ffeeef32b9c950ywan // Must always scale in both directions. 111233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[0][0][0] = vp9_convolve8; 112233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[0][0][1] = vp9_convolve8_avg; 113233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[0][1][0] = vp9_convolve8; 114233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[0][1][1] = vp9_convolve8_avg; 115233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[1][0][0] = vp9_convolve8; 116233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[1][0][1] = vp9_convolve8_avg; 117233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 118233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 119233d2500723e5594f3e7c70896ffeeef32b9c950ywan // 2D subpel motion always gets filtered in both directions 120233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[1][1][0] = vp9_convolve8; 121233d2500723e5594f3e7c70896ffeeef32b9c950ywan sf->predict[1][1][1] = vp9_convolve8_avg; 122233d2500723e5594f3e7c70896ffeeef32b9c950ywan} 123