Speed up ABR transcoding: cap variants at 2, drop x264 preset to superfast

Host CPU is an old Xeon E5530 (2010-era, no hardware encode available at all)
already fairly loaded, so raw compute is the real bottleneck. Two changes:
- Cap ABR renditions to the 2 highest applicable instead of up to 4 — roughly
  halves total encode work per job while still giving a real high/low
  adaptive-bitrate pair.
- veryfast -> superfast x264 preset, a meaningful further speed win at the
  cost of somewhat larger files and slightly softer quality per bitrate.
Combined, remaining variants also get more threads each since fewer variants
now share the same TRANSCODE_THREADS budget.
This commit is contained in:
Myron Blair
2026-07-27 20:41:30 -05:00
parent 4397617cf1
commit 628a729afd
+7 -4
View File
@@ -64,13 +64,16 @@ ALL_VARIANTS = [
def variants_for_source(src_height: int) -> List[Tuple[int, str, str, str, str]]: def variants_for_source(src_height: int) -> List[Tuple[int, str, str, str, str]]:
"""Pick variants ≤ source height. Always include at least one (smallest).""" """Pick up to 2 variants ≤ source height (the two highest applicable renditions —
ALL_VARIANTS is ordered highest-to-lowest, so slicing keeps the best pair). Capped at 2
instead of the full ladder to roughly halve ABR encode time on this host's aging CPU, while
still giving a real high/low adaptive-bitrate pair for most connections."""
if src_height <= 0: if src_height <= 0:
return [ALL_VARIANTS[2]] # safe default 480p return [ALL_VARIANTS[2]] # safe default 480p
chosen = [v for v in ALL_VARIANTS if v[0] <= src_height] chosen = [v for v in ALL_VARIANTS if v[0] <= src_height]
if not chosen: if not chosen:
chosen = [ALL_VARIANTS[-1]] chosen = [ALL_VARIANTS[-1]]
return chosen return chosen[:2]
async def transcode_audio_fix(source: Path, out_dir: Path, on_status: Callable[..., Awaitable]) -> None: async def transcode_audio_fix(source: Path, out_dir: Path, on_status: Callable[..., Awaitable]) -> None:
@@ -133,7 +136,7 @@ async def transcode_abr(source: Path, out_dir: Path, on_status: Callable[..., Aw
filter_complex = ";".join(fc_parts) filter_complex = ";".join(fc_parts)
# Per-variant thread count, not the full cap each — x264 threads are set per encoder # Per-variant thread count, not the full cap each — x264 threads are set per encoder
# instance, so giving every one of the (up to 4) variants the full TRANSCODE_THREADS # instance, so giving every one of the (up to 2) variants the full TRANSCODE_THREADS
# budget lets them all run near-full-tilt simultaneously and still saturate the host. # budget lets them all run near-full-tilt simultaneously and still saturate the host.
per_variant_threads = max(1, TRANSCODE_THREADS // n) per_variant_threads = max(1, TRANSCODE_THREADS // n)
@@ -143,7 +146,7 @@ async def transcode_abr(source: Path, out_dir: Path, on_status: Callable[..., Aw
cmd += [ cmd += [
"-map", f"[v{i}out]", "-map", f"[v{i}out]",
f"-c:v:{i}", "libx264", f"-c:v:{i}", "libx264",
f"-preset:v:{i}", "veryfast", f"-preset:v:{i}", "superfast",
f"-threads:v:{i}", str(per_variant_threads), f"-threads:v:{i}", str(per_variant_threads),
f"-profile:v:{i}", "main", f"-profile:v:{i}", "main",
f"-pix_fmt:v:{i}", "yuv420p", f"-pix_fmt:v:{i}", "yuv420p",