Add data structure to store frame info.
Store frame info. in a circular buffer for level stats calculation.
For example, it can be used to retrieve the number of encoded frame
headers in a 1-second rolling window.
BUG=aomedia:2332
Change-Id: I43228b24b611e9c3b189f2b88597c18acb87b51e
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index d5259a2..bf02394 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -989,12 +989,14 @@
// frame_component_time[] are initialized to zero at beginning of each frame.
uint64_t frame_component_time[kTimingComponents];
#endif
- // level info and flags
+
+ // The following data are for AV1 bitstream levels.
AV1_LEVEL target_seq_level_idx[MAX_NUM_OPERATING_POINTS];
int keep_level_stats;
AV1LevelInfo level_info[MAX_NUM_OPERATING_POINTS];
// Count the number of OBU_FRAME and OBU_FRAME_HEADER for level calculation.
int frame_header_count;
+ FrameWindowBuffer frame_window_buffer;
} AV1_COMP;
typedef struct {
diff --git a/av1/encoder/level.c b/av1/encoder/level.c
index 02bc112..4226a5c 100644
--- a/av1/encoder/level.c
+++ b/av1/encoder/level.c
@@ -364,6 +364,50 @@
}
}
+static int store_frame_record(int64_t ts_start, int64_t ts_end, int pic_size,
+ int frame_header_count, int show_frame,
+ int show_existing_frame,
+ FrameWindowBuffer *const buffer) {
+ if (buffer->num < FRAME_WINDOW_SIZE) {
+ ++buffer->num;
+ } else {
+ buffer->start = (buffer->start + 1) % FRAME_WINDOW_SIZE;
+ }
+ const int new_idx = (buffer->start + buffer->num - 1) % FRAME_WINDOW_SIZE;
+ FrameRecord *const record = &buffer->buf[new_idx];
+ record->ts_start = ts_start;
+ record->ts_end = ts_end;
+ record->pic_size = pic_size;
+ record->frame_header_count = frame_header_count;
+ record->show_frame = show_frame;
+ record->show_existing_frame = show_existing_frame;
+
+ return new_idx;
+}
+
+// Count the number of frames encoded in the last "duration" ticks, in display
+// time.
+static int count_frames(const FrameWindowBuffer *const buffer,
+ int64_t duration) {
+ const int current_idx = (buffer->start + buffer->num - 1) % FRAME_WINDOW_SIZE;
+ // Assume current frame is shown frame.
+ assert(buffer->buf[current_idx].show_frame);
+
+ const int64_t current_time = buffer->buf[current_idx].ts_end;
+ const int64_t time_limit = AOMMAX(current_time - duration, 0);
+ int num_frames = 1;
+ int index = current_idx - 1;
+ for (int i = buffer->num - 2; i >= 0; --i, --index, ++num_frames) {
+ if (index < 0) index = FRAME_WINDOW_SIZE - 1;
+ const FrameRecord *const record = &buffer->buf[index];
+ if (!record->show_frame) continue;
+ const int64_t ts_start = record->ts_start;
+ if (ts_start < time_limit) break;
+ }
+
+ return num_frames;
+}
+
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;
@@ -373,6 +417,20 @@
const int tile_rows = cm->tile_rows;
const int tiles = tile_cols * tile_rows;
const int luma_pic_size = upscaled_width * height;
+ const int frame_header_count = cpi->frame_header_count;
+ const int show_frame = cm->show_frame;
+ const int show_existing_frame = cm->show_existing_frame;
+
+ // Store info. of current frame into FrameWindowBuffer.
+ FrameWindowBuffer *const buffer = &cpi->frame_window_buffer;
+ store_frame_record(ts_start, ts_end, luma_pic_size, frame_header_count,
+ show_frame, show_existing_frame, buffer);
+ // 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;
@@ -399,7 +457,6 @@
const SequenceHeader *const seq = &cm->seq_params;
const int temporal_layer_id = cm->temporal_layer_id;
const int spatial_layer_id = cm->spatial_layer_id;
-
// update level_stats
// TODO(kyslov@) fix the implementation according to buffer model
for (int i = 0; i < seq->operating_points_cnt_minus_1 + 1; ++i) {
@@ -412,7 +469,7 @@
AV1LevelStats *const level_stats = &level_info->level_stats;
level_stats->total_compressed_size += frame_compressed_size;
- if (cm->show_frame) level_stats->total_time_encoded = total_time_encoded;
+ if (show_frame) level_stats->total_time_encoded = total_time_encoded;
// update level_spec
// TODO(kyslov@) update all spec fields
diff --git a/av1/encoder/level.h b/av1/encoder/level.h
index 18f0de5..1692fad 100644
--- a/av1/encoder/level.h
+++ b/av1/encoder/level.h
@@ -37,6 +37,23 @@
double high_cr;
} AV1LevelSpec;
+typedef struct {
+ int64_t ts_start;
+ int64_t ts_end;
+ int pic_size;
+ int frame_header_count;
+ int show_frame;
+ int show_existing_frame;
+} FrameRecord;
+
+// Record frame info. in a rolling window.
+#define FRAME_WINDOW_SIZE 256
+typedef struct {
+ FrameRecord buf[FRAME_WINDOW_SIZE];
+ int num; // Number of FrameRecord stored in the buffer.
+ int start; // Buffer index of the first FrameRecord.
+} FrameWindowBuffer;
+
// Used to keep track of AV1 Level Stats. Currently unimplemented.
typedef struct {
uint64_t total_compressed_size;