AV1 levels: add header, display and decode rate
BUG=aomedia:2332
Change-Id: Ic8fd9c447c9d210864bb18f006458d68dfc25bca
diff --git a/av1/encoder/level.c b/av1/encoder/level.c
index 4226a5c..911924f 100644
--- a/av1/encoder/level.c
+++ b/av1/encoder/level.c
@@ -227,6 +227,9 @@
CROPPED_TILE_WIDTH_TOO_SMALL,
CROPPED_TILE_HEIGHT_TOO_SMALL,
TILE_WIDTH_INVALID,
+ FRAME_HEADER_RATE_TOO_HIGH,
+ DISPLAY_RATE_TOO_HIGH,
+ DECODE_RATE_TOO_HIGH,
TARGET_LEVEL_FAIL_IDS
} TARGET_LEVEL_FAIL_ID;
@@ -241,6 +244,9 @@
"The cropped tile width is less than 8",
"The cropped tile height is less than 8",
"The tile width is invalid",
+ "The frame header rate is too high",
+ "The display luma sample rate is too high",
+ "The decoded luma sample rate is too high",
};
static void check_level_constraints(AV1_COMP *cpi, int operating_point_idx,
@@ -298,6 +304,21 @@
fail_id = TILE_WIDTH_INVALID;
break;
}
+
+ if (level_spec->max_header_rate > target_level_spec->max_header_rate) {
+ fail_id = FRAME_HEADER_RATE_TOO_HIGH;
+ break;
+ }
+
+ if (level_spec->max_display_rate > target_level_spec->max_display_rate) {
+ fail_id = DISPLAY_RATE_TOO_HIGH;
+ break;
+ }
+
+ if (level_spec->max_decode_rate > target_level_spec->max_decode_rate) {
+ fail_id = DECODE_RATE_TOO_HIGH;
+ break;
+ }
} while (0);
if (fail_id != TARGET_LEVEL_FAIL_IDS) {
@@ -408,6 +429,35 @@
return num_frames;
}
+// Scan previously encoded frames and update level metrics accordingly.
+static void scan_past_frames(const FrameWindowBuffer *const buffer,
+ int num_frames_to_scan,
+ AV1LevelSpec *const level_spec) {
+ const int num_frames_in_buffer = buffer->num;
+ int index = (buffer->start + num_frames_in_buffer - 1) % FRAME_WINDOW_SIZE;
+ int frame_headers = 0;
+ int64_t display_samples = 0;
+ int64_t decoded_samples = 0;
+ for (int i = 0; i < AOMMIN(num_frames_in_buffer, num_frames_to_scan); ++i) {
+ const FrameRecord *const record = &buffer->buf[index];
+ if (!record->show_existing_frame) {
+ frame_headers += record->frame_header_count;
+ decoded_samples += record->pic_size;
+ }
+ if (record->show_frame) {
+ display_samples += record->pic_size;
+ }
+ --index;
+ if (index < 0) index = FRAME_WINDOW_SIZE - 1;
+ }
+ level_spec->max_header_rate =
+ AOMMAX(level_spec->max_header_rate, frame_headers);
+ level_spec->max_display_rate =
+ AOMMAX(level_spec->max_display_rate, display_samples);
+ level_spec->max_decode_rate =
+ AOMMAX(level_spec->max_decode_rate, decoded_samples);
+}
+
void av1_update_level_info(AV1_COMP *cpi, size_t size, int64_t ts_start,
int64_t ts_end) {
const AV1_COMMON *const cm = &cpi->common;
@@ -428,9 +478,6 @@
// Count the number of frames encoded in the past 1 second.
const int encoded_frames_in_last_second =
show_frame ? count_frames(buffer, TICKS_PER_SEC) : 0;
- // TODO(huisu@): calculate stats using the info. of the
- // encoded_frames_in_last_sescond frames in frame_window_buffer.
- (void)encoded_frames_in_last_second;
int max_tile_size;
int min_cropped_tile_width;
@@ -489,6 +536,10 @@
AOMMIN(level_spec->min_cropped_tile_height, min_cropped_tile_height);
level_spec->tile_width_is_valid &= tile_width_is_valid;
+ if (show_frame) {
+ scan_past_frames(buffer, encoded_frames_in_last_second, level_spec);
+ }
+
// TODO(kyslov@) These are needed for further level stat calculations
(void)compression_ratio;
(void)ts_start;