generate_Lipsynced_videos_online / lip_sync_online_v1_original.py
utkarsh2299's picture
Upload 8 files
09422f1 verified
Raw
History Blame Contribute Delete
5.09 kB
"""
Lip syncing code - Online version
"""
import os
import sys
import moviepy.editor as mp
from pysrt import SubRipFile, SubRipTime, SubRipItem
from pydub import AudioSegment
from tqdm import tqdm
import argparse
import logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
def srt_time_to_seconds(time_obj):
# Handles both pysrt.SubRipTime and datetime.time
if hasattr(time_obj, 'hours'):
return (
time_obj.hours * 3600 +
time_obj.minutes * 60 +
time_obj.seconds +
time_obj.milliseconds / 1000.0
)
else:
return (
time_obj.hour * 3600 +
time_obj.minute * 60 +
time_obj.second +
time_obj.microsecond / 1_000_000.0
)
def segment_audio(full_audio_path, srt_file, output_dir):
os.makedirs(output_dir, exist_ok=True)
full_audio = AudioSegment.from_file(full_audio_path)
srt = SubRipFile.open(srt_file)
audio_paths = []
logging.info("Segmenting audio based on SRT...")
for i, entry in enumerate(tqdm(srt, desc="Segmenting")):
start_ms = int(srt_time_to_seconds(entry.start) * 1000)
end_ms = int(srt_time_to_seconds(entry.end) * 1000)
segment = full_audio[start_ms:end_ms]
segment_path = os.path.join(output_dir, f"segment_{i+1:03d}.mp3")
segment.export(segment_path, format="mp3")
audio_paths.append(segment_path)
return audio_paths
def lip_sync(video_path, srt_path, audio_list, output_video, output_srt):
output_filename = os.path.splitext(output_video)[0]
video_obj = mp.VideoFileClip(video_path)
srt = SubRipFile.open(srt_path)
video_clips = []
prev_end_time = SubRipTime(0)
new_srt_start_time = []
new_srt_end_time = []
new_srt_total_duration = 0.0
for i, entry in enumerate(tqdm(srt, desc="Generating video segments")):
logging.info(f"Processing subtitle #{i+1}")
start = entry.start.to_time()
end = entry.end.to_time()
if srt_time_to_seconds(start) > srt_time_to_seconds(prev_end_time.to_time()):
inter_clip = video_obj.subclip(srt_time_to_seconds(prev_end_time.to_time()), srt_time_to_seconds(start)).without_audio()
silence = mp.afx.audio_loop(mp.AudioFileClip("silence.wav"), duration=inter_clip.duration)
video_clips.append(inter_clip.set_audio(silence))
new_srt_total_duration += inter_clip.duration
srt_clip = video_obj.subclip(srt_time_to_seconds(start), srt_time_to_seconds(end)).without_audio()
audio_clip = mp.AudioFileClip(audio_list[i])
if srt_clip.duration != audio_clip.duration:
srt_clip = srt_clip.fx(mp.vfx.speedx, factor=srt_clip.duration/audio_clip.duration)
final_clip = srt_clip.set_audio(audio_clip)
video_clips.append(final_clip)
new_srt_start_time.append(new_srt_total_duration)
new_srt_end_time.append(new_srt_total_duration + final_clip.duration)
new_srt_total_duration += final_clip.duration
prev_end_time = entry.end
if srt_time_to_seconds(srt[-1].end.to_time()) < video_obj.duration:
final_clip = video_obj.subclip(srt_time_to_seconds(srt[-1].end.to_time()), video_obj.duration).without_audio()
silence = mp.afx.audio_loop(mp.AudioFileClip("silence.wav"), duration=final_clip.duration)
video_clips.append(final_clip.set_audio(silence))
logging.info("Concatenating video segments...")
final_video = mp.concatenate_videoclips(video_clips)
final_video.write_videofile(
output_video,
codec="libx264",
threads=30,
audio_codec='aac',
temp_audiofile=output_filename+'.m4a',
remove_temp=True,
preset="medium",
ffmpeg_params=["-profile:v", "baseline", "-level", "3.0", "-pix_fmt", "yuv420p"]
)
logging.info("Writing updated SRT timings...")
new_srt = SubRipFile()
for i, entry in enumerate(srt):
new_srt.append(SubRipItem(
index=i+1,
start=SubRipTime(seconds=new_srt_start_time[i]),
end=SubRipTime(seconds=new_srt_end_time[i]),
text=entry.text
))
new_srt.save(output_srt, encoding='utf-8')
logging.info("Lip sync video generation complete.")
def parse_arguments():
parser = argparse.ArgumentParser()
parser.add_argument("--original_video_path", required=True)
parser.add_argument("--Translated_SRT", required=True)
parser.add_argument("--tts_audio_path", required=True)
parser.add_argument("--output_video_path", required=True)
parser.add_argument("--new_srt_path", required=True)
parser.add_argument("--segmented_audio_dir", default="segmented_audio")
return parser.parse_args()
if __name__ == "__main__":
args = parse_arguments()
segmented_audio = segment_audio(args.tts_audio_path, args.Translated_SRT, args.segmented_audio_dir)
lip_sync(args.original_video_path, args.Translated_SRT, segmented_audio, args.output_video_path, args.new_srt_path)