From ee97da2c0317275e12eae68437a5cf212323c4fb Mon Sep 17 00:00:00 2001 From: Dmitry Kovalev Date: Mon, 29 Apr 2013 16:07:17 -0700 Subject: [PATCH] Cleaning up encoder segmentation code. Moving code from vp9_pack_bitstream to new function encode_segmentation. Change-Id: I1f1e59a1f038618ad95162b7db4b6f8164850ea8 --- vp9/common/vp9_blockd.h | 2 +- vp9/encoder/vp9_bitstream.c | 180 ++++++++++++++++----------------- vp9/encoder/vp9_encodeframe.c | 12 +-- vp9/encoder/vp9_mbgraph.c | 4 +- vp9/encoder/vp9_onyx_if.c | 36 ++++--- vp9/encoder/vp9_rdopt.c | 7 +- vp9/encoder/vp9_segmentation.c | 35 +++---- 7 files changed, 126 insertions(+), 150 deletions(-) diff --git a/vp9/common/vp9_blockd.h b/vp9/common/vp9_blockd.h index 8bb5a6911..053159c0a 100644 --- a/vp9/common/vp9_blockd.h +++ b/vp9/common/vp9_blockd.h @@ -355,7 +355,7 @@ typedef struct macroblockd { PARTITION_CONTEXT *above_seg_context; PARTITION_CONTEXT *left_seg_context; - /* 0 indicates segmentation at MB level is not enabled. Otherwise the individual bits indicate which features are active. */ + /* 0 (disable) 1 (enable) segmentation */ unsigned char segmentation_enabled; /* 0 (do not update) 1 (update) the macroblock segmentation map. */ diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c index 245305479..38657450e 100644 --- a/vp9/encoder/vp9_bitstream.c +++ b/vp9/encoder/vp9_bitstream.c @@ -923,25 +923,20 @@ static void write_mb_modes_kf(const VP9_COMP *cpi, const int segment_id = m->mbmi.segment_id; int skip_coeff; - if (xd->update_mb_segmentation_map) { + if (xd->update_mb_segmentation_map) write_mb_segid(bc, &m->mbmi, xd); - } if (vp9_segfeature_active(xd, segment_id, SEG_LVL_SKIP)) { skip_coeff = 1; } else { skip_coeff = m->mbmi.mb_skip_coeff; - vp9_write(bc, skip_coeff, - vp9_get_pred_prob(c, xd, PRED_MBSKIP)); + vp9_write(bc, skip_coeff, vp9_get_pred_prob(c, xd, PRED_MBSKIP)); } - if (m->mbmi.sb_type > BLOCK_SIZE_MB16X16) { - sb_kfwrite_ymode(bc, ym, - c->sb_kf_ymode_prob[c->kf_ymode_probs_index]); - } else { - kfwrite_ymode(bc, ym, - c->kf_ymode_prob[c->kf_ymode_probs_index]); - } + if (m->mbmi.sb_type > BLOCK_SIZE_MB16X16) + sb_kfwrite_ymode(bc, ym, c->sb_kf_ymode_prob[c->kf_ymode_probs_index]); + else + kfwrite_ymode(bc, ym, c->kf_ymode_prob[c->kf_ymode_probs_index]); if (ym == I4X4_PRED) { int i = 0; @@ -1747,16 +1742,91 @@ static void segment_reference_frames(VP9_COMP *cpi) { } } -void vp9_pack_bitstream(VP9_COMP *cpi, unsigned char *dest, - unsigned long *size) { +static void encode_segmentation(VP9_COMP *cpi, vp9_writer *w) { int i, j; + VP9_COMMON *const pc = &cpi->common; + MACROBLOCKD *const xd = &cpi->mb.e_mbd; + + vp9_write_bit(w, xd->segmentation_enabled); + if (!xd->segmentation_enabled) + return; + + // Segmentation map + vp9_write_bit(w, xd->update_mb_segmentation_map); +#if CONFIG_IMPLICIT_SEGMENTATION + vp9_write_bit(w, xd->allow_implicit_segment_update); +#endif + if (xd->update_mb_segmentation_map) { + // Select the coding strategy (temporal or spatial) + vp9_choose_segmap_coding_method(cpi); + // Write out probabilities used to decode unpredicted macro-block segments + for (i = 0; i < MB_SEG_TREE_PROBS; i++) { + const int prob = xd->mb_segment_tree_probs[i]; + if (prob != MAX_PROB) { + vp9_write_bit(w, 1); + vp9_write_prob(w, prob); + } else { + vp9_write_bit(w, 0); + } + } + + // Write out the chosen coding method. + vp9_write_bit(w, pc->temporal_update); + if (pc->temporal_update) { + for (i = 0; i < PREDICTION_PROBS; i++) { + const int prob = pc->segment_pred_probs[i]; + if (prob != MAX_PROB) { + vp9_write_bit(w, 1); + vp9_write_prob(w, prob); + } else { + vp9_write_bit(w, 0); + } + } + } + } + + // Segmentation data + vp9_write_bit(w, xd->update_mb_segmentation_data); + // segment_reference_frames(cpi); + if (xd->update_mb_segmentation_data) { + vp9_write_bit(w, xd->mb_segment_abs_delta); + + for (i = 0; i < MAX_MB_SEGMENTS; i++) { + for (j = 0; j < SEG_LVL_MAX; j++) { + const int data = vp9_get_segdata(xd, i, j); + const int data_max = vp9_seg_feature_data_max(j); + + if (vp9_segfeature_active(xd, i, j)) { + vp9_write_bit(w, 1); + + if (vp9_is_segfeature_signed(j)) { + if (data < 0) { + vp9_encode_unsigned_max(w, -data, data_max); + vp9_write_bit(w, 1); + } else { + vp9_encode_unsigned_max(w, data, data_max); + vp9_write_bit(w, 0); + } + } else { + vp9_encode_unsigned_max(w, data, data_max); + } + } else { + vp9_write_bit(w, 0); + } + } + } + } +} + +void vp9_pack_bitstream(VP9_COMP *cpi, uint8_t *dest, unsigned long *size) { + int i; VP9_HEADER oh; VP9_COMMON *const pc = &cpi->common; vp9_writer header_bc, residual_bc; MACROBLOCKD *const xd = &cpi->mb.e_mbd; int extra_bytes_packed = 0; - unsigned char *cx_data = dest; + uint8_t *cx_data = dest; oh.show_frame = (int) pc->show_frame; oh.type = (int)pc->frame_type; @@ -1989,87 +2059,7 @@ void vp9_pack_bitstream(VP9_COMP *cpi, unsigned char *dest, active_section = 7; #endif - // Signal whether or not Segmentation is enabled - vp9_write_bit(&header_bc, (xd->segmentation_enabled) ? 1 : 0); - - // Indicate which features are enabled - if (xd->segmentation_enabled) { - // Indicate whether or not the segmentation map is being updated. - vp9_write_bit(&header_bc, (xd->update_mb_segmentation_map) ? 1 : 0); -#if CONFIG_IMPLICIT_SEGMENTATION - vp9_write_bit(&header_bc, (xd->allow_implicit_segment_update) ? 1 : 0); -#endif - - // If it is, then indicate the method that will be used. - if (xd->update_mb_segmentation_map) { - // Select the coding strategy (temporal or spatial) - vp9_choose_segmap_coding_method(cpi); - // Send the tree probabilities used to decode unpredicted - // macro-block segments - for (i = 0; i < MB_SEG_TREE_PROBS; i++) { - const int prob = xd->mb_segment_tree_probs[i]; - if (prob != 255) { - vp9_write_bit(&header_bc, 1); - vp9_write_prob(&header_bc, prob); - } else { - vp9_write_bit(&header_bc, 0); - } - } - - // Write out the chosen coding method. - vp9_write_bit(&header_bc, (pc->temporal_update) ? 1 : 0); - if (pc->temporal_update) { - for (i = 0; i < PREDICTION_PROBS; i++) { - const int prob = pc->segment_pred_probs[i]; - if (prob != 255) { - vp9_write_bit(&header_bc, 1); - vp9_write_prob(&header_bc, prob); - } else { - vp9_write_bit(&header_bc, 0); - } - } - } - } - - vp9_write_bit(&header_bc, (xd->update_mb_segmentation_data) ? 1 : 0); - - // segment_reference_frames(cpi); - - if (xd->update_mb_segmentation_data) { - vp9_write_bit(&header_bc, (xd->mb_segment_abs_delta) ? 1 : 0); - - // For each segments id... - for (i = 0; i < MAX_MB_SEGMENTS; i++) { - // For each segmentation codable feature... - for (j = 0; j < SEG_LVL_MAX; j++) { - const int8_t data = vp9_get_segdata(xd, i, j); - const int data_max = vp9_seg_feature_data_max(j); - - // If the feature is enabled... - if (vp9_segfeature_active(xd, i, j)) { - vp9_write_bit(&header_bc, 1); - - // Is the segment data signed.. - if (vp9_is_segfeature_signed(j)) { - // Encode the relevant feature data - if (data < 0) { - vp9_encode_unsigned_max(&header_bc, -data, data_max); - vp9_write_bit(&header_bc, 1); - } else { - vp9_encode_unsigned_max(&header_bc, data, data_max); - vp9_write_bit(&header_bc, 0); - } - } else { - // Unsigned data element so no sign bit needed - vp9_encode_unsigned_max(&header_bc, data, data_max); - } - } else { - vp9_write_bit(&header_bc, 0); - } - } - } - } - } + encode_segmentation(cpi, &header_bc); // Encode the common prediction model status flag probability updates for // the reference frame diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index 3877391d8..06b4d6316 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -631,13 +631,11 @@ static void set_offsets(VP9_COMP *cpi, /* segment ID */ if (xd->segmentation_enabled) { - if (xd->update_mb_segmentation_map) { - mbmi->segment_id = find_seg_id(cpi->segmentation_map, bsize, - mi_row, cm->mi_rows, mi_col, cm->mi_cols); - } else { - mbmi->segment_id = find_seg_id(cm->last_frame_seg_map, bsize, - mi_row, cm->mi_rows, mi_col, cm->mi_cols); - } + uint8_t *map = xd->update_mb_segmentation_map ? cpi->segmentation_map + : cm->last_frame_seg_map; + mbmi->segment_id = find_seg_id(map, bsize, mi_row, + cm->mi_rows, mi_col, cm->mi_cols); + assert(mbmi->segment_id <= (MAX_MB_SEGMENTS-1)); vp9_mb_init_quantizer(cpi, x); diff --git a/vp9/encoder/vp9_mbgraph.c b/vp9/encoder/vp9_mbgraph.c index fe5d114ba..af62ec394 100644 --- a/vp9/encoder/vp9_mbgraph.c +++ b/vp9/encoder/vp9_mbgraph.c @@ -419,10 +419,10 @@ static void separate_arf_mbs(VP9_COMP *cpi) { cpi->static_mb_pct = 0; cpi->seg0_cnt = ncnt[0]; - vp9_enable_segmentation((VP9_PTR) cpi); + vp9_enable_segmentation((VP9_PTR)cpi); } else { cpi->static_mb_pct = 0; - vp9_disable_segmentation((VP9_PTR) cpi); + vp9_disable_segmentation((VP9_PTR)cpi); } // Free localy allocated storage diff --git a/vp9/encoder/vp9_onyx_if.c b/vp9/encoder/vp9_onyx_if.c index 53d03aa95..865cd8a38 100644 --- a/vp9/encoder/vp9_onyx_if.c +++ b/vp9/encoder/vp9_onyx_if.c @@ -280,8 +280,7 @@ static void setup_features(VP9_COMP *cpi) { MACROBLOCKD *xd = &cpi->mb.e_mbd; // Set up default state for MB feature flags - - xd->segmentation_enabled = 0; // Default segmentation disabled + xd->segmentation_enabled = 0; xd->update_mb_segmentation_map = 0; xd->update_mb_segmentation_data = 0; @@ -383,7 +382,7 @@ static void configure_static_seg_features(VP9_COMP *cpi) { xd->update_mb_segmentation_map = 0; xd->update_mb_segmentation_data = 0; #if CONFIG_IMPLICIT_SEGMENTATION - xd->allow_implicit_segment_update = 0; + xd->allow_implicit_segment_update = 0; #endif cpi->static_mb_pct = 0; @@ -399,7 +398,7 @@ static void configure_static_seg_features(VP9_COMP *cpi) { xd->update_mb_segmentation_map = 0; xd->update_mb_segmentation_data = 0; #if CONFIG_IMPLICIT_SEGMENTATION - xd->allow_implicit_segment_update = 0; + xd->allow_implicit_segment_update = 0; #endif cpi->static_mb_pct = 0; @@ -428,9 +427,9 @@ static void configure_static_seg_features(VP9_COMP *cpi) { xd->mb_segment_abs_delta = SEGMENT_DELTADATA; } - } - // All other frames if segmentation has been enabled - else if (xd->segmentation_enabled) { + } else if (xd->segmentation_enabled) { + // All other frames if segmentation has been enabled + // First normal frame in a valid gf or alt ref group if (cpi->common.frames_since_golden == 0) { // Set up segment features for normal frames in an arf group @@ -454,10 +453,10 @@ static void configure_static_seg_features(VP9_COMP *cpi) { vp9_enable_segfeature(xd, 1, SEG_LVL_REF_FRAME); vp9_enable_segfeature(xd, 1, SEG_LVL_SKIP); } - } - // Disable segmentation and clear down features if alt ref - // is not active for this group - else { + } else { + // Disable segmentation and clear down features if alt ref + // is not active for this group + vp9_disable_segmentation((VP9_PTR)cpi); vpx_memset(cpi->segmentation_map, 0, cm->mi_rows * cm->mi_cols); @@ -467,12 +466,11 @@ static void configure_static_seg_features(VP9_COMP *cpi) { vp9_clearall_segfeatures(xd); } - } + } else if (cpi->is_src_frame_alt_ref) { + // Special case where we are coding over the top of a previous + // alt ref frame. + // Segment coding disabled for compred testing - // Special case where we are coding over the top of a previous - // alt ref frame. - // Segment coding disabled for compred testing - else if (cpi->is_src_frame_alt_ref) { // Enable ref frame features for segment 0 as well vp9_enable_segfeature(xd, 0, SEG_LVL_REF_FRAME); vp9_enable_segfeature(xd, 1, SEG_LVL_REF_FRAME); @@ -490,9 +488,9 @@ static void configure_static_seg_features(VP9_COMP *cpi) { } // Enable data udpate xd->update_mb_segmentation_data = 1; - } - // All other frames. - else { + } else { + // All other frames. + // No updates.. leave things as they are. xd->update_mb_segmentation_map = 0; xd->update_mb_segmentation_data = 0; diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c index cc142d94f..92b0cf184 100644 --- a/vp9/encoder/vp9_rdopt.c +++ b/vp9/encoder/vp9_rdopt.c @@ -4824,10 +4824,9 @@ void vp9_pick_mode_inter_macroblock(VP9_COMP *cpi, MACROBLOCK *x, int64_t intra_error = 0; unsigned char *segment_id = &mbmi->segment_id; - if (xd->segmentation_enabled) - x->encode_breakout = cpi->segment_encode_breakout[*segment_id]; - else - x->encode_breakout = cpi->oxcf.encode_breakout; + x->encode_breakout = xd->segmentation_enabled ? + cpi->segment_encode_breakout[*segment_id] : + cpi->oxcf.encode_breakout; // if (cpi->sf.RD) // For now this codebase is limited to a single rd encode path diff --git a/vp9/encoder/vp9_segmentation.c b/vp9/encoder/vp9_segmentation.c index 7f792ae2b..69d3a9617 100644 --- a/vp9/encoder/vp9_segmentation.c +++ b/vp9/encoder/vp9_segmentation.c @@ -16,18 +16,15 @@ #include "vp9/common/vp9_tile_common.h" void vp9_enable_segmentation(VP9_PTR ptr) { - VP9_COMP *cpi = (VP9_COMP *)(ptr); + VP9_COMP *cpi = (VP9_COMP *)ptr; - // Set the appropriate feature bit cpi->mb.e_mbd.segmentation_enabled = 1; cpi->mb.e_mbd.update_mb_segmentation_map = 1; cpi->mb.e_mbd.update_mb_segmentation_data = 1; } void vp9_disable_segmentation(VP9_PTR ptr) { - VP9_COMP *cpi = (VP9_COMP *)(ptr); - - // Clear the appropriate feature bit + VP9_COMP *cpi = (VP9_COMP *)ptr; cpi->mb.e_mbd.segmentation_enabled = 0; } @@ -238,10 +235,8 @@ void vp9_choose_segmap_coding_method(VP9_COMP *cpi) { // Set default state for the segment tree probabilities and the // temporal coding probabilities - vpx_memset(xd->mb_segment_tree_probs, 255, - sizeof(xd->mb_segment_tree_probs)); - vpx_memset(cm->segment_pred_probs, 255, - sizeof(cm->segment_pred_probs)); + vpx_memset(xd->mb_segment_tree_probs, 255, sizeof(xd->mb_segment_tree_probs)); + vpx_memset(cm->segment_pred_probs, 255, sizeof(cm->segment_pred_probs)); vpx_memset(no_pred_segcounts, 0, sizeof(no_pred_segcounts)); vpx_memset(t_unpred_seg_counts, 0, sizeof(t_unpred_seg_counts)); @@ -249,7 +244,6 @@ void vp9_choose_segmap_coding_method(VP9_COMP *cpi) { // First of all generate stats regarding how well the last segment map // predicts this one - for (tile_col = 0; tile_col < cm->tile_columns; tile_col++) { vp9_get_tile_col_offsets(cm, tile_col); mi_ptr = cm->mi + cm->cur_tile_mi_col_start; @@ -279,27 +273,24 @@ void vp9_choose_segmap_coding_method(VP9_COMP *cpi) { // Add in the cost of the signalling for each prediction context for (i = 0; i < PREDICTION_PROBS; i++) { - t_nopred_prob[i] = get_binary_prob(temporal_predictor_count[i][0], - temporal_predictor_count[i][1]); + const int count0 = temporal_predictor_count[i][0]; + const int count1 = temporal_predictor_count[i][1]; + + t_nopred_prob[i] = get_binary_prob(count0, count1); // Add in the predictor signaling cost - t_pred_cost += (temporal_predictor_count[i][0] * - vp9_cost_zero(t_nopred_prob[i])) + - (temporal_predictor_count[i][1] * - vp9_cost_one(t_nopred_prob[i])); + t_pred_cost += count0 * vp9_cost_zero(t_nopred_prob[i]) + + count1 * vp9_cost_one(t_nopred_prob[i]); } } // Now choose which coding method to use. if (t_pred_cost < no_pred_cost) { cm->temporal_update = 1; - vpx_memcpy(xd->mb_segment_tree_probs, - t_pred_tree, sizeof(t_pred_tree)); - vpx_memcpy(&cm->segment_pred_probs, - t_nopred_prob, sizeof(t_nopred_prob)); + vpx_memcpy(xd->mb_segment_tree_probs, t_pred_tree, sizeof(t_pred_tree)); + vpx_memcpy(cm->segment_pred_probs, t_nopred_prob, sizeof(t_nopred_prob)); } else { cm->temporal_update = 0; - vpx_memcpy(xd->mb_segment_tree_probs, - no_pred_tree, sizeof(no_pred_tree)); + vpx_memcpy(xd->mb_segment_tree_probs, no_pred_tree, sizeof(no_pred_tree)); } } -- 2.40.0