Add audio muxing to processed videos using ffmpeg

After processing a video, the original audio track is now muxed into the output file using ffmpeg if available. This ensures the resulting video retains its original audio, and the process fails gracefully if ffmpeg is not present or an error occurs.
This commit is contained in:
scofano
2025-11-20 12:47:52 -03:00
parent 63253a9267
commit 86f8686d30
+43 -2
View File
@@ -1,4 +1,5 @@
import os
import subprocess
import numpy as np
import torch
from PIL import Image, ImageDraw, ImageFont, ImageChops
@@ -643,6 +644,9 @@ class TextOverlayVideo:
Shows progress in:
- ComfyUI (ProgressBar)
- Console (tqdm)
After writing the processed video, we mux the original audio track
from `video_path` into the output file using ffmpeg, if available.
"""
if not video_path or not os.path.exists(video_path):
raise FileNotFoundError(f"Video file not found: {video_path}")
@@ -669,7 +673,6 @@ class TextOverlayVideo:
# 2) Otherwise, estimate from duration * fps if we have that
elif isinstance(duration, (int, float)) and duration > 0 and fps > 0:
total_frames = int(duration * fps)
# ComfyUI progress bar
@@ -683,7 +686,6 @@ class TextOverlayVideo:
else:
frame_iter = tqdm(reader, desc="TextOverlayVideo")
T = max(1, int(animation_frames)) if animate else 1
writer = imageio.get_writer(
@@ -753,6 +755,45 @@ class TextOverlayVideo:
writer.close()
reader.close()
# ---- NEW: mux original audio into the processed video using ffmpeg ----
try:
# We create a temporary output file, then replace the original out_path
tmp_out = out_path + ".tmp_audio.mp4"
# ffmpeg command:
# - input 0: processed video (no audio)
# - input 1: original video (with audio)
# - copy streams without re-encoding: -c copy
# - map video from 0, audio from 1
cmd = [
"ffmpeg",
"-y", # overwrite without asking
"-i", out_path,
"-i", video_path,
"-c", "copy",
"-map", "0:v:0",
"-map", "1:a:0",
tmp_out,
]
completed = subprocess.run(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=False,
)
if completed.returncode == 0:
os.replace(tmp_out, out_path)
else:
# If something goes wrong, keep the silent video and print the error
print("[TextOverlayVideo] ffmpeg failed to mux audio, keeping silent video.")
print(completed.stderr.decode("utf-8", errors="ignore"))
except Exception as e:
# Fail gracefully: overlay still works, just no audio
print(f"[TextOverlayVideo] Could not mux audio from original video: {e}")
# Return STRING so it can be wired or ignored; node still runs even if not connected
return (out_path,)