Add Avisynth video encoding workflow
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fractions import Fraction
|
||||
|
||||
|
||||
def join_parts(parts: list[str | None]) -> str:
|
||||
return ", ".join(part for part in parts if part)
|
||||
|
||||
|
||||
def video_parts(
|
||||
*,
|
||||
codec: str | None = None,
|
||||
width: int | None = None,
|
||||
height: int | None = None,
|
||||
pixel_format: str | None = None,
|
||||
bit_depth: int | None = None,
|
||||
matrix: str | None = None,
|
||||
bit_rate: int | None = None,
|
||||
) -> list[str | None]:
|
||||
return [
|
||||
codec,
|
||||
format_size(width, height),
|
||||
format_chroma(pixel_format),
|
||||
f"{bit_depth}-bit" if bit_depth is not None else None,
|
||||
matrix,
|
||||
format_bitrate(bit_rate),
|
||||
]
|
||||
|
||||
|
||||
def audio_parts(
|
||||
*,
|
||||
codec: str | None = None,
|
||||
channels: int | None = None,
|
||||
sample_rate: int | None = None,
|
||||
bit_rate: int | None = None,
|
||||
) -> list[str | None]:
|
||||
return [
|
||||
codec,
|
||||
format_channels(channels),
|
||||
f"{sample_rate} Hz" if sample_rate is not None else None,
|
||||
format_bitrate(bit_rate),
|
||||
]
|
||||
|
||||
|
||||
def format_size(width: int | None, height: int | None) -> str | None:
|
||||
return f"{width}x{height}" if width is not None and height is not None else None
|
||||
|
||||
|
||||
def format_chroma(pixel_format: str | None) -> str | None:
|
||||
value = (pixel_format or "").lower()
|
||||
for marker, label in (("420", "4:2:0"), ("422", "4:2:2"), ("444", "4:4:4")):
|
||||
if marker in value:
|
||||
return label
|
||||
if value.startswith(("rgb", "bgr", "gbr")):
|
||||
return "RGB"
|
||||
if value.startswith("gray"):
|
||||
return "gray"
|
||||
return pixel_format
|
||||
|
||||
|
||||
def chroma_family(pixel_format: str | None) -> str:
|
||||
value = (pixel_format or "").lower()
|
||||
if "444" in value:
|
||||
return "444"
|
||||
if "422" in value:
|
||||
return "422"
|
||||
return "420"
|
||||
|
||||
|
||||
def format_channels(channels: int | None) -> str | None:
|
||||
if channels is None:
|
||||
return None
|
||||
return f"{channels} channel{'s' if channels != 1 else ''}"
|
||||
|
||||
|
||||
def format_bitrate(bit_rate: int | None) -> str | None:
|
||||
if bit_rate is None:
|
||||
return None
|
||||
if bit_rate >= 1_000_000:
|
||||
return f"{bit_rate / 1_000_000:.3g} Mbit/s"
|
||||
return f"{bit_rate / 1_000:.3g} kbit/s"
|
||||
|
||||
|
||||
def format_seconds(seconds: float | None) -> str:
|
||||
return "unknown" if seconds is None else f"{seconds:.3f}s"
|
||||
|
||||
|
||||
def format_frame_count(stream_count: int | None, timestamp_count: int) -> str:
|
||||
if stream_count is not None and stream_count != timestamp_count:
|
||||
return f"{stream_count} stream frames, {timestamp_count} timestamped frames"
|
||||
count = stream_count if stream_count is not None else timestamp_count
|
||||
return f"{count} frames" if count else "unknown frames"
|
||||
|
||||
|
||||
def rate_value(value: str | None) -> float | None:
|
||||
if not value:
|
||||
return None
|
||||
try:
|
||||
rate = Fraction(value)
|
||||
except (ValueError, ZeroDivisionError):
|
||||
return None
|
||||
return float(rate) if rate else None
|
||||
|
||||
|
||||
def format_framerate(kind: str, value: str | None) -> str:
|
||||
rate = rate_value(value)
|
||||
rate_text = "unknown" if rate is None else f"{rate:.3f} fps"
|
||||
kind = kind.upper()
|
||||
return f"{kind}, average {rate_text}" if kind == "VFR" else f"{kind}, {rate_text}"
|
||||
|
||||
|
||||
def matrix_name(matrix: int | None) -> str:
|
||||
if matrix == 1:
|
||||
return "Rec709"
|
||||
if matrix in {5, 6}:
|
||||
return "Rec601"
|
||||
if matrix in {9, 10}:
|
||||
return "Rec2020"
|
||||
return "unknown" if matrix is None else f"unknown ({matrix})"
|
||||
Reference in New Issue
Block a user