Prevent ffmpeg stderr backpressure

This commit is contained in:
Victor Kuznetsov
2026-07-31 14:59:57 -07:00
parent 0fac8cd000
commit 7818e60824
6 changed files with 144 additions and 68 deletions
+6 -24
View File
@@ -1950,30 +1950,6 @@ class TestVideoVisibleScan:
class TestVideoVisibleEncoding:
@pytest.mark.parametrize("suffix", [".mp4", ".webm"])
def test_encoder_bounds_codec_threads(
self,
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
suffix: str,
):
from remove_ai_watermarks import video_encoding
monkeypatch.setattr(video_encoding.shutil, "which", lambda _name: "/usr/bin/ffmpeg")
command = video_encoding.raw_video_command(
tmp_path / "source.mp4",
tmp_path / f"clean{suffix}",
width=12,
height=8,
fps=24.0,
strip_metadata=True,
crf=14,
profile=video_encoding.VideoEncodeProfile(),
)
assert command[1:3] == ["-filter_threads", "1"]
assert command[command.index("-threads:v") + 1] == "2"
@staticmethod
def _patch_single_frame_encode(
monkeypatch: pytest.MonkeyPatch,
@@ -2008,6 +1984,12 @@ class TestVideoVisibleEncoding:
def poll(self) -> int:
return 1
def wait(self) -> int:
return 1
def discard_stderr(self) -> None:
pass
targets: list[Path] = []
def fake_command(_source: Path, target: Path, **_kwargs: object) -> list[str]:
+51
View File
@@ -2,6 +2,8 @@
from __future__ import annotations
import sys
import threading
from types import SimpleNamespace
from typing import TYPE_CHECKING
@@ -14,6 +16,55 @@ if TYPE_CHECKING:
from pathlib import Path
def test_encoder_redirects_large_stderr_while_frames_are_streaming(
tmp_path: Path,
caplog: pytest.LogCaptureFixture,
) -> None:
diagnostic = "synthetic ffmpeg diagnostic"
tail_diagnostic = "synthetic ffmpeg diagnostic tail"
caplog.set_level("INFO", logger=video_encoding.__name__)
command = [
sys.executable,
"-c",
(
"import sys; "
f"sys.stderr.buffer.write({diagnostic.encode()!r} + b'x' * 262144 + {tail_diagnostic.encode()!r}); "
"sys.stderr.buffer.flush(); "
"sys.stdin.buffer.read(); "
"raise SystemExit(7)"
),
]
encoder = video_encoding.start_raw_video_encoder(command)
write_finished = threading.Event()
write_errors: list[Exception] = []
def write_frames() -> None:
try:
encoder.stdin.write(b"f" * 262144)
encoder.stdin.flush()
except Exception as exc: # pragma: no cover - mutation cleanup path
write_errors.append(exc)
finally:
write_finished.set()
writer = threading.Thread(target=write_frames)
writer.start()
try:
assert write_finished.wait(5), "stderr backpressure blocked the frame producer"
assert write_errors == []
with pytest.raises(RuntimeError, match=diagnostic):
video_encoding.finish_raw_video_encoder(
encoder,
tmp_path / "unused.mp4",
operation="synthetic encode",
)
assert "ffmpeg stderr truncated" in caplog.text
assert tail_diagnostic in caplog.text
finally:
video_encoding.abort_raw_video_encoder(encoder)
writer.join(timeout=5)
def test_availability_requires_both_optional_packages(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(
video_invisible,