Add a script for RTC frame size variation analysis

Change-Id: I3ac981ee503e14cf1500263804db1e03969477b4
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index e5491d1..25d8286 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -4497,6 +4497,13 @@
   }
 #endif
 
+#if CONFIG_OUTPUT_FRAME_SIZE
+  FILE *f = fopen("frame_sizes.csv", "a");
+  fprintf(f, "%d,", 8 * (int)cpi_data->frame_size);
+  fprintf(f, "%d\n", cm->quant_params.base_qindex);
+  fclose(f);
+#endif  // CONFIG_OUTPUT_FRAME_SIZE
+
   if (!is_stat_generation_stage(cpi) && !cpi->is_dropped_frame) {
     // Before calling refresh_reference_frames(), copy ppi->ref_frame_map_copy
     // to cm->ref_frame_map for frame_parallel_level 2 frame in a parallel
diff --git a/build/cmake/aom_config_defaults.cmake b/build/cmake/aom_config_defaults.cmake
index eafd26c..f588afb 100644
--- a/build/cmake/aom_config_defaults.cmake
+++ b/build/cmake/aom_config_defaults.cmake
@@ -155,6 +155,8 @@
                    "AV1 experiment: Enable tensorflow lite library.")
 set_aom_config_var(CONFIG_THREE_PASS 0
                    "AV1 experiment: Enable three-pass encoding.")
+set_aom_config_var(CONFIG_OUTPUT_FRAME_SIZE 0
+                   "AV1 experiment: Output frame size information.")
 
 #
 # Variables in this section control optional features of the build system.
diff --git a/tools/frame_size_variation_analyzer.py b/tools/frame_size_variation_analyzer.py
new file mode 100644
index 0000000..5c02319
--- /dev/null
+++ b/tools/frame_size_variation_analyzer.py
@@ -0,0 +1,74 @@
+# RTC frame size variation analyzer
+# Usage:
+# 1. Config with "-DCONFIG_OUTPUT_FRAME_SIZE=1".
+# 2. Build aomenc. Encode a file, and generate output file: frame_sizes.csv
+# 3. Run: python ./frame_size.py frame_sizes.csv target-bitrate fps
+#    Where target-bitrate: Bitrate (kbps), and fps is frame per second.
+#    Example: python ../aom/tools/frame_size_variation_analyzer.py frame_sizes.csv
+#    1000 30
+
+import numpy as np
+import csv
+import sys
+import matplotlib.pyplot as plt
+
+# return the moving average
+def moving_average(x, w):
+  return np.convolve(x, np.ones(w), 'valid') / w
+
+def frame_size_analysis(filename, target_br, fps):
+  tbr = target_br * 1000 / fps
+
+  with open(filename, 'r') as infile:
+    raw_data = list(csv.reader(infile, delimiter=','))
+
+  data = np.array(raw_data).astype(float)
+  fsize = data[:, 0].astype(float)  # frame size
+  qindex = data[:, 1].astype(float)  # qindex
+
+  # Frame bit rate mismatch
+  mismatch = np.absolute(fsize - np.full(fsize.size, tbr))
+
+  # Count how many frames are more than 2.5x of frame target bit rate.
+  tbr_thr = tbr * 2.5
+  cnt = 0
+  idx = np.arange(fsize.size)
+  for i in idx:
+    if fsize[i] > tbr_thr:
+      cnt = cnt + 1
+
+  # Use the 15-frame moving window
+  win = 15
+  avg_fsize = moving_average(fsize, win)
+  win_mismatch = np.absolute(avg_fsize - np.full(avg_fsize.size, tbr))
+
+  print('[Target frame rate (bit)]:', "%.2f"%tbr)
+  print('[Average frame rate (bit)]:', "%.2f"%np.average(fsize))
+  print('[Frame rate standard deviation]:', "%.2f"%np.std(fsize))
+  print('[Max/min frame rate (bit)]:', "%.2f"%np.max(fsize), '/', "%.2f"%np.min(fsize))
+  print('[Average frame rate mismatch (bit)]:', "%.2f"%np.average(mismatch))
+  print('[Number of frames (frame rate > 2.5x of target frame rate)]:', cnt)
+  print(' Moving window size:', win)
+  print('[Moving average frame rate mismatch (bit)]:', "%.2f"%np.average(win_mismatch))
+  print('------------------------------')
+
+  figure, axis = plt.subplots(2)
+  x = np.arange(fsize.size)
+  axis[0].plot(x, fsize, color='blue')
+  axis[0].set_title("frame sizes")
+  axis[1].plot(x, qindex, color='blue')
+  axis[1].set_title("frame qindex")
+  plt.tight_layout()
+
+  # Save the plot
+  plotname = filename + '.png'
+  plt.savefig(plotname)
+  plt.show()
+
+if __name__ == '__main__':
+  if (len(sys.argv) < 4):
+    print(sys.argv[0], 'input_file, target_bitrate, fps')
+    sys.exit()
+  target_br = int(sys.argv[2])
+  fps = int(sys.argv[3])
+  frame_size_analysis(sys.argv[1], target_br, fps)