from moviepy.editor import *
clip = ( VideoFileClip("https://filelink/file.mp4"))
clip.save_frame("frame.png", t = 3)
I am able to load video using moviepy but its loading complete video and then saving the frame. Is it possible not to load the complete video but only first four second and then save the frame at 3 second.
Unless I missed something, it's not possible using MoviePy.
You may use ffmpeg-python instead.
Here is a code sample using ffmpeg-python:
import ffmpeg
stream_url = "https://file-examples-com.github.io/uploads/2017/04/file_example_MP4_480_1_5MG.mp4"
# Input seeking example: https://trac.ffmpeg.org/wiki/Seeking
(
ffmpeg
.input(stream_url, ss='00:00:03') # Seek to third second
.output("frame.png", pix_fmt='rgb24', frames='1') # Select PNG codec in RGB color space and one frame.
.overwrite_output()
.run()
)
Notes:
The solution may not work for all mp4 URL files, because mp4 format is not so "WEB friendly" - I think the moov atom must be located at the beginning of the file.
You may need to manually install FFmpeg command line tool (but it supposed to be installed with MoviePy).
Result frame:
Related
So far i tried:
from moviepy.editor import *
videoclip = VideoFileClip("filename.mp4")
audioclip = AudioFileClip("audioname.mp3")
new_audioclip = CompositeAudioClip([audioclip])
videoclip.audio = new_audioclip
videoclip.write_videofile("new_filename.mp4")
But it takes very long time.
I'd like to do it without re encoding. i also prefer opening video or audio clip from bytes in moviepy
One way to do it is using ffmpeg_merge_video_audio from FFMPEG tools.
ffmpeg_merge_video_audio - merges video file video and audio file audio into one movie file output.
By default the merging is performed without re-encoding.
Code sample:
from moviepy.video.io import ffmpeg_tools
ffmpeg_tools.ffmpeg_merge_video_audio("filename.mp4", "audioname.mp3", 'new_filename.mp4') # Merge audio and video without re-encoding
Note:
As far as I know, it's not possible to do it "from bytes" using MoviePy.
I have a large set of videos that I need to process but a this is slow going since the processing involves running through the entire video at about 0.6FPS and the vast majority of frames have little change between them.
Is there some way I could sample the video say every two seconds and save this as another video cutting the framerate and duration in two? I am not worried about losing information by doing this, I would gladly cut a 10 minute video down to a few hundred frames. I do need it to be a video file however and not a set of images.
You may solve it using cv2.VideoCapture and cv2.VideoWriter or using FFmpeg.
The solution bellow uses ffmpeg-python.
I posted both OpenCV solution, and FFmpeg solution.
Solving using OpenCV:
Open input video file for reading using cv2.VideoCapture.
Open output video file for writing using cv2.VideoWriter.
Read all frames, but write only every 10th frame to the output file.
Solving using FFmpeg:
Solution is based on: Selecting one every n frames from a video using ffmpeg, but uses ffmpeg-python.
The following example is "self contained" - generates synthetic input video file for testing, and executes the frame skipping on the generated input video.
Here is the code (example using ffmpeg-python is at the bottom):
import ffmpeg # Note: import ffmpeg is not a must, when using OpenCV solution.
import cv2
import sys
out_filename = 'out.mp4'
# Build synthetic video and read binary data into memory (for testing):
#########################################################################
in_filename = 'in.mp4'
width, height = 320, 240
fps = 1 # 1Hz (just for testing)
# Build synthetic video, for testing:
# ffmpeg -y -f lavfi -i testsrc=size=320x240:rate=1 -c:v libx264 -crf 18 -t 50 in.mp4
(
ffmpeg
.input('testsrc=size={}x{}:rate={}'.format(width, height, fps), f='lavfi')
.output(in_filename, vcodec='libx264', crf=18, t=50)
.overwrite_output()
.run()
)
#########################################################################
# Open video file for reading
in_vid = cv2.VideoCapture(in_filename)
#Exit if video not opened.
if not in_vid.isOpened():
print('Cannot open input video file')
sys.exit()
# Read first image (for getting resolution).
ok, frame = in_vid.read()
if not ok:
print('Cannot read video file')
sys.exit()
width, height = frame.shape[1], frame.shape[0]
# Get frame rate of input video.
fps = in_vid.get(cv2.CAP_PROP_FPS)
# Create video writer
# 264 doesn't come by default with the default installation of OpenCV, but I preferred using H.264 (supposed to be better than XVID).
# https://stackoverflow.com/questions/41972503/could-not-open-codec-libopenh264-unspecified-error
# (I had to download openh264-1.8.0-win64.dll)
out_vid = cv2.VideoWriter(out_filename, cv2.VideoWriter_fourcc(*'H264'), fps, (width, height))
frame_counter = 0
while True:
# Write every 10th frame to output video file.
if ((frame_counter % 10) == 0):
out_vid.write(frame)
# Read a new frame
ok, frame = in_vid.read()
if not ok:
break
frame_counter += 1
out_vid.release()
# Selecting one every n frames from a video using FFmpeg:
# https://superuser.com/questions/1274661/selecting-one-every-n-frames-from-a-video-using-ffmpeg
# ffmpeg -y -r 10 -i in.mp4 -vf "select=not(mod(n\,10))" -vsync vfr -vcodec libx264 -crf 18 1_every_10.mp4
out_filename = '1_every_10.mp4'
# Important: set input frame rate to fps*10
(
ffmpeg
.input(in_filename, r=str(fps*10))
.output(out_filename, vf='select=not(mod(n\,10))', vsync='vfr', vcodec='libx264', crf='18')
.overwrite_output()
.run()
)
Note: The solution looses some of the video quality, due to decoding and re-encoding.
You may also try FFmpeg decimate filter, if you are looking for solution that skips frames according to metrics calculation.
What is the most convenient way to capture a video streamed in the browser with a frame rate around 15? I would like to avoid to capture the raw screen because I should play with x,y, width, height. I would like to have something less manual.
Edit The URL is unavailable, I can only access the player that shows the streaming in the browser.
If you want to simply capture a video from a given URL and save it to disk, you can do this:
import urllib2
link_to_movie = 'https://somemovie.com/themovie.mp4'
file_name = 'themovie.mp4'
response = urllib2.urlopen(link_to_movie)
with open(file_name,'wb') as f:
f.write(response.read())
Then if you want to set the frame rate for that movie you just downloaded, use FFMPEG:
ffmpeg -y -r 24 -i seeing_noaudio.mp4 seeing.mp4
FFMPEG answer from here: https://stackoverflow.com/a/50673808/596841
I have been using Moviepy to combine several shorter video files into hour long files. Some small files are "broken", they contain video but was not completed correctly (i.e. they play with VLC but there is no duration and you cannot skip around in the video).
I noticed this issue when I try to create a clip using VideoFileClip(file) function. The error that comes up is:
MoviePy error: failed to read the duration of file
Is there a way to still read the "good" frames from this video file and then add them to the longer video?
UPDATE
To clarify, my issue specifically is with the following function call:
clip = mp.VideoFileClip("/home/test/"+file)
Stepping through the code it seems to be an issue when checking the duration of the file in ffmpeg_reader.py where it looks for the duration parameter in the video file. However, since the file never finished recording properly this information is missing. I'm not very familiar with the way video files are structured so I am unsure of how to proceed from here.
You're correct. This issue arises commonly when the video duration info is missing from the file.
Here's a thread on the issue: GitHub moviepy issue 116
One user proposed the solution of using MP4Box to convert the video using this guide: RASPIVID tutorial
The final solution that worked for me involved specifying the path to ImageMagick's binary file as WDBell mentioned in this post.
I had the path correctly set in my environment variables, but it wasn't till I specificaly defined it in config_defaults.py that it started working:
I solved it in a simpler way, with the help of VLC I converted the file to the forma MPEG4 xxx TV/device,
and you can now use your new file with python without any problem
xxx = 720p or
xxx = 1080p
everything depends on your choice on the output format
I already answered this question on the blog: https://github.com/Zulko/moviepy/issues/116
This issue appears when VideoFileClip(file) function from moviepy it looks for the duration parameter in the video file and it's missing. To avoid this (in those corrupted files cases) you should make sure that the total frames parameter is not null before to shoot the function: clip = mp.VideoFileClip("/home/test/"+file)
So, I handled it in a simpler way using cv2.
The idea:
find out the total frames
if frames is null, then call the writer of cv2 and generate a temporary copy of the video clip.
mix the audio from the original video with the copy.
replace the original video and delete copy.
then call the function clip = mp.VideoFileClip("/home/test/"+file)
Clarification: Since OpenCV VideoWriter does not encode audio, the new copy will not contain audio, so it would be necessary to extract the audio from the original video and then mix it with the copy, before replacing it with the original video.
You must import cv2
import cv2
And then add something like this in your code before the evaluation:
cap = cv2.VideoCapture("/home/test/"+file)
frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
fps = int(cap.get(cv2.CAP_PROP_FPS))
print(f'Checking Video {count} Frames {frames} fps: {fps}')
This will surely return 0 frames but should return at least framerate (fps).
Now we can set the evaluation to avoid the error and handle it making a temp video:
if frames == 0:
print(f'No frames data in video {file}, trying to convert this video..')
writer = cv2.VideoWriter("/home/test/fixVideo.avi", cv2.VideoWriter_fourcc(*'DIVX'), int(cap.get(cv2.CAP_PROP_FPS)),(int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))))
while True:
ret, frame = cap.read()
if ret is True:
writer.write(frame)
else:
cap.release()
print("Stopping video writer")
writer.release()
writer = None
break
Mix the audio from the original video with the copy. I have created a function for this:
def mix_audio_to_video(pathVideoInput, pathVideoNonAudio, pathVideoOutput):
videoclip = VideoFileClip(pathVideoInput)
audioclip = videoclip.audio
new_audioclip = CompositeAudioClip([audioclip])
videoclipNew = VideoFileClip(pathVideoNonAudio)
videoclipNew.audio = new_audioclip
videoclipNew.write_videofile(pathVideoOutput)
mix_audio_to_video("/home/test/"+file, "/home/test/fixVideo.avi", "/home/test/fixVideo.mp4")
replace the original video and delete copys:
os.replace("/home/test/fixVideo.mp4", "/home/test/"+file)
I had the same problem and I have found the solution.
I don't know why but if we enter the path in this method path = r'<path>' instead of ("F:\\path") we get no error.
Just click on the
C:\Users\gladi\AppData\Local\Programs\Python\Python311\Lib\site-packages\moviepy\video\io\ffmpeg_reader.py
and delete the the code and add this one
Provided by me in GITHUB - https://github.com/dudegladiator/Edited-ffmpeg-for-moviepy
clip1=VideoFileClip('path')
c=clip1.duration
print(c)
I can't seem to capture frames from a file using OpenCV -- I've compiled from source on Ubuntu with all the necessary prereqs according to: http://opencv.willowgarage.com/wiki/InstallGuide%20%3A%20Debian
#!/usr/bin/env python
import cv
import sys
files = sys.argv[1:]
for f in files:
capture = cv.CaptureFromFile(f)
print capture
print cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH)
print cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_HEIGHT)
for i in xrange(10000):
frame = cv.QueryFrame(capture)
if frame:
print frame
Output:
ubuntu#local:~/opencv$ ./test.py bbb.avi
<Capture 0xa37b130>
0.0
0.0
The frames are always None...
I've transcoded a video file to i420 format using:
mencoder $1 -nosound -ovc raw -vf format=i420 -o $2
Any ideas?
You don't have the gstreamer-ffmpeg or gsteamer-python or gsteamer-python-devel packages installed. I installed all three of them. and the exact same problem was resolved.
I'm using OpenCV 2.2.0, compiled on Ubuntu from source. I can confirm that the source code you provided works as expected. So the problem is somewhere else.
I couldn't reproduce your problem using mencoder (installing it is a bit of a problem on my machine) so I used ffmpeg to wrap a raw video in the AVI container:
ffmpeg -s cif -i ~/local/sample-video/foreman.yuv -vcodec copy foreman.avi
(foreman.yuv is a standard CIF image sequence you can find on the net if you look around).
Running the AVI from ffmpeg through your source gives this:
misha#misha-desktop:~/Desktop/stackoverflow$ python ocv_video.py foreman.avi
<Capture 0xa71120>
352.0
288.0
<iplimage(nChannels=3 width=352 height=288 widthStep=1056 )>
<iplimage(nChannels=3 width=352 height=288 widthStep=1056 )>
...
So things work as expected. What you should check:
Do you get any errors on standard output/standard error? OpenCV uses ffmpeg libraries to read video files, so be on the lookout for informative messages. Here's what happens if you try to play a RAW video file without a container (sounds similar to your problem):
error:
misha#misha-desktop:~/Desktop/stackoverflow$ python ocv_video.py foreman.yuv
[IMGUTILS # 0x7fff37c8d040] Picture size 0x0 is invalid
[IMGUTILS # 0x7fff37c8cf20] Picture size 0x0 is invalid
[rawvideo # 0x19e65c0] Could not find codec parameters (Video: rawvideo, yuv420p)
[rawvideo # 0x19e65c0] Estimating duration from bitrate, this may be inaccurate
GStreamer Plugin: Embedded video playback halted; module decodebin20 reported: Your GStreamer installation is missing a plug-in.
<Capture 0x19e3130>
0.0
0.0
Make sure your AVI file actually contains the required information to play back the video. At a minimum, this should be the frame dimensions. RAW video typically doesn't contain any information besides the actual pixel data, so knowing the frame dimensions and FPS is required. You can wrong-guess the FPS and still get a viewable video, but if you get the dimensions wrong, the video will be unviewable.
Make sure the AVI file you're trying to open is actually playable. Try ffplay file.avi -- if that fails, then the problem is likely to be with the file. Try using ffmpeg to transcode instead of mencoder.
Make sure you can play other videos, using the same method as above. If you can't, then it's likely that your ffmpeg install is broken.