FPMT: Add code to simulate frame parallel encoding Added code under macro CONFIG_FPMT_TEST to simulate FPMT using single cpi. This facilitates subsequent changes to compare simulation encode (using 1 cpi) with frame parallel encode (using multiple cpis) and ensure bit exactness. Change-Id: I12df9c9d6990d95ecb20081ed8eae24ee8d727b0
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c index 458e1b2..a396fb9 100644 --- a/av1/av1_cx_iface.c +++ b/av1/av1_cx_iface.c
@@ -2517,6 +2517,14 @@ // parallel priv->ppi->num_fp_contexts = av1_compute_num_fp_contexts( priv->ppi, &priv->ppi->parallel_cpi[i]->oxcf); +#if CONFIG_FPMT_TEST + assert(priv->ppi->num_fp_contexts > 1); + // Currently configured 'fmpt_unit_test_cfg' to + // PARALLEL_SIMULATION_ENCODE. + // TODO(Remya): The parameter will be later configured from fpmt unit + // test as required. + priv->ppi->fpmt_unit_test_cfg = PARALLEL_SIMULATION_ENCODE; +#endif } #if !CONFIG_REALTIME_ONLY priv->ppi->parallel_cpi[i]->twopass_frame.stats_in = @@ -2905,6 +2913,7 @@ // visible frame. while (cpi_data.cx_data_sz >= ctx->cx_data_sz / 2 && !is_frame_visible) { #if CONFIG_FRAME_PARALLEL_ENCODE + int simulate_parallel_frame = 0; int status = -1; cpi->do_frame_data_update = true; #if CONFIG_FRAME_PARALLEL_ENCODE_2 @@ -2912,13 +2921,31 @@ cpi->ref_refresh_index = INVALID_IDX; cpi->refresh_idx_available = false; #endif // CONFIG_FRAME_PARALLEL_ENCODE_2 - if (ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == 0) { + +#if CONFIG_FPMT_TEST + simulate_parallel_frame = + cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE ? 1 : 0; + if (simulate_parallel_frame) { + if (ppi->num_fp_contexts > 1 && ppi->gf_group.size > 1) { + if (cpi->gf_frame_index < ppi->gf_group.size) { + calc_frame_data_update_flag(&ppi->gf_group, cpi->gf_frame_index, + &cpi->do_frame_data_update); + } + } status = av1_get_compressed_data(cpi, &cpi_data); - } else if (ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == 1) { - status = av1_compress_parallel_frames(ppi, &cpi_data); - } else { - cpi = av1_get_parallel_frame_enc_data(ppi, &cpi_data); - status = AOM_CODEC_OK; + } + +#endif + if (!simulate_parallel_frame) { + if (ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == 0) { + status = av1_get_compressed_data(cpi, &cpi_data); + } else if (ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == + 1) { + status = av1_compress_parallel_frames(ppi, &cpi_data); + } else { + cpi = av1_get_parallel_frame_enc_data(ppi, &cpi_data); + status = AOM_CODEC_OK; + } } #else const int status = av1_get_compressed_data(cpi, &cpi_data);
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c index 5b975fe..412cd2e 100644 --- a/av1/encoder/encode_strategy.c +++ b/av1/encoder/encode_strategy.c
@@ -162,7 +162,7 @@ } static int choose_primary_ref_frame( - const AV1_COMP *const cpi, const EncodeFrameParams *const frame_params) { + AV1_COMP *const cpi, const EncodeFrameParams *const frame_params) { const AV1_COMMON *const cm = &cpi->common; const int intra_only = frame_params->frame_type == KEY_FRAME || @@ -184,7 +184,27 @@ // current frame const int current_ref_type = get_current_frame_ref_type(cpi); int wanted_fb = cpi->ppi->fb_of_context_type[current_ref_type]; - +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FRAME_PARALLEL_ENCODE_2 && \ + CONFIG_FPMT_TEST + if (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) { + GF_GROUP *const gf_group = &cpi->ppi->gf_group; + if (gf_group->update_type[cpi->gf_frame_index] == INTNL_ARF_UPDATE) { + int frame_level = gf_group->frame_parallel_level[cpi->gf_frame_index]; + // Book keep wanted_fb of frame_parallel_level 1 frame in an FP2 set. + if (frame_level == 1) { + cpi->wanted_fb = wanted_fb; + } + // Use the wanted_fb of level 1 frame in an FP2 for a level 2 frame in the + // set. + if (frame_level == 2 && + gf_group->update_type[cpi->gf_frame_index - 1] == INTNL_ARF_UPDATE) { + assert(gf_group->frame_parallel_level[cpi->gf_frame_index - 1] == 1); + wanted_fb = cpi->wanted_fb; + } + } + } +#endif // CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FRAME_PARALLEL_ENCODE_2 && + // CONFIG_FPMT_TEST int primary_ref_frame = PRIMARY_REF_NONE; for (int ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ref_frame++) { if (get_ref_frame_map_idx(cm, ref_frame) == wanted_fb) { @@ -329,12 +349,17 @@ frame_params->show_frame = *pop_lookahead; #if CONFIG_FRAME_PARALLEL_ENCODE - // Future frame in parallel encode set - if (gf_group->src_offset[cpi->gf_frame_index] != 0 && - !is_stat_generation_stage(cpi)) { - src_index = gf_group->src_offset[cpi->gf_frame_index]; +#if CONFIG_FPMT_TEST + if (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_ENCODE) { +#else + { +#endif // CONFIG_FPMT_TEST + // Future frame in parallel encode set + if (gf_group->src_offset[cpi->gf_frame_index] != 0 && + !is_stat_generation_stage(cpi)) + src_index = gf_group->src_offset[cpi->gf_frame_index]; } -#endif +#endif // CONFIG_FRAME_PARALLEL_ENCODE if (frame_params->show_frame) { // show frame, pop from buffer // Get last frame source. @@ -1262,7 +1287,11 @@ gf_group->frame_parallel_level[gf_index - 1] == 1 && gf_group->update_type[gf_index - 1] == INTNL_ARF_UPDATE) { assert(gf_group->update_type[gf_index] == INTNL_ARF_UPDATE); - +#if CONFIG_FPMT_TEST + is_parallel_encode = (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_ENCODE) + ? is_parallel_encode + : 0; +#endif // CONFIG_FPMT_TEST // If parallel cpis are active, use ref_idx_to_skip, else, use display // index. assert(IMPLIES(is_parallel_encode, cpi->ref_idx_to_skip != INVALID_IDX)); @@ -1536,9 +1565,15 @@ // Initialise frame_level_rate_correction_factors with value previous // to the parallel frames. if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) { - for (int i = 0; i < RATE_FACTOR_LEVELS; i++) + for (int i = 0; i < RATE_FACTOR_LEVELS; i++) { cpi->rc.frame_level_rate_correction_factors[i] = - cpi->ppi->p_rc.rate_correction_factors[i]; +#if CONFIG_FPMT_TEST + (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) + ? cpi->ppi->p_rc.temp_rate_correction_factors[i] + : +#endif // CONFIG_FPMT_TEST + cpi->ppi->p_rc.rate_correction_factors[i]; + } } // copy mv_stats from ppi to frame_level cpi. cpi->mv_stats = cpi->ppi->mv_stats; @@ -1616,6 +1651,14 @@ av1_apply_encoding_flags(cpi, source->flags); *frame_flags = (source->flags & AOM_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0; +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + if (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) { + if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) { + cpi->framerate = cpi->temp_framerate; + } + } +#endif // CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + // Shown frames and arf-overlay frames need frame-rate considering if (frame_params.show_frame) adjust_frame_rate(cpi, source->ts_start, source->ts_end); @@ -1729,10 +1772,16 @@ #endif // CONFIG_FRAME_PARALLEL_ENCODE #if CONFIG_FRAME_PARALLEL_ENCODE - if (gf_group->frame_parallel_level[cpi->gf_frame_index] == 0) { + int get_ref_frames = 0; +#if CONFIG_FPMT_TEST + get_ref_frames = + (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) ? 1 : 0; +#endif // CONFIG_FPMT_TEST + if (get_ref_frames || + gf_group->frame_parallel_level[cpi->gf_frame_index] == 0) { #else { -#endif +#endif // CONFIG_FRAME_PARALLEL_ENCODE if (!ext_flags->refresh_frame.update_pending) { av1_get_ref_frames(&cpi->ref_buffer_stack, #if CONFIG_FRAME_PARALLEL_ENCODE
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c index f54ad30..0e6baae 100644 --- a/av1/encoder/encodeframe.c +++ b/av1/encoder/encodeframe.c
@@ -1282,6 +1282,11 @@ FeatureFlags *const features = &cm->features; MACROBLOCKD *const xd = &x->e_mbd; RD_COUNTS *const rdc = &cpi->td.rd_counts; +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + FrameProbInfo *const temp_frame_probs = &cpi->ppi->temp_frame_probs; + FrameProbInfo *const temp_frame_probs_simulation = + &cpi->ppi->temp_frame_probs_simulation; +#endif FrameProbInfo *const frame_probs = &cpi->ppi->frame_probs; IntraBCHashInfo *const intrabc_hash_info = &x->intrabc_hash_info; MultiThreadInfo *const mt_info = &cpi->mt_info; @@ -1314,8 +1319,14 @@ cpi->sf.inter_sf.prune_warped_prob_thresh > 0) { const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index); - if (frame_probs->warped_probs[update_type] < - cpi->sf.inter_sf.prune_warped_prob_thresh) + int warped_probability = +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE + ? temp_frame_probs->warped_probs[update_type] + : +#endif // CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + frame_probs->warped_probs[update_type]; + if (warped_probability < cpi->sf.inter_sf.prune_warped_prob_thresh) features->allow_warped_motion = 0; } @@ -1581,6 +1592,29 @@ sum ? MAX_TX_TYPE_PROB * cpi->td.rd_counts.tx_type_used[i][j] / sum : (j ? 0 : MAX_TX_TYPE_PROB); #if CONFIG_FRAME_PARALLEL_ENCODE +#if CONFIG_FPMT_TEST + if (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) { + if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == + 0) { + int prob = + (temp_frame_probs_simulation->tx_type_probs[update_type][i][j] + + new_prob) >> + 1; + left -= prob; + if (j == 0) prob += left; + temp_frame_probs_simulation->tx_type_probs[update_type][i][j] = + prob; + // Copy temp_frame_probs_simulation to temp_frame_probs + for (int update_type_idx = 0; update_type_idx < FRAME_UPDATE_TYPES; + update_type_idx++) { + temp_frame_probs->tx_type_probs[update_type_idx][i][j] = + temp_frame_probs_simulation + ->tx_type_probs[update_type_idx][i][j]; + } + } + update_txtype_frameprobs = 0; + } +#endif // CONFIG_FPMT_TEST // Track the frame probabilities of parallel encode frames to update // during postencode stage. if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) { @@ -1613,6 +1647,23 @@ const int new_prob = sum ? 128 * cpi->td.rd_counts.obmc_used[i][1] / sum : 0; #if CONFIG_FRAME_PARALLEL_ENCODE +#if CONFIG_FPMT_TEST + if (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) { + if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == 0) { + temp_frame_probs_simulation->obmc_probs[update_type][i] = + (temp_frame_probs_simulation->obmc_probs[update_type][i] + + new_prob) >> + 1; + // Copy temp_frame_probs_simulation to temp_frame_probs + for (int update_type_idx = 0; update_type_idx < FRAME_UPDATE_TYPES; + update_type_idx++) { + temp_frame_probs->obmc_probs[update_type_idx][i] = + temp_frame_probs_simulation->obmc_probs[update_type_idx][i]; + } + } + update_obmc_frameprobs = 0; + } +#endif // CONFIG_FPMT_TEST // Track the frame probabilities of parallel encode frames to update // during postencode stage. if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) { @@ -1637,6 +1688,23 @@ for (i = 0; i < 2; i++) sum += cpi->td.rd_counts.warped_used[i]; const int new_prob = sum ? 128 * cpi->td.rd_counts.warped_used[1] / sum : 0; #if CONFIG_FRAME_PARALLEL_ENCODE +#if CONFIG_FPMT_TEST + if (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) { + if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == 0) { + temp_frame_probs_simulation->warped_probs[update_type] = + (temp_frame_probs_simulation->warped_probs[update_type] + + new_prob) >> + 1; + // Copy temp_frame_probs_simulation to temp_frame_probs + for (int update_type_idx = 0; update_type_idx < FRAME_UPDATE_TYPES; + update_type_idx++) { + temp_frame_probs->warped_probs[update_type_idx] = + temp_frame_probs_simulation->warped_probs[update_type_idx]; + } + } + update_warp_frameprobs = 0; + } +#endif // CONFIG_FPMT_TEST // Track the frame probabilities of parallel encode frames to update // during postencode stage. if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) { @@ -1672,6 +1740,29 @@ sum ? 1536 * cpi->td.counts->switchable_interp[i][j] / sum : (j ? 0 : 1536); #if CONFIG_FRAME_PARALLEL_ENCODE +#if CONFIG_FPMT_TEST + if (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) { + if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == + 0) { + int prob = (temp_frame_probs_simulation + ->switchable_interp_probs[update_type][i][j] + + new_prob) >> + 1; + left -= prob; + if (j == 0) prob += left; + temp_frame_probs_simulation + ->switchable_interp_probs[update_type][i][j] = prob; + // Copy temp_frame_probs_simulation to temp_frame_probs + for (int update_type_idx = 0; update_type_idx < FRAME_UPDATE_TYPES; + update_type_idx++) { + temp_frame_probs->switchable_interp_probs[update_type_idx][i][j] = + temp_frame_probs_simulation + ->switchable_interp_probs[update_type_idx][i][j]; + } + } + update_interpfilter_frameprobs = 0; + } +#endif // CONFIG_FPMT_TEST // Track the frame probabilities of parallel encode frames to update // during postencode stage. if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) {
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c index 39be35d..4ae7747 100644 --- a/av1/encoder/encoder.c +++ b/av1/encoder/encoder.c
@@ -1771,12 +1771,7 @@ mv_search_params->mv_step_param = av1_init_search_range( AOMMIN(max_mv_def, 2 * mv_search_params->max_mv_magnitude)); } -#if CONFIG_FRAME_PARALLEL_ENCODE - // Reset max_mv_magnitude for parallel frames based on update flag. - if (cpi->do_frame_data_update) mv_search_params->max_mv_magnitude = -1; -#else mv_search_params->max_mv_magnitude = -1; -#endif } } } @@ -2377,10 +2372,15 @@ } #if CONFIG_FRAME_PARALLEL_ENCODE - if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == 0) { -#else + int scale_references = 0; +#if CONFIG_FPMT_TEST + scale_references = + cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE ? 1 : 0; +#endif // CONFIG_FPMT_TEST + if (scale_references || + cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == 0) +#endif // CONFIG_FRAME_PARALLEL_ENCODE { -#endif // For SVC the inter-layer/spatial prediction is not done for newmv // (zero_mode is forced), and since the scaled references are only // use for newmv search, we can avoid scaling here. @@ -2597,10 +2597,16 @@ } #if CONFIG_FRAME_PARALLEL_ENCODE - if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == 0) { + int scale_references = 0; +#if CONFIG_FPMT_TEST + scale_references = + cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE ? 1 : 0; +#endif // CONFIG_FPMT_TEST + if (scale_references || + cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == 0) { #else { -#endif +#endif // CONFIG_FRAME_PARALLEL_ENCODE if (!frame_is_intra_only(cm)) { if (loop_count > 0) { release_scaled_references(cpi); @@ -3542,10 +3548,16 @@ } #if CONFIG_FRAME_PARALLEL_ENCODE - if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == 0) { + int release_scaled_refs = 0; +#if CONFIG_FPMT_TEST + release_scaled_refs = + (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) ? 1 : 0; +#endif // CONFIG_FPMT_TEST + if (release_scaled_refs || + cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == 0) { #else { -#endif +#endif // CONFIG_FRAME_PARALLEL_ENCODE if (frame_is_intra_only(cm) == 0) { release_scaled_references(cpi); } @@ -4142,10 +4154,35 @@ break; } } - if (cpi->ppi->valid_gm_model_found[update_type] == INT32_MAX) { - cpi->ppi->valid_gm_model_found[update_type] = is_gm_present; - } else { - cpi->ppi->valid_gm_model_found[update_type] |= is_gm_present; + int update_actual_stats = 1; +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + update_actual_stats = + (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) ? 0 : 1; + if (!update_actual_stats) { + if (cpi->ppi->temp_valid_gm_model_found[update_type] == INT32_MAX) { + cpi->ppi->temp_valid_gm_model_found[update_type] = is_gm_present; + } else { + cpi->ppi->temp_valid_gm_model_found[update_type] |= is_gm_present; + } + int show_existing_between_parallel_frames = + (cpi->ppi->gf_group.update_type[cpi->gf_frame_index] == + INTNL_OVERLAY_UPDATE && + cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index + 1] == 2); + if (cpi->do_frame_data_update == 1 && + !show_existing_between_parallel_frames) { + for (i = 0; i < FRAME_UPDATE_TYPES; i++) { + cpi->ppi->valid_gm_model_found[i] = + cpi->ppi->temp_valid_gm_model_found[i]; + } + } + } +#endif + if (update_actual_stats) { + if (cpi->ppi->valid_gm_model_found[update_type] == INT32_MAX) { + cpi->ppi->valid_gm_model_found[update_type] = is_gm_present; + } else { + cpi->ppi->valid_gm_model_found[update_type] |= is_gm_present; + } } } @@ -4613,6 +4650,7 @@ cur_cpi->gf_frame_index = i; cur_cpi->framerate = first_cpi->framerate; cur_cpi->common.current_frame.frame_number = cur_frame_num; + cur_cpi->common.current_frame.frame_type = gf_group->frame_type[i]; cur_cpi->frame_index_set.show_frame_count = show_frame_count; cur_cpi->rc.frames_since_key = frames_since_key; cur_cpi->rc.frames_to_key = frames_to_key; @@ -4623,8 +4661,7 @@ cur_cpi->rc.min_frame_bandwidth = first_cpi->rc.min_frame_bandwidth; cur_cpi->rc.intervals_till_gf_calculate_due = first_cpi->rc.intervals_till_gf_calculate_due; - cur_cpi->mv_search_params.max_mv_magnitude = - first_cpi->mv_search_params.max_mv_magnitude; + cur_cpi->mv_search_params.max_mv_magnitude = -1; if (gf_group->update_type[cur_cpi->gf_frame_index] == INTNL_ARF_UPDATE) { cur_cpi->common.lf.mode_ref_delta_enabled = 1; }
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h index a9d794e..96df304 100644 --- a/av1/encoder/encoder.h +++ b/av1/encoder/encoder.h
@@ -135,6 +135,13 @@ } UENUM1BYTE(FRAMETYPE_FLAGS); #if CONFIG_FRAME_PARALLEL_ENCODE +#if CONFIG_FPMT_TEST +enum { + PARALLEL_ENCODE = 0, + PARALLEL_SIMULATION_ENCODE, + NUM_FPMT_TEST_ENCODES +} UENUM1BYTE(FPMT_TEST_ENC_CFG); +#endif // 0 level frames are sometimes used for rate control purposes, but for // reference mapping purposes, the minimum level should be 1. #define MIN_PYR_LEVEL 1 @@ -2355,6 +2362,33 @@ */ int filter_level_v; +#if CONFIG_FPMT_TEST + /*! + * Flag which enables/disables simulation path for fpmt unit test. + * 0 - FPMT integration + * 1 - FPMT simulation + */ + FPMT_TEST_ENC_CFG fpmt_unit_test_cfg; + + /*! + * Temporary variable simulating the delayed frame_probability update. + */ + FrameProbInfo temp_frame_probs; + + /*! + * Temporary variable holding the updated frame probability across + * frames. Copy its value to temp_frame_probs for frame_parallel_level 0 + * frames or last frame in parallel encode set. + */ + FrameProbInfo temp_frame_probs_simulation; + + /*! + * Temporary variable simulating the delayed update of valid global motion + * model across frames. + */ + int temp_valid_gm_model_found[FRAME_UPDATE_TYPES]; +#endif + /*! * Start time stamp of the last encoded show frame */ @@ -2945,7 +2979,13 @@ * Retain condition for fast_extra_bits calculation. */ int do_update_vbr_bits_off_target_fast; - +#if CONFIG_FPMT_TEST + /*! + * Temporary variable for simulation. + * Previous frame's framerate. + */ + double temp_framerate; +#endif /*! * Updated framerate for the current parallel frame. * cpi->framerate is updated with new_framerate during @@ -3178,6 +3218,15 @@ * encode set of lower layer frames. */ int ref_idx_to_skip; +#if CONFIG_FPMT_TEST + /*! + * Stores the wanted frame buffer index for choosing primary ref frame by a + * frame_parallel_level 2 frame in a parallel encode set of lower layer + * frames. + */ + + int wanted_fb; +#endif #endif // CONFIG_FRAME_PARALLEL_ENCODE_2 #endif // CONFIG_FRAME_PARALLEL_ENCODE #if CONFIG_RD_COMMAND @@ -3506,6 +3555,32 @@ ref_frame_map_pairs[map_idx].pyr_level = buf->pyramid_level; } } + +#if CONFIG_FPMT_TEST +static AOM_INLINE void calc_frame_data_update_flag( + GF_GROUP *const gf_group, int gf_frame_index, + bool *const do_frame_data_update) { + *do_frame_data_update = true; + // Set the flag to false for all frames in a given parallel encode set except + // the last frame in the set with frame_parallel_level = 2. + if (gf_group->frame_parallel_level[gf_frame_index] == 1) { + *do_frame_data_update = false; + } else if (gf_group->frame_parallel_level[gf_frame_index] == 2) { + // Check if this is the last frame in the set with frame_parallel_level = 2. + for (int i = gf_frame_index + 1; i < gf_group->size; i++) { + if ((gf_group->frame_parallel_level[i] == 0 && + (gf_group->update_type[i] == ARF_UPDATE || + gf_group->update_type[i] == INTNL_ARF_UPDATE)) || + gf_group->frame_parallel_level[i] == 1) { + break; + } else if (gf_group->frame_parallel_level[i] == 2) { + *do_frame_data_update = false; + break; + } + } + } +} +#endif #endif // CONFIG_FRAME_PARALLEL_ENCODE // TODO(jingning): Move these functions as primitive members for the new cpi
diff --git a/av1/encoder/encoder_utils.c b/av1/encoder/encoder_utils.c index e3f1141..d911265 100644 --- a/av1/encoder/encoder_utils.c +++ b/av1/encoder/encoder_utils.c
@@ -310,7 +310,16 @@ const RATE_CONTROL *const rc = &cpi->rc; struct segmentation *const seg = &cm->seg; - double avg_q = cpi->ppi->p_rc.avg_q; + double avg_q; +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + avg_q = ((cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) && + (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE)) + ? cpi->ppi->p_rc.temp_avg_q + : cpi->ppi->p_rc.avg_q; +#else + avg_q = cpi->ppi->p_rc.avg_q; +#endif + int high_q = (int)(avg_q > 48.0); int qi_delta; @@ -897,7 +906,17 @@ int *projected_size_pass, PSNR_STATS *psnr) { AV1_COMMON *const cm = &cpi->common; FeatureFlags *const features = &cm->features; + +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + projected_size_pass[pass] = + ((cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) && + (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE)) + ? cpi->ppi->p_rc.temp_projected_frame_size + : cpi->rc.projected_frame_size; +#else projected_size_pass[pass] = cpi->rc.projected_frame_size; +#endif + #if CONFIG_AV1_HIGHBITDEPTH const uint32_t in_bit_depth = cpi->oxcf.input_cfg.input_bit_depth; const uint32_t bit_depth = cpi->td.mb.e_mbd.bd;
diff --git a/av1/encoder/encoder_utils.h b/av1/encoder/encoder_utils.h index 15b3296..34a2b6d 100644 --- a/av1/encoder/encoder_utils.h +++ b/av1/encoder/encoder_utils.h
@@ -872,6 +872,44 @@ av1_copy(frame_probs->switchable_interp_probs, default_switchable_interp_probs); } + +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + if (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) { + FrameProbInfo *const temp_frame_probs = &cpi->ppi->temp_frame_probs; + if (cpi->sf.tx_sf.tx_type_search.prune_tx_type_using_stats) { + av1_copy(temp_frame_probs->tx_type_probs, default_tx_type_probs); + } + if (cpi->sf.inter_sf.prune_obmc_prob_thresh > 0 && + cpi->sf.inter_sf.prune_obmc_prob_thresh < INT_MAX) { + av1_copy(temp_frame_probs->obmc_probs, default_obmc_probs); + } + if (cpi->sf.inter_sf.prune_warped_prob_thresh > 0) { + av1_copy(temp_frame_probs->warped_probs, default_warped_probs); + } + if (cpi->sf.interp_sf.adaptive_interp_filter_search == 2) { + av1_copy(temp_frame_probs->switchable_interp_probs, + default_switchable_interp_probs); + } + + FrameProbInfo *const temp_frame_probs_simulation = + &cpi->ppi->temp_frame_probs_simulation; + if (cpi->sf.tx_sf.tx_type_search.prune_tx_type_using_stats) { + av1_copy(temp_frame_probs_simulation->tx_type_probs, + default_tx_type_probs); + } + if (cpi->sf.inter_sf.prune_obmc_prob_thresh > 0 && + cpi->sf.inter_sf.prune_obmc_prob_thresh < INT_MAX) { + av1_copy(temp_frame_probs_simulation->obmc_probs, default_obmc_probs); + } + if (cpi->sf.inter_sf.prune_warped_prob_thresh > 0) { + av1_copy(temp_frame_probs_simulation->warped_probs, default_warped_probs); + } + if (cpi->sf.interp_sf.adaptive_interp_filter_search == 2) { + av1_copy(temp_frame_probs_simulation->switchable_interp_probs, + default_switchable_interp_probs); + } + } +#endif } static AOM_INLINE void restore_cdef_coding_context(CdefInfo *const dst,
diff --git a/av1/encoder/ethread.c b/av1/encoder/ethread.c index 3ef41a8..0506170 100644 --- a/av1/encoder/ethread.c +++ b/av1/encoder/ethread.c
@@ -1013,7 +1013,7 @@ } if (had_error) - aom_internal_error(&ppi->error, error->error_code, error->detail); + aom_internal_error(&ppi->error, error->error_code, "%s", error->detail); } // Restore worker states after parallel encode.
diff --git a/av1/encoder/global_motion_facade.c b/av1/encoder/global_motion_facade.c index 8d9908e..27dbbd7 100644 --- a/av1/encoder/global_motion_facade.c +++ b/av1/encoder/global_motion_facade.c
@@ -458,8 +458,13 @@ if (cpi->oxcf.tool_cfg.enable_global_motion) { if (cpi->gf_frame_index == 0) { - for (int i = 0; i < FRAME_UPDATE_TYPES; i++) + for (int i = 0; i < FRAME_UPDATE_TYPES; i++) { cpi->ppi->valid_gm_model_found[i] = INT32_MAX; +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + if (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) + cpi->ppi->temp_valid_gm_model_found[i] = INT32_MAX; +#endif + } } }
diff --git a/av1/encoder/interp_search.c b/av1/encoder/interp_search.c index acf14ee..c313372 100644 --- a/av1/encoder/interp_search.c +++ b/av1/encoder/interp_search.c
@@ -445,10 +445,25 @@ get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index); const int ctx0 = av1_get_pred_context_switchable_interp(xd, 0); const int ctx1 = av1_get_pred_context_switchable_interp(xd, 1); - const int *switchable_interp_p0 = - cpi->ppi->frame_probs.switchable_interp_probs[update_type][ctx0]; - const int *switchable_interp_p1 = - cpi->ppi->frame_probs.switchable_interp_probs[update_type][ctx1]; + int use_actual_frame_probs = 1; + const int *switchable_interp_p0; + const int *switchable_interp_p1; +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + use_actual_frame_probs = + (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) ? 0 : 1; + if (!use_actual_frame_probs) { + switchable_interp_p0 = (int *)cpi->ppi->temp_frame_probs + .switchable_interp_probs[update_type][ctx0]; + switchable_interp_p1 = (int *)cpi->ppi->temp_frame_probs + .switchable_interp_probs[update_type][ctx1]; + } +#endif + if (use_actual_frame_probs) { + switchable_interp_p0 = + cpi->ppi->frame_probs.switchable_interp_probs[update_type][ctx0]; + switchable_interp_p1 = + cpi->ppi->frame_probs.switchable_interp_probs[update_type][ctx1]; + } static const int thr[7] = { 0, 8, 8, 8, 8, 0, 8 }; const int thresh = thr[update_type]; for (i = 0; i < SWITCHABLE_FILTERS; i++) {
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c index 7f24885..11d85f8 100644 --- a/av1/encoder/pass2_strategy.c +++ b/av1/encoder/pass2_strategy.c
@@ -182,6 +182,43 @@ const double adj_limit = AOMMAX(0.20, (double)(100 - rate_err_tol) / 200.0); const double min_fac = 1.0 - adj_limit; const double max_fac = 1.0 + adj_limit; +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + const int is_parallel_frame = + cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0 ? 1 : 0; + const int simulate_parallel_frame = + cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE + ? is_parallel_frame + : 0; + int64_t local_total_actual_bits = simulate_parallel_frame + ? p_rc->temp_total_actual_bits + : p_rc->total_actual_bits; + int64_t local_vbr_bits_off_target = simulate_parallel_frame + ? p_rc->temp_vbr_bits_off_target + : p_rc->vbr_bits_off_target; + int64_t local_bits_left = simulate_parallel_frame + ? p_rc->temp_bits_left + : cpi->ppi->twopass.bits_left; + double local_rolling_arf_group_target_bits = + (double)(simulate_parallel_frame + ? p_rc->temp_rolling_arf_group_target_bits + : twopass->rolling_arf_group_target_bits); + double local_rolling_arf_group_actual_bits = + (double)(simulate_parallel_frame + ? p_rc->temp_rolling_arf_group_actual_bits + : twopass->rolling_arf_group_actual_bits); + int err_estimate = simulate_parallel_frame ? p_rc->temp_rate_error_estimate + : p_rc->rate_error_estimate; + if (local_vbr_bits_off_target && local_total_actual_bits > 0) { + if (cpi->ppi->lap_enabled) { + rate_err_factor = + local_rolling_arf_group_actual_bits / + DOUBLE_DIVIDE_CHECK(local_rolling_arf_group_target_bits); + } else { + rate_err_factor = + 1.0 - ((double)(local_vbr_bits_off_target) / + AOMMAX(local_total_actual_bits, local_bits_left)); + } +#else int err_estimate = p_rc->rate_error_estimate; if (p_rc->vbr_bits_off_target && p_rc->total_actual_bits > 0) { @@ -194,7 +231,7 @@ 1.0 - ((double)(p_rc->vbr_bits_off_target) / AOMMAX(p_rc->total_actual_bits, cpi->ppi->twopass.bits_left)); } - +#endif rate_err_factor = AOMMAX(min_fac, AOMMIN(max_fac, rate_err_factor)); // Adjustment is damped if this is 1 pass with look ahead processing @@ -3976,6 +4013,33 @@ p_rc->rate_error_estimate = 0; } +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + /* The variables temp_vbr_bits_off_target, temp_bits_left, + * temp_rolling_arf_group_target_bits, temp_rolling_arf_group_actual_bits + * temp_rate_error_estimate are introduced for quality simulation purpose, + * it retains the value previous to the parallel encode frames. The + * variables are updated based on the update flag. + * + * If there exist show_existing_frames between parallel frames, then to + * retain the temp state do not update it. */ + const int simulate_parallel_frame = + cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE; + int show_existing_between_parallel_frames = + (cpi->ppi->gf_group.update_type[cpi->gf_frame_index] == + INTNL_OVERLAY_UPDATE && + cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index + 1] == 2); + + if (cpi->do_frame_data_update && !show_existing_between_parallel_frames && + simulate_parallel_frame) { + cpi->ppi->p_rc.temp_vbr_bits_off_target = p_rc->vbr_bits_off_target; + cpi->ppi->p_rc.temp_bits_left = twopass->bits_left; + cpi->ppi->p_rc.temp_rolling_arf_group_target_bits = + twopass->rolling_arf_group_target_bits; + cpi->ppi->p_rc.temp_rolling_arf_group_actual_bits = + twopass->rolling_arf_group_actual_bits; + cpi->ppi->p_rc.temp_rate_error_estimate = p_rc->rate_error_estimate; + } +#endif // Update the active best quality pyramid. if (!rc->is_src_frame_alt_ref) { const int pyramid_level = @@ -4055,8 +4119,12 @@ twopass->extend_maxq = clamp(twopass->extend_maxq, 0, maxq_adj_limit); #if CONFIG_FRAME_PARALLEL_ENCODE + int update_fast_extra_bits = 1; +#if CONFIG_FPMT_TEST + update_fast_extra_bits = simulate_parallel_frame ? 0 : 1; +#endif if (!frame_is_kf_gf_arf(cpi) && !rc->is_src_frame_alt_ref && - p_rc->vbr_bits_off_target_fast) { + p_rc->vbr_bits_off_target_fast && update_fast_extra_bits) { // Subtract current frame's fast_extra_bits. p_rc->vbr_bits_off_target_fast -= rc->frame_level_fast_extra_bits; } @@ -4088,11 +4156,48 @@ twopass->extend_minq_fast = 0; } } + +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + if (cpi->do_frame_data_update && !show_existing_between_parallel_frames && + simulate_parallel_frame) { + cpi->ppi->p_rc.temp_vbr_bits_off_target_fast = + p_rc->vbr_bits_off_target_fast; + cpi->ppi->p_rc.temp_extend_minq = twopass->extend_minq; + cpi->ppi->p_rc.temp_extend_maxq = twopass->extend_maxq; + cpi->ppi->p_rc.temp_extend_minq_fast = twopass->extend_minq_fast; + } +#endif } #if CONFIG_FRAME_PARALLEL_ENCODE // Update the frame probabilities obtained from parallel encode frames FrameProbInfo *const frame_probs = &cpi->ppi->frame_probs; +#if CONFIG_FPMT_TEST + /* The variable temp_active_best_quality is introduced only for quality + * simulation purpose, it retains the value previous to the parallel + * encode frames. The variable is updated based on the update flag. + * + * If there exist show_existing_frames between parallel frames, then to + * retain the temp state do not update it. */ + if (cpi->do_frame_data_update && !show_existing_between_parallel_frames && + simulate_parallel_frame) { + int i; + const int pyramid_level = + cpi->ppi->gf_group.layer_depth[cpi->gf_frame_index]; + if (!rc->is_src_frame_alt_ref) { + for (i = pyramid_level; i <= MAX_ARF_LAYERS; ++i) + cpi->ppi->p_rc.temp_active_best_quality[i] = + p_rc->active_best_quality[i]; + } + } + + // Update the frame probabilities obtained from parallel encode frames + FrameProbInfo *const temp_frame_probs_simulation = + simulate_parallel_frame ? &cpi->ppi->temp_frame_probs_simulation + : frame_probs; + FrameProbInfo *const temp_frame_probs = + simulate_parallel_frame ? &cpi->ppi->temp_frame_probs : NULL; +#endif int i, j, loop; // Sequentially do average on temp_frame_probs_simulation which holds // probabilities of last frame before parallel encode @@ -4108,11 +4213,21 @@ for (j = TX_TYPES - 1; j >= 0; j--) { const int new_prob = cpi->frame_new_probs[loop].tx_type_probs[update_type][i][j]; +#if CONFIG_FPMT_TEST + int prob = + (temp_frame_probs_simulation->tx_type_probs[update_type][i][j] + + new_prob) >> + 1; + left -= prob; + if (j == 0) prob += left; + temp_frame_probs_simulation->tx_type_probs[update_type][i][j] = prob; +#else int prob = (frame_probs->tx_type_probs[update_type][i][j] + new_prob) >> 1; left -= prob; if (j == 0) prob += left; frame_probs->tx_type_probs[update_type][i][j] = prob; +#endif } } } @@ -4126,8 +4241,15 @@ for (i = 0; i < BLOCK_SIZES_ALL; i++) { const int new_prob = cpi->frame_new_probs[loop].obmc_probs[update_type][i]; +#if CONFIG_FPMT_TEST + temp_frame_probs_simulation->obmc_probs[update_type][i] = + (temp_frame_probs_simulation->obmc_probs[update_type][i] + + new_prob) >> + 1; +#else frame_probs->obmc_probs[update_type][i] = (frame_probs->obmc_probs[update_type][i] + new_prob) >> 1; +#endif } } @@ -4137,8 +4259,14 @@ const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index); const int new_prob = cpi->frame_new_probs[loop].warped_probs[update_type]; +#if CONFIG_FPMT_TEST + temp_frame_probs_simulation->warped_probs[update_type] = + (temp_frame_probs_simulation->warped_probs[update_type] + new_prob) >> + 1; +#else frame_probs->warped_probs[update_type] = (frame_probs->warped_probs[update_type] + new_prob) >> 1; +#endif } // Sequentially update switchable_interp_probs @@ -4153,20 +4281,72 @@ for (j = SWITCHABLE_FILTERS - 1; j >= 0; j--) { const int new_prob = cpi->frame_new_probs[loop] .switchable_interp_probs[update_type][i][j]; +#if CONFIG_FPMT_TEST + int prob = (temp_frame_probs_simulation + ->switchable_interp_probs[update_type][i][j] + + new_prob) >> + 1; + left -= prob; + if (j == 0) prob += left; + + temp_frame_probs_simulation + ->switchable_interp_probs[update_type][i][j] = prob; +#else int prob = (frame_probs->switchable_interp_probs[update_type][i][j] + new_prob) >> 1; left -= prob; if (j == 0) prob += left; frame_probs->switchable_interp_probs[update_type][i][j] = prob; +#endif } } } } +#if CONFIG_FPMT_TEST + // Copying temp_frame_probs_simulation to temp_frame_probs based on + // the flag + if (cpi->do_frame_data_update && + cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0 && + simulate_parallel_frame) { + for (int update_type_idx = 0; update_type_idx < FRAME_UPDATE_TYPES; + update_type_idx++) { + for (i = 0; i < BLOCK_SIZES_ALL; i++) { + temp_frame_probs->obmc_probs[update_type_idx][i] = + temp_frame_probs_simulation->obmc_probs[update_type_idx][i]; + } + temp_frame_probs->warped_probs[update_type_idx] = + temp_frame_probs_simulation->warped_probs[update_type_idx]; + for (i = 0; i < TX_SIZES_ALL; i++) { + for (j = 0; j < TX_TYPES; j++) { + temp_frame_probs->tx_type_probs[update_type_idx][i][j] = + temp_frame_probs_simulation->tx_type_probs[update_type_idx][i][j]; + } + } + for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; i++) { + for (j = 0; j < SWITCHABLE_FILTERS; j++) { + temp_frame_probs->switchable_interp_probs[update_type_idx][i][j] = + temp_frame_probs_simulation + ->switchable_interp_probs[update_type_idx][i][j]; + } + } + } + } +#endif // Update framerate obtained from parallel encode frames if (cpi->common.show_frame && cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) cpi->framerate = cpi->new_framerate; +#if CONFIG_FPMT_TEST + // SIMULATION PURPOSE + int show_existing_between_parallel_frames_cndn = + (cpi->ppi->gf_group.update_type[cpi->gf_frame_index] == + INTNL_OVERLAY_UPDATE && + cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index + 1] == 2); + if (cpi->common.show_frame && !show_existing_between_parallel_frames_cndn && + cpi->do_frame_data_update && simulate_parallel_frame) + cpi->temp_framerate = cpi->framerate; +#endif #endif }
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c index 156698d..312e438 100644 --- a/av1/encoder/ratectrl.c +++ b/av1/encoder/ratectrl.c
@@ -259,6 +259,24 @@ if (cpi->ppi->use_svc) update_layer_buffer_level(&cpi->svc, encoded_frame_size); + +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + /* The variable temp_buffer_level is introduced for quality + * simulation purpose, it retains the value previous to the parallel + * encode frames. The variable is updated based on the update flag. + * + * If there exist show_existing_frames between parallel frames, then to + * retain the temp state do not update it. */ + int show_existing_between_parallel_frames = + (cpi->ppi->gf_group.update_type[cpi->gf_frame_index] == + INTNL_OVERLAY_UPDATE && + cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index + 1] == 2); + + if (cpi->do_frame_data_update && !show_existing_between_parallel_frames && + cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) { + p_rc->temp_buffer_level = p_rc->buffer_level; + } +#endif } int av1_rc_get_default_min_gf_interval(int width, int height, @@ -374,7 +392,15 @@ const AV1EncoderConfig *oxcf = &cpi->oxcf; RATE_CONTROL *const rc = &cpi->rc; PRIMARY_RATE_CONTROL *const p_rc = &cpi->ppi->p_rc; +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + const int simulate_parallel_frame = + cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0 && + cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE; + int64_t buffer_level = + simulate_parallel_frame ? p_rc->temp_buffer_level : p_rc->buffer_level; +#else int64_t buffer_level = p_rc->buffer_level; +#endif if (!oxcf->rc_cfg.drop_frames_water_mark) { return 0; @@ -849,8 +875,18 @@ int active_worst_quality; int last_q_key_frame; int last_q_inter_frame; +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + const int simulate_parallel_frame = + cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0 && + cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE; + last_q_key_frame = simulate_parallel_frame ? p_rc->temp_last_q[KEY_FRAME] + : p_rc->last_q[KEY_FRAME]; + last_q_inter_frame = simulate_parallel_frame ? p_rc->temp_last_q[INTER_FRAME] + : p_rc->last_q[INTER_FRAME]; +#else last_q_key_frame = p_rc->last_q[KEY_FRAME]; last_q_inter_frame = p_rc->last_q[INTER_FRAME]; +#endif if (cpi->common.current_frame.frame_type == KEY_FRAME) { active_worst_quality = @@ -1165,7 +1201,15 @@ av1_compute_qdelta(rc, q_val, q_val * 0.25, bit_depth); active_best_quality = AOMMAX(qindex + delta_qindex, rc->best_quality); } else if (p_rc->this_key_frame_forced) { +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + const int simulate_parallel_frame = + cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0 && + cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE; + int qindex = simulate_parallel_frame ? p_rc->temp_last_boosted_qindex + : p_rc->last_boosted_qindex; +#else int qindex = p_rc->last_boosted_qindex; +#endif const double last_boosted_q = av1_convert_qindex_to_q(qindex, bit_depth); const int delta_qindex = av1_compute_qdelta( rc, last_boosted_q, last_boosted_q * 0.75, bit_depth); @@ -1272,7 +1316,15 @@ // Special case code to try and match quality with forced key frames } else if ((current_frame->frame_type == KEY_FRAME) && p_rc->this_key_frame_forced) { +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + const int simulate_parallel_frame = + cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0 && + cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE; + q = simulate_parallel_frame ? p_rc->temp_last_boosted_qindex + : p_rc->last_boosted_qindex; +#else q = p_rc->last_boosted_qindex; +#endif } else { q = av1_rc_regulate_q(cpi, rc->this_frame_target, active_best_quality, active_worst_quality, width, height); @@ -1360,7 +1412,16 @@ double last_boosted_q; int delta_qindex; int qindex; +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + const int simulate_parallel_frame = + cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0 && + cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE; + int last_boosted_qindex = simulate_parallel_frame + ? p_rc->temp_last_boosted_qindex + : p_rc->last_boosted_qindex; +#else int last_boosted_qindex = p_rc->last_boosted_qindex; +#endif if (is_stat_consumption_stage_twopass(cpi) && cpi->ppi->twopass.last_kfgroup_zeromotion_pct >= STATIC_MOTION_THRESH) { qindex = AOMMIN(p_rc->last_kf_qindex, last_boosted_qindex); @@ -1438,6 +1499,18 @@ const int bit_depth = cpi->common.seq_params->bit_depth; int active_best_quality = *active_best; int active_worst_quality = *active_worst; +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + const int simulate_parallel_frame = + cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0 && + cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE; + int extend_minq_fast = simulate_parallel_frame + ? p_rc->temp_extend_minq_fast + : cpi->ppi->twopass.extend_minq_fast; + int extend_minq = simulate_parallel_frame ? p_rc->temp_extend_minq + : cpi->ppi->twopass.extend_minq; + int extend_maxq = simulate_parallel_frame ? p_rc->temp_extend_maxq + : cpi->ppi->twopass.extend_maxq; +#endif // Extension to max or min Q if undershoot or overshoot is outside // the permitted range. if (cpi->oxcf.rc_cfg.mode != AOM_Q) { @@ -1445,14 +1518,24 @@ (!rc->is_src_frame_alt_ref && (refresh_frame->golden_frame || is_intrl_arf_boost || refresh_frame->alt_ref_frame))) { +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + active_best_quality -= (extend_minq + extend_minq_fast); + active_worst_quality += (extend_maxq / 2); +#else active_best_quality -= (cpi->ppi->twopass.extend_minq + cpi->ppi->twopass.extend_minq_fast); active_worst_quality += (cpi->ppi->twopass.extend_maxq / 2); +#endif } else { +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + active_best_quality -= (extend_minq + extend_minq_fast) / 2; + active_worst_quality += extend_maxq; +#else active_best_quality -= (cpi->ppi->twopass.extend_minq + cpi->ppi->twopass.extend_minq_fast) / 2; active_worst_quality += cpi->ppi->twopass.extend_maxq; +#endif } } @@ -1506,7 +1589,16 @@ const RATE_CONTROL *const rc = &cpi->rc; const PRIMARY_RATE_CONTROL *const p_rc = &cpi->ppi->p_rc; int q; +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + const int simulate_parallel_frame = + cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0 && + cpi->ppi->fpmt_unit_test_cfg; + int last_boosted_qindex = simulate_parallel_frame + ? p_rc->temp_last_boosted_qindex + : p_rc->last_boosted_qindex; +#else int last_boosted_qindex = p_rc->last_boosted_qindex; +#endif if (cpi->oxcf.rc_cfg.mode == AOM_Q || (frame_is_intra_only(cm) && !p_rc->this_key_frame_forced && @@ -1744,7 +1836,19 @@ active_best_quality = get_active_best_quality(cpi, active_worst_quality, cq_level, gf_index); } else { +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + const int simulate_parallel_frame = + cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0 && + cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE; + int local_active_best_quality = + simulate_parallel_frame + ? p_rc->temp_active_best_quality[pyramid_level - 1] + : p_rc->active_best_quality[pyramid_level - 1]; + active_best_quality = local_active_best_quality + 1; +#else active_best_quality = p_rc->active_best_quality[pyramid_level - 1] + 1; +#endif + active_best_quality = AOMMIN(active_best_quality, active_worst_quality); #ifdef STRICT_RC active_best_quality += (active_worst_quality - active_best_quality) / 16; @@ -1960,6 +2064,32 @@ // Update the Golden frame stats as appropriate. update_golden_frame_stats(cpi); +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + /*The variables temp_avg_frame_qindex, temp_last_q, temp_avg_q, + * temp_last_boosted_qindex are introduced only for quality simulation + * purpose, it retains the value previous to the parallel encode frames. The + * variables are updated based on the update flag. + * + * If there exist show_existing_frames between parallel frames, then to + * retain the temp state do not update it. */ + int show_existing_between_parallel_frames = + (cpi->ppi->gf_group.update_type[cpi->gf_frame_index] == + INTNL_OVERLAY_UPDATE && + cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index + 1] == 2); + + if (cpi->do_frame_data_update && !show_existing_between_parallel_frames && + cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) { + for (int i = 0; i < FRAME_TYPES; i++) { + p_rc->temp_last_q[i] = p_rc->last_q[i]; + } + p_rc->temp_avg_q = p_rc->avg_q; + p_rc->temp_last_boosted_qindex = p_rc->last_boosted_qindex; + p_rc->temp_total_actual_bits = p_rc->total_actual_bits; + p_rc->temp_projected_frame_size = rc->projected_frame_size; + for (int i = 0; i < RATE_FACTOR_LEVELS; i++) + p_rc->temp_rate_correction_factors[i] = p_rc->rate_correction_factors[i]; + } +#endif if (current_frame->frame_type == KEY_FRAME) rc->frames_since_key = 0; // if (current_frame->frame_number == 1 && cm->show_frame) /* @@ -2126,7 +2256,16 @@ static void vbr_rate_correction(AV1_COMP *cpi, int *this_frame_target) { RATE_CONTROL *const rc = &cpi->rc; PRIMARY_RATE_CONTROL *const p_rc = &cpi->ppi->p_rc; +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + const int simulate_parallel_frame = + cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0 && + cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE; + int64_t vbr_bits_off_target = simulate_parallel_frame + ? cpi->ppi->p_rc.temp_vbr_bits_off_target + : p_rc->vbr_bits_off_target; +#else int64_t vbr_bits_off_target = p_rc->vbr_bits_off_target; +#endif const int stats_count = cpi->ppi->twopass.stats_buf_ctx->total_stats != NULL ? (int)cpi->ppi->twopass.stats_buf_ctx->total_stats->count @@ -2144,17 +2283,34 @@ *this_frame_target += (vbr_bits_off_target >= 0) ? max_delta : -max_delta; } +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + int64_t vbr_bits_off_target_fast = + simulate_parallel_frame ? cpi->ppi->p_rc.temp_vbr_bits_off_target_fast + : p_rc->vbr_bits_off_target_fast; +#endif // Fast redistribution of bits arising from massive local undershoot. // Dont do it for kf,arf,gf or overlay frames. - if (!frame_is_kf_gf_arf(cpi) && !rc->is_src_frame_alt_ref && - p_rc->vbr_bits_off_target_fast) { + if (!frame_is_kf_gf_arf(cpi) && +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + vbr_bits_off_target_fast && +#else + p_rc->vbr_bits_off_target_fast && +#endif + !rc->is_src_frame_alt_ref) { int one_frame_bits = AOMMAX(rc->avg_frame_bandwidth, *this_frame_target); int fast_extra_bits; +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + fast_extra_bits = (int)AOMMIN(vbr_bits_off_target_fast, one_frame_bits); + fast_extra_bits = + (int)AOMMIN(fast_extra_bits, + AOMMAX(one_frame_bits / 8, vbr_bits_off_target_fast / 8)); +#else fast_extra_bits = (int)AOMMIN(p_rc->vbr_bits_off_target_fast, one_frame_bits); fast_extra_bits = (int)AOMMIN( fast_extra_bits, AOMMAX(one_frame_bits / 8, p_rc->vbr_bits_off_target_fast / 8)); +#endif if (fast_extra_bits > 0) { // Update this_frame_target only if additional bits are available from // local undershoot.
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h index 651f19b..3f822aa 100644 --- a/av1/encoder/ratectrl.h +++ b/av1/encoder/ratectrl.h
@@ -334,6 +334,109 @@ */ int avg_frame_qindex[FRAME_TYPES]; +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + /*! + * Temporary variable used in simulating the delayed update of + * active_best_quality. + */ + int temp_active_best_quality[MAX_ARF_LAYERS + 1]; + + /*! + * Temporary variable used in simulating the delayed update of + * last_boosted_qindex. + */ + int temp_last_boosted_qindex; + + /*! + * Temporary variable used in simulating the delayed update of + * avg_q. + */ + double temp_avg_q; + + /*! + * Temporary variable used in simulating the delayed update of + * last_q. + */ + int temp_last_q[FRAME_TYPES]; + + /*! + * Temporary variable used in simulating the delayed update of + * projected_frame_size. + */ + int temp_projected_frame_size; + + /*! + * Temporary variable used in simulating the delayed update of + * total_actual_bits. + */ + int64_t temp_total_actual_bits; + + /*! + * Temporary variable used in simulating the delayed update of + * buffer_level. + */ + int64_t temp_buffer_level; + + /*! + * Temporary variable used in simulating the delayed update of + * vbr_bits_off_target. + */ + int64_t temp_vbr_bits_off_target; + + /*! + * Temporary variable used in simulating the delayed update of + * vbr_bits_off_target_fast. + */ + int64_t temp_vbr_bits_off_target_fast; + + /*! + * Temporary variable used in simulating the delayed update of + * rate_correction_factors. + */ + double temp_rate_correction_factors[RATE_FACTOR_LEVELS]; + + /*! + * Temporary variable used in simulating the delayed update of + * rate_error_estimate. + */ + int temp_rate_error_estimate; + + /*! + * Temporary variable used in simulating the delayed update of + * rolling_arf_group_target_bits. + */ + int temp_rolling_arf_group_target_bits; + + /*! + * Temporary variable used in simulating the delayed update of + * rolling_arf_group_actual_bits;. + */ + int temp_rolling_arf_group_actual_bits; + + /*! + * Temporary variable used in simulating the delayed update of + * bits_left;. + */ + int64_t temp_bits_left; + + /*! + * Temporary variable used in simulating the delayed update of + * extend_minq. + */ + int temp_extend_minq; + + /*! + * Temporary variable used in simulating the delayed update of + * extend_maxq. + */ + int temp_extend_maxq; + + /*! + * Temporary variable used in simulating the delayed update of + * extend_minq_fast. + */ + int temp_extend_minq_fast; +#endif /*! * Proposed minimum allowed Q different layers in a coding pyramid */
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c index 8ecb4de..7cd8e54 100644 --- a/av1/encoder/rdopt.c +++ b/av1/encoder/rdopt.c
@@ -1352,9 +1352,20 @@ // predetermined threshold for this update_type and block size. const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index); - const int prune_obmc = - cpi->ppi->frame_probs.obmc_probs[update_type][bsize] < - cpi->sf.inter_sf.prune_obmc_prob_thresh; + int use_actual_frame_probs = 1; + int prune_obmc; +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + use_actual_frame_probs = + (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) ? 0 : 1; + if (!use_actual_frame_probs) { + prune_obmc = cpi->ppi->temp_frame_probs.obmc_probs[update_type][bsize] < + cpi->sf.inter_sf.prune_obmc_prob_thresh; + } +#endif + if (use_actual_frame_probs) { + prune_obmc = cpi->ppi->frame_probs.obmc_probs[update_type][bsize] < + cpi->sf.inter_sf.prune_obmc_prob_thresh; + } if ((!cpi->oxcf.motion_mode_cfg.enable_obmc || prune_obmc) && mbmi->motion_mode == OBMC_CAUSAL) continue; @@ -4019,8 +4030,20 @@ av1_count_overlappable_neighbors(cm, xd); const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index); - const int prune_obmc = cpi->ppi->frame_probs.obmc_probs[update_type][bsize] < - cpi->sf.inter_sf.prune_obmc_prob_thresh; + int use_actual_frame_probs = 1; + int prune_obmc; +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + use_actual_frame_probs = + (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) ? 0 : 1; + if (!use_actual_frame_probs) { + prune_obmc = cpi->ppi->temp_frame_probs.obmc_probs[update_type][bsize] < + cpi->sf.inter_sf.prune_obmc_prob_thresh; + } +#endif + if (use_actual_frame_probs) { + prune_obmc = cpi->ppi->frame_probs.obmc_probs[update_type][bsize] < + cpi->sf.inter_sf.prune_obmc_prob_thresh; + } if (cpi->oxcf.motion_mode_cfg.enable_obmc && !prune_obmc) { if (check_num_overlappable_neighbors(mbmi) && is_motion_variation_allowed_bsize(bsize)) {
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c index df79a42..e004bb6 100644 --- a/av1/encoder/speed_features.c +++ b/av1/encoder/speed_features.c
@@ -120,6 +120,8 @@ { 1, 1, 0 }, { 1, 1, 1 } }; +#if !CONFIG_FRAME_PARALLEL_ENCODE || \ + (CONFIG_FRAME_PARALLEL_ENCODE && !CONFIG_FPMT_TEST) // This table holds the maximum number of reference frames for global motion. // The table is indexed as per the speed feature 'gm_search_type'. // 0 : All reference frames are allowed. @@ -129,6 +131,7 @@ static int gm_available_reference_frames[GM_DISABLE_SEARCH + 1] = { INTER_REFS_PER_FRAME, INTER_REFS_PER_FRAME - 2, INTER_REFS_PER_FRAME - 3, 0 }; +#endif // Qindex threshold levels used for selecting full-pel motion search. // ms_qthresh[i][j][k] indicates the qindex boundary value for 'k'th qindex band @@ -2031,6 +2034,8 @@ sf->inter_sf.inter_mode_rd_model_estimation = 2; } +#if !CONFIG_FRAME_PARALLEL_ENCODE || \ + (CONFIG_FRAME_PARALLEL_ENCODE && !CONFIG_FPMT_TEST) // Disable the speed feature 'prune_ref_frame_for_gm_search' to achieve // better parallelism when number of threads available are greater than or // equal to maximum number of reference frames allowed for global motion. @@ -2038,6 +2043,7 @@ (cpi->mt_info.num_workers >= gm_available_reference_frames[sf->gm_sf.gm_search_type])) sf->gm_sf.prune_ref_frame_for_gm_search = 0; +#endif } }
diff --git a/av1/encoder/tx_search.c b/av1/encoder/tx_search.c index f20c6d4..79c21a6 100644 --- a/av1/encoder/tx_search.c +++ b/av1/encoder/tx_search.c
@@ -1682,8 +1682,19 @@ const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index); - const int *tx_type_probs = - cpi->ppi->frame_probs.tx_type_probs[update_type][tx_size]; + int use_actual_frame_probs = 1; + const int *tx_type_probs; +#if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST + use_actual_frame_probs = + (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) ? 0 : 1; + if (!use_actual_frame_probs) { + tx_type_probs = + (int *)cpi->ppi->temp_frame_probs.tx_type_probs[update_type][tx_size]; + } +#endif + if (use_actual_frame_probs) { + tx_type_probs = cpi->ppi->frame_probs.tx_type_probs[update_type][tx_size]; + } if ((!is_inter && txfm_params->use_default_intra_tx_type) || (is_inter && txfm_params->default_inter_tx_type_prob_thresh == 0)) {
diff --git a/build/cmake/aom_config_defaults.cmake b/build/cmake/aom_config_defaults.cmake index fde8a45..4711da6 100644 --- a/build/cmake/aom_config_defaults.cmake +++ b/build/cmake/aom_config_defaults.cmake
@@ -76,6 +76,7 @@ set_aom_config_var( CONFIG_FRAME_PARALLEL_ENCODE_2 0 "Enable frame parallelism during encode for frames in lower layer depths.") +set_aom_config_var(CONFIG_FPMT_TEST 0 "Enable FPMT testing.") set_aom_config_var(CONFIG_GCC 0 "Building with GCC (detect).") set_aom_config_var(CONFIG_GCOV 0 "Enable gcov support.") set_aom_config_var(CONFIG_GPROF 0 "Enable gprof support.")