Amandasaurus
Amandasaurus

Reputation: 60699

How can I speed up a video by dropping frames?

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

Answers (7)

SeB
SeB

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

Wiebe van der Worp
Wiebe van der Worp

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 = 375

The final result of this example is:

ffmpeg -r:v "375/1" -i input.mp4 -an -r:v "30/1" output.mp4

Upvotes: 8

johnboiles
johnboiles

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

user1978011
user1978011

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:

  • the first ffmpeg command extracts the frames from the video
  • the following awk line erases those frames that are not needed when encoding a video with framerate INRATE at 25fps
  • the final ffmpeg line puts the remaining frames back together

You 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

jerdiggity
jerdiggity

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

Peter Cordes
Peter Cordes

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

danio
danio

Reputation: 8653

avidemux can change the frame rate of films and offers command line control.

Upvotes: 1

Related Questions