92 lines
5.5 KiB
Python
92 lines
5.5 KiB
Python
"""Обновить числовую таблицу 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()
|