reflections / ffmpeg_util.py
Cavefishlabs's picture
Reflections service: same code as the CPU fallback (f4aac7d), always-on CPU
5278313 verified
Raw History Blame Contribute Delete
2.25 kB
"""One place that knows how to run ffmpeg and how to report it failing.
Both the /analyze endpoint and the Stage Read pipeline shell out to ffmpeg, and both used to lose
the reason it failed: one discarded the pipes, the other caught everything and returned False. A
process that dies before main() then reports only a numeric exit status - on Windows 3221225794 is
0xC0000142, STATUS_DLL_INIT_FAILED, which says nothing about audio and everything about the
environment the service was started in.
"""
import os
import shutil
import subprocess
class FFmpegError(RuntimeError):
"""ffmpeg exited non-zero. The message carries its stderr where there was any."""
def ffmpeg_exe() -> str:
"""Absolute path to ffmpeg. Resolving it here beats relying on the PATH the service happened to
inherit — a long-lived service can outlive the shell whose PATH it was started with."""
exe = os.environ.get("STAGE_READ_FFMPEG") or shutil.which("ffmpeg")
if not exe:
raise FFmpegError("ffmpeg is not on PATH. Install it, or set STAGE_READ_FFMPEG to its full path.")
return exe
def run_ffmpeg(args, timeout=None):
"""Run ffmpeg with the given arguments and, if it fails, say why.
Passes -nostdin and an explicit DEVNULL: a service launched in the background can be holding a
stdin that is no longer connected to anything, and ffmpeg reads stdin unless told not to.
"""
exe = ffmpeg_exe()
cmd = [exe, "-nostdin", "-y", "-v", "error", *args]
r = subprocess.run(cmd, stdin=subprocess.DEVNULL, capture_output=True, timeout=timeout)
if r.returncode == 0:
return r
err = (r.stderr or b"").decode("utf-8", "replace").strip()
detail = err.splitlines()[-3:] if err else []
status = r.returncode & 0xFFFFFFFF
msg = f"ffmpeg failed (exit {r.returncode}, 0x{status:08X}) [{exe}]"
if detail:
msg += ": " + " | ".join(detail)
elif status == 0xC0000142:
msg += (": the process could not start (Windows STATUS_DLL_INIT_FAILED) - it produced no "
"output at all. Restart the service; if it persists, set STAGE_READ_FFMPEG to a "
"known-good ffmpeg.exe.")
else:
msg += ": no error output."
raise FFmpegError(msg)