shithub: libvpx

Download patch

ref: bbc926dca2479ae41882cdfb6079f5596bfac2bc
parent: f3dff402556cb1b1dd3c7dbc1877104a792f329c
author: Adrian Grange <agrange@google.com>
date: Mon Jun 25 12:23:58 EDT 2012

Added Prediction Filter to Mode Selection

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

--- a/configure
+++ b/configure
@@ -231,6 +231,7 @@
     int_8x8fdct
     newintramodes
     adaptive_entropy
+    pred_filter
 "
 CONFIG_LIST="
     external_build
--- a/vp8/common/blockd.h
+++ b/vp8/common/blockd.h
@@ -214,6 +214,11 @@
     // 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
--- a/vp8/common/onyxc_int.h
+++ b/vp8/common/onyxc_int.h
@@ -287,6 +287,15 @@
 #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
--- a/vp8/common/reconinter.c
+++ b/vp8/common/reconinter.c
@@ -335,18 +335,153 @@
 
 
 /*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 @@
     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 @@
 
 
 /*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 @@
         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,7 +893,64 @@
     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)
     {
         x->subpixel_predict8x8(uptr, pre_stride, _o16x16mv.as_mv.col & 15,  _o16x16mv.as_mv.row & 15, dst_u, dst_uvstride);
@@ -687,17 +1017,60 @@
 
     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 @@
     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)
     {
--- a/vp8/decoder/decodemv.c
+++ b/vp8/decoder/decodemv.c
@@ -527,8 +527,14 @@
 #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);
@@ -727,6 +733,18 @@
 
             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 &&
--- a/vp8/encoder/bitstream.c
+++ b/vp8/encoder/bitstream.c
@@ -815,6 +815,18 @@
 #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 @@
                         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))
                     {
--- a/vp8/encoder/encodeframe.c
+++ b/vp8/encoder/encodeframe.c
@@ -1201,6 +1201,19 @@
     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;
--- a/vp8/encoder/encodemb.c
+++ b/vp8/encoder/encodemb.c
@@ -1223,6 +1223,11 @@
 
     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);
--- a/vp8/encoder/encodemb.h
+++ b/vp8/encoder/encodemb.h
@@ -83,6 +83,17 @@
     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
--- a/vp8/encoder/mbgraph.c
+++ b/vp8/encoder/mbgraph.c
@@ -104,6 +104,11 @@
                                                &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)
--- a/vp8/encoder/onyx_if.c
+++ b/vp8/encoder/onyx_if.c
@@ -741,6 +741,41 @@
     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 @@
         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 @@
 #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 @@
         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 @@
         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 @@
             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 @@
                 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 @@
                 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 @@
             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 @@
                 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 @@
                 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 @@
         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 @@
         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 @@
         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 @@
 
 }
 
+#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 @@
 
         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.
@@ -3690,6 +3891,13 @@
     // build the bitstream
     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
--- 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,35 @@
     MBGRAPH_MB_STATS *mb_stats;
 } MBGRAPH_FRAME_STATS;
 
+#if CONFIG_PRED_FILTER
 typedef enum
 {
-    THR_ZEROMV         = 0,
-    THR_DC             = 1,
+    THR_ZEROMV,
+    THR_ZEROMV_FILT,
+    THR_DC,
 
-    THR_NEARESTMV      = 2,
-    THR_NEARMV         = 3,
+    THR_NEARESTMV,
+    THR_NEARESTMV_FILT,
+    THR_NEARMV,
+    THR_NEARMV_FILT,
 
-    THR_ZEROG          = 4,
-    THR_NEARESTG       = 5,
+    THR_ZEROG,
+    THR_ZEROG_FILT,
+    THR_NEARESTG,
+    THR_NEARESTG_FILT,
 
-    THR_ZEROA          = 6,
-    THR_NEARESTA       = 7,
+    THR_ZEROA,
+    THR_ZEROA_FILT,
+    THR_NEARESTA,
+    THR_NEARESTA_FILT,
 
-    THR_NEARG          = 8,
-    THR_NEARA          = 9,
+    THR_NEARG,
+    THR_NEARG_FILT,
+    THR_NEARA,
+    THR_NEARA_FILT,
 
-    THR_V_PRED         = 10,
-    THR_H_PRED         = 11,
+    THR_V_PRED,
+    THR_H_PRED,
 #if CONFIG_NEWINTRAMODES
     THR_D45_PRED,
     THR_D135_PRED,
@@ -194,8 +212,11 @@
     THR_TM,
 
     THR_NEWMV,
+    THR_NEWMV_FILT,
     THR_NEWG,
+    THR_NEWG_FILT,
     THR_NEWA,
+    THR_NEWA_FILT,
 
     THR_SPLITMV,
     THR_SPLITG,
@@ -225,7 +246,70 @@
     THR_COMP_SPLITGA,
 }
 THR_MODES;
+#else
+typedef enum
+{
+    THR_ZEROMV,
+    THR_DC,
 
+    THR_NEARESTMV,
+    THR_NEARMV,
+
+    THR_ZEROG,
+    THR_NEARESTG,
+
+    THR_ZEROA,
+    THR_NEARESTA,
+
+    THR_NEARG,
+    THR_NEARA,
+
+    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_NEWG,
+    THR_NEWA,
+
+    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;
+#endif
+
 typedef enum
 {
     DIAMOND = 0,
@@ -678,6 +762,11 @@
     int update_context;
 
     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;
 
--- 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
--- a/vp8/encoder/rdopt.c
+++ b/vp8/encoder/rdopt.c
@@ -81,162 +81,146 @@
     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,
+    {ZEROMV,    LAST_FRAME,   0,  0},
+    {ZEROMV,    LAST_FRAME,   0,  1},
+    {DC_PRED,   INTRA_FRAME,  0,  0},
 
-    NEARESTMV,
-    NEARMV,
+    {NEARESTMV, LAST_FRAME,   0,  0},
+    {NEARESTMV, LAST_FRAME,   0,  1},
+    {NEARMV,    LAST_FRAME,   0,  0},
+    {NEARMV,    LAST_FRAME,   0,  1},
 
-    ZEROMV,
-    NEARESTMV,
+    {ZEROMV,    GOLDEN_FRAME, 0,  0},
+    {ZEROMV,    GOLDEN_FRAME, 0,  1},
+    {NEARESTMV, GOLDEN_FRAME, 0,  0},
+    {NEARESTMV, GOLDEN_FRAME, 0,  1},
 
-    ZEROMV,
-    NEARESTMV,
+    {ZEROMV,    ALTREF_FRAME, 0,  0},
+    {ZEROMV,    ALTREF_FRAME, 0,  1},
+    {NEARESTMV, ALTREF_FRAME, 0,  0},
+    {NEARESTMV, ALTREF_FRAME, 0,  1},
 
-    NEARMV,
-    NEARMV,
+    {NEARMV,    GOLDEN_FRAME, 0,  0},
+    {NEARMV,    GOLDEN_FRAME, 0,  1},
+    {NEARMV,    ALTREF_FRAME, 0,  0},
+    {NEARMV,    ALTREF_FRAME, 0,  1},
 
-    V_PRED,
-    H_PRED,
+    {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},
 
+    {B_PRED,    INTRA_FRAME,  0},
+    {I8X8_PRED, INTRA_FRAME,  0},
+
     /* compound prediction modes */
-    LAST_FRAME,
-    LAST_FRAME,
-    LAST_FRAME,
+    {ZEROMV,    LAST_FRAME,   GOLDEN_FRAME},
+    {NEARESTMV, LAST_FRAME,   GOLDEN_FRAME},
+    {NEARMV,    LAST_FRAME,   GOLDEN_FRAME},
 
-    ALTREF_FRAME,
-    ALTREF_FRAME,
-    ALTREF_FRAME,
+    {ZEROMV,    ALTREF_FRAME, LAST_FRAME},
+    {NEARESTMV, ALTREF_FRAME, LAST_FRAME},
+    {NEARMV,    ALTREF_FRAME, LAST_FRAME},
 
-    GOLDEN_FRAME,
-    GOLDEN_FRAME,
-    GOLDEN_FRAME,
+    {ZEROMV,    GOLDEN_FRAME, ALTREF_FRAME},
+    {NEARESTMV, GOLDEN_FRAME, ALTREF_FRAME},
+    {NEARMV,    GOLDEN_FRAME, ALTREF_FRAME},
 
-    LAST_FRAME,
-    ALTREF_FRAME,
-    GOLDEN_FRAME,
+    {NEWMV,     LAST_FRAME,   GOLDEN_FRAME},
+    {NEWMV,     ALTREF_FRAME, LAST_FRAME  },
+    {NEWMV,     GOLDEN_FRAME, ALTREF_FRAME},
 
-    LAST_FRAME,
-    ALTREF_FRAME,
-    GOLDEN_FRAME,
+    {SPLITMV,   LAST_FRAME,   GOLDEN_FRAME},
+    {SPLITMV,   ALTREF_FRAME, LAST_FRAME  },
+    {SPLITMV,   GOLDEN_FRAME, ALTREF_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,
 
-    /* compound prediction modes */
-    GOLDEN_FRAME,
-    GOLDEN_FRAME,
-    GOLDEN_FRAME,
-
-    LAST_FRAME,
-    LAST_FRAME,
-    LAST_FRAME,
-
-    ALTREF_FRAME,
-    ALTREF_FRAME,
-    ALTREF_FRAME,
-
-    GOLDEN_FRAME,
-    LAST_FRAME,
-    ALTREF_FRAME,
-
-    GOLDEN_FRAME,
-    LAST_FRAME,
-    ALTREF_FRAME,
-};
-
 static void fill_token_costs(
     unsigned int (*c)[COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS],
     const vp8_prob (*p)[COEF_BANDS] [PREV_COEF_CONTEXTS] [ENTROPY_NODES],
@@ -2827,6 +2811,7 @@
     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 @@
     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 @@
         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 @@
         // 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 @@
             }
 
             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 @@
                 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,6 +3848,9 @@
                 best_hybrid_rd = hybrid_rd;
             }
         }
+#if CONFIG_PRED_FILTER
+        }
+#endif
 
         if (x->skip)
             break;
@@ -3839,6 +3857,14 @@
 
     }
 
+#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 @@
         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;