From 7070dab44579e0b01c8ae04c65b5e080cc030c4f Mon Sep 17 00:00:00 2001 From: John Koleszar Date: Thu, 8 Mar 2012 12:18:10 -0800 Subject: [PATCH] wip: reuse mode/mv in multistream file Add --read-mvinfo and --write-mvinfo to pass modes and motion vectors between encodes Change-Id: I8d73fbd43d27f765bb2ff3026f4a2191b81c46a9 --- vp8/common/blockd.h | 5 + vp8/encoder/encodeframe.c | 15 ++ vp8/encoder/onyx_if.c | 15 +- vp8/encoder/onyx_int.h | 2 +- vp8/encoder/rdopt.c | 555 +++++++++++++++++++++++++++++++++++++- vp8/vp8_cx_iface.c | 35 +++ vp8/vp8_dx_iface.c | 4 +- vpx/vp8cx.h | 6 + vpxenc.c | 53 +++- 9 files changed, 682 insertions(+), 8 deletions(-) diff --git a/vp8/common/blockd.h b/vp8/common/blockd.h index ae32538fc..cc6ee6ab1 100644 --- a/vp8/common/blockd.h +++ b/vp8/common/blockd.h @@ -205,6 +205,11 @@ typedef struct macroblockd DECLARE_ALIGNED(16, short, dequant_y2[16]); DECLARE_ALIGNED(16, short, dequant_uv[16]); + /* position of this macroblock */ + int mbr; + int mbc; + int mbrc; + /* 16 Y blocks, 4 U, 4 V, 1 DC 2nd order block, each with 16 entries. */ BLOCKD block[25]; int fullpixel_mask; diff --git a/vp8/encoder/encodeframe.c b/vp8/encoder/encodeframe.c index 10f56078b..c4bc9b090 100644 --- a/vp8/encoder/encodeframe.c +++ b/vp8/encoder/encodeframe.c @@ -411,6 +411,10 @@ void encode_mb_row(VP8_COMP *cpi, // for each macroblock col in image for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) { + xd->mbr = mb_row; + xd->mbc = mb_col; + xd->mbrc = mb_row * cm->mb_cols + mb_col; + // Distance of Mb to the left & right edges, specified in // 1/8th pel units as they are always compared to values // that are in 1/8th pel units @@ -1111,6 +1115,8 @@ extern int cnt_pm; extern void vp8_fix_contexts(MACROBLOCKD *x); +#include "valgrind/memcheck.h" + int vp8cx_encode_inter_macroblock ( VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t, @@ -1130,6 +1136,15 @@ int vp8cx_encode_inter_macroblock else x->encode_breakout = cpi->oxcf.encode_breakout; + if (cpi->external_modeinfo) + { + vp8_rd_use_external_mode(cpi, x, recon_yoffset, recon_uvoffset, &rate, + &distortion, &intra_error); + VALGRIND_CHECK_VALUE_IS_DEFINED(rate); + VALGRIND_CHECK_VALUE_IS_DEFINED(distortion); + VALGRIND_CHECK_VALUE_IS_DEFINED(intra_error); + } + else if (cpi->sf.RD) { int zbin_mode_boost_enabled = cpi->zbin_mode_boost_enabled; diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c index 57656bb4f..c8ccd051e 100644 --- a/vp8/encoder/onyx_if.c +++ b/vp8/encoder/onyx_if.c @@ -859,7 +859,7 @@ void vp8_set_speed_features(VP8_COMP *cpi) { sf->auto_filter = 0; // Faster selection of loop filter sf->search_method = HEX; - sf->iterative_sub_pixel = 0; + //sf->iterative_sub_pixel = 0; } if (Speed > 6) @@ -2449,7 +2449,7 @@ int vp8_use_as_reference(VP8_COMP *cpi, int ref_frame_flags) } int vp8_update_reference(VP8_COMP *cpi, int ref_frame_flags) { - if (ref_frame_flags > 7) + if (ref_frame_flags > 127) return -1 ; cpi->common.refresh_golden_frame = 0; @@ -2465,6 +2465,8 @@ int vp8_update_reference(VP8_COMP *cpi, int ref_frame_flags) if (ref_frame_flags & VP8_ALT_FLAG) cpi->common.refresh_alt_ref_frame = 1; + cpi->common.copy_buffer_to_gf = (ref_frame_flags >> 3) & 3; + cpi->common.copy_buffer_to_arf = (ref_frame_flags >> 5) & 3; return 0; } @@ -3187,8 +3189,11 @@ static void encode_frame_to_data_rate cpi->per_frame_bandwidth = (int)(cpi->target_bandwidth / cpi->output_frame_rate); // Default turn off buffer to buffer copying + if(!cpi->external_modeinfo) + { cm->copy_buffer_to_gf = 0; cm->copy_buffer_to_arf = 0; + } // Clear zbin over-quant value and mode boost values. cpi->zbin_over_quant = 0; @@ -4063,10 +4068,14 @@ static void encode_frame_to_data_rate // For inter frames the current default behavior is that when // cm->refresh_golden_frame is set we copy the old GF over to the ARF buffer // This is purely an encoder decision at present. - if (!cpi->oxcf.error_resilient_mode && cm->refresh_golden_frame) + if(!cpi->external_modeinfo) + { + if (!cpi->oxcf.error_resilient_mode && cm->refresh_golden_frame + && !cm->refresh_alt_ref_frame) cm->copy_buffer_to_arf = 2; else cm->copy_buffer_to_arf = 0; + } cm->frame_to_show = &cm->yv12_fb[cm->new_fb_idx]; diff --git a/vp8/encoder/onyx_int.h b/vp8/encoder/onyx_int.h index 6920fc316..19e9ebe65 100644 --- a/vp8/encoder/onyx_int.h +++ b/vp8/encoder/onyx_int.h @@ -678,7 +678,7 @@ typedef struct VP8_COMP /* Number of MBs per row at lower-resolution level */ int mr_low_res_mb_cols; #endif - + MODE_INFO *external_modeinfo; } VP8_COMP; void control_data_rate(VP8_COMP *cpi); diff --git a/vp8/encoder/rdopt.c b/vp8/encoder/rdopt.c index 433412d73..f04ec521d 100644 --- a/vp8/encoder/rdopt.c +++ b/vp8/encoder/rdopt.c @@ -33,6 +33,7 @@ #include "rdopt.h" #include "vpx_mem/vpx_mem.h" #include "vp8/common/systemdependent.h" +#include "valgrind/memcheck.h" extern void vp8_update_zbin_extra(VP8_COMP *cpi, MACROBLOCK *x); @@ -735,11 +736,12 @@ static int rd_pick_intra4x4mby_modes(VP8_COMP *cpi, MACROBLOCK *mb, int *Rate, break; } + VALGRIND_CHECK_VALUE_IS_DEFINED(tot_rate_y); + VALGRIND_CHECK_VALUE_IS_DEFINED(total_rd); if(total_rd >= (int64_t)best_rd) return INT_MAX; - *Rate = cost; - *rate_y += tot_rate_y; + *rate_y = tot_rate_y; *Distortion = distortion; return RDCOST(mb->rdmult, mb->rddiv, cost, distortion); @@ -1709,6 +1711,555 @@ static void rd_update_mvcount(VP8_COMP *cpi, MACROBLOCK *x, int_mv *best_ref_mv) } } +#if 0 +void vp8_rd_use_external_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, + int recon_uvoffset, int *returnrate, + int *returndistortion, int *returnintra) +{ + unsigned char *plane[4][3]; + MODE_INFO *mi; + int rate, rate_y, rate_uv; + int distortion, distortion_y, distortion_uv; + + + mi = cpi->external_modeinfo + x->e_mbd.mbrc; + *x->e_mbd.mode_info_context = *mi; + + /* Map partitioning info */ + if(mi->mbmi.mode == SPLITMV) + { + int i; + + x->partition_info->count = vp8_mbsplit_count[mi->mbmi.partitioning]; + + for (i = 0; i < x->partition_info->count; i++) + { + int j; + + j = vp8_mbsplit_offset[mi->mbmi.partitioning][i]; + + /* TODO: this is mapping a union onto a struct, assume the + * data will never be looked at from the wrong context. + */ + x->partition_info->bmi[i].mode = NEW4X4; //mi->bmi[j].as_mode; + x->partition_info->bmi[i].mv.as_int = mi->bmi[j].mv.as_int; + } + /* + * used to set x->e_mbd.mode_info_context->mbmi.mv.as_int + */ + x->partition_info->bmi[15].mv.as_int = mi->bmi[15].mv.as_int; + } + + rate = x->mbmode_cost[x->e_mbd.frame_type][mi->mbmi.mode]; + rate += x->ref_frame_cost[mi->mbmi.ref_frame]; + if(mi->mbmi.ref_frame == INTRA_FRAME) + { + vp8_build_intra_predictors_mby(&x->e_mbd); + macro_block_yrd(x, &rate_y, &distortion); + //hack + rate_uv = rate_y/4; + distortion_uv = distortion_y/4; + } + else + { + int sign_bias; + int_mv best_ref_mv_sb[2]; + int_mv mode_mv_sb[2][MB_MODE_COUNT]; + int_mv best_ref_mv; + int mdcounts[4]; + + get_predictor_pointers(cpi, plane, recon_yoffset, recon_uvoffset); + x->e_mbd.pre.y_buffer = plane[mi->mbmi.ref_frame][0]; + x->e_mbd.pre.u_buffer = plane[mi->mbmi.ref_frame][1]; + x->e_mbd.pre.v_buffer = plane[mi->mbmi.ref_frame][2]; + + /* Get nearby MV info */ + sign_bias = vp8_find_near_mvs_bias(&x->e_mbd, + x->e_mbd.mode_info_context, + mode_mv_sb, + best_ref_mv_sb, + mdcounts, + mi->mbmi.ref_frame, + cpi->common.ref_frame_sign_bias); + best_ref_mv.as_int = best_ref_mv_sb[sign_bias].as_int; + + if(mi->mbmi.mode != ZEROMV) + rate += vp8_mv_bit_cost(&mi->mbmi.mv, &best_ref_mv, x->mvcost, 96); + rate += vp8_cost_mv_ref(mi->mbmi.mode, mdcounts); + + vp8_build_inter16x16_predictors_mby(&x->e_mbd, x->e_mbd.predictor, 16); + //rate += vp8_cost_mv_ref(mi->mbmi.mode, mdcounts); + + // Y cost and distortion + macro_block_yrd(x, &rate_y, &distortion_y); + + // UV cost and distortion + rd_inter16x16_uv(cpi, x, &rate_uv, &distortion_uv, + cpi->common.full_pixel); + } + + /* Test for skip blocks */ + if (cpi->common.mb_no_coeff_skip) + { + int i, bit=1; + + for(i=0; i<24; i++) + if(x->e_mbd.eobs[i]) + { + bit = 0; + break; + } + if(bit) + { + rate_y = 0; + rate_uv = 0; + } + rate += vp8_cost_bit(cpi->prob_skip_false, bit); + } + + *returnrate = rate + rate_y + rate_uv; + *returndistortion = distortion + distortion_y + distortion_uv; + *returnintra = (mi->mbmi.ref_frame == INTRA_FRAME) + ? *returndistortion : INT_MAX; +} +#else +void vp8_rd_use_external_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, + int recon_uvoffset, int *returnrate, + int *returndistortion, int *returnintra) +{ + MODE_INFO *mi = cpi->external_modeinfo + x->e_mbd.mbrc; + BLOCK *b = &x->block[0]; + BLOCKD *d = &x->e_mbd.block[0]; + MACROBLOCKD *xd = &x->e_mbd; + union b_mode_info best_bmodes[16]; + MB_MODE_INFO best_mbmode; + PARTITION_INFO best_partition; + int_mv best_ref_mv_sb[2]; + int_mv mode_mv_sb[2][MB_MODE_COUNT]; + int_mv best_ref_mv; + int_mv *mode_mv; + MB_PREDICTION_MODE this_mode; + int num00; + + int i; + int mdcounts[4]; + int rate=0; + int distortion=0; + int best_rd = INT_MAX; + int rate2, distortion2; + int uv_intra_rate, uv_intra_distortion, uv_intra_rate_tokenonly; + int rate_y, UNINITIALIZED_IS_SAFE(rate_uv); + int distortion_uv; + int best_yrd = INT_MAX; + + MB_PREDICTION_MODE uv_intra_mode; + int_mv mvp; + int near_sadidx[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + int saddone=0; + int sr=0; //search range got from mv_pred(). It uses step_param levels. (0-7) + + unsigned char *plane[4][3]; + int sign_bias = 0; + + mode_mv = mode_mv_sb[sign_bias]; + best_ref_mv.as_int = 0; + vpx_memset(mode_mv_sb, 0, sizeof(mode_mv_sb)); + vpx_memset(&best_mbmode, 0, sizeof(best_mbmode)); + vpx_memset(&best_bmodes, 0, sizeof(best_bmodes)); + + { + sign_bias = vp8_find_near_mvs_bias(&x->e_mbd, + x->e_mbd.mode_info_context, + mode_mv_sb, + best_ref_mv_sb, + mdcounts, + LAST_FRAME, + cpi->common.ref_frame_sign_bias); + + mode_mv = mode_mv_sb[sign_bias]; + best_ref_mv.as_int = best_ref_mv_sb[sign_bias].as_int; + } + + cpi->ref_frame_flags|=0x7; + get_predictor_pointers(cpi, plane, recon_yoffset, recon_uvoffset); + + *returnintra = INT_MAX; + cpi->mbs_tested_so_far++; // Count of the number of MBs tested so far this frame + + x->skip = 0; + + x->e_mbd.mode_info_context->mbmi.ref_frame = INTRA_FRAME; + rd_pick_intra_mbuv_mode(cpi, x, &uv_intra_rate, &uv_intra_rate_tokenonly, &uv_intra_distortion); + uv_intra_mode = x->e_mbd.mode_info_context->mbmi.uv_mode; + + { + int this_rd = INT_MAX; + int disable_skip = 0; + int other_cost = 0; + int this_ref_frame; + + // These variables hold are rolling total cost and distortion for this mode + rate2 = 0; + distortion2 = 0; + + this_mode = mi->mbmi.mode; //JRK + this_ref_frame = mi->mbmi.ref_frame; + + x->e_mbd.mode_info_context->mbmi.mode = this_mode; + x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED; + x->e_mbd.mode_info_context->mbmi.ref_frame = this_ref_frame; + + /* everything but intra */ + if (x->e_mbd.mode_info_context->mbmi.ref_frame) + { + x->e_mbd.pre.y_buffer = plane[this_ref_frame][0]; + x->e_mbd.pre.u_buffer = plane[this_ref_frame][1]; + x->e_mbd.pre.v_buffer = plane[this_ref_frame][2]; + + if (sign_bias != cpi->common.ref_frame_sign_bias[this_ref_frame]) + { + sign_bias = cpi->common.ref_frame_sign_bias[this_ref_frame]; + mode_mv = mode_mv_sb[sign_bias]; + best_ref_mv.as_int = best_ref_mv_sb[sign_bias].as_int; + } + } + + // Experimental code. Special case for gf and arf zeromv modes. Increase zbin size to supress noise + if (cpi->zbin_mode_boost_enabled) + { + if ( this_ref_frame == INTRA_FRAME ) + cpi->zbin_mode_boost = 0; + else + { + if (this_mode == ZEROMV) + { + if (this_ref_frame != LAST_FRAME) + cpi->zbin_mode_boost = GF_ZEROMV_ZBIN_BOOST; + else + cpi->zbin_mode_boost = LF_ZEROMV_ZBIN_BOOST; + } + else if (this_mode == SPLITMV) + cpi->zbin_mode_boost = 0; + else + cpi->zbin_mode_boost = MV_ZBIN_BOOST; + } + + vp8_update_zbin_extra(cpi, x); + } + + VALGRIND_CHECK_VALUE_IS_DEFINED(rate2); + switch (this_mode) + { + case B_PRED: + { + int tmp_rd; + + // Note the rate value returned here includes the cost of coding the BPRED mode : x->mbmode_cost[x->e_mbd.frame_type][BPRED]; + tmp_rd = rd_pick_intra4x4mby_modes(cpi, x, &rate, &rate_y, &distortion, INT_MAX); + VALGRIND_CHECK_VALUE_IS_DEFINED(rate); + VALGRIND_CHECK_VALUE_IS_DEFINED(rate_y); + VALGRIND_CHECK_VALUE_IS_DEFINED(distortion); + rate2 += rate; + distortion2 += distortion; + + if(tmp_rd < best_yrd) + { + rate2 += uv_intra_rate; + rate_uv = uv_intra_rate_tokenonly; + distortion2 += uv_intra_distortion; + distortion_uv = uv_intra_distortion; + } + else + { + this_rd = INT_MAX; + disable_skip = 1; + } + } + break; + + case SPLITMV: + { + int tmp_rd; + int this_rd_thresh; + + //this_rd_thresh = (this_ref_frame == 1) ? cpi->rd_threshes[THR_NEW1] : cpi->rd_threshes[THR_NEW3]; + //this_rd_thresh = (this_ref_frame == 2) ? cpi->rd_threshes[THR_NEW2] : this_rd_thresh; + this_rd_thresh = 0; + + tmp_rd = vp8_rd_pick_best_mbsegmentation(cpi, x, &best_ref_mv, + best_yrd, mdcounts, + &rate, &rate_y, &distortion, this_rd_thresh) ; + + VALGRIND_CHECK_VALUE_IS_DEFINED(rate); + VALGRIND_CHECK_VALUE_IS_DEFINED(distortion); + rate2 += rate; + distortion2 += distortion; + + // If even the 'Y' rd value of split is higher than best so far then dont bother looking at UV + if (tmp_rd < best_yrd) + { + // Now work out UV cost and add it in + rd_inter4x4_uv(cpi, x, &rate_uv, &distortion_uv, cpi->common.full_pixel); + rate2 += rate_uv; + distortion2 += distortion_uv; + } + else + { + this_rd = INT_MAX; + disable_skip = 1; + } + } + VALGRIND_CHECK_VALUE_IS_DEFINED(rate_y); + break; + case DC_PRED: + case V_PRED: + case H_PRED: + case TM_PRED: + x->e_mbd.mode_info_context->mbmi.ref_frame = INTRA_FRAME; + vp8_build_intra_predictors_mby + (&x->e_mbd); + macro_block_yrd(x, &rate_y, &distortion) ; + rate2 += rate_y; + distortion2 += distortion; + rate2 += x->mbmode_cost[x->e_mbd.frame_type][x->e_mbd.mode_info_context->mbmi.mode]; + rate2 += uv_intra_rate; + rate_uv = uv_intra_rate_tokenonly; + distortion2 += uv_intra_distortion; + distortion_uv = uv_intra_distortion; + VALGRIND_CHECK_VALUE_IS_DEFINED(rate_y); + break; + + case NEWMV: + mode_mv[NEWMV].as_int = mi->mbmi.mv.as_int; + case NEARESTMV: + case NEARMV: + // Clip "next_nearest" so that it does not extend to far out of image + vp8_clamp_mv2(&mode_mv[this_mode], xd); + + // Do not bother proceeding if the vector (from newmv,nearest or near) is 0,0 as this should then be coded using the zeromv mode. + if (((this_mode == NEARMV) || (this_mode == NEARESTMV)) && (mode_mv[this_mode].as_int == 0)) + this_mode = ZEROMV; + + case ZEROMV: + + // Trap vectors that reach beyond the UMV borders + // Note that ALL New MV, Nearest MV Near MV and Zero MV code drops through to this point + // because of the lack of break statements in the previous two cases. + if (((mode_mv[this_mode].as_mv.row >> 3) < x->mv_row_min) || ((mode_mv[this_mode].as_mv.row >> 3) > x->mv_row_max) || + ((mode_mv[this_mode].as_mv.col >> 3) < x->mv_col_min) || ((mode_mv[this_mode].as_mv.col >> 3) > x->mv_col_max)) + assert(0); + + vp8_set_mbmode_and_mvs(x, this_mode, &mode_mv[this_mode]); + vp8_build_inter16x16_predictors_mby(&x->e_mbd, x->e_mbd.predictor, 16); + + if (cpi->active_map_enabled && x->active_ptr[0] == 0) { + x->skip = 1; + } + else if (x->encode_breakout) + { + unsigned int sse; + unsigned int var; + int threshold = (xd->block[0].dequant[1] + * xd->block[0].dequant[1] >>4); + + if(threshold < x->encode_breakout) + threshold = x->encode_breakout; + + var = vp8_variance16x16 + (*(b->base_src), b->src_stride, + x->e_mbd.predictor, 16, &sse); + + if (sse < threshold) + { + unsigned int q2dc = xd->block[24].dequant[0]; + /* If theres is no codeable 2nd order dc + or a very small uniform pixel change change */ + if ((sse - var < q2dc * q2dc >>4) || + (sse /2 > var && sse-var < 64)) + { + // Check u and v to make sure skip is ok + int sse2= VP8_UVSSE(x); + if (sse2 * 2 < threshold) + { + x->skip = 1; + distortion2 = sse + sse2; + rate2 = 500; + + /* for best_yrd calculation */ + rate_uv = 0; + distortion_uv = sse2; + + disable_skip = 1; + this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2); + + break; + } + } + } + } + + + //intermodecost[mode_index] = vp8_cost_mv_ref(this_mode, mdcounts); // Experimental debug code + + // Add in the Mv/mode cost + rate2 += vp8_cost_mv_ref(this_mode, mdcounts); + + // Y cost and distortion + macro_block_yrd(x, &rate_y, &distortion); + rate2 += rate_y; + distortion2 += distortion; + + // UV cost and distortion + rd_inter16x16_uv(cpi, x, &rate_uv, &distortion_uv, cpi->common.full_pixel); + rate2 += rate_uv; + distortion2 += distortion_uv; + break; + + default: + assert(0); + } + VALGRIND_CHECK_VALUE_IS_DEFINED(rate_y); + + VALGRIND_CHECK_VALUE_IS_DEFINED(rate2); + // Where skip is allowable add in the default per mb cost for the no skip case. + // where we then decide to skip we have to delete this and replace it with the + // cost of signallying a skip + if (cpi->common.mb_no_coeff_skip) + { + other_cost += vp8_cost_bit(cpi->prob_skip_false, 0); + rate2 += other_cost; + } + + /* Estimate the reference frame signaling cost and add it + * to the rolling cost variable. + */ + rate2 += + x->ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame]; + + VALGRIND_CHECK_VALUE_IS_DEFINED(rate2); + VALGRIND_CHECK_VALUE_IS_DEFINED(rate_y); + VALGRIND_CHECK_VALUE_IS_DEFINED(rate_uv); + if (!disable_skip) + { + // Test for the condition where skip block will be activated because there are no non zero coefficients and make any necessary adjustment for rate + if (cpi->common.mb_no_coeff_skip) + { + int tteob; + + tteob = 0; + + for (i = 0; i <= 24; i++) + { + tteob += x->e_mbd.eobs[i]; + } + + if (tteob == 0) + { + rate2 -= (rate_y + rate_uv); + //for best_yrd calculation + rate_uv = 0; + + // Back out no skip flag costing and add in skip flag costing + if (cpi->prob_skip_false) + { + int prob_skip_cost; + + prob_skip_cost = vp8_cost_bit(cpi->prob_skip_false, 1); + prob_skip_cost -= vp8_cost_bit(cpi->prob_skip_false, 0); + rate2 += prob_skip_cost; + other_cost += prob_skip_cost; + } + } + } + // Calculate the final RD estimate for this mode + this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2); + } + + VALGRIND_CHECK_VALUE_IS_DEFINED(rate2); + // Keep record of best intra distortion + if (x->e_mbd.mode_info_context->mbmi.ref_frame == INTRA_FRAME) + { + *returnintra = distortion2 ; + } + + // Did this mode help.. i.i is it the new best mode + { + if (this_mode <= B_PRED) + { + x->e_mbd.mode_info_context->mbmi.uv_mode = uv_intra_mode; + /* required for left and above block mv */ + x->e_mbd.mode_info_context->mbmi.mv.as_int = 0; + } + + other_cost += + x->ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame]; + + /* Calculate the final y RD estimate for this mode */ + best_yrd = RDCOST(x->rdmult, x->rddiv, (rate2-rate_uv-other_cost), + (distortion2-distortion_uv)); + + VALGRIND_CHECK_VALUE_IS_DEFINED(rate2); + *returnrate = rate2; + *returndistortion = distortion2; + best_rd = this_rd; + vpx_memcpy(&best_mbmode, &x->e_mbd.mode_info_context->mbmi, sizeof(MB_MODE_INFO)); + vpx_memcpy(&best_partition, x->partition_info, sizeof(PARTITION_INFO)); + + if ((this_mode == B_PRED) || (this_mode == SPLITMV)) + for (i = 0; i < 16; i++) + { + best_bmodes[i] = x->e_mbd.block[i].bmi; + } + } + } + + VALGRIND_CHECK_VALUE_IS_DEFINED(*returnrate); + VALGRIND_CHECK_VALUE_IS_DEFINED(*returndistortion); + VALGRIND_CHECK_VALUE_IS_DEFINED(*returnintra); + + if (cpi->is_src_frame_alt_ref && + (best_mbmode.mode != ZEROMV || best_mbmode.ref_frame != ALTREF_FRAME)) + { + x->e_mbd.mode_info_context->mbmi.mode = ZEROMV; + x->e_mbd.mode_info_context->mbmi.ref_frame = ALTREF_FRAME; + x->e_mbd.mode_info_context->mbmi.mv.as_int = 0; + x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED; + x->e_mbd.mode_info_context->mbmi.mb_skip_coeff = + (cpi->common.mb_no_coeff_skip); + x->e_mbd.mode_info_context->mbmi.partitioning = 0; + + return; + } + + + // macroblock modes + vpx_memcpy(&x->e_mbd.mode_info_context->mbmi, &best_mbmode, sizeof(MB_MODE_INFO)); + + if (best_mbmode.mode == B_PRED) + { + for (i = 0; i < 16; i++) + xd->mode_info_context->bmi[i].as_mode = best_bmodes[i].as_mode; + } + + if (best_mbmode.mode == SPLITMV) + { + for (i = 0; i < 16; i++) + xd->mode_info_context->bmi[i].mv.as_int = best_bmodes[i].mv.as_int; + + vpx_memcpy(x->partition_info, &best_partition, sizeof(PARTITION_INFO)); + + x->e_mbd.mode_info_context->mbmi.mv.as_int = + x->partition_info->bmi[15].mv.as_int; + } + + if (sign_bias + != cpi->common.ref_frame_sign_bias[xd->mode_info_context->mbmi.ref_frame]) + best_ref_mv.as_int = best_ref_mv_sb[!sign_bias].as_int; + + rd_update_mvcount(cpi, x, &best_ref_mv); +} +#endif + void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int recon_uvoffset, int *returnrate, diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c index 31254d47b..108632c6b 100644 --- a/vp8/vp8_cx_iface.c +++ b/vp8/vp8_cx_iface.c @@ -996,6 +996,7 @@ static const vpx_codec_cx_pkt_t *vp8e_get_cxdata(vpx_codec_alg_priv_t *ctx, + ctx->cpi->common.mode_info_stride * ctx->cx_data_iter.mode_info_row; pkt->data.raw.sz = sizeof(MODE_INFO) * ctx->cpi->common.mb_cols; + ctx->cx_data_iter.mode_info_row++; return pkt; } @@ -1218,6 +1219,38 @@ static vpx_codec_err_t vp8e_set_scalemode(vpx_codec_alg_priv_t *ctx, } +static vpx_codec_err_t set_modeinfo(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + vpx_fixed_buf_t *data = va_arg(args, vpx_fixed_buf_t *); + + ctx->cpi->external_modeinfo = data ? data->buf : NULL; + return VPX_CODEC_OK; +} + + +static vpx_codec_err_t vp8_get_last_ref_updates(vpx_codec_alg_priv_t *ctx, + int ctrl_id, + va_list args) +{ + int *update_info = va_arg(args, int *); + VP8_COMP *pbi = ctx->cpi; + + if (update_info) + { + *update_info = pbi->common.refresh_alt_ref_frame * (int) VP8_ALTR_FRAME + + pbi->common.refresh_golden_frame * (int) VP8_GOLD_FRAME + + pbi->common.refresh_last_frame * (int) VP8_LAST_FRAME + + (pbi->common.copy_buffer_to_gf << 3) + + (pbi->common.copy_buffer_to_arf << 5); + + return VPX_CODEC_OK; + } + else + return VPX_CODEC_INVALID_PARAM; +} + static vpx_codec_ctrl_fn_map_t vp8e_ctf_maps[] = { {VP8_SET_REFERENCE, vp8e_set_reference}, @@ -1244,6 +1277,8 @@ static vpx_codec_ctrl_fn_map_t vp8e_ctf_maps[] = {VP8E_SET_TUNING, set_param}, {VP8E_SET_CQ_LEVEL, set_param}, {VP8E_SET_MAX_INTRA_BITRATE_PCT, set_param}, + {VP8E_SET_MODEINFO, set_modeinfo}, + {VP8E_GET_LAST_REF_UPDATES, vp8_get_last_ref_updates}, { -1, NULL}, }; diff --git a/vp8/vp8_dx_iface.c b/vp8/vp8_dx_iface.c index 0a62d9717..276859d31 100644 --- a/vp8/vp8_dx_iface.c +++ b/vp8/vp8_dx_iface.c @@ -692,7 +692,9 @@ static vpx_codec_err_t vp8_get_last_ref_updates(vpx_codec_alg_priv_t *ctx, { *update_info = pbi->common.refresh_alt_ref_frame * (int) VP8_ALTR_FRAME + pbi->common.refresh_golden_frame * (int) VP8_GOLD_FRAME - + pbi->common.refresh_last_frame * (int) VP8_LAST_FRAME; + + pbi->common.refresh_last_frame * (int) VP8_LAST_FRAME + + (pbi->common.copy_buffer_to_gf << 3) + + (pbi->common.copy_buffer_to_arf << 5); return VPX_CODEC_OK; } diff --git a/vpx/vp8cx.h b/vpx/vp8cx.h index 52752832c..41b8fa59f 100644 --- a/vpx/vp8cx.h +++ b/vpx/vp8cx.h @@ -178,6 +178,10 @@ enum vp8e_enc_control_id * */ VP8E_SET_MAX_INTRA_BITRATE_PCT, + + /*!\brief Mode/mv data */ + VP8E_SET_MODEINFO, + VP8E_GET_LAST_REF_UPDATES }; /*!\brief vpx 1-D scaling mode @@ -311,6 +315,8 @@ VPX_CTRL_USE_TYPE(VP8E_GET_LAST_QUANTIZER_64, int *) VPX_CTRL_USE_TYPE(VP8E_SET_MAX_INTRA_BITRATE_PCT, unsigned int) +VPX_CTRL_USE_TYPE(VP8E_SET_MODEINFO, vpx_fixed_buf_t *) +VPX_CTRL_USE_TYPE(VP8E_GET_LAST_REF_UPDATES, int *) /*! @} - end defgroup vp8_encoder */ #include "vpx_codec_impl_bottom.h" diff --git a/vpxenc.c b/vpxenc.c index f2828657f..d8c4fd71a 100644 --- a/vpxenc.c +++ b/vpxenc.c @@ -1182,12 +1182,17 @@ static const arg_def_t q_hist_n = ARG_DEF(NULL, "q-hist", 1, "Show quantizer histogram (n-buckets)"); static const arg_def_t rate_hist_n = ARG_DEF(NULL, "rate-hist", 1, "Show rate histogram (n-buckets)"); +static const arg_def_t read_modemv_arg = ARG_DEF(NULL, "read-modemv", 0, + "Read modes/mvs"); +static const arg_def_t write_modemv_arg = ARG_DEF(NULL, "write-modemv", 0, + "Write modes/mvs"); static const arg_def_t *main_args[] = { &debugmode, &outputfile, &codecarg, &passes, &pass_arg, &fpf_name, &limit, &deadline, &best_dl, &good_dl, &rt_dl, &verbosearg, &psnrarg, &use_ivf, &q_hist_n, &rate_hist_n, + &read_modemv_arg, &write_modemv_arg, NULL }; @@ -1693,6 +1698,8 @@ struct global_config int debug; int show_q_hist_buckets; int show_rate_hist_buckets; + int read_modemv; + int write_modemv; }; @@ -1808,6 +1815,10 @@ static void parse_global_config(struct global_config *global, char **argv) global->show_q_hist_buckets = arg_parse_uint(&arg); else if (arg_match(&arg, &rate_hist_n, argi)) global->show_rate_hist_buckets = arg_parse_uint(&arg); + else if (arg_match(&arg, &read_modemv_arg, argi)) + global->read_modemv = 1; + else if (arg_match(&arg, &write_modemv_arg, argi)) + global->write_modemv = 1; else argj++; } @@ -2456,6 +2467,7 @@ struct link_record uint32_t sz; uint16_t w; uint16_t h; + int refs_updated; }; static void @@ -2472,6 +2484,9 @@ write_multistream_file(struct stream_state *streams, const struct vpx_codec_enc_cfg *cfg = &stream->config.cfg; struct link_record link = {0}; + vpx_codec_control(&stream->encoder, VP8E_GET_LAST_REF_UPDATES, &link.refs_updated); + ctx_exit_on_error(&stream->encoder, "Failed to get refs"); + while ((pkt = vpx_codec_get_cx_data(&stream->encoder, &iter))) { *got_data = 1; @@ -2596,6 +2611,38 @@ float usec_to_fps(uint64_t usec, unsigned int frames) } +static void set_modeinfo(struct stream_state *stream, + struct webm_ctx *webm) +{ + unsigned char *ptr; + struct link_record link; + int again; + int refs=0; + + vpx_codec_control(&stream->encoder, VP8E_SET_MODEINFO, NULL); + ptr = webm->buf + webm->buf_sz; + do + { + ptr -= sizeof(link); + memcpy(&link, ptr, sizeof(link)); + again = link.sz >> 31; + link.sz &= ~(1<<31); + ptr -= link.sz; + if(link.w == stream->config.cfg.g_w + && link.h == stream->config.cfg.g_h) + { + vpx_fixed_buf_t modeinfo; + + modeinfo.buf = ptr; + modeinfo.sz = link.sz; + vpx_codec_control(&stream->encoder, VP8E_SET_MODEINFO, &modeinfo); + vpx_codec_control(&stream->encoder, VP8E_UPD_REFERENCE, link.refs_updated); + ctx_exit_on_error(&stream->encoder, "Failed to set refs"); + break; + } + } while(again); +} + int main(int argc, const char **argv_) { int pass; @@ -2752,6 +2799,10 @@ int main(int argc, const char **argv_) else frame_avail = 0; + /* Update mode/mv info if available */ + if(input.file_type == FILE_TYPE_WEBM && global.read_modemv) + FOREACH_STREAM(set_modeinfo(stream, &input.webm)); + vpx_usec_timer_start(&timer); FOREACH_STREAM(encode_frame(stream, &global, frame_avail ? &raw : NULL, @@ -2762,7 +2813,7 @@ int main(int argc, const char **argv_) FOREACH_STREAM(update_quantizer_histogram(stream)); got_data = 0; - if(1) + if(global.write_modemv) write_multistream_file(streams, &global, &got_data); else FOREACH_STREAM(get_cx_data(stream, &global, &got_data)); -- 2.40.0