Reputation: 1
I've been trying to use Movie Py to create a .srt file, and add the subtitles to a video. The first video without captions, made in _match_audio_duration()
, exports sucessfully. The captions file is also created sucessfully, and appears to be in the right format, but the script crashes when trying to add the captions file to the video.
The line that fails:
final_clip = mp.CompositeVideoClip([input_clip, caption_clip.set_position(("center", "bottom"))])
import os
import subprocess
import time
import moviepy.editor as mp
import pyttsx3
from moviepy.video.tools.subtitles import SubtitlesClip
class VideoEditor:
def __init__(self, input_text_path, input_video_path, output_dir):
self.input_text_path = input_text_path
self.input_video_path = input_video_path
self.output_dir = output_dir
self.text = ""
self.audio_path = ""
self.video_path = ""
self.caption_path = ""
def _convert_text_to_audio(self):
# Read text from file
with open(self.input_text_path, "r") as f:
self.text = f.read()
# Set up pyttsx3
engine = pyttsx3.init()
# Convert text to speech and save as MP3
self.audio_path = os.path.join(self.output_dir, "audio.mp3")
engine.save_to_file(self.text, self.audio_path)
engine.runAndWait()
def _match_audio_duration(self):
# Set up moviepy
input_clip = mp.VideoFileClip(self.input_video_path)
audio_clip = mp.AudioFileClip(self.audio_path)
if audio_clip.duration > input_clip.duration:
input_clip = input_clip.fx(mp.vfx.loop, duration=audio_clip.duration)
# Add audio to video
final_clip = input_clip.set_audio(audio_clip)
# Cut video to match audio duration
final_clip = final_clip.subclip(0, audio_clip.duration)
# Save output video
self.video_path = os.path.join(self.output_dir, "output_video.mp4")
final_clip.write_videofile(self.video_path, fps=24)
def _create_captions(self):
# Create captions from text
self.caption_path = os.path.join(self.output_dir, "captions.srt")
caption_txt = ""
for i, line in enumerate(self.text.splitlines()):
start = i * 3
end = (i + 1) * 3
caption_txt += f"{start}00 --> {end}00\n{line}\n\n"
with open(self.caption_path, "w") as f:
f.write(caption_txt)
def add_captions_to_video(self):
self._convert_text_to_audio()
self._match_audio_duration()
self._create_captions()
# Set up moviepy
input_clip = mp.VideoFileClip(self.video_path)
# Create TextClip for captions
captions = SubtitlesClip(self.caption_path)
caption_clip = captions.set_position(("center", "bottom"))
# Overlay captions on video
final_clip = mp.CompositeVideoClip([input_clip, caption_clip.set_position(("center", "bottom"))])
# Save output video
output_path = os.path.join(self.output_dir, "output_video_captions.mp4")
final_clip.write_videofile(output_path, fps=24)
I double checked the format of the captions file, everything I could find about this error suggested that it was being the captions were in the wrong format or something.
The error:
Traceback (most recent call last):
File "*directory*", line 86, in <module>
editor.add_captions_to_video()
File "*directory*", line 69, in add_captions_to_video
captions = SubtitlesClip(self.caption_path)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "*directory*", line 55, in __init__
self.duration = max([tb for ((ta,tb), txt) in self.subtitles])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "*directory*", line 55, in <listcomp>
self.duration = max([tb for ((ta,tb), txt) in self.subtitles])
^^^^^^^
TypeError: cannot unpack non-iterable NoneType object
Exception ignored in: <function FFMPEG_VideoReader.__del__ at 0x000002097E824400>
Traceback (most recent call last):
File "*directory*", line 199, in __del__
self.close()
File "*directory*", line 190, in close
self.proc.terminate()
File "*directory*", line 1642, in terminate
_winapi.TerminateProcess(self._handle, 1)
OSError: [WinError 6] The handle is invalid
Upvotes: 0
Views: 826
Reputation: 32124
As far as I can tell the issue is the format of subtitles file captions.srt
.
It looks like SubtitlesClip
is very sensitive to the .srt
format structure.
I am not sure, it's the only issue, because the code fails in captions = SubtitlesClip(self.caption_path)
and not in final_clip = mp.CompositeVideoClip
.
When fixing the captions.srt
file, the code finishes successfully.
For correcting the format of captions.srt
we may use the following code (note that I don't know how to synchronize the captions with the audio):
def _create_captions(self):
# Create captions from text
self.caption_path = os.path.join(self.output_dir, "captions.srt")
caption_txt = ""
for i, line in enumerate(self.text.splitlines()):
start = i * 3
end = (i + 1) * 3
start_str = str(datetime.timedelta(seconds=start)) + ',0' # Convert from seconds to hh:mm:ss,0 format
end_str = str(datetime.timedelta(seconds=end)) + ',0'
caption_txt += f"{i+1}\n" # Write the sequential counter
caption_txt += f"{start_str} --> {end_str}\n{line}\n\n"
with open(self.caption_path, "w") as f:
f.write(caption_txt)
As far as I know, the .srt
file format is as follows:
1
00:00:00,0 --> 00:00:01,0
First sentence
2
00:00:01,0 --> 00:00:02,0
Second sentence
3
00:00:02,0 --> 00:00:03,0
Third sentence
4
00:00:03,0 --> 00:00:04,0
Forth sentence
5
00:00:04,0 --> 00:00:05,0
Fifth sentence
For debugging, we may replace captions.srt
with the text above.
Upvotes: 0