video_gen / src /components /each_necklace_video_gen.py
ishworrsubedii's picture
add: endpoint product video gen --> one combined
15a5b8a
raw
history blame
8.34 kB
"""
project @ images_to_video
created @ 2024-12-17
author @ github.com/ishworrsubedii
"""
import os
from moviepy.audio.io.AudioFileClip import AudioFileClip
from moviepy.video.VideoClip import ImageClip, ColorClip, TextClip
from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip
from moviepy.video.compositing.concatenate import concatenate_videoclips
from moviepy.video.fx.all import resize
from moviepy.video.io.VideoFileClip import VideoFileClip
class EachVideoCreator:
def __init__(self, necklace_title, nto_title, cto_title, makeup_title, intro_video_path=None, necklace_image=None,
nto_outputs=None,
nto_cto_outputs=None, makeup_outputs=None, font_path=None, output_path=None,
audio_path=None, image_display_duration=2.5, box_color=(131, 42, 48), box_opacity=0.8,
font_size=28, text_color="white", fps=1):
self.intro_video_path = intro_video_path
self.necklace_images = necklace_image if necklace_image else []
self.nto_outputs = nto_outputs if nto_outputs else []
self.nto_cto_outputs = nto_cto_outputs if nto_cto_outputs else []
self.makeup_outputs = makeup_outputs if makeup_outputs else []
self.output_video_path = output_path
self.font_path = font_path
self.audio_path = audio_path
self.image_display_duration = image_display_duration
self.box_color = box_color
self.box_opacity = box_opacity
self.font_size = font_size
self.text_color = text_color
self.fps = fps
self.necklace_title = necklace_title
self.nto_title = nto_title
self.cto_title = cto_title
self.makeup_title = makeup_title
def create_necklace_clips(self, necklace_image, index, label):
if not necklace_image:
print(f"Skipping necklace {index + 1}: No image provided.")
return []
backgrounds = [
(245, 245, 245), # Soft White
(220, 245, 245), # Light Blue
(230, 230, 235) # Pearl Gray
]
necklace_clips = []
for bg_color in backgrounds:
bg_clip = ColorClip((1080, 1080), col=bg_color, duration=self.image_display_duration)
necklace = resize(ImageClip(necklace_image), width=650)
necklace = necklace.set_duration(self.image_display_duration).set_position('center')
txt_overlay = self.create_text_overlay(f"{label}")
final_clip = CompositeVideoClip([bg_clip, necklace, txt_overlay.set_position(('center', 'bottom'))])
necklace_clips.append(final_clip)
return necklace_clips
def create_grouped_clips(self, grouped_images, label):
clips = []
for idx, group in enumerate(grouped_images):
for img_path in group:
if os.path.exists(img_path) and img_path.lower().endswith(('.png', '.jpg', '.jpeg')):
print(f"Processing {label} image: {img_path}")
img_clip = resize(ImageClip(img_path), (1080, 1080))
txt_overlay = self.create_text_overlay(f"{label} {idx + 1}")
final_clip = CompositeVideoClip([
img_clip.set_duration(self.image_display_duration),
txt_overlay.set_position(('center', 'bottom'))
])
clips.append(final_clip)
return clips
def create_text_overlay(self, text, duration=None):
box = ColorClip((1080, 80), col=self.box_color, duration=duration or self.image_display_duration)
box = box.set_opacity(self.box_opacity)
txt = TextClip(text, font=self.font_path, fontsize=self.font_size, color=self.text_color)
return CompositeVideoClip([box, txt.set_position('center')])
def create_final_video(self):
try:
print("Starting video creation...")
clips = []
# Step 1: Process Intro Video
if self.intro_video_path and os.path.exists(self.intro_video_path):
print(f"Adding intro video from path: {self.intro_video_path}")
intro_clip = resize(VideoFileClip(self.intro_video_path), (1080, 1080))
clips.append(intro_clip)
else:
print("Skipping intro video: Path not provided or invalid.")
# Step 2: Process Necklaces and Associated Outputs
for idx, necklace_image in enumerate(self.necklace_images):
print(f"Processing Necklace {idx + 1}...")
# Necklace preview clips
necklace_clips = self.create_necklace_clips(necklace_image, idx, self.necklace_title[idx])
if necklace_clips:
clips.extend(necklace_clips)
else:
print(f"Skipping Necklace {idx + 1} preview: No valid clips created.")
# NTO outputs
if idx < len(self.nto_outputs):
print(f"Adding NTO outputs for Necklace {idx + 1}")
nto_clips = self.create_grouped_clips([self.nto_outputs[idx]], self.nto_title[idx])
if nto_clips:
clips.extend(nto_clips)
else:
print(f"No valid NTO clips for Necklace {idx + 1}")
# CTO outputs
if idx < len(self.nto_cto_outputs):
print(f"Adding CTO outputs for Necklace {idx + 1}")
cto_clips = self.create_grouped_clips([self.nto_cto_outputs[idx]], self.cto_title[idx])
if cto_clips:
clips.extend(cto_clips)
else:
print(f"No valid CTO clips for Necklace {idx + 1}")
# Makeup outputs
if idx < len(self.makeup_outputs):
print(f"Adding Makeup outputs for Necklace {idx + 1}")
makeup_clips = self.create_grouped_clips([self.makeup_outputs[idx]], self.makeup_title[idx])
if makeup_clips:
clips.extend(makeup_clips)
else:
print(f"No valid Makeup clips for Necklace {idx + 1}")
final_clips = []
for clip in clips:
final_clips.append(clip.set_duration(self.image_display_duration))
clips = final_clips
if not clips:
print("No valid clips to combine. Exiting.")
return
print(f"Total clips to concatenate: {len(clips)}")
final_video = concatenate_videoclips(clips, method="compose")
# Step 4: Add Background Audio
if self.audio_path and os.path.exists(self.audio_path):
print(f"Adding background audio from path: {self.audio_path}")
try:
audio = AudioFileClip(self.audio_path).subclip(0, final_video.duration)
final_video = final_video.set_audio(audio)
except Exception as e:
print(f"Error adding audio: {e}")
else:
print("Skipping background audio: Path not provided or invalid.")
# Step 5: Export Final Video
print("Rendering final video...")
final_video.write_videofile(
self.output_video_path,
fps=self.fps,
codec="libx264",
audio_codec="aac",
threads=4,
preset="ultrafast"
)
print(f"Video successfully saved to: {self.output_video_path}")
except Exception as e:
print(f"An error occurred during video creation: {e}")
# if __name__ == "__main__":
# creator = EachVideoCreator(
# intro_video_path="intro.mp4",
# necklace_image=["necklace.jpg", "necklace2.png"],
# nto_outputs=[["nto1.jpg", "nto2.jpg"], ["nto3.jpg", "nto4.jpg"]],
# nto_cto_outputs=[["cto1.jpg", "cto2.jpg"], ["cto3.jpg", "cto4.jpg"]],
# makeup_outputs=[["makeup1.jpg", "makeup2.jpg"], ["makeup3.jpg", "makeup4.jpg"]],
# font_path="font.ttf",
# output_path="output/final_video.mp4",
# audio_path="audio.mp3"
# )
# creator.create_final_video()