Is there a way to use ffmpeg to halt a video for 3 seconds every 10 seconds?
For example, I use a 30 seconds video, the video should stop at 0:00, 0:10, 0:20 and 0:30 for 3 seconds. The length of the output video is 0:42 seconds.
Thank you!
Edit: Different method added, which accounts for audio and also the overwritten frames due to the initial method,which is shown at the bottom.
ffmpeg -i input.mp4 -filter_complex \
"[0:v]split=4[v0][v1][v2][v3]; \
[v0]trim=start_frame=0:end_frame=1,loop=90:1:0,setpts=N/FRAME_RATE/TB[0v]; \
[v1]trim=start_frame=1:end_frame=301,loop=90:1:299,setpts=N/FRAME_RATE/TB[1v]; \
[v2]trim=start_frame=301:end_frame=601,loop=90:1:299,setpts=N/FRAME_RATE/TB[2v]; \
[v3]trim=start_frame=601:end_frame=900,loop=90:1:298,setpts=N/FRAME_RATE/TB[3v]; \
aevalsrc=0:d=3[0a]; \
[0:a]asplit=3[a1][a2][a3]; \
[a1]atrim=0:10,asetpts=N/SR/TB[1a]; \
[a2]atrim=10:20,asetpts=N/SR/TB[2a]; \
[a3]atrim=20:30,asetpts=N/SR/TB[3a]; \
[0v][0a][1v][1a][2v][2a][3v][3a]concat=n=4:v=1:a=1[v][a]" \
-map "[v]" -map "[a]" outva.mp4
This can be done, using a daisychained loop filter.
ffmpeg -i input.mp4 \
-vf loop=90:1:0,setpts=N/FRAME_RATE/TB, \
loop=90:1:390,setpts=N/FRAME_RATE/TB, \
loop=90:1:780,setpts=N/FRAME_RATE/TB, \
loop=90:1:1169,setpts=N/FRAME_RATE/TB
stuttered.mp4
The command above is for a 30 fps video. Each loop filter sets loop to 90 frames i.e. 3 seconds at 30 fps with a 1-frame segment to be looped. The third argument is the frame index that has to be looped. The index for all loop filters after the first, have to be offset since their input feed contains earlier loops inserted e.g. the 2nd loop at 10 seconds would normally be 300
for a 30 fps video, but since the very first has been looped for 3 seconds, it is 3x30 + 10x30 = 390
.
The setpts generates a monotonic set of new timestamps after each loop, since otherwise the command doesn't work correctly.
Audio has been completely ignored.
I created a Python script that does that: https://github.com/slhck/bufferer — you can install it with
pip install bufferer
Then:
bufferer -i input.mp4 -b "[10,3],[20,3],[30,3]" -o output.avi
This will add a "rebuffering" indicator to the command – like a spinner that indicates the pause. It will insert the pauses you specified, i.e., for three seconds at 10, 20 and 30 seconds of the original clip. It will output lossless video with FFV1 encoding and PCM audio, but this can be changed. See the README
for more info.
I am planning to add a feature to disable that rebuffering indicator, as you may just want a simple pause. In the meantime you can use the --dry-run
switch to just print the command and use that as a starting point for some manual changes.