mirror of
https://github.com/Comfy-Org/ComfyUI.git
synced 2026-08-15 06:05:00 +08:00
fix: robust trim/crop for edge-case videos and pass-through previews
This commit is contained in:
@@ -606,8 +606,13 @@ class VideoFromFile(VideoInput):
|
||||
duration_cap = math.ceil(duration * sample_rate)
|
||||
|
||||
import comfy.utils
|
||||
raw_duration = self._get_raw_duration()
|
||||
window_seconds = duration if duration else max(raw_duration - start_time, 0.0)
|
||||
if duration:
|
||||
window_seconds = duration
|
||||
else:
|
||||
try:
|
||||
window_seconds = max(self._get_raw_duration() - start_time, 0.0)
|
||||
except ValueError:
|
||||
window_seconds = 0.0
|
||||
progress_total = max(1, int(round(window_seconds * float(rate))))
|
||||
pbar = comfy.utils.ProgressBar(progress_total)
|
||||
|
||||
@@ -707,6 +712,12 @@ class VideoFromFile(VideoInput):
|
||||
crop_rect = normalize_crop_rect(*self.__crop, out_width, out_height)
|
||||
if crop_rect is not None:
|
||||
out_width, out_height = crop_rect[2], crop_rect[3]
|
||||
if (out_width % 2 or out_height % 2) and crop_rect is None:
|
||||
even_width = out_width - out_width % 2
|
||||
even_height = out_height - out_height % 2
|
||||
if even_width > 0 and even_height > 0:
|
||||
crop_rect = (0, 0, even_width, even_height)
|
||||
out_width, out_height = even_width, even_height
|
||||
if out_width % 2 or out_height % 2:
|
||||
raise ValueError(f"H.264 output requires even dimensions, got {out_width}x{out_height}")
|
||||
source_size = (frame.width, frame.height)
|
||||
@@ -873,7 +884,7 @@ class VideoFromFile(VideoInput):
|
||||
duration=duration,
|
||||
crop=self.__crop,
|
||||
)
|
||||
if trimmed.get_duration() < duration and strict_duration:
|
||||
if strict_duration and duration and trimmed.get_duration() < duration:
|
||||
return None
|
||||
return trimmed
|
||||
|
||||
|
||||
@@ -250,7 +250,7 @@ class LoadVideo(io.ComfyNode):
|
||||
video = apply_video_trim(source, (edit or {}).get("trim"))
|
||||
video = apply_video_crop(video, (edit or {}).get("crop"))
|
||||
if video is source:
|
||||
return io.NodeOutput(video, ui=preview_input_video(file))
|
||||
return io.NodeOutput(video, ui=preview_input_video(file, source))
|
||||
return io.NodeOutput(video, ui=save_video_preview(video))
|
||||
|
||||
@classmethod
|
||||
@@ -268,25 +268,41 @@ class LoadVideo(io.ComfyNode):
|
||||
|
||||
return True
|
||||
|
||||
def preview_input_video(file: str) -> ui.PreviewVideo:
|
||||
def preview_input_video(file: str, video: Input.Video | None = None) -> ui.PreviewVideo:
|
||||
name, _ = folder_paths.annotated_filepath(file)
|
||||
subfolder, _, filename = name.replace("\\", "/").rpartition("/")
|
||||
return ui.PreviewVideo([ui.SavedResult(filename, subfolder, io.FolderType.input)])
|
||||
result = ui.SavedResult(filename, subfolder, io.FolderType.input)
|
||||
if video is not None:
|
||||
try:
|
||||
video._preview_result = (folder_paths.get_annotated_filepath(file), result)
|
||||
except AttributeError:
|
||||
pass
|
||||
return ui.PreviewVideo([result])
|
||||
|
||||
|
||||
def save_video_preview(video: Input.Video) -> ui.PreviewVideo:
|
||||
cached = getattr(video, "_preview_result", None)
|
||||
if cached is not None and os.path.isfile(cached[0]):
|
||||
return ui.PreviewVideo([cached[1]])
|
||||
|
||||
width, height = video.get_dimensions()
|
||||
full_output_folder, filename, counter, subfolder, _ = folder_paths.get_save_image_path(
|
||||
"ComfyUI_temp_video", folder_paths.get_temp_directory(), width, height
|
||||
)
|
||||
preview_format = Types.VideoContainer.MP4
|
||||
file = f"{filename}_{counter:05}_.{Types.VideoContainer.get_extension(preview_format)}"
|
||||
full_path = os.path.join(full_output_folder, file)
|
||||
video.save_to(
|
||||
os.path.join(full_output_folder, file),
|
||||
full_path,
|
||||
format=preview_format,
|
||||
codec="auto",
|
||||
)
|
||||
return ui.PreviewVideo([ui.SavedResult(file, subfolder, io.FolderType.temp)])
|
||||
result = ui.SavedResult(file, subfolder, io.FolderType.temp)
|
||||
try:
|
||||
video._preview_result = (full_path, result)
|
||||
except AttributeError:
|
||||
pass
|
||||
return ui.PreviewVideo([result])
|
||||
|
||||
|
||||
def apply_video_trim(video: Input.Video, trim, strict_duration: bool = False) -> Input.Video:
|
||||
|
||||
Reference in New Issue
Block a user