Commit 156b221a authored by Paul Wilkins's avatar Paul Wilkins

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
parent 45e49e6e
...@@ -200,6 +200,43 @@ static void read_mvcontexts(vp8_reader *bc, MV_CONTEXT *mvc) ...@@ -200,6 +200,43 @@ static void read_mvcontexts(vp8_reader *bc, MV_CONTEXT *mvc)
while (++i < 2); 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) 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, ...@@ -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; vp8_reader *const bc = & pbi->bc;
MV_CONTEXT *const mvc = pbi->common.fc.mvc; MV_CONTEXT *const mvc = pbi->common.fc.mvc;
const int mis = pbi->common.mode_info_stride; const int mis = pbi->common.mode_info_stride;
#if CONFIG_SEGMENTATION
MACROBLOCKD *const xd = & pbi->mb; MACROBLOCKD *const xd = & pbi->mb;
#if CONFIG_SEGMENTATION
int sum; int sum;
int index = mb_row * pbi->common.mb_cols + mb_col; int index = mb_row * pbi->common.mb_cols + mb_col;
#endif #endif
...@@ -307,24 +345,24 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, ...@@ -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_top_edge;
int mb_to_bottom_edge; int mb_to_bottom_edge;
mb_to_top_edge = pbi->mb.mb_to_top_edge; mb_to_top_edge = xd->mb_to_top_edge;
mb_to_bottom_edge = pbi->mb.mb_to_bottom_edge; mb_to_bottom_edge = xd->mb_to_bottom_edge;
mb_to_top_edge -= LEFT_TOP_MARGIN; mb_to_top_edge -= LEFT_TOP_MARGIN;
mb_to_bottom_edge += RIGHT_BOTTOM_MARGIN; mb_to_bottom_edge += RIGHT_BOTTOM_MARGIN;
mbmi->need_to_clamp_mvs = 0; mbmi->need_to_clamp_mvs = 0;
/* Distance of Mb to the various image edges. /* 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 * 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 = -((mb_col * 16) << 3);
mb_to_left_edge -= LEFT_TOP_MARGIN; 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 = ((pbi->common.mb_cols - 1 - mb_col) * 16) << 3;
mb_to_right_edge += RIGHT_BOTTOM_MARGIN; mb_to_right_edge += RIGHT_BOTTOM_MARGIN;
/* If required read in new segmentation data for this MB */ /* 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 CONFIG_SEGMENTATION
if (xd->temporal_update) if (xd->temporal_update)
...@@ -343,7 +381,7 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, ...@@ -343,7 +381,7 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi,
} }
else else
{ {
vp8_read_mb_features(bc, &mi->mbmi, &pbi->mb); vp8_read_mb_features(bc, &mi->mbmi, xd);
mbmi->segment_flag = 1; mbmi->segment_flag = 1;
pbi->segmentation_map[index] = mbmi->segment_id; 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, ...@@ -351,12 +389,12 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi,
} }
else 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; pbi->segmentation_map[index] = mbmi->segment_id;
} }
index++; index++;
#else #else
vp8_read_mb_features(bc, &mi->mbmi, &pbi->mb); vp8_read_mb_features(bc, &mi->mbmi, xd);
#endif #endif
} }
...@@ -367,23 +405,38 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, ...@@ -367,23 +405,38 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi,
else else
mbmi->mb_skip_coeff = 0; 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]; int rct[4];
vp8_prob mv_ref_p [VP8_MVREFS-1];
int_mv nearest, nearby, best_mv; 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
vp8_find_near_mvs(&pbi->mb, mi, &nearest, &nearby, &best_mv, rct, mbmi->ref_frame, pbi->common.ref_frame_sign_bias); {
mbmi->mode = read_mv_ref(bc, mv_ref_p);
vp8_mv_ref_probs(mv_ref_p, rct); }
#else
mbmi->mode = read_mv_ref(bc, mv_ref_p);
#endif
mbmi->uv_mode = DC_PRED; mbmi->uv_mode = DC_PRED;
switch (mbmi->mode = read_mv_ref(bc, mv_ref_p)) switch (mbmi->mode)
{ {
case SPLITMV: case SPLITMV:
{ {
...@@ -530,6 +583,10 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, ...@@ -530,6 +583,10 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi,
} }
else else
{ {
#if CONFIG_SEGFEATURES
// TBD HANDLE INTRA MODE CASE
#endif
/* required for left and above block mv */ /* required for left and above block mv */
mbmi->mv.as_int = 0; mbmi->mv.as_int = 0;
...@@ -554,6 +611,14 @@ void vp8_decode_mode_mvs(VP8D_COMP *pbi) ...@@ -554,6 +611,14 @@ void vp8_decode_mode_mvs(VP8D_COMP *pbi)
MODE_INFO *mi = pbi->common.mi; MODE_INFO *mi = pbi->common.mi;
int mb_row = -1; 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); mb_mode_mv_init(pbi);
#if CONFIG_QIMODE #if CONFIG_QIMODE
...@@ -577,6 +642,12 @@ void vp8_decode_mode_mvs(VP8D_COMP *pbi) ...@@ -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 = ((pbi->common.mb_rows - 1 - mb_row) * 16) << 3;
mb_to_bottom_edge += RIGHT_BOTTOM_MARGIN; mb_to_bottom_edge += RIGHT_BOTTOM_MARGIN;
#if CONFIG_SEGFEATURES
#if 0
fprintf(statsfile, "\n" );
#endif
#endif
while (++mb_col < pbi->common.mb_cols) while (++mb_col < pbi->common.mb_cols)
{ {
#if CONFIG_ERROR_CONCEALMENT #if CONFIG_ERROR_CONCEALMENT
...@@ -617,9 +688,23 @@ void vp8_decode_mode_mvs(VP8D_COMP *pbi) ...@@ -617,9 +688,23 @@ void vp8_decode_mode_mvs(VP8D_COMP *pbi)
} }
#endif #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 */ mi++; /* next macroblock */
} }
// printf("\n"); // printf("\n");
mi++; /* skip left predictor each row */ mi++; /* skip left predictor each row */
} }
#if CONFIG_SEGFEATURES
#if 0
fclose(statsfile);
#endif
#endif
} }
...@@ -896,7 +896,13 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi) ...@@ -896,7 +896,13 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi)
cpi->mb.partition_info = cpi->mb.pi; cpi->mb.partition_info = cpi->mb.pi;
// Calculate the probabilities to be used to code the reference frame based on actual useage this frame // 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; cpi->prob_intra_coded = 1;
prob_last_coded = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128; 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) ...@@ -1010,7 +1016,15 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi)
if (rf == INTRA_FRAME) 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 #ifdef ENTROPY_STATS
active_section = 6; active_section = 6;
#endif #endif
...@@ -1032,14 +1046,22 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi) ...@@ -1032,14 +1046,22 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi)
int_mv best_mv; int_mv best_mv;
vp8_prob mv_ref_p [VP8_MVREFS-1]; vp8_prob mv_ref_p [VP8_MVREFS-1];
vp8_write(w, 1, cpi->prob_intra_coded); #if CONFIG_SEGFEATURES
// Is the segment coding of reference frame enabled
if (rf == LAST_FRAME) if ( !( xd->segment_feature_mask[mi->segment_id] &
vp8_write(w, 0, prob_last_coded); (0x01 << SEG_LVL_REF_FRAME) ) )
else #endif
{ {
vp8_write(w, 1, prob_last_coded); vp8_write(w, 1, cpi->prob_intra_coded);
vp8_write(w, (rf == GOLDEN_FRAME) ? 0 : 1, prob_gf_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) ...@@ -1052,73 +1074,79 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi)
#ifdef ENTROPY_STATS #ifdef ENTROPY_STATS
accum_mv_refs(mode, ct); accum_mv_refs(mode, ct);
#endif #endif
} }
#ifdef ENTROPY_STATS #ifdef ENTROPY_STATS
active_section = 3; active_section = 3;
#endif #endif
write_mv_ref(w, mode, mv_ref_p); #if CONFIG_SEGFEATURES
// Is the segment coding of reference frame enabled
switch (mode) /* new, split require MVs */ if ( !( xd->segment_feature_mask[mi->segment_id] &
{ (0x01 << SEG_LVL_MODE) ) )
case NEWMV:
#ifdef ENTROPY_STATS
active_section = 5;
#endif #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 switch (mode) /* new, split require MVs */
++count_mb_seg [mi->partitioning]; {
#endif 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 j = 0;
int_mv blockmv;
const int *const L = vp8_mbsplits [mi->partitioning]; #ifdef MODE_STATS
int k = -1; /* first block in subset j */ ++count_mb_seg [mi->partitioning];
int mv_contz; #endif
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]); write_split(w, mi->partitioning);
if (blockmode == NEW4X4) do
{ {
#ifdef ENTROPY_STATS B_PREDICTION_MODE blockmode;
active_section = 11; int_mv blockmv;
#endif const int *const L = vp8_mbsplits [mi->partitioning];
write_mv(w, &blockmv.as_mv, &best_mv, (const MV_CONTEXT *) mvc); 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; break;
default:
break;
}
} }
} }
...@@ -1448,7 +1476,13 @@ int vp8_estimate_entropy_savings(VP8_COMP *cpi) ...@@ -1448,7 +1476,13 @@ int vp8_estimate_entropy_savings(VP8_COMP *cpi)
if (cpi->common.frame_type != KEY_FRAME) 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_intra = 1;
new_last = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128; new_last = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128;
......
...@@ -717,27 +717,51 @@ void encode_mb_row(VP8_COMP *cpi, ...@@ -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)) if ((xd->mode_info_context->mbmi.mode == ZEROMV) && (xd->mode_info_context->mbmi.ref_frame == LAST_FRAME))
cpi->inter_zz_count ++; cpi->inter_zz_count ++;
// Special case code for cyclic refresh // Actions required if segmentation enabled
// If cyclic update enabled then copy xd->mbmi.segment_id; (which may have been updated based on mode if ( xd->segmentation_enabled )
// during vp8cx_encode_inter_macroblock()) back into the global sgmentation map
if (cpi->cyclic_refresh_mode_enabled && 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;
// 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): // (which may have been updated based on mode during
// 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) // vp8cx_encode_inter_macroblock()) back into the global
// else mark it as dirty (1). // segmentation map
if (xd->mode_info_context->mbmi.segment_id) if (cpi->cyclic_refresh_mode_enabled)
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->segmentation_map[map_index+mb_col] =
cpi->cyclic_refresh_map[map_index+mb_col] = 0; 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 #if CONFIG_SEGFEATURES
cpi->cyclic_refresh_map[map_index+mb_col] = 1; 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; cpi->tplist[mb_row].stop = *tp;
...@@ -828,7 +852,44 @@ void encode_mb_row(VP8_COMP *cpi, ...@@ -828,7 +852,44 @@ void encode_mb_row(VP8_COMP *cpi,
sem_post(&cpi->h_event_end_encoding); /* signal frame encoding end */ sem_post(&cpi->h_event_end_encoding); /* signal frame encoding end */
} }
#endif #endif
#if CONFIG_SEGFEATURES
// debug output
#if 0
{
FILE *statsfile;
statsfile = fopen("segmap2.stt", "a");
fprintf(statsfile, "\n" );
fclose(statsfile);
}
#endif
#endif
}