Files
plezy/scripts/maestro_fixtures.py
T

136 lines
13 KiB
Python

"""Deterministic media assets and hosted codec fixture contracts."""
from __future__ import annotations
import base64
from dataclasses import dataclass
import io
import math
import struct
import wave
@dataclass(frozen=True)
class MediaFixtureSpec:
id: str
title: str
filename: str
overview: str
video_codec: str
width: int
height: int
size_bytes: int
sha256: str
MEDIA_FIXTURE_SPECS = (
MediaFixtureSpec(
id="codec-dv-uhd",
title="Codec DV UHD TrueHD PGS",
filename="dv8_hdr10plus_truehd_pgs.mkv",
overview="Dolby Vision profile 8 with an HDR fallback, TrueHD Atmos, AC-3, and PGS subtitles.",
video_codec="hevc",
width=3840,
height=1604,
size_bytes=154537349,
sha256="1feac8feb3bf31323a8da16a9db22549e1acfa7d9469b4b85deaa2bd145ec84c",
),
MediaFixtureSpec(
id="codec-dv-web",
title="Codec DV Web EAC3 SRT",
filename="dv8_hdr_web_eac3_atmos_srt.mkv",
overview="Dolby Vision profile 8 with an HDR fallback, E-AC-3 Atmos, and multilingual SRT subtitles.",
video_codec="hevc",
width=3840,
height=1606,
size_bytes=120581060,
sha256="9bc5e1f90c20de9317800f51424f11366bb16861f10853e93625bb649ea34343",
),
MediaFixtureSpec(
id="codec-av1",
title="Codec AV1 Opus ASS",
filename="av1_opus_ass_srt.mkv",
overview="AV1 video with multilingual Opus audio, styled ASS subtitles, SRT subtitles, and embedded fonts.",
video_codec="av1",
width=1916,
height=1072,
size_bytes=6744111,
sha256="15a825c0d2d70c7f593cde1d86c1044c440b6745735a4e53c212878fd365fccd",
),
MediaFixtureSpec(
id="codec-h264-high10",
title="Codec H264 High10 DTS-HD ASS",
filename="h264_high10_dts_hd_ass.mkv",
overview="H.264 High 10 video with dual DTS-HD MA audio, styled ASS subtitles, and embedded fonts.",
video_codec="h264",
width=1920,
height=1080,
size_bytes=57191760,
sha256="0fb22b97f3542e228d55b80aa2893c3d92934192c908e8f96e696dbaaafcfe86",
),
MediaFixtureSpec(
id="codec-h264-eac3",
title="Codec H264 EAC3 Multisub",
filename="h264_eac3_multisub.mkv",
overview="H.264 video with three E-AC-3 audio tracks and a broad multilingual SRT subtitle set.",
video_codec="h264",
width=1920,
height=1080,
size_bytes=26793597,
sha256="759cc11148b4358611f6bbc1c9a6db014ecc6dce9b907993c8e51bd885f94d18",
),
MediaFixtureSpec(
id="codec-hevc-flac",
title="Codec HEVC10 FLAC ASS",
filename="hevc10_flac_ass.mkv",
overview="HEVC Main 10 video with dual FLAC 5.1 audio, styled ASS subtitles, and embedded fonts.",
video_codec="hevc",
width=1920,
height=1080,
size_bytes=45578288,
sha256="af8950e3c5a487e39b2f23df371583fa7469003da72df723be3d0f0071cf3414",
),
)
# Thirty-second 160x90 H.264 baseline MP4 generated once with ffmpeg. Embedding the
# payload keeps CI independent of ffmpeg and gives the real player a valid range-
# requestable stream long enough for chrome auto-hide and remote-key regressions.
_VIDEO = base64.b64decode(
"AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAjJbW9vdgAAAGxtdmhkAAAAAAAAAAAAAAAAAAAD6AAAdTAAAQAAAQAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAB/N0cmFrAAAAXHRraGQAAAADAAAAAAAAAAAAAAABAAAAAAAAdTAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAKAAAABaAAAAAAAkZWR0cwAAABxlbHN0AAAAAAAAAAEAAHUwAAAAAAABAAAAAAdrbWRpYQAAACBtZGhkAAAAAAAAAAAAAAAAAAAwAAAFoABVxAAAAAAALWhkbHIAAAAAAAAAAHZpZGUAAAAAAAAAAAAAAABWaWRlb0hhbmRsZXIAAAAHFm1pbmYAAAAUdm1oZAAAAAEAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAABtZzdGJsAAAAunN0c2QAAAAAAAAAAQAAAKphdmMxAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAKAAWgBIAAAASAAAAAAAAAABFUxhdmM2Mi4yOC4xMDIgbGlieDI2NAAAAAAAAAAAAAAAGP//AAAAMGF2Y0MBQsAe/+EAGGdCwB7ZAo35MBEAAAMAAQAAAwAYDxYuSAEABWjLg8sgAAAAEHBhc3AAAAABAAAAAQAAABRidHJ0AAAAAAAABIMAAAAAAAAAGHN0dHMAAAAAAAAAAQAAAWgAAAQAAAAAGHN0c3MAAAAAAAAAAgAAAAEAAAD7AAAAHHN0c2MAAAAAAAAAAQAAAAEAAAFoAAAAAQAABbRzdHN6AAAAAAAAAAAAAAFoAAACsgAAAAoAAAALAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAD0AAAAKAAAACwAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoA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AAZBm8A7wewAAAAGQZvgO8HsAAAABkGaADvB7AAAAAZBmiA7wewAAAAGQZpAO8HsAAAABkGaYDvB7AAAAAZBmoA7wewAAAAGQZqgO8HsAAAABkGawDvB7AAAAAZBmuA7wewAAAAGQZsAO8HsAAAABkGbIDvB7AAAAAZBm0A7wewAAAAGQZtgO8HsAAAABkGbgDvB7AAAAAZBm6A7wewAAAAGQZvAO8HsAAAABkGb4DvB7AAAAAZBmgA7wewAAAAGQZogO8HsAAAABkGaQDvB7AAAAAZBmmA7wewAAAAGQZqAO8HsAAAABkGaoDvB7AAAAAZBmsA7wewAAAAGQZrgO8HsAAAABkGbADvB7AAAAAZBmyA7wewAAAAGQZtAO8HsAAAABkGbYDvB7AAAAAZBm4A7wewAAAAGQZugO8HsAAAABkGbwDvB7AAAAAZBm+A7wewAAAAGQZoAO8HsAAAABkGaIDvB7AAAAAZBmkA7wewAAAAGQZpgO8HsAAAABkGagDvB7AAAAAZBmqA7wewAAAAGQZrAO8HsAAAABkGa4DvB7AAAAAZBmwA7wewAAAAGQZsgO8HsAAAABkGbQDvB7AAAAAZBm2A7wewAAAAGQZuAO8HsAAAABkGboDvB7AAAAAZBm8A7wewAAAAGQZvgO8HsAAAABkGaADvB7AAAAAZBmiA7wewAAAAGQZpAO8HsAAAABkGaYDvB7AAAAAZBmoA7wewAAAAGQZqgO8HsAAAABkGawDvB7AAAAAZBmuA7wewAAAAGQZsAO8HsAAAABkGbIDvB7AAAAAZBm0A7wewAAAAGQZtgO8HsAAAABkGbgDvB7AAAAAZBm6A7wewAAAAGQZvAO8HsAAAABkGb4DvB7AAAAAZBmgA7wewAAAAGQZogO8HsAAAABkGaQDvB7AAAAAZBmmA7wewAAAAGQZqAO8HsAAAABkGaoDvB7AAAAAZBmsA7wewAAAAGQZrgO8HsAAAABkGbADvB7AAAAAZBmyA7wewAAAAGQZtAO8HsAAAABkGbYDvB7AAAAAZBm4A7wewAAAAGQZugO8HsAAAABkGbwDvB7AAAAAZBm+A7wewAAAAGQZoAO8HsAAAABkGaIDvB7AAAAAZBmkA7wewAAAAGQZpgO8HsAAAABkGagDvB7AAAAAZBmqA7wewAAAAGQZrAO8HsAAAABkGa4DvB7AAAAAZBmwA7wewAAAAGQZsgO8HsAAAABkGbQDvB7AAAAAZBm2A7wewAAAAGQZuAO8HsAAAABkGboDvB7AAAAAZBm8A7wewAAAAGQZvgO8HsAAAABkGaADvB7AAAAAZBmiA7wewAAAAGQZpAO8HsAAAABkGaYDvB7AAAAAZBmoA7wewAAAAGQZqgO8HsAAAABkGawDvB7AAAAAZBmuA7wewAAAAGQZsAO8HsAAAABkGbIDvB7AAAAAZBm0A7wewAAAAGQZtgO8HsAAAABkGbgDvB7AAAAAZBm6A7wewAAAAGQZvAO8HsAAAABkGb4DvB7AAAAAZBmgA7wewAAAAGQZogO8HsAAAABkGaQDvB7AAAAAZBmmA7wewAAAAGQZqAO8HsAAAABkGaoDvB7AAAAAZBmsA7wewAAAAGQZrgO8HsAAAABkGbADvB7AAAAAZBmyA7wewAAAAGQZtAO8HsAAAABkGbYDvB7AAAAAZBm4A7wewAAAAGQZugO8HsAAAABkGbwDvB7AAAAAZBm+A7wewAAAAGQZoAO8HsAAAABkGaIDvB7AAAAAZBmkA7wewAAAAGQZpgO8HsAAAABkGagDvB7AAAAAZBmqA7wewAAAAGQZrAO8HsAAAABkGa4DvB7AAAAAZBmwA7wewAAAAGQZsgO8HsAAAABkGbQDvB7AAAAAZBm2A7wewAAAAGQZuAO8HsAAAABkGboDvB7AAAAAZBm8A7wewAAAAGQZvgO8HsAAAABkGaADvB7AAAAAZBmiA7wewAAAAGQZpAO8HsAAAABkGaYDvB7AAAAAZBmoA7wewAAAAGQZqgO8HsAAAABkGawDvB7AAAAAZBmuA7wewAAAAGQZsAO8HsAAAABkGbIDvB7AAAAAZBm0A7wewAAAAGQZtgO8HsAAAABkGbgDvB7AAAAAZBm6A7wewAAAAGQZvAO8HsAAAABkGb4DvB7AAAAAZBmgA7wewAAAAGQZogO8HsAAAABkGaQDvB7AAAAAZBmmA7wewAAAAGQZqAO8HsAAAABkGaoDvB7AAAAAZBmsA7wewAAAAGQZrgO8HsAAAABkGbADvB7AAAAAZBmyA7wewAAAAGQZtAO8HsAAAABkGbYDvB7AAAAAZBm4A7wewAAAAGQZugO8HsAAAABkGbwDvB7AAAAAZBm+A7wewAAAAGQZoAO8HsAAAABkGaIDvB7AAAAAZBmkA7wewAAAAGQZpgO8HsAAAABkGagDvB7AAAAAZBmqA7wewAAAAGQZrAO8HsAAAABkGa4DvB7AAAAAZBmwA7wewAAAAGQZsgO8HsAAAAOWWIggEfJigADYjJycnJycnJycnXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXgAAAAZBmjgd4PYAAAAHQZpUB3g9gAAAAAZBmmA7wewAAAAGQZqAO8HsAAAABkGaoDvB7AAAAAZBmsA7wewAAAAGQZrgO8HsAAAABkGbADvB7AAAAAZBmyA7wewAAAAGQZtAO8HsAAAABkGbYDvB7AAAAAZBm4A7wewAAAAGQZugO8HsAAAABkGbwDvB7AAAAAZBm+A7wewAAAAGQZoAO8HsAAAABkGaIDvB7AAAAAZBmkA7wewAAAAGQZpgO8HsAAAABkGagDvB7AAAAAZBmqA7wewAAAAGQZrAO8HsAAAABkGa4DvB7AAAAAZBmwA7wewAAAAGQZsgO8HsAAAABkGbQDvB7AAAAAZBm2A7wewAAAAGQZuAO8HsAAAABkGboDvB7AAAAAZBm8A7wewAAAAGQZvgO8HsAAAABkGaADvB7AAAAAZBmiA7wewAAAAGQZpAO8HsAAAABkGaYDvB7AAAAAZBmoA7wewAAAAGQZqgO8HsAAAABkGawDvB7AAAAAZBmuA7wewAAAAGQZsAO8HsAAAABkGbIDvB7AAAAAZBm0A7wewAAAAGQZtgO8HsAAAABkGbgDvB7AAAAAZBm6A7wewAAAAGQZvAO8HsAAAABkGb4DvB7AAAAAZBmgA7wewAAAAGQZogO8HsAAAABkGaQDvB7AAAAAZBmmA7wewAAAAGQZqAO8HsAAAABkGaoDvB7AAAAAZBmsA7wewAAAAGQZrgO8HsAAAABkGbADvB7AAAAAZBmyA7wewAAAAGQZtAO8HsAAAABkGbYDvB7AAAAAZBm4A7wewAAAAGQZugO8HsAAAABkGbwDvB7AAAAAZBm+A7wewAAAAGQZoAO8HsAAAABkGaIDvB7AAAAAZBmkA7wewAAAAGQZpgO8HsAAAABkGagDvB7AAAAAZBmqA7wewAAAAGQZrAO8HsAAAABkGa4DvB7AAAAAZBmwA7wewAAAAGQZsgO8HsAAAABkGbQDvB7AAAAAZBm2A7wewAAAAGQZuAO8HsAAAABkGboDvB7AAAAAZBm8A7wewAAAAGQZvgO8HsAAAABkGaADvB7AAAAAZBmiA7wewAAAAGQZpAO8HsAAAABkGaYDvB7AAAAAZBmoA7wewAAAAGQZqgO8HsAAAABkGawDvB7AAAAAZBmuA7wewAAAAGQZsAO8HsAAAABkGbIDvB7AAAAAZBm0A7wewAAAAGQZtgO8HsAAAABkGbgDvB7AAAAAZBm6A7wewAAAAGQZvAO8HsAAAABkGb4DvB7AAAAAZBmgA7wewAAAAGQZogO8HsAAAABkGaQDvB7AAAAAZBmmA7wewAAAAGQZqAO8HsAAAABkGaoDvB7AAAAAZBmsA7wewAAAAGQZrgO8HsAAAABkGbADvB7AAAAAZBmyA7wewAAAAGQZtAO8HsAAAABkGbYDvB7AAAAAZBm4A3wewAAAAGQZugM8Hs"
)
def _build_wav() -> bytes:
sample_rate = 8_000
frame_count = sample_rate * 2
pcm = bytearray(frame_count * 2)
for index in range(frame_count):
sample = int(8_000 * math.sin(2 * math.pi * 440 * index / sample_rate))
struct.pack_into("<h", pcm, index * 2, sample)
output = io.BytesIO()
with wave.open(output, "wb") as wav:
wav.setnchannels(1)
wav.setsampwidth(2)
wav.setframerate(sample_rate)
wav.writeframes(pcm)
payload = bytearray(output.getvalue())
info_chunks = []
for code, value in {
"INAM": "Resilient Track",
"IART": "Maestro Artist",
"IPRD": "Regression Album",
"ITRK": "1",
"ICRD": "2026",
}.items():
encoded = value.encode("utf-8") + b"\0"
padded = encoded if len(encoded) % 2 == 0 else encoded + b"\0"
info_chunks.append(code.encode("ascii") + struct.pack("<I", len(encoded)) + padded)
info = b"INFO" + b"".join(info_chunks)
payload.extend(b"LIST" + struct.pack("<I", len(info)) + info)
struct.pack_into("<I", payload, 4, len(payload) - 8)
return bytes(payload)
_AUDIO = _build_wav()