Adding frame to video with same FPS using FFMPEG concat reduces output FPS

6,857

This is indeed due to the H264 PTS generation bug. My suggestion in the comment works for me. But so does the method at the end of the post.

Command for initial file:

ffmpeg -framerate 5 -start_number 1 -t 1 -i "f%d.png" -c:v libx264 -pix_fmt yuv420p -r 5 -bf 0 initial.mp4

Command for individual frames:

ffmpeg -framerate 5 -i "f6.png" -c:v libx264 -pix_fmt yuv420p -bf 0 -r 5 next1.mp4
...
ffmpeg -framerate 5 -i "f10.png" -c:v libx264 -pix_fmt yuv420p -bf 0 -r 5 next5.mp4

A single join:

list.txt:

file initial.mp4
file next1.mp4

and

ffmpeg -f concat -i list.txt -auto_convert 1 -c copy with6.mp4

with6.mp4:

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'with6.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.2.100
  Duration: 00:00:01.20, start: 0.000000, bitrate: 129 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 320x240 [SAR 1:1 DAR 4:3], 124 kb/s, 5 fps, 5 tbr, 10240 tbn, 10 tbc (default)
    Metadata:
      handler_name    : VideoHandler

Join the rest at once:

file with6.mp4
file next2.mp4
file next3.mp4
file next4.mp4
file next5.mp4

and

ffmpeg -f concat -i list.txt -auto_convert 1 -c copy with6.mp4

with10.mp4:

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'with10.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.2.100
  Duration: 00:00:02.00, start: 0.000000, bitrate: 168 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 320x240 [SAR 1:1 DAR 4:3], 165 kb/s, 5 fps, 5 tbr, 10240 tbn, 10 tbc (default)
    Metadata:
      handler_name    : VideoHandler

The other method is to keep your commands as-is but mux to MKV first, and then remux to MP4 i.e.

ffmpeg -f concat -i concat.txt -c copy new_output.mkv

ffmpeg -i new_output.mkv -c copy new_output.mp4
Share:
6,857

Related videos on Youtube

J. Scull
Author by

J. Scull

Python > C#.

Updated on September 18, 2022

Comments

  • J. Scull
    J. Scull over 1 year

    I am developing a piece of C# image-acquisition software in which I am compiling images into a video as I get them.

    Currently I am doing this by creating a video from a set of images once the image count is that of the desired output FPS, for the sake of this question we will use 5 FPS. It will wait until it has 5 images, so it can render 1 second of footage for the base video, to which the new frames will be added. To generate this video I use this command:

    -framerate 5 -start_number 1 -i "C:\path\to\image\Image_%05d.jpg" -c:v libx264 -pix_fmt yuv420p -r 5 "C:\path\to\output\output.mp4"

    Probe output:

    ffmpeg version N-86994-g92da230 Copyright (c) 2000-2017 the FFmpeg developers
      built with gcc 7.1.0 (GCC)
      configuration: --enable-gpl --enable-version3 --enable-cuda --enable-cuvid --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-nvenc --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-lzma --enable-zlib
      libavutil      55. 74.100 / 55. 74.100
      libavcodec     57.102.100 / 57.102.100
      libavformat    57. 76.100 / 57. 76.100
      libavdevice    57.  7.100 / 57.  7.100
      libavfilter     6. 99.100 /  6. 99.100
      libswscale      4.  7.102 /  4.  7.102
      libswresample   2.  8.100 /  2.  8.100
      libpostproc    54.  6.100 / 54.  6.100
    Input #0, image2, from 'B00375_EOL_%05d.jpg':
      Duration: 00:00:02.40, start: 0.000000, bitrate: N/A
        Stream #0:0: Video: mjpeg, yuvj420p(pc, bt470bg/unknown/unknown), 1200x1200 [SAR 144:144 DAR 1:1], 5 fps, 5 tbr, 5 tbn, 5 tbc
    Stream mapping:
      Stream #0:0 -> #0:0 (mjpeg (native) -> h264 (libx264))
    Press [q] to stop, [?] for help
    [swscaler @ 0553cfc0] deprecated pixel format used, make sure you did set range correctly
    [libx264 @ 05491120] using SAR=1/1
    [libx264 @ 05491120] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
    [libx264 @ 05491120] profile High, level 4.0
    [libx264 @ 05491120] 264 - core 152 r2851 ba24899 - H.264/MPEG-4 AVC codec - Copyleft 2003-2017 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=12 lookahead_threads=2 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=5 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
    Output #0, mp4, to 'output.mp4':
      Metadata:
        encoder         : Lavf57.76.100
        Stream #0:0: Video: h264 (libx264) (avc1 / 0x31637661), yuv420p, 1200x1200 [SAR 1:1 DAR 1:1], q=-1--1, 5 fps, 10240 tbn, 5 tbc
        Metadata:
          encoder         : Lavc57.102.100 libx264
        Side data:
          cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: -1
    frame=   12 fps=0.0 q=-1.0 Lsize=     187kB time=00:00:01.80 bitrate= 852.8kbits/s speed=2.76x
    video:186kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.490686%
    [libx264 @ 05491120] frame I:2     Avg QP:14.80  size: 23424
    [libx264 @ 05491120] frame P:9     Avg QP:15.59  size: 14619
    [libx264 @ 05491120] frame B:1     Avg QP:15.13  size: 11846
    [libx264 @ 05491120] consecutive B-frames: 83.3% 16.7%  0.0%  0.0%
    [libx264 @ 05491120] mb I  I16..4: 27.4% 71.2%  1.4%
    [libx264 @ 05491120] mb P  I16..4: 15.6% 72.7%  0.2%  P16..4:  2.8%  0.8%  0.7%  0.0%  0.0%    skip: 7.2%
    [libx264 @ 05491120] mb B  I16..4:  5.3% 31.8%  0.0%  B16..8: 13.6%  8.8%  0.7%  direct: 7.9%  skip:31.8%  L0:93.9% L1: 5.1% BI: 1.0%
    [libx264 @ 05491120] 8x8 transform intra:80.1% inter:91.7%
    [libx264 @ 05491120] coded y,uvDC,uvAC intra: 22.2% 25.1% 4.7% inter: 8.5% 14.4% 0.8%
    [libx264 @ 05491120] i16 v,h,dc,p: 38% 31%  7% 24%
    [libx264 @ 05491120] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 52% 21% 23%  1%  1%  0%  1%  1%  1%
    [libx264 @ 05491120] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 30% 34% 14%  3%  3%  4%  3%  4%  3%
    [libx264 @ 05491120] i8c dc,h,v,p: 65% 18% 14%  3%
    [libx264 @ 05491120] Weighted P-Frames: Y:0.0% UV:0.0%
    [libx264 @ 05491120] ref P L0: 67.1%  9.6% 20.2%  3.1%
    [libx264 @ 05491120] kb/s:634.23
    

    From here I am then generating short single-frame videos to append onto the end of the video to add the new frame, this is done via this commmand:

    -framerate 5 -loop 1 -i "C:\path\to\image\new_image.jpg" -c:v libx264 -pix_fmt yuv420p -t 0.2 -r 5 "C:\path\to\output\new_frame.mp4"

    Probe output:

    ffmpeg version N-86994-g92da230 Copyright (c) 2000-2017 the FFmpeg developers
      built with gcc 7.1.0 (GCC)
      configuration: --enable-gpl --enable-version3 --enable-cuda --enable-cuvid --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-nvenc --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-lzma --enable-zlib
      libavutil      55. 74.100 / 55. 74.100
      libavcodec     57.102.100 / 57.102.100
      libavformat    57. 76.100 / 57. 76.100
      libavdevice    57.  7.100 / 57.  7.100
      libavfilter     6. 99.100 /  6. 99.100
      libswscale      4.  7.102 /  4.  7.102
      libswresample   2.  8.100 /  2.  8.100
      libpostproc    54.  6.100 / 54.  6.100
    Input #0, image2, from 'B00375_PRC_00001.jpg':
      Duration: 00:00:00.20, start: 0.000000, bitrate: 880 kb/s
        Stream #0:0: Video: mjpeg, yuvj420p(pc, bt470bg/unknown/unknown), 1200x1200 [SAR 144:144 DAR 1:1], 5 fps, 5 tbr, 5 tbn, 5 tbc
    Stream mapping:
      Stream #0:0 -> #0:0 (mjpeg (native) -> h264 (libx264))
    Press [q] to stop, [?] for help
    [swscaler @ 03ba0fe0] deprecated pixel format used, make sure you did set range correctly
    [libx264 @ 03b0e2e0] using SAR=1/1
    [libx264 @ 03b0e2e0] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
    [libx264 @ 03b0e2e0] profile High, level 4.0
    [libx264 @ 03b0e2e0] 264 - core 152 r2851 ba24899 - H.264/MPEG-4 AVC codec - Copyleft 2003-2017 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=12 lookahead_threads=2 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=5 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
    Output #0, mp4, to 'new_frame.mp4':
      Metadata:
        encoder         : Lavf57.76.100
        Stream #0:0: Video: h264 (libx264) (avc1 / 0x31637661), yuv420p, 1200x1200 [SAR 1:1 DAR 1:1], q=-1--1, 5 fps, 10240 tbn, 5 tbc
        Metadata:
          encoder         : Lavc57.102.100 libx264
        Side data:
          cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: -1
    frame=    1 fps=0.0 q=23.0 Lsize=      15kB time=00:00:00.00 bitrate=1287020.4kbits/s speed=0.000332x
    video:15kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 5.465249%
    [libx264 @ 03b0e2e0] frame I:1     Avg QP:15.27  size: 14260
    [libx264 @ 03b0e2e0] mb I  I16..4: 19.3% 79.8%  0.9%
    [libx264 @ 03b0e2e0] 8x8 transform intra:79.8%
    [libx264 @ 03b0e2e0] coded y,uvDC,uvAC intra: 19.1% 10.8% 0.1%
    [libx264 @ 03b0e2e0] i16 v,h,dc,p: 35% 49%  6% 10%
    [libx264 @ 03b0e2e0] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 50% 22% 26%  0%  1%  0%  1%  0%  0%
    [libx264 @ 03b0e2e0] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 34% 21% 16%  4%  3%  6%  4%  5%  5%
    [libx264 @ 03b0e2e0] i8c dc,h,v,p: 67% 18% 14%  1%
    [libx264 @ 03b0e2e0] kb/s:570.40
    

    Both of these output files are fine at this stage. The 'main' video generate lasts 1 second and shows 5 FPS in the file properties, so does the single frame, it lasts 0.2 seconds and shows 5 FPS in the properties. These files then get joined via the command:

    -f concat -i concat.txt -auto_convert 1 -c copy joined_vid.mp4 Where concat.txt looks like:

    file 'output.mp4'
    file 'new_frame.mp4'

    Probe output:

    ffmpeg version N-86994-g92da230 Copyright (c) 2000-2017 the FFmpeg developers
      built with gcc 7.1.0 (GCC)
      configuration: --enable-gpl --enable-version3 --enable-cuda --enable-cuvid --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-nvenc --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-lzma --enable-zlib
      libavutil      55. 74.100 / 55. 74.100
      libavcodec     57.102.100 / 57.102.100
      libavformat    57. 76.100 / 57. 76.100
      libavdevice    57.  7.100 / 57.  7.100
      libavfilter     6. 99.100 /  6. 99.100
      libswscale      4.  7.102 /  4.  7.102
      libswresample   2.  8.100 /  2.  8.100
      libpostproc    54.  6.100 / 54.  6.100
    [mov,mp4,m4a,3gp,3g2,mj2 @ 052d8700] Auto-inserting h264_mp4toannexb bitstream filter
    Input #0, concat, from 'concat.txt':
      Duration: N/A, start: 0.000000, bitrate: 636 kb/s
        Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1200x1200 [SAR 1:1 DAR 1:1], 636 kb/s, 5 fps, 5 tbr, 10240 tbn, 10 tbc
        Metadata:
          handler_name    : VideoHandler
    Output #0, mp4, to 'joined_vid.mp4':
      Metadata:
        encoder         : Lavf57.76.100
        Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1200x1200 [SAR 1:1 DAR 1:1], q=2-31, 636 kb/s, 5 fps, 5 tbr, 10240 tbn, 10240 tbc
        Metadata:
          handler_name    : VideoHandler
    Stream mapping:
      Stream #0:0 -> #0:0 (copy)
    Press [q] to stop, [?] for help
    [mov,mp4,m4a,3gp,3g2,mj2 @ 052d8700] Auto-inserting h264_mp4toannexb bitstream filter
    frame=   13 fps=0.0 q=-1.0 Lsize=     202kB time=00:00:02.40 bitrate= 690.0kbits/s speed= 135x
    video:201kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.470814%
    

    From here the newly created 'joined_vid.mp4's FPS drops down, usually to 4 FPS (but have seen it drop straight to 3 FPS) as shown in figure 1. As I incrementally add more frames and new images are acquired the FPS continues to drop until it gets to 1 FPS and then it stays on 1.

    Figure 1

    My question is how can I append my new image onto the end of the video without

    • Dropping frames
    • Having to re-render the whole video with each new image
    • Dropping the output file's FPS

    Any help is greatly appreciated as this currently has me stumped!

    • Gyan
      Gyan over 6 years
      Looks to be due to the broken H.264 PTS generation in ffmpeg. Workaround is to skip B frames, so add -bf 0 to your encoding commands.
    • J. Scull
      J. Scull over 6 years
      @Mulvya sorry for the long reply, this has not fixed my issue and I am still seeing the same thing (frames going from 5 -> 1). Maybe the codecs are different on the appendix file to the time-lapse?
  • Elisa Cha Cha
    Elisa Cha Cha over 6 years
    Is there a bug report for this?
  • Gyan
    Gyan over 6 years
    For this specific issue? No, but #502 is related.
  • J. Scull
    J. Scull over 6 years
    Thank you for this answer, it seems to work perfectly! What I misunderstood was the -bf 0, I only put it on when I was joining the videos as I assumed that's when I would need to skip the frames. I couldn't convert it to a different file type as all this processing has to occur very quickly. Cheers again :)