AV1 levels: change max bitrate constraint
The spec does not spicify clearly how the max bitrate constraint should be
applied. Before this patch, we checked the bitrate of any 1-second window.
With this patch, we check the average bitrate across the whole sequence
instead. The bitrate spikes can be controlled by the (per frame) minimum
compression ratio.
BUG=aomedia:2332
Change-Id: I7f6bd8abf368074b72c83da9a0fcd67a82c0ac98
diff --git a/av1/encoder/level.c b/av1/encoder/level.c
index a182268..4b88631 100644
--- a/av1/encoder/level.c
+++ b/av1/encoder/level.c
@@ -747,7 +747,7 @@
static TARGET_LEVEL_FAIL_ID check_level_constraints(
const AV1LevelInfo *const level_info, AV1_LEVEL level, int tier,
- int is_still_picture, BITSTREAM_PROFILE profile) {
+ int is_still_picture, BITSTREAM_PROFILE profile, int check_bitrate) {
const DECODER_MODEL *const decoder_model = &level_info->decoder_models[level];
const DECODER_MODEL_STATUS decoder_model_status = decoder_model->status;
if (decoder_model_status != DECODER_MODEL_OK &&
@@ -851,11 +851,16 @@
break;
}
- const double max_bitrate =
- get_max_bitrate(target_level_spec, tier, profile);
- if ((double)level_stats->max_bitrate > max_bitrate) {
- fail_id = BITRATE_TOO_HIGH;
- break;
+ if (check_bitrate) {
+ // Check average bitrate instead of max_bitrate.
+ const double bitrate_limit =
+ get_max_bitrate(target_level_spec, tier, profile);
+ const double avg_bitrate = level_stats->total_compressed_size * 8.0 /
+ level_stats->total_time_encoded;
+ if (avg_bitrate > bitrate_limit) {
+ fail_id = BITRATE_TOO_HIGH;
+ break;
+ }
}
if (target_level_spec->level > SEQ_LEVEL_5_1) {
@@ -1083,8 +1088,8 @@
level_stats->min_frame_width = AOMMIN(level_stats->min_frame_width, width);
level_stats->min_frame_height =
AOMMIN(level_stats->min_frame_height, height);
- if (show_frame) level_stats->total_time_encoded = total_time_encoded;
level_stats->min_cr = AOMMIN(level_stats->min_cr, compression_ratio);
+ level_stats->total_compressed_size += (double)size;
// update level_spec
// TODO(kyslov@) update all spec fields
@@ -1108,6 +1113,7 @@
show_frame ? count_frames(buffer, TICKS_PER_SEC) : 0;
scan_past_frames(buffer, encoded_frames_in_last_second, level_spec,
level_stats);
+ level_stats->total_time_encoded = total_time_encoded;
}
DECODER_MODEL *const decoder_models = level_info->decoder_models;
@@ -1120,7 +1126,7 @@
if (target_level < SEQ_LEVELS) {
const int tier = seq_params->tier[i];
const TARGET_LEVEL_FAIL_ID fail_id = check_level_constraints(
- level_info, target_level, tier, is_still_picture, profile);
+ level_info, target_level, tier, is_still_picture, profile, 0);
if (fail_id != TARGET_LEVEL_OK) {
const int target_level_major = 2 + (target_level >> 2);
const int target_level_minor = target_level & 3;
@@ -1145,7 +1151,7 @@
assert(level_info != NULL);
for (int level = 0; level < SEQ_LEVELS; ++level) {
const TARGET_LEVEL_FAIL_ID fail_id = check_level_constraints(
- level_info, level, tier, is_still_picture, profile);
+ level_info, level, tier, is_still_picture, profile, 1);
if (fail_id == TARGET_LEVEL_OK) {
seq_level_idx[op] = level;
break;
diff --git a/av1/encoder/level.h b/av1/encoder/level.h
index 2af9b2d..e826554 100644
--- a/av1/encoder/level.h
+++ b/av1/encoder/level.h
@@ -54,7 +54,7 @@
} FrameWindowBuffer;
typedef struct {
- int max_bitrate; // In bps.
+ int max_bitrate; // Max bitrate in any 1-second window, in bps.
int max_tile_size;
int max_superres_tile_width;
int min_cropped_tile_width;
@@ -62,7 +62,8 @@
int tile_width_is_valid;
int min_frame_width;
int min_frame_height;
- double total_time_encoded;
+ double total_compressed_size; // In bytes.
+ double total_time_encoded; // In seconds.
double min_cr;
} AV1LevelStats;