I would like to to play the first frame of an input video for 260 frames and then play frames 310–930 of the input video:

$ ffmpeg -i video.mp4 -i video.mp4 -filter_complex '
' -map [output] -c:v libx264 -crf 18 -y output.mp4

The above command produces the first frame of the input video for 260 frames as expected, but then continues with frames 0-620 of the input video followed by frames 310–930 of the input video.

When I drop the [first-frame] part, frames 310–930 of the input video are correctly produced:

$ ffmpeg -i video.mp4 -i video.mp4 -filter_complex '
' -map [output] -c:v libx264 -crf 18 -y output.mp4

This is perhaps a timestamp problem, since the documentation for the concat filter clarifies that “for this filter to work correctly, all segments must start at timestamp 0.”

I am using the following version of ffmpeg:

$ ffmpeg -version
ffmpeg version 3.2.12-1~deb9u1 Copyright (c) 2000-2018 the FFmpeg developers
built with gcc 6.3.0 (Debian 6.3.0-18+deb9u1) 20170516
configuration: --prefix=/usr --extra-version='1~deb9u1' --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --disable-stripping --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libebur128 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmp3lame --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264 --enable-shared
libavutil      55. 34.101 / 55. 34.101
libavcodec     57. 64.101 / 57. 64.101
libavformat    57. 56.101 / 57. 56.101
libavdevice    57.  1.100 / 57.  1.100
libavfilter     6. 65.100 /  6. 65.100
libavresample   3.  1.  0 /  3.  1.  0
libswscale      4.  2.100 /  4.  2.100
libswresample   2.  3.100 /  2.  3.100
libpostproc    54.  1.100 / 54.  1.100

A shorter method is

ffmpeg -i video.mp4 -vf 'select=eq(n,0)+between(n,310,930),setpts=if(eq(N,0),0,(N+260)/FRAME_RATE/TB)' -map [output] -vsync cfr -c:v libx264 -crf 18 -y output.mp4
  • It seems that this method also does not waste space encoding frames 1–260. Only frame 0 is encoded and the waiting is done by timestamp manipulation, which is neat. – Witiko Apr 1 at 17:03

The loop filter produces the rest of the video after it has stopped looping. If this is undesirable, trim the resulting video as follows:

$ ffmpeg -i video.mp4 -i video.mp4 -filter_complex '
' -map [output] -c:v libx264 -crf 18 -y output.mp4

This behavior is perhaps counterintuitive and poorly documented, but it covers the common case, when one wants to loop at the beginning of a video. This behavior also makes loop=0 an identity filter that passes the video unchanged.

  • 1
    The loop filter is meant to pass through untouched portions of the input while looping the specified portion. If it dropped the remainder, then the size and start are unnecessary and users would need to always manually trim and then concat the various segments, like your command does. – Gyan Mar 31 at 4:42

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.