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));