diff options
Diffstat (limited to 'vp8/encoder/encodeframe.c')
-rw-r--r-- | vp8/encoder/encodeframe.c | 257 |
1 files changed, 191 insertions, 66 deletions
diff --git a/vp8/encoder/encodeframe.c b/vp8/encoder/encodeframe.c index 584570da9..fc6dc66d6 100644 --- a/vp8/encoder/encodeframe.c +++ b/vp8/encoder/encodeframe.c @@ -417,6 +417,18 @@ static void update_state(VP8_COMP *cpi, MACROBLOCK *x, PICK_MODE_CONTEXT *ctx) { mbmi->mv[1].as_int = x->partition_info->bmi[15].second_mv.as_int; } +#if CONFIG_TX_SELECT + { + int segment_id = mbmi->segment_id; + if (!segfeature_active(xd, segment_id, SEG_LVL_EOB) || + get_segdata(xd, segment_id, SEG_LVL_EOB)) { + for (i = 0; i < NB_TXFM_MODES; i++) { + cpi->rd_tx_select_diff[i] += ctx->txfm_rd_diff[i]; + } + } + } +#endif + if (cpi->common.frame_type == KEY_FRAME) { // Restore the coding modes to that held in the coding context // if (mb_mode == B_PRED) @@ -606,9 +618,6 @@ static void pick_mb_modes(VP8_COMP *cpi, x->active_ptr = cpi->active_map + map_index; - /* force 4x4 transform for mode selection */ - mbmi->txfm_size = TX_4X4; // TODO IS this right?? - #if CONFIG_SUPERBLOCKS xd->mode_info_context->mbmi.encoded_as_sb = 0; #endif @@ -1395,7 +1404,10 @@ static void encode_frame_internal(VP8_COMP *cpi) { vpx_memset(cpi->rd_comp_pred_diff, 0, sizeof(cpi->rd_comp_pred_diff)); vpx_memset(cpi->single_pred_count, 0, sizeof(cpi->single_pred_count)); vpx_memset(cpi->comp_pred_count, 0, sizeof(cpi->comp_pred_count)); - +#if CONFIG_TX_SELECT + vpx_memset(cpi->txfm_count, 0, sizeof(cpi->txfm_count)); + vpx_memset(cpi->rd_tx_select_diff, 0, sizeof(cpi->rd_tx_select_diff)); +#endif { struct vpx_usec_timer emr_timer; vpx_usec_timer_start(&emr_timer); @@ -1458,6 +1470,7 @@ static int check_dual_ref_flags(VP8_COMP *cpi) { void vp8_encode_frame(VP8_COMP *cpi) { if (cpi->sf.RD) { int i, frame_type, pred_type; + TXFM_MODE txfm_type; /* * This code does a single RD pass over the whole frame assuming @@ -1465,9 +1478,8 @@ void vp8_encode_frame(VP8_COMP *cpi) { * worked best for that type of frame in the past. * It also predicts whether another coding mode would have worked * better that this coding mode. If that is the case, it remembers - * that for subsequent frames. If the difference is above a certain - * threshold, it will actually re-encode the current frame using - * that different coding mode. + * that for subsequent frames. + * It does the same analysis for transform size selection also. */ if (cpi->common.frame_type == KEY_FRAME) frame_type = 0; @@ -1478,6 +1490,7 @@ void vp8_encode_frame(VP8_COMP *cpi) { else frame_type = 2; + /* prediction (compound, single or hybrid) mode selection */ if (frame_type == 3) pred_type = SINGLE_PREDICTION_ONLY; else if (cpi->rd_prediction_type_threshes[frame_type][1] > @@ -1492,15 +1505,111 @@ void vp8_encode_frame(VP8_COMP *cpi) { else pred_type = HYBRID_PREDICTION; + /* transform size (4x4, 8x8, 16x16 or select-per-mb) selection */ +#if CONFIG_LOSSLESS + if (cpi->oxcf.lossless) { + txfm_type = ONLY_4X4; + } else +#endif +#if CONFIG_TX_SELECT + /* FIXME (rbultje) + * this is a hack (no really), basically to work around the complete + * nonsense coefficient cost prediction for keyframes. The probabilities + * are reset to defaults, and thus we basically have no idea how expensive + * a 4x4 vs. 8x8 will really be. The result is that any estimate at which + * of the two is better is utterly bogus. + * I'd like to eventually remove this hack, but in order to do that, we + * need to move the frame reset code from the frame encode init to the + * bitstream write code, or alternatively keep a backup of the previous + * keyframe's probabilities as an estimate of what the current keyframe's + * coefficient cost distributions may look like. */ + if (frame_type == 0) { +#if CONFIG_TX16X16 + txfm_type = ALLOW_16X16; +#else + txfm_type = ALLOW_8X8; +#endif + } else +#if 0 + /* FIXME (rbultje) + * this code is disabled for a similar reason as the code above; the + * problem is that each time we "revert" to 4x4 only (or even 8x8 only), + * the coefficient probabilities for 16x16 (and 8x8) start lagging behind, + * thus leading to them lagging further behind and not being chosen for + * subsequent frames either. This is essentially a local minimum problem + * that we can probably fix by estimating real costs more closely within + * a frame, perhaps by re-calculating costs on-the-fly as frame encoding + * progresses. */ + if (cpi->rd_tx_select_threshes[frame_type][TX_MODE_SELECT] > + cpi->rd_tx_select_threshes[frame_type][ONLY_4X4] && +#if CONFIG_TX16X16 + cpi->rd_tx_select_threshes[frame_type][TX_MODE_SELECT] > + cpi->rd_tx_select_threshes[frame_type][ALLOW_16X16] && +#endif + cpi->rd_tx_select_threshes[frame_type][TX_MODE_SELECT] > + cpi->rd_tx_select_threshes[frame_type][ALLOW_8X8]) { + txfm_type = TX_MODE_SELECT; + } else if (cpi->rd_tx_select_threshes[frame_type][ONLY_4X4] > + cpi->rd_tx_select_threshes[frame_type][ALLOW_8X8] +#if CONFIG_TX16X16 + && cpi->rd_tx_select_threshes[frame_type][ONLY_4X4] > + cpi->rd_tx_select_threshes[frame_type][ALLOW_16X16] +#endif + ) { + txfm_type = ONLY_4X4; +#if CONFIG_TX16X16 + } else if (cpi->rd_tx_select_threshes[frame_type][ALLOW_16X16] >= + cpi->rd_tx_select_threshes[frame_type][ALLOW_8X8]) { + txfm_type = ALLOW_16X16; +#endif + } else + txfm_type = ALLOW_8X8; +#else +#if CONFIG_TX16X16 + txfm_type = cpi->rd_tx_select_threshes[frame_type][ALLOW_16X16] >= + cpi->rd_tx_select_threshes[frame_type][TX_MODE_SELECT] ? + ALLOW_16X16 : TX_MODE_SELECT; +#else + txfm_type = cpi->rd_tx_select_threshes[frame_type][ALLOW_8X8] >= + cpi->rd_tx_select_threshes[frame_type][TX_MODE_SELECT] ? + ALLOW_8X8 : TX_MODE_SELECT; +#endif +#endif +#elif CONFIG_TX16X16 + txfm_type = ALLOW_16X16; +#else + txfm_type = ALLOW_8X8; +#endif // CONFIG_TX_SELECT + cpi->common.txfm_mode = txfm_type; +#if CONFIG_TX_SELECT + if (txfm_type != TX_MODE_SELECT) { + cpi->common.prob_tx[0] = 128; +#if CONFIG_TX16X16 + cpi->common.prob_tx[1] = 128; +#endif + } +#endif cpi->common.comp_pred_mode = pred_type; encode_frame_internal(cpi); for (i = 0; i < NB_PREDICTION_TYPES; ++i) { - int diff = cpi->rd_comp_pred_diff[i] / cpi->common.MBs; + const int diff = cpi->rd_comp_pred_diff[i] / cpi->common.MBs; cpi->rd_prediction_type_threshes[frame_type][i] += diff; cpi->rd_prediction_type_threshes[frame_type][i] >>= 1; } +#if CONFIG_TX_SELECT + for (i = 0; i < NB_TXFM_MODES; ++i) { + int64_t pd = cpi->rd_tx_select_diff[i]; + int diff; + if (i == TX_MODE_SELECT) + pd -= RDCOST(cpi->mb.rdmult, cpi->mb.rddiv, 2048 * (TX_SIZE_MAX - 1), 0); + diff = pd / cpi->common.MBs; + cpi->rd_tx_select_threshes[frame_type][i] += diff; + cpi->rd_tx_select_threshes[frame_type][i] /= 2; + } +#endif + if (cpi->common.comp_pred_mode == HYBRID_PREDICTION) { int single_count_zero = 0; int comp_count_zero = 0; @@ -1516,6 +1625,28 @@ void vp8_encode_frame(VP8_COMP *cpi) { cpi->common.comp_pred_mode = COMP_PREDICTION_ONLY; } } + +#if CONFIG_TX_SELECT + if (cpi->common.txfm_mode == TX_MODE_SELECT) { + const int count4x4 = cpi->txfm_count[TX_4X4]; + const int count8x8 = cpi->txfm_count[TX_8X8]; +#if CONFIG_TX16X16 + const int count16x16 = cpi->txfm_count[TX_16X16]; +#else + const int count16x16 = 0; +#endif + + if (count4x4 == 0 && count16x16 == 0) { + cpi->common.txfm_mode = ALLOW_8X8; + } else if (count8x8 == 0 && count16x16 == 0) { + cpi->common.txfm_mode = ONLY_4X4; +#if CONFIG_TX16X16 + } else if (count8x8 == 0 && count4x4 == 0) { + cpi->common.txfm_mode = ALLOW_16X16; +#endif + } + } +#endif } else { encode_frame_internal(cpi); } @@ -1755,18 +1886,6 @@ void vp8cx_encode_intra_super_block(VP8_COMP *cpi, vp8_update_zbin_extra(cpi, x); } - /* test code: set transform size based on mode selection */ - if (cpi->common.txfm_mode == ALLOW_8X8) { - x->e_mbd.mode_info_context->mbmi.txfm_size = TX_8X8; - x->e_mbd.mode_info_context[1].mbmi.txfm_size = TX_8X8; - x->e_mbd.mode_info_context[cm->mode_info_stride].mbmi.txfm_size = TX_8X8; - x->e_mbd.mode_info_context[cm->mode_info_stride+1].mbmi.txfm_size = TX_8X8; - cpi->t8x8_count++; - } else { - x->e_mbd.mode_info_context->mbmi.txfm_size = TX_4X4; - cpi->t4x4_count++; - } - RECON_INVOKE(&rtcd->common->recon, build_intra_predictors_sby_s)(&x->e_mbd); RECON_INVOKE(&rtcd->common->recon, build_intra_predictors_sbuv_s)(&x->e_mbd); @@ -1835,23 +1954,6 @@ void vp8cx_encode_intra_macro_block(VP8_COMP *cpi, vp8_update_zbin_extra(cpi, x); } - /* test code: set transform size based on mode selection */ -#if CONFIG_TX16X16 || CONFIG_HYBRIDTRANSFORM16X16 - if (mbmi->mode <= TM_PRED) { - mbmi->txfm_size = TX_16X16; - cpi->t16x16_count++; - } - else -#endif - if (cpi->common.txfm_mode == ALLOW_8X8 - && mbmi->mode != B_PRED) { - mbmi->txfm_size = TX_8X8; - cpi->t8x8_count++; - } else { - mbmi->txfm_size = TX_4X4; - cpi->t4x4_count++; - } - if (mbmi->mode == I8X8_PRED) { vp8_encode_intra8x8mby(IF_RTCD(&cpi->rtcd), x); vp8_encode_intra8x8mbuv(IF_RTCD(&cpi->rtcd), x); @@ -1865,9 +1967,34 @@ void vp8cx_encode_intra_macro_block(VP8_COMP *cpi, } if (output_enabled) { +#if CONFIG_TX_SELECT + int segment_id = mbmi->segment_id; +#endif + // Tokenize sum_intra_stats(cpi, x); vp8_tokenize_mb(cpi, &x->e_mbd, t, 0); + +#if CONFIG_TX_SELECT + if (cpi->common.txfm_mode == TX_MODE_SELECT && + !((cpi->common.mb_no_coeff_skip && mbmi->mb_skip_coeff) || + (segfeature_active(&x->e_mbd, segment_id, SEG_LVL_EOB) && + get_segdata(&x->e_mbd, segment_id, SEG_LVL_EOB) == 0))) { + if (mbmi->mode != B_PRED && mbmi->mode != I8X8_PRED) { + cpi->txfm_count[mbmi->txfm_size]++; + } + } else +#endif +#if CONFIG_TX16X16 + if (cpi->common.txfm_mode >= ALLOW_16X16 && mbmi->mode <= TM_PRED) { + mbmi->txfm_size = TX_16X16; + } else +#endif + if (cpi->common.txfm_mode >= ALLOW_8X8 && mbmi->mode != B_PRED) { + mbmi->txfm_size = TX_8X8; + } else { + mbmi->txfm_size = TX_4X4; + } } #if CONFIG_NEWBESTREFMV else @@ -1932,24 +2059,6 @@ void vp8cx_encode_inter_macroblock (VP8_COMP *cpi, MACROBLOCK *x, ref_pred_flag = ((mbmi->ref_frame == get_pred_ref(cm, xd))); set_pred_flag(xd, PRED_REF, ref_pred_flag); - /* test code: set transform size based on mode selection */ -#if CONFIG_TX16X16 || CONFIG_HYBRIDTRANSFORM16X16 - if (mbmi->mode <= TM_PRED || mbmi->mode == NEWMV || mbmi->mode == ZEROMV || - mbmi->mode == NEARMV || mbmi->mode == NEARESTMV) { - mbmi->txfm_size = TX_16X16; - cpi->t16x16_count++; - } else -#endif - if (cpi->common.txfm_mode == ALLOW_8X8 - && mbmi->mode != B_PRED - && mbmi->mode != SPLITMV) { - mbmi->txfm_size = TX_8X8; - cpi->t8x8_count++; - } else { - mbmi->txfm_size = TX_4X4; - cpi->t4x4_count++; - } - if (mbmi->ref_frame == INTRA_FRAME) { if (mbmi->mode == B_PRED) { vp8_encode_intra16x16mbuv(IF_RTCD(&cpi->rtcd), x); @@ -2056,6 +2165,33 @@ void vp8cx_encode_inter_macroblock (VP8_COMP *cpi, MACROBLOCK *x, cpi->skip_false_count[mb_skip_context]++; } } + + if (output_enabled) { +#if CONFIG_TX_SELECT + int segment_id = mbmi->segment_id; + if (cpi->common.txfm_mode == TX_MODE_SELECT && + !((cpi->common.mb_no_coeff_skip && mbmi->mb_skip_coeff) || + (segfeature_active(&x->e_mbd, segment_id, SEG_LVL_EOB) && + get_segdata(&x->e_mbd, segment_id, SEG_LVL_EOB) == 0))) { + if (mbmi->mode != B_PRED && mbmi->mode != I8X8_PRED && + mbmi->mode != SPLITMV) { + cpi->txfm_count[mbmi->txfm_size]++; + } + } else +#endif +#if CONFIG_TX16X16 + if (mbmi->mode != B_PRED && mbmi->mode != I8X8_PRED && + mbmi->mode != SPLITMV && cpi->common.txfm_mode >= ALLOW_16X16) { + mbmi->txfm_size = TX_16X16; + } else +#endif + if (mbmi->mode != B_PRED && mbmi->mode != SPLITMV && + cpi->common.txfm_mode >= ALLOW_8X8) { + mbmi->txfm_size = TX_8X8; + } else { + mbmi->txfm_size = TX_4X4; + } + } } #if CONFIG_SUPERBLOCKS @@ -2119,17 +2255,6 @@ void vp8cx_encode_inter_superblock(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t, get_pred_ref(cm, xd))); set_pred_flag(xd, PRED_REF, ref_pred_flag); - /* test code: set transform size based on mode selection */ - if (cpi->common.txfm_mode == ALLOW_8X8 - && x->e_mbd.mode_info_context->mbmi.mode != B_PRED - && x->e_mbd.mode_info_context->mbmi.mode != SPLITMV) { - x->e_mbd.mode_info_context->mbmi.txfm_size = TX_8X8; - cpi->t8x8_count++; - } else { - x->e_mbd.mode_info_context->mbmi.txfm_size = TX_4X4; - cpi->t4x4_count++; - } - if (xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME) { RECON_INVOKE(&rtcd->common->recon, build_intra_predictors_sby_s)(&x->e_mbd); RECON_INVOKE(&rtcd->common->recon, build_intra_predictors_sbuv_s)(&x->e_mbd); |