ref: 156b221a7fd1d4eb1e49a005bf41cc1952d65cd8
parent: 45e49e6e197b236e1fef4c51c3d28da0d6d421b8
author: Paul Wilkins <paulwilkins@google.com>
date: Fri Sep 30 12:45:16 EDT 2011
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
--- a/vp8/decoder/decodemv.c
+++ b/vp8/decoder/decodemv.c
@@ -200,7 +200,44 @@
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)
{
const int i = vp8_treed_read(bc, vp8_mv_ref_tree, p);
@@ -296,8 +333,9 @@
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,8 +345,8 @@
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;
@@ -315,16 +353,16 @@
/* 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 @@
}
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 @@
}
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 @@
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];
}
+ else
+ {
+ mbmi->mode = read_mv_ref(bc, mv_ref_p);
+ }
+#else
+ mbmi->mode = read_mv_ref(bc, mv_ref_p);
+#endif
- 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);
-
mbmi->uv_mode = DC_PRED;
- switch (mbmi->mode = read_mv_ref(bc, mv_ref_p))
+ switch (mbmi->mode)
{
case SPLITMV:
{
@@ -530,6 +583,10 @@
}
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 @@
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 @@
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 @@
}
#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
+
}
--- a/vp8/encoder/bitstream.c
+++ b/vp8/encoder/bitstream.c
@@ -896,7 +896,13 @@
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 @@
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 @@
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,7 +1074,6 @@
#ifdef ENTROPY_STATS
accum_mv_refs(mode, ct);
#endif
-
}
#ifdef ENTROPY_STATS
@@ -1059,66 +1080,73 @@
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;
+ int j = 0;
- 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);
+ #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 @@
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;
--- a/vp8/encoder/encodeframe.c
+++ b/vp8/encoder/encodeframe.c
@@ -717,27 +717,51 @@
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;
+ // 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)
+ {
+ 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 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;
+ }
+#if CONFIG_SEGFEATURES
+ else if ( cm->refresh_alt_ref_frame &&
+ (cm->frame_type != KEY_FRAME) )
{
- if (cpi->cyclic_refresh_map[map_index+mb_col] == 1)
- cpi->cyclic_refresh_map[map_index+mb_col] = 0;
+ // 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;
}
- else
- cpi->cyclic_refresh_map[map_index+mb_col] = 1;
-
+#endif
}
+
}
cpi->tplist[mb_row].stop = *tp;
@@ -828,8 +852,45 @@
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)
{
MACROBLOCK *const x = & cpi->mb;
@@ -927,6 +988,7 @@
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 @@
#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 @@
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 @@
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 @@
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 @@
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)
--- a/vp8/encoder/onyx_if.c
+++ b/vp8/encoder/onyx_if.c
@@ -434,14 +434,6 @@
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 @@
}
+#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 @@
// 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 @@
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 @@
}
}
+#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
--- a/vp8/encoder/pickinter.c
+++ b/vp8/encoder/pickinter.c
@@ -409,6 +409,7 @@
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 @@
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 @@
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 @@
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 @@
if (this_mode != ZEROMV || x->e_mbd.mode_info_context->mbmi.ref_frame != ALTREF_FRAME)
continue;
}
+#endif
switch (this_mode)
{
--- a/vp8/encoder/rdopt.c
+++ b/vp8/encoder/rdopt.c
@@ -1993,6 +1993,7 @@
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 @@
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 @@
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 @@
// 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)
--
⑨