Skip to content

Commit 5a4bf42

Browse files
authored
Merge pull request #438 from AInVFX/main
v2.5.23: Security hardening, GGUF VAE support, FFmpeg stability, MPS optimization
2 parents d69b65f + 43e70bf commit 5a4bf42

File tree

10 files changed

+71
-22
lines changed

10 files changed

+71
-22
lines changed

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,18 @@ We're actively working on improvements and new features. To stay informed:
3636

3737
## 🚀 Release Notes
3838

39+
**2025.12.24 - Version 2.5.23**
40+
41+
- **🔒 Security: Prevent code execution in model loading** - Added protection against malicious .pth files by restricting deserialization to tensors only
42+
- **🎥 Fix: FFmpeg video writer reliability** - Resolved ffmpeg process hanging issues by redirecting stderr and adding buffer flush, with improved error messages for debugging *(thanks [@thehhmdb](https://github.com/thehhmdb))*
43+
- **⚡ Fix: GGUF VAE model support** - Enabled automatic weight dequantization for convolution operations, making GGUF-quantized VAE models fully functional *(thanks [@naxci1](https://github.com/naxci1))*
44+
- **🛡️ Fix: VAE slicing edge cases** - Protected against division by zero crashes when using small split sizes with high temporal downsampling *(thanks [@naxci1](https://github.com/naxci1))*
45+
- **🎨 Fix: LAB color transfer precision** - Resolved dtype mismatch errors during video upscaling by ensuring consistent float types before matrix operations
46+
- **🔧 Fix: PyTorch 2.9+ compatibility** - Extended Conv3d memory workaround to all PyTorch 2.9+ versions, fixing 3x VRAM usage on newer PyTorch releases
47+
- **📦 Fix: Bitsandbytes compatibility** - Added ValueError exception handling for Intel Gaudi version detection failures on non-Gaudi systems
48+
- **🍎 MPS: Memory optimization** - Reduced memory usage during encode/decode operations on Apple Silicon *(thanks [@s-cerevisiae](https://github.com/s-cerevisiae))*
49+
50+
3951
**2025.12.13 - Version 2.5.22**
4052

4153
- **🎬 CLI: FFmpeg video backend with 10-bit support** - New `--video_backend ffmpeg` and `--10bit` flags enable x265 encoding with 10-bit color depth, reducing banding artifacts in gradients compared to 8-bit OpenCV output *(based on PR by [@thehhmdb](https://github.com/thehhmdb) - thank you!)*
@@ -1030,7 +1042,7 @@ For detailed contribution guidelines, see [CONTRIBUTING.md](CONTRIBUTING.md).
10301042

10311043
This ComfyUI implementation is a collaborative project by **[NumZ](https://github.com/numz)** and **[AInVFX](https://www.youtube.com/@AInVFX)** (Adrien Toupet), based on the original [SeedVR2](https://github.com/ByteDance-Seed/SeedVR) by ByteDance Seed Team.
10321044

1033-
Special thanks to our community contributors including [naxci1](https://github.com/naxci1), [benjaminherb](https://github.com/benjaminherb), [cmeka](https://github.com/cmeka), [FurkanGozukara](https://github.com/FurkanGozukara), [JohnAlcatraz](https://github.com/JohnAlcatraz), [lihaoyun6](https://github.com/lihaoyun6), [Luchuanzhao](https://github.com/Luchuanzhao), [Luke2642](https://github.com/Luke2642), [proxyid](https://github.com/proxyid), [q5sys](https://github.com/q5sys), and many others for their improvements, bug fixes, and testing.
1045+
Special thanks to our community contributors including [naxci1](https://github.com/naxci1), [thehhmdb](https://github.com/thehhmdb), [s-cerevisiae](https://github.com/s-cerevisiae), [benjaminherb](https://github.com/benjaminherb), [cmeka](https://github.com/cmeka), [FurkanGozukara](https://github.com/FurkanGozukara), [JohnAlcatraz](https://github.com/JohnAlcatraz), [lihaoyun6](https://github.com/lihaoyun6), [Luchuanzhao](https://github.com/Luchuanzhao), [Luke2642](https://github.com/Luke2642), [proxyid](https://github.com/proxyid), [q5sys](https://github.com/q5sys), and many others for their improvements, bug fixes, and testing.
10341046

10351047
## 📜 License
10361048

inference_cli.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -171,23 +171,41 @@ def __init__(self, path: str, width: int, height: int, fps: float, use_10bit: bo
171171
['ffmpeg', '-y', '-f', 'rawvideo', '-pix_fmt', 'rgb24',
172172
'-s', f'{width}x{height}', '-r', str(fps), '-i', '-',
173173
'-c:v', codec, '-pix_fmt', pix_fmt, '-preset', 'medium', '-crf', '12', path],
174-
stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE
174+
stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
175175
)
176176

177177
def write(self, frame_bgr: np.ndarray):
178+
if not self.isOpened():
179+
raise RuntimeError("FFMPEGVideoWriter: ffmpeg process is not running")
180+
178181
frame_rgb = cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2RGB)
179-
self.proc.stdin.write(frame_rgb.astype(np.uint8).tobytes())
182+
try:
183+
self.proc.stdin.write(frame_rgb.astype(np.uint8).tobytes())
184+
self.proc.stdin.flush() # Critical: prevent buffering issues
185+
except BrokenPipeError:
186+
raise RuntimeError(
187+
"FFMPEGVideoWriter: ffmpeg process terminated unexpectedly. "
188+
"Check video path, codec support, and disk space."
189+
)
180190

181191
def isOpened(self) -> bool:
182192
return self.proc is not None and self.proc.poll() is None
183193

184194
def release(self):
185195
if self.proc:
186-
self.proc.stdin.close()
196+
try:
197+
self.proc.stdin.close()
198+
except Exception:
199+
pass # Ignore errors on close
200+
187201
self.proc.wait()
188-
stderr = self.proc.stderr.read() if self.proc.stderr else b''
202+
189203
if self.proc.returncode != 0:
190-
debug.log(f"ffmpeg error: {stderr.decode()}", level="WARNING", category="file")
204+
debug.log(
205+
f"ffmpeg exited with code {self.proc.returncode}. "
206+
"Check output file for corruption.",
207+
level="WARNING", force=True, category="file"
208+
)
191209
self.proc = None
192210

193211

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[project]
22
name = "seedvr2_videoupscaler"
33
description = "SeedVR2 official ComfyUI integration: ByteDance-Seed's one-step diffusion-based video/image upscaling with memory-efficient inference"
4-
version = "2.5.22"
4+
version = "2.5.23"
55
authors = [
66
{name = "numz"},
77
{name = "adrientoupet"}

src/core/model_loader.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ def load_quantized_state_dict(checkpoint_path: str, device: torch.device = torch
146146
handle_prefix="model.diffusion_model."
147147
)
148148
elif checkpoint_path.endswith('.pth'):
149-
state = torch.load(checkpoint_path, map_location=device_str, mmap=True)
149+
state = torch.load(checkpoint_path, map_location=device_str, mmap=True, weights_only=True)
150150
else:
151151
raise ValueError(f"Unsupported checkpoint format. Expected .safetensors or .pth, got: {checkpoint_path}")
152152

@@ -393,6 +393,20 @@ def __torch_function__(cls, func, types, args=(), kwargs=None):
393393
if debug:
394394
debug.log(f"Error in {func.__name__} dequantization: {e}", level="WARNING", category="dit", force=True)
395395
raise
396+
397+
# Handle conv2d/conv3d operations (critical for GGUF VAE models)
398+
# Conv3d layers (InflatedCausalConv3d) are not replaced by layer replacement
399+
if func in {torch.nn.functional.conv2d, torch.nn.functional.conv3d}:
400+
if len(args) >= 2 and isinstance(args[1], cls): # weight is second arg
401+
try:
402+
weight_tensor = args[1]
403+
dequantized_weight = weight_tensor.dequantize(device=args[0].device, dtype=args[0].dtype)
404+
new_args = (args[0], dequantized_weight) + args[2:]
405+
return func(*new_args, **kwargs)
406+
except Exception as e:
407+
if debug:
408+
debug.log(f"Error in conv dequantization: {e}", level="WARNING", category="dit", force=True)
409+
raise
396410

397411
# For ALL other operations, delegate to parent WITHOUT dequantization
398412
# This includes .cpu(), .to(), .device, .dtype, .shape, etc.

src/models/video_vae_v3/modules/attn_video_vae.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,7 +1093,7 @@ def __init__(
10931093
):
10941094
extra_cond_dim = kwargs.pop("extra_cond_dim") if "extra_cond_dim" in kwargs else None
10951095
self.slicing_sample_min_size = slicing_sample_min_size
1096-
self.slicing_latent_min_size = slicing_sample_min_size // (2**temporal_scale_num)
1096+
self.slicing_latent_min_size = max(1, slicing_sample_min_size // (2**temporal_scale_num))
10971097

10981098
super().__init__(
10991099
in_channels=in_channels,
@@ -1710,7 +1710,7 @@ def set_causal_slicing(
17101710
if split_size is not None:
17111711
self.enable_slicing()
17121712
self.slicing_sample_min_size = split_size
1713-
self.slicing_latent_min_size = split_size // self.temporal_downsample_factor
1713+
self.slicing_latent_min_size = max(1, split_size // self.temporal_downsample_factor)
17141714
else:
17151715
self.disable_slicing()
17161716
for module in self.modules():

src/models/video_vae_v3/modules/video_vae.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@ def __init__(
733733
if slicing_sample_min_size is None:
734734
slicing_sample_min_size = temporal_downsample_factor
735735
self.slicing_sample_min_size = slicing_sample_min_size
736-
self.slicing_latent_min_size = slicing_sample_min_size // (2**temporal_scale_num)
736+
self.slicing_latent_min_size = max(1, slicing_sample_min_size // (2**temporal_scale_num))
737737

738738
# pass init params to Encoder
739739
self.encoder = Encoder3D(
@@ -886,7 +886,7 @@ def set_causal_slicing(
886886
if split_size is not None:
887887
self.enable_slicing()
888888
self.slicing_sample_min_size = split_size
889-
self.slicing_latent_min_size = split_size // self.temporal_downsample_factor
889+
self.slicing_latent_min_size = max(1, split_size // self.temporal_downsample_factor)
890890
else:
891891
self.disable_slicing()
892892
for module in self.modules():
@@ -950,7 +950,7 @@ def set_causal_slicing(
950950
self.disable_slicing()
951951
self.slicing_sample_min_size = split_size
952952
if split_size is not None:
953-
self.slicing_latent_min_size = split_size // self.temporal_downsample_factor
953+
self.slicing_latent_min_size = max(1, split_size // self.temporal_downsample_factor)
954954
for module in self.modules():
955955
if isinstance(module, InflatedCausalConv3d):
956956
module.set_memory_device(memory_device)

src/optimization/compatibility.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ def ensure_bitsandbytes_safe():
9898
try:
9999
import bitsandbytes
100100
# Success - bitsandbytes works, other nodes can use it
101-
except (ImportError, OSError, RuntimeError):
102-
# Installation broken or not present - create stub
101+
except (ImportError, OSError, RuntimeError, ValueError):
102+
# Installation broken, not present, or version detection failed - create stub
103103
stub = types.ModuleType('bitsandbytes')
104104
stub.__spec__ = importlib.machinery.ModuleSpec('bitsandbytes', None)
105105
stub.__file__ = None
@@ -592,11 +592,11 @@ def validate_gguf_availability(operation: str = "load GGUF model", debug=None) -
592592
raise RuntimeError(f"GGUF library required to {operation}")
593593

594594

595-
# 4. NVIDIA Conv3d Memory Bug - Workaround for PyTorch 2.9-2.10 + cuDNN >= 91002
595+
# 4. NVIDIA Conv3d Memory Bug - Workaround for PyTorch >= 2.9 + cuDNN >= 91002
596596
def _check_conv3d_memory_bug():
597597
"""
598598
Check if Conv3d memory bug workaround needed.
599-
Bug: PyTorch 2.9-2.10 with cuDNN >= 91002 uses 3x memory for Conv3d
599+
Bug: PyTorch 2.9+ with cuDNN >= 91002 uses 3x memory for Conv3d
600600
with fp16/bfloat16 due to buggy dispatch layer.
601601
"""
602602
try:
@@ -622,7 +622,8 @@ def _check_conv3d_memory_bug():
622622
parts = version_str.split('.')
623623
torch_version = tuple(int(p) for p in parts[:2])
624624

625-
if not ((2, 9) <= torch_version <= (2, 10)):
625+
# Bug affects PyTorch 2.9 and later versions
626+
if torch_version < (2, 9):
626627
return False
627628

628629
if not hasattr(torch.backends.cudnn, 'version'):

src/utils/color_fix.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,8 @@ def _rgb_to_lab_batch(rgb: Tensor, device: torch.device, matrix: Tensor, epsilon
381381
rgb_flat = rgb_linear.permute(0, 2, 3, 1).reshape(-1, 3)
382382
del rgb_linear
383383

384+
# Ensure dtype consistency for matrix multiplication
385+
rgb_flat = rgb_flat.to(dtype=matrix.dtype)
384386
xyz_flat = torch.matmul(rgb_flat, matrix.T)
385387
del rgb_flat
386388

@@ -452,6 +454,8 @@ def _lab_to_rgb_batch(lab: Tensor, device: torch.device, matrix_inv: Tensor, eps
452454
xyz_flat = xyz.permute(0, 2, 3, 1).reshape(-1, 3)
453455
del xyz
454456

457+
# Ensure dtype consistency for matrix multiplication
458+
xyz_flat = xyz_flat.to(dtype=matrix_inv.dtype)
455459
rgb_linear_flat = torch.matmul(xyz_flat, matrix_inv.T)
456460
del xyz_flat
457461

src/utils/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"""
55

66
# Version information
7-
__version__ = "2.5.22"
7+
__version__ = "2.5.23"
88

99
import os
1010
import warnings

src/utils/debug.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class Debug:
7878
"device": "🖥️", # Device info
7979
"file": "📂", # File operations
8080
"alpha": "👻", # Alpha operations
81-
"star": "⭐", # Star
81+
"starlove": "⭐💝", # Star + love
8282
"dialogue": "💬", # Dialogue
8383
"none" : "",
8484
}
@@ -259,9 +259,9 @@ def print_footer(self) -> None:
259259
"""Print the footer with links - always displayed"""
260260
self.log("", category="none", force=True)
261261
self.log("────────────────────────", category="none", force=True)
262-
self.log("Questions? Updates? Watch the videos, star the repo & join us!", category="dialogue", force=True)
262+
self.log("Questions? Updates? Watch, star & sponsor if you can!", category="dialogue", force=True)
263263
self.log("https://www.youtube.com/@AInVFX", category="generation", force=True)
264-
self.log("https://github.com/numz/ComfyUI-SeedVR2_VideoUpscaler", category="star", force=True)
264+
self.log("https://github.com/numz/ComfyUI-SeedVR2_VideoUpscaler", category="starlove", force=True)
265265

266266
@torch._dynamo.disable # Skip tracing to avoid time.time() warnings
267267
def start_timer(self, name: str, force: bool = False) -> None:

0 commit comments

Comments
 (0)