7

I have multiple (> 100) videos with various constant frame rates (e.g. 7 FPS, 8 FPS, 16 FPS, 25 FPS) but same codecs and resolutions. I want to concatenate (using ffmpeg concat) them into one video with a variable frame rate (VFR), so that the concatenated video plays every part with the respective framerate. Until now, I only managed to concat all files to a single video with a constant (CFR) of eg. 25 FPS. This as the downside, that all parts with <25 FPS play faster. I use -vsync 2 -r 25 to try to tell ffmpeg to use VFR with a maximum FPS of 25, but mediainfo reports a video with CFR of 25 FPS. If I just use -vsync 2 (without -r), I get a VFR video output, but, mediainfo reports that it is a video with minimum 11.9 FPS and maximum 12 FPS (so kind of mean FPS of all videos). How do I concat various videos to a single VFR video?

Here is the command I used:

ffmpeg -y -vsync 2 -r 25 -f concat -safe 0 -i /tmp/filelist.txt -c:v h264_omx -pix_fmt yuv420p -b:v 524231 -maxrate 524231 -bufsize 1048462 -an /tmp/${DATE}.mp4

I use ffmpeg version 3.2.12-1~deb9u1+rpt on (Raspbian 6.3.0-18+rpi1+deb9u1

Tik0
  • 2,499
  • 4
  • 35
  • 50
  • 4
    Not possible at present. On my to-do. – Gyan Apr 22 '19 at 12:57
  • @Gyan to bad. But what would be a valid workaround? Converting all videos to the same framerate and then cancat them? – Tik0 Apr 22 '19 at 14:42
  • 1
    If you can remux them to MPEG-TS and then concat those, that may work. `ffmpeg -i file.mp4 -c copy file.ts` – Gyan Apr 22 '19 at 15:06
  • 1
    In my case I convert all videos to same framerate based on minimum fps of all videos which better than maximum fps. And some video can't use `-c copy` to avoid `Non-monotonous DTS in output stream` warning which causes part of video stuck. – 林果皞 Sep 21 '19 at 22:59

2 Answers2

1

I was able to do this using the "filter_complex" mode. The simple concat option provided output, but had a delay where I believe it was inserting duplicate frames to make up for running a 12fps source at 30fps.

.\ffmpeg.exe -i .\12fps_start.mp4 -i .\30fps_end.mp4 -filter_complex "[0:v] [1:v] concat=n=2:v=1 [v]" -map "[v]" -c:v libx264 -r 30 final.mp4

NOTE: There were no audio streams in the source files. I was stitching timelapses.

0

As my question is mainly answered in the comments, I'd like to post one other solution w/o intermediate files. I use named pipes and send every snippet, which is converted to a framerate of e.g. 5 FPS, as raw video to that pipe. It is crucial to keep the pipe open using exec. A simple bash script which concats many 720p AVI videos to a single MKV video is as follows:

#!/bin/bash
send2pipe() {
    # Open the pipe permanently
    exec 7<>outpipe
    # Decode and send every raw frame to the pipe 
    for l in $(ls *avi); do ffmpeg -nostdin -i $l -an -filter:v fps=fps=5 -f rawvideo pipe:1 > outpipe 2> /dev/null ; done &
    # Close the pipe (aka send EOF), which causes the encoding app to terminate
    exec 7>&-
}

# Create the pipe
mkfifo outpipe
# Start sending videos to the pipe in the background
send2pipe &
# Encode the frames in the pipe to a single video
ffmpeg -fflags +genpts -f rawvideo -s:v 1280x720 -r 5 -i outpipe -an -c:v libx264 -preset ultrafast -crf 35 -y output.mkv
# Remove the pipe
rm outpipe
Tik0
  • 2,499
  • 4
  • 35
  • 50