From 156b221a7fd1d4eb1e49a005bf41cc1952d65cd8 Mon Sep 17 00:00:00 2001
From: Paul Wilkins <paulwilkins@google.com>
Date: Fri, 30 Sep 2011 16:45:16 +0100
Subject: [PATCH] Segment coding of mode and reference frame.

Proof of concept test code that encodes mode and reference
frame data at the segment level.

Decode-able bit stream but some issues not yet resolved.
As it this helps a little on a couple of clips but hurts on most as
the basis for segmentation is unsound.

To build and test, configure with
--enable-experimental --enable-segfeatures

Change-Id: I22a60774f69273523fb152db8c31f4b10b07c7f4
---
 vp8/decoder/decodemv.c    | 121 +++++++++++++++++++++++++-----
 vp8/encoder/bitstream.c   | 152 +++++++++++++++++++++++---------------
 vp8/encoder/encodeframe.c | 152 +++++++++++++++++++++++++++++++++-----
 vp8/encoder/onyx_if.c     | 135 ++++++++++++++++++++++++++++-----
 vp8/encoder/pickinter.c   |  36 +++++++++
 vp8/encoder/rdopt.c       |  29 +++++++-
 6 files changed, 509 insertions(+), 116 deletions(-)

diff --git a/vp8/decoder/decodemv.c b/vp8/decoder/decodemv.c
index a4ea8f11f7..b894c16dd3 100644
--- a/vp8/decoder/decodemv.c
+++ b/vp8/decoder/decodemv.c
@@ -200,6 +200,43 @@ static void read_mvcontexts(vp8_reader *bc, MV_CONTEXT *mvc)
     while (++i < 2);
 }
 
+// Read the referncence frame
+static MV_REFERENCE_FRAME read_ref_frame( VP8D_COMP *pbi,
+                                          unsigned char segment_id )
+{
+    MV_REFERENCE_FRAME ref_frame;
+
+#if CONFIG_SEGFEATURES
+    MACROBLOCKD *const xd = &pbi->mb;
+
+    // Is the segment level refernce frame feature enabled for this segment
+    if ( xd->segment_feature_mask[segment_id] & (0x01 << SEG_LVL_REF_FRAME) )
+    {
+        ref_frame =
+            xd->segment_feature_data[segment_id][SEG_LVL_REF_FRAME];
+    }
+    else
+#endif
+
+    // Per MB read of the reference frame
+    {
+        vp8_reader *const bc = &pbi->bc;
+
+        ref_frame =
+            (MV_REFERENCE_FRAME) vp8_read(bc, pbi->prob_intra);
+
+        if (ref_frame)
+        {
+            if (vp8_read(bc, pbi->prob_last))
+            {
+                ref_frame = (MV_REFERENCE_FRAME)((int)ref_frame +
+                            (int)(1 + vp8_read(bc, pbi->prob_gf)));
+            }
+        }
+    }
+
+    return (MV_REFERENCE_FRAME)ref_frame;
+}
 
 static MB_PREDICTION_MODE read_mv_ref(vp8_reader *bc, const vp8_prob *p)
 {
@@ -296,8 +333,9 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi,
     vp8_reader *const bc = & pbi->bc;
     MV_CONTEXT *const mvc = pbi->common.fc.mvc;
     const int mis = pbi->common.mode_info_stride;
-#if CONFIG_SEGMENTATION
     MACROBLOCKD *const xd  = & pbi->mb;
+
+#if CONFIG_SEGMENTATION
     int sum;
     int index = mb_row * pbi->common.mb_cols + mb_col;
 #endif
@@ -307,24 +345,24 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi,
     int mb_to_top_edge;
     int mb_to_bottom_edge;
 
-    mb_to_top_edge = pbi->mb.mb_to_top_edge;
-    mb_to_bottom_edge = pbi->mb.mb_to_bottom_edge;
+    mb_to_top_edge = xd->mb_to_top_edge;
+    mb_to_bottom_edge = xd->mb_to_bottom_edge;
     mb_to_top_edge -= LEFT_TOP_MARGIN;
     mb_to_bottom_edge += RIGHT_BOTTOM_MARGIN;
     mbmi->need_to_clamp_mvs = 0;
     /* Distance of Mb to the various image edges.
      * These specified to 8th pel as they are always compared to MV values that are in 1/8th pel units
      */
-    pbi->mb.mb_to_left_edge =
+    xd->mb_to_left_edge =
     mb_to_left_edge = -((mb_col * 16) << 3);
     mb_to_left_edge -= LEFT_TOP_MARGIN;
 
-    pbi->mb.mb_to_right_edge =
+    xd->mb_to_right_edge =
     mb_to_right_edge = ((pbi->common.mb_cols - 1 - mb_col) * 16) << 3;
     mb_to_right_edge += RIGHT_BOTTOM_MARGIN;
 
     /* If required read in new segmentation data for this MB */
-    if (pbi->mb.update_mb_segmentation_map)
+    if (xd->update_mb_segmentation_map)
             {
 #if CONFIG_SEGMENTATION
                 if (xd->temporal_update)
@@ -343,7 +381,7 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi,
                     }
                     else
                     {
-                        vp8_read_mb_features(bc, &mi->mbmi, &pbi->mb);
+                        vp8_read_mb_features(bc, &mi->mbmi, xd);
                         mbmi->segment_flag = 1;
                         pbi->segmentation_map[index] = mbmi->segment_id;
                     }
@@ -351,12 +389,12 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi,
                 }
                 else
                 {
-                    vp8_read_mb_features(bc, &mi->mbmi, &pbi->mb);
+                    vp8_read_mb_features(bc, &mi->mbmi, xd);
                     pbi->segmentation_map[index] = mbmi->segment_id;
                 }
                 index++;
 #else
-                vp8_read_mb_features(bc, &mi->mbmi, &pbi->mb);
+                vp8_read_mb_features(bc, &mi->mbmi, xd);
 #endif
             }
 
@@ -367,23 +405,38 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi,
     else
         mbmi->mb_skip_coeff = 0;
 
-    if ((mbmi->ref_frame = (MV_REFERENCE_FRAME) vp8_read(bc, pbi->prob_intra)))    /* inter MB */
+    // Read the reference frame
+    mbmi->ref_frame = read_ref_frame( pbi, mbmi->segment_id );
+
+    // If reference frame is an Inter frame
+    if (mbmi->ref_frame)
     {
         int rct[4];
-        vp8_prob mv_ref_p [VP8_MVREFS-1];
         int_mv nearest, nearby, best_mv;
+        vp8_prob mv_ref_p [VP8_MVREFS-1];
 
-        if (vp8_read(bc, pbi->prob_last))
+        vp8_find_near_mvs(xd, mi, &nearest, &nearby, &best_mv, rct,
+                          mbmi->ref_frame, pbi->common.ref_frame_sign_bias);
+        vp8_mv_ref_probs(mv_ref_p, rct);
+
+#if CONFIG_SEGFEATURES
+        // Is the segment level mode feature enabled for this segment
+        if ( xd->segment_feature_mask[mbmi->segment_id] &
+            (0x01 << SEG_LVL_MODE) )
         {
-            mbmi->ref_frame = (MV_REFERENCE_FRAME)((int)mbmi->ref_frame + (int)(1 + vp8_read(bc, pbi->prob_gf)));
+            mbmi->mode =
+                xd->segment_feature_data[mbmi->segment_id][SEG_LVL_MODE];
         }
-
-        vp8_find_near_mvs(&pbi->mb, mi, &nearest, &nearby, &best_mv, rct, mbmi->ref_frame, pbi->common.ref_frame_sign_bias);
-
-        vp8_mv_ref_probs(mv_ref_p, rct);
+        else
+        {
+            mbmi->mode = read_mv_ref(bc, mv_ref_p);
+        }
+#else
+        mbmi->mode = read_mv_ref(bc, mv_ref_p);
+#endif
 
         mbmi->uv_mode = DC_PRED;
-        switch (mbmi->mode = read_mv_ref(bc, mv_ref_p))
+        switch (mbmi->mode)
         {
         case SPLITMV:
         {
@@ -530,6 +583,10 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi,
     }
     else
     {
+#if CONFIG_SEGFEATURES
+        // TBD HANDLE INTRA MODE CASE
+#endif
+
         /* required for left and above block mv */
         mbmi->mv.as_int = 0;
 
@@ -554,6 +611,14 @@ void vp8_decode_mode_mvs(VP8D_COMP *pbi)
     MODE_INFO *mi = pbi->common.mi;
     int mb_row = -1;
 
+#if CONFIG_SEGFEATURES
+#if 0
+    FILE *statsfile;
+    statsfile = fopen("decsegmap.stt", "a");
+    fprintf(statsfile, "\n" );
+#endif
+#endif
+
     mb_mode_mv_init(pbi);
 
 #if CONFIG_QIMODE
@@ -577,6 +642,12 @@ void vp8_decode_mode_mvs(VP8D_COMP *pbi)
         mb_to_bottom_edge = ((pbi->common.mb_rows - 1 - mb_row) * 16) << 3;
         mb_to_bottom_edge += RIGHT_BOTTOM_MARGIN;
 
+#if CONFIG_SEGFEATURES
+#if 0
+        fprintf(statsfile, "\n" );
+#endif
+#endif
+
         while (++mb_col < pbi->common.mb_cols)
         {
 #if CONFIG_ERROR_CONCEALMENT
@@ -617,9 +688,23 @@ void vp8_decode_mode_mvs(VP8D_COMP *pbi)
             }
 #endif
 
+#if CONFIG_SEGFEATURES
+#if 0
+            fprintf(statsfile, "%2d%2d%2d   ",
+                mi->mbmi.segment_id, mi->mbmi.ref_frame, mi->mbmi.mode );
+#endif
+#endif
+
             mi++;       /* next macroblock */
         }
        // printf("\n");
         mi++;           /* skip left predictor each row */
     }
+
+#if CONFIG_SEGFEATURES
+#if 0
+    fclose(statsfile);
+#endif
+#endif
+
 }
diff --git a/vp8/encoder/bitstream.c b/vp8/encoder/bitstream.c
index df7aee9de5..8015269cf1 100644
--- a/vp8/encoder/bitstream.c
+++ b/vp8/encoder/bitstream.c
@@ -896,7 +896,13 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi)
     cpi->mb.partition_info = cpi->mb.pi;
 
     // Calculate the probabilities to be used to code the reference frame based on actual useage this frame
-    if (!(cpi->prob_intra_coded = rf_intra * 255 / (rf_intra + rf_inter)))
+#if CONFIG_SEGFEATURES
+    cpi->prob_intra_coded = (rf_intra + rf_inter)
+                            ? rf_intra * 255 / (rf_intra + rf_inter) : 1;
+#else
+    cpi->prob_intra_coded = rf_intra * 255 / (rf_intra + rf_inter);
+#endif
+    if (!cpi->prob_intra_coded)
         cpi->prob_intra_coded = 1;
 
     prob_last_coded = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128;
@@ -1010,7 +1016,15 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi)
 
             if (rf == INTRA_FRAME)
             {
-                vp8_write(w, 0, cpi->prob_intra_coded);
+#if CONFIG_SEGFEATURES
+                // Is the segment coding of reference frame enabled
+                if ( !( xd->segment_feature_mask[mi->segment_id] &
+                        (0x01 << SEG_LVL_REF_FRAME) ) )
+#endif
+                {
+                    vp8_write(w, 0, cpi->prob_intra_coded);
+                }
+
 #ifdef ENTROPY_STATS
                 active_section = 6;
 #endif
@@ -1032,14 +1046,22 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi)
                 int_mv best_mv;
                 vp8_prob mv_ref_p [VP8_MVREFS-1];
 
-                vp8_write(w, 1, cpi->prob_intra_coded);
-
-                if (rf == LAST_FRAME)
-                    vp8_write(w, 0, prob_last_coded);
-                else
+#if CONFIG_SEGFEATURES
+                // Is the segment coding of reference frame enabled
+                if ( !( xd->segment_feature_mask[mi->segment_id] &
+                        (0x01 << SEG_LVL_REF_FRAME) ) )
+#endif
                 {
-                    vp8_write(w, 1, prob_last_coded);
-                    vp8_write(w, (rf == GOLDEN_FRAME) ? 0 : 1, prob_gf_coded);
+                    vp8_write(w, 1, cpi->prob_intra_coded);
+
+                    if (rf == LAST_FRAME)
+                        vp8_write(w, 0, prob_last_coded);
+                    else
+                    {
+                        vp8_write(w, 1, prob_last_coded);
+                        vp8_write(w, (rf == GOLDEN_FRAME)
+                                     ? 0 : 1, prob_gf_coded);
+                    }
                 }
 
                 {
@@ -1052,73 +1074,79 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi)
 #ifdef ENTROPY_STATS
                     accum_mv_refs(mode, ct);
 #endif
-
                 }
 
 #ifdef ENTROPY_STATS
                 active_section = 3;
 #endif
 
-                write_mv_ref(w, mode, mv_ref_p);
-
-                switch (mode)   /* new, split require MVs */
-                {
-                case NEWMV:
-
-#ifdef ENTROPY_STATS
-                    active_section = 5;
+#if CONFIG_SEGFEATURES
+                // Is the segment coding of reference frame enabled
+                if ( !( xd->segment_feature_mask[mi->segment_id] &
+                        (0x01 << SEG_LVL_MODE) ) )
 #endif
-
-                    write_mv(w, &mi->mv.as_mv, &best_mv, mvc);
-                    break;
-
-                case SPLITMV:
                 {
-                    int j = 0;
+                    write_mv_ref(w, mode, mv_ref_p);
 
-#ifdef MODE_STATS
-                    ++count_mb_seg [mi->partitioning];
-#endif
+                    switch (mode)   /* new, split require MVs */
+                    {
+                    case NEWMV:
 
-                    write_split(w, mi->partitioning);
+    #ifdef ENTROPY_STATS
+                        active_section = 5;
+    #endif
 
-                    do
+                        write_mv(w, &mi->mv.as_mv, &best_mv, mvc);
+                        break;
+
+                    case SPLITMV:
                     {
-                        B_PREDICTION_MODE blockmode;
-                        int_mv blockmv;
-                        const int *const  L = vp8_mbsplits [mi->partitioning];
-                        int k = -1;  /* first block in subset j */
-                        int mv_contz;
-                        int_mv leftmv, abovemv;
-
-                        blockmode =  cpi->mb.partition_info->bmi[j].mode;
-                        blockmv =  cpi->mb.partition_info->bmi[j].mv;
-#if CONFIG_DEBUG
-                        while (j != L[++k])
-                            if (k >= 16)
-                                assert(0);
-#else
-                        while (j != L[++k]);
-#endif
-                        leftmv.as_int = left_block_mv(m, k);
-                        abovemv.as_int = above_block_mv(m, k, mis);
-                        mv_contz = vp8_mv_cont(&leftmv, &abovemv);
+                        int j = 0;
+
+    #ifdef MODE_STATS
+                        ++count_mb_seg [mi->partitioning];
+    #endif
 
-                        write_sub_mv_ref(w, blockmode, vp8_sub_mv_ref_prob2 [mv_contz]);
+                        write_split(w, mi->partitioning);
 
-                        if (blockmode == NEW4X4)
+                        do
                         {
-#ifdef ENTROPY_STATS
-                            active_section = 11;
-#endif
-                            write_mv(w, &blockmv.as_mv, &best_mv, (const MV_CONTEXT *) mvc);
+                            B_PREDICTION_MODE blockmode;
+                            int_mv blockmv;
+                            const int *const  L = vp8_mbsplits [mi->partitioning];
+                            int k = -1;  /* first block in subset j */
+                            int mv_contz;
+                            int_mv leftmv, abovemv;
+
+                            blockmode =  cpi->mb.partition_info->bmi[j].mode;
+                            blockmv =  cpi->mb.partition_info->bmi[j].mv;
+    #if CONFIG_DEBUG
+                            while (j != L[++k])
+                                if (k >= 16)
+                                    assert(0);
+    #else
+                            while (j != L[++k]);
+    #endif
+                            leftmv.as_int = left_block_mv(m, k);
+                            abovemv.as_int = above_block_mv(m, k, mis);
+                            mv_contz = vp8_mv_cont(&leftmv, &abovemv);
+
+                            write_sub_mv_ref(w, blockmode, vp8_sub_mv_ref_prob2 [mv_contz]);
+
+                            if (blockmode == NEW4X4)
+                            {
+    #ifdef ENTROPY_STATS
+                                active_section = 11;
+    #endif
+                                write_mv(w, &blockmv.as_mv, &best_mv, (const MV_CONTEXT *) mvc);
+                            }
                         }
+                        while (++j < cpi->mb.partition_info->count);
                     }
-                    while (++j < cpi->mb.partition_info->count);
-                }
-                break;
-                default:
                     break;
+                    default:
+                        break;
+                    }
                 }
             }
 
@@ -1448,7 +1476,13 @@ int vp8_estimate_entropy_savings(VP8_COMP *cpi)
 
     if (cpi->common.frame_type != KEY_FRAME)
     {
-        if (!(new_intra = rf_intra * 255 / (rf_intra + rf_inter)))
+#if CONFIG_SEGFEATURES
+        new_intra = (rf_intra + rf_inter)
+                    ? rf_intra * 255 / (rf_intra + rf_inter) : 1;
+#else
+        new_intra = rf_intra * 255 / (rf_intra + rf_inter);
+#endif
+        if (!new_intra)
             new_intra = 1;
 
         new_last = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128;
diff --git a/vp8/encoder/encodeframe.c b/vp8/encoder/encodeframe.c
index d1cb0acabd..60567b1434 100644
--- a/vp8/encoder/encodeframe.c
+++ b/vp8/encoder/encodeframe.c
@@ -717,27 +717,51 @@ void encode_mb_row(VP8_COMP *cpi,
             if ((xd->mode_info_context->mbmi.mode == ZEROMV) && (xd->mode_info_context->mbmi.ref_frame == LAST_FRAME))
                 cpi->inter_zz_count ++;
 
-            // Special case code for cyclic refresh
-            // If cyclic update enabled then copy xd->mbmi.segment_id; (which may have been updated based on mode
-            // during vp8cx_encode_inter_macroblock()) back into the global sgmentation map
-            if (cpi->cyclic_refresh_mode_enabled && xd->segmentation_enabled)
+            // Actions required if segmentation enabled
+            if ( xd->segmentation_enabled )
             {
-                cpi->segmentation_map[map_index+mb_col] = xd->mode_info_context->mbmi.segment_id;
-
-                // If the block has been refreshed mark it as clean (the magnitude of the -ve influences how long it will be before we consider another refresh):
-                // Else if it was coded (last frame 0,0) and has not already been refreshed then mark it as a candidate for cleanup next time (marked 0)
-                // else mark it as dirty (1).
-                if (xd->mode_info_context->mbmi.segment_id)
-                    cpi->cyclic_refresh_map[map_index+mb_col] = -1;
-                else if ((xd->mode_info_context->mbmi.mode == ZEROMV) && (xd->mode_info_context->mbmi.ref_frame == LAST_FRAME))
+                // Special case code for cyclic refresh
+                // If cyclic update enabled then copy xd->mbmi.segment_id;
+                // (which may have been updated based on mode during
+                // vp8cx_encode_inter_macroblock()) back into the global
+                // segmentation map
+                if (cpi->cyclic_refresh_mode_enabled)
                 {
-                    if (cpi->cyclic_refresh_map[map_index+mb_col] == 1)
-                        cpi->cyclic_refresh_map[map_index+mb_col] = 0;
+                    cpi->segmentation_map[map_index+mb_col] =
+                        xd->mode_info_context->mbmi.segment_id;
+
+                    // If the block has been refreshed mark it as clean (the
+                    // magnitude of the -ve influences how long it will be
+                    // before we consider another refresh):
+                    // Else if it was coded (last frame 0,0) and has not
+                    // already been refreshed then mark it as a candidate
+                    // for cleanup next time (marked 0)
+                    // else mark it as dirty (1).
+                    if (xd->mode_info_context->mbmi.segment_id)
+                        cpi->cyclic_refresh_map[map_index+mb_col] = -1;
+
+                    else if ((xd->mode_info_context->mbmi.mode == ZEROMV) &&
+                             (xd->mode_info_context->mbmi.ref_frame ==
+                              LAST_FRAME))
+                    {
+                        if (cpi->cyclic_refresh_map[map_index+mb_col] == 1)
+                            cpi->cyclic_refresh_map[map_index+mb_col] = 0;
+                    }
+                    else
+                        cpi->cyclic_refresh_map[map_index+mb_col] = 1;
                 }
-                else
-                    cpi->cyclic_refresh_map[map_index+mb_col] = 1;
-
+#if CONFIG_SEGFEATURES
+                else if ( cm->refresh_alt_ref_frame &&
+                         (cm->frame_type != KEY_FRAME) )
+                {
+                    // Update the global segmentation map to reflect
+                    // the segment choice made for this MB.
+                    cpi->segmentation_map[map_index+mb_col] =
+                        xd->mode_info_context->mbmi.segment_id;
+                }
+#endif
             }
+
         }
 
         cpi->tplist[mb_row].stop = *tp;
@@ -828,7 +852,44 @@ void encode_mb_row(VP8_COMP *cpi,
         sem_post(&cpi->h_event_end_encoding); /* signal frame encoding end */
     }
 #endif
+
+
+#if CONFIG_SEGFEATURES
+// debug output
+#if 0
+    {
+        FILE *statsfile;
+        statsfile = fopen("segmap2.stt", "a");
+        fprintf(statsfile, "\n" );
+        fclose(statsfile);
+    }
+#endif
+#endif
+}
+
+#if CONFIG_SEGFEATURES
+// Funtion to test out new segment features
+void segfeature_test_function(VP8_COMP *cpi, MACROBLOCKD * xd)
+{
+    VP8_COMMON *const cm = & cpi->common;
+
+    // Only update segment map for a frame that is an arf but not a kf.
+    if ( cm->refresh_alt_ref_frame && (cm->frame_type != KEY_FRAME) )
+    {
+        // Test code to code features at the segment level
+        if ( (xd->mode_info_context->mbmi.mode ==
+                 cpi->segment_feature_data[1][SEG_LVL_MODE]) &&
+             (xd->mode_info_context->mbmi.ref_frame ==
+                 cpi->segment_feature_data[1][SEG_LVL_REF_FRAME]) )
+        {
+            xd->mode_info_context->mbmi.segment_id = 1;
+        }
+        else
+            xd->mode_info_context->mbmi.segment_id = 0;
+    }
 }
+#endif
+
 
 void init_encode_frame_mb_context(VP8_COMP *cpi)
 {
@@ -927,6 +988,7 @@ void vp8_encode_frame(VP8_COMP *cpi)
     MACROBLOCKD *const xd = & x->e_mbd;
 
     TOKENEXTRA *tp = cpi->tok;
+
 #if CONFIG_SEGMENTATION
     int segment_counts[MAX_MB_SEGMENTS + SEEK_SEGID];
     int prob[3];
@@ -936,6 +998,19 @@ void vp8_encode_frame(VP8_COMP *cpi)
 #endif
     int totalrate;
 
+
+#if CONFIG_SEGFEATURES
+// debug output
+#if 0
+    {
+        FILE *statsfile;
+        statsfile = fopen("segmap2.stt", "a");
+        fprintf(statsfile, "\n" );
+        fclose(statsfile);
+    }
+#endif
+#endif
+
     vpx_memset(segment_counts, 0, sizeof(segment_counts));
     totalrate = 0;
 
@@ -1307,8 +1382,16 @@ void vp8_encode_frame(VP8_COMP *cpi)
                     cpi->prob_gf_coded = 1;
             }
         }
+#if CONFIG_SEGFEATURES
+        else
+        {
+            // Trap case where cpi->count_mb_ref_frame_usage[] blank.
+            cpi->prob_intra_coded = 63;
+            cpi->prob_last_coded  = 128;
+            cpi->prob_gf_coded    = 128;
+        }
+#endif
     }
-
 #if 0
     // Keep record of the total distortion this time around for future use
     cpi->last_frame_distortion = cpi->frame_distortion;
@@ -1599,8 +1682,9 @@ int vp8cx_encode_inter_macroblock
         if (cpi->cyclic_refresh_mode_enabled)
         {
             // Clear segment_id back to 0 if not coded (last frame 0,0)
-            if ((xd->mode_info_context->mbmi.segment_id == 1) &&
-                ((xd->mode_info_context->mbmi.ref_frame != LAST_FRAME) || (xd->mode_info_context->mbmi.mode != ZEROMV)))
+            if ( (xd->mode_info_context->mbmi.segment_id == 1) &&
+                 ( (xd->mode_info_context->mbmi.ref_frame != LAST_FRAME) ||
+                   (xd->mode_info_context->mbmi.mode != ZEROMV) ) )
             {
                 xd->mode_info_context->mbmi.segment_id = 0;
 
@@ -1608,6 +1692,26 @@ int vp8cx_encode_inter_macroblock
                 vp8cx_mb_init_quantizer(cpi, x);
             }
         }
+#if CONFIG_SEGFEATURES
+        else
+        {
+            segfeature_test_function(cpi, xd);
+#if 0
+            // Debug output
+            {
+                FILE *statsfile;
+                statsfile = fopen("segmap2.stt", "a");
+
+                fprintf(statsfile, "%2d%2d%2d   ",
+                    xd->mode_info_context->mbmi.segment_id,
+                    xd->mode_info_context->mbmi.ref_frame,
+                    xd->mode_info_context->mbmi.mode );
+
+                fclose(statsfile);
+            }
+#endif
+        }
+#endif
     }
 
     {
@@ -1638,7 +1742,15 @@ int vp8cx_encode_inter_macroblock
             vp8_update_zbin_extra(cpi, x);
     }
 
+#if 0
+//#if CONFIG_SEGFEATURES
+    // Test code using segment 1 only.
+    // Dont increment count if ref frame coded at segment level
+    if ( (xd->mode_info_context->mbmi.segment_id != 1) )
+        cpi->count_mb_ref_frame_usage[xd->mode_info_context->mbmi.ref_frame]++;
+#else
     cpi->count_mb_ref_frame_usage[xd->mode_info_context->mbmi.ref_frame] ++;
+#endif
 
 #if CONFIG_T8X8
     if (xd->segmentation_enabled)
diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c
index 62df2e228c..ce2be25a11 100644
--- a/vp8/encoder/onyx_if.c
+++ b/vp8/encoder/onyx_if.c
@@ -434,14 +434,6 @@ static void set_segmentation_map(VP8_PTR ptr, unsigned char *segmentation_map)
     cpi->mb.e_mbd.update_mb_segmentation_data = 1;
 }
 
-// The values given for each segment can be either deltas (from the default value chosen for the frame) or absolute values.
-//
-// Valid range for abs values is (0-127 for SEG_LVL_ALT_Q) , (0-63 for SEGMENT_ALT_LF)
-// Valid range for delta values are (+/-127 for SEG_LVL_ALT_Q) , (+/-63 for SEGMENT_ALT_LF)
-//
-// abs_delta = SEGMENT_DELTADATA (deltas) abs_delta = SEGMENT_ABSDATA (use the absolute values given).
-//
-//
 static void set_segment_data(VP8_PTR ptr, signed char *feature_data, unsigned char abs_delta)
 {
     VP8_COMP *cpi = (VP8_COMP *)(ptr);
@@ -514,6 +506,99 @@ static void segmentation_test_function(VP8_PTR ptr)
 
 }
 
+#if CONFIG_SEGFEATURES
+static void init_seg_features(VP8_COMP *cpi)
+{
+    VP8_COMMON *cm = &cpi->common;
+    MACROBLOCKD *mbd = &cpi->mb.e_mbd;
+
+    // For now at least dont enable seg features alongside cyclic refresh.
+    if (cpi->cyclic_refresh_mode_enabled)
+        return;
+
+    // No updates for key frames
+    if ( cm->frame_type == KEY_FRAME )
+    {
+        cpi->mb.e_mbd.update_mb_segmentation_map = 0;
+        cpi->mb.e_mbd.update_mb_segmentation_data = 0;
+    }
+    // Arf but not a key frame.
+    else if ( cm->refresh_alt_ref_frame )
+    {
+        // Clear down the global segmentation map
+        vpx_memset( cpi->segmentation_map, 0, (cm->mb_rows * cm->mb_cols));
+
+        // Activate segmentation.
+        enable_segmentation((VP8_PTR)cpi);
+
+        // For now set GF, (0,0) MV in segment 1
+        cpi->segment_feature_data[1][SEG_LVL_REF_FRAME] = LAST_FRAME;
+        cpi->segment_feature_data[1][SEG_LVL_MODE] = ZEROMV;
+
+        mbd->segment_feature_data[1][SEG_LVL_REF_FRAME] = LAST_FRAME;
+        mbd->segment_feature_data[1][SEG_LVL_MODE] = ZEROMV;
+
+        // Enable target features is the segment feature mask
+        mbd->segment_feature_mask[1] |= (0x01 << SEG_LVL_REF_FRAME);
+        mbd->segment_feature_mask[1] |= (0x01 << SEG_LVL_MODE);
+    }
+    else
+    {
+        // Special case where we are coding over the top of a previous
+        // alt ref frame
+        if ( cpi->is_src_frame_alt_ref )
+        {
+            if ( cpi->source_alt_ref_pending )
+            {
+                cpi->mb.e_mbd.update_mb_segmentation_data = 1;
+                cpi->segment_feature_data[1][SEG_LVL_REF_FRAME] = ALTREF_FRAME;
+                mbd->segment_feature_data[1][SEG_LVL_REF_FRAME] = ALTREF_FRAME;
+            }
+            else
+            {
+                vpx_memset( cpi->segmentation_map, 0,
+                            (cm->mb_rows * cm->mb_cols));
+                cpi->mb.e_mbd.update_mb_segmentation_map = 1;
+                cpi->mb.e_mbd.update_mb_segmentation_data = 1;
+            }
+        }
+        else
+        {
+            cpi->mb.e_mbd.update_mb_segmentation_data = 0;
+        }
+    }
+}
+
+// DEBUG: Print out the segment id of each MB in the current frame.
+static void print_seg_map(VP8_COMP *cpi)
+{
+    VP8_COMMON *cm = & cpi->common;
+    int row,col;
+    int map_index = 0;
+    FILE *statsfile;
+
+    statsfile = fopen("segmap.stt", "a");
+
+    fprintf(statsfile, "%10d\n",
+            cm->current_video_frame );
+
+    for ( row = 0; row < cpi->common.mb_rows; row++ )
+    {
+        for ( col = 0; col < cpi->common.mb_cols; col++ )
+        {
+            fprintf(statsfile, "%10d",
+                    cpi->segmentation_map[map_index]);
+            map_index++;
+        }
+        fprintf(statsfile, "\n");
+    }
+    fprintf(statsfile, "\n");
+
+    fclose(statsfile);
+}
+
+#endif
+
 // A simple function to cyclically refresh the background at a lower Q
 static void cyclic_background_refresh(VP8_COMP *cpi, int Q, int lf_adjustment)
 {
@@ -3401,13 +3486,6 @@ static void encode_frame_to_data_rate
     // Clear down mmx registers to allow floating point in what follows
     vp8_clear_system_state();
 
-    // Test code for segmentation of gf/arf (0,0)
-    //segmentation_test_function((VP8_PTR) cpi);
-#if CONFIG_SEGMENTATION
-    cpi->mb.e_mbd.segmentation_enabled = 1;
-    cpi->mb.e_mbd.update_mb_segmentation_map = 1;
-#endif
-
     if (cpi->compressor_speed == 2)
     {
         if(cpi->oxcf.auto_key && cm->frame_type != KEY_FRAME)
@@ -3472,9 +3550,23 @@ static void encode_frame_to_data_rate
         cm->frame_type = KEY_FRAME;
     }
 
-    // Set default state for segment and mode based loop filter update flags
-    cpi->mb.e_mbd.update_mb_segmentation_map = 0;
-    cpi->mb.e_mbd.update_mb_segmentation_data = 0;
+    // Test code for segmentation of gf/arf (0,0)
+    //segmentation_test_function((VP8_PTR) cpi);
+#if CONFIG_SEGMENTATION
+    cpi->mb.e_mbd.segmentation_enabled = 1;
+    cpi->mb.e_mbd.update_mb_segmentation_map = 1;
+#else
+    #if CONFIG_SEGFEATURES
+        // Test code for new segment features
+        init_seg_features( cpi );
+    #else
+        // Set default state for segment update flags
+        cpi->mb.e_mbd.update_mb_segmentation_map = 0;
+        cpi->mb.e_mbd.update_mb_segmentation_data = 0;
+    #endif
+#endif
+
+    // Set default state for segment based loop filter update flags
     cpi->mb.e_mbd.mode_ref_lf_delta_update = 0;
 
     // Set various flags etc to special state if it is a key frame
@@ -4533,6 +4625,13 @@ static void encode_frame_to_data_rate
         }
     }
 
+#endif
+
+#if CONFIG_SEGFEATURES
+#if 0
+    // Debug stats for segment feature experiments.
+    print_seg_map(cpi);
+#endif
 #endif
 
     // If this was a kf or Gf note the Q
diff --git a/vp8/encoder/pickinter.c b/vp8/encoder/pickinter.c
index bfac3fa8f6..9562f266a6 100644
--- a/vp8/encoder/pickinter.c
+++ b/vp8/encoder/pickinter.c
@@ -409,6 +409,7 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
     BLOCKD *d = &x->e_mbd.block[0];
     MACROBLOCKD *xd = &x->e_mbd;
     MB_MODE_INFO best_mbmode;
+    VP8_COMMON *cm = & cpi->common;
 
     int_mv best_ref_mv;
     int_mv mode_mv[MB_MODE_COUNT];
@@ -514,6 +515,38 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
         if (skip_mode[x->e_mbd.mode_info_context->mbmi.ref_frame])
             continue;
 
+#if CONFIG_SEGFEATURES
+        // Experimental use of Segment features.
+        if ( !cm->refresh_alt_ref_frame )
+        {
+            unsigned char segment_id = xd->mode_info_context->mbmi.segment_id;
+            int feature_mask = xd->segment_feature_mask[segment_id];
+
+            if ( (feature_mask & (0x01 << SEG_LVL_REF_FRAME)) &&
+                 ( x->e_mbd.mode_info_context->mbmi.ref_frame !=
+                   cpi->segment_feature_data[segment_id][SEG_LVL_REF_FRAME]))
+            {
+                continue;
+            }
+
+            if ( (feature_mask & (0x01 << SEG_LVL_MODE)) &&
+                 ( this_mode !=
+                   cpi->segment_feature_data[segment_id][SEG_LVL_MODE]))
+            {
+                continue;
+            }
+        }
+#else
+        // Only consider ZEROMV/ALTREF_FRAME for alt ref frame,
+        // unless ARNR filtering is enabled in which case we want
+        // an unfiltered alternative
+        if (cpi->is_src_frame_alt_ref && (cpi->oxcf.arnr_max_frames == 0))
+        {
+            if (this_mode != ZEROMV ||
+                x->e_mbd.mode_info_context->mbmi.ref_frame != ALTREF_FRAME)
+                continue;
+        }
+
         // Check to see if the testing frequency for this mode is at its max
         // If so then prevent it from being tested and increase the threshold for its testing
         if (cpi->mode_test_hit_counts[mode_index] && (cpi->mode_check_freq[mode_index] > 1))
@@ -532,6 +565,7 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
                 continue;
             }
         }
+#endif
 
         // We have now reached the point where we are going to test the current mode so increment the counter for the number of times it has been tested
         cpi->mode_test_hit_counts[mode_index] ++;
@@ -564,6 +598,7 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
             memcpy(mdcounts, MDCounts[x->e_mbd.mode_info_context->mbmi.ref_frame], sizeof(mdcounts));
         }
 
+#if !CONFIG_SEGFEATURES
         // Only consider ZEROMV/ALTREF_FRAME for alt ref frame,
         // unless ARNR filtering is enabled in which case we want
         // an unfiltered alternative
@@ -572,6 +607,7 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
             if (this_mode != ZEROMV || x->e_mbd.mode_info_context->mbmi.ref_frame != ALTREF_FRAME)
                 continue;
         }
+#endif
 
         switch (this_mode)
         {
diff --git a/vp8/encoder/rdopt.c b/vp8/encoder/rdopt.c
index c24bf60ea2..e29f65b739 100644
--- a/vp8/encoder/rdopt.c
+++ b/vp8/encoder/rdopt.c
@@ -1993,6 +1993,7 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int
     BLOCK *b = &x->block[0];
     BLOCKD *d = &x->e_mbd.block[0];
     MACROBLOCKD *xd = &x->e_mbd;
+    VP8_COMMON *cm = &cpi->common;
     union b_mode_info best_bmodes[16];
     MB_MODE_INFO best_mbmode;
     PARTITION_INFO best_partition;
@@ -2119,14 +2120,38 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int
         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];
 
+#if CONFIG_SEGFEATURES
+        // Experimental use of Segment features.
+        if ( !cm->refresh_alt_ref_frame )
+        {
+            unsigned char segment_id = xd->mode_info_context->mbmi.segment_id;
+            int feature_mask = xd->segment_feature_mask[segment_id];
+
+            if ( (feature_mask & (0x01 << SEG_LVL_REF_FRAME)) &&
+                 ( x->e_mbd.mode_info_context->mbmi.ref_frame !=
+                   cpi->segment_feature_data[segment_id][SEG_LVL_REF_FRAME]))
+            {
+                continue;
+            }
+
+            if ( (feature_mask & (0x01 << SEG_LVL_MODE)) &&
+                 ( this_mode !=
+                   cpi->segment_feature_data[segment_id][SEG_LVL_MODE]))
+            {
+                continue;
+            }
+        }
+#else
         // Only consider ZEROMV/ALTREF_FRAME for alt ref frame,
         // unless ARNR filtering is enabled in which case we want
         // an unfiltered alternative
         if (cpi->is_src_frame_alt_ref && (cpi->oxcf.arnr_max_frames == 0))
         {
-            if (this_mode != ZEROMV || x->e_mbd.mode_info_context->mbmi.ref_frame != ALTREF_FRAME)
+            if (this_mode != ZEROMV ||
+                x->e_mbd.mode_info_context->mbmi.ref_frame != ALTREF_FRAME)
                 continue;
         }
+#endif
 
         /* everything but intra */
         if (x->e_mbd.mode_info_context->mbmi.ref_frame)
@@ -2141,6 +2166,7 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int
             lf_or_gf = frame_lf_or_gf[x->e_mbd.mode_info_context->mbmi.ref_frame];
         }
 
+#if !CONFIG_SEGFEATURES
         // Check to see if the testing frequency for this mode is at its max
         // If so then prevent it from being tested and increase the threshold for its testing
         if (cpi->mode_test_hit_counts[mode_index] && (cpi->mode_check_freq[mode_index] > 1))
@@ -2161,6 +2187,7 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int
 
         // We have now reached the point where we are going to test the current mode so increment the counter for the number of times it has been tested
         cpi->mode_test_hit_counts[mode_index] ++;
+#endif
 
         // Experimental code. Special case for gf and arf zeromv modes. Increase zbin size to supress noise
         if (cpi->zbin_mode_boost_enabled)
-- 
GitLab