21

I'm having trouble finding a cli application that can take a video file (avi, mkv, and mp4 preferably) and cut out very short clips (2-6 seconds) with precision time accuracy. I've tried ffmpeg, mencoder, avidemux, and mp4box but they all cut on keyframes which creates 6+ second clips. Is there a tool that will re-encode the input file and cut the accurate time or cut inaccurately, re-encode, and then cut accurately?

  • You'll probably have to reencode before cutting to get it right. You could probably speed things up by first cutting out the surrounding keyframes and only reencode the snippets. – Nifle Aug 7 '12 at 18:19
  • 4
    Which FFmpeg command have you tried, exactly? I believe if you decode the video before (i.e. place the -ss parameter after -i), it should be more accurate. – slhck Aug 7 '12 at 18:19
  • 1
    The FFmpeg trick worked! I didn't realize the order mattered so much. Is this the same for any of the other tools? – curmil Aug 7 '12 at 19:30
  • related- superuser.com/questions/1287650/… – barlop Apr 27 at 11:12
22

Cutting video with ffmpeg

You can accurately cut videos with FFmpeg. Since version 2.5 it's very easy. This would for example cut 10 seconds, starting from 0 minutes, 3 seconds and 123 milliseconds.

ffmpeg -ss 00:00:03.123 -i input.mp4 -t 10 -c:v libx264 -c:a copy out.mp4

The position and the time may be either in seconds or in hh:mm:ss[.xxx] form.

Note that in these examples, video will be re-encoded using the x264 encoder; audio is copied.

You can also use -to instead of -t to specify the end point instead of the duration. In this case, however, -to is equivalent to -t, since by putting the -ss in front of -i, ffmpeg will first seek to that point and then start outputting.

See also the Seeking wiki entry.


Accurate cutting for older ffmpeg versions

If you have an older version of ffmpeg, then for accurate seeking, you need to place the -ss after -i, which makes the encoding process a little slower, because the entire video has to be decoded first:

ffmpeg -i input.mp4 -ss 00:00:03.123 -t 10 -c:v libx264 -c:a copy out.mp4

Here, -to and -t behave differently. -t 10 would create a ten second long clip, whereas -to 10 would create a clip that is seven seconds long.

  • Instead of -c:v libx264 -c:a libfaac I think we can use -acodec copy -vcodec copy which tells ffmpeg just to detect and use the same codecs as the original file. Can anyone confirm? – Baodad Jan 23 '15 at 4:31
  • 2
    @Baodad You can, but this will not accurately cut. When copying video/audio bitstreams, ffmpeg needs to start at a keyframe, which may just be placed at every second or even further apart. – slhck Jan 23 '15 at 7:14
  • How do overcome the "Unknown encoder 'libfaac'" error? – Doug Apr 24 '15 at 3:16
  • @Doug Choose a different encoder, for example -c:a aac -strict experimental. That's the simplest solution. – slhck Apr 24 '15 at 6:34
1

The only Linux command-line tool I've found so-far, that can cut at exact frame (or, with frame accuracy), is melt (sudo apt-get install melt).

Say you have an inputvid.mp4 - first check its encoding settings with say ffmpeg (here, I just say I want to encode it again to -f mp4, but as the file /dev/null so the output is discarded; I redirect stderr so I can grep through it - note in the middle, the command prompts, and you should answer y with ENTER, so the process proceeds and dumps the useful info; this is with ffmpeg 3.3.3 on Ubuntu 14):

ffmpeg -i inputvid.mp4 -f mp4 /dev/null 2>&1 | grep 'Stream\|encoder'
    Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p(tv, bt709), 640x360 [SAR 1:1 DAR 16:9], 389 kb/s, 23.98 fps, 23.98 tbr, 24k tbn, 47.95 tbc (default)
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 95 kb/s (default)
y
File '/dev/null' already exists. Overwrite ? [y/N] Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))
  Stream #0:1 -> #0:1 (aac (native) -> aac (native))
    encoder         : Lavf57.71.100
    Stream #0:0(und): Video: h264 (libx264) ([33][0][0][0] / 0x0021), yuv420p(progressive), 640x360 [SAR 1:1 DAR 16:9], q=-1--1, 23.98 fps, 24k tbn, 23.98 tbc (default)
      encoder         : Lavc57.89.100 libx264
    Stream #0:1(und): Audio: aac (LC) ([64][0][0][0] / 0x0040), 44100 Hz, stereo, fltp, 128 kb/s (default)
      encoder         : Lavc57.89.100 aac

Ok, so we can see ffmpeg chooses libx264 and aac encoders for this video; then we can enter this in for melt:

melt inputvid.mp4 in=7235 out=7349 -consumer avformat:cut.mp4 acodec=aac vcodec=libx264

.... and melt will cut with the piece between frames 7235 and 7349 into a new file, cut.mp4. Then to check if cut.mp4 loops correctly, use melt again to play it back twice - and play it to an SDL window:

melt cut.mp4 cut.mp4 -consumer sdl

... and here is what ffmpeg sees for this file:

ffmpeg -i cut.mp4 -f mp4 /dev/null 2>&1 | grep 'Stream\|encoder'    encoder         : Lavf54.20.4
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 640x360 [SAR 1:1 DAR 16:9], 526 kb/s, 23.98 fps, 23.98 tbr, 24k tbn, 47.95 tbc (default)
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 182 kb/s (default)
y
File '/dev/null' already exists. Overwrite ? [y/N] Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))
  Stream #0:1 -> #0:1 (aac (native) -> aac (native))
    encoder         : Lavf57.71.100
    Stream #0:0(und): Video: h264 (libx264) ([33][0][0][0] / 0x0021), yuv420p, 640x360 [SAR 1:1 DAR 16:9], q=-1--1, 23.98 fps, 24k tbn, 23.98 tbc (default)
      encoder         : Lavc57.89.100 libx264
    Stream #0:1(und): Audio: aac (LC) ([64][0][0][0] / 0x0040), 48000 Hz, stereo, fltp, 128 kb/s (default)
      encoder         : Lavc57.89.100 aac

The video encoding settings for cut.mp4 seem to be identical to inputvid.mp4 except video bitrate changed from 389 kb/s to 526 kb/s, and also the audio encoding settings are nearly the same, except the sampling rate changed from 44100 to 48000 Hz; though that can be regulated with:

melt inputvid.mp4 in=7235 out=7349 -consumer avformat:cut.mp4 acodec=aac ar=44100 ab=95k vcodec=libx264 vb=389k

... however, even with this, the final video bitrate for me ends up 337 kb/s. Still, the cuts loop fine (and that includes audio) when played in a loop, so I guess this is indeed frame-accurate...

  • 1
    melt is re-encoding the video, and it uses the FFmpeg libraries underneath. If you allow re-encoding, ffmpeg can produce the same output. – Gyan Jun 12 '18 at 7:06
  • Thanks @Gyan - was not aware of that (especially that melt uses FFmpeg libraries), good to know! – sdaau Jan 18 at 11:15
  • melt looks easier to use than ffmpeg, all we need is a way to specify times , particularly times in hr,min,sec form, or hr,min,sec,ms, that converts them to the right frame. – barlop Apr 27 at 11:11
0

Like Baodad said in the comments (I post because it's not easy to find if you read quickly), the better approach is to detect the audio/video encoders automatically by ffmpeg, so :

ffmpeg -ss 00:05:17.18 -i in.mp4 -t 00:06:29.10 -acodec copy -vcodec copy out.mp4 
  • start @ 00:05:17.18
  • input = in.mp4
  • stop @ 00:06:29.10
  • output = out.mp4
  • 2
    This does not reencode and does not provide frame accuracy. – Andrea Lazzarotto Feb 17 '16 at 1:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.