Commit 8b0a5b87 authored by Debargha Mukherjee's avatar Debargha Mukherjee

Adding loop wiener restoration

Adds a wiener filter based restoration scheme in loop which can
be optionally selected instead of the bilateral filter.

The LMMSE filter generated per frame is a separable symmetric 7
tap filter. Three parameters for each of horizontal and vertical
filters are transmitted in the bitstream. The fourth parameter
is obtained assuming the sum is normalized to 1.
Also integerizes the bilateral filters, along with other
refactoring necessary in order to support the new switchable
restoration type framework.

derflr: -0.75% BDRATE

[A lot of videos still prefer bilateral, however since many frames
now use the simpler separable filter, the decoding speed is
much better].

Further experiments to follow, related to replacing the bilateral.

Change-Id: I6b1879983d50aab7ec5647340b6aef6b22299636
parent 13efa8a0
......@@ -1568,8 +1568,7 @@ void vp10_setup_past_independence(VP10_COMMON *cm) {
// To force update of the sharpness
lf->last_sharpness_level = -1;
#if CONFIG_LOOP_RESTORATION
lf->restoration_level = 0;
lf->last_restoration_level = 0;
cm->rst_info.restoration_level = -1;
#endif // CONFIG_LOOP_RESTORATION
vp10_default_coef_probs(cm);
......
......@@ -52,11 +52,6 @@ struct loopfilter {
// 0 = ZERO_MV, MV
signed char mode_deltas[MAX_MODE_LF_DELTAS];
signed char last_mode_deltas[MAX_MODE_LF_DELTAS];
#if CONFIG_LOOP_RESTORATION
int restoration_level;
int last_restoration_level;
#endif // CONFIG_LOOP_RESTORATION
};
// Need to align this structure so when it is declared and
......
......@@ -258,7 +258,8 @@ typedef struct VP10Common {
loop_filter_info_n lf_info;
#if CONFIG_LOOP_RESTORATION
restoration_info_n rst_info;
RestorationInfo rst_info;
RestorationInternal rst_internal;
#endif // CONFIG_LOOP_RESTORATION
// Flag signaling how frame contexts should be updated at the end of
......
This diff is collapsed.
......@@ -26,74 +26,54 @@ extern "C" {
#define RESTORATION_LEVELS (1 << RESTORATION_LEVEL_BITS)
#define DEF_RESTORATION_LEVEL 2
#define RESTORATION_PRECISION 16
#define RESTORATION_HALFWIN 3
#define RESTORATION_HALFWIN1 (RESTORATION_HALFWIN + 1)
#define RESTORATION_WIN (2 * RESTORATION_HALFWIN + 1)
#define RESTORATION_WIN2 ((RESTORATION_WIN) * (RESTORATION_WIN))
typedef struct restoration_params {
int sigma_x; // spatial variance x
int sigma_y; // spatial variance y
int sigma_r; // range variance
} restoration_params_t;
#define RESTORATION_FILT_BITS 7
#define RESTORATION_FILT_STEP (1 << RESTORATION_FILT_BITS)
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},
};
#define WIENER_FILT_TAP0_MINV 3
#define WIENER_FILT_TAP1_MINV (-23)
#define WIENER_FILT_TAP2_MINV 5
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},
};
#define WIENER_FILT_TAP0_BITS 2
#define WIENER_FILT_TAP1_BITS 4
#define WIENER_FILT_TAP2_BITS 5
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;
#define WIENER_FILT_TAP0_MAXV \
(WIENER_FILT_TAP0_MINV -1 + (1 << WIENER_FILT_TAP0_BITS))
#define WIENER_FILT_TAP1_MAXV \
(WIENER_FILT_TAP1_MINV -1 + (1 << WIENER_FILT_TAP1_BITS))
#define WIENER_FILT_TAP2_MAXV \
(WIENER_FILT_TAP2_MINV -1 + (1 << WIENER_FILT_TAP2_BITS))
typedef enum {
RESTORE_NONE,
RESTORE_BILATERAL,
RESTORE_WIENER,
} RestorationType;
int vp10_restoration_level_bits(const struct VP10Common *const cm);
int vp10_loop_restoration_used(int level, int kf);
typedef struct {
RestorationType restoration_type;
int restoration_level;
int vfilter[RESTORATION_HALFWIN], hfilter[RESTORATION_HALFWIN];
} RestorationInfo;
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];
}
typedef struct {
RestorationType restoration_type;
uint8_t *wx_lut[RESTORATION_WIN];
uint8_t *wr_lut;
int vfilter[RESTORATION_WIN], hfilter[RESTORATION_WIN];
} RestorationInternal;
void vp10_loop_restoration_init(restoration_info_n *rst, int T, int kf);
int vp10_restoration_level_bits(const struct VP10Common *const cm);
void vp10_loop_restoration_init(RestorationInternal *rst,
RestorationInfo *rsi, int kf);
void vp10_loop_restoration_frame(YV12_BUFFER_CONFIG *frame,
struct VP10Common *cm,
int restoration_level,
RestorationInfo *rsi,
int y_only, int partial_frame);
void vp10_loop_restoration_rows(YV12_BUFFER_CONFIG *frame,
struct VP10Common *cm,
......
......@@ -2126,6 +2126,36 @@ static void setup_segmentation(VP10_COMMON *const cm,
}
}
#if CONFIG_LOOP_RESTORATION
static void setup_restoration(VP10_COMMON *cm,
struct vpx_read_bit_buffer *rb) {
RestorationInfo *rst = &cm->rst_info;
if (vpx_rb_read_bit(rb)) {
if (vpx_rb_read_bit(rb)) {
rst->restoration_type = RESTORE_BILATERAL;
rst->restoration_level =
vpx_rb_read_literal(rb, vp10_restoration_level_bits(cm));
} else {
rst->restoration_type = RESTORE_WIENER;
rst->vfilter[0] = vpx_rb_read_literal(rb, WIENER_FILT_TAP0_BITS) +
WIENER_FILT_TAP0_MINV;
rst->vfilter[1] = vpx_rb_read_literal(rb, WIENER_FILT_TAP1_BITS) +
WIENER_FILT_TAP1_MINV;
rst->vfilter[2] = vpx_rb_read_literal(rb, WIENER_FILT_TAP2_BITS) +
WIENER_FILT_TAP2_MINV;
rst->hfilter[0] = vpx_rb_read_literal(rb, WIENER_FILT_TAP0_BITS) +
WIENER_FILT_TAP0_MINV;
rst->hfilter[1] = vpx_rb_read_literal(rb, WIENER_FILT_TAP1_BITS) +
WIENER_FILT_TAP1_MINV;
rst->hfilter[2] = vpx_rb_read_literal(rb, WIENER_FILT_TAP2_BITS) +
WIENER_FILT_TAP2_MINV;
}
} else {
rst->restoration_type = RESTORE_NONE;
}
}
#endif // CONFIG_LOOP_RESTORATION
static void setup_loopfilter(VP10_COMMON *cm,
struct vpx_read_bit_buffer *rb) {
struct loopfilter *lf = &cm->lf;
......@@ -2151,19 +2181,6 @@ static void setup_loopfilter(VP10_COMMON *cm,
lf->mode_deltas[i] = vpx_rb_read_inv_signed_literal(rb, 6);
}
}
#if CONFIG_LOOP_RESTORATION
lf->restoration_level = vpx_rb_read_bit(rb);
if (lf->restoration_level) {
int level = vpx_rb_read_literal(rb, vp10_restoration_level_bits(cm));
lf->restoration_level = level + (level >= lf->last_restoration_level);
} else {
lf->restoration_level = lf->last_restoration_level;
}
if (cm->frame_type != KEY_FRAME)
cm->lf.last_restoration_level = cm->lf.restoration_level;
else
cm->lf.last_restoration_level = 0;
#endif // CONFIG_LOOP_RESTORATION
}
static INLINE int read_delta_q(struct vpx_read_bit_buffer *rb) {
......@@ -3135,6 +3152,9 @@ static size_t read_uncompressed_header(VP10Decoder *pbi,
vp10_setup_past_independence(cm);
setup_loopfilter(cm, rb);
#if CONFIG_LOOP_RESTORATION
setup_restoration(cm, rb);
#endif // CONFIG_LOOP_RESTORATION
setup_quantization(cm, rb);
#if CONFIG_VP9_HIGHBITDEPTH
xd->bd = (int)cm->bit_depth;
......@@ -3499,9 +3519,10 @@ void vp10_decode_frame(VP10Decoder *pbi,
*p_data_end = decode_tiles(pbi, data + first_partition_size, data_end);
}
#if CONFIG_LOOP_RESTORATION
vp10_loop_restoration_init(&cm->rst_info, cm->lf.restoration_level,
cm->frame_type == KEY_FRAME);
if (cm->rst_info.restoration_used) {
if (cm->rst_info.restoration_type != RESTORE_NONE) {
vp10_loop_restoration_init(&cm->rst_internal,
&cm->rst_info,
cm->frame_type == KEY_FRAME);
vp10_loop_restoration_rows(new_fb, cm, 0, cm->mi_rows, 0);
}
#endif // CONFIG_LOOP_RESTORATION
......
......@@ -1795,6 +1795,35 @@ static void update_coef_probs(VP10_COMP *cpi, vpx_writer* w) {
}
}
#if CONFIG_LOOP_RESTORATION
static void encode_restoration(VP10_COMMON *cm,
struct vpx_write_bit_buffer *wb) {
RestorationInfo *rst = &cm->rst_info;
vpx_wb_write_bit(wb, rst->restoration_type != RESTORE_NONE);
if (rst->restoration_type != RESTORE_NONE) {
if (rst->restoration_type == RESTORE_BILATERAL) {
vpx_wb_write_bit(wb, 1);
vpx_wb_write_literal(wb, rst->restoration_level,
vp10_restoration_level_bits(cm));
} else {
vpx_wb_write_bit(wb, 0);
vpx_wb_write_literal(
wb, rst->vfilter[0] - WIENER_FILT_TAP0_MINV, WIENER_FILT_TAP0_BITS);
vpx_wb_write_literal(
wb, rst->vfilter[1] - WIENER_FILT_TAP1_MINV, WIENER_FILT_TAP1_BITS);
vpx_wb_write_literal(
wb, rst->vfilter[2] - WIENER_FILT_TAP2_MINV, WIENER_FILT_TAP2_BITS);
vpx_wb_write_literal(
wb, rst->hfilter[0] - WIENER_FILT_TAP0_MINV, WIENER_FILT_TAP0_BITS);
vpx_wb_write_literal(
wb, rst->hfilter[1] - WIENER_FILT_TAP1_MINV, WIENER_FILT_TAP1_BITS);
vpx_wb_write_literal(
wb, rst->hfilter[2] - WIENER_FILT_TAP2_MINV, WIENER_FILT_TAP2_BITS);
}
}
}
#endif // CONFIG_LOOP_RESTORATION
static void encode_loopfilter(VP10_COMMON *cm,
struct vpx_write_bit_buffer *wb) {
int i;
......@@ -1832,15 +1861,6 @@ static void encode_loopfilter(VP10_COMMON *cm,
}
}
}
#if CONFIG_LOOP_RESTORATION
vpx_wb_write_bit(wb, lf->restoration_level != lf->last_restoration_level);
if (lf->restoration_level != lf->last_restoration_level) {
int level = lf->restoration_level -
(lf->restoration_level > lf->last_restoration_level);
vpx_wb_write_literal(wb, level,
vp10_restoration_level_bits(cm));
}
#endif // CONFIG_LOOP_RESTORATION
}
static void write_delta_q(struct vpx_write_bit_buffer *wb, int delta_q) {
......@@ -2300,6 +2320,9 @@ static void write_uncompressed_header(VP10_COMP *cpi,
vpx_wb_write_literal(wb, cm->frame_context_idx, FRAME_CONTEXTS_LOG2);
encode_loopfilter(cm, wb);
#if CONFIG_LOOP_RESTORATION
encode_restoration(cm, wb);
#endif // CONFIG_LOOP_RESTORATION
encode_quantization(cm, wb);
encode_segmentation(cm, xd, wb);
if (!cm->seg.enabled && xd->lossless[0])
......
......@@ -36,6 +36,9 @@
#include "vp10/encoder/firstpass.h"
#include "vp10/encoder/mbgraph.h"
#include "vp10/encoder/picklpf.h"
#if CONFIG_LOOP_RESTORATION
#include "vp10/encoder/pickrst.h"
#endif // CONFIG_LOOP_RESTORATION
#include "vp10/encoder/ratectrl.h"
#include "vp10/encoder/rd.h"
#include "vp10/encoder/resize.h"
......@@ -2738,7 +2741,11 @@ static void loopfilter_frame(VP10_COMP *cpi, VP10_COMMON *cm) {
vpx_usec_timer_start(&timer);
#if CONFIG_LOOP_RESTORATION
vp10_pick_filter_restoration(cpi->Source, cpi, cpi->sf.lpf_pick);
#else
vp10_pick_filter_level(cpi->Source, cpi, cpi->sf.lpf_pick);
#endif // CONFIG_LOOP_RESTORATION
vpx_usec_timer_mark(&timer);
cpi->time_pick_lpf += vpx_usec_timer_elapsed(&timer);
......@@ -2758,10 +2765,11 @@ static void loopfilter_frame(VP10_COMP *cpi, VP10_COMMON *cm) {
#endif
}
#if CONFIG_LOOP_RESTORATION
vp10_loop_restoration_init(&cm->rst_info, cm->lf.restoration_level,
cm->frame_type == KEY_FRAME);
if (cm->rst_info.restoration_used)
if (cm->rst_info.restoration_type != RESTORE_NONE) {
vp10_loop_restoration_init(&cm->rst_internal, &cm->rst_info,
cm->frame_type == KEY_FRAME);
vp10_loop_restoration_rows(cm->frame_to_show, cm, 0, cm->mi_rows, 0);
}
#endif // CONFIG_LOOP_RESTORATION
vpx_extend_frame_inner_borders(cm->frame_to_show);
......@@ -3871,12 +3879,6 @@ static void encode_frame_to_data_rate(VP10_COMP *cpi,
cm->last2_frame_type = cm->last_frame_type;
#endif // CONFIG_EXT_REFS
cm->last_frame_type = cm->frame_type;
#if CONFIG_LOOP_RESTORATION
if (cm->frame_type != KEY_FRAME)
cm->lf.last_restoration_level = cm->lf.restoration_level;
else
cm->lf.last_restoration_level = 0;
#endif // CONFIG_LOOP_RESTORATION
vp10_rc_postencode_update(cpi, *size);
......
This diff is collapsed.
......@@ -20,9 +20,11 @@ extern "C" {
struct yv12_buffer_config;
struct VP10_COMP;
int vp10_get_max_filter_level(const VP10_COMP *cpi);
int vp10_search_filter_level(const YV12_BUFFER_CONFIG *sd, VP10_COMP *cpi,
int partial_frame, double *err);
void vp10_pick_filter_level(const struct yv12_buffer_config *sd,
struct VP10_COMP *cpi, LPF_PICK_METHOD method);
struct VP10_COMP *cpi, LPF_PICK_METHOD method);
#ifdef __cplusplus
} // extern "C"
#endif
......
This diff is collapsed.
/*
* 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.
*/
#ifndef VP10_ENCODER_PICKRST_H_
#define VP10_ENCODER_PICKRST_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "vp10/encoder/encoder.h"
struct yv12_buffer_config;
struct VP10_COMP;
void vp10_pick_filter_restoration(
const YV12_BUFFER_CONFIG *sd, VP10_COMP *cpi, LPF_PICK_METHOD method);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP10_ENCODER_PICKRST_H_
......@@ -57,6 +57,8 @@ VP10_CX_SRCS-yes += encoder/palette.h
VP10_CX_SRCS-yes += encoder/palette.c
VP10_CX_SRCS-yes += encoder/picklpf.c
VP10_CX_SRCS-yes += encoder/picklpf.h
VP10_CX_SRCS-$(CONFIG_LOOP_RESTORATION) += encoder/pickrst.c
VP10_CX_SRCS-$(CONFIG_LOOP_RESTORATION) += encoder/pickrst.h
VP10_CX_SRCS-yes += encoder/quantize.c
VP10_CX_SRCS-yes += encoder/ratectrl.c
VP10_CX_SRCS-yes += encoder/rd.c
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment