AOMedia AV1 Codec: Two Pass Mode

| AOMedia AV1 Codec

Functions
Two Pass Mode
Encoder Algorithm » High-level Algorithm

## Functions
static int | has_no_stats_stage (const AV1_COMP *const cpi)
| Check if the current stage has statistics.

## Detailed Description

In two pass mode, the input file is passed into the encoder for a quick first pass, where statistics are gathered. These statistics and the input file are then passed back into the encoder for a second pass. The statistics help the encoder reach the desired bitrate without as much overshooting or undershooting.

During the first pass, the codec will return "stats" packets that contain information useful for the second pass. The caller should concatenate these packets as they are received. In the second pass, the concatenated packets are passed in, along with the frames to encode. During the second pass, "frame" packets are returned that represent the compressed video.

A complete example can be found in `examples/twopass_encoder.c`. Pseudocode is provided below to illustrate the core parts.

During the first pass, the uncompressed frames are passed in and stats information is appended to a byte array.

// For simplicity, assume that there is enough memory in the stats buffer.
// Actual code will want to use a resizable array. stats_len represents
// the length of data already present in the buffer.
void get_stats_data(aom_codec_ctx_t *encoder, char *stats,
size_t *stats_len, bool *got_data) {
const aom_codec_cx_pkt_t *pkt;
aom_codec_iter_t iter = NULL;
while ((pkt = aom_codec_get_cx_data(encoder, &iter))) {
*got_data = true;
if (pkt->kind != AOM_CODEC_STATS_PKT) continue;
memcpy(stats + *stats_len, pkt->data.twopass_stats.buf,
pkt->data.twopass_stats.sz);
*stats_len += pkt->data.twopass_stats.sz;
}
}
void first_pass(char *stats, size_t *stats_len) {
struct aom_codec_enc_cfg first_pass_cfg;
... // Initialize the config as needed.
first_pass_cfg.g_pass = AOM_RC_FIRST_PASS;
aom_codec_ctx_t first_pass_encoder;
... // Initialize the encoder.
while (frame_available) {
// Read in the uncompressed frame, update frame_available
aom_image_t *frame_to_encode = ...;
aom_codec_encode(&first_pass_encoder, img, pts, duration, flags);
get_stats_data(&first_pass_encoder, stats, stats_len);
}
// After all frames have been processed, call aom_codec_encode with
// a NULL ptr repeatedly, until no more data is returned. The NULL
// ptr tells the encoder that no more frames are available.
bool got_data;
do {
got_data = false;
aom_codec_encode(&first_pass_encoder, NULL, pts, duration, flags);
get_stats_data(&first_pass_encoder, stats, stats_len, &got_data);
} while (got_data);
aom_codec_destroy(&first_pass_encoder);
}
aom_image_t
struct aom_image aom_image_t
Image Descriptor.
aom_codec_ctx_t
struct aom_codec_ctx aom_codec_ctx_t
Codec context structure.
aom_codec_destroy
aom_codec_err_t aom_codec_destroy(aom_codec_ctx_t *ctx)
Destroy a codec instance.
aom_codec_iter_t
const void * aom_codec_iter_t
Iterator.
Definition aom_codec.h:305
aom_codec_get_cx_data
const aom_codec_cx_pkt_t * aom_codec_get_cx_data(aom_codec_ctx_t *ctx, aom_codec_iter_t *iter)
Encoded data iterator.
aom_codec_cx_pkt_t
struct aom_codec_cx_pkt aom_codec_cx_pkt_t
Encoder output packet.
aom_codec_encode
aom_codec_err_t aom_codec_encode(aom_codec_ctx_t *ctx, const aom_image_t *img, aom_codec_pts_t pts, unsigned long duration, aom_enc_frame_flags_t flags)
Encode a frame.
AOM_RC_FIRST_PASS
@ AOM_RC_FIRST_PASS
Definition aom_encoder.h:178
AOM_CODEC_STATS_PKT
@ AOM_CODEC_STATS_PKT
Definition aom_encoder.h:111
aom_codec_cx_pkt::kind
enum aom_codec_cx_pkt_kind kind
Definition aom_encoder.h:123
aom_codec_cx_pkt::twopass_stats
aom_fixed_buf_t twopass_stats
Definition aom_encoder.h:140
aom_codec_cx_pkt::data
union aom_codec_cx_pkt::@202210014045072156205127107315337341215221351166 data
aom_codec_enc_cfg
Encoder configuration structure.
Definition aom_encoder.h:387
aom_codec_enc_cfg::g_pass
enum aom_enc_pass g_pass
Multi-pass Encoding Mode.
Definition aom_encoder.h:504
aom_fixed_buf::sz
size_t sz
Definition aom_encoder.h:90
aom_fixed_buf::buf
void * buf
Definition aom_encoder.h:89

During the second pass, the uncompressed frames and the stats are passed into the encoder.

// Write out each encoded frame to the file.
void get_cx_data(aom_codec_ctx_t *encoder, FILE *file,
bool *got_data) {
const aom_codec_cx_pkt_t *pkt;
aom_codec_iter_t iter = NULL;
while ((pkt = aom_codec_get_cx_data(encoder, &iter))) {
*got_data = true;
if (pkt->kind != AOM_CODEC_CX_FRAME_PKT) continue;
fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, file);
}
}
void second_pass(char *stats, size_t stats_len) {
struct aom_codec_enc_cfg second_pass_cfg;
... // Initialize the config file as needed.
second_pass_cfg.g_pass = AOM_RC_LAST_PASS;
cfg.rc_twopass_stats_in.buf = stats;
cfg.rc_twopass_stats_in.sz = stats_len;
aom_codec_ctx_t second_pass_encoder;
... // Initialize the encoder from the config.
FILE *output = fopen("output.obu", "wb");
while (frame_available) {
// Read in the uncompressed frame, update frame_available
aom_image_t *frame_to_encode = ...;
aom_codec_encode(&second_pass_encoder, img, pts, duration, flags);
get_cx_data(&second_pass_encoder, output);
}
// Pass in NULL to flush the encoder.
bool got_data;
do {
got_data = false;
aom_codec_encode(&second_pass_encoder, NULL, pts, duration, flags);
get_cx_data(&second_pass_encoder, output, &got_data);
} while (got_data);
aom_codec_destroy(&second_pass_encoder);
}
AOM_RC_LAST_PASS
@ AOM_RC_LAST_PASS
Definition aom_encoder.h:181
AOM_CODEC_CX_FRAME_PKT
@ AOM_CODEC_CX_FRAME_PKT
Definition aom_encoder.h:110
aom_codec_cx_pkt::sz
size_t sz
Definition aom_encoder.h:127
aom_codec_cx_pkt::frame
struct aom_codec_cx_pkt::@202210014045072156205127107315337341215221351166::@052232317104146204273007241322037340334334344046 frame
aom_codec_cx_pkt::buf
void * buf
Definition aom_encoder.h:126

## Function Documentation

## ◆ has_no_stats_stage()

static int has_no_stats_stage | ( | const AV1_COMP *const | cpi | ) |
| inlinestatic

Check if the current stage has statistics.

Parameters

  [in] | cpi | Top - level encoder instance structure

Returns
  0 if no stats for current stage else 1

References AOM_RC_ONE_PASS, AV1_COMP::compressor_stage, AV1_PRIMARY::lap_enabled, AV1_COMP::oxcf, AV1EncoderConfig::pass, and AV1_COMP::ppi.

Referenced by av1_encode_strategy(), av1_rc_pick_q_and_bounds(), calculate_gf_length(), define_gf_group(), encode_frame_to_data_rate(), encode_rd_sb(), find_next_key_frame(), rc_pick_q_and_bounds(), rc_pick_q_and_bounds_no_stats(), and rc_pick_q_and_bounds_no_stats_cbr().