Added Prediction Filter to Mode Selection
authorAdrian Grange <agrange@google.com>
Mon, 25 Jun 2012 23:23:58 +0000 (16:23 -0700)
committerAdrian Grange <agrange@google.com>
Wed, 27 Jun 2012 21:51:41 +0000 (14:51 -0700)
Added the ability to optionally filter the prediction data
when inter modes are selected (excludes SPLITMV, for now).

The mode selection loop considers both the filtered and
non-filtered prediction data when choosing mode. The filter
can be turned on/off at the frame-level, or signaled for
each MB.

Change-Id: I1b783c71d95a361ab36c761b07e8a6b06bc36822

14 files changed:
configure
vp8/common/blockd.h
vp8/common/onyxc_int.h
vp8/common/reconinter.c
vp8/decoder/decodemv.c
vp8/encoder/bitstream.c
vp8/encoder/encodeframe.c
vp8/encoder/encodemb.c
vp8/encoder/encodemb.h
vp8/encoder/mbgraph.c
vp8/encoder/onyx_if.c
vp8/encoder/onyx_int.h
vp8/encoder/ratectrl.c
vp8/encoder/rdopt.c

index a394fff..b1a3f66 100755 (executable)
--- a/configure
+++ b/configure
@@ -231,6 +231,7 @@ EXPERIMENT_LIST="
     int_8x8fdct
     newintramodes
     adaptive_entropy
+    pred_filter
 "
 CONFIG_LIST="
     external_build
index 19511f3..26ac826 100644 (file)
@@ -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
index f2795a8..93c2fee 100644 (file)
@@ -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
index 376fc7f..384345c 100644 (file)
@@ -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)
     {
index b7b5e49..1243b35 100644 (file)
@@ -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 ))) )
index e0cb2d4..99201ba 100644 (file)
@@ -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))
                     {
index 55041c5..a694192 100644 (file)
@@ -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;
index 345bab0..dcf479f 100644 (file)
@@ -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);
index e211eea..396a151 100644 (file)
@@ -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
index d2d3b6b..cad2750 100644 (file)
@@ -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)
index decb31b..ccb2cb7 100644 (file)
@@ -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);
index 54ed233..c838ecc 100644 (file)
 #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);
index 75246fc..5ea7445 100644 (file)
@@ -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
index 18b62bf..0ec87bb 100644 (file)
@@ -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;