An experiment introducing a bilateral loop filter
Adds a framework to incorporate a parameterized loop postfilter in the coding loop after the application of the standard deblocking loop filter. The first version uses a straight bilateral filter where the parameters conveyed are just spatial and intensity gaussian variances. Results on derflr: +0.523% (only with this experiment) +6.714% (with all expts other than intrabc) Change-Id: I20d47285b4d25b8c6386ff8af2a75ff88ac2b69b
This commit is contained in:
1
configure
vendored
1
configure
vendored
@@ -296,6 +296,7 @@ EXPERIMENT_LIST="
|
|||||||
new_quant
|
new_quant
|
||||||
newmvref
|
newmvref
|
||||||
intrabc
|
intrabc
|
||||||
|
loop_postfilter
|
||||||
"
|
"
|
||||||
CONFIG_LIST="
|
CONFIG_LIST="
|
||||||
external_build
|
external_build
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const unsigned int kHeight = 90;
|
|||||||
const unsigned int kFramerate = 50;
|
const unsigned int kFramerate = 50;
|
||||||
const unsigned int kFrames = 10;
|
const unsigned int kFrames = 10;
|
||||||
const int kBitrate = 500;
|
const int kBitrate = 500;
|
||||||
const int kCpuUsed = 2;
|
const int kCpuUsed = 0;
|
||||||
const double psnr_threshold = 35.0;
|
const double psnr_threshold = 35.0;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@@ -122,6 +122,9 @@ void vp9_free_ref_frame_buffers(VP9_COMMON *cm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vp9_free_frame_buffer(&cm->post_proc_buffer);
|
vp9_free_frame_buffer(&cm->post_proc_buffer);
|
||||||
|
#if CONFIG_LOOP_POSTFILTER
|
||||||
|
vp9_free_frame_buffer(&cm->tmp_loop_buf);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void vp9_free_context_buffers(VP9_COMMON *cm) {
|
void vp9_free_context_buffers(VP9_COMMON *cm) {
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
* be found in the AUTHORS file in the root of the source tree.
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include "./vpx_config.h"
|
#include "./vpx_config.h"
|
||||||
#include "vp9/common/vp9_loopfilter.h"
|
#include "vp9/common/vp9_loopfilter.h"
|
||||||
#include "vp9/common/vp9_onyxc_int.h"
|
#include "vp9/common/vp9_onyxc_int.h"
|
||||||
@@ -227,6 +229,135 @@ static const int mode_lf_lut[MB_MODE_COUNT] = {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if CONFIG_LOOP_POSTFILTER
|
||||||
|
|
||||||
|
#define BILATERAL_WEIGHT_BITS 4
|
||||||
|
static const int bilateral_weight = (1 << BILATERAL_WEIGHT_BITS) - 1;
|
||||||
|
static const int bilateral_weight_round = 1 << (BILATERAL_WEIGHT_BITS - 1);
|
||||||
|
|
||||||
|
int vp9_bilateral_level_bits(const VP9_COMMON *const cm) {
|
||||||
|
return cm->frame_type == KEY_FRAME ?
|
||||||
|
BILATERAL_LEVEL_BITS_KF : BILATERAL_LEVEL_BITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vp9_loop_bilateral_used(int level, int kf) {
|
||||||
|
const bilateral_params_t param = vp9_bilateral_level_to_params(level, kf);
|
||||||
|
return (param.sigma_x && param.sigma_r);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vp9_loop_bilateral_init(loop_filter_info_n *lfi, int level, int kf) {
|
||||||
|
if (level != lfi->bilateral_level_set ||
|
||||||
|
kf != lfi->bilateral_kf_set) {
|
||||||
|
lfi->bilateral_used = vp9_loop_bilateral_used(level, kf);
|
||||||
|
if (lfi->bilateral_used) {
|
||||||
|
const bilateral_params_t param = vp9_bilateral_level_to_params(level, kf);
|
||||||
|
const int sigma_x = param.sigma_x;
|
||||||
|
const int sigma_r = param.sigma_r;
|
||||||
|
const double sigma_r_d = (double)sigma_r / BILATERAL_PRECISION;
|
||||||
|
const double sigma_x_d = (double)sigma_x / BILATERAL_PRECISION;
|
||||||
|
double *wr_lut_ = lfi->wr_lut + 255;
|
||||||
|
double *wx_lut_ = lfi->wx_lut + BILATERAL_HALFWIN * (1 + BILATERAL_WIN);
|
||||||
|
int i, x, y;
|
||||||
|
for (i = 0; i < 256; i++) {
|
||||||
|
wr_lut_[i] = exp(-(i * i) / (2 * sigma_r_d * sigma_r_d));
|
||||||
|
wr_lut_[-i] = wr_lut_[i];
|
||||||
|
}
|
||||||
|
for (y = -BILATERAL_HALFWIN; y <= BILATERAL_HALFWIN; y++)
|
||||||
|
for (x = -BILATERAL_HALFWIN; x <= BILATERAL_HALFWIN; x++) {
|
||||||
|
wx_lut_[y * BILATERAL_WIN + x] =
|
||||||
|
exp(-(x * x + y * y) / (2 * sigma_x_d * sigma_x_d));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lfi->bilateral_level_set = level;
|
||||||
|
lfi->bilateral_kf_set = kf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int is_in_image(int x, int y, int width, int height) {
|
||||||
|
return (x >= 0 && x < width && y >= 0 && y < height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop_bilateral_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 + 255;
|
||||||
|
const double *wx_lut_ = lfi->wx_lut + BILATERAL_HALFWIN * (1 + BILATERAL_WIN);
|
||||||
|
for (i = 0; i < height; ++i) {
|
||||||
|
for (j = 0; j < width; ++j) {
|
||||||
|
int x, y;
|
||||||
|
double wt;
|
||||||
|
double flsum = 0;
|
||||||
|
double wtsum = 0;
|
||||||
|
uint8_t *v = data + i * stride + j;
|
||||||
|
uint8_t *z = tmpdata + i * tmpstride + j;
|
||||||
|
uint8_t *d;
|
||||||
|
for (y = -BILATERAL_HALFWIN; y <= BILATERAL_HALFWIN; ++y) {
|
||||||
|
for (x = -BILATERAL_HALFWIN; x <= BILATERAL_HALFWIN; ++x) {
|
||||||
|
if (!is_in_image(j + x, i + y, width, height))
|
||||||
|
continue;
|
||||||
|
d = data + (i + y) * stride + (j + x);
|
||||||
|
wt = wr_lut_[d[0] - v[0]] * wx_lut_[y * BILATERAL_WIN + x];
|
||||||
|
wtsum += wt;
|
||||||
|
flsum += wt * d[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wtsum > 0)
|
||||||
|
z[0] = (int)(flsum / wtsum + 0.5);
|
||||||
|
else
|
||||||
|
z[0] = v[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0; i < height; ++i) {
|
||||||
|
vpx_memcpy(data + i * stride, tmpdata + i * tmpstride,
|
||||||
|
width * sizeof(*data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vp9_loop_bilateral_rows(YV12_BUFFER_CONFIG *frame,
|
||||||
|
VP9_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 = MIN(yend, cm->height);
|
||||||
|
uvend = MIN(uvend, cm->subsampling_y ? (cm->height + 1) >> 1 : cm->height);
|
||||||
|
|
||||||
|
if (vp9_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
|
||||||
|
0, NULL, NULL, NULL) < 0)
|
||||||
|
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
|
||||||
|
"Failed to allocate post-processing buffer");
|
||||||
|
|
||||||
|
tmp_buf = &cm->tmp_loop_buf;
|
||||||
|
|
||||||
|
loop_bilateral_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) {
|
||||||
|
loop_bilateral_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_bilateral_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // CONFIG_LOOP_POSTFILTER
|
||||||
|
|
||||||
static void update_sharpness(loop_filter_info_n *lfi, int sharpness_lvl) {
|
static void update_sharpness(loop_filter_info_n *lfi, int sharpness_lvl) {
|
||||||
int lvl;
|
int lvl;
|
||||||
|
|
||||||
@@ -267,6 +398,10 @@ void vp9_loop_filter_init(VP9_COMMON *cm) {
|
|||||||
// init hev threshold const vectors
|
// init hev threshold const vectors
|
||||||
for (lvl = 0; lvl <= MAX_LOOP_FILTER; lvl++)
|
for (lvl = 0; lvl <= MAX_LOOP_FILTER; lvl++)
|
||||||
vpx_memset(lfi->lfthr[lvl].hev_thr, (lvl >> 4), SIMD_WIDTH);
|
vpx_memset(lfi->lfthr[lvl].hev_thr, (lvl >> 4), SIMD_WIDTH);
|
||||||
|
|
||||||
|
#if CONFIG_LOOP_POSTFILTER
|
||||||
|
vp9_loop_bilateral_init(lfi, DEF_BILATERAL_LEVEL, 1);
|
||||||
|
#endif // CONFIG_LOOP_POSTFILTER
|
||||||
}
|
}
|
||||||
|
|
||||||
void vp9_loop_filter_frame_init(VP9_COMMON *cm, int default_filt_lvl) {
|
void vp9_loop_filter_frame_init(VP9_COMMON *cm, int default_filt_lvl) {
|
||||||
@@ -1701,7 +1836,8 @@ void vp9_loop_filter_frame(YV12_BUFFER_CONFIG *frame,
|
|||||||
int frame_filter_level,
|
int frame_filter_level,
|
||||||
int y_only, int partial_frame) {
|
int y_only, int partial_frame) {
|
||||||
int start_mi_row, end_mi_row, mi_rows_to_filter;
|
int start_mi_row, end_mi_row, mi_rows_to_filter;
|
||||||
if (!frame_filter_level) return;
|
if (!frame_filter_level)
|
||||||
|
return;
|
||||||
start_mi_row = 0;
|
start_mi_row = 0;
|
||||||
mi_rows_to_filter = cm->mi_rows;
|
mi_rows_to_filter = cm->mi_rows;
|
||||||
if (partial_frame && cm->mi_rows > 8) {
|
if (partial_frame && cm->mi_rows > 8) {
|
||||||
@@ -1710,15 +1846,52 @@ void vp9_loop_filter_frame(YV12_BUFFER_CONFIG *frame,
|
|||||||
mi_rows_to_filter = MAX(cm->mi_rows / 8, 8);
|
mi_rows_to_filter = MAX(cm->mi_rows / 8, 8);
|
||||||
}
|
}
|
||||||
end_mi_row = start_mi_row + mi_rows_to_filter;
|
end_mi_row = start_mi_row + mi_rows_to_filter;
|
||||||
|
if (frame_filter_level) {
|
||||||
vp9_loop_filter_frame_init(cm, frame_filter_level);
|
vp9_loop_filter_frame_init(cm, frame_filter_level);
|
||||||
vp9_loop_filter_rows(frame, cm, xd->plane,
|
vp9_loop_filter_rows(frame, cm, xd->plane,
|
||||||
start_mi_row, end_mi_row,
|
start_mi_row, end_mi_row,
|
||||||
y_only);
|
y_only);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_LOOP_POSTFILTER
|
||||||
|
void vp9_loop_filter_gen_frame(YV12_BUFFER_CONFIG *frame,
|
||||||
|
VP9_COMMON *cm, MACROBLOCKD *xd,
|
||||||
|
int frame_filter_level,
|
||||||
|
int bilateral_level,
|
||||||
|
int y_only, int partial_frame) {
|
||||||
|
int start_mi_row, end_mi_row, mi_rows_to_filter;
|
||||||
|
const int loop_bilateral_used = vp9_loop_bilateral_used(
|
||||||
|
bilateral_level, cm->frame_type == KEY_FRAME);
|
||||||
|
if (!frame_filter_level && !loop_bilateral_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 = MAX(cm->mi_rows / 8, 8);
|
||||||
|
}
|
||||||
|
end_mi_row = start_mi_row + mi_rows_to_filter;
|
||||||
|
if (frame_filter_level) {
|
||||||
|
vp9_loop_filter_frame_init(cm, frame_filter_level);
|
||||||
|
vp9_loop_filter_rows(frame, cm, xd->plane,
|
||||||
|
start_mi_row, end_mi_row,
|
||||||
|
y_only);
|
||||||
|
}
|
||||||
|
if (loop_bilateral_used) {
|
||||||
|
vp9_loop_bilateral_init(&cm->lf_info, bilateral_level,
|
||||||
|
cm->frame_type == KEY_FRAME);
|
||||||
|
vp9_loop_bilateral_rows(frame, cm, start_mi_row, end_mi_row, y_only);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // CONFIG_LOOP_POSTFILTER
|
||||||
|
|
||||||
int vp9_loop_filter_worker(LFWorkerData *const lf_data, void *unused) {
|
int vp9_loop_filter_worker(LFWorkerData *const lf_data, void *unused) {
|
||||||
(void)unused;
|
(void)unused;
|
||||||
|
if (lf_data->cm->lf.filter_level) {
|
||||||
vp9_loop_filter_rows(lf_data->frame_buffer, lf_data->cm, lf_data->planes,
|
vp9_loop_filter_rows(lf_data->frame_buffer, lf_data->cm, lf_data->planes,
|
||||||
lf_data->start, lf_data->stop, lf_data->y_only);
|
lf_data->start, lf_data->stop, lf_data->y_only);
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,70 @@ extern "C" {
|
|||||||
#define MAX_REF_LF_DELTAS 4
|
#define MAX_REF_LF_DELTAS 4
|
||||||
#define MAX_MODE_LF_DELTAS 2
|
#define MAX_MODE_LF_DELTAS 2
|
||||||
|
|
||||||
|
struct VP9Common;
|
||||||
|
|
||||||
|
#if CONFIG_LOOP_POSTFILTER
|
||||||
|
#define BILATERAL_LEVEL_BITS_KF 4
|
||||||
|
#define BILATERAL_LEVELS_KF (1 << BILATERAL_LEVEL_BITS_KF)
|
||||||
|
#define BILATERAL_LEVEL_BITS 3
|
||||||
|
#define BILATERAL_LEVELS (1 << BILATERAL_LEVEL_BITS)
|
||||||
|
#define DEF_BILATERAL_LEVEL 2
|
||||||
|
|
||||||
|
#define BILATERAL_PRECISION 8
|
||||||
|
#define BILATERAL_HALFWIN 3
|
||||||
|
#define BILATERAL_WIN (2 * BILATERAL_HALFWIN + 1)
|
||||||
|
|
||||||
|
typedef struct bilateral_params {
|
||||||
|
int sigma_x; // spatial variance
|
||||||
|
int sigma_r; // range variance
|
||||||
|
} bilateral_params_t;
|
||||||
|
|
||||||
|
static bilateral_params_t
|
||||||
|
bilateral_level_to_params_arr[BILATERAL_LEVELS + 1] = {
|
||||||
|
// Values are rounded to 1/8 th precision
|
||||||
|
{4, 16}, // 0 - default
|
||||||
|
{5, 16},
|
||||||
|
{6, 16},
|
||||||
|
{7, 16},
|
||||||
|
{9, 18},
|
||||||
|
{12, 20},
|
||||||
|
{16, 20},
|
||||||
|
{20, 20},
|
||||||
|
{24, 24}
|
||||||
|
};
|
||||||
|
|
||||||
|
static bilateral_params_t
|
||||||
|
bilateral_level_to_params_arr_kf[BILATERAL_LEVELS_KF + 1] = {
|
||||||
|
// Values are rounded to 1/8 th precision
|
||||||
|
{4, 16}, // 0 - default
|
||||||
|
{5, 16},
|
||||||
|
{6, 16},
|
||||||
|
{7, 16},
|
||||||
|
{9, 18},
|
||||||
|
{12, 20},
|
||||||
|
{15, 22},
|
||||||
|
{18, 24},
|
||||||
|
{21, 24},
|
||||||
|
{24, 24},
|
||||||
|
{24, 28},
|
||||||
|
{28, 24},
|
||||||
|
{28, 28},
|
||||||
|
{28, 32},
|
||||||
|
{32, 24},
|
||||||
|
{32, 28},
|
||||||
|
{32, 32},
|
||||||
|
};
|
||||||
|
|
||||||
|
int vp9_bilateral_level_bits(const struct VP9Common *const cm);
|
||||||
|
int vp9_loop_bilateral_used(int level, int kf);
|
||||||
|
|
||||||
|
static INLINE bilateral_params_t vp9_bilateral_level_to_params(
|
||||||
|
int index, int kf) {
|
||||||
|
return kf ? bilateral_level_to_params_arr_kf[index] :
|
||||||
|
bilateral_level_to_params_arr[index];
|
||||||
|
}
|
||||||
|
#endif // CONFIG_LOOP_POSTFILTER
|
||||||
|
|
||||||
struct loopfilter {
|
struct loopfilter {
|
||||||
int filter_level;
|
int filter_level;
|
||||||
|
|
||||||
@@ -45,6 +109,10 @@ struct loopfilter {
|
|||||||
// 0 = ZERO_MV, MV
|
// 0 = ZERO_MV, MV
|
||||||
signed char mode_deltas[MAX_MODE_LF_DELTAS];
|
signed char mode_deltas[MAX_MODE_LF_DELTAS];
|
||||||
signed char last_mode_deltas[MAX_MODE_LF_DELTAS];
|
signed char last_mode_deltas[MAX_MODE_LF_DELTAS];
|
||||||
|
|
||||||
|
#if CONFIG_LOOP_POSTFILTER
|
||||||
|
int bilateral_level;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// Need to align this structure so when it is declared and
|
// Need to align this structure so when it is declared and
|
||||||
@@ -58,6 +126,13 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
loop_filter_thresh lfthr[MAX_LOOP_FILTER + 1];
|
loop_filter_thresh lfthr[MAX_LOOP_FILTER + 1];
|
||||||
uint8_t lvl[MAX_SEGMENTS][MAX_REF_FRAMES][MAX_MODE_LF_DELTAS];
|
uint8_t lvl[MAX_SEGMENTS][MAX_REF_FRAMES][MAX_MODE_LF_DELTAS];
|
||||||
|
#if CONFIG_LOOP_POSTFILTER
|
||||||
|
double wx_lut[BILATERAL_WIN * BILATERAL_WIN];
|
||||||
|
double wr_lut[512];
|
||||||
|
int bilateral_level_set;
|
||||||
|
int bilateral_kf_set;
|
||||||
|
int bilateral_used;
|
||||||
|
#endif
|
||||||
} loop_filter_info_n;
|
} loop_filter_info_n;
|
||||||
|
|
||||||
// This structure holds bit masks for all 8x8 blocks in a 64x64 region.
|
// This structure holds bit masks for all 8x8 blocks in a 64x64 region.
|
||||||
@@ -81,7 +156,6 @@ typedef struct {
|
|||||||
} LOOP_FILTER_MASK;
|
} LOOP_FILTER_MASK;
|
||||||
|
|
||||||
/* assorted loopfilter functions which get used elsewhere */
|
/* assorted loopfilter functions which get used elsewhere */
|
||||||
struct VP9Common;
|
|
||||||
struct macroblockd;
|
struct macroblockd;
|
||||||
struct VP9LfSyncData;
|
struct VP9LfSyncData;
|
||||||
|
|
||||||
@@ -115,6 +189,20 @@ void vp9_loop_filter_rows(YV12_BUFFER_CONFIG *frame_buffer,
|
|||||||
struct VP9Common *cm,
|
struct VP9Common *cm,
|
||||||
struct macroblockd_plane planes[MAX_MB_PLANE],
|
struct macroblockd_plane planes[MAX_MB_PLANE],
|
||||||
int start, int stop, int y_only);
|
int start, int stop, int y_only);
|
||||||
|
#if CONFIG_LOOP_POSTFILTER
|
||||||
|
void vp9_loop_filter_gen_frame(YV12_BUFFER_CONFIG *frame,
|
||||||
|
struct VP9Common *cm,
|
||||||
|
struct macroblockd *mbd,
|
||||||
|
int frame_filter_level,
|
||||||
|
int bilateral_level,
|
||||||
|
int y_only, int partial_frame);
|
||||||
|
void vp9_loop_bilateral_init(loop_filter_info_n *lfi, int T, int kf);
|
||||||
|
void vp9_loop_bilateral_rows(YV12_BUFFER_CONFIG *frame,
|
||||||
|
struct VP9Common *cm,
|
||||||
|
int start_mi_row, int end_mi_row,
|
||||||
|
int y_only);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
typedef struct LoopFilterWorkerData {
|
typedef struct LoopFilterWorkerData {
|
||||||
YV12_BUFFER_CONFIG *frame_buffer;
|
YV12_BUFFER_CONFIG *frame_buffer;
|
||||||
|
|||||||
@@ -108,6 +108,9 @@ typedef struct VP9Common {
|
|||||||
int new_fb_idx;
|
int new_fb_idx;
|
||||||
|
|
||||||
YV12_BUFFER_CONFIG post_proc_buffer;
|
YV12_BUFFER_CONFIG post_proc_buffer;
|
||||||
|
#if CONFIG_LOOP_POSTFILTER
|
||||||
|
YV12_BUFFER_CONFIG tmp_loop_buf;
|
||||||
|
#endif
|
||||||
|
|
||||||
FRAME_TYPE last_frame_type; /* last frame's frame type for motion search.*/
|
FRAME_TYPE last_frame_type; /* last frame's frame type for motion search.*/
|
||||||
FRAME_TYPE frame_type;
|
FRAME_TYPE frame_type;
|
||||||
|
|||||||
@@ -1586,8 +1586,9 @@ static void setup_segmentation(struct segmentation *seg,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_loopfilter(struct loopfilter *lf,
|
static void setup_loopfilter(VP9_COMMON *cm,
|
||||||
struct vp9_read_bit_buffer *rb) {
|
struct vp9_read_bit_buffer *rb) {
|
||||||
|
struct loopfilter *lf = &cm->lf;
|
||||||
lf->filter_level = vp9_rb_read_literal(rb, 6);
|
lf->filter_level = vp9_rb_read_literal(rb, 6);
|
||||||
lf->sharpness_level = vp9_rb_read_literal(rb, 3);
|
lf->sharpness_level = vp9_rb_read_literal(rb, 3);
|
||||||
|
|
||||||
@@ -1610,6 +1611,13 @@ static void setup_loopfilter(struct loopfilter *lf,
|
|||||||
lf->mode_deltas[i] = vp9_rb_read_signed_literal(rb, 6);
|
lf->mode_deltas[i] = vp9_rb_read_signed_literal(rb, 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if CONFIG_LOOP_POSTFILTER
|
||||||
|
lf->bilateral_level = vp9_rb_read_bit(rb);
|
||||||
|
if (lf->bilateral_level) {
|
||||||
|
lf->bilateral_level += vp9_rb_read_literal(
|
||||||
|
rb, vp9_bilateral_level_bits(cm));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_delta_q(struct vp9_read_bit_buffer *rb, int *delta_q) {
|
static int read_delta_q(struct vp9_read_bit_buffer *rb, int *delta_q) {
|
||||||
@@ -1976,7 +1984,7 @@ static const uint8_t *decode_tiles(VP9Decoder *pbi,
|
|||||||
}
|
}
|
||||||
#if !CONFIG_INTRABC
|
#if !CONFIG_INTRABC
|
||||||
// Loopfilter one row.
|
// Loopfilter one row.
|
||||||
if (cm->lf.filter_level && !pbi->mb.corrupted) {
|
if (!pbi->mb.corrupted && cm->lf.filter_level) {
|
||||||
const int lf_start = mi_row - MI_BLOCK_SIZE;
|
const int lf_start = mi_row - MI_BLOCK_SIZE;
|
||||||
LFWorkerData *const lf_data = (LFWorkerData*)pbi->lf_worker.data1;
|
LFWorkerData *const lf_data = (LFWorkerData*)pbi->lf_worker.data1;
|
||||||
|
|
||||||
@@ -2000,7 +2008,7 @@ static const uint8_t *decode_tiles(VP9Decoder *pbi,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Loopfilter remaining rows in the frame.
|
// Loopfilter remaining rows in the frame.
|
||||||
if (cm->lf.filter_level && !pbi->mb.corrupted) {
|
if (!pbi->mb.corrupted && cm->lf.filter_level) {
|
||||||
LFWorkerData *const lf_data = (LFWorkerData*)pbi->lf_worker.data1;
|
LFWorkerData *const lf_data = (LFWorkerData*)pbi->lf_worker.data1;
|
||||||
winterface->sync(&pbi->lf_worker);
|
winterface->sync(&pbi->lf_worker);
|
||||||
lf_data->start = lf_data->stop;
|
lf_data->start = lf_data->stop;
|
||||||
@@ -2377,7 +2385,7 @@ static size_t read_uncompressed_header(VP9Decoder *pbi,
|
|||||||
if (frame_is_intra_only(cm) || cm->error_resilient_mode)
|
if (frame_is_intra_only(cm) || cm->error_resilient_mode)
|
||||||
vp9_setup_past_independence(cm);
|
vp9_setup_past_independence(cm);
|
||||||
|
|
||||||
setup_loopfilter(&cm->lf, rb);
|
setup_loopfilter(cm, rb);
|
||||||
setup_quantization(cm, &pbi->mb, rb);
|
setup_quantization(cm, &pbi->mb, rb);
|
||||||
setup_segmentation(&cm->seg, rb);
|
setup_segmentation(&cm->seg, rb);
|
||||||
|
|
||||||
@@ -2683,6 +2691,13 @@ void vp9_decode_frame(VP9Decoder *pbi,
|
|||||||
} else {
|
} else {
|
||||||
*p_data_end = decode_tiles(pbi, data + first_partition_size, data_end);
|
*p_data_end = decode_tiles(pbi, data + first_partition_size, data_end);
|
||||||
}
|
}
|
||||||
|
#if CONFIG_LOOP_POSTFILTER
|
||||||
|
vp9_loop_bilateral_init(&cm->lf_info, cm->lf.bilateral_level,
|
||||||
|
cm->frame_type == KEY_FRAME);
|
||||||
|
if (cm->lf_info.bilateral_used) {
|
||||||
|
vp9_loop_bilateral_rows(new_fb, cm, 0, cm->mi_rows, 0);
|
||||||
|
}
|
||||||
|
#endif // CONFIG_LOOP_POSTFILTER
|
||||||
|
|
||||||
new_fb->corrupted |= xd->corrupted;
|
new_fb->corrupted |= xd->corrupted;
|
||||||
if (!new_fb->corrupted) {
|
if (!new_fb->corrupted) {
|
||||||
|
|||||||
@@ -1487,9 +1487,10 @@ static void update_coef_probs(VP9_COMP *cpi, vp9_writer* w) {
|
|||||||
frame_coef_probs[tx_size]);
|
frame_coef_probs[tx_size]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void encode_loopfilter(struct loopfilter *lf,
|
static void encode_loopfilter(VP9_COMMON *cm,
|
||||||
struct vp9_write_bit_buffer *wb) {
|
struct vp9_write_bit_buffer *wb) {
|
||||||
int i;
|
int i;
|
||||||
|
struct loopfilter *lf = &cm->lf;
|
||||||
|
|
||||||
// Encode the loop filter level and type
|
// Encode the loop filter level and type
|
||||||
vp9_wb_write_literal(wb, lf->filter_level, 6);
|
vp9_wb_write_literal(wb, lf->filter_level, 6);
|
||||||
@@ -1525,6 +1526,12 @@ static void encode_loopfilter(struct loopfilter *lf,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if CONFIG_LOOP_POSTFILTER
|
||||||
|
vp9_wb_write_bit(wb, lf->bilateral_level > 0);
|
||||||
|
if (lf->bilateral_level > 0)
|
||||||
|
vp9_wb_write_literal(wb, lf->bilateral_level - 1,
|
||||||
|
vp9_bilateral_level_bits(cm));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_delta_q(struct vp9_write_bit_buffer *wb, int delta_q) {
|
static void write_delta_q(struct vp9_write_bit_buffer *wb, int delta_q) {
|
||||||
@@ -1968,7 +1975,7 @@ static void write_uncompressed_header(VP9_COMP *cpi,
|
|||||||
|
|
||||||
vp9_wb_write_literal(wb, cm->frame_context_idx, FRAME_CONTEXTS_LOG2);
|
vp9_wb_write_literal(wb, cm->frame_context_idx, FRAME_CONTEXTS_LOG2);
|
||||||
|
|
||||||
encode_loopfilter(&cm->lf, wb);
|
encode_loopfilter(cm, wb);
|
||||||
encode_quantization(cm, wb);
|
encode_quantization(cm, wb);
|
||||||
encode_segmentation(cm, &cpi->mb.e_mbd, wb);
|
encode_segmentation(cm, &cpi->mb.e_mbd, wb);
|
||||||
|
|
||||||
|
|||||||
@@ -2449,8 +2449,16 @@ static void loopfilter_frame(VP9_COMP *cpi, VP9_COMMON *cm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lf->filter_level > 0) {
|
if (lf->filter_level > 0) {
|
||||||
vp9_loop_filter_frame(cm->frame_to_show, cm, xd, lf->filter_level, 0, 0);
|
vp9_loop_filter_frame(cm->frame_to_show, cm, xd, lf->filter_level,
|
||||||
|
0, 0);
|
||||||
}
|
}
|
||||||
|
#if CONFIG_LOOP_POSTFILTER
|
||||||
|
vp9_loop_bilateral_init(&cm->lf_info, cm->lf.bilateral_level,
|
||||||
|
cm->frame_type == KEY_FRAME);
|
||||||
|
if (cm->lf_info.bilateral_used) {
|
||||||
|
vp9_loop_bilateral_rows(cm->frame_to_show, cm, 0, cm->mi_rows, 0);
|
||||||
|
}
|
||||||
|
#endif // CONFIG_LOOP_POSTFILTER
|
||||||
|
|
||||||
vp9_extend_frame_inner_borders(cm->frame_to_show);
|
vp9_extend_frame_inner_borders(cm->frame_to_show);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,14 +32,14 @@ static int get_max_filter_level(const VP9_COMP *cpi) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int try_filter_frame(const YV12_BUFFER_CONFIG *sd, VP9_COMP *const cpi,
|
static int try_filter_frame(const YV12_BUFFER_CONFIG *sd, VP9_COMP *const cpi,
|
||||||
int filt_level, int partial_frame) {
|
int filt_level,
|
||||||
|
int partial_frame) {
|
||||||
VP9_COMMON *const cm = &cpi->common;
|
VP9_COMMON *const cm = &cpi->common;
|
||||||
int filt_err;
|
int filt_err;
|
||||||
|
|
||||||
vp9_loop_filter_frame(cm->frame_to_show, cm, &cpi->mb.e_mbd, filt_level, 1,
|
vp9_loop_filter_frame(cm->frame_to_show, cm, &cpi->mb.e_mbd, filt_level,
|
||||||
partial_frame);
|
1, partial_frame);
|
||||||
#if CONFIG_VP9_HIGHBITDEPTH
|
#if CONFIG_VP9_HIGHBITDEPTH
|
||||||
if (cm->use_highbitdepth) {
|
if (cm->use_highbitdepth) {
|
||||||
filt_err = vp9_highbd_get_y_sse(sd, cm->frame_to_show, cm->bit_depth);
|
filt_err = vp9_highbd_get_y_sse(sd, cm->frame_to_show, cm->bit_depth);
|
||||||
@@ -56,6 +56,170 @@ static int try_filter_frame(const YV12_BUFFER_CONFIG *sd, VP9_COMP *const cpi,
|
|||||||
return filt_err;
|
return filt_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_LOOP_POSTFILTER
|
||||||
|
#define JOINT_FILTER_BILATERAL_SEARCH
|
||||||
|
static int try_bilateral_frame(const YV12_BUFFER_CONFIG *sd,
|
||||||
|
VP9_COMP *const cpi,
|
||||||
|
int filt_level,
|
||||||
|
int bilateral_level,
|
||||||
|
int partial_frame) {
|
||||||
|
VP9_COMMON *const cm = &cpi->common;
|
||||||
|
int filt_err;
|
||||||
|
|
||||||
|
vp9_loop_filter_gen_frame(cm->frame_to_show, cm, &cpi->mb.e_mbd, filt_level,
|
||||||
|
bilateral_level, 1, partial_frame);
|
||||||
|
#if CONFIG_VP9_HIGHBITDEPTH
|
||||||
|
if (cm->use_highbitdepth) {
|
||||||
|
filt_err = vp9_highbd_get_y_sse(sd, cm->frame_to_show, cm->bit_depth);
|
||||||
|
} else {
|
||||||
|
filt_err = vp9_get_y_sse(sd, cm->frame_to_show);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
filt_err = vp9_get_y_sse(sd, cm->frame_to_show);
|
||||||
|
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||||
|
|
||||||
|
// Re-instate the unfiltered frame
|
||||||
|
vpx_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
|
||||||
|
|
||||||
|
return filt_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// #define USE_RD_BILATERAL_SEARCH
|
||||||
|
static int64_t search_bilateral_level(const YV12_BUFFER_CONFIG *sd,
|
||||||
|
VP9_COMP *cpi,
|
||||||
|
int filter_level, int partial_frame,
|
||||||
|
int64_t *best_cost_ret) {
|
||||||
|
int i, bilateral_best, err;
|
||||||
|
int64_t best_cost;
|
||||||
|
int64_t cost[BILATERAL_LEVELS_KF];
|
||||||
|
const int bilateral_level_bits = vp9_bilateral_level_bits(&cpi->common);
|
||||||
|
const int bilateral_levels = 1 << bilateral_level_bits;
|
||||||
|
#ifdef USE_RD_BILATERAL_SEARCH
|
||||||
|
MACROBLOCK *x = &cpi->mb;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bilateral_best = 0;
|
||||||
|
err = try_bilateral_frame(sd, cpi, filter_level, 0, partial_frame);
|
||||||
|
#ifdef USE_RD_BILATERAL_SEARCH
|
||||||
|
cost[0] = RDCOST(x->rdmult, x->rddiv, 0, err);
|
||||||
|
#else
|
||||||
|
cost[0] = err;
|
||||||
|
#endif
|
||||||
|
best_cost = cost[0];
|
||||||
|
for (i = 1; i <= bilateral_levels; ++i) {
|
||||||
|
err = try_bilateral_frame(sd, cpi, filter_level, i, partial_frame);
|
||||||
|
#ifdef USE_RD_BILATERAL_SEARCH
|
||||||
|
// Normally the rate is rate in bits * 256 and dist is sum sq err * 64
|
||||||
|
// when RDCOST is used. However below we just scale both in the correct
|
||||||
|
// ratios appropriately but not exactly by these values.
|
||||||
|
cost[i] = RDCOST(x->rdmult, x->rddiv,
|
||||||
|
bilateral_level_bits << 2, err);
|
||||||
|
#else
|
||||||
|
cost[i] = err;
|
||||||
|
#endif
|
||||||
|
if (cost[i] < best_cost) {
|
||||||
|
bilateral_best = i;
|
||||||
|
best_cost = cost[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (best_cost_ret) *best_cost_ret = best_cost;
|
||||||
|
return bilateral_best;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int search_filter_bilateral_level(const YV12_BUFFER_CONFIG *sd,
|
||||||
|
VP9_COMP *cpi,
|
||||||
|
int partial_frame,
|
||||||
|
int *bilateral_level) {
|
||||||
|
const VP9_COMMON *const cm = &cpi->common;
|
||||||
|
const struct loopfilter *const lf = &cm->lf;
|
||||||
|
const int min_filter_level = 0;
|
||||||
|
const int max_filter_level = get_max_filter_level(cpi);
|
||||||
|
int filt_direction = 0;
|
||||||
|
int filt_best, bilateral_best;
|
||||||
|
int64_t best_err;
|
||||||
|
|
||||||
|
// Start the search at the previous frame filter level unless it is now out of
|
||||||
|
// range.
|
||||||
|
int filt_mid = clamp(lf->filter_level, min_filter_level, max_filter_level);
|
||||||
|
int filter_step = filt_mid < 16 ? 4 : filt_mid / 4;
|
||||||
|
// Sum squared error at each filter level
|
||||||
|
int64_t ss_err[MAX_LOOP_FILTER + 1];
|
||||||
|
int bilateral;
|
||||||
|
|
||||||
|
// Set each entry to -1
|
||||||
|
vpx_memset(ss_err, 0xFF, sizeof(ss_err));
|
||||||
|
|
||||||
|
// Make a copy of the unfiltered / processed recon buffer
|
||||||
|
vpx_yv12_copy_y(cm->frame_to_show, &cpi->last_frame_uf);
|
||||||
|
|
||||||
|
bilateral = search_bilateral_level(sd, cpi, filt_mid,
|
||||||
|
partial_frame, &best_err);
|
||||||
|
filt_best = filt_mid;
|
||||||
|
bilateral_best = bilateral;
|
||||||
|
ss_err[filt_mid] = best_err;
|
||||||
|
|
||||||
|
while (filter_step > 0) {
|
||||||
|
const int filt_high = MIN(filt_mid + filter_step, max_filter_level);
|
||||||
|
const int filt_low = MAX(filt_mid - filter_step, min_filter_level);
|
||||||
|
|
||||||
|
// Bias against raising loop filter in favor of lowering it.
|
||||||
|
int64_t bias = (best_err >> (15 - (filt_mid / 8))) * filter_step;
|
||||||
|
|
||||||
|
if ((cpi->oxcf.pass == 2) && (cpi->twopass.section_intra_rating < 20))
|
||||||
|
bias = (bias * cpi->twopass.section_intra_rating) / 20;
|
||||||
|
|
||||||
|
// yx, bias less for large block size
|
||||||
|
if (cm->tx_mode != ONLY_4X4)
|
||||||
|
bias >>= 1;
|
||||||
|
|
||||||
|
if (filt_direction <= 0 && filt_low != filt_mid) {
|
||||||
|
// Get Low filter error score
|
||||||
|
if (ss_err[filt_low] < 0) {
|
||||||
|
bilateral = search_bilateral_level(sd, cpi, filt_low,
|
||||||
|
partial_frame,
|
||||||
|
&ss_err[filt_low]);
|
||||||
|
}
|
||||||
|
// If value is close to the best so far then bias towards a lower loop
|
||||||
|
// filter value.
|
||||||
|
if ((ss_err[filt_low] - bias) < best_err) {
|
||||||
|
// Was it actually better than the previous best?
|
||||||
|
if (ss_err[filt_low] < best_err) {
|
||||||
|
best_err = ss_err[filt_low];
|
||||||
|
}
|
||||||
|
|
||||||
|
filt_best = filt_low;
|
||||||
|
bilateral_best = bilateral;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now look at filt_high
|
||||||
|
if (filt_direction >= 0 && filt_high != filt_mid) {
|
||||||
|
if (ss_err[filt_high] < 0) {
|
||||||
|
bilateral = search_bilateral_level(sd, cpi, filt_high, partial_frame,
|
||||||
|
&ss_err[filt_high]);
|
||||||
|
}
|
||||||
|
// Was it better than the previous best?
|
||||||
|
if (ss_err[filt_high] < (best_err - bias)) {
|
||||||
|
best_err = ss_err[filt_high];
|
||||||
|
filt_best = filt_high;
|
||||||
|
bilateral_best = bilateral;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Half the step distance if the best filter value was the same as last time
|
||||||
|
if (filt_best == filt_mid) {
|
||||||
|
filter_step /= 2;
|
||||||
|
filt_direction = 0;
|
||||||
|
} else {
|
||||||
|
filt_direction = (filt_best < filt_mid) ? -1 : 1;
|
||||||
|
filt_mid = filt_best;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*bilateral_level = bilateral_best;
|
||||||
|
return filt_best;
|
||||||
|
}
|
||||||
|
#endif // CONFIG_LOOP_POSTFILTER
|
||||||
|
|
||||||
static int search_filter_level(const YV12_BUFFER_CONFIG *sd, VP9_COMP *cpi,
|
static int search_filter_level(const YV12_BUFFER_CONFIG *sd, VP9_COMP *cpi,
|
||||||
int partial_frame) {
|
int partial_frame) {
|
||||||
const VP9_COMMON *const cm = &cpi->common;
|
const VP9_COMMON *const cm = &cpi->common;
|
||||||
@@ -78,11 +242,11 @@ static int search_filter_level(const YV12_BUFFER_CONFIG *sd, VP9_COMP *cpi,
|
|||||||
// Make a copy of the unfiltered / processed recon buffer
|
// Make a copy of the unfiltered / processed recon buffer
|
||||||
vpx_yv12_copy_y(cm->frame_to_show, &cpi->last_frame_uf);
|
vpx_yv12_copy_y(cm->frame_to_show, &cpi->last_frame_uf);
|
||||||
|
|
||||||
best_err = try_filter_frame(sd, cpi, filt_mid, partial_frame);
|
best_err = try_filter_frame(sd, cpi, filt_mid,
|
||||||
|
partial_frame);
|
||||||
filt_best = filt_mid;
|
filt_best = filt_mid;
|
||||||
ss_err[filt_mid] = best_err;
|
ss_err[filt_mid] = best_err;
|
||||||
|
|
||||||
|
|
||||||
while (filter_step > 0) {
|
while (filter_step > 0) {
|
||||||
const int filt_high = MIN(filt_mid + filter_step, max_filter_level);
|
const int filt_high = MIN(filt_mid + filter_step, max_filter_level);
|
||||||
const int filt_low = MAX(filt_mid - filter_step, min_filter_level);
|
const int filt_low = MAX(filt_mid - filter_step, min_filter_level);
|
||||||
@@ -100,7 +264,8 @@ static int search_filter_level(const YV12_BUFFER_CONFIG *sd, VP9_COMP *cpi,
|
|||||||
if (filt_direction <= 0 && filt_low != filt_mid) {
|
if (filt_direction <= 0 && filt_low != filt_mid) {
|
||||||
// Get Low filter error score
|
// Get Low filter error score
|
||||||
if (ss_err[filt_low] < 0) {
|
if (ss_err[filt_low] < 0) {
|
||||||
ss_err[filt_low] = try_filter_frame(sd, cpi, filt_low, partial_frame);
|
ss_err[filt_low] = try_filter_frame(sd, cpi, filt_low,
|
||||||
|
partial_frame);
|
||||||
}
|
}
|
||||||
// If value is close to the best so far then bias towards a lower loop
|
// If value is close to the best so far then bias towards a lower loop
|
||||||
// filter value.
|
// filter value.
|
||||||
@@ -116,7 +281,8 @@ static int search_filter_level(const YV12_BUFFER_CONFIG *sd, VP9_COMP *cpi,
|
|||||||
// Now look at filt_high
|
// Now look at filt_high
|
||||||
if (filt_direction >= 0 && filt_high != filt_mid) {
|
if (filt_direction >= 0 && filt_high != filt_mid) {
|
||||||
if (ss_err[filt_high] < 0) {
|
if (ss_err[filt_high] < 0) {
|
||||||
ss_err[filt_high] = try_filter_frame(sd, cpi, filt_high, partial_frame);
|
ss_err[filt_high] = try_filter_frame(sd, cpi, filt_high,
|
||||||
|
partial_frame);
|
||||||
}
|
}
|
||||||
// Was it better than the previous best?
|
// Was it better than the previous best?
|
||||||
if (ss_err[filt_high] < (best_err - bias)) {
|
if (ss_err[filt_high] < (best_err - bias)) {
|
||||||
@@ -176,8 +342,24 @@ void vp9_pick_filter_level(const YV12_BUFFER_CONFIG *sd, VP9_COMP *cpi,
|
|||||||
if (cm->frame_type == KEY_FRAME)
|
if (cm->frame_type == KEY_FRAME)
|
||||||
filt_guess -= 4;
|
filt_guess -= 4;
|
||||||
lf->filter_level = clamp(filt_guess, min_filter_level, max_filter_level);
|
lf->filter_level = clamp(filt_guess, min_filter_level, max_filter_level);
|
||||||
|
#if CONFIG_LOOP_POSTFILTER
|
||||||
|
lf->bilateral_level = search_bilateral_level(
|
||||||
|
sd, cpi, lf->filter_level, method == LPF_PICK_FROM_SUBIMAGE, NULL);
|
||||||
|
#endif // CONFIG_LOOP_POSTFILTER
|
||||||
} else {
|
} else {
|
||||||
lf->filter_level = search_filter_level(sd, cpi,
|
#if CONFIG_LOOP_POSTFILTER
|
||||||
method == LPF_PICK_FROM_SUBIMAGE);
|
#ifdef JOINT_FILTER_BILATERAL_SEARCH
|
||||||
|
lf->filter_level = search_filter_bilateral_level(
|
||||||
|
sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, &lf->bilateral_level);
|
||||||
|
#else
|
||||||
|
lf->filter_level = search_filter_level(
|
||||||
|
sd, cpi, method == LPF_PICK_FROM_SUBIMAGE);
|
||||||
|
lf->bilateral_level = search_bilateral_level(
|
||||||
|
sd, cpi, lf->filter_level, method == LPF_PICK_FROM_SUBIMAGE, NULL);
|
||||||
|
#endif // JOINT_FILTER_BILATERAL_SEARCH
|
||||||
|
#else
|
||||||
|
lf->filter_level = search_filter_level(
|
||||||
|
sd, cpi, method == LPF_PICK_FROM_SUBIMAGE);
|
||||||
|
#endif // CONFIG_LOOP_POSTFILTER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user