Commit ff8b630c authored by Yaowu Xu's avatar Yaowu Xu Committed by On2 (Google) Code Review

Merge "Added Prediction Filter to Mode Selection" into experimental

parents cb231c88 bbc926dc
......@@ -231,6 +231,7 @@ EXPERIMENT_LIST="
int_8x8fdct
newintramodes
adaptive_entropy
pred_filter
"
CONFIG_LIST="
external_build
......
......@@ -214,6 +214,11 @@ typedef struct
// a valid predictor
unsigned char mb_in_image;
#if CONFIG_PRED_FILTER
// Flag to turn prediction signal filter on(1)/off(0 ) at the MB level
unsigned int pred_filter_enabled;
#endif
} MB_MODE_INFO;
typedef struct
......
......@@ -287,6 +287,15 @@ typedef struct VP8Common
#if CONFIG_POSTPROC
struct postproc_state postproc_state;
#endif
#if CONFIG_PRED_FILTER
/* Prediction filter variables */
int pred_filter_mode; // 0=disabled at the frame level (no MB filtered)
// 1=enabled at the frame level (all MB filtered)
// 2=specified per MB (1=filtered, 0=non-filtered)
vp8_prob prob_pred_filter_off;
#endif
} VP8_COMMON;
#endif
......@@ -335,18 +335,153 @@ static void build_inter_predictors2b(MACROBLOCKD *x, BLOCKD *d, int pitch)
/*encoder only*/
void vp8_build_inter16x16_predictors_mbuv(MACROBLOCKD *x)
#if CONFIG_PRED_FILTER
// Select the thresholded or non-thresholded filter
#define USE_THRESH_FILTER 0
#define PRED_FILT_LEN 5
static const int filt_shift = 4;
static const int pred_filter[PRED_FILT_LEN] = {1, 2, 10, 2, 1};
// Alternative filter {1, 1, 4, 1, 1}
#if !USE_THRESH_FILTER
void filter_mb(unsigned char *src, int src_stride,
unsigned char *dst, int dst_stride,
int width, int height)
{
int i, j, k;
unsigned int Temp[32*32];
unsigned int *pTmp = Temp;
unsigned char *pSrc = src - (1 + src_stride) * (PRED_FILT_LEN/2);
// Horizontal
for (i=0; i<height+PRED_FILT_LEN-1; i++)
{
for (j=0; j<width; j++)
{
int sum=0;
for (k=0; k<PRED_FILT_LEN; k++)
sum += pSrc[j+k] * pred_filter[k];
pTmp[j] = sum;
}
pSrc += src_stride;
pTmp += width;
}
// Vertical
pTmp = Temp;
for (i=0; i<width; i++)
{
unsigned char *pDst = dst + i;
for (j=0; j<height; j++)
{
int sum=0;
for (k=0; k<PRED_FILT_LEN; k++)
sum += pTmp[(j+k)*width] * pred_filter[k];
// Round
sum = (sum + ((1 << (filt_shift<<1))>>1)) >> (filt_shift << 1);
pDst[j*dst_stride] = (sum < 0 ? 0 : sum > 255 ? 255 : sum);
}
++pTmp;
}
}
#else
// Based on vp8_post_proc_down_and_across_c (postproc.c)
void filter_mb(unsigned char *src, int src_stride,
unsigned char *dst, int dst_stride,
int width, int height)
{
unsigned char *pSrc, *pDst;
int row;
int col;
int i;
int v;
unsigned char d[8];
/* TODO flimit should be linked to the quantizer value */
int flimit = 7;
for (row = 0; row < height; row++)
{
/* post_proc_down for one row */
pSrc = src;
pDst = dst;
for (col = 0; col < width; col++)
{
int kernel = (1 << (filt_shift-1));
int v = pSrc[col];
for (i = -2; i <= 2; i++)
{
if (abs(v - pSrc[col+i*src_stride]) > flimit)
goto down_skip_convolve;
kernel += pred_filter[2+i] * pSrc[col+i*src_stride];
}
v = (kernel >> filt_shift);
down_skip_convolve:
pDst[col] = v;
}
/* now post_proc_across */
pSrc = dst;
pDst = dst;
for (i = 0; i < 8; i++)
d[i] = pSrc[i];
for (col = 0; col < width; col++)
{
int kernel = (1 << (filt_shift-1));
v = pSrc[col];
d[col&7] = v;
for (i = -2; i <= 2; i++)
{
if (abs(v - pSrc[col+i]) > flimit)
goto across_skip_convolve;
kernel += pred_filter[2+i] * pSrc[col+i];
}
d[col&7] = (kernel >> filt_shift);
across_skip_convolve:
if (col >= 2)
pDst[col-2] = d[(col-2)&7];
}
/* handle the last two pixels */
pDst[col-2] = d[(col-2)&7];
pDst[col-1] = d[(col-1)&7];
/* next row */
src += src_stride;
dst += dst_stride;
}
}
#endif // !USE_THRESH_FILTER
#endif // CONFIG_PRED_FILTER
void vp8_build_inter16x16_predictors_mbuv(MACROBLOCKD *xd)
{
unsigned char *uptr, *vptr;
unsigned char *upred_ptr = &x->predictor[256];
unsigned char *vpred_ptr = &x->predictor[320];
unsigned char *upred_ptr = &xd->predictor[256];
unsigned char *vpred_ptr = &xd->predictor[320];
int omv_row = x->mode_info_context->mbmi.mv.as_mv.row;
int omv_col = x->mode_info_context->mbmi.mv.as_mv.col;
int omv_row = xd->mode_info_context->mbmi.mv.as_mv.row;
int omv_col = xd->mode_info_context->mbmi.mv.as_mv.col;
int mv_row = omv_row;
int mv_col = omv_col;
int offset;
int pre_stride = x->block[16].pre_stride;
int pre_stride = xd->block[16].pre_stride;
/* calc uv motion vectors */
if (mv_row < 0)
......@@ -362,30 +497,84 @@ void vp8_build_inter16x16_predictors_mbuv(MACROBLOCKD *x)
mv_row /= 2;
mv_col /= 2;
mv_row &= x->fullpixel_mask;
mv_col &= x->fullpixel_mask;
mv_row &= xd->fullpixel_mask;
mv_col &= xd->fullpixel_mask;
offset = (mv_row >> 3) * pre_stride + (mv_col >> 3);
uptr = x->pre.u_buffer + offset;
vptr = x->pre.v_buffer + offset;
uptr = xd->pre.u_buffer + offset;
vptr = xd->pre.v_buffer + offset;
#if CONFIG_PRED_FILTER
if (xd->mode_info_context->mbmi.pred_filter_enabled)
{
int i;
#if CONFIG_ENHANCED_INTERP
int Interp_Extend = 4; // 8-tap filter needs 3+4 pels extension
#else
int Interp_Extend = 3; // 6-tap filter needs 2+3 pels extension
#endif
int len = 7 + (Interp_Extend << 1);
unsigned char Temp[32*32]; // Input data required by sub-pel filter
unsigned char *pTemp = Temp + (Interp_Extend-1)*(len+1);
unsigned char *pSrc = uptr;
unsigned char *pDst = upred_ptr;
// U & V
for (i=0; i<2 ; i++)
{
#if CONFIG_SIXTEENTH_SUBPEL_UV
if ((omv_row | omv_col) & 15)
{
// Copy extended MB into Temp array, applying the spatial filter
filter_mb(pSrc-(Interp_Extend-1)*(pre_stride+1), pre_stride,
Temp, len, len, len);
// Sub-pel interpolation
xd->subpixel_predict8x8(pTemp, len, omv_col & 15,
omv_row & 15, pDst, 8);
}
#else /* CONFIG_SIXTEENTH_SUBPEL_UV */
if ((mv_row | mv_col) & 7)
{
// Copy extended MB into Temp array, applying the spatial filter
filter_mb(pSrc-(Interp_Extend-1)*(pre_stride+1), pre_stride,
Temp, len, len, len);
// Sub-pel interpolation
xd->subpixel_predict8x8(pTemp, len, mv_col & 7,
mv_row & 7, pDst, 8);
}
#endif /* CONFIG_SIXTEENTH_SUBPEL_UV */
else
{
// Apply prediction filter as we copy from source to destination
filter_mb(pSrc, pre_stride, pDst, 8, 8, 8);
}
// V
pSrc = vptr;
pDst = vpred_ptr;
}
}
else
#endif
#if CONFIG_SIXTEENTH_SUBPEL_UV
if ((omv_row | omv_col) & 15)
{
x->subpixel_predict8x8(uptr, pre_stride, omv_col & 15, omv_row & 15, upred_ptr, 8);
x->subpixel_predict8x8(vptr, pre_stride, omv_col & 15, omv_row & 15, vpred_ptr, 8);
xd->subpixel_predict8x8(uptr, pre_stride, omv_col & 15, omv_row & 15, upred_ptr, 8);
xd->subpixel_predict8x8(vptr, pre_stride, omv_col & 15, omv_row & 15, vpred_ptr, 8);
}
#else /* CONFIG_SIXTEENTH_SUBPEL_UV */
if ((mv_row | mv_col) & 7)
{
x->subpixel_predict8x8(uptr, pre_stride, mv_col & 7, mv_row & 7, upred_ptr, 8);
x->subpixel_predict8x8(vptr, pre_stride, mv_col & 7, mv_row & 7, vpred_ptr, 8);
xd->subpixel_predict8x8(uptr, pre_stride, mv_col & 7, mv_row & 7, upred_ptr, 8);
xd->subpixel_predict8x8(vptr, pre_stride, mv_col & 7, mv_row & 7, vpred_ptr, 8);
}
#endif /* CONFIG_SIXTEENTH_SUBPEL_UV */
else
{
RECON_INVOKE(&x->rtcd->recon, copy8x8)(uptr, pre_stride, upred_ptr, 8);
RECON_INVOKE(&x->rtcd->recon, copy8x8)(vptr, pre_stride, vpred_ptr, 8);
RECON_INVOKE(&xd->rtcd->recon, copy8x8)(uptr, pre_stride, upred_ptr, 8);
RECON_INVOKE(&xd->rtcd->recon, copy8x8)(vptr, pre_stride, vpred_ptr, 8);
}
}
......@@ -494,29 +683,68 @@ void vp8_build_inter4x4_predictors_mbuv(MACROBLOCKD *x)
/*encoder only*/
void vp8_build_inter16x16_predictors_mby(MACROBLOCKD *x)
void vp8_build_inter16x16_predictors_mby(MACROBLOCKD *xd)
{
unsigned char *ptr_base;
unsigned char *ptr;
unsigned char *pred_ptr = x->predictor;
int mv_row = x->mode_info_context->mbmi.mv.as_mv.row;
int mv_col = x->mode_info_context->mbmi.mv.as_mv.col;
int pre_stride = x->block[0].pre_stride;
unsigned char *pred_ptr = xd->predictor;
int mv_row = xd->mode_info_context->mbmi.mv.as_mv.row;
int mv_col = xd->mode_info_context->mbmi.mv.as_mv.col;
int pre_stride = xd->block[0].pre_stride;
ptr_base = x->pre.y_buffer;
ptr_base = xd->pre.y_buffer;
ptr = ptr_base + (mv_row >> 3) * pre_stride + (mv_col >> 3);
#if CONFIG_PRED_FILTER
if (xd->mode_info_context->mbmi.pred_filter_enabled)
{
// Produce predictor from the filtered source
if ((mv_row | mv_col) & 7)
{
// Sub-pel filter needs extended input
#if CONFIG_ENHANCED_INTERP
int Interp_Extend = 4; // 8-tap filter needs 3+4 pels extension
#else
int Interp_Extend = 3; // 6-tap filter needs 2+3 pels extension
#endif
int len = 15 + (Interp_Extend << 1);
unsigned char Temp[32*32]; // Data required by sub-pel filter
unsigned char *pTemp = Temp + (Interp_Extend-1)*(len+1);
// Copy extended MB into Temp array, applying the spatial filter
filter_mb(ptr-(Interp_Extend-1)*(pre_stride+1), pre_stride,
Temp, len, len, len);
// Sub-pel interpolation
#if CONFIG_SIXTEENTH_SUBPEL_UV
xd->subpixel_predict16x16(pTemp, len, (mv_col & 7)<<1,
(mv_row & 7)<<1, pred_ptr, 16);
#else
xd->subpixel_predict16x16(pTemp, len, mv_col & 7,
mv_row & 7, pred_ptr, 16);
#endif
}
else
{
// Apply spatial filter to create the prediction directly
filter_mb(ptr, pre_stride, pred_ptr, 16, 16, 16);
}
}
else
#endif
if ((mv_row | mv_col) & 7)
{
#if CONFIG_SIXTEENTH_SUBPEL_UV
x->subpixel_predict16x16(ptr, pre_stride, (mv_col & 7)<<1, (mv_row & 7)<<1, pred_ptr, 16);
xd->subpixel_predict16x16(ptr, pre_stride, (mv_col & 7)<<1,
(mv_row & 7)<<1, pred_ptr, 16);
#else
x->subpixel_predict16x16(ptr, pre_stride, mv_col & 7, mv_row & 7, pred_ptr, 16);
xd->subpixel_predict16x16(ptr, pre_stride, mv_col & 7,
mv_row & 7, pred_ptr, 16);
#endif
}
else
{
RECON_INVOKE(&x->rtcd->recon, copy16x16)(ptr, pre_stride, pred_ptr, 16);
RECON_INVOKE(&xd->rtcd->recon, copy16x16)(ptr, pre_stride, pred_ptr, 16);
}
}
......@@ -582,19 +810,64 @@ void vp8_build_inter16x16_predictors_mb(MACROBLOCKD *x,
clamp_mv_to_umv_border(&_16x16mv.as_mv, x);
}
ptr = ptr_base + ( _16x16mv.as_mv.row >> 3) * pre_stride + (_16x16mv.as_mv.col >> 3);
ptr = ptr_base + (_16x16mv.as_mv.row >> 3) * pre_stride +
(_16x16mv.as_mv.col >> 3);
#if CONFIG_PRED_FILTER
if (x->mode_info_context->mbmi.pred_filter_enabled)
{
if ( _16x16mv.as_int & 0x00070007)
{
// Sub-pel filter needs extended input
#if CONFIG_ENHANCED_INTERP
int Interp_Extend = 4; // 8-tap filter needs 3+4 pels extension
#else
int Interp_Extend = 3; // 6-tap filter needs 2+3 pels extension
#endif
int len = 15 + (Interp_Extend << 1);
unsigned char Temp[32*32]; // Data required by the sub-pel filter
unsigned char *pTemp = Temp + (Interp_Extend-1)*(len+1);
// Copy extended MB into Temp array, applying the spatial filter
filter_mb(ptr-(Interp_Extend-1)*(pre_stride+1), pre_stride,
Temp, len, len, len);
// Sub-pel filter
#if CONFIG_SIXTEENTH_SUBPEL_UV
x->subpixel_predict16x16(pTemp, len,
(_16x16mv.as_mv.col & 7)<<1,
(_16x16mv.as_mv.row & 7)<<1,
dst_y, dst_ystride);
#else
x->subpixel_predict16x16(pTemp, len,
_16x16mv.as_mv.col & 7,
_16x16mv.as_mv.row & 7,
dst_y, dst_ystride);
#endif
}
else
{
// Apply spatial filter to create the prediction directly
filter_mb(ptr, pre_stride, dst_y, dst_ystride, 16, 16);
}
}
else
#endif
if ( _16x16mv.as_int & 0x00070007)
{
#if CONFIG_SIXTEENTH_SUBPEL_UV
x->subpixel_predict16x16(ptr, pre_stride, (_16x16mv.as_mv.col & 7)<<1, (_16x16mv.as_mv.row & 7)<<1, dst_y, dst_ystride);
x->subpixel_predict16x16(ptr, pre_stride, (_16x16mv.as_mv.col & 7)<<1,
(_16x16mv.as_mv.row & 7)<<1,
dst_y, dst_ystride);
#else
x->subpixel_predict16x16(ptr, pre_stride, _16x16mv.as_mv.col & 7, _16x16mv.as_mv.row & 7, dst_y, dst_ystride);
x->subpixel_predict16x16(ptr, pre_stride, _16x16mv.as_mv.col & 7,
_16x16mv.as_mv.row & 7, dst_y, dst_ystride);
#endif
}
else
{
RECON_INVOKE(&x->rtcd->recon, copy16x16)(ptr, pre_stride, dst_y, dst_ystride);
RECON_INVOKE(&x->rtcd->recon, copy16x16)(ptr, pre_stride, dst_y,
dst_ystride);
}
_o16x16mv = _16x16mv;
......@@ -620,6 +893,63 @@ void vp8_build_inter16x16_predictors_mb(MACROBLOCKD *x,
uptr = x->pre.u_buffer + offset;
vptr = x->pre.v_buffer + offset;
#if CONFIG_PRED_FILTER
if (x->mode_info_context->mbmi.pred_filter_enabled)
{
int i;
unsigned char *pSrc = uptr;
unsigned char *pDst = dst_u;
#if CONFIG_ENHANCED_INTERP
int Interp_Extend = 4; // 8-tap filter needs 3+4 pels extension
#else
int Interp_Extend = 3; // 6-tap filter needs 2+3 pels extension
#endif
int len = 7 + (Interp_Extend << 1);
unsigned char Temp[32*32]; // Data required by the sub-pel filter
unsigned char *pTemp = Temp + (Interp_Extend-1)*(len+1);
// U & V
for (i=0; i<2; i++)
{
#if CONFIG_SIXTEENTH_SUBPEL_UV
if ( _o16x16mv.as_int & 0x000f000f)
{
// Copy extended MB into Temp array, applying the spatial filter
filter_mb(pSrc-(Interp_Extend-1)*(pre_stride+1), pre_stride,
Temp, len, len, len);
// Sub-pel filter
x->subpixel_predict8x8(pTemp, len,
_o16x16mv.as_mv.col & 15,
_o16x16mv.as_mv.row & 15,
pDst, dst_uvstride);
}
#else /* CONFIG_SIXTEENTH_SUBPEL_UV */
if ( _16x16mv.as_int & 0x00070007)
{
// Copy extended MB into Temp array, applying the spatial filter
filter_mb(pSrc-(Interp_Extend-1)*(pre_stride+1), pre_stride,
Temp, len, len, len);
// Sub-pel filter
x->subpixel_predict8x8(pTemp, len,
_16x16mv.as_mv.col & 7,
_16x16mv.as_mv.row & 7,
pDst, dst_uvstride);
}
#endif /* CONFIG_SIXTEENTH_SUBPEL_UV */
else
{
filter_mb(pSrc, pre_stride, pDst, dst_uvstride, 8, 8);
}
// V
pSrc = vptr;
pDst = dst_v;
}
}
else
#endif
#if CONFIG_SIXTEENTH_SUBPEL_UV
if ( _o16x16mv.as_int & 0x000f000f)
{
......@@ -687,17 +1017,60 @@ void vp8_build_2nd_inter16x16_predictors_mb(MACROBLOCKD *x,
ptr = ptr_base + (mv_row >> 3) * pre_stride + (mv_col >> 3);
if ((mv_row | mv_col) & 7)
#if CONFIG_PRED_FILTER
if (x->mode_info_context->mbmi.pred_filter_enabled)
{
if ((mv_row | mv_col) & 7)
{
// Sub-pel filter needs extended input
#if CONFIG_ENHANCED_INTERP
int Interp_Extend = 4; // 8-tap filter needs 3+4 pels extension
#else
int Interp_Extend = 3; // 6-tap filter needs 2+3 pels extension
#endif
int len = 15 + (Interp_Extend << 1);
unsigned char Temp[32*32]; // Data required by sub-pel filter
unsigned char *pTemp = Temp + (Interp_Extend-1)*(len+1);
// Copy extended MB into Temp array, applying the spatial filter
filter_mb(ptr-(Interp_Extend-1)*(pre_stride+1), pre_stride,
Temp, len, len, len);
// Sub-pel filter
#if CONFIG_SIXTEENTH_SUBPEL_UV
x->subpixel_predict_avg16x16(ptr, pre_stride, (mv_col & 7)<<1, (mv_row & 7)<<1, dst_y, dst_ystride);
x->subpixel_predict_avg16x16(pTemp, len, (mv_col & 7)<<1,
(mv_row & 7)<<1, dst_y, dst_ystride);
#else
x->subpixel_predict_avg16x16(ptr, pre_stride, mv_col & 7, mv_row & 7, dst_y, dst_ystride);
x->subpixel_predict_avg16x16(pTemp, len, mv_col & 7,
mv_row & 7, dst_y, dst_ystride);
#endif
}
else
{
// TODO Needs to AVERAGE with the dst_y
// For now, do not apply the prediction filter in these cases!
RECON_INVOKE(&x->rtcd->recon, avg16x16)(ptr, pre_stride, dst_y,
dst_ystride);
}
}
else
#endif // CONFIG_PRED_FILTER
{
RECON_INVOKE(&x->rtcd->recon, avg16x16)(ptr, pre_stride, dst_y, dst_ystride);
if ((mv_row | mv_col) & 7)
{
#if CONFIG_SIXTEENTH_SUBPEL_UV
x->subpixel_predict_avg16x16(ptr, pre_stride, (mv_col & 7)<<1,
(mv_row & 7)<<1, dst_y, dst_ystride);
#else
x->subpixel_predict_avg16x16(ptr, pre_stride, mv_col & 7,
mv_row & 7, dst_y, dst_ystride);
#endif
}
else
{
RECON_INVOKE(&x->rtcd->recon, avg16x16)(ptr, pre_stride, dst_y,
dst_ystride);
}
}
/* calc uv motion vectors */
......@@ -714,6 +1087,62 @@ void vp8_build_2nd_inter16x16_predictors_mb(MACROBLOCKD *x,
uptr = x->second_pre.u_buffer + offset;
vptr = x->second_pre.v_buffer + offset;
#if CONFIG_PRED_FILTER
if (x->mode_info_context->mbmi.pred_filter_enabled)
{
int i;
#if CONFIG_ENHANCED_INTERP
int Interp_Extend = 4; // 8-tap filter needs 3+4 pels extension
#else
int Interp_Extend = 3; // 6-tap filter needs 2+3 pels extension
#endif
int len = 7 + (Interp_Extend << 1);
unsigned char Temp[32*32]; // Data required by sub-pel filter
unsigned char *pTemp = Temp + (Interp_Extend-1)*(len+1);
unsigned char *pSrc = uptr;
unsigned char *pDst = dst_u;
// U & V
for (i=0; i<2; i++)
{
#if CONFIG_SIXTEENTH_SUBPEL_UV
if ((omv_row | omv_col) & 15)
{
// Copy extended MB into Temp array, applying the spatial filter
filter_mb(pSrc-(Interp_Extend-1)*(pre_stride+1), pre_stride,
Temp, len, len, len);
// Sub-pel filter
x->subpixel_predict_avg8x8(pTemp, len, omv_col & 15,
omv_row & 15, pDst, dst_uvstride);
}
#else /* CONFIG_SIXTEENTH_SUBPEL_UV */
if ((mv_row | mv_col) & 7)
{
// Copy extended MB into Temp array, applying the spatial filter
filter_mb(pSrc-(Interp_Extend-1)*(pre_stride+1), pre_stride,
Temp, len, len, len);
// Sub-pel filter
x->subpixel_predict_avg8x8(pTemp, len, mv_col & 7, mv_row & 7,
pDst, dst_uvstride);
}
#endif /* CONFIG_SIXTEENTH_SUBPEL_UV */
else
{
// TODO Needs to AVERAGE with the dst_[u|v]
// For now, do not apply the prediction filter here!
RECON_INVOKE(&x->rtcd->recon, avg8x8)(pSrc, pre_stride, pDst,
dst_uvstride);
}
// V
pSrc = vptr;
pDst = dst_v;
}
}
else
#endif // CONFIG_PRED_FILTER
#if CONFIG_SIXTEENTH_SUBPEL_UV
if ((omv_row | omv_col) & 15)