FFmpeg may stop with Application provided invalid, non monotonically increasing dts to muxer, or print many timestamp warnings and write a file that stutters when played. It happens most often with recordings, downloaded streams and joined files. The cause is broken timestamps (PTS/DTS). Which fix you need depends on how they broke.

What the Error Means and Why It Happens

Common Messages

[mp4 @ 0x...] Application provided invalid, non monotonically increasing dts to muxer in stream 0
Invalid timestamps stream=0, pts=..., dts=..., size=...
[aost#0:1/copy @ 0x...] Non-monotonic DTS; previous: 96256, current: 96000; changing to 96257. This may result in incorrect timestamps in the output file.

What PTS and DTS Are

  • PTS (Presentation Time Stamp): when a frame is shown
  • DTS (Decoding Time Stamp): when a frame is decoded

The muxer (the part of FFmpeg that writes the output file) expects each stream’s DTS to be monotonically increasing: every frame’s DTS must be later than the one before. If a frame arrives with a DTS equal to or earlier than the previous one, you get the non monotonically increasing dts error.

In a normal video the timestamps keep rising and this error never appears. Interrupted recordings and joined streams can put the timestamps out of order, or make them jump back and forth where a gap was filled in later. The muxer reports this backward jump as an error or a warning. The message names dts, but the damage is often in the PTS, so treat the two together.

Main Causes

Cause Description
VFR (variable frame rate) sources Not a cause by itself. In a VFR file the gaps between frames vary, but the timestamps still rise in order
Broken / discontinuous timestamps TS streams and partly downloaded files can lose PTS/DTS or have them jump backward
Concatenating files The concat demuxer places each file after the previous one. A stream can still step back slightly at a join when the audio and video in a file do not start or end at exactly the same time
Interrupted recordings A capture or recording that is cut off partway ends with damaged timestamps
Negative timestamps With B-frames the first DTS is below zero. FFmpeg handles this by default, so a TS→MP4 copy normally needs no extra option

Some causes can be fixed by rewriting only the timestamps, with -c copy. Others need the frames re-timed, which means re-encoding.

Fix 1: Fill In Missing PTS with genpts

Try this first when the frames are intact but the PTS are missing, as in an AVI file with B-frames. With -fflags +genpts, FFmpeg fills in missing PTS from the DTS. It does not change PTS that are already there, or any DTS.

ffmpeg -fflags +genpts -i input.mp4 -c copy output.mp4
  • -fflags +genpts: generate PTS. It works on the input, so put it before -i
  • -c copy: copy video and audio without re-encoding. No quality loss, and fast

It is the lightest fix, but it leaves the DTS as they are, so it does not fix a non monotonically increasing dts error. If warnings remain, go on to the next fix.

genpts only fills in missing PTS in the container and leaves the video and audio data alone. With -c copy it takes seconds and keeps the full picture and sound quality. If it does not help, the timestamps already in the file are wrong. Then re-encode with Fix 3, which gives the video frames new timestamps.

Tip: -fflags applies to the input file, so write it before -i input.mp4. Placed after it, FFmpeg treats it as an output flag and it has no effect.

Fix 2: Correcting Negative Timestamps

Timestamps do not always start at 0. With B-frames the first DTS is below zero: frames are decoded in a different order from the one they are shown in, so decoding starts before the first frame is shown at 0. -avoid_negative_ts make_zero moves the start to zero.

ffmpeg -i input.ts -c copy -avoid_negative_ts make_zero output.mp4
  • -avoid_negative_ts make_zero: shift all timestamps by the same amount so that the first one is 0, also when the start is above zero
  • -c copy: no re-encoding. Only the timestamps move, so there is no quality loss

make_zero moves every timestamp by the same amount. It does not set only the first frame to 0, and it keeps the gap between the audio and video starts, so it does not fix sync. It is the first DTS that becomes 0, so with B-frames the file can end up starting slightly after 0.

A TS→MP4 copy normally does not need it. MPEG-TS timestamps usually start well above zero, and FFmpeg moves the start of each input to 0 by default. It also handles a negative first DTS on its own.

Using It Together with genpts

If PTS are missing and you want the start at 0, use both options at once.

ffmpeg -fflags +genpts -i input.ts -c copy -avoid_negative_ts make_zero output.mp4

-fflags +genpts fills in missing PTS on the input side, and -avoid_negative_ts make_zero moves the start to 0 on the output side.

Fix 3: Re-Encoding at a Constant Frame Rate

If Fix 1 and Fix 2 (both -c copy) do not help, the timestamps already in the file are wrong, and copying keeps them. Re-encode at a constant frame rate. VFR (variable frame rate) alone is not the cause: a VFR file with correct timestamps copies without these warnings.

ffmpeg -i input.mp4 -fps_mode cfr -r 30 -c:v libx264 -preset veryfast -c:a aac output.mp4
  • -fps_mode cfr: make the output CFR (constant frame rate). FFmpeg duplicates or drops frames to even out the spacing
  • -r 30: target 30 fps (use 24, 25, 60 and so on to match the source)
  • -c:v libx264: the frames are re-timed, so the video must be re-encoded (copy is not possible)
  • -preset veryfast: balances encoding speed and quality
  • -c:a aac: re-encode the audio as AAC

Every video frame gets a new timestamp at a fixed interval, so the video’s DTS rise in order again. The same conversion also helps editing software and players that cannot handle VFR.

CFR conversion fills gaps by duplicating frames and thins out dense stretches, so every frame sits at the same interval. Choose the target rate from the recording settings and what your editor or platform requires, not from the type of device. A higher rate than the source only duplicates frames and does not make motion smoother, and too low a rate makes motion choppy.

Older FFmpeg: -fps_mode is fairly new, and older builds may not have it. Use -vsync cfr instead (ffmpeg -i input.mp4 -vsync cfr -r 30 -c:v libx264 -c:a aac output.mp4). It does the same thing.

Fix 4: Resetting with setpts/asetpts

When the file does not start at 0, or the times shifted after trimming or joining, the setpts and asetpts filters reset the timestamps so the file starts at 0.

ffmpeg -i input.mp4 -vf setpts=PTS-STARTPTS -af asetpts=PTS-STARTPTS -c:v libx264 -c:a aac output.mp4
  • -vf setpts=PTS-STARTPTS: subtract the first PTS (STARTPTS) from every video frame, so the video starts at 0
  • -af asetpts=PTS-STARTPTS: the same for the audio (the a stands for audio)
  • -c:v libx264 / -c:a aac: setpts and asetpts are filters, and filters need re-encoding

Use the two filters together. Each one moves its own stream so that it starts at 0, so if the video and audio start at different times in the input, that gap disappears and the sync shifts by the same amount. genpts fills in only missing PTS. setpts=PTS-STARTPTS keeps the existing values and only moves the start to 0.

When -c copy Fixes It vs. When Re-Encoding Is Required

The main question when you choose a fix is whether you need to re-encode.

Situation Fix Re-encoding
PTS are missing -fflags +genpts + -c copy Not needed
Negative timestamps at the start -avoid_negative_ts make_zero + -c copy Not needed
The copy fixes do not help, or an editor needs CFR -fps_mode cfr -r N (re-encode with libx264 or similar) Required
You want the file to start at 0 setpts=PTS-STARTPTS / asetpts=PTS-STARTPTS Required (they are filters)

Work in this order:

  1. Try the light -c copy options first (genpts, avoid_negative_ts). If they work, you are done, fast and with no quality loss
  2. If warnings remain or playback is still unstable, re-encode with -fps_mode cfr
  3. If the times only shifted after trimming or joining, reset them with setpts/asetpts

-c copy copies the encoded data unchanged and only rewrites the container’s timing information, so quality does not drop. It cannot change the order of the frames themselves. VFR→CFR conversion and filters drop, duplicate or re-time frames, so they cannot work with copy and need re-encoding.

Tested Versions / Target OS

Target OS: Ubuntu 24.04, macOS and Windows. The commands are the same on all three.

FAQ

Q1. The warnings don’t disappear even after adding -fflags +genpts

genpts only fills in missing PTS. It does not change the DTS, so it cannot fix DTS that go backward. Re-encode at a constant frame rate with -fps_mode cfr -r 30 (Fix 3), which gives the video frames new timestamps. Also check that -fflags is before -i, since it is an input flag.

Q2. How do -avoid_negative_ts make_zero and setpts=PTS-STARTPTS differ?

-avoid_negative_ts make_zero is an output option. It moves the start to 0 at the container (muxer) level and works with -c copy. setpts=PTS-STARTPTS is a filter that rewrites the PTS of each frame, so it needs re-encoding. Try avoid_negative_ts first. Use setpts when you want the zero start as part of a filter chain.

Q3. I get non monotonically increasing dts after joining with concat

This is common. The concat demuxer places each file after the previous one, but a stream can still step back slightly at a join, for example when the next file’s audio starts a little before its video. -fflags +genpts does not change the DTS, so it does not help. Re-encoding while you join (-c:v libx264 -c:a aac instead of -c copy) usually avoids it. For how to join files, see Concatenating Multiple Videos.

Q4. I’m told the -fps_mode option doesn’t exist

Your FFmpeg may be too old. -fps_mode is a fairly new name; older builds use -vsync for the same job. Replace -fps_mode cfr with -vsync cfr. Check your version with ffmpeg -version and update if you can.