#17788·jellyfin

Live TV MPEG-TS → HLS remux causes non-monotonic DTS and visible video judder with -copyts / -avoid_negative_ts disabled

Author: josemartingagoCreated Sep 4, 2026Updated Sep 17, 2026
Labelsbug

Description of the bug

Live TV playback shows visible video judder when Jellyfin remuxes an interlaced MPEG-TS source to HLS without re-encoding.

The original continuous MPEG-TS stream plays smoothly when opened directly in standalone mpv.

However, the HLS generated by Jellyfin from that same stream shows visible judder, even when the generated .m3u8 is played directly in standalone mpv. This indicates that the problem is introduced during Jellyfin's server-side MPEG-TS -> HLS remux, rather than by the Jellyfin Desktop renderer.

The problematic source is H.264 1920x1080 interlaced video with:

  • field_order=tt
  • r_frame_rate=50/1
  • avg_frame_rate=25/1
  • time_base=1/90000

The continuous source has regular video PTS values at 40 ms intervals.

Jellyfin Direct Streams the channel to HLS using stream copy for both video and audio, but the generated FFmpeg command includes:

-fflags +igndts+genpts -copyts -start_at_zero -avoid_negative_ts disabled

During playback FFmpeg continuously reports invalid/non-monotonic DTS corrections.

A manual HLS remux of the exact same MPEG-TS source becomes perfectly smooth when timestamps are normalized instead:

-fflags +genpts no -copyts no -start_at_zero -avoid_negative_ts make_zero

while still using:

-c:v copy -c:a copy

I also tested the same timestamp changes inside Jellyfin using an FFmpeg wrapper applied only to /LiveTv/LiveStreamFiles/, and Live TV playback became smooth at original quality.

This appears to be a timestamp-handling issue in the Live TV MPEG-TS -> HLS Direct Stream/remux path.

Reproduction steps

  1. Configure a Live TV source that provides an interlaced H.264 MPEG-TS channel.

    Example source properties:

    • H.264 High
    • 1920x1080
    • interlaced, top-field-first
    • 25 fps frame cadence / 50 tbr
    • AC3 audio
  2. Play the channel in Jellyfin using a client where the source is Direct Streamed/remuxed to HLS rather than transcoded.

  3. Observe visible motion judder during playback.

  4. Check the FFmpeg log generated by Jellyfin. The command contains timestamp-related arguments similar to:

    -fflags +igndts+genpts -copyts -start_at_zero -avoid_negative_ts disabled

  5. Observe repeated FFmpeg messages such as:

    Invalid DTS: ... PTS: ..., replacing by guess

    and:

    Non-monotonic DTS; previous: ..., current: ...; changing to previous+1

  6. Copy the continuous MPEG-TS input used by Jellyfin and play it directly with standalone mpv.

    Result: playback is smooth.

  7. Copy the Jellyfin-generated HLS playlist and segments and play the .m3u8 directly with standalone mpv.

    Result: the same visible judder is present.

  8. Remux the exact same continuous MPEG-TS manually to HLS using FFmpeg with:

    -fflags +genpts no -copyts no -start_at_zero -avoid_negative_ts make_zero -c:v copy -c:a copy

  9. Play the manually generated HLS with standalone mpv.

    Result: playback is perfectly smooth.

  10. As an additional control test, configure Jellyfin to use an FFmpeg wrapper that applies only those timestamp changes to /LiveTv/LiveStreamFiles/.

    Result: the same Live TV channel becomes smooth in Jellyfin at original quality.

What is the current bug behavior?

Jellyfin remuxes the Live TV MPEG-TS source to HLS and introduces timestamp problems.

FFmpeg repeatedly reports invalid and non-monotonic DTS values and adjusts the output timestamps.

The resulting HLS has visible video judder, despite the original MPEG-TS source having a stable frame cadence and playing smoothly directly.

The problem is also visible when the Jellyfin-generated HLS is played outside Jellyfin in standalone mpv, so the judder is already present in the server-generated output.

What is the expected correct behavior?

A Live TV MPEG-TS stream that can be Direct Streamed/remuxed without video re-encoding should retain smooth motion after being converted to HLS.

Jellyfin should generate monotonic/valid output timestamps and should not introduce visible judder into a source that plays smoothly before the remux.

The source should remain at original quality using video/audio stream copy.

Jellyfin Server version

10.11.10

Specify commit id

No response

Specify unstable release number

No response

Specify version number

No response

Specify the build version

10.11.10

Environment

- **OS**: Linux host running Docker
- **Linux Kernel**: 6.8.0-134-generic
- **Virtualization**: Docker
- **Docker Image**: `jellyfin/jellyfin:10.11.10`
- **Clients**: Jellyfin Desktop
- **Client Version**: Jellyfin Desktop 2.0.0-dev
- **Client OS**: Windows 11 22H2
- **FFmpeg Version**: 7.1.3-Jellyfin
- **Playback**: Live TV Direct Stream / Remux to HLS, video and audio stream copy
- **Hardware Acceleration**: Intel iGPU available; issue also reproduced independently of client hardware decoding
- **CPU Model**: 12th Gen Intel(R) Core(TM) i5-1240P
- **GPU Model**: Intel HD Graphics 620
- **Networking**: Docker bridge network
- **Jellyfin Data Storage & Filesystem**: bind mount `/opt/jellyfin-test/config` -> `/config`
- **Jellyfin Cache Storage**: bind mount `/opt/jellyfin-test/cache` -> `/cache`
- **Media Storage & Filesystem**: bind mount `/opt/jellyfin-test/media` -> `/media`
- **External Integrations**: Live TV MPEG-TS over HTTP

Jellyfin logs

Jellyfin Server relevant log excerpt
Issue: Live TV MPEG-TS -> HLS timestamp/judder problem
Jellyfin: 10.11.10

Relevant Live TV MediaSourceInfo (extracted from Jellyfin server log):

[17:07:32] [INF] Emby.Server.Implementations.Library.MediaSourceManager: Live stream opened:
Protocol=Http
Container=ts
ReadAtNativeFramerate=false
IgnoreDts=true
GenPtsInput=false
SupportsTranscoding=true
SupportsDirectStream=true
SupportsDirectPlay=false
IsInfiniteStream=true
UseMostCompatibleTranscodingProfile=true
AnalyzeDurationMs=3000

Video stream:
Codec=h264
DisplayTitle="1080i H264 SDR"
TimeBase=1/90000
IsInterlaced=true
BitRate=20000000
BitDepth=8
Height=1080
Width=1920
AverageFrameRate=25
RealFrameRate=50
ReferenceFrameRate=25
Profile=High
PixelFormat=yuv420p

Audio stream:
Codec=ac3
DisplayTitle="Dolby Digital - Stereo"
TimeBase=1/90000
BitRate=192000
Channels=2
SampleRate=48000

Relevant FFmpeg command generated by Jellyfin:

[17:07:36] [INF] MediaBrowser.MediaEncoding.Transcoding.TranscodeManager:
/usr/lib/jellyfin-ffmpeg/ffmpeg -analyzeduration 3000000 -probesize 1G -fflags +igndts+genpts -f mpegts -i "http://172.26.0.3:8096/LiveTv/LiveStreamFiles/70638b80138b404aa0a9670ebfd84f08/stream.ts" -map_metadata -1 -map_chapters -1 -threads 0 -sn -codec:v:0 copy -start_at_zero -flags -global_header -codec:a:0 copy -copyts -avoid_negative_ts disabled -max_muxing_queue_size 2048 -f hls -max_delay 5000000 -hls_time 3 -hls_segment_type mpegts -start_number 0 -hls_base_url "hls/43bc333729834fe6fb5ff44e5a45592a/" -hls_segment_filename "/cache/transcodes/43bc333729834fe6fb5ff44e5a45592a%d.ts" -hls_playlist_type event -hls_list_size 0 -y "/cache/transcodes/43bc333729834fe6fb5ff44e5a45592a.m3u8"

Additional repetitions from the same server log show the same Direct Stream command being generated:

[17:11:26] [INF] MediaBrowser.MediaEncoding.Transcoding.TranscodeManager:
/usr/lib/jellyfin-ffmpeg/ffmpeg -analyzeduration 3000000 -probesize 1G -fflags +igndts+genpts -f mpegts -i "http://172.26.0.3:8096/LiveTv/LiveStreamFiles/220b423eebbf43e7af2fdddca06e146a/stream.ts" -map_metadata -1 -map_chapters -1 -threads 0 -sn -codec:v:0 copy -start_at_zero -flags -global_header -codec:a:0 copy -copyts -avoid_negative_ts disabled -max_muxing_queue_size 2048 -f hls -max_delay 5000000 -hls_time 3 -hls_segment_type mpegts -start_number 0 -hls_base_url "hls/c36edb312b92a6303cfcb956ad8abbe6/" -hls_segment_filename "/cache/transcodes/c36edb312b92a6303cfcb956ad8abbe6%d.ts" -hls_playlist_type event -hls_list_size 0 -y "/cache/transcodes/c36edb312b92a6303cfcb956ad8abbe6.m3u8"

[17:15:59] [INF] MediaBrowser.MediaEncoding.Transcoding.TranscodeManager:
/usr/lib/jellyfin-ffmpeg/ffmpeg -analyzeduration 3000000 -probesize 1G -fflags +igndts+genpts -f mpegts -i "http://172.26.0.3:8096/LiveTv/LiveStreamFiles/449f1e1824974e538904cb35c3bd45cb/stream.ts" -map_metadata -1 -map_chapters -1 -threads 0 -sn -codec:v:0 copy -start_at_zero -flags -global_header -codec:a:0 copy -copyts -avoid_negative_ts disabled -max_muxing_queue_size 2048 -f hls -max_delay 5000000 -hls_time 3 -hls_segment_type mpegts -start_number 0 -hls_base_url "hls/f61f86684b9eca65d1888d77bdf77716/" -hls_segment_filename "/cache/transcodes/f61f86684b9eca65d1888d77bdf77716%d.ts" -hls_playlist_type event -hls_list_size 0 -y "/cache/transcodes/f61f86684b9eca65d1888d77bdf77716.m3u8"

Key timestamp-related arguments visible in Jellyfin's generated command:
-fflags +igndts+genpts
-start_at_zero
-copyts
-avoid_negative_ts disabled

Video and audio are stream-copied:
-codec:v:0 copy
-codec:a:0 copy

FFmpeg logs

Jellyfin FFmpeg relevant log excerpt
Issue: Live TV MPEG-TS -> HLS timestamp/judder problem
Source: original FFmpeg log uploaded by user (Pegado text(9).txt)


/usr/lib/jellyfin-ffmpeg/ffmpeg -analyzeduration 3000000 -probesize 1G -fflags +igndts+genpts -f mpegts  -i "http://172.26.0.3:8096/LiveTv/LiveStreamFiles/02abd1cb5e4f43c0aca2cc022b8da469/stream.ts" -map_metadata -1 -map_chapters -1 -threads 0 -sn -codec:v:0 copy -start_at_zero -flags -global_header -codec:a:0 copy -copyts -avoid_negative_ts disabled -max_muxing_queue_size 2048 -f hls -max_delay 5000000 -hls_time 3 -hls_segment_type mpegts -start_number 0 -hls_base_url "hls/5c78f90c24b8604b0aadc4d502a5bc92/" -hls_segment_filename "/cache/transcodes/5c78f90c24b8604b0aadc4d502a5bc92%d.ts" -hls_playlist_type event -hls_list_size 0 -y "/cache/transcodes/5c78f90c24b8604b0aadc4d502a5bc92.m3u8"


ffmpeg version 7.1.3-Jellyfin Copyright (c) 2000-2025 the FFmpeg developers
  built with gcc 14 (Debian 14.2.0-19)
  configuration: --prefix=/usr/lib/jellyfin-ffmpeg --target-os=linux --extra-version=Jellyfin --disable-doc --disable-ffplay --disable-static --disable-libxcb --disable-sdl2 --disable-xlib --enable-lto=auto --enable-gpl --enable-version3 --enable-shared --enable-gmp --enable-gnutls --enable-chromaprint --enable-opencl --enable-libdrm --enable-libxml2 --enable-libass --enable-libfreetype --enable-libfribidi --enable-libfontconfig --enable-libharfbuzz --enable-libbluray --enable-libmp3lame --enable-libopus --enable-libtheora --enable-libvorbis --enable-libopenmpt --enable-libdav1d --enable-libsvtav1 --enable-libwebp --enable-libvpx --enable-libx264 --enable-libx265 --enable-libzvbi --enable-libzimg --enable-libfdk-aac --arch=amd64 --enable-libshaderc --enable-libplacebo --enable-vulkan --enable-vaapi --enable-amf --enable-libvpl --enable-ffnvcodec --enable-cuda --enable-cuda-llvm --enable-cuvid --enable-nvdec --enable-nvenc
  libavutil      59. 39.100 / 59. 39.100
  libavcodec     61. 19.101 / 61. 19.101
  libavformat    61.  7.100 / 61.  7.100
  libavdevice    61.  3.100 / 61.  3.100
  libavfilter    10.  4.100 / 10.  4.100
  libswscale      8.  3.100 /  8.  3.100
  libswresample   5.  3.100 /  5.  3.100
  libpostproc    58.  3.100 / 58.  3.100
[h264 @ 0x7274ba561a80] non-existing PPS 0 referenced
    Last message repeated 1 times

Input #0, mpegts, from 'http://172.26.0.3:8096/LiveTv/LiveStreamFiles/02abd1cb5e4f43c0aca2cc022b8da469/stream.ts':
  Duration: N/A, start: 53127.963200, bitrate: N/A
  Program 29951 
  Program 29956 
  Program 29959 
  Program 29960 
  Program 29961 
  Program 29962 
  Program 29963 
  Program 29964 
  Program 29965 
  Program 29967 
  Stream #0:1[0xa7]: Video: h264 (High) ([27][0][0][0] / 0x001B), yuv420p(top first), 1920x1080 [SAR 1:1 DAR 16:9], 25 fps, 50 tbr, 90k tbn
  Stream #0:2[0x78](spa): Audio: ac3 ([6][0][0][0] / 0x0006), 48000 Hz, stereo, fltp, 192 kb/s (clean effects)
  Stream #0:3[0x79](dos): Audio: ac3 ([6][0][0][0] / 0x0006), 48000 Hz, stereo, fltp, 192 kb/s (clean effects)
  Stream #0:4[0x7a]: Audio: mp2 ([4][0][0][0] / 0x0004), 48000 Hz, stereo, s16p, 160 kb/s
  Stream #0:5[0x7b]: Audio: mp2 ([4][0][0][0] / 0x0004), 48000 Hz, stereo, s16p, 160 kb/s
  Stream #0:6[0x7c]: Audio: mp2 ([4][0][0][0] / 0x0004), 48000 Hz, stereo, s16p, 160 kb/s
  Stream #0:7[0x7d]: Audio: mp2 ([4][0][0][0] / 0x0004), 48000 Hz, stereo, s16p, 160 kb/s
  Stream #0:8[0x36](spa): Subtitle: dvb_teletext (libzvbi_teletextdec) ([6][0][0][0] / 0x0006), 492x250
  Stream #0:9[0xd0]: Unknown: none ([192][0][0][0] / 0x00C0)
  Stream #0:10[0xde]: Unknown: none ([192][0][0][0] / 0x00C0)
  Stream #0:11[0x133]: Audio: ac3 ([193][0][0][0] / 0x00C1), 0 channels, fltp
  Stream #0:12[0x164]: Audio: ac3 ([193][0][0][0] / 0x00C1), 0 channels, fltp
  Stream #0:13[0x188]: Audio: ac3 ([193][0][0][0] / 0x00C1), 0 channels, fltp
  Stream #0:14[0x135]: Unknown: none ([192][0][0][0] / 0x00C0)
  Stream #0:15[0x275]: Audio: ac3 ([193][0][0][0] / 0x00C1), 0 channels, fltp
  Stream #0:16[0x378]: Audio: ac3 ([193][0][0][0] / 0x00C1), 0 channels, fltp
  Program 29968 
  Program 29969 
  No Program
  Stream #0:0[0x12]: Data: epg
Stream mapping:
  Stream #0:1 -> #0:0 (copy)
  Stream #0:2 -> #0:1 (copy)
Output #0, hls, to '/cache/transcodes/5c78f90c24b8604b0aadc4d502a5bc92.m3u8':
  Metadata:
    encoder         : Lavf61.7.100
  Stream #0:0: Video: h264 (High) ([27][0][0][0] / 0x001B), yuv420p(top first), 1920x1080 [SAR 1:1 DAR 16:9], q=2-31, 25 fps, 50 tbr, 90k tbn
  Stream #0:1: Audio: ac3 ([6][0][0][0] / 0x0006), 48000 Hz, stereo, fltp, 192 kb/s (clean effects)
Press [q] to stop, [?] for help
[vost#0:0/copy @ 0x7274ba454000] Invalid DTS: 169560 PTS: 160560, replacing by guess
[vost#0:0/copy @ 0x7274ba454000] Invalid DTS: 171360 PTS: 162360, replacing by guess
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 167762, current: 156960; changing to 167763. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 167763, current: 158760; changing to 167764. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 167764, current: 153360; changing to 167765. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 167765, current: 155160; changing to 167766. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 167766, current: 160560; changing to 167767. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 167767, current: 162360; changing to 167768. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 167768, current: 164160; changing to 167769. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 167769, current: 165960; changing to 167770. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 182160, current: 174960; changing to 182161. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 182161, current: 176760; changing to 182162. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 182162, current: 171360; changing to 182163. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 182163, current: 173160; changing to 182164. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 182164, current: 178560; changing to 182165. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 182165, current: 180360; changing to 182166. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 189360, current: 185760; changing to 189361. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 189361, current: 187560; changing to 189362. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 210960, current: 203760; changing to 210961. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 210961, current: 205560; changing to 210962. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 210962, current: 200160; changing to 210963. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 210963, current: 201960; changing to 210964. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 210964, current: 207360; changing to 210965. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 210965, current: 209160; changing to 210966. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 218160, current: 214560; changing to 218161. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 218161, current: 216360; changing to 218162. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 239760, current: 232560; changing to 239761. This may result in incorrect timestamps in the output file.
[vost#0:0/copy @ 0x7274ba454000] Non-monotonic DTS; previous: 239761, current: 234360; changing to 239762. This may result in incorrect timestamps in the output file.

---- Representative errors later during the same playback ----

---- Key observations ----

Jellyfin-generated timestamp options:
-fflags +igndts+genpts
-start_at_zero
-copyts
-avoid_negative_ts disabled

Streams are copied without video/audio re-encoding:
Stream #0:1 -> #0:0 (copy)
Stream #0:2 -> #0:1 (copy)

FFmpeg repeatedly reports:
Invalid DTS ... replacing by guess
Non-monotonic DTS ... changing to previous+1

The errors are not limited to startup; they continue more than two minutes into playback.

Client / Browser logs

No response

Relevant screenshots or videos

I have an .m3u8 playlist together with the associated .ts segments generated by Jellyfin that reproduce the judder when played in standalone mpv, but GitHub does not allow me to upload them here.

Additional information

I performed an A/B test using the exact same continuous MPEG-TS input.

Jellyfin-generated HLS:

-fflags +igndts+genpts -copyts -start_at_zero -avoid_negative_ts disabled

Result: visible judder.

Manual FFmpeg HLS remux:

-fflags +genpts no -copyts no -start_at_zero -avoid_negative_ts make_zero -c:v copy -c:a copy

Result: perfectly smooth.

I then configured Jellyfin to use an FFmpeg wrapper that applies only these timestamp changes to commands containing:

/LiveTv/LiveStreamFiles/

With that workaround, the same channel plays smoothly in Jellyfin at original quality.

No video re-encoding is required to fix the issue.

I am not suggesting that -copyts should necessarily be removed globally. It may be required for other playback/transcoding scenarios.

The request is to investigate timestamp handling specifically in the Live TV MPEG-TS -> HLS Direct Stream/remux path, especially when the media source has IgnoreDts: true.