10

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.

Amandasaurus
  • 58,203
  • 71
  • 188
  • 248
  • 4
    Unless you're using the original, raw, unencoded video, individual frames don't necessarily exist to drop. Most codecs use periodic keyframes and then just describe the differences from frame to frame to save massive amounts of file size. – ceejayoz Aug 26 '09 at 14:13
  • My video is in motion-jpeg format, so it's not an issue. even still, I want to 'double speed' the film, how would I do it? – Amandasaurus Aug 26 '09 at 14:16
  • Even if he is not using raw, unencoded video, he can drop every other frame by rendering all frames and only showing every other. (If the CPU is fast enough.) – Prof. Falken Dec 01 '09 at 13:06
  • Or, if his cpu can't do it real time, render all frames, drop every other one, and save the resultant video (rencoding, if desired.) – Beska Dec 09 '09 at 22:29

6 Answers6

5

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
jerdiggity
  • 3,655
  • 1
  • 29
  • 41
  • 1
    You know what the numbers mean? Especially 480/1? – Bernhard Apr 01 '14 at 11:01
  • @Bernhard from `man ffmpeg` it looks to set the frame rate. I don't understand why 480, but I think it's sort of like saying "treat the input like it's 480 and make the output 12 frames/sec." In other words, reduce it by 480/12 = 40x? That's my interpretation, anyway! – Hendy Jun 08 '18 at 00:39
  • 1
    @Hendy, no. 480/30 ("forced" FPS / current input FPS) = 16 (after rounding 29.97 to 30). Now, this is where the "slowing down" happens. Now, out of these 480 frames for 1 second, we'll pick 12 to be in 1 second of the output movie (indeed, every 40-th, but they will be spaced 1/12 second away) – Tomasz Gandor Jul 06 '20 at 00:02
  • @TomaszGandor thanks for the clarification. Is the 480 arbitrary? As in, could one do `"240/1"` and `"6/1"` to achieve the same result? Is it just about the ratio of these? And also, is the ratio of 480/30=16 meaningful? That is, if the input video was 10fps, does it matter that this would become 480/10=48? – Hendy Jul 07 '20 at 16:28
  • The speedup (or slowdown) is determined by the first `-r:v` (input framerate), so when using `"240/1"`, the video will be only slowed down 8x instead of 16 (240/30 = 8). This 8x slower video will have an FPS of 6. So in that case, there will be the same number of frames, but they will play at half the speed. About 2 other questions: yes and yes - if the input video was 10 FPS, setting input rate to 480/1 would produce a 48x faster video. – Tomasz Gandor Jul 15 '20 at 22:06
5

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
petrkotek
  • 4,541
  • 1
  • 18
  • 15
johnboiles
  • 3,494
  • 1
  • 32
  • 26
4

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.

Dustin Kirkland
  • 5,323
  • 3
  • 36
  • 34
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
4

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

It was difficult to distill this information from this post. As far as I am concerned, it is an attempt to clarify the missing information on the net.

alani
  • 12,573
  • 2
  • 13
  • 23
1

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

danio
  • 8,548
  • 6
  • 47
  • 55
0

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.

user1978011
  • 3,419
  • 25
  • 38