"""End-to-end tests against a real ffmpeg. Skipped when ffmpeg is not available. Set FFWRAP_FFMPEG_DIR to point at a folder containing ffmpeg/ffprobe, or put them on PATH. """ import os import subprocess from pathlib import Path import pytest from ffwrap.command import Options, build_command, match_audio_selection from ffwrap.probe import probe from ffwrap.tools import locate_tools TOOLS = locate_tools(os.environ.get("FFWRAP_FFMPEG_DIR")) pytestmark = pytest.mark.skipif(TOOLS is None, reason="ffmpeg/ffprobe not found") @pytest.fixture(scope="module") def sample(tmp_path_factory) -> Path: """3 s 640x360 H.264 + jpn 5.1 AC3 + eng stereo AAC + English SRT in an MKV.""" d = tmp_path_factory.mktemp("media") srt = d / "subs.srt" srt.write_text("1\n00:00:00,500 --> 00:00:02,000\nHello\n", encoding="utf-8") out = d / "sample.mkv" subprocess.run([ TOOLS.ffmpeg, "-v", "error", "-y", "-f", "lavfi", "-i", "testsrc2=size=640x360:rate=25:duration=3", "-f", "lavfi", "-i", "sine=frequency=440:duration=3", "-f", "lavfi", "-i", "sine=frequency=880:duration=3", "-i", str(srt), "-map", "0", "-map", "1", "-map", "2", "-map", "3", "-c:v", "libx264", "-preset", "ultrafast", "-c:a:0", "ac3", "-ac:a:0", "6", "-c:a:1", "aac", "-ac:a:1", "2", "-c:s", "srt", "-metadata:s:a:0", "language=jpn", "-metadata:s:a:1", "language=eng", "-metadata:s:s:0", "language=eng", str(out), ], check=True) return out def run(info, opts, audio, out): built = build_command(TOOLS.ffmpeg, info, opts, audio, out) res = subprocess.run(built.args, capture_output=True, text=True) assert res.returncode == 0, res.stderr return probe(TOOLS.ffprobe, out) def test_remux_to_mp4_keeps_streams(sample, tmp_path): info = probe(TOOLS.ffprobe, sample) eng = match_audio_selection(info.audio, [info.audio[1].index], info.audio) out = run(info, Options(container="mp4"), eng, tmp_path / "out.mp4") assert out.video.codec == "h264" assert [(a.codec, a.language) for a in out.audio] == [("aac", "eng")] assert [s.codec for s in out.subtitles] == ["mov_text"] assert abs(out.duration - info.duration) < 0.5 def test_reencode_scale_and_downmix(sample, tmp_path): info = probe(TOOLS.ffprobe, sample) opts = Options(container="mkv", video_mode="encode", video_encoder="libx265", resolution=240, speed=0, audio_mode="encode", audio_encoder="libopus", audio_channels=2, subtitles=False) out = run(info, opts, [a.index for a in info.audio], tmp_path / "out.mkv") assert out.video.codec == "hevc" and (out.video.width, out.video.height) == (426, 240) assert [(a.codec, a.channels) for a in out.audio] == [("opus", 2), ("opus", 2)] assert out.subtitles == [] def test_strip_audio_webm(sample, tmp_path): info = probe(TOOLS.ffprobe, sample) opts = Options(container="webm", video_mode="auto", video_encoder="libvpx-vp9", speed=0, audio_mode="strip") out = run(info, opts, [], tmp_path / "out.webm") assert out.video.codec == "vp9" and out.audio == [] assert [s.codec for s in out.subtitles] == ["webvtt"]