tech-invite   World Map     

IETF     RFCs     Groups     SIP     ABNFs    |    3GPP     Specs     Gloss.     Arch.     IMS     UICC    |    Misc.    |    search     info

RFC 6386

 
 
 

VP8 Data Format and Decoding Guide

Part 7 of 11, p. 158 to 192
Prev RFC Part       Next RFC Part

 


prevText      Top      Up      ToC       Page 158 
20.6.  dixie_loopfilter.c

   ---- Begin code block --------------------------------------

   /*
    *  Copyright (c) 2010, 2011, Google Inc.  All rights reserved.
    *
    *  Use of this source code is governed by a BSD-style license
    *  that can be found in the LICENSE file in the root of the source
    *  tree.  An additional intellectual property rights grant can be
    *  found in the file PATENTS.  All contributing project authors may
    *  be found in the AUTHORS file in the root of the source tree.
    */
   #include "dixie.h"
   #include "dixie_loopfilter.h"

   #define ABS(x) ((x) >= 0 ? (x) : -(x))

   #define p3 pixels[-4*stride]
   #define p2 pixels[-3*stride]
   #define p1 pixels[-2*stride]
   #define p0 pixels[-1*stride]
   #define q0 pixels[ 0*stride]
   #define q1 pixels[ 1*stride]
   #define q2 pixels[ 2*stride]
   #define q3 pixels[ 3*stride]

   #define static
   static int

   saturate_int8(int x)
   {
       if (x < -128)
           return -128;

       if (x > 127)
           return 127;

       return x;
   }

Top      Up      ToC       Page 159 
   static int
   saturate_uint8(int x)
   {
       if (x < 0)
           return 0;

       if (x > 255)
           return 255;

       return x;
   }


   static int
   high_edge_variance(unsigned char *pixels,
                      int            stride,
                      int            hev_threshold)
   {
       return ABS(p1 - p0) > hev_threshold ||
              ABS(q1 - q0) > hev_threshold;
   }


   static int
   simple_threshold(unsigned char *pixels,
                    int            stride,
                    int            filter_limit)
   {
       return (ABS(p0 - q0) * 2 + (ABS(p1 - q1) >> 1)) <= filter_limit;
   }


   static int
   normal_threshold(unsigned char *pixels,
                    int            stride,
                    int            edge_limit,
                    int            interior_limit)
   {
       int E = edge_limit;
       int I = interior_limit;

       return simple_threshold(pixels, stride, 2 * E + I)
              && ABS(p3 - p2) <= I && ABS(p2 - p1) <= I
              && ABS(p1 - p0) <= I && ABS(q3 - q2) <= I
              && ABS(q2 - q1) <= I && ABS(q1 - q0) <= I;
   }

Top      Up      ToC       Page 160 
   static void
   filter_common(unsigned char *pixels,
                 int            stride,
                 int            use_outer_taps)
   {
       int a, f1, f2;

       a = 3 * (q0 - p0);

       if (use_outer_taps)
           a += saturate_int8(p1 - q1);

       a = saturate_int8(a);

       f1 = ((a + 4 > 127) ? 127 : a + 4) >> 3;
       f2 = ((a + 3 > 127) ? 127 : a + 3) >> 3;

       p0 = saturate_uint8(p0 + f2);
       q0 = saturate_uint8(q0 - f1);

       if (!use_outer_taps)
       {
           /* This handles the case of subblock_filter()
            * (from the bitstream guide.
            */
           a = (f1 + 1) >> 1;
           p1 = saturate_uint8(p1 + a);
           q1 = saturate_uint8(q1 - a);
       }
   }

Top      Up      ToC       Page 161 
   static void
   filter_mb_edge(unsigned char *pixels,
                  int            stride)
   {
       int w, a;

       w = saturate_int8(saturate_int8(p1 - q1) + 3 * (q0 - p0));

       a = (27 * w + 63) >> 7;
       p0 = saturate_uint8(p0 + a);
       q0 = saturate_uint8(q0 - a);

       a = (18 * w + 63) >> 7;
       p1 = saturate_uint8(p1 + a);
       q1 = saturate_uint8(q1 - a);

       a = (9 * w + 63) >> 7;
       p2 = saturate_uint8(p2 + a);
       q2 = saturate_uint8(q2 - a);
   }


   static void
   filter_mb_v_edge(unsigned char *src,
                    int            stride,
                    int            edge_limit,
                    int            interior_limit,
                    int            hev_threshold,
                    int            size)
   {
       int i;

       for (i = 0; i < 8 * size; i++)
       {
           if (normal_threshold(src, 1, edge_limit, interior_limit))
           {
               if (high_edge_variance(src, 1, hev_threshold))
                   filter_common(src, 1, 1);
               else
                   filter_mb_edge(src, 1);
           }

           src += stride;
       }
   }

Top      Up      ToC       Page 162 
   static void
   filter_subblock_v_edge(unsigned char *src,
                          int            stride,
                          int            edge_limit,
                          int            interior_limit,
                          int            hev_threshold,
                          int            size)
   {
       int i;

       for (i = 0; i < 8 * size; i++)
       {
           if (normal_threshold(src, 1, edge_limit, interior_limit))
               filter_common(src, 1,
                             high_edge_variance(src, 1, hev_threshold));

           src += stride;
       }
   }


   static void
   filter_mb_h_edge(unsigned char *src,
                    int            stride,
                    int            edge_limit,
                    int            interior_limit,
                    int            hev_threshold,
                    int            size)
   {
       int i;

       for (i = 0; i < 8 * size; i++)
       {
           if (normal_threshold(src, stride, edge_limit,
                                interior_limit))
           {
               if (high_edge_variance(src, stride, hev_threshold))
                   filter_common(src, stride, 1);
               else
                   filter_mb_edge(src, stride);
           }

           src += 1;
       }
   }

Top      Up      ToC       Page 163 
   static void
   filter_subblock_h_edge(unsigned char *src,
                          int            stride,
                          int            edge_limit,
                          int            interior_limit,
                          int            hev_threshold,
                          int            size)
   {
       int i;

       for (i = 0; i < 8 * size; i++)
       {
           if (normal_threshold(src, stride, edge_limit,
                                interior_limit))
               filter_common(src, stride,
                             high_edge_variance(src, stride,
                                                hev_threshold));

           src += 1;
       }
   }


   static void
   filter_v_edge_simple(unsigned char *src,
                        int            stride,
                        int            filter_limit)
   {
       int i;

       for (i = 0; i < 16; i++)
       {
           if (simple_threshold(src, 1, filter_limit))
               filter_common(src, 1, 1);

           src += stride;
       }
   }

Top      Up      ToC       Page 164 
   static void
   filter_h_edge_simple(unsigned char *src,
                        int            stride,
                        int            filter_limit)
   {
       int i;

       for (i = 0; i < 16; i++)
       {
           if (simple_threshold(src, stride, filter_limit))
               filter_common(src, stride, 1);

           src += 1;
       }
   }


   static void
   calculate_filter_parameters(struct vp8_decoder_ctx *ctx,
                               struct mb_info         *mbi,
                               int                    *edge_limit_,
                               int                    *interior_limit_,
                               int                    *hev_threshold_)
   {
       int filter_level, interior_limit, hev_threshold;

       /* Reference code/spec seems to conflate filter_level and
        * edge_limit
        */

       filter_level = ctx->loopfilter_hdr.level;

       if (ctx->segment_hdr.enabled)
       {
           if (!ctx->segment_hdr.abs)
               filter_level +=
                   ctx->segment_hdr.lf_level[mbi->base.segment_id];
           else
               filter_level =
                   ctx->segment_hdr.lf_level[mbi->base.segment_id];
       }

       if (filter_level > 63)
           filter_level = 63;
       else if (filter_level < 0)
           filter_level = 0;

Top      Up      ToC       Page 165 
       if (ctx->loopfilter_hdr.delta_enabled)
       {
           filter_level +=
               ctx->loopfilter_hdr.ref_delta[mbi->base.ref_frame];

           if (mbi->base.ref_frame == CURRENT_FRAME)
           {
               if (mbi->base.y_mode == B_PRED)
                   filter_level += ctx->loopfilter_hdr.mode_delta[0];
           }
           else if (mbi->base.y_mode == ZEROMV)
               filter_level += ctx->loopfilter_hdr.mode_delta[1];
           else if (mbi->base.y_mode == SPLITMV)
               filter_level += ctx->loopfilter_hdr.mode_delta[3];
           else
               filter_level += ctx->loopfilter_hdr.mode_delta[2];
       }

       if (filter_level > 63)
           filter_level = 63;
       else if (filter_level < 0)
           filter_level = 0;

       interior_limit = filter_level;

       if (ctx->loopfilter_hdr.sharpness)
       {
           interior_limit >>= ctx->loopfilter_hdr.sharpness > 4 ? 2 : 1;

           if (interior_limit > 9 - ctx->loopfilter_hdr.sharpness)
               interior_limit = 9 - ctx->loopfilter_hdr.sharpness;
       }

       if (interior_limit < 1)
           interior_limit = 1;

       hev_threshold = (filter_level >= 15);

       if (filter_level >= 40)
           hev_threshold++;

       if (filter_level >= 20 && !ctx->frame_hdr.is_keyframe)
           hev_threshold++;

       *edge_limit_ = filter_level;
       *interior_limit_ = interior_limit;
       *hev_threshold_ = hev_threshold;
   }

Top      Up      ToC       Page 166 
   static void
   filter_row_normal(struct vp8_decoder_ctx *ctx,
                     unsigned int            row,
                     unsigned int            start_col,
                     unsigned int            num_cols)
   {
       unsigned char  *y, *u, *v;
       int             stride, uv_stride;
       struct mb_info *mbi;
       unsigned int    col;

       /* Adjust pointers based on row, start_col */

       stride    = ctx->ref_frames[CURRENT_FRAME]->img.stride[PLANE_Y];
       uv_stride = ctx->ref_frames[CURRENT_FRAME]->img.stride[PLANE_U];
       y = ctx->ref_frames[CURRENT_FRAME]->img.planes[PLANE_Y];
       u = ctx->ref_frames[CURRENT_FRAME]->img.planes[PLANE_U];
       v = ctx->ref_frames[CURRENT_FRAME]->img.planes[PLANE_V];
       y += (stride * row + start_col) * 16;
       u += (uv_stride * row + start_col) * 8;
       v += (uv_stride * row + start_col) * 8;
       mbi = ctx->mb_info_rows[row] + start_col;

       for (col = start_col; col < start_col + num_cols; col++)
       {
           int edge_limit, interior_limit, hev_threshold;

           /* TODO: Only need to recalculate every MB if segmentation is
            * enabled.
            */
           calculate_filter_parameters(ctx, mbi, &edge_limit,
                                       &interior_limit, &hev_threshold);

           if (edge_limit)
           {
               if (col)
               {
                   filter_mb_v_edge(y, stride, edge_limit + 2,
                                    interior_limit, hev_threshold, 2);
                   filter_mb_v_edge(u, uv_stride, edge_limit + 2,
                                    interior_limit, hev_threshold, 1);
                   filter_mb_v_edge(v, uv_stride, edge_limit + 2,
                                    interior_limit, hev_threshold, 1);
               }

Top      Up      ToC       Page 167 
               /* NOTE: This conditional is actually dependent on the
                * number of coefficients decoded, not the skip flag as
                * coded in the bitstream.  The tokens task is expected
                * to set 31 if there is *any* non-zero data.
                */
               if (mbi->base.eob_mask
                   || mbi->base.y_mode == SPLITMV
                   || mbi->base.y_mode == B_PRED)
               {
                   filter_subblock_v_edge(y + 4, stride, edge_limit,
                                          interior_limit, hev_threshold,
                                          2);
                   filter_subblock_v_edge(y + 8, stride, edge_limit,
                                          interior_limit, hev_threshold,
                                          2);
                   filter_subblock_v_edge(y + 12, stride, edge_limit,
                                          interior_limit, hev_threshold,
                                          2);
                   filter_subblock_v_edge(u + 4, uv_stride, edge_limit,
                                          interior_limit, hev_threshold,
                                          1);
                   filter_subblock_v_edge(v + 4, uv_stride, edge_limit,
                                          interior_limit, hev_threshold,
                                          1);
               }

               if (row)
               {
                   filter_mb_h_edge(y, stride, edge_limit + 2,
                                    interior_limit, hev_threshold, 2);
                   filter_mb_h_edge(u, uv_stride, edge_limit + 2,
                                    interior_limit, hev_threshold, 1);
                   filter_mb_h_edge(v, uv_stride, edge_limit + 2,
                                    interior_limit, hev_threshold, 1);
               }

Top      Up      ToC       Page 168 
               if (mbi->base.eob_mask
                   || mbi->base.y_mode == SPLITMV
                   || mbi->base.y_mode == B_PRED)
               {
                   filter_subblock_h_edge(y + 4 * stride, stride,
                                          edge_limit, interior_limit,
                                          hev_threshold, 2);
                   filter_subblock_h_edge(y + 8 * stride, stride,
                                          edge_limit, interior_limit,
                                          hev_threshold, 2);
                   filter_subblock_h_edge(y + 12 * stride, stride,
                                          edge_limit, interior_limit,
                                          hev_threshold, 2);
                   filter_subblock_h_edge(u + 4 * uv_stride, uv_stride,
                                          edge_limit, interior_limit,
                                          hev_threshold, 1);
                   filter_subblock_h_edge(v + 4 * uv_stride, uv_stride,
                                          edge_limit, interior_limit,
                                          hev_threshold, 1);
               }
           }

           y += 16;
           u += 8;
           v += 8;
           mbi++;
       }
   }

   static void
   filter_row_simple(struct vp8_decoder_ctx *ctx,
                     unsigned int            row,
                     unsigned int            start_col,
                     unsigned int            num_cols)
   {
       unsigned char  *y;
       int             stride;
       struct mb_info *mbi;
       unsigned int    col;

       /* Adjust pointers based on row, start_col */
       stride    = ctx->ref_frames[CURRENT_FRAME]->img.stride[PLANE_Y];
       y = ctx->ref_frames[CURRENT_FRAME]->img.planes[PLANE_Y];
       y += (stride * row + start_col) * 16;
       mbi = ctx->mb_info_rows[row] + start_col;

Top      Up      ToC       Page 169 
       for (col = start_col; col < start_col + num_cols; col++)
       {
           int edge_limit, interior_limit, hev_threshold;

           /* TODO: Only need to recalculate every MB if segmentation is
            * enabled.
            */
           calculate_filter_parameters(ctx, mbi, &edge_limit,
                                       &interior_limit, &hev_threshold);

           if (edge_limit)
           {

               /* NOTE: This conditional is actually dependent on the
                * number of coefficients decoded, not the skip flag as
                * coded in the bitstream.  The tokens task is expected
                * to set 31 if there is *any* non-zero data.
                */
               int filter_subblocks = (mbi->base.eob_mask
                                       || mbi->base.y_mode == SPLITMV
                                       || mbi->base.y_mode == B_PRED);
               int mb_limit = (edge_limit + 2) * 2 + interior_limit;
               int b_limit = edge_limit * 2 + interior_limit;

               if (col)
                   filter_v_edge_simple(y, stride, mb_limit);

               if (filter_subblocks)
               {
                   filter_v_edge_simple(y + 4, stride, b_limit);
                   filter_v_edge_simple(y + 8, stride, b_limit);
                   filter_v_edge_simple(y + 12, stride, b_limit);
               }

               if (row)
                   filter_h_edge_simple(y, stride, mb_limit);

               if (filter_subblocks)
               {
                   filter_h_edge_simple(y + 4 * stride, stride,
                                        b_limit);
                   filter_h_edge_simple(y + 8 * stride, stride,
                                        b_limit);
                   filter_h_edge_simple(y + 12 * stride, stride,
                                        b_limit);
               }
           }

Top      Up      ToC       Page 170 
           y += 16;
           mbi++;
       }
   }


   void
   vp8_dixie_loopfilter_process_row(struct vp8_decoder_ctx *ctx,
                                    unsigned int            row,
                                    unsigned int            start_col,
                                    unsigned int            num_cols)
   {
       if (ctx->loopfilter_hdr.use_simple)
           filter_row_simple(ctx, row, start_col, num_cols);
       else
           filter_row_normal(ctx, row, start_col, num_cols);
   }

   ---- End code block ----------------------------------------

20.7.  dixie_loopfilter.h

   ---- Begin code block --------------------------------------

   /*
    *  Copyright (c) 2010, 2011, Google Inc.  All rights reserved.
    *
    *  Use of this source code is governed by a BSD-style license
    *  that can be found in the LICENSE file in the root of the source
    *  tree.  An additional intellectual property rights grant can be
    *  found in the file PATENTS.  All contributing project authors may
    *  be found in the AUTHORS file in the root of the source tree.
    */
   #ifndef DIXIE_LOOPFILTER_H
   #define DIXIE_LOOPFILTER_H

   void
   vp8_dixie_loopfilter_process_row(struct vp8_decoder_ctx *ctx,
                                    unsigned int            row,
                                    unsigned int            start_col,
                                    unsigned int            num_cols);

   #endif

   ---- End code block ----------------------------------------

Top      Up      ToC       Page 171 
20.8.  idct_add.c

   ---- Begin code block --------------------------------------

   /*
    *  Copyright (c) 2010, 2011, Google Inc.  All rights reserved.
    *
    *  Use of this source code is governed by a BSD-style license
    *  that can be found in the LICENSE file in the root of the source
    *  tree.  An additional intellectual property rights grant can be
    *  found in the file PATENTS.  All contributing project authors may
    *  be found in the AUTHORS file in the root of the source tree.
    */
   #include "dixie.h"
   #include "idct_add.h"
   #include <assert.h>

   void
   vp8_dixie_walsh(const short *input, short *output)
   {
       int i;
       int a1, b1, c1, d1;
       int a2, b2, c2, d2;
       const short *ip = input;
       short *op = output;

       for (i = 0; i < 4; i++)
       {
           a1 = ip[0] + ip[12];
           b1 = ip[4] + ip[8];
           c1 = ip[4] - ip[8];
           d1 = ip[0] - ip[12];

           op[0] = a1 + b1;
           op[4] = c1 + d1;
           op[8] = a1 - b1;
           op[12] = d1 - c1;
           ip++;
           op++;
       }

       ip = output;
       op = output;

Top      Up      ToC       Page 172 
       for (i = 0; i < 4; i++)
       {
           a1 = ip[0] + ip[3];
           b1 = ip[1] + ip[2];
           c1 = ip[1] - ip[2];
           d1 = ip[0] - ip[3];

           a2 = a1 + b1;
           b2 = c1 + d1;
           c2 = a1 - b1;
           d2 = d1 - c1;

           op[0] = (a2 + 3) >> 3;
           op[1] = (b2 + 3) >> 3;
           op[2] = (c2 + 3) >> 3;
           op[3] = (d2 + 3) >> 3;

           ip += 4;
           op += 4;
       }
   }


   #define cospi8sqrt2minus1 20091
   #define sinpi8sqrt2       35468
   #define rounding          0
   static void
   idct_columns(const short *input, short *output)
   {
       int i;
       int a1, b1, c1, d1;

       const short *ip = input;
       short *op = output;
       int temp1, temp2;
       int shortpitch = 4;

       for (i = 0; i < 4; i++)
       {
           a1 = ip[0] + ip[8];
           b1 = ip[0] - ip[8];

           temp1 = (ip[4] * sinpi8sqrt2 + rounding) >> 16;
           temp2 = ip[12] +
               ((ip[12] * cospi8sqrt2minus1 + rounding) >> 16);
           c1 = temp1 - temp2;

Top      Up      ToC       Page 173 
           temp1 = ip[4] +
               ((ip[4] * cospi8sqrt2minus1 + rounding) >> 16);
           temp2 = (ip[12] * sinpi8sqrt2 + rounding) >> 16;
           d1 = temp1 + temp2;

           op[shortpitch*0] = a1 + d1;
           op[shortpitch*3] = a1 - d1;

           op[shortpitch*1] = b1 + c1;
           op[shortpitch*2] = b1 - c1;

           ip++;
           op++;
       }
   }


   void
   vp8_dixie_idct_add(unsigned char        *recon,
                      const unsigned char  *predict,
                      int                   stride,
                      const short          *coeffs)
   {
       int i;
       int a1, b1, c1, d1, temp1, temp2;
       short tmp[16];
       idct_columns(coeffs, tmp);
       coeffs = tmp;

       for (i = 0; i < 4; i++)
       {
           a1 = coeffs[0] + coeffs[2];
           b1 = coeffs[0] - coeffs[2];

           temp1 = (coeffs[1] * sinpi8sqrt2 + rounding) >> 16;
           temp2 = coeffs[3] +
               ((coeffs[3] * cospi8sqrt2minus1 + rounding) >> 16);
           c1 = temp1 - temp2;

           temp1 = coeffs[1] +
               ((coeffs[1] * cospi8sqrt2minus1 + rounding) >> 16);
           temp2 = (coeffs[3] * sinpi8sqrt2 + rounding) >> 16;
           d1 = temp1 + temp2;

           recon[0] = CLAMP_255(predict[0] + ((a1 + d1 + 4) >> 3));
           recon[3] = CLAMP_255(predict[3] + ((a1 - d1 + 4) >> 3));
           recon[1] = CLAMP_255(predict[1] + ((b1 + c1 + 4) >> 3));
           recon[2] = CLAMP_255(predict[2] + ((b1 - c1 + 4) >> 3));

Top      Up      ToC       Page 174 
           coeffs += 4;
           recon += stride;
           predict += stride;
       }
   }

   ---- End code block ----------------------------------------

20.9.  idct_add.h

   ---- Begin code block --------------------------------------

   /*
    *  Copyright (c) 2010, 2011, Google Inc.  All rights reserved.
    *
    *  Use of this source code is governed by a BSD-style license
    *  that can be found in the LICENSE file in the root of the source
    *  tree.  An additional intellectual property rights grant can be
    *  found in the file PATENTS.  All contributing project authors may
    *  be found in the AUTHORS file in the root of the source tree.
    */
   #ifndef IDCT_ADD_H
   #define IDCT_ADD_H

   void
   vp8_dixie_idct_add_init(struct vp8_decoder_ctx *ctx);


   void
   vp8_dixie_idct_add(unsigned char        *recon,
                      const unsigned char  *predict,
                      int                   stride,
                      const short          *coeffs);


   void
   vp8_dixie_walsh(const short *in, short *out);


   void
   vp8_dixie_idct_add_process_row(struct vp8_decoder_ctx *ctx,
                                  short                  *coeffs,
                                  unsigned int            row,
                                  unsigned int            start_col,
                                  unsigned int            num_cols);
   #endif

   ---- End code block ----------------------------------------

Top      Up      ToC       Page 175 
20.10.  mem.h

   ---- Begin code block --------------------------------------

   /*
    *  Copyright (c) 2010, 2011, Google Inc.  All rights reserved.
    *
    *  Use of this source code is governed by a BSD-style license
    *  that can be found in the LICENSE file in the root of the source
    *  tree.  An additional intellectual property rights grant can be
    *  found in the file PATENTS.  All contributing project authors may
    *  be found in the AUTHORS file in the root of the source tree.
    */
   #ifndef VPX_PORTS_MEM_H
   #define VPX_PORTS_MEM_H
   #include "vpx_config.h"
   #include "vpx_integer.h"

   #if defined(__GNUC__) && __GNUC__
   #define DECLARE_ALIGNED(n,typ,val)  typ val __attribute__ \
       ((aligned (n)))
   #elif defined(_MSC_VER)
   #define DECLARE_ALIGNED(n,typ,val)  __declspec(align(n)) typ val
   #else
   #warning No alignment directives known for this compiler.
   #define DECLARE_ALIGNED(n,typ,val)  typ val
   #endif
   #endif


   /* Declare an aligned array on the stack, for situations where the
    * stack pointer may not have the alignment we expect.  Creates an
    * array with a modified name, then defines val to be a pointer, and
    * aligns that pointer within the array.
    */
   #define DECLARE_ALIGNED_ARRAY(a,typ,val,n)\
   typ val##_[(n)+(a)/sizeof(typ)+1];\
   typ *val = (typ*)((((intptr_t)val##_)+(a)-1)&((intptr_t)-(a)))

Top      Up      ToC       Page 176 
   /* Indicates that the usage of the specified variable has been
    * audited to assure that it's safe to use uninitialized.  Silences
    * 'may be used uninitialized' warnings on gcc.
    */
   #if defined(__GNUC__) && __GNUC__
   #define UNINITIALIZED_IS_SAFE(x) x=x
   #else
   #define UNINITIALIZED_IS_SAFE(x) x
   #endif

   ---- End code block ----------------------------------------

20.11.  modemv.c

   ---- Begin code block --------------------------------------

   /*
    *  Copyright (c) 2010, 2011, Google Inc.  All rights reserved.
    *
    *  Use of this source code is governed by a BSD-style license
    *  that can be found in the LICENSE file in the root of the source
    *  tree.  An additional intellectual property rights grant can be
    *  found in the file PATENTS.  All contributing project authors may
    *  be found in the AUTHORS file in the root of the source tree.
    */
   #include "dixie.h"
   #include "modemv_data.h"
   #include <stdlib.h>
   #include <assert.h>


   struct mv_clamp_rect
   {
       int to_left, to_right, to_top, to_bottom;
   };

Top      Up      ToC       Page 177 
   static union mv
           clamp_mv(union mv raw, const struct mv_clamp_rect *bounds)
   {
       union mv newmv;

       newmv.d.x = (raw.d.x < bounds->to_left)
                   ? bounds->to_left : raw.d.x;
       newmv.d.x = (raw.d.x > bounds->to_right)
                   ? bounds->to_right : newmv.d.x;
       newmv.d.y = (raw.d.y < bounds->to_top)
                   ? bounds->to_top : raw.d.y;
       newmv.d.y = (raw.d.y > bounds->to_bottom)
                   ? bounds->to_bottom : newmv.d.y;
       return newmv;
   }


   static int
   read_segment_id(struct bool_decoder *bool,
                   struct vp8_segment_hdr *seg)
   {
       return bool_get(bool, seg->tree_probs[0])
              ? 2 + bool_get(bool, seg->tree_probs[2])
              : bool_get(bool, seg->tree_probs[1]);
   }


   static enum prediction_mode
   above_block_mode(const struct mb_info *this,
                    const struct mb_info *above,
                    unsigned int b)
   {
       if (b < 4)
       {
           switch (above->base.y_mode)
           {
           case DC_PRED:
               return B_DC_PRED;
           case V_PRED:
               return B_VE_PRED;
           case H_PRED:
               return B_HE_PRED;

Top      Up      ToC       Page 178 
           case TM_PRED:
               return B_TM_PRED;
           case B_PRED:
               return above->split.modes[b+12];
           default:
               assert(0);
           }
       }

       return this->split.modes[b-4];
   }


   static enum prediction_mode
   left_block_mode(const struct mb_info *this,
                   const struct mb_info *left,
                   unsigned int b)
   {
       if (!(b & 3))
       {
           switch (left->base.y_mode)
           {
           case DC_PRED:
               return B_DC_PRED;
           case V_PRED:
               return B_VE_PRED;
           case H_PRED:
               return B_HE_PRED;
           case TM_PRED:
               return B_TM_PRED;
           case B_PRED:
               return left->split.modes[b+3];
           default:
               assert(0);
           }
       }

       return this->split.modes[b-1];
   }

Top      Up      ToC       Page 179 
   static void
   decode_kf_mb_mode(struct mb_info      *this,
                     struct mb_info      *left,
                     struct mb_info      *above,
                     struct bool_decoder *bool)
   {
       int y_mode, uv_mode;

       y_mode = bool_read_tree(bool, kf_y_mode_tree, kf_y_mode_probs);

       if (y_mode == B_PRED)
       {
           unsigned int i;

           for (i = 0; i < 16; i++)
           {
               enum prediction_mode a = above_block_mode(this, above,
                                                         i);
               enum prediction_mode l = left_block_mode(this, left, i);
               enum prediction_mode b;

               b = bool_read_tree(bool, b_mode_tree,
                                  kf_b_mode_probs[a][l]);
               this->split.modes[i] = b;
           }
       }

       uv_mode = bool_read_tree(bool, uv_mode_tree, kf_uv_mode_probs);

       this->base.y_mode = y_mode;
       this->base.uv_mode = uv_mode;
       this->base.mv.raw = 0;
       this->base.ref_frame = 0;
   }

   static void
   decode_intra_mb_mode(struct mb_info         *this,
                        struct vp8_entropy_hdr *hdr,
                        struct bool_decoder    *bool)
   {
       /* Like decode_kf_mb_mode, but with probabilities transmitted in
        * the bitstream and no context on the above/left block mode.
        */
       int y_mode, uv_mode;

       y_mode = bool_read_tree(bool, y_mode_tree, hdr->y_mode_probs);

Top      Up      ToC       Page 180 
       if (y_mode == B_PRED)
       {
           unsigned int i;

           for (i = 0; i < 16; i++)
           {
               enum prediction_mode b;

               b = bool_read_tree(bool, b_mode_tree,
                                  default_b_mode_probs);
               this->split.modes[i] = b;
           }
       }

       uv_mode = bool_read_tree(bool, uv_mode_tree, hdr->uv_mode_probs);

       this->base.y_mode = y_mode;
       this->base.uv_mode = uv_mode;
       this->base.mv.raw = 0;
       this->base.ref_frame = CURRENT_FRAME;
   }


   static int
   read_mv_component(struct bool_decoder *bool,
                     const unsigned char  mvc[MV_PROB_CNT])
   {
       enum {IS_SHORT, SIGN, SHORT, BITS = SHORT + 8 - 1,
             LONG_WIDTH = 10};
       int x = 0;

       if (bool_get(bool, mvc[IS_SHORT])) /* Large */
       {
           int i = 0;

           for (i = 0; i < 3; i++)
               x += bool_get(bool, mvc[BITS + i]) << i;

           /* Skip bit 3, which is sometimes implicit */
           for (i = LONG_WIDTH - 1; i > 3; i--)
               x += bool_get(bool, mvc[BITS + i]) << i;

           if (!(x & 0xFFF0)  ||  bool_get(bool, mvc[BITS + 3]))
               x += 8;
       }
       else   /* small */
           x = bool_read_tree(bool, small_mv_tree, mvc + SHORT);

Top      Up      ToC       Page 181 
       if (x && bool_get(bool, mvc[SIGN]))
           x = -x;

       return x << 1;
   }


   static mv_t
   above_block_mv(const struct mb_info *this,
                  const struct mb_info *above,
                  unsigned int          b)
   {
       if (b < 4)
       {
           if (above->base.y_mode == SPLITMV)
               return above->split.mvs[b+12];

           return above->base.mv;
       }

       return this->split.mvs[b-4];
   }


   static mv_t
   left_block_mv(const struct mb_info *this,
                 const struct mb_info *left,
                 unsigned int          b)
   {
       if (!(b & 3))
       {
           if (left->base.y_mode == SPLITMV)
               return left->split.mvs[b+3];

           return left->base.mv;
       }

       return this->split.mvs[b-1];
   }

Top      Up      ToC       Page 182 
   static enum prediction_mode
   submv_ref(struct bool_decoder *bool, union mv l, union mv a)
   {
       enum subblock_mv_ref
       {
           SUBMVREF_NORMAL,
           SUBMVREF_LEFT_ZED,
           SUBMVREF_ABOVE_ZED,
           SUBMVREF_LEFT_ABOVE_SAME,
           SUBMVREF_LEFT_ABOVE_ZED
       };

       int lez = !(l.raw);
       int aez = !(a.raw);
       int lea = l.raw == a.raw;
       enum subblock_mv_ref ctx = SUBMVREF_NORMAL;

       if (lea && lez)
           ctx = SUBMVREF_LEFT_ABOVE_ZED;
       else if (lea)
           ctx = SUBMVREF_LEFT_ABOVE_SAME;
       else if (aez)
           ctx = SUBMVREF_ABOVE_ZED;
       else if (lez)
           ctx = SUBMVREF_LEFT_ZED;

       return bool_read_tree(bool, submv_ref_tree,
                             submv_ref_probs2[ctx]);
   }


   static void
   read_mv(struct bool_decoder  *bool,
           union mv             *mv,
           mv_component_probs_t  mvc[2])
   {
       mv->d.y = read_mv_component(bool, mvc[0]);
       mv->d.x = read_mv_component(bool, mvc[1]);
   }

Top      Up      ToC       Page 183 
   static void
   mv_bias(const struct mb_info *mb,
           const unsigned int   sign_bias[3],
           enum reference_frame ref_frame,
           union mv             *mv)
   {
       if (sign_bias[mb->base.ref_frame] ^ sign_bias[ref_frame])
       {
           mv->d.x *= -1;
           mv->d.y *= -1;
       }
   }


   enum near_mv_v
   {
       CNT_BEST = 0,
       CNT_ZEROZERO = 0,
       CNT_NEAREST,
       CNT_NEAR,
       CNT_SPLITMV
   };


   static void
   find_near_mvs(const struct mb_info   *this,
                 const struct mb_info   *left,
                 const struct mb_info   *above,
                 const unsigned int      sign_bias[3],
                 union  mv               near_mvs[4],
                 int                     cnt[4])
   {
       const struct mb_info *aboveleft = above - 1;
       union  mv             *mv = near_mvs;
       int                   *cntx = cnt;

       /* Zero accumulators */
       mv[0].raw = mv[1].raw = mv[2].raw = 0;
       cnt[0] = cnt[1] = cnt[2] = cnt[3] = 0;

Top      Up      ToC       Page 184 
       /* Process above */
       if (above->base.ref_frame != CURRENT_FRAME)
       {
           if (above->base.mv.raw)
           {
               (++mv)->raw = above->base.mv.raw;
               mv_bias(above, sign_bias, this->base.ref_frame, mv);
               ++cntx;
           }

           *cntx += 2;
       }

       /* Process left */
       if (left->base.ref_frame != CURRENT_FRAME)
       {
           if (left->base.mv.raw)
           {
               union mv this_mv;

               this_mv.raw = left->base.mv.raw;
               mv_bias(left, sign_bias, this->base.ref_frame, &this_mv);

               if (this_mv.raw != mv->raw)
               {
                   (++mv)->raw = this_mv.raw;
                   ++cntx;
               }

               *cntx += 2;
           }
           else
               cnt[CNT_ZEROZERO] += 2;
       }

       /* Process above left */
       if (aboveleft->base.ref_frame != CURRENT_FRAME)
       {
           if (aboveleft->base.mv.raw)
           {
               union mv this_mv;

               this_mv.raw = aboveleft->base.mv.raw;
               mv_bias(aboveleft, sign_bias, this->base.ref_frame,
                       &this_mv);

Top      Up      ToC       Page 185 
               if (this_mv.raw != mv->raw)
               {
                   (++mv)->raw = this_mv.raw;
                   ++cntx;
               }

               *cntx += 1;
           }
           else
               cnt[CNT_ZEROZERO] += 1;
       }

       /* If we have three distinct MVs ... */

       if (cnt[CNT_SPLITMV])
       {
           /* See if above-left MV can be merged with NEAREST */
           if (mv->raw == near_mvs[CNT_NEAREST].raw)
               cnt[CNT_NEAREST] += 1;
       }

       cnt[CNT_SPLITMV] = ((above->base.y_mode == SPLITMV)
                           + (left->base.y_mode == SPLITMV)) * 2
                          + (aboveleft->base.y_mode == SPLITMV);

       /* Swap near and nearest if necessary */
       if (cnt[CNT_NEAR] > cnt[CNT_NEAREST])
       {
           int tmp;
           tmp = cnt[CNT_NEAREST];
           cnt[CNT_NEAREST] = cnt[CNT_NEAR];
           cnt[CNT_NEAR] = tmp;
           tmp = near_mvs[CNT_NEAREST].raw;
           near_mvs[CNT_NEAREST].raw = near_mvs[CNT_NEAR].raw;
           near_mvs[CNT_NEAR].raw = tmp;
       }

       /* Use near_mvs[CNT_BEST] to store the "best" MV.  Note that this
        * storage shares the same address as near_mvs[CNT_ZEROZERO].
        */
       if (cnt[CNT_NEAREST] >= cnt[CNT_BEST])
           near_mvs[CNT_BEST] = near_mvs[CNT_NEAREST];
   }

Top      Up      ToC       Page 186 
   static void
   decode_split_mv(struct mb_info         *this,
                   const struct mb_info   *left,
                   const struct mb_info   *above,
                   struct vp8_entropy_hdr *hdr,
                   union  mv              *best_mv,
                   struct bool_decoder    *bool)
   {
       const int *partition;
       int        j, k, mask, partition_id;

       partition_id = bool_read_tree(bool, split_mv_tree,
                                     split_mv_probs);
       partition = mv_partitions[partition_id];
       this->base.partitioning = partition_id;

       for (j = 0, mask = 0; mask < 65535; j++)
       {
           union mv mv, left_mv, above_mv;
           enum prediction_mode subblock_mode;

           /* Find the first subblock in this partition. */
           for (k = 0; j != partition[k]; k++);

           /* Decode the next MV */
           left_mv = left_block_mv(this, left, k);
           above_mv = above_block_mv(this, above, k);
           subblock_mode = submv_ref(bool, left_mv,  above_mv);

           switch (subblock_mode)
           {
           case LEFT4X4:
               mv = left_mv;
               break;
           case ABOVE4X4:
               mv = above_mv;
               break;
           case ZERO4X4:
               mv.raw = 0;
               break;
           case NEW4X4:
               read_mv(bool, &mv, hdr->mv_probs);
               mv.d.x += best_mv->d.x;
               mv.d.y += best_mv->d.y;
               break;
           default:
               assert(0);
           }

Top      Up      ToC       Page 187 
           /* Fill the MVs for this partition */
           for (; k < 16; k++)
               if (j == partition[k])
               {
                   this->split.mvs[k] = mv;
                   mask |= 1 << k;
               }
       }
   }


   static int
   need_mc_border(union mv mv, int l, int t, int b_w, int w, int h)
   {
       int b, r;

       /* Get distance to edge for top-left pixel */
       l += (mv.d.x >> 3);
       t += (mv.d.y >> 3);

       /* Get distance to edge for bottom-right pixel */
       r = w - (l + b_w);
       b = h - (t + b_w);

       return (l >> 1 < 2 || r >> 1 < 3 || t >> 1 < 2 || b >> 1 < 3);
   }

   static void
   decode_mvs(struct vp8_decoder_ctx       *ctx,
              struct mb_info               *this,
              const struct mb_info         *left,
              const struct mb_info         *above,
              const struct mv_clamp_rect   *bounds,
              struct bool_decoder          *bool)
   {
       struct vp8_entropy_hdr *hdr = &ctx->entropy_hdr;
       union mv          near_mvs[4];
       union mv          clamped_best_mv;
       int               mv_cnts[4];
       unsigned char     probs[4];
       enum {BEST, NEAREST, NEAR};
       int x, y, w, h, b;

       this->base.ref_frame = bool_get(bool, hdr->prob_last)
                              ? 2 + bool_get(bool, hdr->prob_gf)
                              : 1;

Top      Up      ToC       Page 188 
       find_near_mvs(this, this - 1, above,
                     ctx->reference_hdr.sign_bias, near_mvs, mv_cnts);
       probs[0] = mv_counts_to_probs[mv_cnts[0]][0];
       probs[1] = mv_counts_to_probs[mv_cnts[1]][1];
       probs[2] = mv_counts_to_probs[mv_cnts[2]][2];
       probs[3] = mv_counts_to_probs[mv_cnts[3]][3];

       this->base.y_mode = bool_read_tree(bool, mv_ref_tree, probs);
       this->base.uv_mode = this->base.y_mode;

       this->base.need_mc_border = 0;
       x = (-bounds->to_left - 128) >> 3;
       y = (-bounds->to_top - 128) >> 3;
       w = ctx->mb_cols * 16;
       h = ctx->mb_rows * 16;

       switch (this->base.y_mode)
       {
       case NEARESTMV:
           this->base.mv = clamp_mv(near_mvs[NEAREST], bounds);
           break;
       case NEARMV:
           this->base.mv = clamp_mv(near_mvs[NEAR], bounds);
           break;
       case ZEROMV:
           this->base.mv.raw = 0;
           return; //skip need_mc_border check
       case NEWMV:
           clamped_best_mv = clamp_mv(near_mvs[BEST], bounds);
           read_mv(bool, &this->base.mv, hdr->mv_probs);
           this->base.mv.d.x += clamped_best_mv.d.x;
           this->base.mv.d.y += clamped_best_mv.d.y;
           break;
       case SPLITMV:
       {
           union mv          chroma_mv[4] = {{{0}}};

           clamped_best_mv = clamp_mv(near_mvs[BEST], bounds);
           decode_split_mv(this, left, above, hdr, &clamped_best_mv,
                           bool);
           this->base.mv = this->split.mvs[15];

Top      Up      ToC       Page 189 
           for (b = 0; b < 16; b++)
           {
               chroma_mv[(b>>1&1) + (b>>2&2)].d.x +=
                   this->split.mvs[b].d.x;
               chroma_mv[(b>>1&1) + (b>>2&2)].d.y +=
                   this->split.mvs[b].d.y;

               if (need_mc_border(this->split.mvs[b],
               x + (b & 3) * 4, y + (b & ~3), 4, w, h))
               {
                   this->base.need_mc_border = 1;
                   break;
               }
           }

           for (b = 0; b < 4; b++)
           {
               chroma_mv[b].d.x += 4 + 8 * (chroma_mv[b].d.x >> 31);
               chroma_mv[b].d.y += 4 + 8 * (chroma_mv[b].d.y >> 31);
               chroma_mv[b].d.x /= 4;
               chroma_mv[b].d.y /= 4;

               //note we're passing in non-subsampled coordinates

               if (need_mc_border(chroma_mv[b],
               x + (b & 1) * 8, y + (b >> 1) * 8, 16, w, h))
               {
                   this->base.need_mc_border = 1;
                   break;
               }
           }

           return; //skip need_mc_border check
       }
       default:
           assert(0);
       }

       if (need_mc_border(this->base.mv, x, y, 16, w, h))
           this->base.need_mc_border = 1;
   }

Top      Up      ToC       Page 190 
   void
   vp8_dixie_modemv_process_row(struct vp8_decoder_ctx *ctx,
   struct bool_decoder    *bool,
   int                     row,
   int                     start_col,
   int                     num_cols)
   {
       struct mb_info       *above, *this;
       unsigned int          col;
       struct mv_clamp_rect  bounds;

       this = ctx->mb_info_rows[row] + start_col;
       above = ctx->mb_info_rows[row - 1] + start_col;

       /* Calculate the eighth-pel MV bounds using a 1 MB border. */
       bounds.to_left   = -((start_col + 1) << 7);
       bounds.to_right  = (ctx->mb_cols - start_col) << 7;
       bounds.to_top    = -((row + 1) << 7);
       bounds.to_bottom = (ctx->mb_rows - row) << 7;

       for (col = start_col; col < start_col + num_cols; col++)
       {
           if (ctx->segment_hdr.update_map)
               this->base.segment_id = read_segment_id(bool,
               &ctx->segment_hdr);

           if (ctx->entropy_hdr.coeff_skip_enabled)
               this->base.skip_coeff = bool_get(bool,
               ctx->entropy_hdr.coeff_skip_prob);

           if (ctx->frame_hdr.is_keyframe)
           {
               if (!ctx->segment_hdr.update_map)
                   this->base.segment_id = 0;

               decode_kf_mb_mode(this, this - 1, above, bool);
           }
           else
           {
               if (bool_get(bool, ctx->entropy_hdr.prob_inter))
                   decode_mvs(ctx, this, this - 1, above, &bounds,
                              bool);
               else
                   decode_intra_mb_mode(this, &ctx->entropy_hdr, bool);

               bounds.to_left -= 16 << 3;
               bounds.to_right -= 16 << 3;
           }

Top      Up      ToC       Page 191 
           /* Advance to next mb */
           this++;
           above++;
       }
   }


   void
   vp8_dixie_modemv_init(struct vp8_decoder_ctx *ctx)
   {
       unsigned int    mbi_w, mbi_h, i;
       struct mb_info *mbi;

       mbi_w = ctx->mb_cols + 1; /* For left border col */
       mbi_h = ctx->mb_rows + 1; /* For above border row */

       if (ctx->frame_hdr.frame_size_updated)
       {
           free(ctx->mb_info_storage);
           ctx->mb_info_storage = NULL;
           free(ctx->mb_info_rows_storage);
           ctx->mb_info_rows_storage = NULL;
       }

       if (!ctx->mb_info_storage)
           ctx->mb_info_storage = calloc(mbi_w * mbi_h,
           sizeof(*ctx->mb_info_storage));

       if (!ctx->mb_info_rows_storage)

           ctx->mb_info_rows_storage = calloc(mbi_h,
           sizeof(*ctx->mb_info_rows_storage));

       /* Set up row pointers */
       mbi = ctx->mb_info_storage + 1;

       for (i = 0; i < mbi_h; i++)
       {
           ctx->mb_info_rows_storage[i] = mbi;
           mbi += mbi_w;
       }

       ctx->mb_info_rows = ctx->mb_info_rows_storage + 1;
   }

Top      Up      ToC       Page 192 
   void
   vp8_dixie_modemv_destroy(struct vp8_decoder_ctx *ctx)
   {
       free(ctx->mb_info_storage);
       ctx->mb_info_storage = NULL;
       free(ctx->mb_info_rows_storage);
       ctx->mb_info_rows_storage = NULL;
   }

   ---- End code block ----------------------------------------

20.12.  modemv.h

   ---- Begin code block --------------------------------------

   /*
    *  Copyright (c) 2010, 2011, Google Inc.  All rights reserved.
    *
    *  Use of this source code is governed by a BSD-style license
    *  that can be found in the LICENSE file in the root of the source
    *  tree.  An additional intellectual property rights grant can be
    *  found in the file PATENTS.  All contributing project authors may
    *  be found in the AUTHORS file in the root of the source tree.
    */
   #ifndef MODEMV_H
   #define MODEMV_H

   void
   vp8_dixie_modemv_init(struct vp8_decoder_ctx *ctx);


   void
   vp8_dixie_modemv_destroy(struct vp8_decoder_ctx *ctx);


   void
   vp8_dixie_modemv_process_row(struct vp8_decoder_ctx *ctx,
                                struct bool_decoder    *bool,
                                int                     row,
                                int                     start_col,
                                int                     num_cols);

   #endif

   ---- End code block ----------------------------------------


Next RFC Part