| #!/usr/bin/python3 | 
 | ## | 
 | ## Copyright (c) 2022, Alliance for Open Media. All rights reserved. | 
 | ## | 
 | ## This source code is subject to the terms of the BSD 2 Clause License and | 
 | ## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License | 
 | ## was not distributed with this source code in the LICENSE file, you can | 
 | ## obtain it at www.aomedia.org/license/software. If the Alliance for Open | 
 | ## Media Patent License 1.0 was not distributed with this source code in the | 
 | ## PATENTS file, you can obtain it at www.aomedia.org/license/patent. | 
 | ## | 
 | """ Analyze the log generated by experimental flag CONFIG_RATECTRL_LOG.""" | 
 |  | 
 | import matplotlib.pyplot as plt | 
 | import os | 
 |  | 
 |  | 
 | def get_file_basename(filename): | 
 |   return filename.split(".")[0] | 
 |  | 
 |  | 
 | def parse_log(log_file): | 
 |   data_list = [] | 
 |   with open(log_file) as fp: | 
 |     for line in fp: | 
 |       dic = {} | 
 |       word_ls = line.split() | 
 |       i = 0 | 
 |       while i < len(word_ls): | 
 |         dic[word_ls[i]] = float(word_ls[i + 1]) | 
 |         i += 2 | 
 |       data_list.append(dic) | 
 |     fp.close() | 
 |   return data_list | 
 |  | 
 |  | 
 | def extract_data(data_list, name): | 
 |   arr = [] | 
 |   for data in data_list: | 
 |     arr.append(data[name]) | 
 |   return arr | 
 |  | 
 |  | 
 | def visualize_q_indices(exp_summary, exp_list, fig_path=None): | 
 |   for exp in exp_list: | 
 |     data = parse_log(exp["log"]) | 
 |     q_indices = extract_data(data, "q") | 
 |     plt.title(exp_summary) | 
 |     plt.xlabel("frame_coding_idx") | 
 |     plt.ylabel("q_index") | 
 |     plt.plot(q_indices, marker=".", label=exp["label"]) | 
 |   plt.legend() | 
 |   if fig_path: | 
 |     plt.savefig(fig_path) | 
 |   else: | 
 |     plt.show() | 
 |   plt.clf() | 
 |  | 
 |  | 
 | def get_rc_type_from_exp_type(exp_type): | 
 |   if exp_type == "Q_3P": | 
 |     return "q" | 
 |   return "vbr" | 
 |  | 
 |  | 
 | def test_video(exe_name, input, exp_type, level, log=None, limit=150): | 
 |   basic_cmd = ("--test-decode=warn --threads=0 --profile=0 --min-q=0 --max-q=63" | 
 |                " --auto-alt-ref=1 --kf-max-dist=160 --kf-min-dist=0 " | 
 |                "--drop-frame=0 --static-thresh=0 --minsection-pct=0 " | 
 |                "--maxsection-pct=2000 --arnr-maxframes=7 --arnr-strength=5 " | 
 |                "--sharpness=0 --undershoot-pct=100 --overshoot-pct=100 " | 
 |                "--frame-parallel=0 --tile-columns=0 --cpu-used=3 " | 
 |                "--lag-in-frames=48 --psnr") | 
 |   rc_type = get_rc_type_from_exp_type(exp_type) | 
 |   rc_cmd = "--end-usage=" + rc_type | 
 |   level_cmd = "" | 
 |   if rc_type == "q": | 
 |     level_cmd += "--cq-level=" + str(level) | 
 |   elif rc_type == "vbr": | 
 |     level_cmd += "--target-bitrate=" + str(level) | 
 |   limit_cmd = "--limit=" + str(limit) | 
 |   passes_cmd = "--passes=3 --second-pass-log=second_pass_log" | 
 |   output_cmd = "-o test.webm" | 
 |   input_cmd = "~/data/" + input | 
 |   log_cmd = "" | 
 |   if log != None: | 
 |     log_cmd = ">" + log | 
 |   cmd_ls = [ | 
 |       exe_name, basic_cmd, rc_cmd, level_cmd, limit_cmd, passes_cmd, output_cmd, | 
 |       input_cmd, log_cmd | 
 |   ] | 
 |   cmd = " ".join(cmd_ls) | 
 |   os.system(cmd) | 
 |  | 
 |  | 
 | def gen_ratectrl_log(test_case): | 
 |   exe = test_case["exe"] | 
 |   video = test_case["video"] | 
 |   exp_type = test_case["exp_type"] | 
 |   level = test_case["level"] | 
 |   log = test_case["log"] | 
 |   test_video(exe, video, exp_type, level, log=log, limit=150) | 
 |   return log | 
 |  | 
 |  | 
 | def gen_test_case(exp_type, dataset, videoname, level, log_dir=None): | 
 |   test_case = {} | 
 |   exe = "./aomenc_bl" | 
 |   if exp_type == "BA_3P": | 
 |     exe = "./aomenc_ba" | 
 |   test_case["exe"] = exe | 
 |  | 
 |   video = os.path.join(dataset, videoname) | 
 |   test_case["video"] = video | 
 |   test_case["exp_type"] = exp_type | 
 |   test_case["level"] = level | 
 |  | 
 |   video_basename = get_file_basename(videoname) | 
 |   log = ".".join([dataset, video_basename, exp_type, str(level)]) | 
 |   if log_dir != None: | 
 |     log = os.path.join(log_dir, log) | 
 |   test_case["log"] = log | 
 |   return test_case | 
 |  | 
 |  | 
 | def run_ratectrl_exp(exp_config): | 
 |   fp = open(exp_config) | 
 |   log_dir = "./lowres_rc_log" | 
 |   fig_dir = "./lowres_rc_fig" | 
 |   dataset = "lowres" | 
 |   for line in fp: | 
 |     word_ls = line.split() | 
 |     dataset = word_ls[0] | 
 |     videoname = word_ls[1] | 
 |     exp_type_ls = ["VBR_3P", "BA_3P"] | 
 |     level_ls = [int(v) for v in word_ls[2:4]] | 
 |     exp_ls = [] | 
 |     for i in range(len(exp_type_ls)): | 
 |       exp_type = exp_type_ls[i] | 
 |       test_case = gen_test_case(exp_type, dataset, videoname, level_ls[i], | 
 |                                 log_dir) | 
 |       log = gen_ratectrl_log(test_case) | 
 |       exp = {} | 
 |       exp["log"] = log | 
 |       exp["label"] = exp_type | 
 |       exp_ls.append(exp) | 
 |     video_basename = get_file_basename(videoname) | 
 |     fig_path = os.path.join(fig_dir, video_basename + ".png") | 
 |     visualize_q_indices(video_basename, exp_ls, fig_path) | 
 |   fp.close() | 
 |  | 
 |  | 
 | if __name__ == "__main__": | 
 |   run_ratectrl_exp("exp_rc_config") |