]> granicus.if.org Git - libvpx/commitdiff
Segmentation Features;
authorPaul Wilkins <paulwilkins@google.com>
Fri, 7 Oct 2011 15:58:28 +0000 (16:58 +0100)
committerPaul Wilkins <paulwilkins@google.com>
Mon, 24 Oct 2011 16:06:29 +0000 (17:06 +0100)
Only encode sign bit for feature data that can have a sign.

Tweaks to the test segmentation rules so that it now actually gives
a net benefit on the derf set of about 0.4% though much higher
on some clips at the low end.

Change-Id: I8e61f1aebf41c9037db7e67e2f8975aa18a0c986

vp8/common/seg_common.c
vp8/common/seg_common.h
vp8/decoder/decodframe.c
vp8/encoder/bitstream.c
vp8/encoder/encodeframe.c
vp8/encoder/mbgraph.c
vp8/encoder/onyx_if.c

index 292a2fd758c6a1cb40c5337e278b8be937e8a953..ef77dfc53a867e2babc3b48f3a113ae071705601 100644 (file)
@@ -10,6 +10,9 @@
 
 #include "vp8/common/seg_common.h"
 
+const int segfeaturedata_signed[SEG_LVL_MAX] = {1, 1, 0, 0, 0, 0};
+
+
 // These functions provide access to new segment level features.
 // Eventually these function may be "optimized out" but for the moment,
 // the coding mechanism is still subject to change so these provide a
@@ -25,6 +28,12 @@ int segfeature_active( MACROBLOCKD *xd,
                (0x01 << feature_id) ) );
 }
 
+void clearall_segfeatures( MACROBLOCKD *xd )
+{
+     vpx_memset(xd->segment_feature_data, 0, sizeof(xd->segment_feature_data));
+     vpx_memset(xd->segment_feature_mask, 0, sizeof(xd->segment_feature_mask));
+}
+
 void enable_segfeature( MACROBLOCKD *xd,
                         int segment_id,
                         SEG_LVL_FEATURES feature_id )
@@ -38,4 +47,9 @@ void disable_segfeature( MACROBLOCKD *xd,
      xd->segment_feature_mask[segment_id] &= ~(1 << feature_id);
 }
 
+int is_segfeature_signed( SEG_LVL_FEATURES feature_id )
+{
+    return ( segfeaturedata_signed[feature_id] );
+}
+
 // TBD? Functions to read and write segment data with range / validity checking
\ No newline at end of file
index 2a9d3dc8fcc7661c4fc21ce10ce6e7b977052070..cea16c8859249c243f26110b7c718e24711baa84 100644 (file)
@@ -18,6 +18,8 @@ int segfeature_active( MACROBLOCKD *xd,
                        int segment_id,
                        SEG_LVL_FEATURES feature_id );
 
+void clearall_segfeatures( MACROBLOCKD *xd );
+
 void enable_segfeature( MACROBLOCKD *xd,
                         int segment_id,
                         SEG_LVL_FEATURES feature_id );
@@ -26,5 +28,7 @@ void disable_segfeature( MACROBLOCKD *xd,
                          int segment_id,
                          SEG_LVL_FEATURES feature_id );
 
+int is_segfeature_signed( SEG_LVL_FEATURES feature_id );
+
 #endif /* __INC_SEG_COMMON_H__ */
 
index 585413b868fa1d6e7bd2f245fd1b0caf4820a623..bfa13caec9e06f0368aaa855219168920bae6bb6 100644 (file)
@@ -1030,14 +1030,8 @@ int vp8_decode_frame(VP8D_COMP *pbi)
         {
             xd->mb_segement_abs_delta = (unsigned char)vp8_read_bit(bc);
 
-            // Clear down feature data structure
-            vpx_memset(xd->segment_feature_data, 0,
-                       sizeof(xd->segment_feature_data));
-
 #if CONFIG_SEGFEATURES
-            // Clear down feature enabled masks
-            vpx_memset(xd->segment_feature_mask, 0,
-                       sizeof(xd->segment_feature_mask));
+            clearall_segfeatures( xd );
 
             // For each segmentation...
             for (j = 0; j < MAX_MB_SEGMENTS; j++)
@@ -1045,8 +1039,11 @@ int vp8_decode_frame(VP8D_COMP *pbi)
                 // For each of the segments features...
                 for (i = 0; i < SEG_LVL_MAX; i++)
                 {
-
 #else
+            // Clear down feature data structure
+            vpx_memset(xd->segment_feature_data, 0,
+                       sizeof(xd->segment_feature_data));
+
             // For each segmentation feature...
             for (i = 0; i < SEG_LVL_MAX; i++)
             {
@@ -1061,10 +1058,23 @@ int vp8_decode_frame(VP8D_COMP *pbi)
                         // Update the feature data and mask
                         enable_segfeature(xd, j, i);
 #endif
-                        xd->segment_feature_data[j][i] = (signed char)vp8_read_literal(bc, mb_feature_data_bits[i]);
+                        xd->segment_feature_data[j][i] =
+                            (signed char)vp8_read_literal(
+                                             bc, mb_feature_data_bits[i]);
 
-                        if (vp8_read_bit(bc))
-                            xd->segment_feature_data[j][i] = -xd->segment_feature_data[j][i];
+#if CONFIG_SEGFEATURES
+                        // Is the segment data signed..
+                        if ( is_segfeature_signed(i) )
+#else
+                        if ( 1 )
+#endif
+                        {
+                            if (vp8_read_bit(bc))
+                            {
+                                xd->segment_feature_data[j][i] =
+                                    -xd->segment_feature_data[j][i];
+                            }
+                        }
                     }
                     else
                     {
index 6b30a59af76ac238e1f092067293214bfcbc8da1..395ffa79db6ef84a72c439fd6efe36766267ceaa 100644 (file)
@@ -1987,20 +1987,32 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size)
                     {
                         vp8_write_bit(bc, 1);
 
-                        // Encode the relevant feature data
-                        if (Data < 0)
+#if CONFIG_SEGFEATURES
+                        // Is the segment data signed..
+                        if ( is_segfeature_signed(i) )
+#else
+                        if ( 1 )
+#endif
                         {
-                            Data = - Data;
-                            vp8_write_literal(bc, Data,
-                                              mb_feature_data_bits[i]);
-                            vp8_write_bit(bc, 1);
+                            // Encode the relevant feature data
+                            if (Data < 0)
+                            {
+                                Data = - Data;
+                                vp8_write_literal(bc, Data,
+                                                  mb_feature_data_bits[i]);
+                                vp8_write_bit(bc, 1);
+                            }
+                            else
+                            {
+                                vp8_write_literal(bc, Data,
+                                                  mb_feature_data_bits[i]);
+                                vp8_write_bit(bc, 0);
+                            }
                         }
+                        // Unsigned data element so no sign bit needed
                         else
-                        {
                             vp8_write_literal(bc, Data,
                                               mb_feature_data_bits[i]);
-                            vp8_write_bit(bc, 0);
-                        }
                     }
                     else
                         vp8_write_bit(bc, 0);
index ca3cb6efbbd9f56cad79e20e811cfe7679c282b8..a6e47f240760b5398193c10f9cdc2fc0a93e8dd7 100644 (file)
@@ -969,7 +969,7 @@ void vp8_encode_frame(VP8_COMP *cpi)
 
 #if CONFIG_SEGFEATURES
 // debug output
-#if 0
+#if DBG_PRNT_SEGMAP
     {
         FILE *statsfile;
         statsfile = fopen("segmap2.stt", "a");
index 1a9612d3976f31768345f0e82e4e80952d524253..8a3f55f33fca2c974b533162bdd66e15ca340b7d 100644 (file)
@@ -143,6 +143,47 @@ static int do_16x16_motion_search
     return err;
 }
 
+static int do_16x16_zerozero_search
+(
+    VP8_COMP *cpi,
+    int_mv *dst_mv,
+    YV12_BUFFER_CONFIG *buf,
+    int buf_mb_y_offset,
+    YV12_BUFFER_CONFIG *ref,
+    int mb_y_offset
+)
+{
+    MACROBLOCK  * const x  = &cpi->mb;
+    MACROBLOCKD * const xd = &x->e_mbd;
+    unsigned int err, tmp_err;
+    int_mv tmp_mv;
+    int n;
+
+    for (n = 0; n < 16; n++) {
+        BLOCKD *d = &xd->block[n];
+        BLOCK *b  = &x->block[n];
+
+        b->base_src   = &buf->y_buffer;
+        b->src_stride = buf->y_stride;
+        b->src        = buf->y_stride * (n & 12) + (n & 3) * 4 + buf_mb_y_offset;
+
+        d->base_pre   = &ref->y_buffer;
+        d->pre_stride = ref->y_stride;
+        d->pre        = ref->y_stride * (n & 12) + (n & 3) * 4 + mb_y_offset;
+    }
+
+    // Try zero MV first
+    // FIXME should really use something like near/nearest MV and/or MV prediction
+    xd->pre.y_buffer = ref->y_buffer + mb_y_offset;
+    xd->pre.y_stride = ref->y_stride;
+    VARIANCE_INVOKE(&cpi->rtcd.variance, satd16x16)
+                    (ref->y_buffer + mb_y_offset,
+                     ref->y_stride, xd->dst.y_buffer,
+                     xd->dst.y_stride, &err);
+    dst_mv->as_int = 0;
+
+    return err;
+}
 static int find_best_16x16_intra
 (
     VP8_COMP *cpi,
@@ -227,10 +268,17 @@ static void update_mbgraph_mb_stats
     // Alt-ref frame MV search, if it exists and is different than last/golden frame
     if (alt_ref)
     {
-        int a_motion_error = do_16x16_motion_search(cpi, prev_alt_ref_mv,
-                                                    &stats->ref[ALTREF_FRAME].m.mv,
-                                                    buf, mb_y_offset,
-                                                    alt_ref, arf_y_offset);
+        //int a_motion_error = do_16x16_motion_search(cpi, prev_alt_ref_mv,
+        //                                            &stats->ref[ALTREF_FRAME].m.mv,
+        //                                            buf, mb_y_offset,
+        //                                            alt_ref, arf_y_offset);
+
+        int a_motion_error =
+                do_16x16_zerozero_search( cpi,
+                                          &stats->ref[ALTREF_FRAME].m.mv,
+                                          buf, mb_y_offset,
+                                          alt_ref, arf_y_offset);
+
         stats->ref[ALTREF_FRAME].err = a_motion_error;
     }
     else
@@ -312,6 +360,15 @@ static void update_mbgraph_frame_stats
     }
 }
 
+// Test for small magnitude (<= 1 pel mvs)
+int small_mv( MV mv )
+{
+    if ( (abs( (int)mv.col ) > 2) || (abs( (int)mv.row ) > 2) )
+        return FALSE;
+    else
+        return TRUE;
+}
+
 //void separate_arf_mbs_byzz
 void separate_arf_mbs
 (
@@ -350,16 +407,15 @@ void separate_arf_mbs
                 int altref_err = mb_stats->ref[ALTREF_FRAME].err;
 
                 int intra_err  =
-                    ((mb_stats->ref[INTRA_FRAME ].err * 9) >> 3);
+                    mb_stats->ref[INTRA_FRAME ].err + 250;
 
                 int golden_err =
-                    250 + ((mb_stats->ref[GOLDEN_FRAME].err * 9) >> 3);
+                    mb_stats->ref[GOLDEN_FRAME].err + 250;
 
                 // Test for altref vs intra and gf and that its mv was 0,0.
-                if ( mb_stats->ref[ALTREF_FRAME].m.mv.as_int ||
-                     ( (altref_err > 500) &&
-                       ( (altref_err > (intra_err >> 2)) ||
-                         (altref_err > golden_err) ) ) )
+                if ( (altref_err > 1000) ||
+                     (altref_err > intra_err) ||
+                     (altref_err > golden_err) )
                 {
                     arf_not_zz[offset + mb_col]++;
                 }
@@ -389,7 +445,8 @@ void separate_arf_mbs
     }
 
     // Only bother with segmentation if over 10% of the MBs in static segment
-    if ( ncnt[1] && (ncnt[0] / ncnt[1] < 10) )
+    //if ( ncnt[1] && (ncnt[0] / ncnt[1] < 10) )
+    if ( 1 )
     {
         cpi->mbgraph_use_arf_segmentation = ncnt[1];
         vp8_enable_segmentation((VP8_PTR) cpi);
index 26cbbf0116bb2f2151b110ec395fa752f633e908..c6547cf4a03a09f3c04404391c5f66bc4d5a86d8 100644 (file)
@@ -489,8 +489,8 @@ static void init_seg_features(VP8_COMP *cpi)
         return;
     }
 
-    // Disable and clear down for KF,ARF and low Q
-    if ( cm->frame_type == KEY_FRAME || cm->refresh_alt_ref_frame )
+    // Disable and clear down for KF
+    if ( cm->frame_type == KEY_FRAME  )
     {
         // Clear down the global segmentation map
         vpx_memset( cpi->segmentation_map, 0, (cm->mb_rows * cm->mb_cols));
@@ -499,59 +499,117 @@ static void init_seg_features(VP8_COMP *cpi)
 
         // Disable segmentation
         vp8_disable_segmentation((VP8_PTR)cpi);
+
+        // Clear down the segment features.
+        clearall_segfeatures(xd);
     }
 
-    // First normal frame in a valid alt ref group and we dont have low Q
-    else if ( cpi->source_alt_ref_active &&
-              (cpi->common.frames_since_golden == 1) )
+    // If this is an alt ref frame
+    else if ( cm->refresh_alt_ref_frame )
     {
-        // Low Q test (only use segmentation at high q)
-        if ( ( (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) &&
-               (cpi->cq_target_quality > 56 ) ) ||
-             (cpi->ni_av_qi > 64) )
+        // Clear down the global segmentation map
+        vpx_memset( cpi->segmentation_map, 0, (cm->mb_rows * cm->mb_cols));
+        xd->update_mb_segmentation_map = 0;
+        xd->update_mb_segmentation_data = 0;
+
+        // Disable segmentation and individual segment features by default
+        vp8_disable_segmentation((VP8_PTR)cpi);
+        clearall_segfeatures(xd);
+
+        // Scan frames from current to arf frame.
+        // This function re-enables segmentation if appropriate.
+        vp8_update_mbgraph_stats(cpi);
+
+        // If segmentation was enabled set those features needed for the
+        // arf itself.
+        if ( xd->segmentation_enabled )
         {
-            xd->segment_feature_data[1][SEG_LVL_REF_FRAME] = LAST_FRAME;
-            xd->segment_feature_data[1][SEG_LVL_MODE] = ZEROMV;
-            xd->segment_feature_data[1][SEG_LVL_EOB] = 10;
-            xd->segment_feature_data[1][SEG_LVL_ALT_Q] = 10;
-            xd->segment_feature_data[1][SEG_LVL_ALT_LF] = -5;
-
-            // Enable target features is the segment feature mask
-            enable_segfeature(xd, 1, SEG_LVL_REF_FRAME);
-            enable_segfeature(xd, 1, SEG_LVL_MODE);
-            enable_segfeature(xd, 1, SEG_LVL_EOB);
+            xd->update_mb_segmentation_map = 1;
+            xd->update_mb_segmentation_data = 1;
+
+            xd->segment_feature_data[1][SEG_LVL_ALT_Q] = -3;
+            xd->segment_feature_data[1][SEG_LVL_ALT_LF] = -2;
+
             enable_segfeature(xd, 1, SEG_LVL_ALT_Q);
             enable_segfeature(xd, 1, SEG_LVL_ALT_LF);
 
             // Where relevant assume segment data is delta data
             xd->mb_segement_abs_delta = SEGMENT_DELTADATA;
-
-            // Scan frames from current to arf frame and define segmentation
-            vp8_update_mbgraph_stats(cpi);
         }
     }
-    // Normal frames if segmentation got enabled.
+
+    // All other frames if segmentation has been enabled
     else if ( xd->segmentation_enabled )
     {
-        // Special case where we are coding over the top of a previous
-        // alt ref frame
-        if ( cpi->is_src_frame_alt_ref )
+        // First normal frame in a valid gf or alt ref group
+        if ( cpi->common.frames_since_golden == 0 )
         {
-            if ( cpi->source_alt_ref_pending )
+            // Set up segment features for normal frames in an af group
+            if ( cpi->source_alt_ref_active )
             {
+                xd->update_mb_segmentation_map = 0;
                 xd->update_mb_segmentation_data = 1;
-                xd->segment_feature_data[1][SEG_LVL_REF_FRAME] = ALTREF_FRAME;
+                xd->mb_segement_abs_delta = SEGMENT_DELTADATA;
+
+                xd->segment_feature_data[1][SEG_LVL_ALT_Q] = 5;
+                xd->segment_feature_data[1][SEG_LVL_ALT_LF] = -2;
+
+                enable_segfeature(xd, 1, SEG_LVL_ALT_Q);
+                enable_segfeature(xd, 1, SEG_LVL_ALT_LF);
+
+                if ( ( (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) &&
+                       (cpi->cq_target_quality > 56 ) ) ||
+                     (cpi->ni_av_qi > 64) )
+                {
+                    xd->segment_feature_data[1]
+                                            [SEG_LVL_REF_FRAME] = LAST_FRAME;
+                    xd->segment_feature_data[1][SEG_LVL_MODE] = ZEROMV;
+                    xd->segment_feature_data[1][SEG_LVL_EOB] = 15;
+
+                    enable_segfeature(xd, 1, SEG_LVL_REF_FRAME);
+                    enable_segfeature(xd, 1, SEG_LVL_MODE);
+                    enable_segfeature(xd, 1, SEG_LVL_EOB);
+                }
             }
+
+            // Disable segmentation and clear down features if alt ref
+            // is not active for this group
             else
             {
+                vp8_disable_segmentation((VP8_PTR)cpi);
+
                 vpx_memset( cpi->segmentation_map, 0,
                             (cm->mb_rows * cm->mb_cols));
-                xd->update_mb_segmentation_map = 1;
-                xd->update_mb_segmentation_data = 1;
+
+                xd->update_mb_segmentation_map = 0;
+                xd->update_mb_segmentation_data = 0;
+
+                clearall_segfeatures(xd);
             }
         }
+
+        // Special case where we are coding over the top of a previous
+        // alt ref frame
+        else if ( cpi->is_src_frame_alt_ref )
+        {
+            // Enable mode and ref frame features for segment 0 as well
+            enable_segfeature(xd, 0, SEG_LVL_REF_FRAME);
+            enable_segfeature(xd, 0, SEG_LVL_MODE);
+
+            // All mbs should use ALTREF_FRAME, ZEROMV
+            xd->segment_feature_data[0][SEG_LVL_REF_FRAME] = ALTREF_FRAME;
+            xd->segment_feature_data[0][SEG_LVL_MODE] = ZEROMV;
+            xd->segment_feature_data[1][SEG_LVL_REF_FRAME] = ALTREF_FRAME;
+            xd->segment_feature_data[1][SEG_LVL_MODE] = ZEROMV;
+
+            // Enable data udpate
+            xd->update_mb_segmentation_data = 1;
+        }
+        // All other frames.
         else
         {
+            // No updeates.. leave things as they are.
+            xd->update_mb_segmentation_map = 0;
             xd->update_mb_segmentation_data = 0;
         }
     }