Reputation: 60699
I've got a video that's 30 minutes long. I want to make a speeded up version that's (say) 15 minutes long. I could do this by dropping every 2nd frame. How can I do this on linux?
I'm playing with gstreamer and it looks cool. Is there a way to do this with gstreamer? What would be the gst-launch
command line to do it?
My source video is in Motion JPEG, so I do have the frames to drop. Even if it was using keyframes, there still should be a way to 'double speed' the film?
I'd like a command line way to do this since I want to automate it.
Upvotes: 12
Views: 18553
Reputation: 1616
First creating a 60s test video with:
gst-launch-1.0 videotestsrc num-buffers=1800 ! videoconvert ! x264enc ! h264parse ! matroskamux ! filesink location=test.mkv
# For NVIDIA Jetson having NVENC, you may use instead:
gst-launch-1.0 videotestsrc num-buffers=1800 ! nvvidconv ! nvv4l2h264enc ! h264parse ! matroskamux ! filesink location=test.mkv
# Then check source video properties with:
gst-discoverer-1.0 test.mkv
Then try using videorate
element with decoded video:
gst-launch-1.0 filesrc location=test.mkv ! matroskademux ! h264parse ! avdec_h264 ! videorate rate=2 ! x264enc ! h264parse ! matroskamux ! filesink location=test_speed_up_x2.mkv
# For Jetson having NVENC:
gst-launch-1.0 filesrc location=test.mkv ! matroskademux ! h264parse ! nvv4l2decoder ! videorate rate=2 ! nvv4l2h264enc ! h264parse ! matroskamux ! filesink location=test_speed_up_x2.mkv
# Check with:
gst-discoverer-1.0 test_speed_up_x2.mkv
...
Properties:
Duration: 0:00:30.033333333
Upvotes: 0
Reputation: 91
To speed up a video file, by removing frames, the following syntax can be used:
ffmpeg -r:v "Fin*M/1" -i input.mp4 -an -r:v "Fout/1" output.mp4
Fout
": This is nothing more and less than the number of FPS (Frames
Per Second) you want for output.mp4, e.g. 30 FPS.Fin
": The number of FPS of input.mp4, for example 25 FPS. You can
find this out with: ffmpeg -i input.mp4
M
": Multiplier, the speed factor you want, e.g. 15 to make the video
15 times faster.Fin * M
": So in this example, that's 25 * 15 = 375The final result of this example is:
ffmpeg -r:v "375/1" -i input.mp4 -an -r:v "30/1" output.mp4
Upvotes: 8
Reputation: 3524
I looked around for a while recently on the best way to do this. I experimented with mencoder -speed and also libavfilter's setpts option. The best way I found was to output individual frames and then re-encode those frames into a single video. This example assumes a 30fps input video for best results and drops every other frame.
# Output the video at 15fps as jpegs
ffmpeg -i input.m4v -r 15 -f image2 /tmp/output-%06d.jpg
# Re-encode the frames at 30fps as h264
ffmpeg -r 30 -i "/tmp/output-%06d.jpg" -vcodec libx264 -threads 0 -an output.m4v
Upvotes: 5
Reputation: 3589
If you have a video encoded with mjpeg, you can avoid re-encoding your video and have identical frames -- only fewer. I use a combination of ffmpeg and awk to accomplish this:
#!/bin/bash
INMOVIE=${1}
INRATE=${2}
OUTMOVIE="${INMOVIE%.avi}-25fps.avi"
ffmpeg -i ${INMOVIE} -c:v copy .frame_%08d.jpg
rm $(ls .frame_*.jpg | awk " BEGIN { c=0.0; fd=1./${INRATE}; fr=25.; last=-1 } { current=int(NR * fr * fd); if (current > last) {last = current;} else { print \$0;} }" )
ffmpeg -pattern_type glob -i '.frame_*.jpg' -c:v copy ${OUTMOVIE}
rm -- .frame_*.jpg
Explanation:
ffmpeg
command extracts the frames from the videoawk
line erases those frames that are not needed when encoding a video with framerate INRATE
at 25fpsffmpeg
line puts the remaining frames back togetherYou can check that the frames are identical with the framemd5 filter:
ffmpeg -i in.avi -f framemd5 in.md5
ffmpeg -i in-25fps.avi -f framemd5 in-25fps.md5
and find that the frames are indeed identical.
Upvotes: 0
Reputation: 3665
I had a video that was originally 16m06s long with a frame rate of 29.97, but I wanted to speed it up (by dropping frames) so that it played back at about 16x the normal speed. This is the command I used:
ffmpeg -r:v "480/1" -i input.avi -an -r:v "12/1" output.avi
Upvotes: 5
Reputation: 364160
You could just set the frame rate to twice as high. e.g. if the input was really 30/1.001 FPS:
mencoder -fps 60/1.001 -oac copy -ovc copy -o output.avi input.avi
http://www.mplayerhq.hu/DOCS/HTML/en/index.html
Or drop frames with mencoder -sstep 0.1
to skip forwards 0.1 seconds after every frame.
mplayer -nosound -channels 2 -vf decimate=-2:16384:16384:1 mvi_3524.avi
works, too, but it's probably slow, and you probably can't do it without decompressing/recompressing every frame.
mjpegtools has a yuvfps
for blending/dropping frames in a y4m video. See http://linux.die.net/man/1/mjpegtools.
I'm not having much luck finding a tool that knows how to drop frames from an mjpeg video without decompressing/recompressing. So you might have to convert the mjpeg to a directory of .jpg files, delete the odd numbered ones, and re-assemble them into an mjpeg video with the same frame rate. That wouldn't degrade the image quality.
Upvotes: 4
Reputation: 8653
avidemux can change the frame rate of films and offers command line control.
Upvotes: 1