392 lines · 11.5 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 "./vpx_dsp_rtcd.h"#include "./vpx_scale_rtcd.h"#include "vp8/common/onyxc_int.h"#include "onyx_int.h"#include "vp8/encoder/picklpf.h"#include "vp8/encoder/quantize.h"#include "vpx_mem/vpx_mem.h"#include "vpx_scale/vpx_scale.h"#include "vp8/common/alloccommon.h"#include "vp8/common/loopfilter.h"#if VPX_ARCH_ARM#include "vpx_ports/arm.h"#endif extern int vp8_calc_ss_err(YV12_BUFFER_CONFIG *source,                           YV12_BUFFER_CONFIG *dest); static void yv12_copy_partial_frame(YV12_BUFFER_CONFIG *src_ybc,                                    YV12_BUFFER_CONFIG *dst_ybc) {  unsigned char *src_y, *dst_y;  int yheight;  int ystride;  int yoffset;  int linestocopy;   yheight = src_ybc->y_height;  ystride = src_ybc->y_stride;   /* number of MB rows to use in partial filtering */  linestocopy = (yheight >> 4) / PARTIAL_FRAME_FRACTION;  linestocopy = linestocopy ? linestocopy << 4 : 16; /* 16 lines per MB */   /* Copy extra 4 so that full filter context is available if filtering done   * on the copied partial frame and not original. Partial filter does mb   * filtering for top row also, which can modify3 pixels above.   */  linestocopy += 4;  /* partial image starts at ~middle of frame (macroblock border)*/  yoffset = ystride * (((yheight >> 5) * 16) - 4);  src_y = src_ybc->y_buffer + yoffset;  dst_y = dst_ybc->y_buffer + yoffset;   memcpy(dst_y, src_y, ystride * linestocopy);} static int calc_partial_ssl_err(YV12_BUFFER_CONFIG *source,                                YV12_BUFFER_CONFIG *dest) {  int i, j;  int Total = 0;  int srcoffset, dstoffset;  unsigned char *src = source->y_buffer;  unsigned char *dst = dest->y_buffer;   int linestocopy;   /* number of MB rows to use in partial filtering */  linestocopy = (source->y_height >> 4) / PARTIAL_FRAME_FRACTION;  linestocopy = linestocopy ? linestocopy << 4 : 16; /* 16 lines per MB */   /* partial image starts at ~middle of frame (macroblock border)*/  srcoffset = source->y_stride * ((dest->y_height >> 5) * 16);  dstoffset = dest->y_stride * ((dest->y_height >> 5) * 16);   src += srcoffset;  dst += dstoffset;   /* Loop through the Y plane raw and reconstruction data summing   * (square differences)   */  for (i = 0; i < linestocopy; i += 16) {    for (j = 0; j < source->y_width; j += 16) {      unsigned int sse;      Total += vpx_mse16x16(src + j, source->y_stride, dst + j, dest->y_stride,                            &sse);    }     src += 16 * source->y_stride;    dst += 16 * dest->y_stride;  }   return Total;} /* Enforce a minimum filter level based upon baseline Q */static int get_min_filter_level(VP8_COMP *cpi, int base_qindex) {  int min_filter_level;   if (cpi->source_alt_ref_active && cpi->common.refresh_golden_frame &&      !cpi->common.refresh_alt_ref_frame) {    min_filter_level = 0;  } else {    if (base_qindex <= 6) {      min_filter_level = 0;    } else if (base_qindex <= 16) {      min_filter_level = 1;    } else {      min_filter_level = (base_qindex / 8);    }  }   return min_filter_level;} /* Enforce a maximum filter level based upon baseline Q */static int get_max_filter_level(VP8_COMP *cpi, int base_qindex) {  /* PGW August 2006: Highest filter values almost always a bad idea */   /* jbb chg: 20100118 - not so any more with this overquant stuff allow   * high values with lots of intra coming in.   */  int max_filter_level = MAX_LOOP_FILTER;  (void)base_qindex;   if (cpi->twopass.section_intra_rating > 8) {    max_filter_level = MAX_LOOP_FILTER * 3 / 4;  }   return max_filter_level;} void vp8cx_pick_filter_level_fast(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi) {  VP8_COMMON *cm = &cpi->common;   int best_err = 0;  int filt_err = 0;  int min_filter_level = get_min_filter_level(cpi, cm->base_qindex);  int max_filter_level = get_max_filter_level(cpi, cm->base_qindex);  int filt_val;  int best_filt_val;  YV12_BUFFER_CONFIG *saved_frame = cm->frame_to_show;   /* Replace unfiltered frame buffer with a new one */  cm->frame_to_show = &cpi->pick_lf_lvl_frame;   if (cm->frame_type == KEY_FRAME) {    cm->sharpness_level = 0;  } else {    cm->sharpness_level = cpi->oxcf.Sharpness;  }   if (cm->sharpness_level != cm->last_sharpness_level) {    vp8_loop_filter_update_sharpness(&cm->lf_info, cm->sharpness_level);    cm->last_sharpness_level = cm->sharpness_level;  }   /* Start the search at the previous frame filter level unless it is   * now out of range.   */  if (cm->filter_level < min_filter_level) {    cm->filter_level = min_filter_level;  } else if (cm->filter_level > max_filter_level) {    cm->filter_level = max_filter_level;  }   filt_val = cm->filter_level;  best_filt_val = filt_val;   /* Get the err using the previous frame's filter value. */   /* Copy the unfiltered / processed recon buffer to the new buffer */  yv12_copy_partial_frame(saved_frame, cm->frame_to_show);  vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val);   best_err = calc_partial_ssl_err(sd, cm->frame_to_show);   filt_val -= 1 + (filt_val > 10);   /* Search lower filter levels */  while (filt_val >= min_filter_level) {    /* Apply the loop filter */    yv12_copy_partial_frame(saved_frame, cm->frame_to_show);    vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val);     /* Get the err for filtered frame */    filt_err = calc_partial_ssl_err(sd, cm->frame_to_show);     /* Update the best case record or exit loop. */    if (filt_err < best_err) {      best_err = filt_err;      best_filt_val = filt_val;    } else {      break;    }     /* Adjust filter level */    filt_val -= 1 + (filt_val > 10);  }   /* Search up (note that we have already done filt_val = cm->filter_level) */  filt_val = cm->filter_level + 1 + (filt_val > 10);   if (best_filt_val == cm->filter_level) {    /* Resist raising filter level for very small gains */    best_err -= (best_err >> 10);     while (filt_val < max_filter_level) {      /* Apply the loop filter */      yv12_copy_partial_frame(saved_frame, cm->frame_to_show);       vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val);       /* Get the err for filtered frame */      filt_err = calc_partial_ssl_err(sd, cm->frame_to_show);       /* Update the best case record or exit loop. */      if (filt_err < best_err) {        /* Do not raise filter level if improvement is < 1 part         * in 4096         */        best_err = filt_err - (filt_err >> 10);         best_filt_val = filt_val;      } else {        break;      }       /* Adjust filter level */      filt_val += 1 + (filt_val > 10);    }  }   cm->filter_level = best_filt_val;   if (cm->filter_level < min_filter_level) cm->filter_level = min_filter_level;   if (cm->filter_level > max_filter_level) cm->filter_level = max_filter_level;   /* restore unfiltered frame pointer */  cm->frame_to_show = saved_frame;} /* Stub function for now Alt LF not used */void vp8cx_set_alt_lf_level(VP8_COMP *cpi, int filt_val) {  MACROBLOCKD *mbd = &cpi->mb.e_mbd;  (void)filt_val;   mbd->segment_feature_data[MB_LVL_ALT_LF][0] =      cpi->segment_feature_data[MB_LVL_ALT_LF][0];  mbd->segment_feature_data[MB_LVL_ALT_LF][1] =      cpi->segment_feature_data[MB_LVL_ALT_LF][1];  mbd->segment_feature_data[MB_LVL_ALT_LF][2] =      cpi->segment_feature_data[MB_LVL_ALT_LF][2];  mbd->segment_feature_data[MB_LVL_ALT_LF][3] =      cpi->segment_feature_data[MB_LVL_ALT_LF][3];} void vp8cx_pick_filter_level(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi) {  VP8_COMMON *cm = &cpi->common;   int best_err = 0;  int filt_err = 0;  int min_filter_level = get_min_filter_level(cpi, cm->base_qindex);  int max_filter_level = get_max_filter_level(cpi, cm->base_qindex);   int filter_step;  int filt_high = 0;  int filt_mid;  int filt_low = 0;  int filt_best;  int filt_direction = 0;   /* Bias against raising loop filter and in favor of lowering it */  int Bias = 0;   int ss_err[MAX_LOOP_FILTER + 1];   YV12_BUFFER_CONFIG *saved_frame = cm->frame_to_show;   memset(ss_err, 0, sizeof(ss_err));   /* Replace unfiltered frame buffer with a new one */  cm->frame_to_show = &cpi->pick_lf_lvl_frame;   if (cm->frame_type == KEY_FRAME) {    cm->sharpness_level = 0;  } else {    cm->sharpness_level = cpi->oxcf.Sharpness;  }   /* Start the search at the previous frame filter level unless it is   * now out of range.   */  filt_mid = cm->filter_level;   if (filt_mid < min_filter_level) {    filt_mid = min_filter_level;  } else if (filt_mid > max_filter_level) {    filt_mid = max_filter_level;  }   /* Define the initial step size */  filter_step = (filt_mid < 16) ? 4 : filt_mid / 4;   /* Get baseline error score */   /* Copy the unfiltered / processed recon buffer to the new buffer */  vpx_yv12_copy_y(saved_frame, cm->frame_to_show);   vp8cx_set_alt_lf_level(cpi, filt_mid);  vp8_loop_filter_frame_yonly(cm, &cpi->mb.e_mbd, filt_mid);   best_err = vp8_calc_ss_err(sd, cm->frame_to_show);   ss_err[filt_mid] = best_err;   filt_best = filt_mid;   while (filter_step > 0) {    Bias = (best_err >> (15 - (filt_mid / 8))) * filter_step;     if (cpi->twopass.section_intra_rating < 20) {      Bias = Bias * cpi->twopass.section_intra_rating / 20;    }     filt_high = ((filt_mid + filter_step) > max_filter_level)                    ? max_filter_level                    : (filt_mid + filter_step);    filt_low = ((filt_mid - filter_step) < min_filter_level)                   ? min_filter_level                   : (filt_mid - filter_step);     if ((filt_direction <= 0) && (filt_low != filt_mid)) {      if (ss_err[filt_low] == 0) {        /* Get Low filter error score */        vpx_yv12_copy_y(saved_frame, cm->frame_to_show);        vp8cx_set_alt_lf_level(cpi, filt_low);        vp8_loop_filter_frame_yonly(cm, &cpi->mb.e_mbd, filt_low);         filt_err = vp8_calc_ss_err(sd, cm->frame_to_show);        ss_err[filt_low] = filt_err;      } else {        filt_err = ss_err[filt_low];      }       /* If value is close to the best so far then bias towards a       * lower loop filter value.       */      if ((filt_err - Bias) < best_err) {        /* Was it actually better than the previous best? */        if (filt_err < best_err) best_err = filt_err;         filt_best = filt_low;      }    }     /* Now look at filt_high */    if ((filt_direction >= 0) && (filt_high != filt_mid)) {      if (ss_err[filt_high] == 0) {        vpx_yv12_copy_y(saved_frame, cm->frame_to_show);        vp8cx_set_alt_lf_level(cpi, filt_high);        vp8_loop_filter_frame_yonly(cm, &cpi->mb.e_mbd, filt_high);         filt_err = vp8_calc_ss_err(sd, cm->frame_to_show);        ss_err[filt_high] = filt_err;      } else {        filt_err = ss_err[filt_high];      }       /* Was it better than the previous best? */      if (filt_err < (best_err - Bias)) {        best_err = filt_err;        filt_best = filt_high;      }    }     /* Half the step distance if the best filter value was the same     * as last time     */    if (filt_best == filt_mid) {      filter_step = filter_step / 2;      filt_direction = 0;    } else {      filt_direction = (filt_best < filt_mid) ? -1 : 1;      filt_mid = filt_best;    }  }   cm->filter_level = filt_best;   /* restore unfiltered frame pointer */  cm->frame_to_show = saved_frame;}

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