diff --git a/tests/test_pipeline_ffmpeg_ops.py b/tests/test_pipeline_ffmpeg_ops.py index 63d8336..bdfc94d 100644 --- a/tests/test_pipeline_ffmpeg_ops.py +++ b/tests/test_pipeline_ffmpeg_ops.py @@ -1,4 +1,4 @@ -from tools.pipeline.ffmpeg_ops import frame_args, crossfade_loop_args +from tools.pipeline.ffmpeg_ops import frame_args, crossfade_loop_args, transcode_args def test_frame_args_trims_scales_pads_and_strips_audio(): @@ -33,3 +33,16 @@ def test_crossfade_loop_rejects_overlap_too_large(): import pytest with pytest.raises(ValueError): crossfade_loop_args("in.mp4", "loop.mp4", duration=4.0, overlap=2.0) + + +def test_transcode_args_high_profile_even_dims_faststart(): + args = transcode_args("loop.mp4", "proxy.mp4", width=1920, height=1080, + crf=20, fps=30) + assert "-profile:v" in args and args[args.index("-profile:v") + 1] == "high" + assert "-crf" in args and args[args.index("-crf") + 1] == "20" + vf = args[args.index("-vf") + 1] + assert "scale=1920:1080:force_original_aspect_ratio=decrease" in vf + assert "fps=30" in vf + assert "+faststart" in args + assert "-an" in args + assert args[-1] == "proxy.mp4" diff --git a/tools/pipeline/ffmpeg_ops.py b/tools/pipeline/ffmpeg_ops.py index f1476d7..a8a2655 100644 --- a/tools/pipeline/ffmpeg_ops.py +++ b/tools/pipeline/ffmpeg_ops.py @@ -51,3 +51,21 @@ def crossfade_loop_args(src, dst, *, duration: float, overlap: float, "-c:v", "libx264", "-preset", "medium", "-crf", "16", "-pix_fmt", "yuv420p", "-movflags", "+faststart", str(dst), ] + + +def transcode_args(src, dst, *, width: int, height: int, crf: int, + fps: int = 30, ff: str = "ffmpeg") -> list[str]: + """Stage 4 — encode a final deliverable (master or proxy). Master: source res + capped ~3840 wide, crf 18. Proxy: 1920×1080, crf 20. Both H.264 High, yuv420p, + even dims, +faststart, video-only (spec §6).""" + vf = ( + f"scale={width}:{height}:force_original_aspect_ratio=decrease," + f"pad={width}:{height}:(ow-iw)/2:(oh-ih)/2," + f"setsar=1,fps={fps},format=yuv420p" + ) + return [ + ff, "-y", "-i", str(src), "-vf", vf, "-an", + "-c:v", "libx264", "-profile:v", "high", "-preset", "slow", + "-crf", str(crf), "-pix_fmt", "yuv420p", + "-movflags", "+faststart", str(dst), + ]