Commit b9a18344 authored by Suman Sunkara's avatar Suman Sunkara
Browse files

Use of temporal context for encoding delta updates.

- Used three probability approach for temporal context as follows:
P0 - probability of no change if both above and left not changed
P1 - probability of no change if one of above and left has changed
P2 - probability of no change if both above and left have changed

In addition, a 1 bit/frame has been used to decide whether to use temporal context or to encode directly.  The cost of using both the schemes is calculated ahead and the temporal_update flag is set if the cost of using temporal context is lower than encoding the segment ids directly.

This approach has given around 20% reduction in cost of bits needed to encode segmentation ids.

Change-Id: I44a5509599eded215ae5be9554314280d3d35405
parent 00cec8f9
......@@ -172,6 +172,7 @@ typedef struct
int mb_skip_coeff; //does this mb has coefficients at all, 1=no coefficients, 0=need decode tokens
int dc_diff;
unsigned char segment_id; // Which set of segmentation parameters should be used for this MB
unsigned char segment_flag;
int force_no_skip;
B_MODE_INFO partition_bmi[16];
......@@ -253,6 +254,7 @@ typedef struct
// 0 (do not update) 1 (update) the macroblock segmentation feature data.
unsigned char mb_segement_abs_delta;
unsigned char temporal_update;
// Per frame flags that define which MB level features (such as quantizer or loop filter level)
// are enabled and when enabled the proabilities used to decode the per MB flags in MB_MODE_INFO
#if CONFIG_SEGMENTATION
......
......@@ -113,7 +113,7 @@ void vp8_decode_mode_mvs(VP8D_COMP *pbi)
VP8_COMMON *const pc = & pbi->common;
vp8_reader *const bc = & pbi->bc;
MACROBLOCKD *xd = &pbi->mb;
MODE_INFO *mi = pc->mi, *ms;
const int mis = pc->mode_info_stride;
......@@ -123,6 +123,8 @@ void vp8_decode_mode_mvs(VP8D_COMP *pbi)
#if CONFIG_SEGMENTATION
int left_id, above_id;
int i;
int sum;
int index = 0;
#endif
vp8_prob prob_intra;
vp8_prob prob_last;
......@@ -161,7 +163,9 @@ void vp8_decode_mode_mvs(VP8D_COMP *pbi)
}
read_mvcontexts(bc, mvc);
#if CONFIG_SEGMENTATION
xd->temporal_update = vp8_read_bit(bc);
#endif
while (++mb_row < pc->mb_rows)
{
int mb_col = -1;
......@@ -171,7 +175,7 @@ void vp8_decode_mode_mvs(VP8D_COMP *pbi)
MB_MODE_INFO *const mbmi = & mi->mbmi;
MV *const mv = & mbmi->mv.as_mv;
VP8_COMMON *const pc = &pbi->common;
MACROBLOCKD *xd = &pbi->mb;
// MACROBLOCKD *xd = &pbi->mb;
vp8dx_bool_decoder_fill(bc);
// Distance of Mb to the various image edges.
......@@ -185,69 +189,40 @@ void vp8_decode_mode_mvs(VP8D_COMP *pbi)
if (pbi->mb.update_mb_segmentation_map)
{
#if CONFIG_SEGMENTATION
xd->up_available = (mb_row != 0);
xd->left_available = (mb_col != 0);
int count = 0;
int j;
if(xd->left_available)
left_id = (mi-1)->mbmi.segment_id;
else
left_id = 0;
if (xd->temporal_update)
{
sum = 0;
if(xd->up_available)
above_id = (mi-pc->mb_cols)->mbmi.segment_id;
else
above_id = 0;
if (mb_col != 0)
sum += (mi-1)->mbmi.segment_flag;
if (mb_row != 0)
sum += (mi-pc->mb_cols)->mbmi.segment_flag;
if (vp8_read(bc, xd->mb_segment_tree_probs[0]))
{
for(i = 0; i < MAX_MB_SEGMENTS; i++)
if (vp8_read(bc, xd->mb_segment_tree_probs[3+sum]) == 0)
{
if((left_id != i) && (above_id != i))
{
if(left_id != above_id)
{
if (vp8_read(bc, xd->mb_segment_tree_probs[2+i]) == 0)
mbmi->segment_id = i;
else
mbmi->segment_id = 6-left_id-above_id-i;
break;
}
else
{
if (vp8_read(bc, xd->mb_segment_tree_probs[2+i]) == 0)
{
mbmi->segment_id = i;
break;
}
else
{
count++;
if(count == 1)
j = i;
if(count == 2)
{
mbmi->segment_id = 6-left_id-j-i;
break;
}
}
}
}
mbmi->segment_id = pbi->segmentation_map[index];
mbmi->segment_flag = 0;
}
else
{
vp8_read_mb_features(bc, &mi->mbmi, &pbi->mb);
mbmi->segment_flag = 1;
pbi->segmentation_map[index] = mbmi->segment_id;
}
}
else
{
if (vp8_read(bc, xd->mb_segment_tree_probs[1]))
mbmi->segment_id = above_id;
else
mbmi->segment_id = left_id;
vp8_read_mb_features(bc, &mi->mbmi, &pbi->mb);
pbi->segmentation_map[index] = mbmi->segment_id;
}
index++;
#else
vp8_read_mb_features(bc, &mi->mbmi, &pbi->mb);
#endif
}
// Read the macroblock coeff skip flag if this feature is in use, else default to 0
if (pc->mb_no_coeff_skip)
mbmi->mb_skip_coeff = vp8_read(bc, prob_skip_false);
......
......@@ -632,7 +632,6 @@ int vp8_decode_frame(VP8D_COMP *pbi)
// Is segmentation enabled
xd->segmentation_enabled = (unsigned char)vp8_read_bit(bc);
if (xd->segmentation_enabled)
{
// Signal whether or not the segmentation map is being explicitly updated this frame.
......@@ -794,7 +793,6 @@ int vp8_decode_frame(VP8D_COMP *pbi)
fclose(z);
}
vp8dx_bool_decoder_fill(bc);
{
// read coef probability tree
......@@ -818,6 +816,11 @@ int vp8_decode_frame(VP8D_COMP *pbi)
vpx_memcpy(&xd->pre, &pc->last_frame, sizeof(YV12_BUFFER_CONFIG));
vpx_memcpy(&xd->dst, &pc->new_frame, sizeof(YV12_BUFFER_CONFIG));
#if CONFIG_SEGMENTATION
// Create the encoder segmentation map and set all entries to 0
CHECK_MEM_ERROR(pbi->segmentation_map, vpx_calloc((pc->mb_rows * pc->mb_cols), 1));
#endif
// set up frame new frame for intra coded blocks
vp8_setup_intra_recon(&pc->new_frame);
......
......@@ -91,65 +91,8 @@ void vp8_kfread_modes(VP8D_COMP *pbi)
{
#if CONFIG_SEGMENTATION
MACROBLOCKD *xd = &pbi->mb;
xd->up_available = (mb_row != 0);
xd->left_available = (mb_col != 0);
int count = 0;
int j;
if(xd->left_available)
left_id = (m-1)->mbmi.segment_id;
else
left_id = 0;
if(xd->up_available)
above_id = (m-cp->mb_cols)->mbmi.segment_id;
else
above_id = 0;
if (vp8_read(bc, xd->mb_segment_tree_probs[0]))
{
for(i = 0; i < MAX_MB_SEGMENTS; i++)
{
if((left_id != i) && (above_id != i))
{
if(left_id != above_id)
{
if (vp8_read(bc, xd->mb_segment_tree_probs[2+i]) == 0)
m->mbmi.segment_id = i;
else
m->mbmi.segment_id = 6-left_id-above_id-i;
break;
}
else
{
if (vp8_read(bc, xd->mb_segment_tree_probs[2+i]) == 0)
{
m->mbmi.segment_id = i;
break;
}
else
{
count++;
if(count == 1)
j = i;
if(count == 2)
{
m->mbmi.segment_id = 6-left_id-j-i;
break;
}
}
}
}
}
}
else
{
if (vp8_read(bc, xd->mb_segment_tree_probs[1]))
m->mbmi.segment_id = above_id;
else
m->mbmi.segment_id = left_id;
}
vp8_read_mb_features(bc, &m->mbmi, &pbi->mb);
pbi->segmentation_map[(mb_row * cp->mb_cols) + mb_col] = m->mbmi.segment_id;
#else
vp8_read_mb_features(bc, &m->mbmi, &pbi->mb);
#endif
......
......@@ -137,7 +137,11 @@ void vp8dx_remove_decompressor(VP8D_PTR ptr)
if (!pbi)
return;
#if CONFIG_SEGMENTATION
// Delete sementation map
if (pbi->segmentation_map != 0)
vpx_free(pbi->segmentation_map);
#endif
vp8_decoder_remove_threads(pbi);
vp8_remove_common(&pbi->common);
vpx_free(pbi);
......
......@@ -81,7 +81,7 @@ typedef struct VP8Decompressor
const unsigned char *Source;
unsigned int source_sz;
unsigned char *segmentation_map;
unsigned int CPUFreq;
unsigned int decode_microseconds;
unsigned int time_decoding;
......
......@@ -862,9 +862,12 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi)
VP8_COMMON *const pc = & cpi->common;
vp8_writer *const w = & cpi->bc;
const MV_CONTEXT *mvc = pc->fc.mvc;
MACROBLOCKD *xd = &cpi->mb.e_mbd;
#if CONFIG_SEGMENTATION
int left_id, above_id;
int i;
int sum;
int index = 0;
#endif
const int *const rfct = cpi->count_mb_ref_frame_usage;
const int rf_intra = rfct[INTRA_FRAME];
......@@ -920,7 +923,9 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi)
update_mbintra_mode_probs(cpi);
vp8_write_mvprobs(cpi);
#if CONFIG_SEGMENTATION
vp8_write_bit(w, (xd->temporal_update) ? 1:0);
#endif
while (++mb_row < pc->mb_rows)
{
int mb_col = -1;
......@@ -931,7 +936,7 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi)
const MV_REFERENCE_FRAME rf = mi->ref_frame;
const MB_PREDICTION_MODE mode = mi->mode;
MACROBLOCKD *xd = &cpi->mb.e_mbd;
//MACROBLOCKD *xd = &cpi->mb.e_mbd;
// 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
......@@ -948,87 +953,37 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi)
if (cpi->mb.e_mbd.update_mb_segmentation_map)
{
#if CONFIG_SEGMENTATION
if(xd->left_available)
left_id = (m-1)->mbmi.segment_id;
else
left_id = 0;
if(xd->up_available)
above_id = (m-pc->mb_cols)->mbmi.segment_id;
else
above_id = 0;
if ((m->mbmi.segment_id == left_id) || (m->mbmi.segment_id == above_id))
if (xd->temporal_update)
{
vp8_write(w, 0, xd->mb_segment_tree_probs[0]);
segment_cost += vp8_cost_zero(xd->mb_segment_tree_probs[0]);
sum = 0;
if (mb_col != 0)
sum += (m-1)->mbmi.segment_flag;
if (mb_row != 0)
sum += (m-pc->mb_cols)->mbmi.segment_flag;
if (left_id != above_id)
if (m->mbmi.segment_flag == 0)
{
if(m->mbmi.segment_id == left_id)
{
vp8_write(w, 0, xd->mb_segment_tree_probs[1]);
segment_cost += vp8_cost_zero(xd->mb_segment_tree_probs[1]);
}
else
{
vp8_write(w, 1, xd->mb_segment_tree_probs[1]);
segment_cost += vp8_cost_one(xd->mb_segment_tree_probs[1]);
}
vp8_write(w,0,xd->mb_segment_tree_probs[3+sum]);
segment_cost += vp8_cost_zero(xd->mb_segment_tree_probs[3+sum]);
}
else
{
vp8_write(w, 0, xd->mb_segment_tree_probs[1]);
segment_cost += vp8_cost_zero(xd->mb_segment_tree_probs[1]);
vp8_write(w,1,xd->mb_segment_tree_probs[3+sum]);
segment_cost += vp8_cost_one(xd->mb_segment_tree_probs[3+sum]);
write_mb_features(w, mi, &cpi->mb.e_mbd);
cpi->segmentation_map[index] = mi->segment_id;
}
}
else
{
vp8_write(w, 1, xd->mb_segment_tree_probs[0]);
segment_cost += vp8_cost_one(xd->mb_segment_tree_probs[0]);
int count = 0;
for(i = 0; i < MAX_MB_SEGMENTS; i++)
{
if((left_id != i) && (above_id != i))
{
if(left_id != above_id)
{
if(m->mbmi.segment_id == i)
{
vp8_write(w, 0, xd->mb_segment_tree_probs[2+i]);
segment_cost += vp8_cost_zero(xd->mb_segment_tree_probs[2+i]);
}
else
{
vp8_write(w, 1, xd->mb_segment_tree_probs[2+i]);
segment_cost += vp8_cost_one(xd->mb_segment_tree_probs[2+i]);
}
break;
}
else
{
if(m->mbmi.segment_id == i)
{
vp8_write(w, 0, xd->mb_segment_tree_probs[2+i]);
segment_cost += vp8_cost_zero(xd->mb_segment_tree_probs[2+i]);
break;
}
else
{
count++;
vp8_write(w, 1, xd->mb_segment_tree_probs[2+i]);
segment_cost += vp8_cost_one(xd->mb_segment_tree_probs[2+i]);
if(count == 2)
break;
}
}
}
}
write_mb_features(w, mi, &cpi->mb.e_mbd);
cpi->segmentation_map[index] = mi->segment_id;
}
index++;
#else
write_mb_features(w, mi, &cpi->mb.e_mbd);
#endif
}
}
if (pc->mb_no_coeff_skip)
vp8_encode_bool(w, m->mbmi.mb_skip_coeff, prob_skip_false);
......@@ -1157,6 +1112,7 @@ static void write_kfmodes(VP8_COMP *cpi)
#if CONFIG_SEGMENTATION
int left_id, above_id;
int i;
int index = 0;
#endif
int mb_row = -1;
int prob_skip_false = 0;
......@@ -1190,85 +1146,12 @@ static void write_kfmodes(VP8_COMP *cpi)
if (cpi->mb.e_mbd.update_mb_segmentation_map)
{
#if CONFIG_SEGMENTATION
if(xd->left_available)
left_id = (m-1)->mbmi.segment_id;
else
left_id = 0;
if(xd->up_available)
above_id = (m-c->mb_cols)->mbmi.segment_id;
else
above_id = 0;
if ((m->mbmi.segment_id == left_id) || (m->mbmi.segment_id == above_id))
{
vp8_write(bc, 0, xd->mb_segment_tree_probs[0]);
segment_cost += vp8_cost_zero(xd->mb_segment_tree_probs[0]);
if (left_id != above_id)
{
if(m->mbmi.segment_id == left_id)
{
vp8_write(bc, 0, xd->mb_segment_tree_probs[1]);
segment_cost += vp8_cost_zero(xd->mb_segment_tree_probs[1]);
}
else
{
vp8_write(bc, 1, xd->mb_segment_tree_probs[1]);
segment_cost += vp8_cost_one(xd->mb_segment_tree_probs[1]);
}
}
else
{
vp8_write(bc, 0, xd->mb_segment_tree_probs[1]);
segment_cost += vp8_cost_zero(xd->mb_segment_tree_probs[1]);
}
}
else
{
vp8_write(bc, 1, xd->mb_segment_tree_probs[0]);
segment_cost += vp8_cost_one(xd->mb_segment_tree_probs[0]);
int count = 0;
for(i = 0; i < MAX_MB_SEGMENTS; i++)
{
if((left_id != i) && (above_id != i))
{
if(left_id != above_id)
{
if(m->mbmi.segment_id == i)
{
vp8_write(bc, 0, xd->mb_segment_tree_probs[2+i]);
segment_cost += vp8_cost_zero(xd->mb_segment_tree_probs[2+i]);
}
else
{
vp8_write(bc, 1, xd->mb_segment_tree_probs[2+i]);
segment_cost += vp8_cost_one(xd->mb_segment_tree_probs[2+i]);
}
break;
}
else
{
if(m->mbmi.segment_id == i)
{
vp8_write(bc, 0, xd->mb_segment_tree_probs[2+i]);
segment_cost += vp8_cost_zero(xd->mb_segment_tree_probs[2+i]);
break;
}
else
{
count++;
vp8_write(bc, 1, xd->mb_segment_tree_probs[2+i]);
segment_cost += vp8_cost_one(xd->mb_segment_tree_probs[2+i]);
if(count == 2)
break;
}
}
}
}
}
write_mb_features(bc, &m->mbmi, &cpi->mb.e_mbd);
cpi->segmentation_map[index] = m->mbmi.segment_id;
index++;
#else
write_mb_features(bc, &m->mbmi, &cpi->mb.e_mbd);
write_mb_features(bc, &m->mbmi, &cpi->mb.e_mbd);
#endif
}
......@@ -1587,10 +1470,9 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size)
}
else
vp8_start_encode(bc, cx_data);
#if CONFIG_SEGMENTATION
//xd->segmentation_enabled =1;
xd->update_mb_segmentation_map = 1;
#endif
xd->update_mb_segmentation_map = 1;
// Signal whether or not Segmentation is enabled
vp8_write_bit(bc, (xd->segmentation_enabled) ? 1 : 0);
......@@ -1810,7 +1692,7 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size)
#endif
}
#if CONFIG_SEGMENTATION
//printf("\nseg_cost is %d\n",segment_cost);
//printf("%d\n",segment_cost);
#endif
vp8_stop_encode(bc);
......
......@@ -29,6 +29,7 @@
#include "subpixel.h"
#include "vpx_ports/vpx_timer.h"
#if CONFIG_RUNTIME_CPU_DETECT
#define RTCD(x) &cpi->common.rtcd.x
#define IF_RTCD(x) (x)
......@@ -36,6 +37,13 @@
#define RTCD(x) NULL
#define IF_RTCD(x) NULL
#endif
#if CONFIG_SEGMENTATION
#define SEEK_SEGID 12
#define SEEK_SAMEID 4
#define SEEK_DIFFID 7
#endif
extern void vp8_stuff_mb(VP8_COMP *cpi, MACROBLOCKD *x, TOKENEXTRA **t) ;
extern void vp8cx_initialize_me_consts(VP8_COMP *cpi, int QIndex);
......@@ -260,6 +268,7 @@ void encode_mb_row(VP8_COMP *cpi,
int seg_map_index = (mb_row * cpi->common.mb_cols);
#if CONFIG_SEGMENTATION
int left_id, above_id;
int sum;
#endif
// reset above block coeffs
xd->above_context[Y1CONTEXT] = cm->above_context[Y1CONTEXT];
......@@ -370,6 +379,11 @@ void encode_mb_row(VP8_COMP *cpi,
xd->gf_active_ptr++; // Increment pointer into gf useage flags structure for next mb
if ((xd->mbmi.mode == ZEROMV) && (xd->mbmi.ref_frame == LAST_FRAME))
xd->mbmi.segment_id = 0;
else
xd->mbmi.segment_id = 1;
// store macroblock mode info into context array
vpx_memcpy(&xd->mode_info_context->mbmi, &xd->mbmi, sizeof(xd->mbmi));
......@@ -385,66 +399,40 @@ void encode_mb_row(VP8_COMP *cpi,
recon_uvoffset += 8;
#if CONFIG_SEGMENTATION
if(xd->left_available)
left_id = cpi->segmentation_map[seg_map_index+mb_col-1];
else
left_id = 0;
if(xd->up_available)
above_id = cpi->segmentation_map[seg_map_index+mb_col-cpi->common.mb_cols];
else
above_id = 0;
if ((xd->mbmi.segment_id == left_id) || (xd->mbmi.segment_id == above_id))
{
segment_counts[8]++;
if (left_id != above_id)
//cpi->segmentation_map[mb_row * cm->mb_cols + mb_col] = xd->mbmi.segment_id;
if (cm->frame_type == KEY_FRAME)
{
if(xd->mbmi.segment_id == left_id)
segment_counts[10]++;
else
segment_counts[11]++;
segment_counts[xd->mode_info_context->mbmi.segment_id] ++;
}
else
segment_counts[10]++;
}
else
{
segment_counts[9]++;
int count =0;
for(i = 0; i < MAX_MB_SEGMENTS; i++)
{
if((left_id != i) && (above_id != i))
sum = 0;
if (mb_col != 0)
sum += (xd->mode_info_context-1)->mbmi.segment_flag;
if (mb_row != 0)
sum += (xd->mode_info_context-cm->mb_cols)->mbmi.segment_flag;
if (xd->mbmi.segment_id == cpi->segmentation_map[(mb_row*cm->mb_cols) + mb_col])
xd->mode_info_context->mbmi.segment_flag = 0;
else
xd->mode_info_context->mbmi.segment_flag = 1;
if (xd->mode_info_context->mbmi.segment_flag == 0)