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]

Reply via email to