Commit 74021a5a authored by Rostislav Pehlivanov's avatar Rostislav Pehlivanov

Implement twopass support for the xiphrc system

This commit implements support for twopass encoding using the xiphrc
experimental rate control system. Most of the code and logic comes
from the theora project encoder.

Currently support is limited to the bitrate targeting mode of the
rate control system and while it does visibly improve quality and does
bring rate closer to the target than the one pass mode there's still
tuning and bug fixing to be done.

Change-Id: Iae0d65bbce5ddfbb95b436e2238a43d6100a23b3
parent f0fbf9d9
......@@ -293,13 +293,16 @@ static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx,
ERROR("Option --tune=ssim is not currently supported in AV1.");
if (cfg->g_pass == AOM_RC_LAST_PASS) {
#if !CONFIG_XIPHRC
const size_t packet_sz = sizeof(FIRSTPASS_STATS);
const int n_packets = (int)(cfg->rc_twopass_stats_in.sz / packet_sz);
const FIRSTPASS_STATS *stats;
#endif
if (cfg->rc_twopass_stats_in.buf == NULL)
ERROR("rc_twopass_stats_in.buf not set.");
#if !CONFIG_XIPHRC
if (cfg->rc_twopass_stats_in.sz % packet_sz)
ERROR("rc_twopass_stats_in.sz indicates truncated packet.");
......@@ -311,6 +314,7 @@ static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx,
if ((int)(stats->count + 0.5) != n_packets - 1)
ERROR("rc_twopass_stats_in missing EOS stats packet");
#endif
}
#if !CONFIG_AOM_HIGHBITDEPTH
......
......@@ -2187,6 +2187,7 @@ AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf,
cpi->od_rc.keyframe_rate = oxcf->key_freq;
cpi->od_rc.goldenframe_rate = FIXED_GF_INTERVAL;
cpi->od_rc.altref_rate = 25;
cpi->od_rc.firstpass_quant = 1;
cpi->od_rc.bit_depth = cm->bit_depth;
cpi->od_rc.minq = oxcf->best_allowed_q;
cpi->od_rc.maxq = oxcf->worst_allowed_q;
......@@ -2314,6 +2315,12 @@ AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf,
kf_list = fopen("kf_list.stt", "w");
#endif
#if CONFIG_XIPHRC
if (oxcf->pass == 2) {
cpi->od_rc.twopass_allframes_buf = oxcf->two_pass_stats_in.buf;
cpi->od_rc.twopass_allframes_buf_size = oxcf->two_pass_stats_in.sz;
}
#else
if (oxcf->pass == 1) {
av1_init_first_pass(cpi);
} else if (oxcf->pass == 2) {
......@@ -2339,6 +2346,7 @@ AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf,
av1_init_second_pass(cpi);
}
#endif
init_upsampled_ref_frame_bufs(cpi);
......@@ -3972,9 +3980,11 @@ static void set_frame_size(AV1_COMP *cpi) {
}
}
#if !CONFIG_XIPHRC
if (oxcf->pass == 2) {
av1_set_target_rate(cpi);
}
#endif
alloc_frame_mvs(cm, cm->new_fb_idx);
......@@ -4705,7 +4715,7 @@ static void make_update_tile_list_enc(AV1_COMP *cpi, const int tile_rows,
#endif
static void encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size,
uint8_t *dest,
uint8_t *dest, int skip_adapt,
unsigned int *frame_flags) {
AV1_COMMON *const cm = &cpi->common;
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
......@@ -4951,6 +4961,8 @@ static void encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size,
// Build the bitstream
av1_pack_bitstream(cpi, dest, size);
if (skip_adapt) return;
#if CONFIG_REFERENCE_BUFFER
{
int i;
......@@ -5099,7 +5111,7 @@ static void encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size,
}
static void Pass0Encode(AV1_COMP *cpi, size_t *size, uint8_t *dest,
unsigned int *frame_flags) {
int skip_adapt, unsigned int *frame_flags) {
#if CONFIG_XIPHRC
int64_t ip_count;
int frame_type, is_golden, is_altref;
......@@ -5132,12 +5144,13 @@ static void Pass0Encode(AV1_COMP *cpi, size_t *size, uint8_t *dest,
av1_rc_get_one_pass_vbr_params(cpi);
}
#endif
encode_frame_to_data_rate(cpi, size, dest, frame_flags);
encode_frame_to_data_rate(cpi, size, dest, skip_adapt, frame_flags);
}
#if !CONFIG_XIPHRC
static void Pass2Encode(AV1_COMP *cpi, size_t *size, uint8_t *dest,
unsigned int *frame_flags) {
encode_frame_to_data_rate(cpi, size, dest, frame_flags);
encode_frame_to_data_rate(cpi, size, dest, 0, frame_flags);
#if CONFIG_EXT_REFS
// Do not do post-encoding update for those frames that do not have a spot in
......@@ -5151,6 +5164,7 @@ static void Pass2Encode(AV1_COMP *cpi, size_t *size, uint8_t *dest,
av1_twopass_postencode_update(cpi);
#endif // CONFIG_EXT_REFS
}
#endif
static void init_ref_frame_bufs(AV1_COMMON *cm) {
int i;
......@@ -5673,7 +5687,9 @@ int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags,
} else {
*size = 0;
if (flush && oxcf->pass == 1 && !cpi->twopass.first_pass_done) {
#if !CONFIG_XIPHRC
#if CONFIG_XIPHRC
od_enc_rc_2pass_out(&cpi->od_rc, cpi->output_pkt_list, 1);
#else
av1_end_first_pass(cpi); /* get last stats packet */
#endif
cpi->twopass.first_pass_done = 1;
......@@ -5725,12 +5741,15 @@ int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags,
cpi->frame_flags = *frame_flags;
if (oxcf->pass == 2) {
#if !CONFIG_XIPHRC
#if CONFIG_XIPHRC
if (od_enc_rc_2pass_in(&cpi->od_rc) < 0) return -1;
}
#else
av1_rc_get_second_pass_params(cpi);
#endif
} else if (oxcf->pass == 1) {
set_frame_size(cpi);
}
#endif
if (cpi->oxcf.pass != 0 || frame_is_intra_only(cm) == 1) {
for (i = 0; i < TOTAL_REFS_PER_FRAME; ++i)
......@@ -5749,6 +5768,23 @@ int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags,
}
#endif
#if CONFIG_XIPHRC
if (oxcf->pass == 1) {
size_t tmp;
if (cpi->od_rc.cur_frame == 0) Pass0Encode(cpi, &tmp, dest, 1, frame_flags);
cpi->od_rc.firstpass_quant = cpi->od_rc.target_quantizer;
Pass0Encode(cpi, &tmp, dest, 0, frame_flags);
od_enc_rc_2pass_out(&cpi->od_rc, cpi->output_pkt_list, 0);
} else if (oxcf->pass == 2) {
Pass0Encode(cpi, size, dest, 0, frame_flags);
} else {
if (cpi->od_rc.cur_frame == 0) {
size_t tmp;
Pass0Encode(cpi, &tmp, dest, 1, frame_flags);
}
Pass0Encode(cpi, size, dest, 0, frame_flags);
}
#else
if (oxcf->pass == 1) {
cpi->td.mb.e_mbd.lossless[0] = is_lossless_requested(oxcf);
av1_first_pass(cpi, source);
......@@ -5756,8 +5792,9 @@ int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags,
Pass2Encode(cpi, size, dest, frame_flags);
} else {
// One pass encode
Pass0Encode(cpi, size, dest, frame_flags);
Pass0Encode(cpi, size, dest, 0, frame_flags);
}
#endif
if (!cm->error_resilient_mode)
cm->frame_contexts[cm->frame_context_idx] = *cm->fc;
......
This diff is collapsed.
......@@ -13,6 +13,7 @@
#define _ratectrl_xiph_H (1)
#include "av1/encoder/ratectrl.h"
#include "aom/internal/aom_codec_internal.h"
/*Frame types.*/
#define OD_I_FRAME (0)
......@@ -48,6 +49,12 @@
conversion (6.235 * 2^45) */
#define OD_LOG_QUANTIZER_OFFSET_Q45 (0x0000C7851EB851ECLL)
#define OD_RC_2PASS_MAGIC (0x53015641) /* [A, V, 1, S] in little endian */
#define OD_RC_2PASS_SUMMARY_SZ (4 + 1 + (4 + 4 + 8) * OD_FRAME_NSUBTYPES)
#define OD_RC_2PASS_PACKET_SZ (1 + 4)
#define OD_RC_2PASS_MIN (OD_RC_2PASS_PACKET_SZ + OD_RC_2PASS_SUMMARY_SZ)
#define OD_RC_2PASS_VERSION (1)
/*A 2nd order low-pass Bessel follower.
We use this for rate control because it has fast reaction time, but is
critically damped.*/
......@@ -58,6 +65,14 @@ typedef struct od_iir_bessel2 {
int32_t y[2];
} od_iir_bessel2;
/* The 2-pass metrics associated with a single frame. */
typedef struct od_frame_metrics {
/*The log base 2 of the scale factor for this frame in Q24 format.*/
int64_t log_scale;
/*The frame type from pass 1.*/
unsigned frame_type : 1;
} od_frame_metrics;
/*Rate control setup and working state information.*/
typedef struct od_rc_state {
/* Image format */
......@@ -83,6 +98,26 @@ typedef struct od_rc_state {
int maxq;
/* Min Q */
int minq;
/* Quantizer to use for the first pass */
int firstpass_quant;
/* 2-pass metrics */
od_frame_metrics cur_metrics;
/* 2-pass state */
int64_t scale_sum[OD_FRAME_NSUBTYPES];
int nframes[OD_FRAME_NSUBTYPES];
/* 2-pass bytestream reader/writer context */
uint8_t *twopass_buffer;
int twopass_buffer_bytes;
/* Pass 1 stats packet storage */
uint8_t firstpass_buffer[OD_RC_2PASS_SUMMARY_SZ];
/* Every state packet from the first pass in a single buffer */
uint8_t *twopass_allframes_buf;
size_t twopass_allframes_buf_size;
/* Actual returned quantizer */
int target_quantizer;
......@@ -157,4 +192,9 @@ int od_frame_type(od_rc_state *rc, int64_t coding_frame_count, int *is_golden,
int od_enc_rc_resize(od_rc_state *rc);
int od_enc_rc_2pass_out(od_rc_state *rc, struct aom_codec_pkt_list *pkt_list,
int summary);
int od_enc_rc_2pass_in(od_rc_state *rc);
#endif
......@@ -567,7 +567,11 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi) {
if (oxcf->mode == REALTIME)
set_rt_speed_feature(cpi, sf, oxcf->speed, oxcf->content);
else if (oxcf->mode == GOOD)
else if (oxcf->mode == GOOD
#if CONFIG_XIPHRC
|| oxcf->pass == 1
#endif
)
set_good_speed_feature(cpi, cm, sf, oxcf->speed);
// sf->partition_search_breakout_dist_thr is set assuming max 64x64
......@@ -607,9 +611,11 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi) {
}
}
#if !CONFIG_XIPHRC
// Slow quant, dct and trellis not worthwhile for first pass
// so make sure they are always turned off.
if (oxcf->pass == 1) sf->optimize_coefficients = 0;
#endif
// No recode for 1 pass.
if (oxcf->pass == 0) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment