Commit be3559ba authored by hui su's avatar hui su
Browse files

ext-intra experiment

Currently there are two parts in this experiment: extra directional intra
prediction modes and the filter intra modes migrated from the nextgen branch.

Several macros are defined in "blockd.h" to provide controls of the experiment
settings. Setting "DR_ONLY" as 1 (default is 0) means we only use directional
modes, and skip the filter-intra modes; "EXT_INTRA_ANGLES" (default is 128)
defines the number of different angles we want to support; setting
"ANGLE_FAST_SEARCH" as 1 (default is 1) means we use fast sub-optimal search
for the best prediction angle, instead of exhaustive search. The fast search
is about 6 times faster than the exhaustive search, while preserving about
60% of the coding gains.

With extra directional prediction modes (fast search), we observe the following
code gains (number in parentheses is for all-key-frame setting):
derflr +0.42%  (+1.79%)
hevclr +0.78%  (+2.19%)
hevcmr +1.20%  (+3.49%)
stdhd  +0.56%
Speed-wise, about 110% slower for key frames, and 30% slower overall.

The gains of filter intra modes mostly add up with the gains of directional
modes. The overall coding gain of this experiment:
derflr +0.94%
hevclr +1.46%
hevcmr +1.94%
stdhd  +1.58%

Change-Id: Ida9ad00cdb33aff422d06eb42b4f4e5f25df8a2a
parent 4101154d
......@@ -77,6 +77,15 @@ typedef struct {
uint8_t palette_first_color_idx[2];
} PALETTE_MODE_INFO;
#if CONFIG_EXT_INTRA
typedef struct {
// 1: an ext intra mode is used; 0: otherwise.
uint8_t use_ext_intra_mode[PLANE_TYPES];
EXT_INTRA_MODE ext_intra_mode[PLANE_TYPES];
uint8_t ext_intra_angle[PLANE_TYPES];
} EXT_INTRA_MODE_INFO;
#endif // CONFIG_EXT_INTRA
// This structure now relates to 8x8 block regions.
typedef struct {
// Common for both INTER and INTRA blocks
......@@ -106,6 +115,10 @@ typedef struct {
TX_TYPE tx_type;
#endif // CONFIG_EXT_TX
#if CONFIG_EXT_INTRA
EXT_INTRA_MODE_INFO ext_intra_mode_info;
#endif // CONFIG_EXT_INTRA
// TODO(slavarnway): Delete and use bmi[3].as_mv[] instead.
int_mv mv[2];
} MB_MODE_INFO;
......@@ -307,11 +320,72 @@ static const int ext_tx_used_inter[EXT_TX_SETS_INTER][TX_TYPES] = {
};
#endif // CONFIG_EXT_TX
#if CONFIG_EXT_INTRA
// 0: use both directional and filter modes; 1: use directional modes only.
#define DR_ONLY 0
// 0: use slow exhaustive search; 1: use fast sub-optimal search.
#define ANGLE_FAST_SEARCH 1
// A parameter to adjust early termination in the fast search of angles.
#define RD_ADJUSTER 1.4
// Number of different angles that are supported
#define EXT_INTRA_ANGLES 128
static const TX_TYPE filter_intra_mode_to_tx_type_lookup[FILTER_INTRA_MODES] = {
DCT_DCT, // FILTER_DC
ADST_DCT, // FILTER_V
DCT_ADST, // FILTER_H
DCT_DCT, // FILTER_D45
ADST_ADST, // FILTER_D135
ADST_DCT, // FILTER_D117
DCT_ADST, // FILTER_D153
DCT_ADST, // FILTER_D207
ADST_DCT, // FILTER_D63
ADST_ADST, // FILTER_TM
};
// Maps the angle index to the actual prediction angle (in degrees).
// Angle index is in the range [0, EXT_INTRA_ANGLES); the actual prediction
// angle is in the range (0, 270).
static INLINE int prediction_angle_map(int angle_in) {
return (10 + 2 * angle_in);
}
#endif // CONFIG_EXT_INTRA
static INLINE TX_TYPE get_tx_type(PLANE_TYPE plane_type,
const MACROBLOCKD *xd,
int block_idx, TX_SIZE tx_size) {
const MODE_INFO *const mi = xd->mi[0];
const MB_MODE_INFO *const mbmi = &mi->mbmi;
#if CONFIG_EXT_INTRA
const int use_ext_intra_mode_info =
mbmi->ext_intra_mode_info.use_ext_intra_mode[plane_type];
const EXT_INTRA_MODE ext_intra_mode =
mbmi->ext_intra_mode_info.ext_intra_mode[plane_type];
if (!is_inter_block(mbmi) && use_ext_intra_mode_info) {
if (!xd->lossless[mbmi->segment_id] && tx_size < TX_32X32
#if CONFIG_EXT_TX
&& !(mbmi->sb_type >= BLOCK_8X8 && plane_type == PLANE_TYPE_Y)
#endif // CONFIG_EXT_TX
) {
if (ext_intra_mode > FILTER_TM_PRED) {
int angle = mbmi->ext_intra_mode_info.ext_intra_angle[plane_type];
angle = prediction_angle_map(angle);
assert(angle > 0 && angle < 270);
if (angle == 135)
return ADST_ADST;
else if (angle < 45 || angle > 225)
return DCT_DCT;
else if (angle < 135)
return ADST_DCT;
else
return DCT_ADST;
} else {
return filter_intra_mode_to_tx_type_lookup[ext_intra_mode];
}
}
}
#endif // CONFIG_EXT_INTRA
#if CONFIG_EXT_TX
#if USE_IDTX_FOR_32X32
......@@ -328,7 +402,6 @@ static INLINE TX_TYPE get_tx_type(PLANE_TYPE plane_type,
// UV Inter only
return (mbmi->tx_type == IDTX && tx_size == TX_32X32 ?
DCT_DCT : mbmi->tx_type);
// return mbmi->tx_type;
}
// Sub8x8-Inter/Intra OR UV-Intra
......
......@@ -955,6 +955,10 @@ static const struct segmentation_probs default_seg_probs = {
};
#endif
#if CONFIG_EXT_INTRA
static const vpx_prob default_ext_intra_probs[2] = {200, 200};
#endif // CONFIG_EXT_INTRA
static void init_mode_probs(FRAME_CONTEXT *fc) {
vp10_copy(fc->uv_mode_prob, default_uv_probs);
vp10_copy(fc->y_mode_prob, default_if_y_probs);
......@@ -978,6 +982,9 @@ static void init_mode_probs(FRAME_CONTEXT *fc) {
vp10_copy(fc->seg.tree_probs, default_seg_probs.tree_probs);
vp10_copy(fc->seg.pred_probs, default_seg_probs.pred_probs);
#endif
#if CONFIG_EXT_INTRA
vp10_copy(fc->ext_intra_probs, default_ext_intra_probs);
#endif // CONFIG_EXT_INTRA
}
const vpx_tree_index vp10_switchable_interp_tree
......@@ -1119,6 +1126,12 @@ void vp10_adapt_intra_frame_probs(VP10_COMMON *cm) {
vpx_tree_merge_probs(vp10_partition_tree, pre_fc->partition_prob[i],
counts->partition[i], fc->partition_prob[i]);
#endif
#if CONFIG_EXT_INTRA
for (i = 0; i < PLANE_TYPES; ++i) {
fc->ext_intra_probs[i] = mode_mv_merge_probs(
pre_fc->ext_intra_probs[i], counts->ext_intra[i]);
}
#endif // CONFIG_EXT_INTRA
}
static void set_default_lf_deltas(struct loopfilter *lf) {
......
......@@ -32,6 +32,10 @@ extern "C" {
#define PALETTE_BLOCK_SIZES (BLOCK_64X64 - BLOCK_8X8 + 1)
#define PALETTE_Y_MODE_CONTEXTS 3
#if CONFIG_EXT_INTRA
// Probability that an ext_intra mode is a directional prediction mode
#define DR_EXT_INTRA_PROB 144
#endif // CONFIG_EXT_INTRA
struct VP10Common;
......@@ -72,6 +76,7 @@ typedef struct frame_contexts {
#endif
vpx_prob skip_probs[SKIP_CONTEXTS];
nmv_context nmvc;
int initialized;
#if CONFIG_EXT_TX
vpx_prob inter_ext_tx_prob[EXT_TX_SETS_INTER][EXT_TX_SIZES][TX_TYPES - 1];
vpx_prob intra_ext_tx_prob[EXT_TX_SETS_INTRA][EXT_TX_SIZES][INTRA_MODES]
......@@ -80,7 +85,9 @@ typedef struct frame_contexts {
#if CONFIG_MISC_FIXES
struct segmentation_probs seg;
#endif
int initialized;
#if CONFIG_EXT_INTRA
vpx_prob ext_intra_probs[PLANE_TYPES];
#endif // CONFIG_EXT_INTRA
} FRAME_CONTEXT;
typedef struct FRAME_COUNTS {
......@@ -112,6 +119,9 @@ typedef struct FRAME_COUNTS {
#if CONFIG_MISC_FIXES
struct seg_counts seg;
#endif
#if CONFIG_EXT_INTRA
unsigned int ext_intra[PLANE_TYPES][2];
#endif // CONFIG_EXT_INTRA
} FRAME_COUNTS;
extern const vpx_prob vp10_kf_y_mode_prob[INTRA_MODES][INTRA_MODES]
......
......@@ -156,6 +156,25 @@ typedef enum {
PALETTE_COLORS
} PALETTE_COLOR;
#if CONFIG_EXT_INTRA
typedef enum {
FILTER_DC_PRED,
FILTER_V_PRED,
FILTER_H_PRED,
FILTER_D45_PRED,
FILTER_D135_PRED,
FILTER_D117_PRED,
FILTER_D153_PRED,
FILTER_D207_PRED,
FILTER_D63_PRED,
FILTER_TM_PRED,
EXT_DR_PRED,
EXT_INTRA_MODES,
} EXT_INTRA_MODE;
#define FILTER_INTRA_MODES (FILTER_TM_PRED + 1)
#endif // CONFIG_EXT_INTRA
#define DC_PRED 0 // Average of above and left pixels
#define V_PRED 1 // Vertical
#define H_PRED 2 // Horizontal
......
......@@ -8,6 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include <math.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
......@@ -268,6 +270,630 @@ static inline void memset16(uint16_t *dst, int val, int n) {
}
#endif
#if CONFIG_EXT_INTRA
#define PI 3.14159265
#define FILTER_INTRA_PREC_BITS 10
#define FILTER_INTRA_ROUND_VAL 511
#if CONFIG_MISC_FIXES
static const uint8_t ext_intra_extend_modes[FILTER_INTRA_MODES] = {
NEED_LEFT | NEED_ABOVE, // FILTER_DC
NEED_LEFT | NEED_ABOVE, // FILTER_V
NEED_LEFT | NEED_ABOVE, // FILTER_H
NEED_LEFT | NEED_ABOVE, // FILTER_D45
NEED_LEFT | NEED_ABOVE, // FILTER_D135
NEED_LEFT | NEED_ABOVE, // FILTER_D117
NEED_LEFT | NEED_ABOVE, // FILTER_D153
NEED_LEFT | NEED_ABOVE, // FILTER_D207
NEED_LEFT | NEED_ABOVE, // FILTER_D63
NEED_LEFT | NEED_ABOVE, // FILTER_TM
};
#else
static const uint8_t ext_intra_extend_modes[FILTER_INTRA_MODES] = {
NEED_LEFT | NEED_ABOVERIGHT, // FILTER_DC
NEED_LEFT | NEED_ABOVERIGHT, // FILTER_V
NEED_LEFT | NEED_ABOVERIGHT, // FILTER_H
NEED_LEFT | NEED_ABOVERIGHT, // FILTER_D45
NEED_LEFT | NEED_ABOVERIGHT, // FILTER_D135
NEED_LEFT | NEED_ABOVERIGHT, // FILTER_D117
NEED_LEFT | NEED_ABOVERIGHT, // FILTER_D153
NEED_LEFT | NEED_ABOVERIGHT, // FILTER_D207
NEED_LEFT | NEED_ABOVERIGHT, // FILTER_D63
NEED_LEFT | NEED_ABOVERIGHT, // FILTER_TM
};
#endif // CONFIG_MISC_FIXES
// Directional prediction, zone 1: 0 < angle < 90
static void dr_prediction_z1(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above, const uint8_t *left,
int dx, int dy) {
int r, c, x, y, base, shift, val;
(void)left;
(void)dy;
assert(dy == 1);
assert(dx < 0);
for (r = 0; r < bs; ++r) {
y = r + 1;
for (c = 0; c < bs; ++c) {
x = c * 256 - y * dx;
base = x >> 8;
shift = x - base * 256;
if (base < 2 * bs - 1) {
val =
(above[base] * (256 - shift) + above[base + 1] * shift + 128) >> 8;
dst[c] = clip_pixel(val);
} else {
dst[c] = above[2 * bs - 1];
}
}
dst += stride;
}
}
// Directional prediction, zone 2: 90 < angle < 180
static void dr_prediction_z2(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above, const uint8_t *left,
int dx, int dy) {
int r, c, x, y, val1, val2, shift, val, base;
assert(dx > 0);
assert(dy > 0);
for (r = 0; r < bs; ++r) {
for (c = 0; c < bs; ++c) {
y = r + 1;
x = c * 256 - y * dx;
if (x >= -256) {
if (x <= 0) {
val1 = above[-1];
val2 = above[0];
shift = x + 256;
} else {
base = x >> 8;
val1 = above[base];
val2 = above[base + 1];
shift = x - base * 256;
}
} else {
x = c + 1;
y = r * 256 - x * dy;
base = y >> 8;
if (base >= 0) {
val1 = left[base];
val2 = left[base + 1];
shift = y - base * 256;
} else {
val1 = val2 = left[0];
shift = 0;
}
}
val = (val1 * (256 - shift) + val2 * shift + 128) >> 8;
dst[c] = clip_pixel(val);
}
dst += stride;
}
}
// Directional prediction, zone 3: 180 < angle < 270
static void dr_prediction_z3(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above, const uint8_t *left,
int dx, int dy) {
int r, c, x, y, base, shift, val;
(void)above;
(void)dx;
assert(dx == 1);
assert(dy < 0);
for (r = 0; r < bs; ++r) {
for (c = 0; c < bs; ++c) {
x = c + 1;
y = r * 256 - x * dy;
base = y >> 8;
shift = y - base * 256;
if (base < bs - 1) {
val =
(left[base] * (256 - shift) + left[base + 1] * shift + 128) >> 8;
dst[c] = clip_pixel(val);
} else {
dst[c] = left[bs - 1];
}
}
dst += stride;
}
}
static INLINE void v_predictor(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above, const uint8_t *left) {
int r;
(void) left;
for (r = 0; r < bs; r++) {
memcpy(dst, above, bs);
dst += stride;
}
}
static INLINE void h_predictor(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above, const uint8_t *left) {
int r;
(void) above;
for (r = 0; r < bs; r++) {
memset(dst, left[r], bs);
dst += stride;
}
}
static void dr_predictor(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above, const uint8_t *left, int angle) {
double t = 0;
int dx, dy;
if (angle != 90 && angle != 180)
t = tan(angle * PI / 180.0);
if (angle > 0 && angle < 90) {
dx = -((int)(256 / t));
dy = 1;
dr_prediction_z1(dst, stride, bs, above, left, dx, dy);
} else if (angle > 90 && angle < 180) {
t = -t;
dx = (int)(256 / t);
dy = (int)(256 * t);
dr_prediction_z2(dst, stride, bs, above, left, dx, dy);
} else if (angle > 180 && angle < 270) {
dx = 1;
dy = -((int)(256 * t));
dr_prediction_z3(dst, stride, bs, above, left, dx, dy);
} else if (angle == 90) {
v_predictor(dst, stride, bs, above, left);
} else if (angle == 180) {
h_predictor(dst, stride, bs, above, left);
}
}
static int filter_intra_taps_4[TX_SIZES][INTRA_MODES][4] = {
{
{735, 881, -537, -54},
{1005, 519, -488, -11},
{383, 990, -343, -6},
{442, 805, -542, 319},
{658, 616, -133, -116},
{875, 442, -141, -151},
{386, 741, -23, -80},
{390, 1027, -446, 51},
{679, 606, -523, 262},
{903, 922, -778, -23},
},
{
{648, 803, -444, 16},
{972, 620, -576, 7},
{561, 967, -499, -5},
{585, 762, -468, 144},
{596, 619, -182, -9},
{895, 459, -176, -153},
{557, 722, -126, -129},
{601, 839, -523, 105},
{562, 709, -499, 251},
{803, 872, -695, 43},
},
{
{423, 728, -347, 111},
{963, 685, -665, 23},
{281, 1024, -480, 216},
{640, 596, -437, 78},
{429, 669, -259, 99},
{740, 646, -415, 23},
{568, 771, -346, 40},
{404, 833, -486, 209},
{398, 712, -423, 307},
{939, 935, -887, 17},
},
{
{477, 737, -393, 150},
{881, 630, -546, 67},
{506, 984, -443, -20},
{114, 459, -270, 528},
{433, 528, 14, 3},
{837, 470, -301, -30},
{181, 777, 89, -107},
{-29, 716, -232, 259},
{589, 646, -495, 255},
{740, 884, -728, 77},
},
};
static void filter_intra_predictors_4tap(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above,
const uint8_t *left,
int mode) {
int k, r, c;
int pred[33][65];
int mean, ipred;
const TX_SIZE tx_size = (bs == 32) ? TX_32X32 :
((bs == 16) ? TX_16X16 : ((bs == 8) ? TX_8X8 : (TX_4X4)));
const int c0 = filter_intra_taps_4[tx_size][mode][0];
const int c1 = filter_intra_taps_4[tx_size][mode][1];
const int c2 = filter_intra_taps_4[tx_size][mode][2];
const int c3 = filter_intra_taps_4[tx_size][mode][3];
k = 0;
mean = 0;
while (k < bs) {
mean = mean + (int)left[k];
mean = mean + (int)above[k];
k++;
}
mean = (mean + bs) / (2 * bs);
for (r = 0; r < bs; ++r)
pred[r + 1][0] = (int)left[r] - mean;
for (c = 0; c < 2 * bs + 1; ++c)
pred[0][c] = (int)above[c - 1] - mean;
for (r = 1; r < bs + 1; ++r)
for (c = 1; c < 2 * bs + 1 - r; ++c) {
ipred = c0 * pred[r - 1][c] + c1 * pred[r][c - 1] +
c2 * pred[r - 1][c - 1] + c3 * pred[r - 1][c + 1];
pred[r][c] = ipred < 0 ?
-((-ipred + FILTER_INTRA_ROUND_VAL) >> FILTER_INTRA_PREC_BITS) :
((ipred + FILTER_INTRA_ROUND_VAL) >> FILTER_INTRA_PREC_BITS);
}
for (r = 0; r < bs; ++r) {
for (c = 0; c < bs; ++c) {
ipred = pred[r + 1][c + 1] + mean;
dst[c] = clip_pixel(ipred);
}
dst += stride;
}
}
static void dc_filter_predictor(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above, const uint8_t *left) {
filter_intra_predictors_4tap(dst, stride, bs, above, left, DC_PRED);
}
static void v_filter_predictor(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above, const uint8_t *left) {
filter_intra_predictors_4tap(dst, stride, bs, above, left, V_PRED);
}
static void h_filter_predictor(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above, const uint8_t *left) {
filter_intra_predictors_4tap(dst, stride, bs, above, left, H_PRED);
}
static void d45_filter_predictor(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above, const uint8_t *left) {
filter_intra_predictors_4tap(dst, stride, bs, above, left, D45_PRED);
}
static void d135_filter_predictor(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above, const uint8_t *left) {
filter_intra_predictors_4tap(dst, stride, bs, above, left, D135_PRED);
}
static void d117_filter_predictor(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above, const uint8_t *left) {
filter_intra_predictors_4tap(dst, stride, bs, above, left, D117_PRED);
}
static void d153_filter_predictor(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above, const uint8_t *left) {
filter_intra_predictors_4tap(dst, stride, bs, above, left, D153_PRED);
}
static void d207_filter_predictor(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above, const uint8_t *left) {
filter_intra_predictors_4tap(dst, stride, bs, above, left, D207_PRED);
}
static void d63_filter_predictor(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above, const uint8_t *left) {
filter_intra_predictors_4tap(dst, stride, bs, above, left, D63_PRED);
}
static void tm_filter_predictor(uint8_t *dst, ptrdiff_t stride, int bs,
const uint8_t *above, const uint8_t *left) {
filter_intra_predictors_4tap(dst, stride, bs, above, left, TM_PRED);
}
static void (*filter_intra_predictors[EXT_INTRA_MODES])(uint8_t *dst,
ptrdiff_t stride, int bs, const uint8_t *above, const uint8_t *left) = {
dc_filter_predictor, v_filter_predictor, h_filter_predictor,
d45_filter_predictor, d135_filter_predictor, d117_filter_predictor,
d153_filter_predictor, d207_filter_predictor, d63_filter_predictor,
tm_filter_predictor,
};
#if CONFIG_VP9_HIGHBITDEPTH
// Directional prediction, zone 1: 0 < angle < 90
static void highbd_dr_prediction_z1(uint16_t *dst, ptrdiff_t stride, int bs,
const uint16_t *above, const uint16_t *left,
int dx, int dy, int bd) {
int r, c, x, y, base, shift, val;
(void)left;
(void)dy;
assert(dy == 1);
assert(dx < 0);
for (r = 0; r < bs; ++r) {
y = r + 1;
for (c = 0; c < bs; ++c) {
x = c * 256 - y * dx;
base = x >> 8;
shift = x - base * 256;
if (base < 2 * bs - 1) {
val =
(above[base] * (256 - shift) + above[base + 1] * shift + 128) >> 8;
dst[c] = clip_pixel_highbd(val, bd);
} else {
dst[c] = above[2 * bs - 1];
}
}
dst += stride;
}
}
// Directional prediction, zone 2: 90 < angle < 180
static void highbd_dr_prediction_z2(uint16_t *dst, ptrdiff_t stride, int bs,
const uint16_t *above, const uint16_t *left,
int dx, int dy, int bd) {
int r, c, x, y, val1, val2, shift, val, base;
assert(dx > 0);
assert(dy > 0);
for (r = 0; r < bs; ++r) {
for (c = 0; c < bs; ++c) {
y = r + 1;
x