I am trying to build a small video editor using a Tkinter GUI and Moviepy.
The start/end times of the desired subclip are entered by the user. The error occurs when the user does not specify the end time (the program uses the duration of the source video as the end time for the sub clip.
source_video = VideoFileClip("sample_video_clip.mp4")
start_time = float(start_time_entry.get())
eg: 6 seconds
The user did not specify the end time so the program uses the duration of source clip using the moviepy duration function
end_time = source_video.duration eg. 56.11 seconds
I then try to display the frames that relate to the these time locations
end_frame_image_array = source_video.get_frame(end_time)
end_frame_image_location = Image.fromarray(end_frame_image_array)
end_frame_image_resized = end_frame_image_location.resize((150,100))
end_frame_image = ImageTk.PhotoImage(end_frame_image_resized)
end_frame_label.config(image=end_frame_image)
The following error appears.
OSError: MoviePy error: failed to read the first frame of video file
C:/Users/.../sample_video_clip.mp4.
That might mean that the file is corrupted. That may also mean that
you are using a deprecated version of FFMPEG. On Ubuntu/Debian for
instance the version in the repos is deprecated. Please update to a
recent version from the website.
If the user enters a valid end time not including manually entering 56.11seconds (the duration of the clip) the frame is displayed.
The start frame is also displayed using similar code and works fine
Edit 1.0: Tried using other .mp4 files and the error continues. I don't think its related to the file being corrupted as I can open the files in the media player and also import them into Adobe premier pro 2015
Edit 2.0: looked at the frame.1 seconds from the end time and the image is displayed (see code change below). Error continues if -.1 is not included
end_frame_image_array = source_video.get_frame((end_time-.1))
Edit 3.0: Manually entered time clips until I got to this error
Source Clip duration (length) = 56.11 seconds
entering 56.038 seconds as the end time generates the clip as desired
entering 56.04 and upwards brings up the error stated above
Related
After I Converted it, if i click get info it shows the real duration
ConvertFile = AudioSegment.from_file(fullPath, format=fileFormat) ConvertFile.export(fullPath,format=self.ExportFormat)
But after I play it on MAC it doubles the playing time automatically,
although I track the file itself it shows the original duration
So I wrote a script that creates a video out of a series of images. I have the images stored in a folder called "TEMP". The part of the script that takes a very long time is the following:
from moviepy.editor import *
def createVideoFromImages(genre, audio):
#export name
timeStamp = str(time.time()).split(".")[0]
exportFolderName = f"./finished/{genre}{timeStamp}"
exportFileName = f"{exportFolderName}/video.mp4"
images = os.listdir("TEMP")
clips = [ImageClip(f"./TEMP/{m}").set_duration(10).crossfadein(1.0) for m in images]
concat_clip = concatenate_videoclips(clips, method="compose")
audio_duration = audio.duration
videoclip = concat_clip.set_duration(audio_duration)
exportClip = videoclip.set_audio(audio)
#create folder and save video there
os.mkdir(exportFolderName)
exportClip.write_videofile(exportFileName, fps=60, preset="ultrafast")
return exportFolderName
I tried a couple of things, like changing the concatenation of videoclips to method="chain" but that broke and I got a glitchy video, where only the first image was properly showing.
I also tried to add the preset="ultrafast" as I found somewhere online, but I find it to slow things down rather than speed things up.
I suspect the script to run this slow(it takes 8-9 hours for an ~300 second video) because it takes almost all the RAM of my computer.
Is there a way to speed up this script, preferrably with a minimal sacrifice of quality?
I'm trying to get the number of audio tracks in a video file. The video have multiple tracks (like different, selectable languages for the same movie.) So if there are three optional languages for the video, i'd like to get the number 3 in the end, no matter if the audio is in stereo, mono or in 5.1.
So far I tried to do it with moviepy. I found only the function "reader.nchannels", but that counts only the first audio track's left and right channel, so I get the number 2 every time.
The code right now is really simple, it looks like this:
from moviepy.editor import *
from moviepy.audio import *
clip = VideoFileClip(source)
audio_tracks = clip.audio.reader.nchannels
I also tried to get every info from the audio like this:
audio = AudioFileClip(source)
tracks= audio_tracks.reader.infos
The output for this looks like this:
"'audio_found': True, 'audio_fps': 48000}"
tburrows13, thanks for pointing to the right direction.
I was able to get the numbers of audio channels and store it in a variable through a py script. Maybe this is not the most elegant solution, but it works, so here it is, if someone needs it. You have to import "subprocess" and use ffprobe with it. ffprobe comes with ffmpeg.
To get the number of streams the command goes like this:
ffprobe <filename here> -show_entries format=nb_streams
This will give you the number of streams in the file, not just the audios, but the video streams too. There is an option to get the data only for the audio streams, but this was not necessary for my project.
You can call this command through a python script. The command needs to be a string, you can store it in a variable too. To get and store the output of this commmand in an other variable you can use this:
variable = subprocess.check_output(subprocesscommand) # subprocesscommand is the string version of the command wrote above.
If you print out now this variable the output will be something like: b'[FORMAT]\r\nnb_streams=3\r\n[/FORMAT]\r\n'
Now you just need to slice the string value, to get the number of the streams.
Thanks again for your help!
I'm using moviepy to edit some video clips. I want to play the last frame of orginal clip for 10 seconds, so that I could display some text on it. I tried to convert last frame to video by using
clip.to_ImageClip(t=clip.duration).set_duration(10)
but failed.
Does anyone konw why? And any possible solutions.
import moviepy.editor as ed
import os
content=ed.VideoFileClip(path)
myclip=content.to_ImageClip(content.duration).set_duration(10)
myclip.write_videofile(path)
MoviePy error:
failed to read the first frame of video file C:\my\test.mp4.
That might mean that the file is corrupted.
That may also mean that you are using a deprecated version of FFMPEG.
On Ubuntu/Debian for instance the version in the repos is deprecated.
Please update to a recent version from the website.
I was too facing the same issue, however, the below code worked for me:
clip = VideoFileClip(path)
frame_t = clip.duration - 1
ext_clip = clip.to_ImageClip(t=frame_t, duration=4)
ext_clip.write_videofile("sample4.mp4", fps=24)
While recording my screen with OBS capture, I accumulated large quantity of videos that had been subject to a forced system shutdown, leaving them unfinalized. The videos were created using an .flv format, so when I play them in VLC Player they play flawlessly, however they are missing an end time (video length). Instead, the videos show the running time as they play, but maintain the 00:00 end time, despite the actual video playing for several minutes.
From my understanding, unlike .mp4 formatting, .flv formatted video should be able to be recovered if it has not been finalized (as in the case of my footage stopped by unexpected shutdowns). Since I have a large quantity of unfinalized, I need an automated solution to fix them.
Using MoviePy write_videofile
I attempted to fix the videos by using the MoviePy write_videofile command in the python shell with the directory set to the directory of the bad video:
from moviepy.editor import * #no error
vid = VideoFileClip("oldVideoName.flv") #no error
vid.write_videofile("corrected.mp4") #IndexError
The final line created breifly created a file "correctedTEMP_MPY_wvf_snd.mp3"(only 1KB, unplayable in Audacity), shorty before throwing an exception. I recieved a massive traceback with the final teir reading:
File "\Python37-32\lib\site-packages\moviepy\audio\io\readers.py", line 168, in get_frame
"Accessing time t=%.02f-%.02f seconds, "%(tt[0], tt[-1])+
IndexError: index 0 is out of bounds for axis 0 with size 0
I assumed that this was caused by a problem with an audio reader not accepting the supposed 00:00 timestamp as the length of the video.
Using MoviePy subclip
I attempted to see if there was a way that I could manually feed MoviePy the start and end timestamps, using the subclip method. I know the video is at least 4 seconds long, so I used that as a control test:
clip = vid.subclip("00:00:00", "00:00:05") #no error
clip.write_videofile("corrected.mp4") #OSError
The write_videofile method again threw an exception:
File "\Python37-32\lib\site-packages\moviepy\audio\io\readers.py", line 169, in get_frame
"with clip duration=%d seconds, "%self.duration)
OSError: Error in file oldVideoName.flv,
Accessing time t=0.00-0.04 seconds, with clip duration=0 seconds,
Even if this method were to work, I would need to find a way to automate the process of discovering the video end time.
Using OpenCV CAP_PROP_FRAME_COUNT
One possible solution to finding the end time (video length) is to use cv2, per this post.
import cv2 #no error
vid=cv2.VideoCapture("oldVideoName.flv") #no error
vid.get(cv2.CAP_PROP_FRAME_COUNT) #returns -5.534023222112865e+17
I was not expecting to receive a negative float for this value. Further tests reveal to me that this float does not correspond at all with the length of the video, as all unfinalized videos return the same float for this request. (Normal videos do return their length for this method call) This is useful to iterate over a directory identifying unfinalized videos.
Is using MoviePy to correct a large quantity of unfinalized videos a viable or even possible solution? Is it better to use cv2 (Python OpenCV) for solving this problem?
I was able to fix the video files using yamdi, an open source metadata injector for FLV files. After downloading and installing yamdi, I can use the following command to repair an .flv file named oldVideoName.flv:
yamdi -i oldVideoName.flv -o corrected.flv
The command leaves oldVideoName.flv untouched, and saves a repaired file as corrected.flv.