know-flow / src /text_to_video.py
Hieucyber2208's picture
Update src/text_to_video.py
5902d94 verified
raw
history blame
6.5 kB
from moviepy.video.io.VideoFileClip import VideoFileClip, AudioFileClip
from moviepy.video.VideoClip import TextClip, ImageClip
from moviepy.video.compositing.CompositeVideoClip import concatenate_videoclips, CompositeVideoClip
from moviepy.audio.AudioClip import concatenate_audioclips
from moviepy.video.tools.subtitles import SubtitlesClip
from moviepy.video.VideoClip import ColorClip
import os
from itertools import accumulate
import pysrt
def format_time(seconds):
"""Chuyển đổi thời gian (giây) thành định dạng SRT hh:mm:ss,ms"""
mins, sec = divmod(seconds, 60)
hours, mins = divmod(mins, 60)
return f"{int(hours):02}:{int(mins):02}:{int(sec):02},{int((sec % 1) * 1000):03}"
def get_audio_duration(audio_path):
# Lọc các file có đuôi .mp3
audio_paths = os.listdir(audio_path)
audio_list = [file for file in audio_paths if file.endswith(".mp3")]
# Khởi tạo danh sách audio duration
duration_list = []
for audio_path in audio_list:
# Mở file âm thanh và lấy thời gian
with AudioFileClip(f"./audio/{audio_path}") as audio:
duration_list.append(audio.duration)
# Tính tổng tích lũy thời gian
duration_list = [format_time(time) for time in list(accumulate(duration_list))]
return [format_time(0.0)] + duration_list
def create_srt_from_time_and_text(duration_time, text_folder, output_srt):
subtitle = ""
subtitle_index = 1
text_list = sorted([file for file in os.listdir(text_folder) if file.endswith('txt')])
# Duyệt qua các mốc thời gian và file text
for i in range(len(duration_time) - 1):
start_time = duration_time[i]
end_time = duration_time[i + 1]
# Lấy tên file text tương ứng
text_file = text_list[i]
text_path = os.path.join(text_folder, text_file)
if os.path.exists(text_path):
with open(text_path, 'r', encoding='utf-8') as f:
text = f.read().strip()
# Thêm phần subtitle vào chuỗi kết quả
subtitle += f"{subtitle_index}\n{start_time} --> {end_time}\n{text}\n\n"
subtitle_index += 1
else:
print(f"File {text_file} không tồn tại!")
# Lưu vào file SRT
with open(output_srt, 'w', encoding='utf-8') as f:
f.write(subtitle)
def concatenate_audio_files(audio_folder, output_audio_path):
# Lọc tất cả các file âm thanh .mp3 trong thư mục
audio_clips = []
for file in sorted(os.listdir(audio_folder)):
if file.endswith('.mp3'):
audio_path = os.path.join(audio_folder, file)
audio_clip = AudioFileClip(audio_path)
audio_clips.append(audio_clip)
# Ghép tất cả các audio clip lại với nhau
final_audio = concatenate_audioclips(audio_clips)
# Lưu kết quả vào file output
final_audio.write_audiofile(output_audio_path, codec = 'libmp3lame')
print(f"File audio đã được lưu tại: {output_audio_path}")
def create_video_from_images(image_folder, audio_path, output_video_path):
# Đọc file âm thanh để lấy thời lượng
audio = AudioFileClip(audio_path)
total_duration = audio.duration # Tổng thời lượng video bằng thời lượng audio
# Đọc tất cả các file ảnh trong thư mục và sắp xếp theo tên
image_files = [file for file in sorted(os.listdir(image_folder)) if file.endswith("png")]
if not image_files:
raise ValueError("Không tìm thấy ảnh nào trong thư mục!")
# Tính thời lượng hiển thị cho mỗi ảnh
duration_per_image = total_duration / len(image_files)
# Tạo danh sách các clip ảnh
clips = [ImageClip(f"./image/{img}").with_duration(duration_per_image).resized(width=1280) for img in image_files]
# Ghép các clip ảnh lại với nhau
final_video = concatenate_videoclips(clips, method="chain")
# Gán âm thanh vào video
final_video .audio = audio
# Xuất video
final_video.write_videofile(output_video_path, codec="libx264", audio_codec="aac", fps=30)
print(f"Video đã được lưu tại: {output_video_path}")
def wrap_text(text, max_width):
"""
Tự động xuống dòng để vừa với chiều rộng max_width.
"""
import textwrap
return "\n".join(textwrap.wrap(text, width=max_width))
def add_subtitles_to_video(video_path, subtitle_path, output_video_path):
"""
Thêm phụ đề từ file .srt trực tiếp vào video.
:param video_path: Đường dẫn video gốc
:param subtitle_path: Đường dẫn file .srt
:param output_video_path: Đường dẫn lưu video đầu ra
"""
# Đọc file video
video = VideoFileClip(video_path)
# Đọc file .srt
subs = pysrt.open(subtitle_path)
subtitle_clips = [] # Danh sách các đoạn phụ đề
# Xử lý từng dòng phụ đề
for sub in subs:
# Chuyển thời gian thành giây
start_time = sub.start.ordinal / 1000 # Chuyển từ milliseconds sang giây
end_time = sub.end.ordinal / 1000
font = "./BeVietnamPro-Light.ttf"
# Tạo clip phụ đề
txt_clip = TextClip(font=font, text=wrap_text(sub.text, max_width=85), font_size=30, stroke_color="black", stroke_width=3, color="#fff")
# Đặt vị trí hiển thị (giữa phía dưới video)
txt_clip = txt_clip.with_position(('center', 'bottom')).with_duration(end_time - start_time).with_start(start_time)
subtitle_clips.append(txt_clip)
# Ghép phụ đề vào video
final_video = CompositeVideoClip([video] + subtitle_clips)
# Xuất video với phụ đề
final_video.write_videofile(output_video_path, fps=video.fps, codec='libx264', threads=4)
print(f"Video với phụ đề đã được lưu tại: {output_video_path}")
def text_to_video():
duration_time = get_audio_duration("./audio")
create_srt_from_time_and_text(duration_time, './text', './output/subtitle.srt')
concatenate_audio_files("./audio","./output/final_audio.mp3")
create_video_from_images("./image","./output/final_audio.mp3","./output/output.mp4")
add_subtitles_to_video("./output/output.mp4", "./output/subtitle.srt", "./output/final_output.mp4")
if __name__ == "__main__":
text_to_video()