Complete VIDEO-001 through VIDEO-004 software video studies
This commit is contained in:
91
tools/video_report_table.py
Normal file
91
tools/video_report_table.py
Normal file
@@ -0,0 +1,91 @@
|
||||
"""Обновить числовую таблицу VIDEO-001 по сохранённым результатам."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from collections import defaultdict
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
MATRIX = (((320, 240), (5, 10, 15)), ((640, 360), (5, 10, 15)),
|
||||
((640, 480), (5, 10)), ((854, 480), (5, 10)), ((1280, 720), (5,)))
|
||||
|
||||
# Это качественные оценки контрольных кадров, а не результат автоматической метрики.
|
||||
QUALITY = {
|
||||
(320, 240, "jpeg"): "Ближние машины и полоса видны; дальние предметы мелки",
|
||||
(320, 240, "160k"): "Ближние машины и направление видны; мелкие детали ограничены",
|
||||
(320, 240, "320k"): "Почти тот же вид, что при 160k",
|
||||
(640, 360, "jpeg"): "Машины и разметка видны; крупный поток",
|
||||
(640, 360, "160k"): "Машины видны; текстура дороги размыта при движении",
|
||||
(640, 360, "320k"): "Машины, полоса и направление различимы",
|
||||
(640, 480, "jpeg"): "Машины видны; чёрные поля 60 пикселей",
|
||||
(640, 480, "160k"): "Машины видны; поля и размытие деталей",
|
||||
(640, 480, "320k"): "Машины видны; полезная область как 640×360",
|
||||
(854, 480, "jpeg"): "Машины и разметка чётче; крупный поток",
|
||||
(854, 480, "160k"): "Ближние машины видны; дальние детали размыты",
|
||||
(854, 480, "320k"): "Машины, полосы и направление хорошо различимы",
|
||||
(1280, 720, "jpeg"): "Машины и разметка подробны; поток велик",
|
||||
(1280, 720, "160k"): "Машины видны; разрешение не даёт ожидаемой детализации",
|
||||
(1280, 720, "320k"): "Машины и разметка видны; дальние надписи не проверены",
|
||||
}
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--comparison-160k", type=Path, required=True)
|
||||
parser.add_argument("--comparison-320k", type=Path, required=True)
|
||||
parser.add_argument("--report", type=Path, required=True)
|
||||
arguments = parser.parse_args()
|
||||
datasets = {
|
||||
code: json.loads(path.read_text(encoding="utf-8"))
|
||||
for code, path in (("160k", arguments.comparison_160k),
|
||||
("320k", arguments.comparison_320k))
|
||||
}
|
||||
if datasets["160k"]["source_sha256"] != datasets["320k"]["source_sha256"]:
|
||||
raise ValueError("Наборы сравнения используют разные исходные ролики")
|
||||
if datasets["160k"]["windows"] != datasets["320k"]["windows"]:
|
||||
raise ValueError("Наборы сравнения используют разные участки ролика")
|
||||
cases = defaultdict(list)
|
||||
for code, dataset in datasets.items():
|
||||
for case in dataset["cases"]:
|
||||
key = (tuple(case["resolution"]), case["fps"], case["codec"], code)
|
||||
cases[key].append(case)
|
||||
rows = [
|
||||
"| Разрешение | FPS | Кодек | Средний поток | Пик 1 с | Кодирование | "
|
||||
"Декодирование | Качество для оператора | FITS CURRENT RADIO BUDGET |",
|
||||
"|---|---:|---|---:|---:|---:|---:|---|---|",
|
||||
]
|
||||
for resolution, rates in MATRIX:
|
||||
for fps in rates:
|
||||
for codec, code, label, quality_code in (
|
||||
("JPEG_INDEPENDENT", "160k", "JPEG q35", "jpeg"),
|
||||
("H264_LIBX264", "160k", "H.264 160k", "160k"),
|
||||
("H264_LIBX264", "320k", "H.264 320k", "320k"),
|
||||
):
|
||||
pair = cases[(resolution, fps, codec, code)]
|
||||
if len(pair) != 2:
|
||||
raise ValueError(f"Ожидались два участка: {resolution}, {fps}, {label}")
|
||||
average = max(case["average_bitrate_bps"] for case in pair) / 1000
|
||||
peak = max(case["peak_one_second_bitrate_bps"] for case in pair) / 1000
|
||||
encode = max(case["encode_time_per_frame_s"]["mean"] for case in pair) * 1000
|
||||
decode = max(case["decode_time_per_frame_s"]["mean"] for case in pair) * 1000
|
||||
if any(case["radio_screen"]["fits_current_radio_budget"] !=
|
||||
"NO_ON_OBSERVED_BURST_SCREEN" for case in pair):
|
||||
raise ValueError(f"Недостаточно оснований для НЕТ: {resolution}, {fps}, {label}")
|
||||
quality = QUALITY[(*resolution, quality_code)]
|
||||
encode_text = f"{encode:.1f}".replace(".", ",")
|
||||
decode_text = f"{decode:.1f}".replace(".", ",")
|
||||
rows.append(f"| {resolution[0]}×{resolution[1]} | {fps} | {label} | "
|
||||
f"{average:.0f} | {peak:.0f} | "
|
||||
f"{encode_text} | {decode_text} | {quality} | НЕТ |")
|
||||
report = arguments.report.read_text(encoding="utf-8")
|
||||
start = report.index("| Разрешение | FPS | Кодек |")
|
||||
end = report.index("\n\n", start)
|
||||
arguments.report.write_text(report[:start] + "\n".join(rows) + report[end:],
|
||||
encoding="utf-8")
|
||||
print(f"Обновлено строк таблицы: {len(rows) - 2}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user