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
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;
}
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, },
{ 34, 3, },
{ 149, 144, },
};
+#endif
#if CONFIG_EXT_TX
const vpx_tree_index vp10_ext_tx_inter_tree[EXT_TX_SETS_INTER]
#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;
{ 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},
{ -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},
{-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},
{ 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
};
#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"
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
#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"
}
#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
}
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);
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
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
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
#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;
// 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.
// 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.
sf->highbd_predict[1][1][0] = vpx_highbd_convolve8;
sf->highbd_predict[1][1][1] = vpx_highbd_convolve8_avg;
}
-#endif
+#endif // CONFIG_VP9_HIGHBITDEPTH
}
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);
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 &&
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) {
// 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;
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;
}
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,
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;
}
}
}
+#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;
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,
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] =
}
#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;
}
}
- 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(cpi, xd, w);
+#endif // !CONFIG_EXT_INTERP
if (bsize < BLOCK_8X8) {
const int num_4x4_w = num_4x4_blocks_wide_lookup[bsize];
allow_hp);
}
}
+#if CONFIG_EXT_INTERP
+ write_switchable_interp_filter(cpi, xd, w);
+#endif // CONFIG_EXT_INTERP
}
#if CONFIG_EXT_TX
}
}
- // printf("Update %d %d, savings %d\n", update[0], update[1], savings);
/* Is coef updated at all */
if (update[1] == 0 || savings < 0) {
vpx_write_bit(bc, 0);
struct vpx_write_bit_buffer *wb) {
vpx_wb_write_bit(wb, filter == SWITCHABLE);
if (filter != SWITCHABLE)
- vpx_wb_write_literal(wb, filter, 2);
+ vpx_wb_write_literal(wb, filter, 2 + CONFIG_EXT_INTERP);
}
static void fix_interp_filter(VP10_COMMON *cm, FRAME_COUNTS *counts) {
if (is_inter_block(mbmi)) {
vp10_update_mv_count(td);
- if (cm->interp_filter == SWITCHABLE) {
+ if (cm->interp_filter == SWITCHABLE
+#if CONFIG_EXT_INTERP
+ && vp10_is_interp_needed(xd)
+#endif
+ ) {
const int ctx = vp10_get_pred_context_switchable_interp(xd);
++td->counts->switchable_interp[ctx][mbmi->interp_filter];
}
else
cm->reference_mode = REFERENCE_MODE_SELECT;
- if (cm->interp_filter == SWITCHABLE)
+ if (cm->interp_filter == SWITCHABLE) {
cm->interp_filter = get_interp_filter(filter_thrs, is_alt_ref);
+ }
encode_frame_internal(cpi);
if (cpi->sf.recode_loop >= ALLOW_RECODE_KFARFGF) {
save_coding_context(cpi);
vp10_pack_bitstream(cpi, dest, size);
-
rc->projected_frame_size = (int)(*size) << 3;
restore_coding_context(cpi);
const MACROBLOCKD *const xd) {
const MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
const int ctx = vp10_get_pred_context_switchable_interp(xd);
+#if CONFIG_EXT_INTERP
+ if (!vp10_is_interp_needed(xd)) return 0;
+#endif // CONFIG_EXT_INTERP
return SWITCHABLE_INTERP_RATE_FACTOR *
- cpi->switchable_interp_costs[ctx][mbmi->interp_filter];
+ cpi->switchable_interp_costs[ctx][mbmi->interp_filter];
}
void vp10_set_rd_speed_thresholds(VP10_COMP *cpi) {
x->e_mbd.plane[0].pre[1] = orig_pre[1];
}
-static INLINE int mv_has_subpel(const MV *mv) {
- return (mv->row & 0x0F) || (mv->col & 0x0F);
-}
-
// Check if NEARESTMV/NEARMV/ZEROMV is the cheapest way encode zero motion.
// TODO(aconverse): Find out if this is still productive then clean up or remove
static int check_best_zero_mv(
// frame we must use a unit scaling factor during mode selection.
#if CONFIG_VP9_HIGHBITDEPTH
vp10_setup_scale_factors_for_frame(&sf, cm->width, cm->height,
- cm->width, cm->height,
- cm->use_highbitdepth);
+ cm->width, cm->height,
+ cm->use_highbitdepth);
#else
vp10_setup_scale_factors_for_frame(&sf, cm->width, cm->height,
- cm->width, cm->height);
+ cm->width, cm->height);
#endif // CONFIG_VP9_HIGHBITDEPTH
// Allow joint search multiple times iteratively for each reference frame
if (cm->interp_filter != BILINEAR) {
if (x->source_variance < cpi->sf.disable_filter_search_var_thresh) {
best_filter = EIGHTTAP;
+#if CONFIG_EXT_INTERP
+ } else if (!vp10_is_interp_needed(xd) && cm->interp_filter == SWITCHABLE) {
+ best_filter = EIGHTTAP;
+#endif
} else if (best_filter == SWITCHABLE) {
int newbest;
int tmp_rate_sum = 0;
rs = vp10_get_switchable_rate(cpi, xd);
rs_rd = RDCOST(x->rdmult, x->rddiv, rs, 0);
- if (i > 0 && intpel_mv) {
+ if (i > 0 && intpel_mv && IsInterpolatingFilter(i)) {
rd = RDCOST(x->rdmult, x->rddiv, tmp_rate_sum, tmp_dist_sum);
filter_cache[i] = rd;
filter_cache[SWITCHABLE_FILTERS] =
(!i || best_needs_copy)) ||
(cm->interp_filter != SWITCHABLE &&
(cm->interp_filter == mbmi->interp_filter ||
- (i == 0 && intpel_mv)))) {
+ (i == 0 && intpel_mv && IsInterpolatingFilter(i))))) {
restore_dst_buf(xd, orig_dst, orig_dst_stride);
} else {
for (j = 0; j < MAX_MB_PLANE; j++) {
rd += rs_rd;
*mask_filter = VPXMAX(*mask_filter, rd);
- if (i == 0 && intpel_mv) {
+ if (i == 0 && intpel_mv && IsInterpolatingFilter(i)) {
tmp_rate_sum = rate_sum;
tmp_dist_sum = dist_sum;
}
if (newbest) {
best_rd = rd;
best_filter = mbmi->interp_filter;
- if (cm->interp_filter == SWITCHABLE && i && !intpel_mv)
+ if (cm->interp_filter == SWITCHABLE && i &&
+ !(intpel_mv && IsInterpolatingFilter(i)))
best_needs_copy = !best_needs_copy;
}
restore_dst_buf(xd, orig_dst, orig_dst_stride);
}
}
+
// Set the appropriate filter
mbmi->interp_filter = cm->interp_filter != SWITCHABLE ?
cm->interp_filter : best_filter;
single_newmv, single_inter_filter,
single_skippable, &total_sse, best_rd,
&mask_filter, filter_cache);
+
if (this_rd == INT64_MAX)
continue;
// Cost the skip mb case
rate2 += vp10_cost_bit(vp10_get_skip_prob(cm, xd), 1);
+
} else if (ref_frame != INTRA_FRAME && !xd->lossless[mbmi->segment_id]) {
if (RDCOST(x->rdmult, x->rddiv, rate_y + rate_uv, distortion2) <
RDCOST(x->rdmult, x->rddiv, 0, total_sse)) {
if (cm->interp_filter != BILINEAR) {
best_filter = EIGHTTAP;
if (cm->interp_filter == SWITCHABLE &&
+#if CONFIG_EXT_INTERP
+ vp10_is_interp_needed(xd) &&
+#endif // CONFIG_EXT_INTERP
x->source_variance >= cpi->sf.disable_filter_search_var_thresh) {
int rs;
int best_rs = INT_MAX;
(int) this_rd_thresh, seg_mvs,
bsi, switchable_filter_index,
mi_row, mi_col);
-
+#if CONFIG_EXT_INTERP
+ if (!vp10_is_interp_needed(xd) && cm->interp_filter == SWITCHABLE &&
+ mbmi->interp_filter != EIGHTTAP) // invalid configuration
+ continue;
+#endif // CONFIG_EXT_INTERP
if (tmp_rd == INT64_MAX)
continue;
rs = vp10_get_switchable_rate(cpi, xd);
mbmi->interp_filter = (cm->interp_filter == SWITCHABLE ?
tmp_best_filter : cm->interp_filter);
+
+
if (!pred_exists) {
// Handles the special case when a filter that is not in the
- // switchable list (bilinear, 6-tap) is indicated at the frame level
+ // switchable list (bilinear) is indicated at the frame level
tmp_rd = rd_pick_best_sub8x8_mode(cpi, x,
&x->mbmi_ext->ref_mvs[ref_frame][0],
second_ref, best_yrd, &rate, &rate_y,
&distortion, &skippable, &total_sse,
(int) this_rd_thresh, seg_mvs, bsi, 0,
mi_row, mi_col);
+#if CONFIG_EXT_INTERP
+ if (!vp10_is_interp_needed(xd) && cm->interp_filter == SWITCHABLE &&
+ mbmi->interp_filter != EIGHTTAP) {
+ mbmi->interp_filter = EIGHTTAP;
+ tmp_rd = rd_pick_best_sub8x8_mode(
+ cpi, x,
+ &x->mbmi_ext->ref_mvs[ref_frame][0],
+ second_ref, best_yrd, &rate, &rate_y,
+ &distortion, &skippable, &total_sse,
+ (int) this_rd_thresh, seg_mvs, bsi, 0,
+ mi_row, mi_col);
+ }
+#endif // CONFIG_EXT_INTERP
if (tmp_rd == INT64_MAX)
continue;
} else {