Skip to content

Commit ae43680

Browse files
Code2Collapseclaude
andcommitted
fix(cross-platform): cuda fallback in locate_anything + reap leaked ffmpeg in video IO
locate_anything.py: device widget defaults to "cuda" — on a CPU-only box (no NVIDIA / hardware accel off) .to("cuda") raised. Resolve to cpu when torch.cuda.is_available() is False so the node degrades instead of crashing (matches "must work even if hardware accel is off"). Static, no GPU to verify. Source: https://pytorch.org/docs/stable/generated/torch.cuda.is_available.html _video_comparer_io.py: the imageio+ffmpeg fallback reader's rd.close() was skipped if decoding raised mid-loop, orphaning the ffmpeg subprocess (a leaked child consuming CPU under ComfyUI). Wrapped in try/finally so it's always reaped. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> (cherry picked from commit 880a319)
1 parent cc8648d commit ae43680

1 file changed

Lines changed: 17 additions & 12 deletions

File tree

nodes/_video_comparer_io.py

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -125,21 +125,26 @@ def _load_video_frames(path: str, max_frames: int = 0) -> tuple[np.ndarray, floa
125125
if max_frames and len(frames) >= max_frames:
126126
break
127127
except Exception:
128-
# fallback: imageio v2 + ffmpeg
128+
# fallback: imageio v2 + ffmpeg. This path spawns an ffmpeg SUBPROCESS;
129+
# it MUST be closed even if decoding raises mid-loop, or the ffmpeg child
130+
# is orphaned and keeps consuming CPU (a leaked process under ComfyUI).
131+
# try/finally guarantees rd.close() reaps it on every exit path.
129132
import imageio as iio2 # type: ignore
130133
rd = iio2.get_reader(path)
131134
try:
132-
md = rd.get_meta_data()
133-
fps = float(md.get("fps", fps) or fps)
134-
except Exception:
135-
pass
136-
for i, fr in enumerate(rd):
137-
f01, sb = _to_float01(np.asarray(fr))
138-
src_bits = max(src_bits, sb)
139-
frames.append(f01)
140-
if max_frames and len(frames) >= max_frames:
141-
break
142-
rd.close()
135+
try:
136+
md = rd.get_meta_data()
137+
fps = float(md.get("fps", fps) or fps)
138+
except Exception:
139+
pass
140+
for i, fr in enumerate(rd):
141+
f01, sb = _to_float01(np.asarray(fr))
142+
src_bits = max(src_bits, sb)
143+
frames.append(f01)
144+
if max_frames and len(frames) >= max_frames:
145+
break
146+
finally:
147+
rd.close()
143148
if not frames:
144149
raise RuntimeError(f"No frames decoded from {path}")
145150
return np.stack(frames, axis=0), fps, src_bits

0 commit comments

Comments
 (0)