3010 lines · 114.0 KB · C
RawDownload
/* *  Copyright (c) 2010 The WebM project authors. All Rights Reserved. * *  Use of this source code is governed by a BSD-style license *  that can be found in the LICENSE file in the root of the source *  tree. An additional intellectual property rights grant can be found *  in the file PATENTS.  All contributing project authors may *  be found in the AUTHORS file in the root of the source tree. */ #include <assert.h>#include <limits.h>#include <math.h>#include <stdio.h> #include "./vpx_config.h"#include "./vpx_dsp_rtcd.h" #include "vpx_dsp/vpx_dsp_common.h"#include "vpx_mem/vpx_mem.h"#include "vpx_ports/mem.h" #include "vp9/common/vp9_common.h"#include "vp9/common/vp9_mvref_common.h"#include "vp9/common/vp9_reconinter.h" #include "vp9/encoder/vp9_encoder.h"#include "vp9/encoder/vp9_mcomp.h" // #define NEW_DIAMOND_SEARCH void vp9_set_mv_search_range(MvLimits *mv_limits, const MV *mv) {  int col_min = (mv->col >> 3) - MAX_FULL_PEL_VAL + (mv->col & 7 ? 1 : 0);  int row_min = (mv->row >> 3) - MAX_FULL_PEL_VAL + (mv->row & 7 ? 1 : 0);  int col_max = (mv->col >> 3) + MAX_FULL_PEL_VAL;  int row_max = (mv->row >> 3) + MAX_FULL_PEL_VAL;   col_min = VPXMAX(col_min, (MV_LOW >> 3) + 1);  row_min = VPXMAX(row_min, (MV_LOW >> 3) + 1);  col_max = VPXMIN(col_max, (MV_UPP >> 3) - 1);  row_max = VPXMIN(row_max, (MV_UPP >> 3) - 1);   // Get intersection of UMV window and valid MV window to reduce # of checks  // in diamond search.  if (mv_limits->col_min < col_min) mv_limits->col_min = col_min;  if (mv_limits->col_max > col_max) mv_limits->col_max = col_max;  if (mv_limits->row_min < row_min) mv_limits->row_min = row_min;  if (mv_limits->row_max > row_max) mv_limits->row_max = row_max;} void vp9_set_subpel_mv_search_range(MvLimits *subpel_mv_limits,                                    const MvLimits *umv_window_limits,                                    const MV *ref_mv) {  subpel_mv_limits->col_min = VPXMAX(umv_window_limits->col_min * 8,                                     ref_mv->col - MAX_FULL_PEL_VAL * 8);  subpel_mv_limits->col_max = VPXMIN(umv_window_limits->col_max * 8,                                     ref_mv->col + MAX_FULL_PEL_VAL * 8);  subpel_mv_limits->row_min = VPXMAX(umv_window_limits->row_min * 8,                                     ref_mv->row - MAX_FULL_PEL_VAL * 8);  subpel_mv_limits->row_max = VPXMIN(umv_window_limits->row_max * 8,                                     ref_mv->row + MAX_FULL_PEL_VAL * 8);   subpel_mv_limits->col_min = VPXMAX(MV_LOW + 1, subpel_mv_limits->col_min);  subpel_mv_limits->col_max = VPXMIN(MV_UPP - 1, subpel_mv_limits->col_max);  subpel_mv_limits->row_min = VPXMAX(MV_LOW + 1, subpel_mv_limits->row_min);  subpel_mv_limits->row_max = VPXMIN(MV_UPP - 1, subpel_mv_limits->row_max);} int vp9_init_search_range(int size) {  int sr = 0;  // Minimum search size no matter what the passed in value.  size = VPXMAX(16, size);   while ((size << sr) < MAX_FULL_PEL_VAL) sr++;   sr = VPXMIN(sr, MAX_MVSEARCH_STEPS - 2);  return sr;} static INLINE int mv_cost(const MV *mv, const int *joint_cost,                          int *const comp_cost[2]) {  assert(mv->row >= -MV_MAX && mv->row < MV_MAX);  assert(mv->col >= -MV_MAX && mv->col < MV_MAX);  return joint_cost[vp9_get_mv_joint(mv)] + comp_cost[0][mv->row] +         comp_cost[1][mv->col];} int vp9_mv_bit_cost(const MV *mv, const MV *ref, const int *mvjcost,                    int *mvcost[2], int weight) {  const MV diff = { mv->row - ref->row, mv->col - ref->col };  return ROUND_POWER_OF_TWO(mv_cost(&diff, mvjcost, mvcost) * weight, 7);} #define PIXEL_TRANSFORM_ERROR_SCALE 4static int mv_err_cost(const MV *mv, const MV *ref, const int *mvjcost,                       int *mvcost[2], int error_per_bit) {  if (mvcost) {    const MV diff = { mv->row - ref->row, mv->col - ref->col };    return (int)ROUND64_POWER_OF_TWO(        (int64_t)mv_cost(&diff, mvjcost, mvcost) * error_per_bit,        RDDIV_BITS + VP9_PROB_COST_SHIFT - RD_EPB_SHIFT +            PIXEL_TRANSFORM_ERROR_SCALE);  }  return 0;} static int mvsad_err_cost(const MACROBLOCK *x, const MV *mv, const MV *ref,                          int sad_per_bit) {  const MV diff = { mv->row - ref->row, mv->col - ref->col };  return ROUND_POWER_OF_TWO(      (unsigned)mv_cost(&diff, x->nmvjointsadcost, x->nmvsadcost) * sad_per_bit,      VP9_PROB_COST_SHIFT);} void vp9_init_dsmotion_compensation(search_site_config *cfg, int stride) {  int len;  int ss_count = 0;   for (len = MAX_FIRST_STEP; len > 0; len /= 2) {    // Generate offsets for 4 search sites per step.    const MV ss_mvs[] = { { -len, 0 }, { len, 0 }, { 0, -len }, { 0, len } };    int i;    for (i = 0; i < 4; ++i, ++ss_count) {      cfg->ss_mv[ss_count] = ss_mvs[i];      cfg->ss_os[ss_count] = ss_mvs[i].row * stride + ss_mvs[i].col;    }  }   cfg->searches_per_step = 4;  cfg->total_steps = ss_count / cfg->searches_per_step;} void vp9_init3smotion_compensation(search_site_config *cfg, int stride) {  int len;  int ss_count = 0;   for (len = MAX_FIRST_STEP; len > 0; len /= 2) {    // Generate offsets for 8 search sites per step.    const MV ss_mvs[8] = { { -len, 0 },   { len, 0 },     { 0, -len },                           { 0, len },    { -len, -len }, { -len, len },                           { len, -len }, { len, len } };    int i;    for (i = 0; i < 8; ++i, ++ss_count) {      cfg->ss_mv[ss_count] = ss_mvs[i];      cfg->ss_os[ss_count] = ss_mvs[i].row * stride + ss_mvs[i].col;    }  }   cfg->searches_per_step = 8;  cfg->total_steps = ss_count / cfg->searches_per_step;} // convert motion vector component to offset for sv[a]f calcstatic INLINE int sp(int x) { return x & 7; } static INLINE const uint8_t *pre(const uint8_t *buf, int stride, int r, int c) {  return &buf[(r >> 3) * stride + (c >> 3)];} #if CONFIG_VP9_HIGHBITDEPTH/* checks if (r, c) has better score than previous best */#define CHECK_BETTER(v, r, c)                                                \  if (c >= minc && c <= maxc && r >= minr && r <= maxr) {                    \    int64_t tmpmse;                                                          \    const MV mv = { r, c };                                                  \    const MV ref_mv = { rr, rc };                                            \    if (second_pred == NULL) {                                               \      thismse = vfp->svf(pre(y, y_stride, r, c), y_stride, sp(c), sp(r), z,  \                         src_stride, &sse);                                  \    } else {                                                                 \      thismse = vfp->svaf(pre(y, y_stride, r, c), y_stride, sp(c), sp(r), z, \                          src_stride, &sse, second_pred);                    \    }                                                                        \    tmpmse = thismse;                                                        \    tmpmse += mv_err_cost(&mv, &ref_mv, mvjcost, mvcost, error_per_bit);     \    if (tmpmse >= INT_MAX) {                                                 \      v = INT_MAX;                                                           \    } else if ((v = (uint32_t)tmpmse) < besterr) {                           \      besterr = v;                                                           \      br = r;                                                                \      bc = c;                                                                \      *distortion = thismse;                                                 \      *sse1 = sse;                                                           \    }                                                                        \  } else {                                                                   \    v = INT_MAX;                                                             \  }#else/* checks if (r, c) has better score than previous best */#define CHECK_BETTER(v, r, c)                                                \  if (c >= minc && c <= maxc && r >= minr && r <= maxr) {                    \    const MV mv = { r, c };                                                  \    const MV ref_mv = { rr, rc };                                            \    if (second_pred == NULL)                                                 \      thismse = vfp->svf(pre(y, y_stride, r, c), y_stride, sp(c), sp(r), z,  \                         src_stride, &sse);                                  \    else                                                                     \      thismse = vfp->svaf(pre(y, y_stride, r, c), y_stride, sp(c), sp(r), z, \                          src_stride, &sse, second_pred);                    \    if ((v = mv_err_cost(&mv, &ref_mv, mvjcost, mvcost, error_per_bit) +     \             thismse) < besterr) {                                           \      besterr = v;                                                           \      br = r;                                                                \      bc = c;                                                                \      *distortion = thismse;                                                 \      *sse1 = sse;                                                           \    }                                                                        \  } else {                                                                   \    v = INT_MAX;                                                             \  } #endif#define FIRST_LEVEL_CHECKS                                       \  {                                                              \    unsigned int left, right, up, down, diag;                    \    CHECK_BETTER(left, tr, tc - hstep);                          \    CHECK_BETTER(right, tr, tc + hstep);                         \    CHECK_BETTER(up, tr - hstep, tc);                            \    CHECK_BETTER(down, tr + hstep, tc);                          \    whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2);     \    switch (whichdir) {                                          \      case 0: CHECK_BETTER(diag, tr - hstep, tc - hstep); break; \      case 1: CHECK_BETTER(diag, tr - hstep, tc + hstep); break; \      case 2: CHECK_BETTER(diag, tr + hstep, tc - hstep); break; \      case 3: CHECK_BETTER(diag, tr + hstep, tc + hstep); break; \    }                                                            \  } #define SECOND_LEVEL_CHECKS                                       \  {                                                               \    int kr, kc;                                                   \    unsigned int second;                                          \    if (tr != br && tc != bc) {                                   \      kr = br - tr;                                               \      kc = bc - tc;                                               \      CHECK_BETTER(second, tr + kr, tc + 2 * kc);                 \      CHECK_BETTER(second, tr + 2 * kr, tc + kc);                 \    } else if (tr == br && tc != bc) {                            \      kc = bc - tc;                                               \      CHECK_BETTER(second, tr + hstep, tc + 2 * kc);              \      CHECK_BETTER(second, tr - hstep, tc + 2 * kc);              \      switch (whichdir) {                                         \        case 0:                                                   \        case 1: CHECK_BETTER(second, tr + hstep, tc + kc); break; \        case 2:                                                   \        case 3: CHECK_BETTER(second, tr - hstep, tc + kc); break; \      }                                                           \    } else if (tr != br && tc == bc) {                            \      kr = br - tr;                                               \      CHECK_BETTER(second, tr + 2 * kr, tc + hstep);              \      CHECK_BETTER(second, tr + 2 * kr, tc - hstep);              \      switch (whichdir) {                                         \        case 0:                                                   \        case 2: CHECK_BETTER(second, tr + kr, tc + hstep); break; \        case 1:                                                   \        case 3: CHECK_BETTER(second, tr + kr, tc - hstep); break; \      }                                                           \    }                                                             \  } #define SETUP_SUBPEL_SEARCH                                                 \  const uint8_t *const z = x->plane[0].src.buf;                             \  const int src_stride = x->plane[0].src.stride;                            \  const MACROBLOCKD *xd = &x->e_mbd;                                        \  unsigned int besterr = UINT_MAX;                                          \  unsigned int sse;                                                         \  unsigned int whichdir;                                                    \  int thismse;                                                              \  const unsigned int halfiters = iters_per_step;                            \  const unsigned int quarteriters = iters_per_step;                         \  const unsigned int eighthiters = iters_per_step;                          \  const int y_stride = xd->plane[0].pre[0].stride;                          \  const int offset = bestmv->row * y_stride + bestmv->col;                  \  const uint8_t *const y = xd->plane[0].pre[0].buf;                         \                                                                            \  int rr = ref_mv->row;                                                     \  int rc = ref_mv->col;                                                     \  int br = bestmv->row * 8;                                                 \  int bc = bestmv->col * 8;                                                 \  int hstep = 4;                                                            \  int minc, maxc, minr, maxr;                                               \  int tr = br;                                                              \  int tc = bc;                                                              \  MvLimits subpel_mv_limits;                                                \                                                                            \  vp9_set_subpel_mv_search_range(&subpel_mv_limits, &x->mv_limits, ref_mv); \  minc = subpel_mv_limits.col_min;                                          \  maxc = subpel_mv_limits.col_max;                                          \  minr = subpel_mv_limits.row_min;                                          \  maxr = subpel_mv_limits.row_max;                                          \                                                                            \  bestmv->row *= 8;                                                         \  bestmv->col *= 8; static unsigned int setup_center_error(    const MACROBLOCKD *xd, const MV *bestmv, const MV *ref_mv,    int error_per_bit, const vp9_variance_fn_ptr_t *vfp,    const uint8_t *const src, const int src_stride, const uint8_t *const y,    int y_stride, const uint8_t *second_pred, int w, int h, int offset,    int *mvjcost, int *mvcost[2], uint32_t *sse1, uint32_t *distortion) {#if CONFIG_VP9_HIGHBITDEPTH  uint64_t besterr;  if (second_pred != NULL) {    if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {      DECLARE_ALIGNED(16, uint16_t, comp_pred16[64 * 64]);      vpx_highbd_comp_avg_pred(comp_pred16, CONVERT_TO_SHORTPTR(second_pred), w,                               h, CONVERT_TO_SHORTPTR(y + offset), y_stride);      besterr =          vfp->vf(CONVERT_TO_BYTEPTR(comp_pred16), w, src, src_stride, sse1);    } else {      DECLARE_ALIGNED(16, uint8_t, comp_pred[64 * 64]);      vpx_comp_avg_pred(comp_pred, second_pred, w, h, y + offset, y_stride);      besterr = vfp->vf(comp_pred, w, src, src_stride, sse1);    }  } else {    besterr = vfp->vf(y + offset, y_stride, src, src_stride, sse1);  }  *distortion = (uint32_t)besterr;  besterr += mv_err_cost(bestmv, ref_mv, mvjcost, mvcost, error_per_bit);  if (besterr >= UINT_MAX) return UINT_MAX;  return (uint32_t)besterr;#else  uint32_t besterr;  (void)xd;  if (second_pred != NULL) {    DECLARE_ALIGNED(16, uint8_t, comp_pred[64 * 64]);    vpx_comp_avg_pred(comp_pred, second_pred, w, h, y + offset, y_stride);    besterr = vfp->vf(comp_pred, w, src, src_stride, sse1);  } else {    besterr = vfp->vf(y + offset, y_stride, src, src_stride, sse1);  }  *distortion = besterr;  besterr += mv_err_cost(bestmv, ref_mv, mvjcost, mvcost, error_per_bit);  return besterr;#endif  // CONFIG_VP9_HIGHBITDEPTH} static INLINE int64_t divide_and_round(const int64_t n, const int64_t d) {  return ((n < 0) ^ (d < 0)) ? ((n - d / 2) / d) : ((n + d / 2) / d);} static INLINE int is_cost_list_wellbehaved(int *cost_list) {  return cost_list[0] < cost_list[1] && cost_list[0] < cost_list[2] &&         cost_list[0] < cost_list[3] && cost_list[0] < cost_list[4];} // Returns surface minima estimate at given precision in 1/2^n bits.// Assume a model for the cost surface: S = A(x - x0)^2 + B(y - y0)^2 + C// For a given set of costs S0, S1, S2, S3, S4 at points// (y, x) = (0, 0), (0, -1), (1, 0), (0, 1) and (-1, 0) respectively,// the solution for the location of the minima (x0, y0) is given by:// x0 = 1/2 (S1 - S3)/(S1 + S3 - 2*S0),// y0 = 1/2 (S4 - S2)/(S4 + S2 - 2*S0).// The code below is an integerized version of that.static void get_cost_surf_min(int *cost_list, int *ir, int *ic, int bits) {  const int64_t x0 = (int64_t)cost_list[1] - cost_list[3];  const int64_t y0 = cost_list[1] - 2 * (int64_t)cost_list[0] + cost_list[3];  const int64_t x1 = (int64_t)cost_list[4] - cost_list[2];  const int64_t y1 = cost_list[4] - 2 * (int64_t)cost_list[0] + cost_list[2];  const int b = 1 << (bits - 1);  *ic = (int)divide_and_round(x0 * b, y0);  *ir = (int)divide_and_round(x1 * b, y1);} uint32_t vp9_skip_sub_pixel_tree(    const MACROBLOCK *x, MV *bestmv, const MV *ref_mv, int allow_hp,    int error_per_bit, const vp9_variance_fn_ptr_t *vfp, int forced_stop,    int iters_per_step, int *cost_list, int *mvjcost, int *mvcost[2],    uint32_t *distortion, uint32_t *sse1, const uint8_t *second_pred, int w,    int h, int use_accurate_subpel_search) {  SETUP_SUBPEL_SEARCH;  besterr = setup_center_error(xd, bestmv, ref_mv, error_per_bit, vfp, z,                               src_stride, y, y_stride, second_pred, w, h,                               offset, mvjcost, mvcost, sse1, distortion);  (void)halfiters;  (void)quarteriters;  (void)eighthiters;  (void)whichdir;  (void)allow_hp;  (void)forced_stop;  (void)hstep;  (void)rr;  (void)rc;  (void)minr;  (void)minc;  (void)maxr;  (void)maxc;  (void)tr;  (void)tc;  (void)sse;  (void)thismse;  (void)cost_list;  (void)use_accurate_subpel_search;   return besterr;} uint32_t vp9_find_best_sub_pixel_tree_pruned_evenmore(    const MACROBLOCK *x, MV *bestmv, const MV *ref_mv, int allow_hp,    int error_per_bit, const vp9_variance_fn_ptr_t *vfp, int forced_stop,    int iters_per_step, int *cost_list, int *mvjcost, int *mvcost[2],    uint32_t *distortion, uint32_t *sse1, const uint8_t *second_pred, int w,    int h, int use_accurate_subpel_search) {  SETUP_SUBPEL_SEARCH;  besterr = setup_center_error(xd, bestmv, ref_mv, error_per_bit, vfp, z,                               src_stride, y, y_stride, second_pred, w, h,                               offset, mvjcost, mvcost, sse1, distortion);  (void)halfiters;  (void)quarteriters;  (void)eighthiters;  (void)whichdir;  (void)allow_hp;  (void)forced_stop;  (void)hstep;  (void)use_accurate_subpel_search;   if (cost_list && cost_list[0] != INT_MAX && cost_list[1] != INT_MAX &&      cost_list[2] != INT_MAX && cost_list[3] != INT_MAX &&      cost_list[4] != INT_MAX && is_cost_list_wellbehaved(cost_list)) {    int ir, ic;    unsigned int minpt = INT_MAX;    get_cost_surf_min(cost_list, &ir, &ic, 2);    if (ir != 0 || ic != 0) {      CHECK_BETTER(minpt, tr + 2 * ir, tc + 2 * ic);    }  } else {    FIRST_LEVEL_CHECKS;    if (halfiters > 1) {      SECOND_LEVEL_CHECKS;    }     tr = br;    tc = bc;     // Each subsequent iteration checks at least one point in common with    // the last iteration could be 2 ( if diag selected) 1/4 pel    // Note forced_stop: 0 - full, 1 - qtr only, 2 - half only    if (forced_stop != 2) {      hstep >>= 1;      FIRST_LEVEL_CHECKS;      if (quarteriters > 1) {        SECOND_LEVEL_CHECKS;      }    }  }   tr = br;  tc = bc;   if (allow_hp && use_mv_hp(ref_mv) && forced_stop == 0) {    hstep >>= 1;    FIRST_LEVEL_CHECKS;    if (eighthiters > 1) {      SECOND_LEVEL_CHECKS;    }  }   bestmv->row = br;  bestmv->col = bc;   return besterr;} uint32_t vp9_find_best_sub_pixel_tree_pruned_more(    const MACROBLOCK *x, MV *bestmv, const MV *ref_mv, int allow_hp,    int error_per_bit, const vp9_variance_fn_ptr_t *vfp, int forced_stop,    int iters_per_step, int *cost_list, int *mvjcost, int *mvcost[2],    uint32_t *distortion, uint32_t *sse1, const uint8_t *second_pred, int w,    int h, int use_accurate_subpel_search) {  SETUP_SUBPEL_SEARCH;  (void)use_accurate_subpel_search;   besterr = setup_center_error(xd, bestmv, ref_mv, error_per_bit, vfp, z,                               src_stride, y, y_stride, second_pred, w, h,                               offset, mvjcost, mvcost, sse1, distortion);  if (cost_list && cost_list[0] != INT_MAX && cost_list[1] != INT_MAX &&      cost_list[2] != INT_MAX && cost_list[3] != INT_MAX &&      cost_list[4] != INT_MAX && is_cost_list_wellbehaved(cost_list)) {    unsigned int minpt;    int ir, ic;    get_cost_surf_min(cost_list, &ir, &ic, 1);    if (ir != 0 || ic != 0) {      CHECK_BETTER(minpt, tr + ir * hstep, tc + ic * hstep);    }  } else {    FIRST_LEVEL_CHECKS;    if (halfiters > 1) {      SECOND_LEVEL_CHECKS;    }  }   // Each subsequent iteration checks at least one point in common with  // the last iteration could be 2 ( if diag selected) 1/4 pel   // Note forced_stop: 0 - full, 1 - qtr only, 2 - half only  if (forced_stop != 2) {    tr = br;    tc = bc;    hstep >>= 1;    FIRST_LEVEL_CHECKS;

Lines 1–500 of 3010.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t