#include "vp10/common/loopfilter.h"
#include "vp10/common/onyxc_int.h"
#include "vp10/common/reconinter.h"
+#include "vp10/common/restoration.h"
#include "vpx_dsp/vpx_dsp_common.h"
#include "vpx_mem/vpx_mem.h"
#include "vpx_ports/mem.h"
#endif // CONFIG_EXT_INTER
};
-#if CONFIG_LOOP_RESTORATION
-#define RESTORATION_RANGE 256
-#define RESTORATION_RANGE_SYM (2 * RESTORATION_RANGE + 1)
-static double restoration_filters_r_kf[RESTORATION_LEVELS_KF + 1]
- [RESTORATION_RANGE_SYM];
-static double restoration_filters_r[RESTORATION_LEVELS + 1]
- [RESTORATION_RANGE_SYM];
-static double restoration_filters_s_kf[RESTORATION_LEVELS_KF + 1]
- [RESTORATION_WIN][RESTORATION_WIN];
-static double restoration_filters_s[RESTORATION_LEVELS + 1]
- [RESTORATION_WIN][RESTORATION_WIN];
-
-void vp10_loop_restoration_precal() {
- int i;
- for (i = 1; i < RESTORATION_LEVELS_KF + 1; i ++) {
- const restoration_params_t param = vp10_restoration_level_to_params(i, 1);
- const int sigma_x = param.sigma_x;
- const int sigma_y = param.sigma_y;
- const int sigma_r = param.sigma_r;
- const double sigma_r_d = (double)sigma_r / RESTORATION_PRECISION;
- const double sigma_x_d = (double)sigma_x / RESTORATION_PRECISION;
- const double sigma_y_d = (double)sigma_y / RESTORATION_PRECISION;
-
- double *fr = restoration_filters_r_kf[i] + RESTORATION_RANGE;
- int j, x, y;
- for (j = 0; j <= RESTORATION_RANGE; j++) {
- fr[j] = exp(-(j * j) / (2 * sigma_r_d * sigma_r_d));
- fr[-j] = fr[j];
- }
- for (y = -RESTORATION_HALFWIN; y <= RESTORATION_HALFWIN; y++) {
- for (x = -RESTORATION_HALFWIN; x <= RESTORATION_HALFWIN; x++) {
- restoration_filters_s_kf[i][y + RESTORATION_HALFWIN]
- [x + RESTORATION_HALFWIN] =
- exp(-(x * x) / (2 * sigma_x_d * sigma_x_d)
- -(y * y) / (2 * sigma_y_d * sigma_y_d));
- }
- }
- }
- for (i = 1; i < RESTORATION_LEVELS + 1; i ++) {
- const restoration_params_t param = vp10_restoration_level_to_params(i, 0);
- const int sigma_x = param.sigma_x;
- const int sigma_y = param.sigma_y;
- const int sigma_r = param.sigma_r;
- const double sigma_r_d = (double)sigma_r / RESTORATION_PRECISION;
- const double sigma_x_d = (double)sigma_x / RESTORATION_PRECISION;
- const double sigma_y_d = (double)sigma_y / RESTORATION_PRECISION;
-
- double *fr = restoration_filters_r[i] + RESTORATION_RANGE;
- int j, x, y;
- for (j = 0; j <= RESTORATION_RANGE; j++) {
- fr[j] = exp(-(j * j) / (2 * sigma_r_d * sigma_r_d));
- fr[-j] = fr[j];
- }
- for (y = -RESTORATION_HALFWIN; y <= RESTORATION_HALFWIN; y++) {
- for (x = -RESTORATION_HALFWIN; x <= RESTORATION_HALFWIN; x++) {
- restoration_filters_s
- [i][y + RESTORATION_HALFWIN][x + RESTORATION_HALFWIN] =
- exp(-(x * x) / (2 * sigma_x_d * sigma_x_d)
- -(y * y) / (2 * sigma_y_d * sigma_y_d));
- }
- }
- }
-}
-
-int vp10_restoration_level_bits(const VP10_COMMON *const cm) {
- return cm->frame_type == KEY_FRAME ?
- RESTORATION_LEVEL_BITS_KF : RESTORATION_LEVEL_BITS;
-}
-
-int vp10_loop_restoration_used(int level, int kf) {
- const restoration_params_t param =
- vp10_restoration_level_to_params(level, kf);
- return (param.sigma_x && param.sigma_y && param.sigma_r);
-}
-
-void vp10_loop_restoration_init(loop_filter_info_n *lfi, int level, int kf) {
- lfi->restoration_used = vp10_loop_restoration_used(level, kf);
-
- if (lfi->restoration_used) {
- int i;
- lfi->wr_lut = kf ? restoration_filters_r_kf[level] :
- restoration_filters_r[level];
- for (i = 0; i < RESTORATION_WIN; i++)
- lfi->wx_lut[i] = kf ? restoration_filters_s_kf[level][i] :
- restoration_filters_s[level][i];
- }
-}
-
-static int is_in_image(int x, int y, int width, int height) {
- return (x >= 0 && x < width && y >= 0 && y < height);
-}
-
-void loop_restoration_filter(uint8_t *data, int width, int height,
- int stride, loop_filter_info_n *lfi,
- uint8_t *tmpdata, int tmpstride) {
- int i, j;
- const double *wr_lut_ = lfi->wr_lut + RESTORATION_RANGE;
-
- uint8_t *data_p = data;
- uint8_t *tmpdata_p = tmpdata;
- for (i = 0; i < height; ++i) {
- for (j = 0; j < width; ++j) {
- int x, y;
- double flsum = 0, wtsum = 0, wt;
- uint8_t *data_p2 = data_p + j - RESTORATION_HALFWIN * stride;
- for (y = -RESTORATION_HALFWIN; y <= RESTORATION_HALFWIN; ++y) {
- for (x = -RESTORATION_HALFWIN; x <= RESTORATION_HALFWIN; ++x) {
- if (!is_in_image(j + x, i + y, width, height))
- continue;
- wt = lfi->wx_lut[y + RESTORATION_HALFWIN][x + RESTORATION_HALFWIN] *
- wr_lut_[data_p2[x] - data_p[j]];
- wtsum += wt;
- flsum += wt * data_p2[x];
- }
- data_p2 += stride;
- }
- assert(wtsum > 0);
- tmpdata_p[j] = clip_pixel((int)(flsum / wtsum + 0.5));
- }
- tmpdata_p += tmpstride;
- data_p += stride;
- }
-
- for (i = 0; i < height; ++i) {
- memcpy(data + i * stride, tmpdata + i * tmpstride,
- width * sizeof(*data));
- }
-}
-
-// Normalized non-separable filter where weights all sum to 1
-void loop_restoration_filter_norm(uint8_t *data, int width, int height,
- int stride, loop_filter_info_n *lfi,
- uint8_t *tmpdata, int tmpstride) {
- int i, j;
- uint8_t *data_p = data;
- uint8_t *tmpdata_p = tmpdata;
- for (i = RESTORATION_HALFWIN; i < height - RESTORATION_HALFWIN; ++i) {
- for (j = RESTORATION_HALFWIN; j < width - RESTORATION_HALFWIN; ++j) {
- int x, y;
- double flsum = 0;
- uint8_t *data_p2 = data_p + j - RESTORATION_HALFWIN * stride;
- for (y = -RESTORATION_HALFWIN; y <= RESTORATION_HALFWIN; ++y) {
- for (x = -RESTORATION_HALFWIN; x <= RESTORATION_HALFWIN; ++x) {
- flsum += data_p2[x] *
- lfi->wx_lut[y + RESTORATION_HALFWIN][x + RESTORATION_HALFWIN];
- }
- data_p2 += stride;
- }
- tmpdata_p[j] = clip_pixel((int)(flsum + 0.5));
- }
- tmpdata_p += tmpstride;
- data_p += stride;
- }
- for (i = 0; i < height; ++i) {
- memcpy(data + i * stride, tmpdata + i * tmpstride,
- width * sizeof(*data));
- }
-}
-
-#if CONFIG_VP9_HIGHBITDEPTH
-void loop_restoration_filter_highbd(uint8_t *data8, int width, int height,
- int stride, loop_filter_info_n *lfi,
- uint8_t *tmpdata8, int tmpstride,
- int bit_depth) {
- int i, j;
- const double *wr_lut_ = lfi->wr_lut + RESTORATION_RANGE;
-
- uint16_t *data = CONVERT_TO_SHORTPTR(data8);
- uint16_t *tmpdata = CONVERT_TO_SHORTPTR(tmpdata8);
- uint16_t *data_p = data;
- uint16_t *tmpdata_p = tmpdata;
- for (i = 0; i < height; ++i) {
- for (j = 0; j < width; ++j) {
- int x, y, diff_r;
- double flsum = 0, wtsum = 0, wt;
- uint16_t *data_p2 = data_p + j - RESTORATION_HALFWIN * stride;
-
- for (y = -RESTORATION_HALFWIN; y <= RESTORATION_HALFWIN; ++y) {
- for (x = -RESTORATION_HALFWIN; x <= RESTORATION_HALFWIN; ++x) {
- if (!is_in_image(j + x, i + y, width, height))
- continue;
-
- diff_r = (data_p2[x] - data_p[j]) >> (bit_depth - 8);
- assert(diff_r >= -RESTORATION_RANGE && diff_r <= RESTORATION_RANGE);
-
- wt = lfi->wx_lut[y + RESTORATION_HALFWIN][x + RESTORATION_HALFWIN] *
- wr_lut_[diff_r];
- wtsum += wt;
- flsum += wt * data_p2[x];
- }
- data_p2 += stride;
- }
-
- assert(wtsum > 0);
- tmpdata_p[j] = (int)(flsum / wtsum + 0.5);
- }
- tmpdata_p += tmpstride;
- data_p += stride;
- }
- for (i = 0; i < height; ++i) {
- memcpy(data + i * stride, tmpdata + i * tmpstride,
- width * sizeof(*data));
- }
-}
-
-// Normalized non-separable filter where weights all sum to 1
-void loop_restoration_filter_norm(uint8_t *data8, int width, int height,
- int stride, loop_filter_info_n *lfi,
- uint8_t *tmpdata8, int tmpstride) {
- int i, j;
- uint16_t *data = CONVERT_TO_SHORTPTR(data8);
- uint16_t *tmpdata = CONVERT_TO_SHORTPTR(tmpdata8);
- uint16_t *data_p = data;
- uint16_t *tmpdata_p = tmpdata;
- for (i = RESTORATION_HALFWIN; i < height - RESTORATION_HALFWIN; ++i) {
- for (j = RESTORATION_HALFWIN; j < width - RESTORATION_HALFWIN; ++j) {
- int x, y;
- double flsum = 0;
- uint16_t *data_p2 = data_p + j - RESTORATION_HALFWIN * stride;
- for (y = -RESTORATION_HALFWIN; y <= RESTORATION_HALFWIN; ++y) {
- for (x = -RESTORATION_HALFWIN; x <= RESTORATION_HALFWIN; ++x) {
- flsum += data_p2[x] *
- lfi->wx_lut[y + RESTORATION_HALFWIN][x + RESTORATION_HALFWIN];
- }
- data_p2 += stride;
- }
- tmpdata_p[j] = (int)(flsum + 0.5);
- }
- tmpdata_p += tmpstride;
- data_p += stride;
- }
- for (i = 0; i < height; ++i) {
- memcpy(data + i * stride, tmpdata + i * tmpstride,
- width * sizeof(*data));
- }
-}
-#endif // CONFIG_VP9_HIGHBITDEPTH
-
-void vp10_loop_restoration_rows(YV12_BUFFER_CONFIG *frame,
- VP10_COMMON *cm,
- int start_mi_row, int end_mi_row,
- int y_only) {
- const int ywidth = frame->y_crop_width;
- const int ystride = frame->y_stride;
- const int uvwidth = frame->uv_crop_width;
- const int uvstride = frame->uv_stride;
- const int ystart = start_mi_row << MI_SIZE_LOG2;
- const int uvstart = ystart >> cm->subsampling_y;
- int yend = end_mi_row << MI_SIZE_LOG2;
- int uvend = yend >> cm->subsampling_y;
- YV12_BUFFER_CONFIG *tmp_buf;
- yend = VPXMIN(yend, cm->height);
- uvend = VPXMIN(uvend, cm->subsampling_y ? (cm->height + 1) >> 1 : cm->height);
-
- if (vpx_realloc_frame_buffer(&cm->tmp_loop_buf, cm->width, cm->height,
- cm->subsampling_x, cm->subsampling_y,
-#if CONFIG_VP9_HIGHBITDEPTH
- cm->use_highbitdepth,
-#endif
- VP9_DEC_BORDER_IN_PIXELS, cm->byte_alignment,
- NULL, NULL, NULL) < 0)
- vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
- "Failed to allocate tmp restoration buffer");
-
- tmp_buf = &cm->tmp_loop_buf;
-
-#if CONFIG_VP9_HIGHBITDEPTH
- if (cm->use_highbitdepth)
- loop_restoration_filter_highbd(
- frame->y_buffer + ystart * ystride,
- ywidth, yend - ystart, ystride, &cm->lf_info,
- tmp_buf->y_buffer + ystart * tmp_buf->y_stride,
- tmp_buf->y_stride, cm->bit_depth);
- else
-#endif // CONFIG_VP9_HIGHBITDEPTH
- loop_restoration_filter(
- frame->y_buffer + ystart * ystride,
- ywidth, yend - ystart, ystride, &cm->lf_info,
- tmp_buf->y_buffer + ystart * tmp_buf->y_stride,
- tmp_buf->y_stride);
- if (!y_only) {
-#if CONFIG_VP9_HIGHBITDEPTH
- if (cm->use_highbitdepth) {
- loop_restoration_filter_highbd(
- frame->u_buffer + uvstart * uvstride,
- uvwidth, uvend - uvstart, uvstride, &cm->lf_info,
- tmp_buf->u_buffer + uvstart * tmp_buf->uv_stride,
- tmp_buf->uv_stride, cm->bit_depth);
- loop_restoration_filter_highbd(
- frame->v_buffer + uvstart * uvstride,
- uvwidth, uvend - uvstart, uvstride, &cm->lf_info,
- tmp_buf->v_buffer + uvstart * tmp_buf->uv_stride,
- tmp_buf->uv_stride, cm->bit_depth);
- } else {
-#endif // CONFIG_VP9_HIGHBITDEPTH
- loop_restoration_filter(
- frame->u_buffer + uvstart * uvstride,
- uvwidth, uvend - uvstart, uvstride, &cm->lf_info,
- tmp_buf->u_buffer + uvstart * tmp_buf->uv_stride,
- tmp_buf->uv_stride);
- loop_restoration_filter(
- frame->v_buffer + uvstart * uvstride,
- uvwidth, uvend - uvstart, uvstride, &cm->lf_info,
- tmp_buf->v_buffer + uvstart * tmp_buf->uv_stride,
- tmp_buf->uv_stride);
-#if CONFIG_VP9_HIGHBITDEPTH
- }
-#endif // CONFIG_VP9_HIGHBITDEPTH
- }
-}
-#endif // CONFIG_LOOP_RESTORATION
-
static void update_sharpness(loop_filter_info_n *lfi, int sharpness_lvl) {
int lvl;
// init hev threshold const vectors
for (lvl = 0; lvl <= MAX_LOOP_FILTER; lvl++)
memset(lfi->lfthr[lvl].hev_thr, (lvl >> 4), SIMD_WIDTH);
-
-#if CONFIG_LOOP_RESTORATION
- vp10_loop_restoration_precal();
-#endif // CONFIG_LOOP_RESTORATION
}
void vp10_loop_filter_frame_init(VP10_COMMON *cm, int default_filt_lvl) {
memcpy(lf_data->planes, planes, sizeof(lf_data->planes));
}
-#if CONFIG_LOOP_RESTORATION
-void vp10_loop_restoration_frame(YV12_BUFFER_CONFIG *frame,
- VP10_COMMON *cm,
- int restoration_level,
- int y_only, int partial_frame) {
- int start_mi_row, end_mi_row, mi_rows_to_filter;
- // const int loop_restoration_used = vp10_loop_restoration_used(
- // restoration_level, cm->frame_type == KEY_FRAME);
- vp10_loop_restoration_init(&cm->lf_info, restoration_level,
- cm->frame_type == KEY_FRAME);
- if (!cm->lf_info.restoration_used)
- return;
- start_mi_row = 0;
- mi_rows_to_filter = cm->mi_rows;
- if (partial_frame && cm->mi_rows > 8) {
- start_mi_row = cm->mi_rows >> 1;
- start_mi_row &= 0xfffffff8;
- mi_rows_to_filter = VPXMAX(cm->mi_rows / 8, 8);
- }
- end_mi_row = start_mi_row + mi_rows_to_filter;
- vp10_loop_restoration_rows(frame, cm, start_mi_row, end_mi_row, y_only);
-}
-#endif // CONFIG_LOOP_RESTORATION
-
int vp10_loop_filter_worker(LFWorkerData *const lf_data, void *unused) {
(void)unused;
vp10_loop_filter_rows(lf_data->frame_buffer, lf_data->cm, lf_data->planes,
#include "./vpx_config.h"
#include "vp10/common/blockd.h"
+#include "vp10/common/restoration.h"
#include "vp10/common/seg_common.h"
#ifdef __cplusplus
#define MAX_MODE_LF_DELTAS 2
-#if CONFIG_LOOP_RESTORATION
-#define RESTORATION_LEVEL_BITS_KF 4
-#define RESTORATION_LEVELS_KF (1 << RESTORATION_LEVEL_BITS_KF)
-#define RESTORATION_LEVEL_BITS 3
-#define RESTORATION_LEVELS (1 << RESTORATION_LEVEL_BITS)
-#define DEF_RESTORATION_LEVEL 2
-
-#define RESTORATION_PRECISION 16
-#define RESTORATION_HALFWIN 3
-#define RESTORATION_WIN (2 * RESTORATION_HALFWIN + 1)
-
-typedef struct restoration_params {
- int sigma_x; // spatial variance x
- int sigma_y; // spatial variance y
- int sigma_r; // range variance
-} restoration_params_t;
-
-static restoration_params_t
- restoration_level_to_params_arr[RESTORATION_LEVELS + 1] = {
- // Values are rounded to 1/16 th precision
- {0, 0, 0}, // 0 - default
- {8, 9, 30},
- {9, 8, 30},
- {9, 11, 32},
- {11, 9, 32},
- {14, 14, 32},
- {18, 18, 36},
- {24, 24, 40},
- {32, 32, 40},
-};
-
-static restoration_params_t
- restoration_level_to_params_arr_kf[RESTORATION_LEVELS_KF + 1] = {
- // Values are rounded to 1/16 th precision
- {0, 0, 0}, // 0 - default
- {8, 8, 30},
- {9, 9, 32},
- {10, 10, 32},
- {12, 12, 32},
- {14, 14, 32},
- {18, 18, 36},
- {24, 24, 40},
- {30, 30, 44},
- {36, 36, 48},
- {42, 42, 48},
- {48, 48, 48},
- {48, 48, 56},
- {56, 56, 48},
- {56, 56, 56},
- {56, 56, 64},
- {64, 64, 48},
-};
-
-int vp10_restoration_level_bits(const struct VP10Common *const cm);
-int vp10_loop_restoration_used(int level, int kf);
-
-static INLINE restoration_params_t vp10_restoration_level_to_params(
- int index, int kf) {
- return kf ? restoration_level_to_params_arr_kf[index] :
- restoration_level_to_params_arr[index];
-}
-#endif // CONFIG_LOOP_RESTORATION
-
enum lf_path {
LF_PATH_420,
LF_PATH_444,
typedef struct {
loop_filter_thresh lfthr[MAX_LOOP_FILTER + 1];
uint8_t lvl[MAX_SEGMENTS][MAX_REF_FRAMES][MAX_MODE_LF_DELTAS];
-#if CONFIG_LOOP_RESTORATION
- double *wx_lut[RESTORATION_WIN];
- double *wr_lut;
- int restoration_sigma_x_set;
- int restoration_sigma_y_set;
- int restoration_sigma_r_set;
- int restoration_used;
-#endif // CONFIG_LOOP_RESTORATION
} loop_filter_info_n;
// This structure holds bit masks for all 8x8 blocks in a 64x64 region.
struct macroblockd_plane planes[MAX_MB_PLANE],
int start, int stop, int y_only);
-#if CONFIG_LOOP_RESTORATION
-void vp10_loop_restoration_frame(YV12_BUFFER_CONFIG *frame,
- struct VP10Common *cm,
- int restoration_level,
- int y_only, int partial_frame);
-void vp10_loop_filter_restoration_frame(YV12_BUFFER_CONFIG *frame,
- struct VP10Common *cm,
- struct macroblockd *mbd,
- int frame_filter_level,
- int restoration_level,
- int y_only, int partial_frame);
-void vp10_loop_restoration_init(loop_filter_info_n *lfi, int T, int kf);
-void vp10_loop_restoration_rows(YV12_BUFFER_CONFIG *frame,
- struct VP10Common *cm,
- int start_mi_row, int end_mi_row,
- int y_only);
-#endif // CONFIG_LOOP_RESTORATION
-
typedef struct LoopFilterWorkerData {
YV12_BUFFER_CONFIG *frame_buffer;
struct VP10Common *cm;
#include "vp10/common/frame_buffers.h"
#include "vp10/common/quant_common.h"
#include "vp10/common/tile_common.h"
+#include "vp10/common/restoration.h"
#if CONFIG_VP9_POSTPROC
#include "vp10/common/postproc.h"
INTERP_FILTER interp_filter;
loop_filter_info_n lf_info;
+#if CONFIG_LOOP_RESTORATION
+ restoration_info_n rst_info;
+#endif // CONFIG_LOOP_RESTORATION
// Flag signaling how frame contexts should be updated at the end of
// a frame decode
--- /dev/null
+/*
+ * Copyright (c) 2016 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 <math.h>
+
+#include "./vpx_config.h"
+#include "./vpx_dsp_rtcd.h"
+#include "vp10/common/onyxc_int.h"
+#include "vp10/common/restoration.h"
+#include "vpx_dsp/vpx_dsp_common.h"
+#include "vpx_mem/vpx_mem.h"
+#include "vpx_ports/mem.h"
+
+#define RESTORATION_RANGE 256
+#define RESTORATION_RANGE_SYM (2 * RESTORATION_RANGE + 1)
+static double restoration_filters_r_kf[RESTORATION_LEVELS_KF + 1]
+ [RESTORATION_RANGE_SYM];
+static double restoration_filters_r[RESTORATION_LEVELS + 1]
+ [RESTORATION_RANGE_SYM];
+static double restoration_filters_s_kf[RESTORATION_LEVELS_KF + 1]
+ [RESTORATION_WIN][RESTORATION_WIN];
+static double restoration_filters_s[RESTORATION_LEVELS + 1]
+ [RESTORATION_WIN][RESTORATION_WIN];
+
+void vp10_loop_restoration_precal() {
+ int i;
+ for (i = 1; i < RESTORATION_LEVELS_KF + 1; i ++) {
+ const restoration_params_t param = vp10_restoration_level_to_params(i, 1);
+ const int sigma_x = param.sigma_x;
+ const int sigma_y = param.sigma_y;
+ const int sigma_r = param.sigma_r;
+ const double sigma_r_d = (double)sigma_r / RESTORATION_PRECISION;
+ const double sigma_x_d = (double)sigma_x / RESTORATION_PRECISION;
+ const double sigma_y_d = (double)sigma_y / RESTORATION_PRECISION;
+
+ double *fr = restoration_filters_r_kf[i] + RESTORATION_RANGE;
+ int j, x, y;
+ for (j = 0; j <= RESTORATION_RANGE; j++) {
+ fr[j] = exp(-(j * j) / (2 * sigma_r_d * sigma_r_d));
+ fr[-j] = fr[j];
+ }
+ for (y = -RESTORATION_HALFWIN; y <= RESTORATION_HALFWIN; y++) {
+ for (x = -RESTORATION_HALFWIN; x <= RESTORATION_HALFWIN; x++) {
+ restoration_filters_s_kf[i][y + RESTORATION_HALFWIN]
+ [x + RESTORATION_HALFWIN] =
+ exp(-(x * x) / (2 * sigma_x_d * sigma_x_d)
+ -(y * y) / (2 * sigma_y_d * sigma_y_d));
+ }
+ }
+ }
+ for (i = 1; i < RESTORATION_LEVELS + 1; i ++) {
+ const restoration_params_t param = vp10_restoration_level_to_params(i, 0);
+ const int sigma_x = param.sigma_x;
+ const int sigma_y = param.sigma_y;
+ const int sigma_r = param.sigma_r;
+ const double sigma_r_d = (double)sigma_r / RESTORATION_PRECISION;
+ const double sigma_x_d = (double)sigma_x / RESTORATION_PRECISION;
+ const double sigma_y_d = (double)sigma_y / RESTORATION_PRECISION;
+
+ double *fr = restoration_filters_r[i] + RESTORATION_RANGE;
+ int j, x, y;
+ for (j = 0; j <= RESTORATION_RANGE; j++) {
+ fr[j] = exp(-(j * j) / (2 * sigma_r_d * sigma_r_d));
+ fr[-j] = fr[j];
+ }
+ for (y = -RESTORATION_HALFWIN; y <= RESTORATION_HALFWIN; y++) {
+ for (x = -RESTORATION_HALFWIN; x <= RESTORATION_HALFWIN; x++) {
+ restoration_filters_s
+ [i][y + RESTORATION_HALFWIN][x + RESTORATION_HALFWIN] =
+ exp(-(x * x) / (2 * sigma_x_d * sigma_x_d)
+ -(y * y) / (2 * sigma_y_d * sigma_y_d));
+ }
+ }
+ }
+}
+
+int vp10_restoration_level_bits(const VP10_COMMON *const cm) {
+ return cm->frame_type == KEY_FRAME ?
+ RESTORATION_LEVEL_BITS_KF : RESTORATION_LEVEL_BITS;
+}
+
+int vp10_loop_restoration_used(int level, int kf) {
+ const restoration_params_t param =
+ vp10_restoration_level_to_params(level, kf);
+ return (param.sigma_x && param.sigma_y && param.sigma_r);
+}
+
+void vp10_loop_restoration_init(restoration_info_n *rst,
+ int level, int kf) {
+ rst->restoration_used = vp10_loop_restoration_used(level, kf);
+
+ if (rst->restoration_used) {
+ int i;
+ rst->wr_lut = kf ? restoration_filters_r_kf[level] :
+ restoration_filters_r[level];
+ for (i = 0; i < RESTORATION_WIN; i++)
+ rst->wx_lut[i] = kf ? restoration_filters_s_kf[level][i] :
+ restoration_filters_s[level][i];
+ }
+}
+
+static int is_in_image(int x, int y, int width, int height) {
+ return (x >= 0 && x < width && y >= 0 && y < height);
+}
+
+static void loop_restoration_filter(uint8_t *data, int width, int height,
+ int stride, restoration_info_n *rst,
+ uint8_t *tmpdata, int tmpstride) {
+ int i, j;
+ const double *wr_lut_ = rst->wr_lut + RESTORATION_RANGE;
+
+ uint8_t *data_p = data;
+ uint8_t *tmpdata_p = tmpdata;
+ for (i = 0; i < height; ++i) {
+ for (j = 0; j < width; ++j) {
+ int x, y;
+ double flsum = 0, wtsum = 0, wt;
+ uint8_t *data_p2 = data_p + j - RESTORATION_HALFWIN * stride;
+ for (y = -RESTORATION_HALFWIN; y <= RESTORATION_HALFWIN; ++y) {
+ for (x = -RESTORATION_HALFWIN; x <= RESTORATION_HALFWIN; ++x) {
+ if (!is_in_image(j + x, i + y, width, height))
+ continue;
+ wt = rst->wx_lut[y + RESTORATION_HALFWIN][x + RESTORATION_HALFWIN] *
+ wr_lut_[data_p2[x] - data_p[j]];
+ wtsum += wt;
+ flsum += wt * data_p2[x];
+ }
+ data_p2 += stride;
+ }
+ assert(wtsum > 0);
+ tmpdata_p[j] = clip_pixel((int)(flsum / wtsum + 0.5));
+ }
+ tmpdata_p += tmpstride;
+ data_p += stride;
+ }
+
+ for (i = 0; i < height; ++i) {
+ memcpy(data + i * stride, tmpdata + i * tmpstride,
+ width * sizeof(*data));
+ }
+}
+
+// Normalized non-separable filter where weights all sum to 1
+static void loop_restoration_filter_norm(uint8_t *data, int width, int height,
+ int stride, restoration_info_n *rst,
+ uint8_t *tmpdata, int tmpstride) {
+ int i, j;
+ uint8_t *data_p = data;
+ uint8_t *tmpdata_p = tmpdata;
+ for (i = RESTORATION_HALFWIN; i < height - RESTORATION_HALFWIN; ++i) {
+ for (j = RESTORATION_HALFWIN; j < width - RESTORATION_HALFWIN; ++j) {
+ int x, y;
+ double flsum = 0;
+ uint8_t *data_p2 = data_p + j - RESTORATION_HALFWIN * stride;
+ for (y = -RESTORATION_HALFWIN; y <= RESTORATION_HALFWIN; ++y) {
+ for (x = -RESTORATION_HALFWIN; x <= RESTORATION_HALFWIN; ++x) {
+ flsum += data_p2[x] *
+ rst->wx_lut[y + RESTORATION_HALFWIN][x + RESTORATION_HALFWIN];
+ }
+ data_p2 += stride;
+ }
+ tmpdata_p[j] = clip_pixel((int)(flsum + 0.5));
+ }
+ tmpdata_p += tmpstride;
+ data_p += stride;
+ }
+ for (i = 0; i < height; ++i) {
+ memcpy(data + i * stride, tmpdata + i * tmpstride,
+ width * sizeof(*data));
+ }
+}
+
+#if CONFIG_VP9_HIGHBITDEPTH
+static void loop_restoration_filter_highbd(
+ uint8_t *data8, int width, int height,
+ int stride, restoration_info_n *rst,
+ uint8_t *tmpdata8, int tmpstride, int bit_depth) {
+ int i, j;
+ const double *wr_lut_ = rst->wr_lut + RESTORATION_RANGE;
+
+ uint16_t *data = CONVERT_TO_SHORTPTR(data8);
+ uint16_t *tmpdata = CONVERT_TO_SHORTPTR(tmpdata8);
+ uint16_t *data_p = data;
+ uint16_t *tmpdata_p = tmpdata;
+ for (i = 0; i < height; ++i) {
+ for (j = 0; j < width; ++j) {
+ int x, y, diff_r;
+ double flsum = 0, wtsum = 0, wt;
+ uint16_t *data_p2 = data_p + j - RESTORATION_HALFWIN * stride;
+
+ for (y = -RESTORATION_HALFWIN; y <= RESTORATION_HALFWIN; ++y) {
+ for (x = -RESTORATION_HALFWIN; x <= RESTORATION_HALFWIN; ++x) {
+ if (!is_in_image(j + x, i + y, width, height))
+ continue;
+
+ diff_r = (data_p2[x] - data_p[j]) >> (bit_depth - 8);
+ assert(diff_r >= -RESTORATION_RANGE && diff_r <= RESTORATION_RANGE);
+
+ wt = rst->wx_lut[y + RESTORATION_HALFWIN][x + RESTORATION_HALFWIN] *
+ wr_lut_[diff_r];
+ wtsum += wt;
+ flsum += wt * data_p2[x];
+ }
+ data_p2 += stride;
+ }
+
+ assert(wtsum > 0);
+ tmpdata_p[j] = (int)(flsum / wtsum + 0.5);
+ }
+ tmpdata_p += tmpstride;
+ data_p += stride;
+ }
+ for (i = 0; i < height; ++i) {
+ memcpy(data + i * stride, tmpdata + i * tmpstride,
+ width * sizeof(*data));
+ }
+}
+
+// Normalized non-separable filter where weights all sum to 1
+static void loop_restoration_filter_norm_highbd(
+ uint8_t *data8, int width, int height,
+ int stride, restoration_info_n *rst,
+ uint8_t *tmpdata8, int tmpstride) {
+ int i, j;
+ uint16_t *data = CONVERT_TO_SHORTPTR(data8);
+ uint16_t *tmpdata = CONVERT_TO_SHORTPTR(tmpdata8);
+ uint16_t *data_p = data;
+ uint16_t *tmpdata_p = tmpdata;
+ for (i = RESTORATION_HALFWIN; i < height - RESTORATION_HALFWIN; ++i) {
+ for (j = RESTORATION_HALFWIN; j < width - RESTORATION_HALFWIN; ++j) {
+ int x, y;
+ double flsum = 0;
+ uint16_t *data_p2 = data_p + j - RESTORATION_HALFWIN * stride;
+ for (y = -RESTORATION_HALFWIN; y <= RESTORATION_HALFWIN; ++y) {
+ for (x = -RESTORATION_HALFWIN; x <= RESTORATION_HALFWIN; ++x) {
+ flsum += data_p2[x] *
+ rst->wx_lut[y + RESTORATION_HALFWIN][x + RESTORATION_HALFWIN];
+ }
+ data_p2 += stride;
+ }
+ tmpdata_p[j] = (int)(flsum + 0.5);
+ }
+ tmpdata_p += tmpstride;
+ data_p += stride;
+ }
+ for (i = 0; i < height; ++i) {
+ memcpy(data + i * stride, tmpdata + i * tmpstride,
+ width * sizeof(*data));
+ }
+}
+#endif // CONFIG_VP9_HIGHBITDEPTH
+
+void vp10_loop_restoration_rows(YV12_BUFFER_CONFIG *frame,
+ VP10_COMMON *cm,
+ int start_mi_row, int end_mi_row,
+ int y_only) {
+ const int ywidth = frame->y_crop_width;
+ const int ystride = frame->y_stride;
+ const int uvwidth = frame->uv_crop_width;
+ const int uvstride = frame->uv_stride;
+ const int ystart = start_mi_row << MI_SIZE_LOG2;
+ const int uvstart = ystart >> cm->subsampling_y;
+ int yend = end_mi_row << MI_SIZE_LOG2;
+ int uvend = yend >> cm->subsampling_y;
+ YV12_BUFFER_CONFIG *tmp_buf;
+ yend = VPXMIN(yend, cm->height);
+ uvend = VPXMIN(uvend, cm->subsampling_y ? (cm->height + 1) >> 1 : cm->height);
+
+ if (vpx_realloc_frame_buffer(&cm->tmp_loop_buf, cm->width, cm->height,
+ cm->subsampling_x, cm->subsampling_y,
+#if CONFIG_VP9_HIGHBITDEPTH
+ cm->use_highbitdepth,
+#endif
+ VP9_DEC_BORDER_IN_PIXELS, cm->byte_alignment,
+ NULL, NULL, NULL) < 0)
+ vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
+ "Failed to allocate tmp restoration buffer");
+
+ tmp_buf = &cm->tmp_loop_buf;
+
+#if CONFIG_VP9_HIGHBITDEPTH
+ if (cm->use_highbitdepth)
+ loop_restoration_filter_highbd(
+ frame->y_buffer + ystart * ystride,
+ ywidth, yend - ystart, ystride, &cm->rst_info,
+ tmp_buf->y_buffer + ystart * tmp_buf->y_stride,
+ tmp_buf->y_stride, cm->bit_depth);
+ else
+#endif // CONFIG_VP9_HIGHBITDEPTH
+ loop_restoration_filter(
+ frame->y_buffer + ystart * ystride,
+ ywidth, yend - ystart, ystride, &cm->rst_info,
+ tmp_buf->y_buffer + ystart * tmp_buf->y_stride,
+ tmp_buf->y_stride);
+ if (!y_only) {
+#if CONFIG_VP9_HIGHBITDEPTH
+ if (cm->use_highbitdepth) {
+ loop_restoration_filter_highbd(
+ frame->u_buffer + uvstart * uvstride,
+ uvwidth, uvend - uvstart, uvstride, &cm->rst_info,
+ tmp_buf->u_buffer + uvstart * tmp_buf->uv_stride,
+ tmp_buf->uv_stride, cm->bit_depth);
+ loop_restoration_filter_highbd(
+ frame->v_buffer + uvstart * uvstride,
+ uvwidth, uvend - uvstart, uvstride, &cm->rst_info,
+ tmp_buf->v_buffer + uvstart * tmp_buf->uv_stride,
+ tmp_buf->uv_stride, cm->bit_depth);
+ } else {
+#endif // CONFIG_VP9_HIGHBITDEPTH
+ loop_restoration_filter(
+ frame->u_buffer + uvstart * uvstride,
+ uvwidth, uvend - uvstart, uvstride, &cm->rst_info,
+ tmp_buf->u_buffer + uvstart * tmp_buf->uv_stride,
+ tmp_buf->uv_stride);
+ loop_restoration_filter(
+ frame->v_buffer + uvstart * uvstride,
+ uvwidth, uvend - uvstart, uvstride, &cm->rst_info,
+ tmp_buf->v_buffer + uvstart * tmp_buf->uv_stride,
+ tmp_buf->uv_stride);
+#if CONFIG_VP9_HIGHBITDEPTH
+ }
+#endif // CONFIG_VP9_HIGHBITDEPTH
+ }
+}
+
+void vp10_loop_restoration_frame(YV12_BUFFER_CONFIG *frame,
+ VP10_COMMON *cm,
+ int restoration_level,
+ int y_only, int partial_frame) {
+ int start_mi_row, end_mi_row, mi_rows_to_filter;
+ vp10_loop_restoration_init(&cm->rst_info, restoration_level,
+ cm->frame_type == KEY_FRAME);
+ if (!cm->rst_info.restoration_used)
+ return;
+ start_mi_row = 0;
+ mi_rows_to_filter = cm->mi_rows;
+ if (partial_frame && cm->mi_rows > 8) {
+ start_mi_row = cm->mi_rows >> 1;
+ start_mi_row &= 0xfffffff8;
+ mi_rows_to_filter = VPXMAX(cm->mi_rows / 8, 8);
+ }
+ end_mi_row = start_mi_row + mi_rows_to_filter;
+ vp10_loop_restoration_rows(frame, cm, start_mi_row, end_mi_row, y_only);
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.
+ */
+
+#ifndef VP10_COMMON_RESTORATION_H_
+#define VP10_COMMON_RESTORATION_H_
+
+#include "vpx_ports/mem.h"
+#include "./vpx_config.h"
+
+#include "vp10/common/blockd.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RESTORATION_LEVEL_BITS_KF 4
+#define RESTORATION_LEVELS_KF (1 << RESTORATION_LEVEL_BITS_KF)
+#define RESTORATION_LEVEL_BITS 3
+#define RESTORATION_LEVELS (1 << RESTORATION_LEVEL_BITS)
+#define DEF_RESTORATION_LEVEL 2
+
+#define RESTORATION_PRECISION 16
+#define RESTORATION_HALFWIN 3
+#define RESTORATION_WIN (2 * RESTORATION_HALFWIN + 1)
+
+typedef struct restoration_params {
+ int sigma_x; // spatial variance x
+ int sigma_y; // spatial variance y
+ int sigma_r; // range variance
+} restoration_params_t;
+
+static restoration_params_t
+ restoration_level_to_params_arr[RESTORATION_LEVELS + 1] = {
+ // Values are rounded to 1/16 th precision
+ {0, 0, 0}, // 0 - default
+ {8, 9, 30},
+ {9, 8, 30},
+ {9, 11, 32},
+ {11, 9, 32},
+ {14, 14, 32},
+ {18, 18, 36},
+ {24, 24, 40},
+ {32, 32, 40},
+};
+
+static restoration_params_t
+ restoration_level_to_params_arr_kf[RESTORATION_LEVELS_KF + 1] = {
+ // Values are rounded to 1/16 th precision
+ {0, 0, 0}, // 0 - default
+ {8, 8, 30},
+ {9, 9, 32},
+ {10, 10, 32},
+ {12, 12, 32},
+ {14, 14, 32},
+ {18, 18, 36},
+ {24, 24, 40},
+ {30, 30, 44},
+ {36, 36, 48},
+ {42, 42, 48},
+ {48, 48, 48},
+ {48, 48, 56},
+ {56, 56, 48},
+ {56, 56, 56},
+ {56, 56, 64},
+ {64, 64, 48},
+};
+
+typedef struct {
+ double *wx_lut[RESTORATION_WIN];
+ double *wr_lut;
+ int restoration_sigma_x_set;
+ int restoration_sigma_y_set;
+ int restoration_sigma_r_set;
+ int restoration_used;
+} restoration_info_n;
+
+int vp10_restoration_level_bits(const struct VP10Common *const cm);
+int vp10_loop_restoration_used(int level, int kf);
+
+static INLINE restoration_params_t vp10_restoration_level_to_params(
+ int index, int kf) {
+ return kf ? restoration_level_to_params_arr_kf[index] :
+ restoration_level_to_params_arr[index];
+}
+
+void vp10_loop_restoration_init(restoration_info_n *rst, int T, int kf);
+void vp10_loop_restoration_frame(YV12_BUFFER_CONFIG *frame,
+ struct VP10Common *cm,
+ int restoration_level,
+ int y_only, int partial_frame);
+void vp10_loop_restoration_rows(YV12_BUFFER_CONFIG *frame,
+ struct VP10Common *cm,
+ int start_mi_row, int end_mi_row,
+ int y_only);
+void vp10_loop_restoration_precal();
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // VP10_COMMON_RESTORATION_H_
*p_data_end = decode_tiles(pbi, data + first_partition_size, data_end);
}
#if CONFIG_LOOP_RESTORATION
- vp10_loop_restoration_init(&cm->lf_info, cm->lf.restoration_level,
+ vp10_loop_restoration_init(&cm->rst_info, cm->lf.restoration_level,
cm->frame_type == KEY_FRAME);
- if (cm->lf_info.restoration_used) {
+ if (cm->rst_info.restoration_used) {
vp10_loop_restoration_rows(new_fb, cm, 0, cm->mi_rows, 0);
}
#endif // CONFIG_LOOP_RESTORATION
cm->setup_mi = vp10_dec_setup_mi;
vp10_loop_filter_init(cm);
+#if CONFIG_LOOP_RESTORATION
+ vp10_loop_restoration_precal();
+#endif // CONFIG_LOOP_RESTORATION
#if CONFIG_ANS
vp10_build_pareto8_dec_tab(vp10_pareto8_token_probs, pbi->token_tab);
#endif // CONFIG_ANS
vp10_init_quantizer(cpi);
vp10_loop_filter_init(cm);
+#if CONFIG_LOOP_RESTORATION
+ vp10_loop_restoration_precal();
+#endif // CONFIG_LOOP_RESTORATION
cm->error.setjmp = 0;
#endif
}
#if CONFIG_LOOP_RESTORATION
- vp10_loop_restoration_init(&cm->lf_info, cm->lf.restoration_level,
- cm->frame_type == KEY_FRAME);
- if (cm->lf_info.restoration_used)
+ vp10_loop_restoration_init(&cm->rst_info, cm->lf.restoration_level,
+ cm->frame_type == KEY_FRAME);
+ if (cm->rst_info.restoration_used)
vp10_loop_restoration_rows(cm->frame_to_show, cm, 0, cm->mi_rows, 0);
#endif // CONFIG_LOOP_RESTORATION
VP10_COMMON_SRCS-$(CONFIG_VP9_POSTPROC) += common/postproc.h
VP10_COMMON_SRCS-$(CONFIG_VP9_POSTPROC) += common/postproc.c
+VP10_COMMON_SRCS-$(CONFIG_LOOP_RESTORATION) += common/restoration.h
+VP10_COMMON_SRCS-$(CONFIG_LOOP_RESTORATION) += common/restoration.c
VP10_COMMON_SRCS-$(CONFIG_VP9_POSTPROC) += common/mfqe.h
VP10_COMMON_SRCS-$(CONFIG_VP9_POSTPROC) += common/mfqe.c
ifeq ($(CONFIG_VP9_POSTPROC),yes)