Streaming concatenated MPEG-TS local files

I’m reading locally stored MpegTS files concatenating them and streaming it live using a simple GStreamer pipeline. Whenever I change to the next file I get in my logs:

0:40:21.209116458 22688 0x6000037d2080 WARN        mpegtspacketizer mpegtspacketizer.c:1895:_set_current_group: RESET detected. diff 0:00:00.710724962

(diff timing variable)

In order to get rid of this, I guess, I need to transmux the content from MpegTS and back to MpegTS, right? The content itself doesn’t have gaps or drops. Before I try to transmux I thought would be good to ask if anyone has an alternative idea here.

My pipeline is as simple as:

appsrc ! typefind ! identity sync=true ! queue ! tsparse set-timestamps=true ! srtsink mode=caller uri="srt://127.0.0.1"

The stream seems to be a little broken, but ffmpeg seems to do a decent job in estimating the timing of the content. Is there a suggestion on how I could maybe do the same with GStreamer?

ffmpeg -re -f concat -safe 0 -i filelist.txt -map 0 -c copy -f mpegts 'srt://127.0.0.1:7001?mode=caller'
[mpegts @ 0x134804d30] start time for stream 9 is not set in estimate_timings_from_pts
[mpegts @ 0x134804d30] stream 0 : no PTS found at end of file, duration not set
Input #0, concat, from 'filelist.txt':
  Duration: N/A, start: 0.000000, bitrate: N/A
  Stream #0:0: Video: hevc (Main 10) ([36][0][0][0] / 0x0024), yuv420p10le(tv, bt709), 1920x1080 [SAR 1:1 DAR 16:9], 59.94 fps, 59.94 tbr, 90k tbn
  Stream #0:1(und): Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 513 kb/s
  Stream #0:2(und): Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 513 kb/s
  Stream #0:3(und): Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 513 kb/s
  Stream #0:4(und): Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 509 kb/s
  Stream #0:5(und): Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 512 kb/s
  Stream #0:6(und): Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 513 kb/s
  Stream #0:7(und): Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 513 kb/s
  Stream #0:8(und): Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 513 kb/s
  Stream #0:9: Data: scte_35
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
  Stream #0:1 -> #0:1 (copy)
  Stream #0:2 -> #0:2 (copy)
  Stream #0:3 -> #0:3 (copy)
  Stream #0:4 -> #0:4 (copy)
  Stream #0:5 -> #0:5 (copy)
  Stream #0:6 -> #0:6 (copy)
  Stream #0:7 -> #0:7 (copy)
  Stream #0:8 -> #0:8 (copy)
  Stream #0:9 -> #0:9 (copy)
Output #0, mpegts, to 'srt://18.235.94.68:7001?mode=caller':
  Metadata:
    encoder         : Lavf61.7.100
  Stream #0:0: Video: hevc (Main 10) ([36][0][0][0] / 0x0024), yuv420p10le(tv, bt709), 1920x1080 [SAR 1:1 DAR 16:9], q=2-31, 59.94 fps, 59.94 tbr, 90k tbn
  Stream #0:1(und): Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 513 kb/s (default)
  Stream #0:2(und): Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 513 kb/s
  Stream #0:3(und): Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 513 kb/s
  Stream #0:4(und): Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 509 kb/s
  Stream #0:5(und): Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 512 kb/s
  Stream #0:6(und): Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 513 kb/s
  Stream #0:7(und): Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 513 kb/s
  Stream #0:8(und): Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 513 kb/s
  Stream #0:9: Data: scte_35
Press [q] to stop, [?] for help
[mpegts @ 0x13482e040] Stream 9, codec scte_35, is muxed as a private data stream and may not be recognized upon reading.
[mpegts @ 0x113604080] start time for stream 9 is not set in estimate_timings_from_pts
[mpegts @ 0x113604080] stream 0 : no PTS found at end of file, duration not set
[mpegts @ 0x10ab04080] start time for stream 9 is not set in estimate_timings_from_pts
[mpegts @ 0x10ab04080] stream 0 : no PTS found at end of file, duration not set
[mpegts @ 0x113604080] start time for stream 1 is not set in estimate_timings_from_pts
[mpegts @ 0x113604080] start time for stream 3 is not set in estimate_timings_from_pts
[mpegts @ 0x113604080] start time for stream 5 is not set in estimate_timings_from_pts
[mpegts @ 0x113604080] start time for stream 6 is not set in estimate_timings_from_pts
[mpegts @ 0x113604080] start time for stream 7 is not set in estimate_timings_from_pts
[mpegts @ 0x113604080] start time for stream 8 is not set in estimate_timings_from_pts
[mpegts @ 0x113604080] start time for stream 9 is not set in estimate_timings_from_pts
[mpegts @ 0x113604080] stream 0 : no PTS found at end of file, duration not set
[mpegts @ 0x113604080] stream 1 : no TS found at start of file, duration not set
[mpegts @ 0x113604080] stream 3 : no TS found at start of file, duration not set
[mpegts @ 0x113604080] stream 5 : no TS found at start of file, duration not set
[mpegts @ 0x113604080] stream 6 : no TS found at start of file, duration not set
[mpegts @ 0x113604080] stream 7 : no TS found at start of file, duration not set
[mpegts @ 0x113604080] stream 8 : no TS found at start of file, duration not set
[mpegts @ 0x113604080] Could not find codec parameters for stream 1 (Audio: aac ([15][0][0][0] / 0x000F), 0 channels): unspecified sample format
Consider increasing the value for the 'analyzeduration' (0) and 'probesize' (5000000) options
[mpegts @ 0x113604080] Could not find codec parameters for stream 3 (Audio: aac ([15][0][0][0] / 0x000F), 0 channels): unspecified sample format
Consider increasing the value for the 'analyzeduration' (0) and 'probesize' (5000000) options
[mpegts @ 0x113604080] Could not find codec parameters for stream 5 (Audio: aac ([15][0][0][0] / 0x000F), 0 channels): unspecified sample format
Consider increasing the value for the 'analyzeduration' (0) and 'probesize' (5000000) options
[mpegts @ 0x113604080] Could not find codec parameters for stream 6 (Audio: aac ([15][0][0][0] / 0x000F), 0 channels): unspecified sample format
Consider increasing the value for the 'analyzeduration' (0) and 'probesize' (5000000) options
[mpegts @ 0x113604080] Could not find codec parameters for stream 7 (Audio: aac ([15][0][0][0] / 0x000F), 0 channels): unspecified sample format
Consider increasing the value for the 'analyzeduration' (0) and 'probesize' (5000000) options
[mpegts @ 0x113604080] Could not find codec parameters for stream 8 (Audio: aac ([15][0][0][0] / 0x000F), 0 channels): unspecified sample format
Consider increasing the value for the 'analyzeduration' (0) and 'probesize' (5000000) options
[mpegts @ 0x113704080] start time for stream 9 is not set in estimate_timings_from_pts
[mpegts @ 0x113704080] stream 0 : no PTS found at end of file, duration not set
[out#0/mpegts @ 0x6000000295c0] video:3891055KiB audio:318379KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: 2.546410%
frame=38212 fps= 60 q=-1.0 Lsize= 4316623KiB time=N/A bitrate=N/A speed=N/A

I also tried setting a high value in the smoothing-latency property of tsdemux (tsparse set-timestamps=true smoothing-latency=2000000) but it causes some bursts in the output. I then tried to add another tsparse set-timestamps=true later to re-adjust, but didn’t work. Anyone has other ideas?

You are concatenating mpeg-ts files. That needs to be done very carefully if you want the resulting file/stream to be flawlessly played back.

tsparse and tsdemux try to do a best-effort to figure out the outgoing timing information.

I’m currently in the middle of a (non-trivial) refactoring of those elements to better handle the whole timing handling (amongst other not-great-ideas my younger self wrote 15 years ago).

I can’t really give an ETA right now, but I’m working on it a bit at a time. This should solve those issues

I shortly looked at this and it’s a regression between 1.24 and main/1.26 introduced by

63a03b167ad39f6d44ab941e7d871359f5bb88fe is the first bad commit
commit 63a03b167ad39f6d44ab941e7d871359f5bb88fe (HEAD)
Author: Edward Hervey <edward@centricular.com>
Date:   Thu Feb 6 09:11:14 2025 +0100

    mpegts: Take into account adaptation field discont
    
    If the flag is set, there is an *expected* discontinuity:
    * For CC, we ignore the fact it's not contiguous
    * For PCR, we acknowledge the values aren't contiguous
    
    Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8420>

 subprojects/gst-plugins-bad/gst/mpegtsdemux/mpegtspacketizer.c | 22 ++++++++++++++++++++++
 subprojects/gst-plugins-bad/gst/mpegtsdemux/tsdemux.c          |  7 +++++++
 2 files changed, 29 insertions(+)

With that commit there’s always a ~1s frame freeze between two concatenated MPEG-TS files (the ones from @rafaelcaricio at least, I didn’t check if it’s a more generic problem).

Pipeline in question was

$ gst-launch-1.0 filesrc location=broken.ts ! tsparse set-timestamps=true ! queue ! tsdemux ! h265parse ! avdec_h265 ! queue ! videoconvert ! autovideosink

I didn’t investigate further yet but I guess each file starts with the discont flag in the adaptation field (or otherwise the commit shouldn’t make any difference).

I have tried using the 1.24.12 version of GStreamer and the frame freeze indeed does not happen (the video frames slows down and not freeze), but there is an very noticeable audio distortion for several seconds.

Example pipeline would be:

gst-launch-1.0 filesrc location=$HOME/broken.ts ! typefind ! \
  tsparse set-timestamps=true ! queue ! tsdemux name=d ! queue ! \
  h265parse ! decodebin ! queue ! videoconvert ! autovideosink  \
  d. ! aacparse ! queue ! decodebin ! audioconvert ! autoaudiosink

The broken.ts is a concatenation of two MPEG-TS streams.

It seems like right now I have to choose the glitch I want to have. :sweat_smile:

1 Like

@rafaelcaricio gitlab is back now (except for various CI things). Can you create an issue for this? :slight_smile:

It seems like right now I have to choose the glitch I want to have. :sweat_smile:

This will need a bit more analysis then based on the stream. It sounds like a) a discont is signalled and if we consider that then tsdemux will align streams so that no stream goes backwards which then causes video to freeze for a moment but audio continues normally, b) if we don’t consider the discont then video is continuous but there’s a glitch with audio (probably audio going backwards).

So the question is whether there is something actually going wrong here, or if timestamps are simply not ideal from one file to another and we don’t handle that as well as ffmpeg.

Created an issue here now: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/4355

I didn’t mark it as regression because either way the behaviour was not ideal.