diff --git a/configure b/configure index a394fff7e6aa0cc1a74dd7b073dfca12d34e767b..b1a3f66515225eef8c4614f849cc2be03261d168 100755 --- a/configure +++ b/configure @@ -231,6 +231,7 @@ EXPERIMENT_LIST=" int_8x8fdct newintramodes adaptive_entropy + pred_filter " CONFIG_LIST=" external_build diff --git a/vp8/common/blockd.h b/vp8/common/blockd.h index 19511f31df0485771f786056de13df662c81a96d..26ac8262d96b81c5be0e8075d259218a1c4483b8 100644 --- a/vp8/common/blockd.h +++ b/vp8/common/blockd.h @@ -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 diff --git a/vp8/common/onyxc_int.h b/vp8/common/onyxc_int.h index f2795a8f8c54ac828f9bd34d3dd1dd160d6595fe..93c2fee54e21155ca7acba450ee86132e724b560 100644 --- a/vp8/common/onyxc_int.h +++ b/vp8/common/onyxc_int.h @@ -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 diff --git a/vp8/common/reconinter.c b/vp8/common/reconinter.c index 376fc7f0b57453d8821ae500dd814b0e85f24c49..384345c14506cc6bdb3a60b958d9df1cfd3c3de7 100644 --- a/vp8/common/reconinter.c +++ b/vp8/common/reconinter.c @@ -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) { diff --git a/vp8/decoder/decodemv.c b/vp8/decoder/decodemv.c index b7b5e49b130d8aa29154e670f6359344588a3b01..1243b359c1b8b7cc986d7b0c53fe317a69d57764 100644 --- a/vp8/decoder/decodemv.c +++ b/vp8/decoder/decodemv.c @@ -527,8 +527,14 @@ static void mb_mode_mv_init(VP8D_COMP *pbi) #endif } - if(pbi->common.frame_type != KEY_FRAME) + if(cm->frame_type != KEY_FRAME) { +#if CONFIG_PRED_FILTER + cm->pred_filter_mode = (vp8_prob)vp8_read_literal(bc, 2); + + if (cm->pred_filter_mode == 2) + cm->prob_pred_filter_off = (vp8_prob)vp8_read_literal(bc, 8); +#endif // Decode the baseline probabilities for decoding reference frame cm->prob_intra_coded = (vp8_prob)vp8_read_literal(bc, 8); cm->prob_last_coded = (vp8_prob)vp8_read_literal(bc, 8); @@ -728,6 +734,18 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, vp8_accum_mv_refs(&pbi->common, mbmi->mode, rct); } +#if CONFIG_PRED_FILTER + if (mbmi->mode >= NEARESTMV && mbmi->mode < SPLITMV) + { + // Is the prediction filter enabled + if (cm->pred_filter_mode == 2) + mbmi->pred_filter_enabled = + vp8_read(bc, cm->prob_pred_filter_off); + else + mbmi->pred_filter_enabled = cm->pred_filter_mode; + } +#endif + if ( cm->comp_pred_mode == COMP_PREDICTION_ONLY || (cm->comp_pred_mode == HYBRID_PREDICTION && vp8_read(bc, get_pred_prob( cm, xd, PRED_COMP ))) ) diff --git a/vp8/encoder/bitstream.c b/vp8/encoder/bitstream.c index e0cb2d48c76d93d3bf66f7f044c8e4c61712e011..99201ba78a3a7288060f31ffb2aa5c29801d67fc 100644 --- a/vp8/encoder/bitstream.c +++ b/vp8/encoder/bitstream.c @@ -815,6 +815,18 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi) #endif } +#if CONFIG_PRED_FILTER + // Write the prediction filter mode used for this frame + vp8_write_literal(w, pc->pred_filter_mode, 2); + + // Write prediction filter on/off probability if signaling at MB level + if (pc->pred_filter_mode == 2) + vp8_write_literal(w, pc->prob_pred_filter_off, 8); + + //printf("pred_filter_mode:%d prob_pred_filter_off:%d\n", + // pc->pred_filter_mode, pc->prob_pred_filter_off); +#endif + vp8_write_literal(w, pc->prob_intra_coded, 8); vp8_write_literal(w, pc->prob_last_coded, 8); vp8_write_literal(w, pc->prob_gf_coded, 8); @@ -1032,6 +1044,18 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi) vp8_accum_mv_refs(&cpi->common, mode, ct); } +#if CONFIG_PRED_FILTER + // Is the prediction filter enabled + if (mode >= NEARESTMV && mode < SPLITMV) + { + if (cpi->common.pred_filter_mode == 2 ) + vp8_write(w, mi->pred_filter_enabled, + pc->prob_pred_filter_off); + else + assert (mi->pred_filter_enabled == + cpi->common.pred_filter_mode); + } +#endif if (mi->second_ref_frame && (mode == NEWMV || mode == SPLITMV)) { diff --git a/vp8/encoder/encodeframe.c b/vp8/encoder/encodeframe.c index 55041c5a695e7b153aaff5f62b68235e3e4da27c..a6941925ef99d02b2a53752ec0f40b3154e144c8 100644 --- a/vp8/encoder/encodeframe.c +++ b/vp8/encoder/encodeframe.c @@ -1201,6 +1201,19 @@ static void encode_frame_internal(VP8_COMP *cpi) cpi->skip_false_count = 0; #endif +#if CONFIG_PRED_FILTER + if (cm->current_video_frame == 0) + { + // Initially assume that we'll signal the prediction filter + // state at the frame level and that it is off. + cpi->common.pred_filter_mode = 0; + cpi->common.prob_pred_filter_off = 128; + } + cpi->pred_filter_on_count = 0; + cpi->pred_filter_off_count = 0; + +#endif + #if 0 // Experimental code cpi->frame_distortion = 0; diff --git a/vp8/encoder/encodemb.c b/vp8/encoder/encodemb.c index 345bab007a1e6f75ae55260c2d158c96164a10d6..dcf479f6132ac78bef495036d07d83f6251781fe 100644 --- a/vp8/encoder/encodemb.c +++ b/vp8/encoder/encodemb.c @@ -1223,6 +1223,11 @@ void vp8_encode_inter16x16y(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x) BLOCK *b = &x->block[0]; +#if CONFIG_PRED_FILTER + // Disable the prediction filter for firstpass + x->e_mbd.mode_info_context->mbmi.pred_filter_enabled = 0; +#endif + vp8_build_inter16x16_predictors_mby(&x->e_mbd); ENCODEMB_INVOKE(&rtcd->encodemb, submby)(x->src_diff, *(b->base_src), x->e_mbd.predictor, b->src_stride); diff --git a/vp8/encoder/encodemb.h b/vp8/encoder/encodemb.h index e211eea65f6724177f365366ea041b1562edaa98..396a15196787b21b5f373bf67f2dd456716d85f3 100644 --- a/vp8/encoder/encodemb.h +++ b/vp8/encoder/encodemb.h @@ -83,6 +83,17 @@ typedef struct prototype_submbuv(*submbuv); } vp8_encodemb_rtcd_vtable_t; +typedef struct +{ + MB_PREDICTION_MODE mode; + MV_REFERENCE_FRAME ref_frame; + MV_REFERENCE_FRAME second_ref_frame; +#if CONFIG_PRED_FILTER + int pred_filter_flag; +#endif +} MODE_DEFINITION; + + #if CONFIG_RUNTIME_CPU_DETECT #define ENCODEMB_INVOKE(ctx,fn) (ctx)->fn #else diff --git a/vp8/encoder/mbgraph.c b/vp8/encoder/mbgraph.c index d2d3b6bdcdf6b0ff4fdeaef12c5f7d2f3d75eb62..cad27500a8bfea582b2802a2cf906151de83f406 100644 --- a/vp8/encoder/mbgraph.c +++ b/vp8/encoder/mbgraph.c @@ -104,6 +104,11 @@ static unsigned int do_16x16_motion_iteration &distortion, &sse); } +#if CONFIG_PRED_FILTER + // Disable the prediction filter + xd->mode_info_context->mbmi.pred_filter_enabled = 0; +#endif + vp8_set_mbmode_and_mvs(x, NEWMV, dst_mv); vp8_build_inter16x16_predictors_mby(xd); //VARIANCE_INVOKE(&cpi->rtcd.variance, satd16x16) diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c index decb31b4ba9b899fec3eedfba28db0b51029b0cd..ccb2cb7d45802170161051fea776511d745c6afc 100644 --- a/vp8/encoder/onyx_if.c +++ b/vp8/encoder/onyx_if.c @@ -741,6 +741,41 @@ void vp8_set_speed_features(VP8_COMP *cpi) switch (Mode) { case 0: // best quality mode +#if CONFIG_PRED_FILTER + sf->thresh_mult[THR_ZEROMV ] = 0; + sf->thresh_mult[THR_ZEROMV_FILT ] = 0; + sf->thresh_mult[THR_ZEROG ] = 0; + sf->thresh_mult[THR_ZEROG_FILT ] = 0; + sf->thresh_mult[THR_ZEROA ] = 0; + sf->thresh_mult[THR_ZEROA_FILT ] = 0; + sf->thresh_mult[THR_NEARESTMV ] = 0; + sf->thresh_mult[THR_NEARESTMV_FILT] = 0; + sf->thresh_mult[THR_NEARESTG ] = 0; + sf->thresh_mult[THR_NEARESTG_FILT ] = 0; + sf->thresh_mult[THR_NEARESTA ] = 0; + sf->thresh_mult[THR_NEARESTA_FILT ] = 0; + sf->thresh_mult[THR_NEARMV ] = 0; + sf->thresh_mult[THR_NEARMV_FILT ] = 0; + sf->thresh_mult[THR_NEARG ] = 0; + sf->thresh_mult[THR_NEARG_FILT ] = 0; + sf->thresh_mult[THR_NEARA ] = 0; + sf->thresh_mult[THR_NEARA_FILT ] = 0; + + sf->thresh_mult[THR_DC ] = 0; + + sf->thresh_mult[THR_V_PRED ] = 1000; + sf->thresh_mult[THR_H_PRED ] = 1000; + sf->thresh_mult[THR_B_PRED ] = 2000; + sf->thresh_mult[THR_I8X8_PRED] = 2000; + sf->thresh_mult[THR_TM ] = 1000; + + sf->thresh_mult[THR_NEWMV ] = 1000; + sf->thresh_mult[THR_NEWG ] = 1000; + sf->thresh_mult[THR_NEWA ] = 1000; + sf->thresh_mult[THR_NEWMV_FILT ] = 1000; + sf->thresh_mult[THR_NEWG_FILT ] = 1000; + sf->thresh_mult[THR_NEWA_FILT ] = 1000; +#else sf->thresh_mult[THR_ZEROMV ] = 0; sf->thresh_mult[THR_ZEROG ] = 0; sf->thresh_mult[THR_ZEROA ] = 0; @@ -770,7 +805,7 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_NEWMV ] = 1000; sf->thresh_mult[THR_NEWG ] = 1000; sf->thresh_mult[THR_NEWA ] = 1000; - +#endif sf->thresh_mult[THR_SPLITMV ] = 2500; sf->thresh_mult[THR_SPLITG ] = 5000; sf->thresh_mult[THR_SPLITA ] = 5000; @@ -800,10 +835,14 @@ void vp8_set_speed_features(VP8_COMP *cpi) #endif break; case 1: +#if CONFIG_PRED_FILTER sf->thresh_mult[THR_NEARESTMV] = 0; + sf->thresh_mult[THR_NEARESTMV_FILT] = 0; sf->thresh_mult[THR_ZEROMV ] = 0; + sf->thresh_mult[THR_ZEROMV_FILT ] = 0; sf->thresh_mult[THR_DC ] = 0; sf->thresh_mult[THR_NEARMV ] = 0; + sf->thresh_mult[THR_NEARMV_FILT ] = 0; sf->thresh_mult[THR_V_PRED ] = 1000; sf->thresh_mult[THR_H_PRED ] = 1000; #if CONFIG_NEWINTRAMODES @@ -819,12 +858,18 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_TM ] = 1000; sf->thresh_mult[THR_NEARESTG ] = 1000; + sf->thresh_mult[THR_NEARESTG_FILT ] = 1000; sf->thresh_mult[THR_NEARESTA ] = 1000; + sf->thresh_mult[THR_NEARESTA_FILT ] = 1000; sf->thresh_mult[THR_ZEROG ] = 1000; sf->thresh_mult[THR_ZEROA ] = 1000; sf->thresh_mult[THR_NEARG ] = 1000; sf->thresh_mult[THR_NEARA ] = 1000; + sf->thresh_mult[THR_ZEROG_FILT ] = 1000; + sf->thresh_mult[THR_ZEROA_FILT ] = 1000; + sf->thresh_mult[THR_NEARG_FILT ] = 1000; + sf->thresh_mult[THR_NEARA_FILT ] = 1000; sf->thresh_mult[THR_ZEROMV ] = 0; sf->thresh_mult[THR_ZEROG ] = 0; @@ -835,11 +880,63 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_NEARMV ] = 0; sf->thresh_mult[THR_NEARG ] = 0; sf->thresh_mult[THR_NEARA ] = 0; + sf->thresh_mult[THR_ZEROMV_FILT ] = 0; + sf->thresh_mult[THR_ZEROG_FILT ] = 0; + sf->thresh_mult[THR_ZEROA_FILT ] = 0; + sf->thresh_mult[THR_NEARESTMV_FILT] = 0; + sf->thresh_mult[THR_NEARESTG_FILT ] = 0; + sf->thresh_mult[THR_NEARESTA_FILT ] = 0; + sf->thresh_mult[THR_NEARMV_FILT ] = 0; + sf->thresh_mult[THR_NEARG_FILT ] = 0; + sf->thresh_mult[THR_NEARA_FILT ] = 0; sf->thresh_mult[THR_NEWMV ] = 1000; sf->thresh_mult[THR_NEWG ] = 1000; sf->thresh_mult[THR_NEWA ] = 1000; + sf->thresh_mult[THR_NEWMV_FILT ] = 1000; + sf->thresh_mult[THR_NEWG_FILT ] = 1000; + sf->thresh_mult[THR_NEWA_FILT ] = 1000; +#else + sf->thresh_mult[THR_NEARESTMV] = 0; + sf->thresh_mult[THR_ZEROMV ] = 0; + sf->thresh_mult[THR_DC ] = 0; + sf->thresh_mult[THR_NEARMV ] = 0; + sf->thresh_mult[THR_V_PRED ] = 1000; + sf->thresh_mult[THR_H_PRED ] = 1000; +#if CONFIG_NEWINTRAMODES + sf->thresh_mult[THR_D45_PRED ] = 1000; + sf->thresh_mult[THR_D135_PRED] = 1000; + sf->thresh_mult[THR_D117_PRED] = 1000; + sf->thresh_mult[THR_D153_PRED] = 1000; + sf->thresh_mult[THR_D27_PRED ] = 1000; + sf->thresh_mult[THR_D63_PRED ] = 1000; +#endif + sf->thresh_mult[THR_B_PRED ] = 2500; + sf->thresh_mult[THR_I8X8_PRED] = 2500; + sf->thresh_mult[THR_TM ] = 1000; + sf->thresh_mult[THR_NEARESTG ] = 1000; + sf->thresh_mult[THR_NEARESTA ] = 1000; + + sf->thresh_mult[THR_ZEROG ] = 1000; + sf->thresh_mult[THR_ZEROA ] = 1000; + sf->thresh_mult[THR_NEARG ] = 1000; + sf->thresh_mult[THR_NEARA ] = 1000; + + sf->thresh_mult[THR_ZEROMV ] = 0; + sf->thresh_mult[THR_ZEROG ] = 0; + sf->thresh_mult[THR_ZEROA ] = 0; + sf->thresh_mult[THR_NEARESTMV] = 0; + sf->thresh_mult[THR_NEARESTG ] = 0; + sf->thresh_mult[THR_NEARESTA ] = 0; + sf->thresh_mult[THR_NEARMV ] = 0; + sf->thresh_mult[THR_NEARG ] = 0; + sf->thresh_mult[THR_NEARA ] = 0; + + sf->thresh_mult[THR_NEWMV ] = 1000; + sf->thresh_mult[THR_NEWG ] = 1000; + sf->thresh_mult[THR_NEWA ] = 1000; +#endif sf->thresh_mult[THR_SPLITMV ] = 1700; sf->thresh_mult[THR_SPLITG ] = 4500; sf->thresh_mult[THR_SPLITA ] = 4500; @@ -906,6 +1003,9 @@ void vp8_set_speed_features(VP8_COMP *cpi) if (cpi->ref_frame_flags & VP8_LAST_FLAG) { sf->thresh_mult[THR_NEWMV ] = 2000; +#if CONFIG_PRED_FILTER + sf->thresh_mult[THR_NEWMV_FILT ] = 2000; +#endif sf->thresh_mult[THR_SPLITMV ] = 10000; sf->thresh_mult[THR_COMP_SPLITLG ] = 20000; } @@ -916,6 +1016,12 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_ZEROG ] = 1500; sf->thresh_mult[THR_NEARG ] = 1500; sf->thresh_mult[THR_NEWG ] = 2000; +#if CONFIG_PRED_FILTER + sf->thresh_mult[THR_NEARESTG_FILT ] = 1500; + sf->thresh_mult[THR_ZEROG_FILT ] = 1500; + sf->thresh_mult[THR_NEARG_FILT ] = 1500; + sf->thresh_mult[THR_NEWG_FILT ] = 2000; +#endif sf->thresh_mult[THR_SPLITG ] = 20000; sf->thresh_mult[THR_COMP_SPLITGA ] = 20000; } @@ -926,6 +1032,12 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_ZEROA ] = 1500; sf->thresh_mult[THR_NEARA ] = 1500; sf->thresh_mult[THR_NEWA ] = 2000; +#if CONFIG_PRED_FILTER + sf->thresh_mult[THR_NEARESTA_FILT ] = 1500; + sf->thresh_mult[THR_ZEROA_FILT ] = 1500; + sf->thresh_mult[THR_NEARA_FILT ] = 1500; + sf->thresh_mult[THR_NEWA_FILT ] = 2000; +#endif sf->thresh_mult[THR_SPLITA ] = 20000; sf->thresh_mult[THR_COMP_SPLITLA ] = 10000; } @@ -972,6 +1084,9 @@ void vp8_set_speed_features(VP8_COMP *cpi) if (cpi->ref_frame_flags & VP8_LAST_FLAG) { sf->thresh_mult[THR_NEWMV ] = 2000; +#if CONFIG_PRED_FILTER + sf->thresh_mult[THR_NEWMV_FILT ] = 2000; +#endif sf->thresh_mult[THR_SPLITMV ] = 25000; sf->thresh_mult[THR_COMP_SPLITLG ] = 50000; } @@ -982,6 +1097,12 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_ZEROG ] = 2000; sf->thresh_mult[THR_NEARG ] = 2000; sf->thresh_mult[THR_NEWG ] = 2500; +#if CONFIG_PRED_FILTER + sf->thresh_mult[THR_NEARESTG_FILT ] = 2000; + sf->thresh_mult[THR_ZEROG_FILT ] = 2000; + sf->thresh_mult[THR_NEARG_FILT ] = 2000; + sf->thresh_mult[THR_NEWG_FILT ] = 2500; +#endif sf->thresh_mult[THR_SPLITG ] = 50000; sf->thresh_mult[THR_COMP_SPLITGA ] = 50000; } @@ -992,6 +1113,12 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_ZEROA ] = 2000; sf->thresh_mult[THR_NEARA ] = 2000; sf->thresh_mult[THR_NEWA ] = 2500; +#if CONFIG_PRED_FILTER + sf->thresh_mult[THR_NEARESTA_FILT ] = 2000; + sf->thresh_mult[THR_ZEROA_FILT ] = 2000; + sf->thresh_mult[THR_NEARA_FILT ] = 2000; + sf->thresh_mult[THR_NEWA_FILT ] = 2500; +#endif sf->thresh_mult[THR_SPLITA ] = 50000; sf->thresh_mult[THR_COMP_SPLITLA ] = 25000; } @@ -1029,6 +1156,12 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_NEARESTMV] = INT_MAX; sf->thresh_mult[THR_ZEROMV ] = INT_MAX; sf->thresh_mult[THR_NEARMV ] = INT_MAX; +#if CONFIG_PRED_FILTER + sf->thresh_mult[THR_NEWMV_FILT ] = INT_MAX; + sf->thresh_mult[THR_NEARESTMV_FILT] = INT_MAX; + sf->thresh_mult[THR_ZEROMV_FILT ] = INT_MAX; + sf->thresh_mult[THR_NEARMV_FILT ] = INT_MAX; +#endif sf->thresh_mult[THR_SPLITMV ] = INT_MAX; } @@ -1038,6 +1171,12 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_ZEROG ] = INT_MAX; sf->thresh_mult[THR_NEARG ] = INT_MAX; sf->thresh_mult[THR_NEWG ] = INT_MAX; +#if CONFIG_PRED_FILTER + sf->thresh_mult[THR_NEARESTG_FILT ] = INT_MAX; + sf->thresh_mult[THR_ZEROG_FILT ] = INT_MAX; + sf->thresh_mult[THR_NEARG_FILT ] = INT_MAX; + sf->thresh_mult[THR_NEWG_FILT ] = INT_MAX; +#endif sf->thresh_mult[THR_SPLITG ] = INT_MAX; } @@ -1047,6 +1186,12 @@ void vp8_set_speed_features(VP8_COMP *cpi) sf->thresh_mult[THR_ZEROA ] = INT_MAX; sf->thresh_mult[THR_NEARA ] = INT_MAX; sf->thresh_mult[THR_NEWA ] = INT_MAX; +#if CONFIG_PRED_FILTER + sf->thresh_mult[THR_NEARESTA_FILT ] = INT_MAX; + sf->thresh_mult[THR_ZEROA_FILT ] = INT_MAX; + sf->thresh_mult[THR_NEARA_FILT ] = INT_MAX; + sf->thresh_mult[THR_NEWA_FILT ] = INT_MAX; +#endif sf->thresh_mult[THR_SPLITA ] = INT_MAX; } @@ -2866,6 +3011,55 @@ void loopfilter_frame(VP8_COMP *cpi, VP8_COMMON *cm) } +#if CONFIG_PRED_FILTER +void select_pred_filter_mode(VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + + int prob_pred_filter_off = cm->prob_pred_filter_off; + + // Force filter on/off if probability is extreme + if (prob_pred_filter_off >= 255 * 0.95) + cm->pred_filter_mode = 0; // Off at the frame level + else if (prob_pred_filter_off <= 255 * 0.05) + cm->pred_filter_mode = 1; // On at the frame level + else + cm->pred_filter_mode = 2; // Selectable at the MB level +} + +void update_pred_filt_prob(VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + int prob_pred_filter_off; + + // Based on the selection in the previous frame determine what mode + // to use for the current frame and work out the signaling probability + if ( cpi->pred_filter_on_count + cpi->pred_filter_off_count ) + { + prob_pred_filter_off = cpi->pred_filter_off_count * 256 / + ( cpi->pred_filter_on_count + cpi->pred_filter_off_count); + + if (prob_pred_filter_off < 1) + prob_pred_filter_off = 1; + + if (prob_pred_filter_off > 255) + prob_pred_filter_off = 255; + + cm->prob_pred_filter_off = prob_pred_filter_off; + } + else + cm->prob_pred_filter_off = 128; +/* + { + FILE *fp = fopen("filt_use.txt", "a"); + fprintf (fp, "%d %d prob=%d\n", cpi->pred_filter_off_count, + cpi->pred_filter_on_count, cm->prob_pred_filter_off); + fclose(fp); + } +*/ +} +#endif + static void encode_frame_to_data_rate ( VP8_COMP *cpi, @@ -3358,6 +3552,13 @@ static void encode_frame_to_data_rate vp8_clear_system_state(); //__asm emms; +#if CONFIG_PRED_FILTER + // Update prediction filter on/off probability based on + // selection made for the current frame + if (cm->frame_type != KEY_FRAME) + update_pred_filt_prob( cpi ); +#endif + // Dummy pack of the bitstream using up to date stats to get an // accurate estimate of output frame size to determine if we need // to recode. @@ -3691,6 +3892,13 @@ static void encode_frame_to_data_rate cpi->dummy_packing = 0; vp8_pack_bitstream(cpi, dest, size); +#if CONFIG_PRED_FILTER + // Select the prediction filtering mode to use for the + // next frame based on the current frame selections + if(cm->frame_type != KEY_FRAME) + select_pred_filter_mode (cpi); +#endif + update_reference_frames(cm); #if CONFIG_ADAPTIVE_ENTROPY vp8_copy(cpi->common.fc.coef_counts, cpi->coef_counts); diff --git a/vp8/encoder/onyx_int.h b/vp8/encoder/onyx_int.h index 54ed233405f6b950d4d22713d327d22c41e516c3..c838eccad213ca2db178489e430a45328fe7b675 100644 --- a/vp8/encoder/onyx_int.h +++ b/vp8/encoder/onyx_int.h @@ -43,11 +43,19 @@ #define AF_THRESH2 100 #define ARF_DECAY_THRESH 12 +#if CONFIG_PRED_FILTER +#if CONFIG_NEWINTRAMODES +#define MAX_MODES 54 +#else +#define MAX_MODES 48 +#endif +#else // CONFIG_PRED_FILTER #if CONFIG_NEWINTRAMODES #define MAX_MODES 42 #else #define MAX_MODES 36 #endif +#endif // CONFIG_PRED_FILTER #define MIN_THRESHMULT 32 #define MAX_THRESHMULT 512 @@ -164,25 +172,100 @@ typedef struct MBGRAPH_MB_STATS *mb_stats; } MBGRAPH_FRAME_STATS; +#if CONFIG_PRED_FILTER +typedef enum +{ + THR_ZEROMV, + THR_ZEROMV_FILT, + THR_DC, + + THR_NEARESTMV, + THR_NEARESTMV_FILT, + THR_NEARMV, + THR_NEARMV_FILT, + + THR_ZEROG, + THR_ZEROG_FILT, + THR_NEARESTG, + THR_NEARESTG_FILT, + + THR_ZEROA, + THR_ZEROA_FILT, + THR_NEARESTA, + THR_NEARESTA_FILT, + + THR_NEARG, + THR_NEARG_FILT, + THR_NEARA, + THR_NEARA_FILT, + + THR_V_PRED, + THR_H_PRED, +#if CONFIG_NEWINTRAMODES + THR_D45_PRED, + THR_D135_PRED, + THR_D117_PRED, + THR_D153_PRED, + THR_D27_PRED, + THR_D63_PRED, +#endif + THR_TM, + + THR_NEWMV, + THR_NEWMV_FILT, + THR_NEWG, + THR_NEWG_FILT, + THR_NEWA, + THR_NEWA_FILT, + + THR_SPLITMV, + THR_SPLITG, + THR_SPLITA, + + THR_B_PRED, + THR_I8X8_PRED, + + THR_COMP_ZEROLG, + THR_COMP_NEARESTLG, + THR_COMP_NEARLG, + + THR_COMP_ZEROLA, + THR_COMP_NEARESTLA, + THR_COMP_NEARLA, + + THR_COMP_ZEROGA, + THR_COMP_NEARESTGA, + THR_COMP_NEARGA, + + THR_COMP_NEWLG, + THR_COMP_NEWLA, + THR_COMP_NEWGA, + + THR_COMP_SPLITLG, + THR_COMP_SPLITLA, + THR_COMP_SPLITGA, +} +THR_MODES; +#else typedef enum { - THR_ZEROMV = 0, - THR_DC = 1, + THR_ZEROMV, + THR_DC, - THR_NEARESTMV = 2, - THR_NEARMV = 3, + THR_NEARESTMV, + THR_NEARMV, - THR_ZEROG = 4, - THR_NEARESTG = 5, + THR_ZEROG, + THR_NEARESTG, - THR_ZEROA = 6, - THR_NEARESTA = 7, + THR_ZEROA, + THR_NEARESTA, - THR_NEARG = 8, - THR_NEARA = 9, + THR_NEARG, + THR_NEARA, - THR_V_PRED = 10, - THR_H_PRED = 11, + THR_V_PRED, + THR_H_PRED, #if CONFIG_NEWINTRAMODES THR_D45_PRED, THR_D135_PRED, @@ -222,9 +305,10 @@ typedef enum THR_COMP_SPLITLG, THR_COMP_SPLITLA, - THR_COMP_SPLITGA, + THR_COMP_SPLITGA } THR_MODES; +#endif typedef enum { @@ -679,6 +763,11 @@ typedef struct VP8_COMP int dummy_packing; /* flag to indicate if packing is dummy */ +#if CONFIG_PRED_FILTER + int pred_filter_on_count; + int pred_filter_off_count; +#endif + } VP8_COMP; void control_data_rate(VP8_COMP *cpi); diff --git a/vp8/encoder/ratectrl.c b/vp8/encoder/ratectrl.c index 75246fca2af7d503e132059b565433a416780f4e..5ea74456affcd442628ad7ae0f0794062c8a7765 100644 --- a/vp8/encoder/ratectrl.c +++ b/vp8/encoder/ratectrl.c @@ -27,9 +27,7 @@ #define MIN_BPB_FACTOR 0.005 #define MAX_BPB_FACTOR 50 -extern const MB_PREDICTION_MODE vp8_mode_order[MAX_MODES]; -extern const MV_REFERENCE_FRAME vp8_ref_frame_order[MAX_MODES]; - +extern const MODE_DEFINITION vp8_mode_order[MAX_MODES]; #ifdef MODE_STATS diff --git a/vp8/encoder/rdopt.c b/vp8/encoder/rdopt.c index 18b62bf599abed7e1b4a3034e6dc9aa0dae7107a..0ec87bb8fcfec1be69d29fc6667cf7510c60baa7 100644 --- a/vp8/encoder/rdopt.c +++ b/vp8/encoder/rdopt.c @@ -81,161 +81,145 @@ static const int auto_speed_thresh[17] = 105 }; -const MB_PREDICTION_MODE vp8_mode_order[MAX_MODES] = +#if CONFIG_PRED_FILTER +const MODE_DEFINITION vp8_mode_order[MAX_MODES] = { - ZEROMV, - DC_PRED, - - NEARESTMV, - NEARMV, - - ZEROMV, - NEARESTMV, - - ZEROMV, - NEARESTMV, - - NEARMV, - NEARMV, - - V_PRED, - H_PRED, + {ZEROMV, LAST_FRAME, 0, 0}, + {ZEROMV, LAST_FRAME, 0, 1}, + {DC_PRED, INTRA_FRAME, 0, 0}, + + {NEARESTMV, LAST_FRAME, 0, 0}, + {NEARESTMV, LAST_FRAME, 0, 1}, + {NEARMV, LAST_FRAME, 0, 0}, + {NEARMV, LAST_FRAME, 0, 1}, + + {ZEROMV, GOLDEN_FRAME, 0, 0}, + {ZEROMV, GOLDEN_FRAME, 0, 1}, + {NEARESTMV, GOLDEN_FRAME, 0, 0}, + {NEARESTMV, GOLDEN_FRAME, 0, 1}, + + {ZEROMV, ALTREF_FRAME, 0, 0}, + {ZEROMV, ALTREF_FRAME, 0, 1}, + {NEARESTMV, ALTREF_FRAME, 0, 0}, + {NEARESTMV, ALTREF_FRAME, 0, 1}, + + {NEARMV, GOLDEN_FRAME, 0, 0}, + {NEARMV, GOLDEN_FRAME, 0, 1}, + {NEARMV, ALTREF_FRAME, 0, 0}, + {NEARMV, ALTREF_FRAME, 0, 1}, + + {V_PRED, INTRA_FRAME, 0, 0}, + {H_PRED, INTRA_FRAME, 0, 0}, #if CONFIG_NEWINTRAMODES - D45_PRED, - D135_PRED, - D117_PRED, - D153_PRED, - D27_PRED, - D63_PRED, + {D45_PRED, INTRA_FRAME, 0, 0}, + {D135_PRED, INTRA_FRAME, 0, 0}, + {D117_PRED, INTRA_FRAME, 0, 0}, + {D153_PRED, INTRA_FRAME, 0, 0}, + {D27_PRED, INTRA_FRAME, 0, 0}, + {D63_PRED, INTRA_FRAME, 0, 0}, #endif - TM_PRED, - NEWMV, - NEWMV, - NEWMV, + {TM_PRED, INTRA_FRAME, 0, 0}, - SPLITMV, - SPLITMV, - SPLITMV, + {NEWMV, LAST_FRAME, 0, 0}, + {NEWMV, LAST_FRAME, 0, 1}, + {NEWMV, GOLDEN_FRAME, 0, 0}, + {NEWMV, GOLDEN_FRAME, 0, 1}, + {NEWMV, ALTREF_FRAME, 0, 0}, + {NEWMV, ALTREF_FRAME, 0, 1}, - B_PRED, - I8X8_PRED, + {SPLITMV, LAST_FRAME, 0, 0}, + {SPLITMV, GOLDEN_FRAME, 0, 0}, + {SPLITMV, ALTREF_FRAME, 0, 0}, + + {B_PRED, INTRA_FRAME, 0, 0}, + {I8X8_PRED, INTRA_FRAME, 0, 0}, /* compound prediction modes */ - ZEROMV, - NEARESTMV, - NEARMV, + {ZEROMV, LAST_FRAME, GOLDEN_FRAME, 0}, + {NEARESTMV, LAST_FRAME, GOLDEN_FRAME, 0}, + {NEARMV, LAST_FRAME, GOLDEN_FRAME, 0}, - ZEROMV, - NEARESTMV, - NEARMV, + {ZEROMV, ALTREF_FRAME, LAST_FRAME, 0}, + {NEARESTMV, ALTREF_FRAME, LAST_FRAME, 0}, + {NEARMV, ALTREF_FRAME, LAST_FRAME, 0}, - ZEROMV, - NEARESTMV, - NEARMV, + {ZEROMV, GOLDEN_FRAME, ALTREF_FRAME, 0}, + {NEARESTMV, GOLDEN_FRAME, ALTREF_FRAME, 0}, + {NEARMV, GOLDEN_FRAME, ALTREF_FRAME, 0}, - NEWMV, - NEWMV, - NEWMV, + {NEWMV, LAST_FRAME, GOLDEN_FRAME, 0}, + {NEWMV, ALTREF_FRAME, LAST_FRAME, 0}, + {NEWMV, GOLDEN_FRAME, ALTREF_FRAME, 0}, - SPLITMV, - SPLITMV, - SPLITMV, + {SPLITMV, LAST_FRAME, GOLDEN_FRAME, 0}, + {SPLITMV, ALTREF_FRAME, LAST_FRAME, 0}, + {SPLITMV, GOLDEN_FRAME, ALTREF_FRAME, 0} }; - -const MV_REFERENCE_FRAME vp8_ref_frame_order[MAX_MODES] = +#else +const MODE_DEFINITION vp8_mode_order[MAX_MODES] = { - LAST_FRAME, - INTRA_FRAME, + {ZEROMV, LAST_FRAME, 0}, + {DC_PRED, INTRA_FRAME, 0}, - LAST_FRAME, - LAST_FRAME, + {NEARESTMV, LAST_FRAME, 0}, + {NEARMV, LAST_FRAME, 0}, - GOLDEN_FRAME, - GOLDEN_FRAME, + {ZEROMV, GOLDEN_FRAME, 0}, + {NEARESTMV, GOLDEN_FRAME, 0}, - ALTREF_FRAME, - ALTREF_FRAME, + {ZEROMV, ALTREF_FRAME, 0}, + {NEARESTMV, ALTREF_FRAME, 0}, - GOLDEN_FRAME, - ALTREF_FRAME, + {NEARMV, GOLDEN_FRAME, 0}, + {NEARMV, ALTREF_FRAME, 0}, - INTRA_FRAME, - INTRA_FRAME, + {V_PRED, INTRA_FRAME, 0}, + {H_PRED, INTRA_FRAME, 0}, #if CONFIG_NEWINTRAMODES - INTRA_FRAME, - INTRA_FRAME, - INTRA_FRAME, - INTRA_FRAME, - INTRA_FRAME, - INTRA_FRAME, + {D45_PRED, INTRA_FRAME, 0}, + {D135_PRED, INTRA_FRAME, 0}, + {D117_PRED, INTRA_FRAME, 0}, + {D153_PRED, INTRA_FRAME, 0}, + {D27_PRED, INTRA_FRAME, 0}, + {D63_PRED, INTRA_FRAME, 0}, #endif - INTRA_FRAME, - LAST_FRAME, - GOLDEN_FRAME, - ALTREF_FRAME, + {TM_PRED, INTRA_FRAME, 0}, - LAST_FRAME, - GOLDEN_FRAME, - ALTREF_FRAME, + {NEWMV, LAST_FRAME, 0}, + {NEWMV, GOLDEN_FRAME, 0}, + {NEWMV, ALTREF_FRAME, 0}, - INTRA_FRAME, - INTRA_FRAME, + {SPLITMV, LAST_FRAME, 0}, + {SPLITMV, GOLDEN_FRAME, 0}, + {SPLITMV, ALTREF_FRAME, 0}, - /* compound prediction modes */ - LAST_FRAME, - LAST_FRAME, - LAST_FRAME, - - ALTREF_FRAME, - ALTREF_FRAME, - ALTREF_FRAME, - - GOLDEN_FRAME, - GOLDEN_FRAME, - GOLDEN_FRAME, - - LAST_FRAME, - ALTREF_FRAME, - GOLDEN_FRAME, - - LAST_FRAME, - ALTREF_FRAME, - GOLDEN_FRAME, -}; - -const MV_REFERENCE_FRAME vp8_second_ref_frame_order[MAX_MODES] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -#if CONFIG_NEWINTRAMODES - 0, 0, - 0, 0, - 0, 0, -#endif - 0, 0, 0, 0, 0, 0, 0, 0, 0, + {B_PRED, INTRA_FRAME, 0}, + {I8X8_PRED, INTRA_FRAME, 0}, /* compound prediction modes */ - GOLDEN_FRAME, - GOLDEN_FRAME, - GOLDEN_FRAME, + {ZEROMV, LAST_FRAME, GOLDEN_FRAME}, + {NEARESTMV, LAST_FRAME, GOLDEN_FRAME}, + {NEARMV, LAST_FRAME, GOLDEN_FRAME}, - LAST_FRAME, - LAST_FRAME, - LAST_FRAME, + {ZEROMV, ALTREF_FRAME, LAST_FRAME}, + {NEARESTMV, ALTREF_FRAME, LAST_FRAME}, + {NEARMV, ALTREF_FRAME, LAST_FRAME}, - ALTREF_FRAME, - ALTREF_FRAME, - ALTREF_FRAME, + {ZEROMV, GOLDEN_FRAME, ALTREF_FRAME}, + {NEARESTMV, GOLDEN_FRAME, ALTREF_FRAME}, + {NEARMV, GOLDEN_FRAME, ALTREF_FRAME}, - GOLDEN_FRAME, - LAST_FRAME, - ALTREF_FRAME, + {NEWMV, LAST_FRAME, GOLDEN_FRAME}, + {NEWMV, ALTREF_FRAME, LAST_FRAME }, + {NEWMV, GOLDEN_FRAME, ALTREF_FRAME}, - GOLDEN_FRAME, - LAST_FRAME, - ALTREF_FRAME, + {SPLITMV, LAST_FRAME, GOLDEN_FRAME}, + {SPLITMV, ALTREF_FRAME, LAST_FRAME }, + {SPLITMV, GOLDEN_FRAME, ALTREF_FRAME} }; +#endif static void fill_token_costs( unsigned int (*c)[COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS], @@ -2827,6 +2811,7 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int int best_comp_rd = INT_MAX; int best_single_rd = INT_MAX; int best_hybrid_rd = INT_MAX; + int best_overall_rd = INT_MAX; int rate2, distortion2; int uv_intra_rate, uv_intra_distortion, uv_intra_rate_tokenonly; int uv_intra_skippable = 0; @@ -2835,6 +2820,7 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int int rate_y, UNINITIALIZED_IS_SAFE(rate_uv); int distortion_uv; int best_yrd = INT_MAX; + int best_filter_state; //int all_rds[MAX_MODES]; // Experimental debug code. //int all_rates[MAX_MODES]; @@ -2978,16 +2964,21 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int rate_y = 0; rate_uv =0; - this_mode = vp8_mode_order[mode_index]; - x->e_mbd.mode_info_context->mbmi.mode = this_mode; + this_mode = vp8_mode_order[mode_index].mode; + xd->mode_info_context->mbmi.mode = this_mode; + xd->mode_info_context->mbmi.uv_mode = DC_PRED; + xd->mode_info_context->mbmi.ref_frame = + vp8_mode_order[mode_index].ref_frame; + xd->mode_info_context->mbmi.second_ref_frame = + vp8_mode_order[mode_index].second_ref_frame; +#if CONFIG_PRED_FILTER + xd->mode_info_context->mbmi.pred_filter_enabled = 0; +#endif #if CONFIG_COMP_INTRA_PRED - x->e_mbd.mode_info_context->mbmi.second_mode = (MB_PREDICTION_MODE) (DC_PRED - 1); - x->e_mbd.mode_info_context->mbmi.second_uv_mode = (MB_PREDICTION_MODE) (DC_PRED - 1); + xd->mode_info_context->mbmi.second_mode = (MB_PREDICTION_MODE) (DC_PRED - 1); + xd->mode_info_context->mbmi.second_uv_mode = (MB_PREDICTION_MODE) (DC_PRED - 1); #endif - x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED; - x->e_mbd.mode_info_context->mbmi.ref_frame = vp8_ref_frame_order[mode_index]; - x->e_mbd.mode_info_context->mbmi.second_ref_frame = vp8_second_ref_frame_order[mode_index]; // If the segment reference frame feature is enabled.... // then do nothing if the current ref frame is not allowed.. @@ -3053,18 +3044,18 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int // Increase zbin size to suppress noise if (cpi->zbin_mode_boost_enabled) { - if ( vp8_ref_frame_order[mode_index] == INTRA_FRAME ) + if ( vp8_mode_order[mode_index].ref_frame == INTRA_FRAME ) cpi->zbin_mode_boost = 0; else { - if (vp8_mode_order[mode_index] == ZEROMV) + if (vp8_mode_order[mode_index].mode == ZEROMV) { - if (vp8_ref_frame_order[mode_index] != LAST_FRAME) + if (vp8_mode_order[mode_index].ref_frame != LAST_FRAME) cpi->zbin_mode_boost = GF_ZEROMV_ZBIN_BOOST; else cpi->zbin_mode_boost = LF_ZEROMV_ZBIN_BOOST; } - else if (vp8_mode_order[mode_index] == SPLITMV) + else if (vp8_mode_order[mode_index].mode == SPLITMV) cpi->zbin_mode_boost = 0; else cpi->zbin_mode_boost = MV_ZBIN_BOOST; @@ -3389,6 +3380,15 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int } vp8_set_mbmode_and_mvs(x, this_mode, &mode_mv[this_mode]); + +#if CONFIG_PRED_FILTER + // Filtered prediction: + xd->mode_info_context->mbmi.pred_filter_enabled = + vp8_mode_order[mode_index].pred_filter_flag; + rate2 += vp8_cost_bit( cpi->common.prob_pred_filter_off, + xd->mode_info_context->mbmi.pred_filter_enabled); +#endif + vp8_build_inter16x16_predictors_mby(&x->e_mbd); compmode_cost = @@ -3741,6 +3741,21 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int best_hybrid_rd = this_rd; } +#if CONFIG_PRED_FILTER + // Keep track of the best mode irrespective of prediction filter state + if (this_rd < best_overall_rd) + { + best_overall_rd = this_rd; + best_filter_state = xd->mode_info_context->mbmi.pred_filter_enabled; + } + + // Ignore modes where the prediction filter state doesn't + // match the state signaled at the frame level + if ((cm->pred_filter_mode == 2) || + (cm->pred_filter_mode == + xd->mode_info_context->mbmi.pred_filter_enabled)) + { +#endif // Did this mode help.. i.e. is it the new best mode if (this_rd < best_rd || x->skip) { @@ -3833,12 +3848,23 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int best_hybrid_rd = hybrid_rd; } } +#if CONFIG_PRED_FILTER + } +#endif if (x->skip) break; } +#if CONFIG_PRED_FILTER + // Update counts for prediction filter usage + if (best_filter_state != 0) + ++cpi->pred_filter_on_count; + else + ++cpi->pred_filter_off_count; +#endif + // Reduce the activation RD thresholds for the best choice mode if ((cpi->rd_baseline_thresh[best_mode_index] > 0) && (cpi->rd_baseline_thresh[best_mode_index] < (INT_MAX >> 2))) { @@ -3848,7 +3874,7 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int cpi->rd_threshes[best_mode_index] = (cpi->rd_baseline_thresh[best_mode_index] >> 7) * cpi->rd_thresh_mult[best_mode_index]; // If we chose a split mode then reset the new MV thresholds as well - /*if ( vp8_mode_order[best_mode_index] == SPLITMV ) + /*if ( vp8_mode_order[best_mode_index].mode == SPLITMV ) { best_adjustment = 4; //(cpi->rd_thresh_mult[THR_NEWMV] >> 4); cpi->rd_thresh_mult[THR_NEWMV] = (cpi->rd_thresh_mult[THR_NEWMV] >= (MIN_THRESHMULT+best_adjustment)) ? cpi->rd_thresh_mult[THR_NEWMV]-best_adjustment: MIN_THRESHMULT;