76 lines
2.9 KiB
Python
76 lines
2.9 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
|
|
|
|
_MATRIX = {1: "bt709", 5: "smpte170m", 6: "smpte170m", 9: "bt2020nc", 10: "bt2020nc"}
|
|
_PRIMARIES = {1: "bt709", 9: "bt2020", 12: "smpte432"}
|
|
_TRANSFER = {1: "bt709", 16: "smpte2084", 18: "arib-std-b67"}
|
|
_RANGE = {0: "tv", 1: "pc"}
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class ColorMetadata:
|
|
matrix: int | None
|
|
primaries: int | None
|
|
transfer: int | None
|
|
color_range: int | None
|
|
|
|
@property
|
|
def colorspace(self) -> str | None:
|
|
return _MATRIX.get(self.matrix)
|
|
|
|
def ffmpeg_args(self) -> list[str]:
|
|
values = [
|
|
("-colorspace", self.colorspace),
|
|
("-color_primaries", _PRIMARIES.get(self.primaries)),
|
|
("-color_trc", _TRANSFER.get(self.transfer)),
|
|
("-color_range", _RANGE.get(self.color_range)),
|
|
]
|
|
return [part for option, value in values if value is not None for part in (option, value)]
|
|
|
|
def x264_args(self) -> list[str]:
|
|
values = [
|
|
("--colormatrix", self.colorspace),
|
|
("--colorprim", _PRIMARIES.get(self.primaries)),
|
|
("--transfer", _TRANSFER.get(self.transfer)),
|
|
("--range", _RANGE.get(self.color_range)),
|
|
]
|
|
return [part for option, value in values if value is not None for part in (option, value)]
|
|
|
|
def x265_params(self) -> str:
|
|
values = [
|
|
("colorprim", _PRIMARIES.get(self.primaries)),
|
|
("transfer", _TRANSFER.get(self.transfer)),
|
|
("colormatrix", self.colorspace),
|
|
("range", "full" if self.color_range == 1 else "limited" if self.color_range == 0 else None),
|
|
]
|
|
return ":".join(f"{name}={value}" for name, value in values if value is not None)
|
|
|
|
def mkvmerge_args(self) -> list[str]:
|
|
values = [
|
|
("--color-matrix-coefficients", self.matrix),
|
|
("--color-primaries", self.primaries),
|
|
("--color-transfer-characteristics", self.transfer),
|
|
("--color-range", {0: 1, 1: 2}.get(self.color_range)),
|
|
]
|
|
return [part for option, value in values if value is not None for part in (option, f"0:{value}")]
|
|
|
|
def hevc_bitstream_filter(self) -> str | None:
|
|
values = [
|
|
("colour_primaries", self.primaries),
|
|
("transfer_characteristics", self.transfer),
|
|
("matrix_coefficients", self.matrix),
|
|
("video_full_range_flag", self.color_range),
|
|
]
|
|
params = ":".join(f"{name}={value}" for name, value in values if value is not None)
|
|
return f"hevc_metadata={params}" if params else None
|
|
|
|
def expected_probe_values(self) -> dict[str, str | None]:
|
|
return {
|
|
"matrix": {1: "Rec709", 5: "Rec601", 6: "Rec601", 9: "Rec2020", 10: "Rec2020"}.get(self.matrix),
|
|
"primaries": _PRIMARIES.get(self.primaries),
|
|
"transfer": _TRANSFER.get(self.transfer),
|
|
"range": _RANGE.get(self.color_range),
|
|
}
|