Commit 85514c40 authored by Debargha Mukherjee's avatar Debargha Mukherjee

New interpolation experiment

Adds a new interpolation experiment.

Improves entropy coding to send the filter type only if
the motion vectors have subpel components.
Adds one new 8-tap smooth filter, and tweaks the others.

derflr: +0.695%
hevcmr: +0.305%

About 5% encode slowdown. No visible impact for decoding.

Also makes the interpolation framework flexible to support both
strictly interpolating filters as well as non-interpolating
filters that filter integer offsets. This is mainly for
further experimentation and if not found useful the code will
be removed.

Change-Id: I8db9cde56ca916be771fe54a130d608bf10786e6
parent 9b3ad185
......@@ -38,6 +38,13 @@ typedef enum {
FRAME_TYPES,
} FRAME_TYPE;
#if CONFIG_EXT_INTERP && SUPPORT_NONINTERPOLATING_FILTERS
#define IsInterpolatingFilter(filter) \
(vp10_filter_kernels[filter][0][SUBPEL_TAPS / 2 - 1] == 128)
#else
#define IsInterpolatingFilter(filter) (1)
#endif // CONFIG_EXT_INTERP && SUPPORT_NONINTERPOLATING_FILTERS
static INLINE int is_inter_mode(PREDICTION_MODE mode) {
return mode >= NEARESTMV && mode <= NEWMV;
}
......
......@@ -752,6 +752,16 @@ static const vpx_prob default_skip_probs[SKIP_CONTEXTS] = {
192, 128, 64
};
#if CONFIG_EXT_INTERP && SWITCHABLE_FILTERS == 4
static const vpx_prob default_switchable_interp_prob[SWITCHABLE_FILTER_CONTEXTS]
[SWITCHABLE_FILTERS - 1] = {
{ 235, 192, 128},
{ 36, 243, 208},
{ 34, 16, 128},
{ 36, 243, 48},
{ 149, 160, 128},
};
#else
static const vpx_prob default_switchable_interp_prob[SWITCHABLE_FILTER_CONTEXTS]
[SWITCHABLE_FILTERS - 1] = {
{ 235, 162, },
......@@ -759,6 +769,7 @@ static const vpx_prob default_switchable_interp_prob[SWITCHABLE_FILTER_CONTEXTS]
{ 34, 3, },
{ 149, 144, },
};
#endif
#if CONFIG_EXT_TX
const vpx_tree_index vp10_ext_tx_inter_tree[EXT_TX_SETS_INTER]
......@@ -987,11 +998,20 @@ static void init_mode_probs(FRAME_CONTEXT *fc) {
#endif // CONFIG_EXT_INTRA
}
#if CONFIG_EXT_INTERP && SWITCHABLE_FILTERS == 4
const vpx_tree_index vp10_switchable_interp_tree
[TREE_SIZE(SWITCHABLE_FILTERS)] = {
-EIGHTTAP, 2,
4, -EIGHTTAP_SHARP,
-EIGHTTAP_SMOOTH, -EIGHTTAP_SMOOTH2,
};
#else
const vpx_tree_index vp10_switchable_interp_tree
[TREE_SIZE(SWITCHABLE_FILTERS)] = {
-EIGHTTAP, 2,
-EIGHTTAP_SMOOTH, -EIGHTTAP_SHARP
};
#endif // CONFIG_EXT_INTERP
void vp10_adapt_inter_frame_probs(VP10_COMMON *cm) {
int i, j;
......
......@@ -32,9 +32,28 @@ DECLARE_ALIGNED(256, static const InterpKernel,
{ 0, 0, 0, 8, 120, 0, 0, 0 }
};
// Lagrangian interpolation filter
DECLARE_ALIGNED(256, static const InterpKernel,
sub_pel_filters_8[SUBPEL_SHIFTS]) = {
#if CONFIG_EXT_INTERP
// intfilt 0.575
{0, 0, 0, 128, 0, 0, 0, 0},
{0, 1, -5, 126, 8, -3, 1, 0},
{-1, 3, -10, 123, 18, -6, 2, -1},
{-1, 4, -14, 118, 27, -9, 3, 0},
{-1, 5, -16, 112, 37, -12, 4, -1},
{-1, 5, -18, 105, 48, -14, 4, -1},
{-1, 6, -19, 97, 58, -17, 5, -1},
{-1, 6, -20, 88, 68, -18, 6, -1},
{-1, 6, -19, 78, 78, -19, 6, -1},
{-1, 6, -18, 68, 88, -20, 6, -1},
{-1, 5, -17, 58, 97, -19, 6, -1},
{-1, 4, -14, 48, 105, -18, 5, -1},
{-1, 4, -12, 37, 112, -16, 5, -1},
{0, 3, -9, 27, 118, -14, 4, -1},
{-1, 2, -6, 18, 123, -10, 3, -1},
{0, 1, -3, 8, 126, -5, 1, 0},
#else
// Lagrangian interpolation filter
{ 0, 0, 0, 128, 0, 0, 0, 0},
{ 0, 1, -5, 126, 8, -3, 1, 0},
{ -1, 3, -10, 122, 18, -6, 2, 0},
......@@ -51,11 +70,31 @@ DECLARE_ALIGNED(256, static const InterpKernel,
{ -1, 3, -9, 27, 118, -13, 4, -1},
{ 0, 2, -6, 18, 122, -10, 3, -1},
{ 0, 1, -3, 8, 126, -5, 1, 0}
#endif // CONFIG_EXT_INTERP
};
// DCT based filter
DECLARE_ALIGNED(256, static const InterpKernel,
sub_pel_filters_8s[SUBPEL_SHIFTS]) = {
sub_pel_filters_8sharp[SUBPEL_SHIFTS]) = {
#if CONFIG_EXT_INTERP
// intfilt 0.8
{0, 0, 0, 128, 0, 0, 0, 0},
{-1, 2, -6, 127, 9, -4, 2, -1},
{-2, 5, -12, 124, 18, -7, 4, -2},
{-2, 7, -16, 119, 28, -11, 5, -2},
{-3, 8, -19, 114, 38, -14, 7, -3},
{-3, 9, -22, 107, 49, -17, 8, -3},
{-4, 10, -23, 99, 60, -20, 10, -4},
{-4, 11, -23, 90, 70, -22, 10, -4},
{-4, 11, -23, 80, 80, -23, 11, -4},
{-4, 10, -22, 70, 90, -23, 11, -4},
{-4, 10, -20, 60, 99, -23, 10, -4},
{-3, 8, -17, 49, 107, -22, 9, -3},
{-3, 7, -14, 38, 114, -19, 8, -3},
{-2, 5, -11, 28, 119, -16, 7, -2},
{-2, 4, -7, 18, 124, -12, 5, -2},
{-1, 2, -4, 9, 127, -6, 2, -1},
#else
// DCT based filter
{0, 0, 0, 128, 0, 0, 0, 0},
{-1, 3, -7, 127, 8, -3, 1, 0},
{-2, 5, -13, 125, 17, -6, 3, -1},
......@@ -72,11 +111,58 @@ DECLARE_ALIGNED(256, static const InterpKernel,
{-2, 5, -10, 27, 121, -17, 7, -3},
{-1, 3, -6, 17, 125, -13, 5, -2},
{0, 1, -3, 8, 127, -7, 3, -1}
#endif // CONFIG_EXT_INTERP
};
// freqmultiplier = 0.5
#if CONFIG_EXT_INTERP && SWITCHABLE_FILTERS == 4
DECLARE_ALIGNED(256, static const InterpKernel,
sub_pel_filters_8lp[SUBPEL_SHIFTS]) = {
sub_pel_filters_8smooth2[SUBPEL_SHIFTS]) = {
// freqmultiplier = 0.35
{0, 0, 0, 128, 0, 0, 0, 0},
{-1, 8, 31, 47, 34, 10, 0, -1},
{-1, 7, 29, 46, 36, 12, 0, -1},
{-1, 6, 28, 46, 37, 13, 0, -1},
{-1, 5, 26, 46, 38, 14, 1, -1},
{-1, 4, 25, 45, 39, 16, 1, -1},
{-1, 4, 23, 44, 41, 17, 1, -1},
{-1, 3, 21, 44, 42, 18, 2, -1},
{-1, 2, 20, 43, 43, 20, 2, -1},
{-1, 2, 18, 42, 44, 21, 3, -1},
{-1, 1, 17, 41, 44, 23, 4, -1},
{-1, 1, 16, 39, 45, 25, 4, -1},
{-1, 1, 14, 38, 46, 26, 5, -1},
{-1, 0, 13, 37, 46, 28, 6, -1},
{-1, 0, 12, 36, 46, 29, 7, -1},
{-1, 0, 10, 34, 47, 31, 8, -1},
};
DECLARE_ALIGNED(256, static const InterpKernel,
sub_pel_filters_8smooth[SUBPEL_SHIFTS]) = {
// freqmultiplier = 0.75
{0, 0, 0, 128, 0, 0, 0, 0},
{2, -10, 19, 95, 31, -11, 2, 0},
{2, -9, 14, 94, 37, -12, 2, 0},
{2, -8, 9, 92, 43, -12, 1, 1},
{2, -7, 5, 90, 49, -12, 1, 0},
{2, -5, 1, 86, 55, -12, 0, 1},
{1, -4, -2, 82, 61, -11, 0, 1},
{1, -3, -5, 77, 67, -9, -1, 1},
{1, -2, -7, 72, 72, -7, -2, 1},
{1, -1, -9, 67, 77, -5, -3, 1},
{1, 0, -11, 61, 82, -2, -4, 1},
{1, 0, -12, 55, 86, 1, -5, 2},
{0, 1, -12, 49, 90, 5, -7, 2},
{1, 1, -12, 43, 92, 9, -8, 2},
{0, 2, -12, 37, 94, 14, -9, 2},
{0, 2, -11, 31, 95, 19, -10, 2},
};
#else
DECLARE_ALIGNED(256, static const InterpKernel,
sub_pel_filters_8smooth[SUBPEL_SHIFTS]) = {
// freqmultiplier = 0.5
{ 0, 0, 0, 128, 0, 0, 0, 0},
{-3, -1, 32, 64, 38, 1, -3, 0},
{-2, -2, 29, 63, 41, 2, -3, 0},
......@@ -95,10 +181,14 @@ DECLARE_ALIGNED(256, static const InterpKernel,
{ 0, -3, 1, 38, 64, 32, -1, -3}
};
#endif // CONFIG_EXT_INTERP
const InterpKernel *vp10_filter_kernels[4] = {
const InterpKernel *vp10_filter_kernels[SWITCHABLE_FILTERS + 1] = {
sub_pel_filters_8,
sub_pel_filters_8lp,
sub_pel_filters_8s,
sub_pel_filters_8smooth,
sub_pel_filters_8sharp,
#if CONFIG_EXT_INTERP && SWITCHABLE_FILTERS == 4
sub_pel_filters_8smooth2,
#endif
bilinear_filters
};
......@@ -24,16 +24,24 @@ extern "C" {
#define EIGHTTAP 0
#define EIGHTTAP_SMOOTH 1
#define EIGHTTAP_SHARP 2
#if CONFIG_EXT_INTERP
#define SUPPORT_NONINTERPOLATING_FILTERS 0 /* turn it on for experimentation */
#define EIGHTTAP_SMOOTH2 3
#define SWITCHABLE_FILTERS 4 /* Number of switchable filters */
#else
#define SWITCHABLE_FILTERS 3 /* Number of switchable filters */
#define BILINEAR 3
#endif // CONFIG_EXT_INTERP
// The codec can operate in four possible inter prediction filter mode:
// 8-tap, 8-tap-smooth, 8-tap-sharp, and switching between the three.
#define BILINEAR (SWITCHABLE_FILTERS)
#define SWITCHABLE (SWITCHABLE_FILTERS + 1) /* the last one */
#define SWITCHABLE_FILTER_CONTEXTS (SWITCHABLE_FILTERS + 1)
#define SWITCHABLE 4 /* should be the last one */
typedef uint8_t INTERP_FILTER;
extern const InterpKernel *vp10_filter_kernels[4];
extern const InterpKernel *vp10_filter_kernels[SWITCHABLE_FILTERS + 1];
#ifdef __cplusplus
} // extern "C"
......
......@@ -48,6 +48,9 @@ static INLINE void clamp_mv(MV *mv, int min_col, int max_col,
mv->row = clamp(mv->row, min_row, max_row);
}
static INLINE int mv_has_subpel(const MV *mv) {
return (mv->row & 0x0F) || (mv->col & 0x0F);
}
#ifdef __cplusplus
} // extern "C"
#endif
......
......@@ -20,6 +20,7 @@
#include "vp10/common/entropymv.h"
#include "vp10/common/entropy.h"
#include "vp10/common/entropymode.h"
#include "vp10/common/mv.h"
#include "vp10/common/frame_buffers.h"
#include "vp10/common/quant_common.h"
#include "vp10/common/tile_common.h"
......@@ -531,6 +532,54 @@ static INLINE int txfm_partition_context(TXFM_CONTEXT *above_ctx,
}
#endif
#if CONFIG_EXT_INTERP
static INLINE int vp10_is_interp_needed(const MACROBLOCKD *const xd) {
MODE_INFO *const mi = xd->mi[0];
MB_MODE_INFO *const mbmi = &mi->mbmi;
const BLOCK_SIZE bsize = mbmi->sb_type;
const int is_compound = has_second_ref(mbmi);
int intpel_mv;
#if SUPPORT_NONINTERPOLATING_FILTERS
// TODO(debargha): This is is currently only for experimentation
// with non-interpolating filters. Remove later.
// If any of the filters are non-interpolating, then indicate the
// interpolation filter always.
int i;
for (i = 0; i < SWITCHABLE_FILTERS; ++i) {
if (!IsInterpolatingFilter(i)) return 1;
}
#endif
// For scaled references, interpolation filter is indicated all the time.
if (vp10_is_scaled(&xd->block_refs[0]->sf))
return 1;
if (is_compound && vp10_is_scaled(&xd->block_refs[1]->sf))
return 1;
if (bsize < BLOCK_8X8) {
intpel_mv =
!mv_has_subpel(&mi->bmi[0].as_mv[0].as_mv) &&
!mv_has_subpel(&mi->bmi[1].as_mv[0].as_mv) &&
!mv_has_subpel(&mi->bmi[2].as_mv[0].as_mv) &&
!mv_has_subpel(&mi->bmi[3].as_mv[0].as_mv);
if (is_compound && intpel_mv) {
intpel_mv &=
!mv_has_subpel(&mi->bmi[0].as_mv[1].as_mv) &&
!mv_has_subpel(&mi->bmi[1].as_mv[1].as_mv) &&
!mv_has_subpel(&mi->bmi[2].as_mv[1].as_mv) &&
!mv_has_subpel(&mi->bmi[3].as_mv[1].as_mv);
}
} else {
intpel_mv = !mv_has_subpel(&mbmi->mv[0].as_mv);
if (is_compound && intpel_mv) {
intpel_mv &= !mv_has_subpel(&mbmi->mv[1].as_mv);
}
}
return !intpel_mv;
}
#endif // CONFIG_EXT_INTERP
#ifdef __cplusplus
} // extern "C"
#endif
......
......@@ -64,9 +64,9 @@ void vp10_build_inter_predictor(const uint8_t *src, int src_stride,
}
void build_inter_predictors(MACROBLOCKD *xd, int plane, int block,
int bw, int bh,
int x, int y, int w, int h,
int mi_x, int mi_y) {
int bw, int bh,
int x, int y, int w, int h,
int mi_x, int mi_y) {
struct macroblockd_plane *const pd = &xd->plane[plane];
const MODE_INFO *mi = xd->mi[0];
const int is_compound = has_second_ref(&mi->mbmi);
......
......@@ -28,9 +28,22 @@ static INLINE void inter_predictor(const uint8_t *src, int src_stride,
int w, int h, int ref,
const InterpKernel *kernel,
int xs, int ys) {
#if CONFIG_EXT_INTERP && SUPPORT_NONINTERPOLATING_FILTERS
if (kernel[0][SUBPEL_TAPS / 2 - 1] == 128) {
// Interpolating filter
sf->predict[subpel_x != 0][subpel_y != 0][ref](
src, src_stride, dst, dst_stride,
kernel[subpel_x], xs, kernel[subpel_y], ys, w, h);
} else {
sf->predict_ni[subpel_x != 0][subpel_y != 0][ref](
src, src_stride, dst, dst_stride,
kernel[subpel_x], xs, kernel[subpel_y], ys, w, h);
}
#else
sf->predict[subpel_x != 0][subpel_y != 0][ref](
src, src_stride, dst, dst_stride,
kernel[subpel_x], xs, kernel[subpel_y], ys, w, h);
#endif // CONFIG_EXT_INTERP && SUPPORT_NONINTERPOLATING_FILTERS
}
#if CONFIG_VP9_HIGHBITDEPTH
......@@ -42,9 +55,22 @@ static INLINE void high_inter_predictor(const uint8_t *src, int src_stride,
int w, int h, int ref,
const InterpKernel *kernel,
int xs, int ys, int bd) {
#if CONFIG_EXT_INTERP && SUPPORT_NONINTERPOLATING_FILTERS
if (kernel[0][SUBPEL_TAPS / 2 - 1] == 128) {
// Interpolating filter
sf->highbd_predict[subpel_x != 0][subpel_y != 0][ref](
src, src_stride, dst, dst_stride,
kernel[subpel_x], xs, kernel[subpel_y], ys, w, h, bd);
} else {
sf->highbd_predict_ni[subpel_x != 0][subpel_y != 0][ref](
src, src_stride, dst, dst_stride,
kernel[subpel_x], xs, kernel[subpel_y], ys, w, h, bd);
}
#else
sf->highbd_predict[subpel_x != 0][subpel_y != 0][ref](
src, src_stride, dst, dst_stride,
kernel[subpel_x], xs, kernel[subpel_y], ys, w, h, bd);
#endif // CONFIG_EXT_INTERP && SUPPORT_NONINTERPOLATING_FILTERS
}
#endif // CONFIG_VP9_HIGHBITDEPTH
......@@ -192,7 +218,6 @@ void vp10_setup_dst_planes(struct macroblockd_plane planes[MAX_MB_PLANE],
void vp10_setup_pre_planes(MACROBLOCKD *xd, int idx,
const YV12_BUFFER_CONFIG *src, int mi_row, int mi_col,
const struct scale_factors *sf);
#ifdef __cplusplus
} // extern "C"
#endif
......
......@@ -46,15 +46,15 @@ MV32 vp10_scale_mv(const MV *mv, int x, int y, const struct scale_factors *sf) {
#if CONFIG_VP9_HIGHBITDEPTH
void vp10_setup_scale_factors_for_frame(struct scale_factors *sf,
int other_w, int other_h,
int this_w, int this_h,
int use_highbd) {
int other_w, int other_h,
int this_w, int this_h,
int use_highbd) {
#else
void vp10_setup_scale_factors_for_frame(struct scale_factors *sf,
int other_w, int other_h,
int this_w, int this_h) {
int other_w, int other_h,
int this_w, int this_h) {
#endif
if (!valid_ref_frame_size(other_w, other_h, this_w, this_h)) {
if (!valid_ref_frame_size(other_w, other_h, this_w, this_h)) {
sf->x_scale_fp = REF_INVALID_SCALE;
sf->y_scale_fp = REF_INVALID_SCALE;
return;
......@@ -79,6 +79,16 @@ void vp10_setup_scale_factors_for_frame(struct scale_factors *sf,
// applied in one direction only, and not at all for 0,0, seems to give the
// best quality, but it may be worth trying an additional mode that does
// do the filtering on full-pel.
#if CONFIG_EXT_INTERP && SUPPORT_NONINTERPOLATING_FILTERS
sf->predict_ni[0][0][0] = vpx_convolve8_c;
sf->predict_ni[0][0][1] = vpx_convolve8_avg_c;
sf->predict_ni[0][1][0] = vpx_convolve8_c;
sf->predict_ni[0][1][1] = vpx_convolve8_avg_c;
sf->predict_ni[1][0][0] = vpx_convolve8_c;
sf->predict_ni[1][0][1] = vpx_convolve8_avg_c;
sf->predict_ni[1][1][0] = vpx_convolve8;
sf->predict_ni[1][1][1] = vpx_convolve8_avg;
#endif // CONFIG_EXT_INTERP && SUPPORT_NONINTERPOLATING_FILTERS
if (sf->x_step_q4 == 16) {
if (sf->y_step_q4 == 16) {
// No scaling in either direction.
......@@ -119,8 +129,19 @@ void vp10_setup_scale_factors_for_frame(struct scale_factors *sf,
// 2D subpel motion always gets filtered in both directions
sf->predict[1][1][0] = vpx_convolve8;
sf->predict[1][1][1] = vpx_convolve8_avg;
#if CONFIG_VP9_HIGHBITDEPTH
if (use_highbd) {
#if CONFIG_EXT_INTERP && SUPPORT_NONINTERPOLATING_FILTERS
sf->highbd_predict_ni[0][0][0] = vpx_highbd_convolve8_c;
sf->highbd_predict_ni[0][0][1] = vpx_highbd_convolve8_avg_c;
sf->highbd_predict_ni[0][1][0] = vpx_highbd_convolve8_c;
sf->highbd_predict_ni[0][1][1] = vpx_highbd_convolve8_avg_c;
sf->highbd_predict_ni[1][0][0] = vpx_highbd_convolve8_c;
sf->highbd_predict_ni[1][0][1] = vpx_highbd_convolve8_avg_c;
sf->highbd_predict_ni[1][1][0] = vpx_highbd_convolve8;
sf->highbd_predict_ni[1][1][1] = vpx_highbd_convolve8_avg;
#endif // CONFIG_EXT_INTERP && SUPPORT_NONINTERPOLATING_FILTERS
if (sf->x_step_q4 == 16) {
if (sf->y_step_q4 == 16) {
// No scaling in either direction.
......@@ -162,5 +183,5 @@ void vp10_setup_scale_factors_for_frame(struct scale_factors *sf,
sf->highbd_predict[1][1][0] = vpx_highbd_convolve8;
sf->highbd_predict[1][1][1] = vpx_highbd_convolve8_avg;
}
#endif
#endif // CONFIG_VP9_HIGHBITDEPTH
}
......@@ -34,7 +34,15 @@ struct scale_factors {
convolve_fn_t predict[2][2][2]; // horiz, vert, avg
#if CONFIG_VP9_HIGHBITDEPTH
highbd_convolve_fn_t highbd_predict[2][2][2]; // horiz, vert, avg
#endif
#endif // CONFIG_VP9_HIGHBITDEPTH
// Functions for non-interpolating filters (those that filter zero offsets)
#if CONFIG_EXT_INTERP && SUPPORT_NONINTERPOLATING_FILTERS
convolve_fn_t predict_ni[2][2][2]; // horiz, vert, avg
#if CONFIG_VP9_HIGHBITDEPTH
highbd_convolve_fn_t highbd_predict_ni[2][2][2]; // horiz, vert, avg
#endif // CONFIG_VP9_HIGHBITDEPTH
#endif // CONFIG_EXT_INTERP && SUPPORT_NONINTERPOLATING_FILTERS
};
MV32 vp10_scale_mv(const MV *mv, int x, int y, const struct scale_factors *sf);
......@@ -48,7 +56,7 @@ void vp10_setup_scale_factors_for_frame(struct scale_factors *sf,
void vp10_setup_scale_factors_for_frame(struct scale_factors *sf,
int other_w, int other_h,
int this_w, int this_h);
#endif
#endif // CONFIG_VP9_HIGHBITDEPTH
static INLINE int vp10_is_valid_scale(const struct scale_factors *sf) {
return sf->x_scale_fp != REF_INVALID_SCALE &&
......
......@@ -625,6 +625,9 @@ static void dec_build_inter_predictors(VP10Decoder *const pbi, MACROBLOCKD *xd,
int xs, ys, x0, y0, x0_16, y0_16, frame_width, frame_height,
buf_stride, subpel_x, subpel_y;
uint8_t *ref_frame, *buf_ptr;
#if CONFIG_EXT_INTERP
const int i_filter = IsInterpolatingFilter(xd->mi[0]->mbmi.interp_filter);
#endif // CONFIG_EXT_INTERP
// Get reference frame pointer, width and height.
if (plane == 0) {
......@@ -694,6 +697,9 @@ static void dec_build_inter_predictors(VP10Decoder *const pbi, MACROBLOCKD *xd,
// Do border extension if there is motion or the
// width/height is not a multiple of 8 pixels.
if (is_scaled || scaled_mv.col || scaled_mv.row ||
#if CONFIG_EXT_INTERP
!i_filter ||
#endif
(frame_width & 0x7) || (frame_height & 0x7)) {
int y1 = ((y0_16 + (h - 1) * ys) >> SUBPEL_BITS) + 1;
......@@ -701,13 +707,21 @@ static void dec_build_inter_predictors(VP10Decoder *const pbi, MACROBLOCKD *xd,
int x1 = ((x0_16 + (w - 1) * xs) >> SUBPEL_BITS) + 1;
int x_pad = 0, y_pad = 0;
if (subpel_x || (sf->x_step_q4 != SUBPEL_SHIFTS)) {
if (subpel_x ||
#if CONFIG_EXT_INTERP
!i_filter ||
#endif
(sf->x_step_q4 != SUBPEL_SHIFTS)) {
x0 -= VP9_INTERP_EXTEND - 1;
x1 += VP9_INTERP_EXTEND;
x_pad = 1;
}
if (subpel_y || (sf->y_step_q4 != SUBPEL_SHIFTS)) {
if (subpel_y ||
#if CONFIG_EXT_INTERP
!i_filter ||
#endif
(sf->y_step_q4 != SUBPEL_SHIFTS)) {
y0 -= VP9_INTERP_EXTEND - 1;
y1 += VP9_INTERP_EXTEND;
y_pad = 1;
......@@ -1296,7 +1310,8 @@ static void setup_segmentation_dequant(VP10_COMMON *const cm) {
}
static INTERP_FILTER read_interp_filter(struct vpx_read_bit_buffer *rb) {
return vpx_rb_read_bit(rb) ? SWITCHABLE : vpx_rb_read_literal(rb, 2);
return vpx_rb_read_bit(rb) ?
SWITCHABLE : vpx_rb_read_literal(rb, 2 + CONFIG_EXT_INTERP);
}
static void setup_render_size(VP10_COMMON *cm,
......
......@@ -582,12 +582,17 @@ static INLINE INTERP_FILTER read_switchable_interp_filter(
VP10_COMMON *const cm, MACROBLOCKD *const xd,
vpx_reader *r) {
const int ctx = vp10_get_pred_context_switchable_interp(xd);
const INTERP_FILTER type =
(INTERP_FILTER)vpx_read_tree(r, vp10_switchable_interp_tree,
cm->fc->switchable_interp_prob[ctx]);
FRAME_COUNTS *counts = xd->counts;
INTERP_FILTER type;
#if CONFIG_EXT_INTERP
if (!vp10_is_interp_needed(xd)) return EIGHTTAP;
#endif
type = (INTERP_FILTER)vpx_read_tree(r, vp10_switchable_interp_tree,
cm->fc->switchable_interp_prob[ctx]);
if (counts)
++counts->switchable_interp[ctx][type];
// printf("%d/%d -> %d, %d\n", cm->current_video_frame, cm->show_frame,
// xd->mi[0]->mbmi.sb_type, xd->mi[0]->mbmi.interp_filter);
return type;
}
......@@ -753,9 +758,11 @@ static void read_inter_block_mode_info(VP10Decoder *const pbi,
}
}
#if !CONFIG_EXT_INTERP
mbmi->interp_filter = (cm->interp_filter == SWITCHABLE)
? read_switchable_interp_filter(cm, xd, r)
: cm->interp_filter;
? read_switchable_interp_filter(cm, xd, r)
: cm->interp_filter;
#endif // !CONFIG_EXT_INTERP
if (bsize < BLOCK_8X8) {
const int num_4x4_w = 1 << xd->bmode_blocks_wl;
......@@ -804,6 +811,11 @@ static void read_inter_block_mode_info(VP10Decoder *const pbi,
xd->corrupted |= !assign_mv(cm, xd, mbmi->mode, mbmi->mv, nearestmv,
nearestmv, nearmv, is_compound, allow_hp, r);
}
#if CONFIG_EXT_INTERP
mbmi->interp_filter = (cm->interp_filter == SWITCHABLE)
? read_switchable_interp_filter(cm, xd, r)
: cm->interp_filter;
#endif // CONFIG_EXT_INTERP
}
static void read_inter_frame_mode_info(VP10Decoder *const pbi,
......
......@@ -38,8 +38,13 @@
static const struct vp10_token intra_mode_encodings[INTRA_MODES] = {
{0, 1}, {6, 3}, {28, 5}, {30, 5}, {58, 6}, {59, 6}, {126, 7}, {127, 7},
{62, 6}, {2, 2}};
#if CONFIG_EXT_INTERP && SWITCHABLE_FILTERS == 4
static const struct vp10_token switchable_interp_encodings[SWITCHABLE_FILTERS] =
{{0, 1}, {4, 3}, {3, 2}, {5, 3}};
#else
static const struct vp10_token switchable_interp_encodings[SWITCHABLE_FILTERS] =
{{0, 1}, {2, 2}, {3, 2}};
#endif // CONFIG_EXT_INTERP && SWITCHABLE_FILTERS == 4
static const struct vp10_token partition_encodings[PARTITION_TYPES] =
{{0, 1}, {2, 2}, {6, 3}, {7, 3}};
static const struct vp10_token inter_mode_encodings[INTER_MODES] =
......@@ -548,6 +553,28 @@ static void write_ext_intra_mode_info(const VP10_COMMON *const cm,
}
#endif // CONFIG_EXT_INTRA
static void write_switchable_interp_filter(VP10_COMP *cpi,
const MACROBLOCKD *xd,
vpx_writer *w) {
VP10_COMMON *const cm = &cpi->common;
const MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
if (cm->interp_filter == SWITCHABLE) {
const int ctx = vp10_get_pred_context_switchable_interp(xd);
#if CONFIG_EXT_INTERP
if (!vp10_is_interp_needed(xd)) {
// if (mbmi->interp_filter != EIGHTTAP)
// printf("Error [%d]\n", mbmi->sb_type);
assert(mbmi->interp_filter == EIGHTTAP);
return;
}
#endif
vp10_write_token(w, vp10_switchable_interp_tree,
cm->fc->switchable_interp_prob[ctx],
&switchable_interp_encodings[mbmi->interp_filter]);
++cpi->interp_filter_selected[0][mbmi->interp_filter];
}
}
static void pack_inter_mode_mvs(VP10_COMP *cpi, const MODE_INFO *mi,
vpx_writer *w) {
VP10_COMMON *const cm = &cpi->common;
......@@ -645,15 +672,9 @@ static void pack_inter_mode_mvs(VP10_COMP *cpi, const MODE_INFO *mi,
}
}
if (cm->interp_filter == SWITCHABLE) {
const int ctx = vp10_get_pred_context_switchable_interp(xd);
vp10_write_token(w, vp10_switchable_interp_tree,
cm->fc->switchable_interp_prob[ctx],
&switchable_interp_encodings[mbmi->interp_filter]);
++cpi->interp_filter_selected[0][mbmi->interp_filter];
} else {
assert(mbmi->interp_filter == cm->interp_filter);
}
#if !CONFIG_EXT_INTERP
write_switchable_interp_filter