Add crf option to save video node. (#15191)

This commit is contained in:
comfyanonymous
2026-07-31 21:27:48 -07:00
committed by GitHub
parent a1c421994c
commit 235b466a0c
4 changed files with 61 additions and 5 deletions

View File

@@ -29,11 +29,13 @@ class VideoInput(ABC):
codec: VideoCodec = VideoCodec.AUTO,
metadata: Optional[dict] = None,
bit_depth: int | None = None,
crf: float | None = None,
):
"""
Abstract method to save the video input to a file.
bit_depth selects the encoded bit depth; None keeps the video's native depth.
crf selects the H.264 constant rate factor; None uses the encoder default.
"""
pass

View File

@@ -460,6 +460,7 @@ class VideoFromFile(VideoInput):
codec: VideoCodec = VideoCodec.AUTO,
metadata: Optional[dict] = None,
bit_depth: int | None = None,
crf: float | None = None,
):
if isinstance(self.__file, io.BytesIO):
self.__file.seek(0) # Reset the BytesIO object to the beginning
@@ -475,13 +476,15 @@ class VideoFromFile(VideoInput):
reuse_streams = False
if bit_depth is not None and video_encoding is not None and bit_depth != source_bit_depth:
reuse_streams = False
if crf is not None:
reuse_streams = False
if self.__start_time or self.__duration:
reuse_streams = False
if not reuse_streams:
if bit_depth is None:
bit_depth = source_bit_depth
return self._save_transcoded(container, path, format=format, codec=codec, metadata=metadata, bit_depth=bit_depth)
return self._save_transcoded(container, path, format=format, codec=codec, metadata=metadata, bit_depth=bit_depth, crf=crf)
streams = container.streams
@@ -514,6 +517,7 @@ class VideoFromFile(VideoInput):
codec: VideoCodec,
metadata: dict | None,
bit_depth: int,
crf: float | None = None,
):
"""Re-encode to H.264/AAC one frame at a time; peak memory does not scale with video length."""
open_kwargs = mp4_output_open_kwargs(path, format, codec)
@@ -659,6 +663,8 @@ class VideoFromFile(VideoInput):
out_video.width = out_width
out_video.height = out_height
out_video.pix_fmt = pix_fmt
if crf is not None:
out_video.options = {"crf": str(crf)}
# source pts pass through (rebased to 0), so variable frame rate survives
out_video.codec_context.time_base = video_stream.time_base
if audio_stream is not None:
@@ -827,6 +833,7 @@ class VideoFromComponents(VideoInput):
codec: VideoCodec = VideoCodec.AUTO,
metadata: Optional[dict] = None,
bit_depth: int | None = None,
crf: float | None = None,
):
"""Save the video to a file path or BytesIO buffer."""
open_kwargs = mp4_output_open_kwargs(path, format, codec)
@@ -847,6 +854,8 @@ class VideoFromComponents(VideoInput):
video_stream.width = self.__components.images.shape[2]
video_stream.height = self.__components.images.shape[1]
video_stream.pix_fmt = pix_fmt
if crf is not None:
video_stream.options = {"crf": str(crf)}
# Create an audio stream
audio_sample_rate = 1