dzmdd's picture
Upload folder using huggingface_hub (part 2)
bc50ea0 verified
Raw History Blame Contribute Delete
31.8 kB
"""Masked target-prefix continuation for recursive MiniMax H3 chains.
Generated scenes continue directly from the previous sampled H3 video/audio
latent tails, avoiding a lossy video decode/re-encode round trip. Imported
scene-1 video and audio still use their respective VAEs because no sampled H3
latent exists yet. A nested AV denoise mask protects the copied prefix while
the sampler generates only the future portion.
The mask design follows ComfyUI PR #15375 and seitanism's GPL-3.0
ComfyUI-H3-Motion-Context-MultiRef masked-extension work. Runtime support is
enabled lazily so ordinary guide-mode chains do not patch H3 mask handling.
"""
from __future__ import annotations
import logging
import math
import torch
from .contracts_v05 import CONTEXT_SPATIAL_PROXY_RECIPE, DETAIL_AV_RECIPE
from .nodes import (
AV_RUN_GRID,
AUDIO_HZ,
FPS,
VIDEO_RUN_GRID,
_audio_tail_from_latent,
_pixel_frames,
_resize,
_streams_from_latent,
)
_LOG = logging.getLogger("minimax_h3_context_loop.masked_prefix")
def _latent_context_spatial_proxy(video_prefix):
"""Low-pass a copied AV prefix through the fixed 5/6 latent canvas.
Time, channels, dtype, device, and final target geometry are unchanged.
Only this disposable copy is filtered; the predecessor checkpoint remains
byte-for-byte untouched.
"""
if not torch.is_tensor(video_prefix) or video_prefix.ndim != 5:
raise ValueError(
"h3_context_spatial_proxy: video prefix must be "
"[B,C,T,H,W], got %s." %
(tuple(getattr(video_prefix, "shape", ())),))
if not video_prefix.is_floating_point():
raise ValueError(
"h3_context_spatial_proxy: video prefix must be floating point.")
batch, channels, steps, latent_height, latent_width = (
int(value) for value in video_prefix.shape)
alignment = int(CONTEXT_SPATIAL_PROXY_RECIPE["pixel_alignment"])
numerator = int(CONTEXT_SPATIAL_PROXY_RECIPE["scale_numerator"])
denominator = int(CONTEXT_SPATIAL_PROXY_RECIPE["scale_denominator"])
def proxy_latent_size(value):
pixels = int(value) * 16
units = max(1, int(round(
pixels * numerator / float(denominator * alignment))))
return max(1, units * alignment // 16)
proxy_height = proxy_latent_size(latent_height)
proxy_width = proxy_latent_size(latent_width)
if (proxy_height, proxy_width) == (latent_height, latent_width):
return video_prefix.detach().contiguous().clone(), (
proxy_height, proxy_width)
source = video_prefix.permute(0, 2, 1, 3, 4).reshape(
batch * steps, channels, latent_height, latent_width)
work = source.float()
reduced = torch.nn.functional.interpolate(
work, size=(proxy_height, proxy_width), mode="area")
restored = torch.nn.functional.interpolate(
reduced, size=(latent_height, latent_width), mode="bilinear",
align_corners=False)
restored = restored.to(
device=video_prefix.device, dtype=video_prefix.dtype)
restored = restored.reshape(
batch, steps, channels, latent_height, latent_width).permute(
0, 2, 1, 3, 4).contiguous()
return restored, (proxy_height, proxy_width)
def _detail_av_alpha(position, step_count):
"""Return the latent-noise amount for one carried video step."""
position = int(position)
step_count = int(step_count)
if step_count < 1 or position < 0 or position >= step_count:
raise ValueError("h3_detail_av: position is outside its context span.")
ramp = min(int(DETAIL_AV_RECIPE["ramp_steps"]), step_count)
from_end = step_count - 1 - position
alpha = float(DETAIL_AV_RECIPE["alpha"])
if from_end >= ramp:
return alpha
alpha_end = float(DETAIL_AV_RECIPE["alpha_end"])
if from_end == 0:
return alpha_end
return alpha + (alpha_end - alpha) * (ramp - from_end) / ramp
def _detail_av_video_prefix(video_prefix, seed):
"""Build a deterministic, disposable noisy copy of an AV video prefix.
Only the video tensor is accepted here. The caller retains the clean
predecessor latent and the audio prefix independently, preventing this
one-shot context treatment from contaminating recursive state.
"""
if not torch.is_tensor(video_prefix) or video_prefix.ndim != 5:
raise ValueError(
"h3_detail_av: video prefix must be [B,C,T,H,W], got %s." %
(tuple(getattr(video_prefix, "shape", ())),)
)
if not video_prefix.is_floating_point():
raise ValueError("h3_detail_av: video prefix must be floating point.")
steps = int(video_prefix.shape[2])
expected_steps = int(DETAIL_AV_RECIPE["video_steps"])
if steps != expected_steps:
raise ValueError(
"h3_detail_av: the v2 recipe requires %d video steps, got %d." %
(expected_steps, steps)
)
out = video_prefix.detach().contiguous().clone()
scale = float(out.detach().float().std().item())
if not scale or not math.isfinite(scale):
_LOG.warning(
"h3_detail_av: degenerate carried-latent standard deviation; "
"using unit Gaussian scale")
scale = 1.0
generator = torch.Generator(device="cpu")
generator.manual_seed(int(seed) & 0xFFFFFFFFFFFFFFFF)
alphas = []
for position in range(steps):
amount = _detail_av_alpha(position, steps)
alphas.append(amount)
block = out[:, :, position]
noise = torch.randn(
tuple(block.shape), generator=generator, dtype=torch.float32,
device="cpu")
noise = noise.mul_(scale).to(
device=block.device, dtype=block.dtype)
out[:, :, position] = block * (1.0 - amount) + noise * amount
return out, scale, tuple(alphas)
def _require_h3_mask_support():
"""Compatibility alias retained for focused tests and chain callers."""
from .masking_support import require_h3_mask_support
return require_h3_mask_support("masked AV continuation")
def _snap_prefix_length(
requested, available, target_frames, preserve_audio_prefix=True):
"""Resolve an AV prefix on the grid required by its active streams."""
cap = min(int(requested), int(available), int(target_frames) - 1)
preserve_audio_prefix = bool(preserve_audio_prefix)
grid = AV_RUN_GRID if preserve_audio_prefix else VIDEO_RUN_GRID
minimum = 39 if preserve_audio_prefix else 5
run = next((value for value in grid if value <= cap), 0)
if run < minimum:
requirement = (
"at least 39 previous frames and an exact shared video/audio "
"boundary" if preserve_audio_prefix else
"at least 5 previous frames on H3's video latent grid"
)
raise ValueError(
"h3_masked_prefix: masked continuation needs %s and a target "
"longer than the prefix." % requirement
)
if run != int(requested):
if preserve_audio_prefix:
detail = "exact shared AV runs are 39, 90, 141, 192, and 243"
else:
detail = "video-only prefix snapped to H3's video latent grid"
_LOG.warning(
"h3_masked_prefix: context_length %d -> exact H3 prefix %d (%s)",
int(requested), run, detail)
return run
def _validate_target_streams(latent, strict_audio_grid=True):
video, audio = _streams_from_latent(latent)[:2]
if video.ndim == 4:
video = video.unsqueeze(0)
if audio.ndim == 3:
audio = audio.unsqueeze(0)
if video.ndim != 5:
raise ValueError(
"h3_masked_prefix: video latent must be [B,C,T,H,W], got %s" %
(tuple(video.shape),)
)
if audio.ndim != 4:
raise ValueError(
"h3_masked_prefix: audio latent must be [B,C,2,T], got %s" %
(tuple(audio.shape),)
)
if int(video.shape[0]) != 1 or int(audio.shape[0]) != 1:
raise ValueError(
"h3_masked_prefix: masked continuation supports H3 batch size 1."
)
target_frames = _pixel_frames(int(video.shape[2]))
expected_audio = int(round(target_frames / float(FPS) * AUDIO_HZ))
if int(audio.shape[-1]) != expected_audio:
message = (
"h3_masked_prefix: target latent has %d audio steps for %d video "
"frames; expected %d on H3's nominal 40 Hz grid." %
(int(audio.shape[-1]), target_frames, expected_audio)
)
if strict_audio_grid:
raise RuntimeError(message)
_LOG.warning("%s The target audio length is authoritative.", message)
return video, audio, target_frames
def _generated_video_tail(previous_latent, frames, target_video):
"""Copy a phase-aligned video prefix from a generated H3 AV latent."""
parts = _streams_from_latent(previous_latent)
if len(parts) < 2:
raise ValueError(
"h3_masked_prefix: previous sampled latent has no audio stream. "
"Wire the joint H3 AV sampler output, not a video-only latent."
)
source_video, source_audio = parts[:2]
if source_video.ndim == 4:
source_video = source_video.unsqueeze(0)
if source_audio.ndim == 3:
source_audio = source_audio.unsqueeze(0)
if source_video.ndim != 5:
raise ValueError(
"h3_masked_prefix: previous video latent must be [B,C,T,H,W], "
"got %s." % (tuple(source_video.shape),)
)
if source_audio.ndim != 4:
raise ValueError(
"h3_masked_prefix: previous audio latent must be [B,C,2,T], got "
"%s." % (tuple(source_audio.shape),)
)
if int(source_video.shape[0]) != 1 or int(source_audio.shape[0]) != 1:
raise ValueError(
"h3_masked_prefix: generated-latent continuation supports H3 "
"batch size 1."
)
# Valid H3 prefix runs 5/22/39/... map to 2/7/12/... latent steps. Full
# H3 clips and these prefixes are both 2 mod 5 latent steps, so slicing the
# source tail and placing it at target step zero preserves temporal phase.
video_steps = 2 + 5 * ((int(frames) - 5) // 17)
if _pixel_frames(video_steps) != int(frames):
raise RuntimeError(
"h3_masked_prefix: internal H3 context mapping failed for %d "
"frames." % int(frames)
)
if int(source_video.shape[2]) < video_steps:
raise ValueError(
"h3_masked_prefix: previous sampled latent has too few video "
"steps for the %d-frame context." % int(frames)
)
if tuple(source_video.shape[1:2] + source_video.shape[3:]) != tuple(
target_video.shape[1:2] + target_video.shape[3:]):
raise ValueError(
"h3_masked_prefix: previous/target video latent geometry differs: "
"%s vs %s. Keep chained clips at the same H3 resolution." %
(tuple(source_video.shape), tuple(target_video.shape))
)
return source_video[:1, :, -video_steps:].clone(), video_steps
def _encoded_video_tail(vae, previous_frames, frames, target_video, crop):
"""Encode an imported decoded-video tail when no H3 source latent exists."""
if getattr(previous_frames, "ndim", 0) != 4:
raise ValueError(
"h3_masked_prefix: imported previous frames must be IMAGE "
"[N,H,W,C]."
)
available = int(previous_frames.shape[0])
if available < int(frames):
raise ValueError(
"h3_masked_prefix: imported video has %d frames but the resolved "
"prefix needs %d." % (available, int(frames))
)
width = int(target_video.shape[4]) * 16
height = int(target_video.shape[3]) * 16
video_tail = _resize(
previous_frames[available - int(frames):], width, height, crop)
video_prefix = vae.encode(video_tail)
if getattr(video_prefix, "ndim", 0) != 5:
raise ValueError(
"h3_masked_prefix: video VAE returned %s; expected "
"[B,C,T,H,W]." %
(tuple(getattr(video_prefix, "shape", ())),)
)
video_steps = int(video_prefix.shape[2])
covered = _pixel_frames(video_steps)
if covered != int(frames):
raise RuntimeError(
"h3_masked_prefix: %d imported context frames encoded to %d "
"video steps covering %d frames; refusing a phase-shifted seam." %
(int(frames), video_steps, covered)
)
return video_prefix, video_steps
def _encode_imported_audio(audio_vae, audio, frames):
if audio_vae is None:
raise ValueError(
"h3_masked_prefix: imported-video scene 1 needs the H3 audio VAE "
"connected to Chain Context."
)
if audio is None:
raise ValueError(
"h3_masked_prefix: imported-video scene 1 has no context audio. "
"Reconnect source audio to Existing Video Context."
)
waveform = audio["waveform"]
sample_rate = int(audio["sample_rate"])
vae_rate = int(getattr(audio_vae, "audio_sample_rate", 32000))
if sample_rate != vae_rate:
try:
import torchaudio
except ImportError as exc:
raise RuntimeError(
"h3_masked_prefix: imported audio is %d Hz but the H3 audio "
"VAE wants %d Hz and torchaudio is unavailable." %
(sample_rate, vae_rate)
) from exc
waveform = torchaudio.functional.resample(
waveform, sample_rate, vae_rate)
wanted = int(round(int(frames) / float(FPS) * vae_rate))
if int(waveform.shape[-1]) < wanted:
raise ValueError(
"h3_masked_prefix: imported context audio is shorter than the "
"%d-frame masked prefix." % int(frames)
)
encoded = audio_vae.encode(waveform[:1, ..., -wanted:].movedim(1, -1))
if getattr(encoded, "ndim", 0) != 4:
raise ValueError(
"h3_masked_prefix: audio VAE returned %s; expected [B,C,2,T]." %
(tuple(getattr(encoded, "shape", ())),)
)
steps = int(round(int(frames) / float(FPS) * AUDIO_HZ))
if int(encoded.shape[-1]) < steps:
raise RuntimeError(
"h3_masked_prefix: %d frames need %d audio steps but the audio "
"VAE produced %d." % (int(frames), steps, int(encoded.shape[-1]))
)
return encoded[:1, ..., -steps:], steps, "imported decoded audio"
def _existing_mask_streams(latent, video, audio):
mask = latent.get("noise_mask")
if mask is None:
return (
torch.ones(
(1, 1, int(video.shape[2]), int(video.shape[3]),
int(video.shape[4])),
device=video.device, dtype=torch.float32,
),
torch.ones(
(1, 1, int(audio.shape[2]), int(audio.shape[3])),
device=audio.device, dtype=torch.float32,
),
)
if hasattr(mask, "unbind"):
parts = list(mask.unbind())
elif isinstance(mask, (tuple, list)):
parts = list(mask)
else:
raise ValueError(
"h3_masked_prefix: an existing target noise_mask is not a nested "
"H3 video/audio mask and cannot be composed safely."
)
if len(parts) < 2:
raise ValueError(
"h3_masked_prefix: existing target noise_mask has no audio stream."
)
video_mask, audio_mask = parts[:2]
if video_mask.ndim == 4:
video_mask = video_mask.unsqueeze(0)
if audio_mask.ndim == 3:
audio_mask = audio_mask.unsqueeze(0)
expected_video = (1, 1, int(video.shape[2]), int(video.shape[3]),
int(video.shape[4]))
expected_audio = (1, 1, int(audio.shape[2]), int(audio.shape[3]))
try:
video_mask = torch.broadcast_to(video_mask, expected_video).clone()
audio_mask = torch.broadcast_to(audio_mask, expected_audio).clone()
except RuntimeError as exc:
raise ValueError(
"h3_masked_prefix: existing AV noise-mask shapes %s / %s cannot "
"broadcast to target %s / %s." %
(tuple(video_mask.shape), tuple(audio_mask.shape), expected_video,
expected_audio)
) from exc
return video_mask.float(), audio_mask.float()
def apply_locked_source_audio_target(
latent, audio_vae, source_audio, *, lip_sync_options=None,
voice=None, clip_start_seconds=0.0,
voice_clip_start_seconds=None,
force_active_voice_prefix_seconds=0.0):
"""Place exact scene-local source audio in H3's protected target stream.
Reuse the standalone master-audio implementation so Chain Policy receives
the same authoritative target-grid sizing, short encoder-lookahead retry,
channel normalization, and mask composition as the public masking node.
The Current Shot window is already scene-local, so its clock begins at 0.
"""
if audio_vae is None:
raise ValueError(
"h3_source_audio_target: Lock source audio requires the H3 audio "
"VAE connected to Chain Context.")
if not isinstance(source_audio, dict):
raise ValueError(
"h3_source_audio_target: Current Shot state has no source-audio "
"target window. Keep Current Shot state connected to Chain Context.")
from .master_audio_context import MiniMaxH3ContexMasterAudioMaskedAV
option_kwargs = {}
if lip_sync_options is not None:
option_kwargs = {
key: lip_sync_options[key]
for key in (
"preroll_seconds", "lookahead_seconds", "audio_denoise",
"gap_denoise", "gate_hold_seconds")
}
out, prefix_frames, _clip_audio = (
MiniMaxH3ContexMasterAudioMaskedAV().prepare(
latent=latent,
audio_vae=audio_vae,
master_audio=source_audio,
clip_start_seconds=clip_start_seconds,
context_length=0,
voice=voice,
voice_clip_start_seconds=voice_clip_start_seconds,
force_active_voice_prefix_seconds=(
force_active_voice_prefix_seconds),
**option_kwargs,
))
if int(prefix_frames) != 0:
raise RuntimeError(
"h3_source_audio_target: audio-only target unexpectedly changed "
"the video prefix.")
return out
def _feather_preserved_prefix(video_mask, audio_mask, video_steps, audio_steps):
"""Apply a narrow, high-denoise handoff at a protected AV tail."""
video_steps = int(video_steps)
audio_steps = int(audio_steps)
video_feather = min(4, max(0, video_steps - 1))
if video_feather < 1:
video_mask[:, :, :video_steps] = 0.0
audio_mask[..., :audio_steps] = 0.0
return 0, 0
# Fractional H3 masks are most useful close to full denoise. Keep the
# accepted prefix exact until the final four video-latent steps, then
# give the model a deliberately narrow 0.85..0.95 reconstruction band.
# Audio uses its own shorter 200 ms ramp instead of inheriting the much
# wider video-to-audio grid conversion, which used to start the audible
# handoff roughly 575 ms before the prefix boundary.
audio_feather = min(max(0, audio_steps - 1), 8)
video_ramp = torch.linspace(
0.85, 0.95, video_feather,
device=video_mask.device, dtype=video_mask.dtype,
)
video_hard_steps = video_steps - video_feather
video_mask[:, :, :video_hard_steps] = 0.0
video_mask[:, :, video_hard_steps:video_steps] = torch.minimum(
video_mask[:, :, video_hard_steps:video_steps],
video_ramp.view(1, 1, video_feather, 1, 1),
)
if audio_feather:
audio_ramp = torch.linspace(
0.85, 0.95, audio_feather,
device=audio_mask.device, dtype=audio_mask.dtype,
)
audio_hard_steps = audio_steps - audio_feather
audio_mask[..., :audio_hard_steps] = 0.0
audio_mask[..., audio_hard_steps:audio_steps] = torch.minimum(
audio_mask[..., audio_hard_steps:audio_steps],
audio_ramp.view(1, 1, 1, audio_feather),
)
return video_feather, audio_feather
def _audio_feather_preserved_prefix(
video_mask, audio_mask, video_steps, audio_steps,
):
"""Keep picture exact and release only the final audio-prefix ticks."""
video_steps = int(video_steps)
audio_steps = int(audio_steps)
video_mask[:, :, :video_steps] = 0.0
audio_feather = min(8, max(0, audio_steps))
audio_hard_steps = audio_steps - audio_feather
audio_mask[..., :audio_hard_steps] = 0.0
if audio_feather:
indices = torch.arange(
1, audio_feather + 1,
device=audio_mask.device, dtype=audio_mask.dtype,
)
audio_ramp = 0.5 - 0.5 * torch.cos(
torch.pi * indices / float(audio_feather))
audio_mask[..., audio_hard_steps:audio_steps] = torch.minimum(
audio_mask[..., audio_hard_steps:audio_steps],
audio_ramp.view(1, 1, 1, audio_feather),
)
return audio_feather
def _drop_prefix_guides(conditioning, prefix_frames):
"""Remove target guides that conflict with the preserved latent prefix."""
out = []
dropped = []
for embedding, extra in conditioning:
metadata = extra.copy()
kept = []
for guide in metadata.get("minimax_keyframes") or []:
position = float(guide.get(
"resolved_frame_index", guide.get("frame_index", 0)))
if 0 <= position < int(prefix_frames):
dropped.append(position)
else:
kept.append(guide)
if "minimax_keyframes" in metadata:
metadata["minimax_keyframes"] = kept
out.append([embedding, metadata])
if dropped:
_LOG.warning(
"h3_masked_prefix: dropped %d target guide(s) inside preserved "
"frames 0..%d; the clean target latent already owns that prefix.",
len(dropped), int(prefix_frames) - 1,
)
return out
def apply_masked_prefix(
conditioning,
vae,
latent,
previous_frames,
context_length,
crop,
previous_latent=None,
audio_vae=None,
previous_audio=None,
temporal_feather=False,
audio_only_feather=False,
preserve_audio_prefix=True,
detail_video_taper=False,
detail_video_seed=0,
context_spatial_proxy="off",
latent_color_carry=None,
):
"""Return conditioning, masked target latent, and repeated trim length."""
_require_h3_mask_support()
target_video, target_audio, target_frames = _validate_target_streams(latent)
width = int(target_video.shape[4]) * 16
height = int(target_video.shape[3]) * 16
if previous_latent is not None:
source_video = _streams_from_latent(previous_latent)[0]
if source_video.ndim == 4:
source_video = source_video.unsqueeze(0)
if source_video.ndim != 5:
raise ValueError(
"h3_masked_prefix: previous video latent must be "
"[B,C,T,H,W], got %s." % (tuple(source_video.shape),)
)
available = _pixel_frames(int(source_video.shape[2]))
frames = _snap_prefix_length(
context_length, available, target_frames,
preserve_audio_prefix=preserve_audio_prefix)
video_prefix, video_steps = _generated_video_tail(
previous_latent, frames, target_video)
video_source = "previous sampled latent"
else:
if getattr(previous_frames, "ndim", 0) != 4:
raise ValueError(
"h3_masked_prefix: imported previous frames must be IMAGE "
"[N,H,W,C]."
)
available = int(previous_frames.shape[0])
frames = _snap_prefix_length(
context_length, available, target_frames,
preserve_audio_prefix=preserve_audio_prefix)
video_prefix, video_steps = _encoded_video_tail(
vae, previous_frames, frames, target_video, crop)
video_source = "imported decoded frames via video VAE"
if video_steps >= int(target_video.shape[2]):
raise ValueError(
"h3_masked_prefix: video prefix consumes the whole target latent."
)
context_spatial_proxy = str(context_spatial_proxy or "off").strip().lower()
if context_spatial_proxy == "latent_5_6":
if previous_latent is None:
raise ValueError(
"h3_context_spatial_proxy: latent 5/6 requires a sampled "
"predecessor latent; imported RGB context is not eligible.")
original_height = int(video_prefix.shape[3])
original_width = int(video_prefix.shape[4])
video_prefix, proxy_size = _latent_context_spatial_proxy(video_prefix)
video_source += " + 5/6 latent spatial proxy"
_LOG.info(
"h3_context_spatial_proxy: AV boundary latent %dx%d -> %dx%d "
"-> %dx%d; audio and saved predecessor are unchanged.",
original_width, original_height, int(proxy_size[1]),
int(proxy_size[0]), original_width, original_height)
elif context_spatial_proxy != "off":
raise ValueError(
"h3_context_spatial_proxy: masked AV accepts only off or "
"latent_5_6, got %r." % context_spatial_proxy)
latent_color_summary = None
if latent_color_carry is not None:
if previous_latent is None:
raise ValueError(
"h3_latent_color_carry: Color-Stable Drift AV requires a "
"sampled generated predecessor latent; imported scene-1 "
"context is not eligible.")
if not isinstance(latent_color_carry, dict):
raise ValueError(
"h3_latent_color_carry: scene anchor data is malformed.")
from .latent_color_carry import apply_delta_vae_color_carry
video_prefix, latent_color_summary = apply_delta_vae_color_carry(
video_prefix,
vae,
latent_color_carry.get("anchor_stats"),
latent_color_carry.get("current_stats"),
)
if bool(latent_color_summary.get("applied", False)):
video_source += " + tapered scene-one VAE-delta color carry"
else:
video_source += " + scene-one color carry (neutral)"
detail_scale = None
detail_alphas = ()
if bool(detail_video_taper):
if int(frames) != int(DETAIL_AV_RECIPE["context_frames"]):
raise ValueError(
"h3_detail_av: the experimental v2 recipe requires exactly "
"%d context frames, got %d." %
(int(DETAIL_AV_RECIPE["context_frames"]), int(frames))
)
video_prefix, detail_scale, detail_alphas = _detail_av_video_prefix(
video_prefix, detail_video_seed)
video_source += " + disposable Detail AV latent taper"
if not bool(preserve_audio_prefix):
audio_prefix = None
audio_steps = 0
audio_source = "open target (generated continuity off)"
elif previous_latent is not None:
audio_prefix, audio_steps, overhang = _audio_tail_from_latent(
previous_latent, frames)
audio_source = "previous sampled latent"
if abs(overhang) > 1e-9:
_LOG.warning(
"h3_masked_prefix: predecessor audio grid ends %.3f latent "
"steps from its last video frame; the copied %d-step prefix "
"is end-aligned. Use 39/90/141/... context frames for an exact "
"prefix duration.",
overhang, audio_steps,
)
else:
audio_prefix, audio_steps, audio_source = _encode_imported_audio(
audio_vae, previous_audio, frames)
if bool(preserve_audio_prefix):
expected_audio_steps = int(round(frames / float(FPS) * AUDIO_HZ))
if audio_steps != expected_audio_steps:
raise RuntimeError(
"h3_masked_prefix: %d video frames require %d audio steps, "
"got %d." % (frames, expected_audio_steps, audio_steps)
)
if audio_steps >= int(target_audio.shape[-1]):
raise ValueError(
"h3_masked_prefix: audio prefix consumes the whole target "
"latent.")
out_video = target_video.clone()
out_audio = target_audio.clone()
vp = video_prefix[:1].to(out_video.device, out_video.dtype)
ap = (audio_prefix[:1].to(out_audio.device, out_audio.dtype)
if audio_prefix is not None else None)
if (int(vp.shape[1]) != int(out_video.shape[1])
or tuple(vp.shape[3:]) != tuple(out_video.shape[3:])):
raise ValueError(
"h3_masked_prefix: encoded video prefix shape %s does not match "
"target %s." % (tuple(vp.shape), tuple(out_video.shape))
)
if ap is not None and tuple(ap.shape[1:3]) != tuple(out_audio.shape[1:3]):
raise ValueError(
"h3_masked_prefix: audio prefix shape %s does not match target %s."
% (tuple(ap.shape), tuple(out_audio.shape))
)
out_video[:, :, :video_steps] = vp
if ap is not None:
out_audio[..., :audio_steps] = ap
video_mask, audio_mask = _existing_mask_streams(
latent, out_video, out_audio)
video_feather_steps = audio_feather_steps = 0
if bool(audio_only_feather):
audio_feather_steps = _audio_feather_preserved_prefix(
video_mask, audio_mask, video_steps, audio_steps)
elif bool(temporal_feather):
video_feather_steps, audio_feather_steps = _feather_preserved_prefix(
video_mask, audio_mask, video_steps, audio_steps)
else:
video_mask[:, :, :video_steps] = 0.0
audio_mask[..., :audio_steps] = 0.0
import comfy.nested_tensor
out_latent = latent.copy()
out_latent["samples"] = comfy.nested_tensor.NestedTensor(
(out_video, out_audio))
out_latent["noise_mask"] = comfy.nested_tensor.NestedTensor(
(video_mask, audio_mask))
out_conditioning = _drop_prefix_guides(conditioning, frames)
if not bool(preserve_audio_prefix):
mask_summary = "audio fully denoisable (generated continuity off)"
elif audio_only_feather:
mask_summary = "audio-only half-cosine feather %d audio steps" % (
audio_feather_steps)
elif temporal_feather:
mask_summary = "temporal feather %d video / %d audio steps" % (
video_feather_steps, audio_feather_steps)
else:
mask_summary = "hard prefix mask"
if detail_scale is not None:
mask_summary += (
"; Detail AV video-only Gaussian taper %.3f -> %.3f over "
"%d steps (sigma %.4f, seed %d)" %
(float(detail_alphas[0]), float(detail_alphas[-1]),
int(DETAIL_AV_RECIPE["ramp_steps"]), float(detail_scale),
int(detail_video_seed)))
if latent_color_summary is not None:
mask_summary += (
"; scene-one latent color delta %s, brightness %+.4f, "
"saturation %.4f, audio unchanged" %
("applied" if latent_color_summary.get("applied") else "neutral",
float(latent_color_summary.get("brightness", 0.0)),
float(latent_color_summary.get("saturation", 1.0))))
_LOG.info(
"h3_masked_prefix: preserved %d target frames = %d video steps / %d "
"audio steps (%.3fs, video from %s, audio from %s); %s; target %d "
"frames at %dx%d; trim %d",
frames, video_steps, audio_steps, frames / float(FPS), video_source,
audio_source,
mask_summary,
target_frames, width, height, frames,
)
return out_conditioning, out_latent, frames