>From 3692430935d7987a41225eec289adb9f2561dd98 Mon Sep 17 00:00:00 2001
From: Alan Young <consult....@gmail.com>
Date: Tue, 2 Feb 2021 12:18:34 +0000
Subject: [PATCH] avformat/hls: Use #EXT-X-PROGRAM-DATE-TIME if available

If all the segments in an HLS playlist have #EXT-X-PROGRAM-DATE-TIME
timestamps then they provide better seeking than (just) using #EXTINF.

Parse timestamp in hls.c:parse_playlist() and use in
find_timestamp_in_playlist() if available.

This results in significantly faster startup when seeking long
distances (say > 30 minutes) into HLS/AAC streams.
---
 libavformat/hls.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/libavformat/hls.c b/libavformat/hls.c
index 3c7e197ce7..b0df06151d 100644
--- a/libavformat/hls.c
+++ b/libavformat/hls.c
@@ -34,6 +34,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/dict.h"
 #include "libavutil/time.h"
+#include "libavutil/parseutils.h"
 #include "avformat.h"
 #include "internal.h"
 #include "avio_internal.h"
@@ -67,6 +68,7 @@ enum KeyType {
 
 struct segment {
     int64_t duration;
+    int64_t timestamp;
     int64_t url_offset;
     int64_t size;
     char *url;
@@ -714,6 +716,7 @@ static int parse_playlist(HLSContext *c, const char *url,
 {
     int ret = 0, is_segment = 0, is_variant = 0;
     int64_t duration = 0;
+    int64_t timestamp = 0;
     enum KeyType key_type = KEY_NONE;
     uint8_t iv[16] = "";
     int has_iv = 0;
@@ -868,6 +871,11 @@ static int parse_playlist(HLSContext *c, const char *url,
         } else if (av_strstart(line, "#EXTINF:", &ptr)) {
             is_segment = 1;
             duration   = atof(ptr) * AV_TIME_BASE;
+        } else if (av_strstart(line, "#EXT-X-PROGRAM-DATE-TIME:", &ptr)) {
+            if (av_parse_time(&timestamp, ptr, 0) < 0) {
+                av_log(c->ctx, AV_LOG_INFO, "Cannot parse ('%s')\n", line);
+                timestamp = 0;
+            }
         } else if (av_strstart(line, "#EXT-X-BYTERANGE:", &ptr)) {
             seg_size = strtoll(ptr, NULL, 10);
             ptr = strchr(ptr, '@');
@@ -941,6 +949,8 @@ static int parse_playlist(HLSContext *c, const char *url,
                     duration = 0.001 * AV_TIME_BASE;
                 }
                 seg->duration = duration;
+                seg->timestamp = timestamp;
+                timestamp = 0;
                 seg->key_type = key_type;
                 dynarray_add(&pls->segments, &pls->n_segments, seg);
                 is_segment = 0;
@@ -1644,6 +1654,21 @@ static int find_timestamp_in_playlist(HLSContext *c, struct playlist *pls,
         return 0;
     }
 
+    /* If all segments have timestamps then more accurate than using segment duration */
+    if (pls->n_segments && pls->segments[0]->timestamp) {
+        int64_t initial_timestamp = pls->segments[0]->timestamp;
+        for (i = 1; i < pls->n_segments; i++) {
+            if (!pls->segments[i]->timestamp) break;
+            if (timestamp < pls->segments[i]->timestamp - initial_timestamp) {
+                *seq_no = pls->start_seq_no + i - 1;
+                return 1;
+            } else if (i == pls->n_segments - 1) {
+                *seq_no = pls->start_seq_no + i;
+                return 1;
+            }
+        }
+    }
+
     for (i = 0; i < pls->n_segments; i++) {
         int64_t diff = pos + pls->segments[i]->duration - timestamp;
         if (diff > 0) {
-- 
2.28.0

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".

Reply via email to