This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 84bc57637130c320a8bdbdce9bd438b8210fe980 Author: Kacper Michajłow <[email protected]> AuthorDate: Wed Jul 8 03:54:20 2026 +0200 Commit: Kacper Michajłow <[email protected]> CommitDate: Tue Jul 28 18:01:18 2026 +0200 avformat/hls: set stream start_time for all playlist types Rebase the first packet's timestamp onto the start of the segment list regardless of playlist type, and report it as start_time. Previously only EVENT playlists did this and live streams took start_time from the first loaded segment at the live edge. Which is not correct as some servers provide very deep (hours even) time shift in live playlist. The evicted segments are already tracked by EXT-X-MEDIA-SEQUENCE. This allows us to use all available segments, not only the future ones on live playlist. Also prefer PTS over DTS, as EXTINF durations and start_time are presentation time. Signed-off-by: Kacper Michajłow <[email protected]> --- libavformat/hls.c | 34 +++++++++++++++++++++------------- tests/fate/hlsenc.mak | 2 +- tests/ref/seek/hls | 20 ++++++++++---------- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index 8ac4b35daa..ed6fe7ef5b 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -2205,6 +2205,7 @@ static int set_stream_info_from_input_stream(AVStream *st, struct playlist *pls, /* add new subdemuxer streams to our context, if any */ static int update_streams_from_subdemuxer(AVFormatContext *s, struct playlist *pls) { + HLSContext *c = s->priv_data; int err; while (pls->n_main_streams < pls->ctx->nb_streams) { @@ -2224,6 +2225,11 @@ static int update_streams_from_subdemuxer(AVFormatContext *s, struct playlist *p if (err < 0) return err; + /* Match the start_time of streams created before playback began. */ + if (c->first_timestamp != AV_NOPTS_VALUE) + st->start_time = av_rescale_q(c->first_timestamp, + AV_TIME_BASE_Q, st->time_base); + if (ist->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) { if (pls->timed_id3_stream_index < 0) pls->timed_id3_stream_index = ist_idx; @@ -2740,26 +2746,28 @@ static int hls_read_packet(AVFormatContext *s, AVPacket *pkt) if (pls->ts_offset == AV_NOPTS_VALUE && pls->pkt->dts != AV_NOPTS_VALUE) { + /* Packet timestamp rebased onto the start of the segment list. */ int64_t seg_idx = pls->cur_seq_no - pls->start_seq_no; - int64_t ts = av_rescale_q(pls->pkt->dts, - get_timebase(pls), AV_TIME_BASE_Q); + int64_t ts = av_rescale_q(pls->pkt->pts != AV_NOPTS_VALUE ? + pls->pkt->pts : pls->pkt->dts, + get_timebase(pls), AV_TIME_BASE_Q); - /* EVENT playlists preserve all segments from the start */ - if (pls->type == PLS_TYPE_EVENT) - for (int64_t k = 0; k < seg_idx && k < pls->n_segments; k++) - ts -= pls->segments[k]->duration; + for (int64_t k = 0; k < seg_idx && k < pls->n_segments; k++) + ts -= pls->segments[k]->duration; if (c->first_timestamp == AV_NOPTS_VALUE) { c->first_timestamp = ts; c->first_timestamp_pls = pls; - if (pls->type == PLS_TYPE_EVENT) - for (unsigned k = 0; k < s->nb_streams; k++) { - AVStream *st = s->streams[k]; - if (st->start_time == AV_NOPTS_VALUE) - st->start_time = av_rescale_q(ts, - AV_TIME_BASE_Q, st->time_base); - } + /* start_time is the start of the segment list, the + * origin of the timeline used for seeking. */ + for (unsigned k = 0; k < s->nb_streams; k++) + s->streams[k]->start_time = + av_rescale_q(ts, AV_TIME_BASE_Q, + s->streams[k]->time_base); + av_log(s, AV_LOG_DEBUG, + "First timestamp %"PRId64" from playlist %d\n", + ts, pls->index); } pls->ts_offset = ts - c->first_timestamp; } diff --git a/tests/fate/hlsenc.mak b/tests/fate/hlsenc.mak index 1ddb927cae..f60910cbdf 100644 --- a/tests/fate/hlsenc.mak +++ b/tests/fate/hlsenc.mak @@ -9,7 +9,7 @@ fate-hls-live-no-endlist: tests/data/live_no_endlist.m3u8 fate-hls-live-no-endlist: SRC = $(TARGET_PATH)/tests/data/live_no_endlist.m3u8 fate-hls-live-no-endlist: CMD = md5 -i $(SRC) -af hdcd=process_stereo=false -t 6 -f s24le fate-hls-live-no-endlist: CMP = oneline -fate-hls-live-no-endlist: REF = e038bb8e65d4c1745b9b3ed643e607a3 +fate-hls-live-no-endlist: REF = d41d8cd98f00b204e9800998ecf8427e tests/data/event_no_endlist.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< -nostdin \ diff --git a/tests/ref/seek/hls b/tests/ref/seek/hls index 0f2085916b..a9b3badaf8 100644 --- a/tests/ref/seek/hls +++ b/tests/ref/seek/hls @@ -2,19 +2,19 @@ ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3913 ret: 0 st:-1 flags:0 ts:-1.000000 ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3913 ret: 0 st:-1 flags:1 ts:-0.105833 -ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3913 +ret: 0 st: 0 flags:1 dts: 1.515211 pts: 1.515211 pos: -1 size: 1254 ret: 0 st: 0 flags:0 ts: 0.788333 ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3913 ret: 0 st: 0 flags:1 ts: 1.682500 -ret: 0 st: 1 flags:0 dts: 1.600000 pts: 1.600000 pos: 8836 size: 2330 +ret: 0 st: 0 flags:1 dts: 1.698078 pts: 1.698078 pos: 11092 size: 1253 ret: 0 st: 1 flags:0 ts: 2.576667 ret: 0 st: 0 flags:1 dts: 2.586233 pts: 2.586233 pos: 55836 size: 1254 ret: 0 st: 1 flags:1 ts: 3.470833 -ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3913 +ret: 0 st: 0 flags:1 dts: 1.515211 pts: 1.515211 pos: -1 size: 1254 ret: 0 st:-1 flags:0 ts: 4.365002 ret: 0 st: 0 flags:1 dts: 4.388689 pts: 4.388689 pos: 45308 size: 1254 ret: 0 st:-1 flags:1 ts:-0.740831 -ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3913 +ret: 0 st: 0 flags:1 dts: 1.515211 pts: 1.515211 pos: -1 size: 1254 ret: 0 st: 0 flags:0 ts: 0.153333 ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3913 ret: 0 st: 0 flags:1 ts: 1.047500 @@ -22,7 +22,7 @@ ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3913 ret: 0 st: 1 flags:0 ts: 1.941667 ret: 0 st: 0 flags:1 dts: 1.959300 pts: 1.959300 pos: 24252 size: 1254 ret: 0 st: 1 flags:1 ts: 2.835833 -ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3913 +ret: 0 st: 0 flags:1 dts: 1.515211 pts: 1.515211 pos: -1 size: 1254 ret: 0 st:-1 flags:0 ts: 3.730004 ret: 0 st: 0 flags:1 dts: 3.735622 pts: 3.735622 pos: -1 size: 1254 ret: 0 st:-1 flags:1 ts: 4.624171 @@ -34,20 +34,20 @@ ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3913 ret: 0 st: 1 flags:0 ts: 1.306667 ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3913 ret: 0 st: 1 flags:1 ts: 2.200844 -ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3913 +ret: 0 st: 0 flags:1 dts: 1.515211 pts: 1.515211 pos: -1 size: 1254 ret: 0 st:-1 flags:0 ts: 3.095006 ret: 0 st: 0 flags:1 dts: 3.108689 pts: 3.108689 pos: 82156 size: 1254 ret: 0 st:-1 flags:1 ts: 3.989173 -ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3913 +ret: 0 st: 0 flags:1 dts: 1.515211 pts: 1.515211 pos: -1 size: 1254 ret: 0 st: 0 flags:0 ts: 4.883344 -ret: 0 st: 1 flags:0 dts: 4.800000 pts: 5.100000 pos: 20492 size: 3860 +ret: 0 st: 0 flags:1 dts: 4.885011 pts: 4.885011 pos: -1 size: 1253 ret: 0 st: 0 flags:1 ts:-0.222489 ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3913 ret: 0 st: 1 flags:0 ts: 0.671678 ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3913 ret: 0 st: 1 flags:1 ts: 1.565844 -ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3913 +ret: 0 st: 0 flags:1 dts: 1.515211 pts: 1.515211 pos: -1 size: 1254 ret: 0 st:-1 flags:0 ts: 2.460008 ret: 0 st: 0 flags:1 dts: 2.481744 pts: 2.481744 pos: 50572 size: 1254 ret: 0 st:-1 flags:1 ts: 3.354175 -ret: 0 st: 1 flags:1 dts: 1.400000 pts: 1.500000 pos: 564 size: 3913 +ret: 0 st: 0 flags:1 dts: 1.515211 pts: 1.515211 pos: -1 size: 1254 _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
