Ffmpeg concat demuxer shifts video stream start time

Viewed 532

Summary

Ffmpeg concat demuxer shifts video stream start time when invoked with -c copy option.

Reproduction

Given an before.mp4 containing video and audio streams both with start_time=0 and start_pts=0.

Given concat demuxer input file concat.txt with contents:

file before.mp4

Run command ffmpeg -f concat -i concat.txt -c copy concat.mp4

Run command ffprobe concat.mp4 -show_streams and observe that video stream start_time and start_pts are now non-zero (in my tests, the magnitude of this shift is small, on the scale of 0 -> 0.022969).

This causes the processed video, when opened using QuickTime player on Mac, to initially display a blank frame, although the rest of the video plays normally. In the image linked below, the left is what we see when first opening before.mp4; the right is what we see when first opening concat.mp4:

https://i.stack.imgur.com/lWxgF.jpg

Note that this issue occurs when concat demuxer is used to concatenate multiple mp4 files too. I used only one file above for ease of reproduction.

I understand that this issue may be dependent on the codecs used. Therefore, I've included the ffprobe output for before.mp4 below:

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'before.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.45.100
  Duration: 00:00:06.50, start: 0.000000, bitrate: 998 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1024x768 [SAR 1:1 DAR 4:3], 865 kb/s, 50 fps, 50 tbr, 12800 tbn, 100 tbc (default)
    Metadata:
      handler_name    : VideoHandler
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 126 kb/s (default)
    Metadata:
      handler_name    : SoundHandler

What I would like to do

Invoke concat demuxer with -c copy (i.e. without reencoding) without unexpected adjustments to output video stream start time.

I have a limited understanding of audio and video codecs and containers, so any suggestions on why this issue might occur, whether or not it could be fixed by ffmpeg, or suggestions for any other workarounds would be greatly appreciated!

Workarounds I've tried

start_time and start_pts are reset to 0 when the processed video is reencoded without any filters: ffmpeg -i concat.mp4 concat_reencoded.mp4.

This issue is not present when concat demuxer is invoked without -c copy option.

However, both of the above are undesirable since reencoding degrades video quality, which I would like to avoid.

This issue is also not present if before.mp4 is remuxed to before.mkv via ffmpeg -i before.mp4 -c copy before.mkv before being processed by concat demuxer. However, this causes a slight change in fps (e.g. 30 -> 29.96) which I also haven't figured out how to avoid without reencoding.

1 Answers

I've had this issue with the concat demuxer as well. If you then take these videos with start_pts and start_time not 0 and try to concat them with other videos, you end up getting a lot of Non-Monotonous DTS warnings and it can introduce some jankiness in some players.

I have figured out a solution though assuming you have a constant framerate video:

ffmpeg -i problematic_video.mp4 -c copy problematic_video.h264

ffmpeg -fflags +genpts -r 30 -i problematic_video.h264 -i problematic_video.mp4 -c copy -aspect 16:9 -map 0:v -map 1:a -video_track_timescale 90000 fixed_video.mp4

In the first ffmpeg run you pull the raw .h264 stream out of the problematic video

In the second ffmpeg run, we tell it to generate new PTS values and also give tell it the input framerate. You also need to tell it the aspect ratio, otherwise ffprobe will show "N/A" for DAR/SAR. And finally provide your time_base that was used in the problematic_video.mp4.

You will see a lot of warnings about PTS values missing in the second ffmpeg command, but the video should be fine when it finishes processing.

I've bolded the values you will need to change depending your particular video. You can get these values by running:

ffprobe -show_streams -select_streams v problematic_video.mp4
...
display_aspect_ratio: 16:9
r_frame_rate: 30/1
time_base: 1/90000
...

If you ffprobe on fixed_video.mp4 now, you should see all nice values with start_time and start_pts at 0. The wonky average/minimum framerate values you might have got in the problematic_video.mp4 should be fixed as well.

I'm not an expert at ffmpeg, so there may be other solutions, but this is the solution that has worked for me in these situations.

Related