mirror of
https://github.com/storytold/filmcraft.git
synced 2026-10-24 10:10:05 -06:00
100 lines
4.9 KiB
Python
100 lines
4.9 KiB
Python
#!/usr/bin/env python3
|
||
"""Extract the VP9 constant tables from the text of the public VP9 Bitstream & Decoding Process
|
||
Specification (v0.6, WebM project / Google).
|
||
|
||
Usage:
|
||
curl -L -o vp9.pdf 'https://storage.googleapis.com/downloads.webmproject.org/docs/vp9/vp9-bitstream-specification-v0.6-20160331-draft.pdf'
|
||
pdftotext -layout vp9.pdf vp9.txt
|
||
python3 extract_tables.py vp9.txt > ../src/spec_tables.rs
|
||
|
||
Only the specification text is read. Every table is emitted flat (row-major, as printed) with its
|
||
element count checked against the declared dimensions.
|
||
"""
|
||
import re
|
||
import sys
|
||
|
||
text = open(sys.argv[1], encoding="utf-8").read().replace("−", "-").replace("–", "-")
|
||
lines = [l for l in text.split("\n") if "Copyright" not in l and "VP9 Bitstream & Decoding Process Specification" not in l]
|
||
text = "\n".join(lines)
|
||
|
||
|
||
def table(name, count):
|
||
"""Integers of the table `name[...] = { ... }` (the last definition in the text)."""
|
||
starts = [m.start() for m in re.finditer(r"\b%s\s*\[" % re.escape(name), text)]
|
||
for s in reversed(starts):
|
||
eq = text.find("=", s)
|
||
brace = text.find("{", s)
|
||
if eq < 0 or brace < 0 or eq > brace or text[s:eq].count("\n") > 2:
|
||
continue
|
||
depth = 0
|
||
i = brace
|
||
while True:
|
||
ch = text[i]
|
||
if ch == "{":
|
||
depth += 1
|
||
elif ch == "}":
|
||
depth -= 1
|
||
if depth == 0:
|
||
break
|
||
i += 1
|
||
body = text[brace:i]
|
||
body = re.sub(r"//[^\n]*", "", body)
|
||
body = re.sub(r"/\*.*?\*/", "", body, flags=re.S)
|
||
vals = [int(v) for v in re.findall(r"-?\d+", body)]
|
||
assert len(vals) == count, (name, len(vals), count)
|
||
return vals
|
||
raise AssertionError("table not found: " + name)
|
||
|
||
|
||
def emit(rust_name, ty, vals, per_line=16):
|
||
print("pub const %s: [%s; %d] = [" % (rust_name, ty, len(vals)))
|
||
for k in range(0, len(vals), per_line):
|
||
print(" " + ", ".join(str(v) for v in vals[k:k + per_line]) + ",")
|
||
print("];")
|
||
print()
|
||
|
||
|
||
print("// Generated by tools/extract_tables.py from the VP9 Bitstream & Decoding Process Specification")
|
||
print("// v0.6 (section numbers refer to that document). Do not edit by hand.")
|
||
print()
|
||
|
||
emit("INV_MAP_TABLE", "u8", table("inv_map_table", 255))
|
||
emit("SUBPEL_FILTERS", "i16", table("subpel_filters", 4 * 16 * 8), 8)
|
||
emit("DC_QLOOKUP", "i32", table("dc_qlookup", 3 * 256))
|
||
emit("AC_QLOOKUP", "i32", table("ac_qlookup", 3 * 256))
|
||
emit("COS64_LOOKUP", "i32", table("cos64_lookup", 33))
|
||
for n, c in [("4x4", 16), ("8x8", 64), ("16x16", 256)]:
|
||
for kind in ["default", "col", "row"]:
|
||
emit("%s_SCAN_%s" % (kind.upper(), n.upper()), "u16", table("%s_scan_%s" % (kind, n), c))
|
||
emit("DEFAULT_SCAN_32X32", "u16", table("default_scan_32x32", 1024))
|
||
emit("COEFBAND_4X4", "u8", table("coefband_4x4", 16))
|
||
emit("COEFBAND_8X8PLUS", "u8", table("coefband_8x8plus", 1024))
|
||
emit("ENERGY_CLASS", "u8", table("energy_class", 12))
|
||
emit("PARETO_TABLE", "u8", table("pareto_table", 128 * 8), 8)
|
||
emit("MV_REF_BLOCKS", "i8", table("mv_ref_blocks", 13 * 8 * 2))
|
||
emit("MODE_2_COUNTER", "u8", table("mode_2_counter", 14))
|
||
emit("KF_PARTITION_PROBS", "u8", table("kf_partition_probs", 16 * 3), 3)
|
||
emit("KF_Y_MODE_PROBS", "u8", table("kf_y_mode_probs", 10 * 10 * 9), 9)
|
||
emit("KF_UV_MODE_PROBS", "u8", table("kf_uv_mode_probs", 10 * 9), 9)
|
||
emit("DEFAULT_PARTITION_PROBS", "u8", table("default_partition_probs", 16 * 3), 3)
|
||
emit("DEFAULT_Y_MODE_PROBS", "u8", table("default_y_mode_probs", 4 * 9), 9)
|
||
emit("DEFAULT_UV_MODE_PROBS", "u8", table("default_uv_mode_probs", 10 * 9), 9)
|
||
emit("DEFAULT_SKIP_PROB", "u8", table("default_skip_prob", 3))
|
||
emit("DEFAULT_IS_INTER_PROB", "u8", table("default_is_inter_prob", 4))
|
||
emit("DEFAULT_COMP_MODE_PROB", "u8", table("default_comp_mode_prob", 5))
|
||
emit("DEFAULT_COMP_REF_PROB", "u8", table("default_comp_ref_prob", 5))
|
||
emit("DEFAULT_SINGLE_REF_PROB", "u8", table("default_single_ref_prob", 10), 2)
|
||
emit("DEFAULT_MV_SIGN_PROB", "u8", table("default_mv_sign_prob", 2))
|
||
emit("DEFAULT_MV_BITS_PROB", "u8", table("default_mv_bits_prob", 20), 10)
|
||
emit("DEFAULT_MV_CLASS0_BIT_PROB", "u8", table("default_mv_class0_bit_prob", 2))
|
||
emit("DEFAULT_TX_PROBS", "u8", table("default_tx_probs", 4 * 2 * 3), 3)
|
||
emit("DEFAULT_INTER_MODE_PROBS", "u8", table("default_inter_mode_probs", 7 * 3), 3)
|
||
emit("DEFAULT_INTERP_FILTER_PROBS", "u8", table("default_interp_filter_probs", 8), 2)
|
||
emit("DEFAULT_MV_JOINT_PROBS", "u8", table("default_mv_joint_probs", 3))
|
||
emit("DEFAULT_MV_CLASS_PROBS", "u8", table("default_mv_class_probs", 20), 10)
|
||
emit("DEFAULT_MV_CLASS0_FR_PROBS", "u8", table("default_mv_class0_fr_probs", 12), 3)
|
||
emit("DEFAULT_MV_CLASS0_HP_PROB", "u8", table("default_mv_class0_hp_prob", 2))
|
||
emit("DEFAULT_MV_FR_PROBS", "u8", table("default_mv_fr_probs", 6), 3)
|
||
emit("DEFAULT_MV_HP_PROB", "u8", table("default_mv_hp_prob", 2))
|
||
emit("DEFAULT_COEF_PROBS", "u8", table("default_coef_probs", 4 * 2 * 2 * 6 * 6 * 3), 3)
|