Facilitate LAP based single pass in VBR mode. Accumulate total_stats with limited number of stats available, use this to calculate avg_frame_qindex and active_worst_quality for single pass VBR using LAP. Change-Id: I8725fb72911e6cec5ba676ec0815ad0aad0854c0
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c index 928501f..cdd4fab 100644 --- a/av1/av1_cx_iface.c +++ b/av1/av1_cx_iface.c
@@ -1818,9 +1818,10 @@ return update_extra_cfg(ctx, &extra_cfg); } -static aom_codec_err_t create_frame_stats_buffer( - FIRSTPASS_STATS **frame_stats_buffer, STATS_BUFFER_CTX *stats_buf_context, - int num_lap_buffers) { +#if !CONFIG_REALTIME_ONLY +static aom_codec_err_t create_stats_buffer(FIRSTPASS_STATS **frame_stats_buffer, + STATS_BUFFER_CTX *stats_buf_context, + int num_lap_buffers) { aom_codec_err_t res = AOM_CODEC_OK; int size = get_stats_buf_size(num_lap_buffers, MAX_LAG_BUFFERS); @@ -1832,8 +1833,16 @@ stats_buf_context->stats_in_end = stats_buf_context->stats_in_start; stats_buf_context->stats_in_buf_end = stats_buf_context->stats_in_start + size; + + stats_buf_context->total_left_stats = aom_calloc(1, sizeof(FIRSTPASS_STATS)); + if (stats_buf_context->total_left_stats == NULL) return AOM_CODEC_MEM_ERROR; + av1_twopass_zero_stats(stats_buf_context->total_left_stats); + stats_buf_context->total_stats = aom_calloc(1, sizeof(FIRSTPASS_STATS)); + if (stats_buf_context->total_stats == NULL) return AOM_CODEC_MEM_ERROR; + av1_twopass_zero_stats(stats_buf_context->total_stats); return res; } +#endif static aom_codec_err_t create_context_and_bufferpool( AV1_COMP **p_cpi, BufferPool **p_buffer_pool, AV1EncoderConfig *oxcf, @@ -1911,10 +1920,11 @@ priv->oxcf.use_highbitdepth = (ctx->init_flags & AOM_CODEC_USE_HIGHBITDEPTH) ? 1 : 0; - res = - create_frame_stats_buffer(&priv->frame_stats_buffer, - &priv->stats_buf_context, *num_lap_buffers); +#if !CONFIG_REALTIME_ONLY + res = create_stats_buffer(&priv->frame_stats_buffer, + &priv->stats_buf_context, *num_lap_buffers); if (res != AOM_CODEC_OK) return AOM_CODEC_MEM_ERROR; +#endif res = create_context_and_bufferpool( &priv->cpi, &priv->buffer_pool, &priv->oxcf, &priv->pkt_list.head, @@ -1935,9 +1945,6 @@ return res; } -static void destroy_frame_stats_buffer(FIRSTPASS_STATS *frame_stats_buffer) { - aom_free(frame_stats_buffer); -} static void destroy_context_and_bufferpool(AV1_COMP *cpi, BufferPool *buffer_pool) { av1_remove_compressor(cpi); @@ -1947,6 +1954,13 @@ aom_free(buffer_pool); } +static void destroy_stats_buffer(STATS_BUFFER_CTX *stats_buf_context, + FIRSTPASS_STATS *frame_stats_buffer) { + aom_free(stats_buf_context->total_left_stats); + aom_free(stats_buf_context->total_stats); + aom_free(frame_stats_buffer); +} + static aom_codec_err_t encoder_destroy(aom_codec_alg_priv_t *ctx) { free(ctx->cx_data); destroy_context_and_bufferpool(ctx->cpi, ctx->buffer_pool); @@ -1957,7 +1971,7 @@ ctx->cpi_lap->lookahead = NULL; destroy_context_and_bufferpool(ctx->cpi_lap, ctx->buffer_pool_lap); } - destroy_frame_stats_buffer(ctx->frame_stats_buffer); + destroy_stats_buffer(&ctx->stats_buf_context, ctx->frame_stats_buffer); aom_free(ctx); return AOM_CODEC_OK; }
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c index 2d2e020..6c1fb2c 100644 --- a/av1/encoder/encoder.c +++ b/av1/encoder/encoder.c
@@ -2748,7 +2748,7 @@ oxcf->target_bandwidth = AOMMIN(oxcf->target_bandwidth, max_bitrate); // Also need to update cpi->twopass.bits_left. TWO_PASS *const twopass = &cpi->twopass; - FIRSTPASS_STATS *stats = twopass->total_stats; + FIRSTPASS_STATS *stats = twopass->stats_buf_ctx->total_stats; if (stats != NULL) cpi->twopass.bits_left = (int64_t)(stats->duration * cpi->oxcf.target_bandwidth / 10000000.0); @@ -3156,9 +3156,7 @@ cpi->twopass.stats_in = cpi->twopass.stats_buf_ctx->stats_in_start; #if !CONFIG_REALTIME_ONLY - if (is_stat_generation_stage(cpi)) { - av1_init_first_pass(cpi); - } else if (is_stat_consumption_stage(cpi)) { + if (is_stat_consumption_stage(cpi)) { const size_t packet_sz = sizeof(FIRSTPASS_STATS); const int packets = (int)(oxcf->two_pass_stats_in.sz / packet_sz); @@ -3668,9 +3666,6 @@ #endif // CONFIG_HTB_TRELLIS av1_free_ref_frame_buffers(cm->buffer_pool); - aom_free(cpi->twopass.total_stats); - aom_free(cpi->twopass.total_left_stats); - aom_free(cpi); #ifdef OUTPUT_YUV_SKINMAP
diff --git a/av1/encoder/firstpass.c b/av1/encoder/firstpass.c index bbe37e6..0955510 100644 --- a/av1/encoder/firstpass.c +++ b/av1/encoder/firstpass.c
@@ -136,16 +136,9 @@ section->duration += frame->duration; } -void av1_init_first_pass(AV1_COMP *cpi) { - if (!cpi->lap_enabled) { - cpi->twopass.total_stats = aom_calloc(1, sizeof(FIRSTPASS_STATS)); - av1_twopass_zero_stats(cpi->twopass.total_stats); - } -} - void av1_end_first_pass(AV1_COMP *cpi) { - if (cpi->twopass.total_stats) - output_stats(cpi->twopass.total_stats, cpi->output_pkt_list); + if (cpi->twopass.stats_buf_ctx->total_stats) + output_stats(cpi->twopass.stats_buf_ctx->total_stats, cpi->output_pkt_list); } static aom_variance_fn_t get_block_variance_fn(BLOCK_SIZE bsize) { @@ -820,8 +813,8 @@ // local variable 'fps'), and then cpi->output_pkt_list will point to it. *this_frame_stats = fps; output_stats(this_frame_stats, cpi->output_pkt_list); - if (twopass->total_stats != NULL) { - accumulate_stats(twopass->total_stats, &fps); + if (cpi->twopass.stats_buf_ctx->total_stats != NULL) { + accumulate_stats(cpi->twopass.stats_buf_ctx->total_stats, &fps); } /*In the case of two pass, first pass uses it as a circular buffer, * when LAP is enabled it is used as a linear buffer*/
diff --git a/av1/encoder/firstpass.h b/av1/encoder/firstpass.h index b7f1fd0..99d4445 100644 --- a/av1/encoder/firstpass.h +++ b/av1/encoder/firstpass.h
@@ -133,11 +133,12 @@ FIRSTPASS_STATS *stats_in_start; FIRSTPASS_STATS *stats_in_end; FIRSTPASS_STATS *stats_in_buf_end; + FIRSTPASS_STATS *total_stats; + FIRSTPASS_STATS *total_left_stats; } STATS_BUFFER_CTX; typedef struct { unsigned int section_intra_rating; - FIRSTPASS_STATS *total_stats; // Circular queue of first pass stats stored for most recent frames. // cpi->output_pkt_list[i].data.twopass_stats.buf points to actual data stored // here. @@ -145,7 +146,6 @@ int frame_stats_next_idx; // Index to next unused element in frame_stats_arr. const FIRSTPASS_STATS *stats_in; STATS_BUFFER_CTX *stats_buf_ctx; - FIRSTPASS_STATS *total_left_stats; int first_pass_done; int64_t bits_left; double modified_error_min; @@ -183,7 +183,6 @@ struct EncodeFrameParams; struct AV1EncoderConfig; -void av1_init_first_pass(struct AV1_COMP *cpi); void av1_rc_get_first_pass_params(struct AV1_COMP *cpi); void av1_first_pass(struct AV1_COMP *cpi, const int64_t ts_duration); void av1_end_first_pass(struct AV1_COMP *cpi);
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c index d55b69e..6adc1fb 100644 --- a/av1/encoder/pass2_strategy.c +++ b/av1/encoder/pass2_strategy.c
@@ -55,7 +55,7 @@ const TWO_PASS *twopass, const AV1EncoderConfig *oxcf, const FIRSTPASS_STATS *this_frame) { - const FIRSTPASS_STATS *const stats = twopass->total_stats; + const FIRSTPASS_STATS *const stats = twopass->stats_buf_ctx->total_stats; if (stats == NULL) { return 0; } @@ -2410,20 +2410,31 @@ TWO_PASS *const twopass = &cpi->twopass; if (cpi->oxcf.rc_mode != AOM_Q && current_frame->frame_number == 0 && - cpi->twopass.total_stats && cpi->twopass.total_left_stats) { - const int frames_left = - (int)(twopass->total_stats->count - current_frame->frame_number); + cpi->twopass.stats_buf_ctx->total_stats && + cpi->twopass.stats_buf_ctx->total_left_stats) { + if (cpi->lap_enabled) { + /* + * Accumulate total_stats using available limited number of stats, + * and assign it to total_left_stats. + */ + *cpi->twopass.stats_buf_ctx->total_left_stats = + *cpi->twopass.stats_buf_ctx->total_stats; + } + const int frames_left = (int)(twopass->stats_buf_ctx->total_stats->count - + current_frame->frame_number); // Special case code for first frame. const int section_target_bandwidth = (int)(twopass->bits_left / frames_left); - const double section_length = twopass->total_left_stats->count; + const double section_length = + twopass->stats_buf_ctx->total_left_stats->count; const double section_error = - twopass->total_left_stats->coded_error / section_length; + twopass->stats_buf_ctx->total_left_stats->coded_error / section_length; const double section_intra_skip = - twopass->total_left_stats->intra_skip_pct / section_length; + twopass->stats_buf_ctx->total_left_stats->intra_skip_pct / + section_length; const double section_inactive_zone = - (twopass->total_left_stats->inactive_zone_rows * 2) / + (twopass->stats_buf_ctx->total_left_stats->inactive_zone_rows * 2) / ((double)cm->mi_params.mb_rows * section_length); const int tmp_q = get_twopass_worst_quality( cpi, section_error, section_intra_skip + section_inactive_zone, @@ -2458,8 +2469,8 @@ } // Update the total stats remaining structure. - if (twopass->total_left_stats) - subtract_stats(twopass->total_left_stats, this_frame); + if (twopass->stats_buf_ctx->total_left_stats) + subtract_stats(twopass->stats_buf_ctx->total_left_stats, this_frame); // Set the frame content type flag. if (this_frame->intra_skip_pct >= FC_ANIMATION_THRESH) @@ -2661,17 +2672,12 @@ double frame_rate; FIRSTPASS_STATS *stats; - twopass->total_stats = aom_calloc(1, sizeof(FIRSTPASS_STATS)); - twopass->total_left_stats = aom_calloc(1, sizeof(FIRSTPASS_STATS)); - av1_twopass_zero_stats(twopass->total_stats); - av1_twopass_zero_stats(twopass->total_left_stats); - if (!twopass->stats_buf_ctx->stats_in_end) return; - stats = twopass->total_stats; + stats = twopass->stats_buf_ctx->total_stats; *stats = *twopass->stats_buf_ctx->stats_in_end; - *twopass->total_left_stats = *stats; + *twopass->stats_buf_ctx->total_left_stats = *stats; frame_rate = 10000000.0 * stats->count / stats->duration; // Each frame can have a different duration, as the frame rate in the source @@ -2726,9 +2732,6 @@ void av1_init_single_pass_lap(AV1_COMP *cpi) { TWO_PASS *const twopass = &cpi->twopass; - twopass->total_stats = NULL; - twopass->total_left_stats = NULL; - if (!twopass->stats_buf_ctx->stats_in_end) return; // This variable monitors how far behind the second ref update is lagging.
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c index ea4ff9f..433163f 100644 --- a/av1/encoder/ratectrl.c +++ b/av1/encoder/ratectrl.c
@@ -1813,9 +1813,10 @@ static void vbr_rate_correction(AV1_COMP *cpi, int *this_frame_target) { RATE_CONTROL *const rc = &cpi->rc; int64_t vbr_bits_off_target = rc->vbr_bits_off_target; - const int stats_count = cpi->twopass.total_stats != NULL - ? (int)cpi->twopass.total_stats->count - : 0; + const int stats_count = + cpi->twopass.stats_buf_ctx->total_stats != NULL + ? (int)cpi->twopass.stats_buf_ctx->total_stats->count + : 0; const int frame_window = AOMMIN( 16, (int)(stats_count - (int)cpi->common.current_frame.frame_number));