qur / background.py
digidau's picture
Update background.py
d9e2c18 verified
Raw
History Blame Contribute Delete
3.52 kB
import subprocess
import os
def generate_background(images, output_path):
if not images:
raise Exception("No images uploaded")
temp_videos = []
slide_duration = 15
fade_duration = 1
total_slide_duration = slide_duration + fade_duration
fps = 30
total_frames = int(total_slide_duration * fps)
# =====================================================
# GENERATE EACH SLIDE
# =====================================================
for i, img in enumerate(images):
temp_video = f"/tmp/slide_{i}.mp4"
temp_videos.append(temp_video)
vf = (
"scale=3840:2160:force_original_aspect_ratio=increase,"
"crop=3840:2160,"
f"zoompan="
f"z='1+0.30*on/{total_frames}':"
f"x='(iw-iw/zoom)/2':"
f"y='(ih-ih/zoom)/2':"
f"d={total_frames}:"
"s=3840x2160:"
f"fps={fps},"
"scale=1920:1080:flags=lanczos"
)
cmd = [
"ffmpeg",
"-y",
"-loop", "1",
"-i", img,
"-vf", vf,
"-t", str(total_slide_duration),
"-c:v", "libx264",
"-preset", "ultrafast",
"-crf", "22",
"-pix_fmt", "yuv420p",
temp_video
]
print(f"Generating slide {i+1}/{len(images)}")
subprocess.run(cmd, check=True)
# =====================================================
# SINGLE IMAGE
# =====================================================
if len(temp_videos) == 1:
os.replace(temp_videos[0], output_path)
return
# =====================================================
# XFADE COMBINE
# =====================================================
print("Combining slides...")
cmd_concat = ["ffmpeg", "-y"]
for v in temp_videos:
cmd_concat.extend(["-i", v])
filter_complex = ""
current = "[0:v]"
offset = slide_duration
for i in range(1, len(temp_videos)):
next_input = f"[{i}:v]"
if i == len(temp_videos) - 1:
out = ""
else:
out = f"[v{i}]"
filter_complex += (
f"{current}{next_input}"
f"xfade="
f"transition=fade:"
f"duration={fade_duration}:"
f"offset={offset}"
f"{out};"
)
current = f"[v{i}]"
offset += slide_duration
filter_complex = filter_complex.rstrip(";")
cmd_concat.extend([
"-filter_complex", filter_complex,
"-c:v", "libx264",
"-preset", "ultrafast",
"-crf", "22",
"-pix_fmt", "yuv420p",
output_path
])
subprocess.run(cmd_concat, check=True)
# =====================================================
# CHECK RESULT
# =====================================================
probe = subprocess.run(
[
"ffprobe",
"-v", "error",
"-show_entries",
"format=duration",
"-of",
"default=noprint_wrappers=1:nokey=1",
output_path
],
capture_output=True,
text=True
)
print("\nSUCCESS")
print(f"Duration: {probe.stdout.strip()} sec")
# =====================================================
# CLEANUP
# =====================================================
for v in temp_videos:
if os.path.exists(v):
os.remove(v)