Export With Ffmpeg (mtb)¶
Documentation¶
- Class name:
Export With Ffmpeg (mtb)
- Category:
mtb/IO
- Output node:
True
The Export With Ffmpeg (mtb) node provides functionality for exporting media files using FFmpeg, supporting various formats and codecs. It allows for the conversion of image sequences or playlists into video files, with customizable frame rates, formats, and codecs, catering to different requirements for video production.
Input types¶
Required¶
fps
- Specifies the frames per second for the video export, affecting the playback speed and smoothness of the resulting video.
- Comfy dtype:
FLOAT
- Python dtype:
float
prefix
- A prefix for the output file name, aiding in the organization and identification of exported files.
- Comfy dtype:
STRING
- Python dtype:
str
format
- Determines the video file format (e.g., mov, mp4, mkv), influencing compatibility with different players and platforms.
- Comfy dtype:
COMBO[STRING]
- Python dtype:
str
codec
- Selects the codec used for encoding the video, impacting the balance between quality and file size.
- Comfy dtype:
COMBO[STRING]
- Python dtype:
str
Optional¶
images
- An optional tensor of images to be exported as a video, enabling the creation of video content from individual frames.
- Comfy dtype:
IMAGE
- Python dtype:
Optional[torch.Tensor]
playlist
- An optional list of video file paths for concatenation, facilitating the compilation of multiple videos into a single file.
- Comfy dtype:
PLAYLIST
- Python dtype:
Optional[List[str]]
Output types¶
video
- Comfy dtype:
VIDEO
- The path to the exported video file, indicating the successful creation of the video.
- Python dtype:
str
- Comfy dtype:
Usage tips¶
- Infra type:
CPU
- Common nodes: unknown
Source code¶
class MTB_ExportWithFfmpeg:
"""Export with FFmpeg (Experimental)"""
@classmethod
def INPUT_TYPES(cls):
return {
"optional": {
"images": ("IMAGE",),
"playlist": ("PLAYLIST",),
},
"required": {
"fps": ("FLOAT", {"default": 24, "min": 1}),
"prefix": ("STRING", {"default": "export"}),
"format": (
["mov", "mp4", "mkv", "gif", "avi"],
{"default": "mov"},
),
"codec": (
["prores_ks", "libx264", "libx265", "gif"],
{"default": "prores_ks"},
),
},
}
RETURN_TYPES = ("VIDEO",)
OUTPUT_NODE = True
FUNCTION = "export_prores"
CATEGORY = "mtb/IO"
def export_prores(
self,
fps: float,
prefix: str,
format: str,
codec: str,
images: Optional[torch.Tensor] = None,
playlist: Optional[List[str]] = None,
):
pix_fmt = "rgb48le" if codec == "prores_ks" else "yuv420p"
file_ext = format
file_id = f"{prefix}_{uuid.uuid4()}.{file_ext}"
if playlist is not None and images is not None:
log.info(f"Exporting to {output_dir / file_id}")
if playlist is not None:
if len(playlist) == 0:
log.debug("Playlist is empty, skipping")
return ("",)
temp_playlist_path = (
output_dir / f"temp_playlist_{uuid.uuid4()}.txt"
)
log.debug(
f"Create a temporary file to list the videos for concatenation to {temp_playlist_path}"
)
with open(temp_playlist_path, "w") as f:
for video_path in playlist:
f.write(f"file '{video_path}'\n")
out_path = (output_dir / file_id).as_posix()
# Prepare the FFmpeg command for concatenating videos from the playlist
command = [
"ffmpeg",
"-f",
"concat",
"-safe",
"0",
"-i",
temp_playlist_path.as_posix(),
"-c",
"copy",
"-y",
out_path,
]
log.debug(f"Executing {command}")
subprocess.run(command)
temp_playlist_path.unlink()
return (out_path,)
if (
images is None or images.size(0) == 0
): # the is None check is just for the type checker
return ("",)
frames = tensor2np(images)
log.debug(f"Frames type {type(frames[0])}")
log.debug(f"Exporting {len(frames)} frames")
if codec == "gif":
out_path = (output_dir / file_id).as_posix()
command = [
"ffmpeg",
"-f",
"image2pipe",
"-vcodec",
"png",
"-r",
str(fps),
"-i",
"-",
"-vcodec",
"gif",
"-y",
out_path,
]
process = subprocess.Popen(command, stdin=subprocess.PIPE)
for frame in frames:
model_management.throw_exception_if_processing_interrupted()
Image.fromarray(frame).save(process.stdin, "PNG")
process.stdin.close()
process.wait()
else:
frames = [frame.astype(np.uint16) * 257 for frame in frames]
height, width, _ = frames[0].shape
out_path = (output_dir / file_id).as_posix()
# Prepare the FFmpeg command
command = [
"ffmpeg",
"-y",
"-f",
"rawvideo",
"-vcodec",
"rawvideo",
"-s",
f"{width}x{height}",
"-pix_fmt",
pix_fmt,
"-r",
str(fps),
"-i",
"-",
"-c:v",
codec,
"-r",
str(fps),
"-y",
out_path,
]
process = subprocess.Popen(command, stdin=subprocess.PIPE)
for frame in frames:
model_management.throw_exception_if_processing_interrupted()
process.stdin.write(frame.tobytes())
process.stdin.close()
process.wait()
return (out_path,)