Segmentation Features;

Only encode sign bit for feature data that can have a sign.

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

Change-Id: I8e61f1aebf41c9037db7e67e2f8975aa18a0c986
This commit is contained in:
Paul Wilkins 2011-10-07 16:58:28 +01:00
parent 01ce04bc06
commit 23701f4f87
7 changed files with 217 additions and 62 deletions

View File

@ -10,6 +10,9 @@
#include "vp8/common/seg_common.h"
const int segfeaturedata_signed[SEG_LVL_MAX] = {1, 1, 0, 0, 0, 0};
// These functions provide access to new segment level features.
// Eventually these function may be "optimized out" but for the moment,
// the coding mechanism is still subject to change so these provide a
@ -25,6 +28,12 @@ int segfeature_active( MACROBLOCKD *xd,
(0x01 << feature_id) ) );
}
void clearall_segfeatures( MACROBLOCKD *xd )
{
vpx_memset(xd->segment_feature_data, 0, sizeof(xd->segment_feature_data));
vpx_memset(xd->segment_feature_mask, 0, sizeof(xd->segment_feature_mask));
}
void enable_segfeature( MACROBLOCKD *xd,
int segment_id,
SEG_LVL_FEATURES feature_id )
@ -38,4 +47,9 @@ void disable_segfeature( MACROBLOCKD *xd,
xd->segment_feature_mask[segment_id] &= ~(1 << feature_id);
}
int is_segfeature_signed( SEG_LVL_FEATURES feature_id )
{
return ( segfeaturedata_signed[feature_id] );
}
// TBD? Functions to read and write segment data with range / validity checking

View File

@ -18,6 +18,8 @@ int segfeature_active( MACROBLOCKD *xd,
int segment_id,
SEG_LVL_FEATURES feature_id );
void clearall_segfeatures( MACROBLOCKD *xd );
void enable_segfeature( MACROBLOCKD *xd,
int segment_id,
SEG_LVL_FEATURES feature_id );
@ -26,5 +28,7 @@ void disable_segfeature( MACROBLOCKD *xd,
int segment_id,
SEG_LVL_FEATURES feature_id );
int is_segfeature_signed( SEG_LVL_FEATURES feature_id );
#endif /* __INC_SEG_COMMON_H__ */

View File

@ -1030,14 +1030,8 @@ int vp8_decode_frame(VP8D_COMP *pbi)
{
xd->mb_segement_abs_delta = (unsigned char)vp8_read_bit(bc);
// Clear down feature data structure
vpx_memset(xd->segment_feature_data, 0,
sizeof(xd->segment_feature_data));
#if CONFIG_SEGFEATURES
// Clear down feature enabled masks
vpx_memset(xd->segment_feature_mask, 0,
sizeof(xd->segment_feature_mask));
clearall_segfeatures( xd );
// For each segmentation...
for (j = 0; j < MAX_MB_SEGMENTS; j++)
@ -1045,8 +1039,11 @@ int vp8_decode_frame(VP8D_COMP *pbi)
// For each of the segments features...
for (i = 0; i < SEG_LVL_MAX; i++)
{
#else
// Clear down feature data structure
vpx_memset(xd->segment_feature_data, 0,
sizeof(xd->segment_feature_data));
// For each segmentation feature...
for (i = 0; i < SEG_LVL_MAX; i++)
{
@ -1061,10 +1058,23 @@ int vp8_decode_frame(VP8D_COMP *pbi)
// Update the feature data and mask
enable_segfeature(xd, j, i);
#endif
xd->segment_feature_data[j][i] = (signed char)vp8_read_literal(bc, mb_feature_data_bits[i]);
xd->segment_feature_data[j][i] =
(signed char)vp8_read_literal(
bc, mb_feature_data_bits[i]);
if (vp8_read_bit(bc))
xd->segment_feature_data[j][i] = -xd->segment_feature_data[j][i];
#if CONFIG_SEGFEATURES
// Is the segment data signed..
if ( is_segfeature_signed(i) )
#else
if ( 1 )
#endif
{
if (vp8_read_bit(bc))
{
xd->segment_feature_data[j][i] =
-xd->segment_feature_data[j][i];
}
}
}
else
{

View File

@ -1987,20 +1987,32 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size)
{
vp8_write_bit(bc, 1);
// Encode the relevant feature data
if (Data < 0)
#if CONFIG_SEGFEATURES
// Is the segment data signed..
if ( is_segfeature_signed(i) )
#else
if ( 1 )
#endif
{
Data = - Data;
vp8_write_literal(bc, Data,
mb_feature_data_bits[i]);
vp8_write_bit(bc, 1);
// Encode the relevant feature data
if (Data < 0)
{
Data = - Data;
vp8_write_literal(bc, Data,
mb_feature_data_bits[i]);
vp8_write_bit(bc, 1);
}
else
{
vp8_write_literal(bc, Data,
mb_feature_data_bits[i]);
vp8_write_bit(bc, 0);
}
}
// Unsigned data element so no sign bit needed
else
{
vp8_write_literal(bc, Data,
mb_feature_data_bits[i]);
vp8_write_bit(bc, 0);
}
}
else
vp8_write_bit(bc, 0);

View File

@ -969,7 +969,7 @@ void vp8_encode_frame(VP8_COMP *cpi)
#if CONFIG_SEGFEATURES
// debug output
#if 0
#if DBG_PRNT_SEGMAP
{
FILE *statsfile;
statsfile = fopen("segmap2.stt", "a");

View File

@ -143,6 +143,47 @@ static int do_16x16_motion_search
return err;
}
static int do_16x16_zerozero_search
(
VP8_COMP *cpi,
int_mv *dst_mv,
YV12_BUFFER_CONFIG *buf,
int buf_mb_y_offset,
YV12_BUFFER_CONFIG *ref,
int mb_y_offset
)
{
MACROBLOCK * const x = &cpi->mb;
MACROBLOCKD * const xd = &x->e_mbd;
unsigned int err, tmp_err;
int_mv tmp_mv;
int n;
for (n = 0; n < 16; n++) {
BLOCKD *d = &xd->block[n];
BLOCK *b = &x->block[n];
b->base_src = &buf->y_buffer;
b->src_stride = buf->y_stride;
b->src = buf->y_stride * (n & 12) + (n & 3) * 4 + buf_mb_y_offset;
d->base_pre = &ref->y_buffer;
d->pre_stride = ref->y_stride;
d->pre = ref->y_stride * (n & 12) + (n & 3) * 4 + mb_y_offset;
}
// Try zero MV first
// FIXME should really use something like near/nearest MV and/or MV prediction
xd->pre.y_buffer = ref->y_buffer + mb_y_offset;
xd->pre.y_stride = ref->y_stride;
VARIANCE_INVOKE(&cpi->rtcd.variance, satd16x16)
(ref->y_buffer + mb_y_offset,
ref->y_stride, xd->dst.y_buffer,
xd->dst.y_stride, &err);
dst_mv->as_int = 0;
return err;
}
static int find_best_16x16_intra
(
VP8_COMP *cpi,
@ -227,10 +268,17 @@ static void update_mbgraph_mb_stats
// Alt-ref frame MV search, if it exists and is different than last/golden frame
if (alt_ref)
{
int a_motion_error = do_16x16_motion_search(cpi, prev_alt_ref_mv,
&stats->ref[ALTREF_FRAME].m.mv,
buf, mb_y_offset,
alt_ref, arf_y_offset);
//int a_motion_error = do_16x16_motion_search(cpi, prev_alt_ref_mv,
// &stats->ref[ALTREF_FRAME].m.mv,
// buf, mb_y_offset,
// alt_ref, arf_y_offset);
int a_motion_error =
do_16x16_zerozero_search( cpi,
&stats->ref[ALTREF_FRAME].m.mv,
buf, mb_y_offset,
alt_ref, arf_y_offset);
stats->ref[ALTREF_FRAME].err = a_motion_error;
}
else
@ -312,6 +360,15 @@ static void update_mbgraph_frame_stats
}
}
// Test for small magnitude (<= 1 pel mvs)
int small_mv( MV mv )
{
if ( (abs( (int)mv.col ) > 2) || (abs( (int)mv.row ) > 2) )
return FALSE;
else
return TRUE;
}
//void separate_arf_mbs_byzz
void separate_arf_mbs
(
@ -350,16 +407,15 @@ void separate_arf_mbs
int altref_err = mb_stats->ref[ALTREF_FRAME].err;
int intra_err =
((mb_stats->ref[INTRA_FRAME ].err * 9) >> 3);
mb_stats->ref[INTRA_FRAME ].err + 250;
int golden_err =
250 + ((mb_stats->ref[GOLDEN_FRAME].err * 9) >> 3);
mb_stats->ref[GOLDEN_FRAME].err + 250;
// Test for altref vs intra and gf and that its mv was 0,0.
if ( mb_stats->ref[ALTREF_FRAME].m.mv.as_int ||
( (altref_err > 500) &&
( (altref_err > (intra_err >> 2)) ||
(altref_err > golden_err) ) ) )
if ( (altref_err > 1000) ||
(altref_err > intra_err) ||
(altref_err > golden_err) )
{
arf_not_zz[offset + mb_col]++;
}
@ -389,7 +445,8 @@ void separate_arf_mbs
}
// Only bother with segmentation if over 10% of the MBs in static segment
if ( ncnt[1] && (ncnt[0] / ncnt[1] < 10) )
//if ( ncnt[1] && (ncnt[0] / ncnt[1] < 10) )
if ( 1 )
{
cpi->mbgraph_use_arf_segmentation = ncnt[1];
vp8_enable_segmentation((VP8_PTR) cpi);

View File

@ -489,8 +489,8 @@ static void init_seg_features(VP8_COMP *cpi)
return;
}
// Disable and clear down for KF,ARF and low Q
if ( cm->frame_type == KEY_FRAME || cm->refresh_alt_ref_frame )
// Disable and clear down for KF
if ( cm->frame_type == KEY_FRAME )
{
// Clear down the global segmentation map
vpx_memset( cpi->segmentation_map, 0, (cm->mb_rows * cm->mb_cols));
@ -499,59 +499,117 @@ static void init_seg_features(VP8_COMP *cpi)
// Disable segmentation
vp8_disable_segmentation((VP8_PTR)cpi);
// Clear down the segment features.
clearall_segfeatures(xd);
}
// First normal frame in a valid alt ref group and we dont have low Q
else if ( cpi->source_alt_ref_active &&
(cpi->common.frames_since_golden == 1) )
// If this is an alt ref frame
else if ( cm->refresh_alt_ref_frame )
{
// Low Q test (only use segmentation at high q)
if ( ( (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) &&
(cpi->cq_target_quality > 56 ) ) ||
(cpi->ni_av_qi > 64) )
{
xd->segment_feature_data[1][SEG_LVL_REF_FRAME] = LAST_FRAME;
xd->segment_feature_data[1][SEG_LVL_MODE] = ZEROMV;
xd->segment_feature_data[1][SEG_LVL_EOB] = 10;
xd->segment_feature_data[1][SEG_LVL_ALT_Q] = 10;
xd->segment_feature_data[1][SEG_LVL_ALT_LF] = -5;
// Clear down the global segmentation map
vpx_memset( cpi->segmentation_map, 0, (cm->mb_rows * cm->mb_cols));
xd->update_mb_segmentation_map = 0;
xd->update_mb_segmentation_data = 0;
// Disable segmentation and individual segment features by default
vp8_disable_segmentation((VP8_PTR)cpi);
clearall_segfeatures(xd);
// Scan frames from current to arf frame.
// This function re-enables segmentation if appropriate.
vp8_update_mbgraph_stats(cpi);
// If segmentation was enabled set those features needed for the
// arf itself.
if ( xd->segmentation_enabled )
{
xd->update_mb_segmentation_map = 1;
xd->update_mb_segmentation_data = 1;
xd->segment_feature_data[1][SEG_LVL_ALT_Q] = -3;
xd->segment_feature_data[1][SEG_LVL_ALT_LF] = -2;
// Enable target features is the segment feature mask
enable_segfeature(xd, 1, SEG_LVL_REF_FRAME);
enable_segfeature(xd, 1, SEG_LVL_MODE);
enable_segfeature(xd, 1, SEG_LVL_EOB);
enable_segfeature(xd, 1, SEG_LVL_ALT_Q);
enable_segfeature(xd, 1, SEG_LVL_ALT_LF);
// Where relevant assume segment data is delta data
xd->mb_segement_abs_delta = SEGMENT_DELTADATA;
// Scan frames from current to arf frame and define segmentation
vp8_update_mbgraph_stats(cpi);
}
}
// Normal frames if segmentation got enabled.
// All other frames if segmentation has been enabled
else if ( xd->segmentation_enabled )
{
// Special case where we are coding over the top of a previous
// alt ref frame
if ( cpi->is_src_frame_alt_ref )
// First normal frame in a valid gf or alt ref group
if ( cpi->common.frames_since_golden == 0 )
{
if ( cpi->source_alt_ref_pending )
// Set up segment features for normal frames in an af group
if ( cpi->source_alt_ref_active )
{
xd->update_mb_segmentation_map = 0;
xd->update_mb_segmentation_data = 1;
xd->segment_feature_data[1][SEG_LVL_REF_FRAME] = ALTREF_FRAME;
xd->mb_segement_abs_delta = SEGMENT_DELTADATA;
xd->segment_feature_data[1][SEG_LVL_ALT_Q] = 5;
xd->segment_feature_data[1][SEG_LVL_ALT_LF] = -2;
enable_segfeature(xd, 1, SEG_LVL_ALT_Q);
enable_segfeature(xd, 1, SEG_LVL_ALT_LF);
if ( ( (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) &&
(cpi->cq_target_quality > 56 ) ) ||
(cpi->ni_av_qi > 64) )
{
xd->segment_feature_data[1]
[SEG_LVL_REF_FRAME] = LAST_FRAME;
xd->segment_feature_data[1][SEG_LVL_MODE] = ZEROMV;
xd->segment_feature_data[1][SEG_LVL_EOB] = 15;
enable_segfeature(xd, 1, SEG_LVL_REF_FRAME);
enable_segfeature(xd, 1, SEG_LVL_MODE);
enable_segfeature(xd, 1, SEG_LVL_EOB);
}
}
// Disable segmentation and clear down features if alt ref
// is not active for this group
else
{
vp8_disable_segmentation((VP8_PTR)cpi);
vpx_memset( cpi->segmentation_map, 0,
(cm->mb_rows * cm->mb_cols));
xd->update_mb_segmentation_map = 1;
xd->update_mb_segmentation_data = 1;
xd->update_mb_segmentation_map = 0;
xd->update_mb_segmentation_data = 0;
clearall_segfeatures(xd);
}
}
// Special case where we are coding over the top of a previous
// alt ref frame
else if ( cpi->is_src_frame_alt_ref )
{
// Enable mode and ref frame features for segment 0 as well
enable_segfeature(xd, 0, SEG_LVL_REF_FRAME);
enable_segfeature(xd, 0, SEG_LVL_MODE);
// All mbs should use ALTREF_FRAME, ZEROMV
xd->segment_feature_data[0][SEG_LVL_REF_FRAME] = ALTREF_FRAME;
xd->segment_feature_data[0][SEG_LVL_MODE] = ZEROMV;
xd->segment_feature_data[1][SEG_LVL_REF_FRAME] = ALTREF_FRAME;
xd->segment_feature_data[1][SEG_LVL_MODE] = ZEROMV;
// Enable data udpate
xd->update_mb_segmentation_data = 1;
}
// All other frames.
else
{
// No updeates.. leave things as they are.
xd->update_mb_segmentation_map = 0;
xd->update_mb_segmentation_data = 0;
}
}