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