Files
Vladimir ChopineandCopilot 1e2605069f feat: close major V1 PRD gaps for UniversalVideoIO
Adds advanced save controls, load-video resize options, archive-sequence master preset, FFmpeg capability self-check cache, optional UV_TranscodeVideo utility node, Comfy registry metadata scaffolding, updated docs/workflows, and expanded tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-25 10:23:41 -06:00

81 lines
2.3 KiB
Python

import json
import shutil
import subprocess
import tempfile
from pathlib import Path
_CACHE_PATH = Path(tempfile.gettempdir()) / "uvio_ffmpeg_probe_cache.json"
def get_ffmpeg_path(prefer_system=True):
if prefer_system:
found = shutil.which("ffmpeg")
if found:
return found
try:
import imageio_ffmpeg
return imageio_ffmpeg.get_ffmpeg_exe()
except Exception as exc:
raise RuntimeError("FFmpeg binary not found. Install ffmpeg or imageio-ffmpeg.") from exc
def ffmpeg_codec_probe(ffmpeg_path=None):
ffmpeg_path = ffmpeg_path or get_ffmpeg_path()
proc = subprocess.run([ffmpeg_path, "-hide_banner", "-codecs"], capture_output=True, text=True, check=False)
if proc.returncode != 0:
return {"error": proc.stderr.strip() or "ffmpeg codec probe failed", "encoders": {}}
txt = proc.stdout.lower()
return {
"encoders": {
"libx264": "libx264" in txt,
"libx265": "libx265" in txt,
"libsvtav1": "libsvtav1" in txt,
"libvpx-vp9": "libvpx-vp9" in txt,
"prores_ks": "prores_ks" in txt,
"dnxhd": "dnxhd" in txt,
}
}
def ensure_ffmpeg_ready():
if _CACHE_PATH.exists():
try:
return json.loads(_CACHE_PATH.read_text())
except Exception:
pass
ffmpeg_path = get_ffmpeg_path()
codecs = ffmpeg_codec_probe(ffmpeg_path)
payload = {"ffmpeg_path": ffmpeg_path, **codecs}
try:
_CACHE_PATH.write_text(json.dumps(payload))
except Exception:
pass
return payload
def _ffprobe_path(ffmpeg_path):
folder = ffmpeg_path.rsplit("/", 1)[0] if "/" in ffmpeg_path else ""
candidate = f"{folder}/ffprobe" if folder else "ffprobe"
return candidate if shutil.which(candidate) else "ffprobe"
def ffprobe_json(path, ffmpeg_path=None):
ffmpeg_path = ffmpeg_path or get_ffmpeg_path()
ffprobe = _ffprobe_path(ffmpeg_path)
cmd = [
ffprobe,
"-v",
"error",
"-print_format",
"json",
"-show_streams",
"-show_format",
path,
]
proc = subprocess.run(cmd, capture_output=True, text=True, check=False)
if proc.returncode != 0:
return {"error": proc.stderr.strip() or "ffprobe failed"}
return json.loads(proc.stdout or "{}")