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;