shithub: libvpx

Download patch

ref: f6f0ffe96a69d7de718b9528dcc3f6f66b9cb92d
parent: c97a9fc1460a9bb078b569366020f55643597e30
parent: 3085025fa1392e99bc95a519657374f2e9a4249b
author: John Koleszar <jkoleszar@google.com>
date: Wed Jun 9 13:55:57 EDT 2010

Merge "Remove secondary mv clamping from decode stage"

--- a/vp8/common/blockd.h
+++ b/vp8/common/blockd.h
@@ -174,9 +174,8 @@
     int dc_diff;
     unsigned char   segment_id;                  // Which set of segmentation parameters should be used for this MB
     int force_no_skip;
-
+    int need_to_clamp_mvs;
     B_MODE_INFO partition_bmi[16];
-
 } MB_MODE_INFO;
 
 
--- a/vp8/decoder/decodemv.c
+++ b/vp8/decoder/decodemv.c
@@ -171,6 +171,7 @@
             VP8_COMMON *const pc = &pbi->common;
             MACROBLOCKD *xd = &pbi->mb;
 
+            mbmi->need_to_clamp_mvs = 0;
             vp8dx_bool_decoder_fill(bc);
 
             // Distance of Mb to the various image edges.
@@ -269,6 +270,17 @@
                             break;
                         }
 
+                        if (mv->col < xd->mb_to_left_edge
+                                      - LEFT_TOP_MARGIN
+                            || mv->col > xd->mb_to_right_edge
+                                         + RIGHT_BOTTOM_MARGIN
+                            || mv->row < xd->mb_to_top_edge
+                                         - LEFT_TOP_MARGIN
+                            || mv->row > xd->mb_to_bottom_edge
+                                         + RIGHT_BOTTOM_MARGIN
+                            )
+                            mbmi->need_to_clamp_mvs = 1;
+
                         /* Fill (uniform) modes, mvs of jth subset.
                            Must do it here because ensuing subsets can
                            refer back to us via "left" or "above". */
@@ -325,28 +337,19 @@
                     read_mv(bc, mv, (const MV_CONTEXT *) mvc);
                     mv->row += best_mv.row;
                     mv->col += best_mv.col;
-                    /* Encoder should not produce invalid motion vectors, but since
-                     * arbitrary length MVs can be parsed from the bitstream, we
-                     * need to clamp them here in case we're reading bad data to
-                     * avoid a crash.
+
+                    /* Don't need to check this on NEARMV and NEARESTMV modes
+                     * since those modes clamp the MV. The NEWMV mode does not,
+                     * so signal to the prediction stage whether special
+                     * handling may be required.
                      */
-#if CONFIG_DEBUG
-                    assert(mv->col >= (xd->mb_to_left_edge - LEFT_TOP_MARGIN));
-                    assert(mv->col <= (xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN));
-                    assert(mv->row >= (xd->mb_to_top_edge - LEFT_TOP_MARGIN));
-                    assert(mv->row <= (xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN));
-#endif
+                    if (mv->col < xd->mb_to_left_edge - LEFT_TOP_MARGIN
+                        || mv->col > xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN
+                        || mv->row < xd->mb_to_top_edge - LEFT_TOP_MARGIN
+                        || mv->row > xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN
+                        )
+                        mbmi->need_to_clamp_mvs = 1;
 
-                    if (mv->col < (xd->mb_to_left_edge - LEFT_TOP_MARGIN))
-                        mv->col = xd->mb_to_left_edge - LEFT_TOP_MARGIN;
-                    else if (mv->col > xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN)
-                        mv->col = xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN;
-
-                    if (mv->row < (xd->mb_to_top_edge - LEFT_TOP_MARGIN))
-                        mv->row = xd->mb_to_top_edge - LEFT_TOP_MARGIN;
-                    else if (mv->row > xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN)
-                        mv->row = xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN;
-
                 propagate_mv:  /* same MV throughout */
                     {
                         //int i=0;
@@ -381,7 +384,6 @@
                     assert(0);
 #endif
                 }
-
             }
             else
             {
--- a/vp8/decoder/decodframe.c
+++ b/vp8/decoder/decodframe.c
@@ -1,10 +1,10 @@
 /*
  *  Copyright (c) 2010 The VP8 project authors. All Rights Reserved.
  *
- *  Use of this source code is governed by a BSD-style license 
+ *  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 
+ *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
@@ -126,6 +126,47 @@
     }
 }
 
+
+static void clamp_mv_to_umv_border(MV *mv, const MACROBLOCKD *xd)
+{
+    /* If the MV points so far into the UMV border that no visible pixels
+     * are used for reconstruction, the subpel part of the MV can be
+     * discarded and the MV limited to 16 pixels with equivalent results.
+     *
+     * This limit kicks in at 19 pixels for the top and left edges, for
+     * the 16 pixels plus 3 taps right of the central pixel when subpel
+     * filtering. The bottom and right edges use 16 pixels plus 2 pixels
+     * left of the central pixel when filtering.
+     */
+    if (mv->col < (xd->mb_to_left_edge - (19 << 3)))
+        mv->col = xd->mb_to_left_edge - (16 << 3);
+    else if (mv->col > xd->mb_to_right_edge + (18 << 3))
+        mv->col = xd->mb_to_right_edge + (16 << 3);
+
+    if (mv->row < (xd->mb_to_top_edge - (19 << 3)))
+        mv->row = xd->mb_to_top_edge - (16 << 3);
+    else if (mv->row > xd->mb_to_bottom_edge + (18 << 3))
+        mv->row = xd->mb_to_bottom_edge + (16 << 3);
+}
+
+
+static void clamp_mvs(MACROBLOCKD *xd)
+{
+    if (xd->mbmi.mode == SPLITMV)
+    {
+        int i;
+
+        for (i=0; i<16; i++)
+            clamp_mv_to_umv_border(&xd->block[i].bmi.mv.as_mv, xd);
+    }
+    else
+    {
+        clamp_mv_to_umv_border(&xd->mbmi.mv.as_mv, xd);
+        clamp_mv_to_umv_border(&xd->block[16].bmi.mv.as_mv, xd);
+    }
+
+}
+
 static void reconstruct_mb(VP8D_COMP *pbi, MACROBLOCKD *xd)
 {
     if (xd->frame_type == KEY_FRAME  ||  xd->mbmi.ref_frame == INTRA_FRAME)
@@ -233,6 +274,8 @@
 void vp8_decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd)
 {
     int eobtotal = 0;
+    MV  orig_mvs[24];
+    int i, do_clamp = xd->mbmi.need_to_clamp_mvs;
 
     if (xd->mbmi.mb_skip_coeff)
     {
@@ -243,20 +286,50 @@
         eobtotal = vp8_decode_mb_tokens(pbi, xd);
     }
 
-    xd->mode_info_context->mbmi.dc_diff = 1;
-
-    if (xd->mbmi.mode != B_PRED && xd->mbmi.mode != SPLITMV && eobtotal == 0)
+    /* Perform temporary clamping of the MV to be used for prediction */
+    if (do_clamp)
     {
-        xd->mode_info_context->mbmi.dc_diff = 0;
-        skip_recon_mb(pbi, xd);
-        return;
+        if (xd->mbmi.mode == SPLITMV)
+            for (i=0; i<24; i++)
+                orig_mvs[i] = xd->block[i].bmi.mv.as_mv;
+        else
+        {
+            orig_mvs[0] = xd->mbmi.mv.as_mv;
+            orig_mvs[1] = xd->block[16].bmi.mv.as_mv;
+        }
+        clamp_mvs(xd);
     }
 
-    if (xd->segmentation_enabled)
-        mb_init_dequantizer(pbi, xd);
+    xd->mode_info_context->mbmi.dc_diff = 1;
 
-    de_quantand_idct(pbi, xd);
-    reconstruct_mb(pbi, xd);
+    do {
+        if (xd->mbmi.mode != B_PRED && xd->mbmi.mode != SPLITMV && eobtotal == 0)
+        {
+            xd->mode_info_context->mbmi.dc_diff = 0;
+            skip_recon_mb(pbi, xd);
+            break;
+        }
+
+        if (xd->segmentation_enabled)
+            mb_init_dequantizer(pbi, xd);
+
+        de_quantand_idct(pbi, xd);
+        reconstruct_mb(pbi, xd);
+    } while(0);
+
+
+    /* Restore the original MV so as not to affect the entropy context. */
+    if (do_clamp)
+    {
+        if (xd->mbmi.mode == SPLITMV)
+            for (i=0; i<24; i++)
+                xd->block[i].bmi.mv.as_mv = orig_mvs[i];
+        else
+        {
+            xd->mbmi.mv.as_mv = orig_mvs[0];
+            xd->block[16].bmi.mv.as_mv = orig_mvs[1];
+        }
+    }
 }
 
 static int get_delta_q(vp8_reader *bc, int prev, int *q_update)
@@ -314,7 +387,9 @@
     for (mb_col = 0; mb_col < pc->mb_cols; mb_col++)
     {
         // Take a copy of the mode and Mv information for this macroblock into the xd->mbmi
-        vpx_memcpy(&xd->mbmi, &xd->mode_info_context->mbmi, 32); //sizeof(MB_MODE_INFO) );
+        // the partition_bmi array is unused in the decoder, so don't copy it.
+        vpx_memcpy(&xd->mbmi, &xd->mode_info_context->mbmi,
+                   sizeof(MB_MODE_INFO) - sizeof(xd->mbmi.partition_bmi));
 
         if (xd->mbmi.mode == SPLITMV || xd->mbmi.mode == B_PRED)
         {
--- a/vp8/decoder/threading.c
+++ b/vp8/decoder/threading.c
@@ -1,10 +1,10 @@
 /*
  *  Copyright (c) 2010 The VP8 project authors. All Rights Reserved.
  *
- *  Use of this source code is governed by a BSD-style license 
+ *  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 
+ *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
@@ -154,7 +154,9 @@
                     }
 
                     // Take a copy of the mode and Mv information for this macroblock into the xd->mbmi
-                    vpx_memcpy(&xd->mbmi, &xd->mode_info_context->mbmi, 32); //sizeof(MB_MODE_INFO) );
+                    // the partition_bmi array is unused in the decoder, so don't copy it.
+                    vpx_memcpy(&xd->mbmi, &xd->mode_info_context->mbmi,
+                               sizeof(MB_MODE_INFO) - sizeof(xd->mbmi.partition_bmi));
 
                     if (xd->mbmi.mode == SPLITMV || xd->mbmi.mode == B_PRED)
                     {