ffmpeg speed up video from 25 to 60 fps dropping frames
Timestamps are denominated in terms of a timebase which is the clock-keeping scale.
setpts
will assign the value nearest to the expression value which is possible in the stream timebase. When compressing timestamps, like here, make sure that enough resolution is available using the settb filter.
For 25 and 60, 300 is LCM but let's pick something higher, like 6000.
-filter:v "settb=1/6000,setpts=PTS/2.4"
If your video is constant frame rate, this will do what you want. If it's VFR, it's possible that -r 60
will still cause frames to be dropped/duped. Add -vsync vfr
for that.
How can I use python to speed up a video without dropping frames
I think I found the solution using the set_fps
attribute of the Clip
class. Indeed, the set_fps
function returns a copy of the clip with a modified FPS count. When applying the transformation to this copy, you end up with the correct number of FPS.
As you did not provide a reproducible example, I used a stock video (renamed dummy_in.mp4
) of 15 seconds and 24 FPS and no sound. I end up with a 5 seconds clip and 72 FPS using this code :
from moviepy.editor import VideoFileClip
import moviepy.video.fx.all as vfx
in_loc = 'dummy_in.mp4'
out_loc = 'dummy_out.mp4'
# Import video clip
clip = VideoFileClip(in_loc)
print("fps: {}".format(clip.fps))
# Modify the FPS
clip = clip.set_fps(clip.fps * 3)
# Apply speed up
final = clip.fx(vfx.speedx, 3)
print("fps: {}".format(final.fps))
# Save video clip
final.write_videofile(out_loc)
It produces this output :
fps: 23.976023976023978
fps: 71.92807192807193
Moviepy - Building video dummy_out.mp4.
Moviepy - Writing video dummy_out.mp4
Moviepy - Done !
Moviepy - video ready dummy_out.mp4
OpenCV real time streaming video capture is slow. How to drop frames or get synced with real time?
My hypothesis is that the jitter is most likely due to network limitations and occurs when a frame packet is dropped. When a frame is dropped, this causes the program to display the last "good" frame which results in the display freezing. This is probably a hardware or bandwidth issue but we can alleviate some of this with software. Here are some possible changes:
1. Set maximum buffer size
We set the cv2.videoCapture()
object to have a limited buffer size with the cv2.CAP_PROP_BUFFERSIZE
parameter. The idea is that by limiting the buffer, we will always have the latest frame. This can also help to alleviate the problem of frames randomly jumping ahead.
2. Set frame retrieval delay
Currently, I believe the read()
is reading too fast even though it is in its own dedicated thread. This may be one reason why all the frames appear to pool up and suddenly burst in the next frame. For instance, say in a one second time interval, it may produce 15 new frames but in the next one second interval, only 3 frames are returned. This may be due to the network packet frame loss so to ensure that we obtain constant frame rates, we simply add a delay in the frame retrieval thread. A delay to obtain roughly ~30
FPS does a good job to "normalize" the frame rate and smooth the transition between frames incase there is packet loss.
Note: We should try to match the frame rate of the stream but I'm not sure what the FPS of the webcam is so I just guessed 30
FPS. Also, there is usually a "direct" stream link instead of going through a intermediate webserver which can greatly improve performance.
If you try using a saved .mp4
video file, you will notice that there is no jitter. This confirms my suspicion that the problem is most likely due to network latency.
from threading import Thread
import cv2, time
class ThreadedCamera(object):
def __init__(self, src=0):
self.capture = cv2.VideoCapture(src)
self.capture.set(cv2.CAP_PROP_BUFFERSIZE, 2)
# FPS = 1/X
# X = desired FPS
self.FPS = 1/30
self.FPS_MS = int(self.FPS * 1000)
# Start frame retrieval thread
self.thread = Thread(target=self.update, args=())
self.thread.daemon = True
self.thread.start()
def update(self):
while True:
if self.capture.isOpened():
(self.status, self.frame) = self.capture.read()
time.sleep(self.FPS)
def show_frame(self):
cv2.imshow('frame', self.frame)
cv2.waitKey(self.FPS_MS)
if __name__ == '__main__':
src = 'https://videos3.earthcam.com/fecnetwork/9974.flv/chunklist_w1421640637.m3u8'
threaded_camera = ThreadedCamera(src)
while True:
try:
threaded_camera.show_frame()
except AttributeError:
pass
Related camera/IP/RTSP/streaming, FPS, video, threading, and multiprocessing posts
Python OpenCV streaming from camera - multithreading, timestamps
Video Streaming from IP Camera in Python Using OpenCV cv2.VideoCapture
How to capture multiple camera streams with OpenCV?
OpenCV real time streaming video capture is slow. How to drop frames or get synced with real time?
Storing RTSP stream as video file with OpenCV VideoWriter
OpenCV video saving
Python OpenCV multiprocessing cv2.VideoCapture mp4
How to speed up a video in order to shorten its length and embed a timestamp to represent time as it was recorded?
Put the drawtext
filter first and then the setpts
filter:
ffmpeg -i input.mp4 -r 30 -vf "drawtext=..., setpts=..." output.mp4
How to get FFmpeg to consistently apply speed effect to first few frames?
Add an fps
filter after the setpts
filter and use the -t
option like this:
ffmpeg -i 123410fps.mp4 -vf 'setpts=0.5*PTS,fps=10' -t 1.64 -an 123410fpsout.mp4
10
is the fps of your 123410fps.mp4
video and 1.64
is the half of its duration in seconds.
The documentation says this about the fps
filter:
Convert the video to specified constant frame rate by duplicating or dropping frames as necessary.
It seems that the use of this filter forces a correct dropping of frames.
The Changing the frame rate page of the FFmpeg wiki describes how to use the fps
filter, but also says this:
The output duration of the video will stay the same.
The -t
option is necessary to obtain an output with half of the duration of the input, which is consistent with the speed up of 2x.
The fps
filter also has a round
parameter that in this particular case allows you to obtain an output with the numbers 1,3,1,... or 2,4,2,...
For 1,3,1,... you can use fps=fps=10:round=up
.
For 2,4,2,... you can use fps=fps=10:round=down
.
Speeding up/slowing down video ffmpeg
If you change each timestamp (Presentation Timestamp, PTS) to be half of its original value, your video will be half as long.
So, if the PTS is x * PTS
, then your final duration will be x * duration
.
Example:
$ ffprobe -loglevel error input.mp4 -show_format -show_entries format=duration -of compact=p=0:nk=1
60.000000
$ ffmpeg -i input.mp4 -filter:v 'setpts=0.5*PTS' -filter:a 'atempo=2' output.mp4
...
$ ffprobe -loglevel error output.mp4 -show_format -show_entries format=duration -of compact=p=0:nk=1
30.050000
Related Topics
Linux Bash Script Get User Input and Store in a Array
Sed Only The Last Match Pattern
How to Log Messages from an ASP.NET Core Application to a Specific File on Linux
Can Perf-Stat Results Be Generated from a Perf.Data File
Terminal "Png" Missing When Using Gnuplot
How to Add a Ssh Key to Remote Server
Base Address at Which The Linux Kernel Is Loaded
How to Install Docker 1.9+ in Centos 6.5
How to Speed Up a Video by Dropping Frames
What Are Best Parameters to Run Imagemagick to Convert Low Quality PDF to Images (For Ocr)
What's The Meaning of 'C' in Result of Command "Ls -L /Dev/Tty'
Command-Line Fulltext Indexing