>From 3692430935d7987a41225eec289adb9f2561dd98 Mon Sep 17 00:00:00 2001
From: Alan Young <[email protected]>
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(×tamp, 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
[email protected]
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".