[FFmpeg-devel] [PATCH 01/10] avformat/hls: fix repeated requests for media init section

Zhao Zhili quinkblack at foxmail.com
Tue Apr 12 11:15:13 EEST 2022


---
 libavformat/hls.c | 59 ++++++++++++++++++++++++++++++++---------------
 1 file changed, 40 insertions(+), 19 deletions(-)

diff --git a/libavformat/hls.c b/libavformat/hls.c
index 83ff4cc607..67c9650e0b 100644
--- a/libavformat/hls.c
+++ b/libavformat/hls.c
@@ -407,48 +407,65 @@ struct init_section_info {
     char byterange[32];
 };
 
-static struct segment *new_init_section(struct playlist *pls,
+/*
+ * Return a new init section if info is new, otherwise return an entry
+ * from pls->init_sections.
+ */
+static struct segment *get_init_section(struct playlist *pls,
                                         struct init_section_info *info,
-                                        const char *url_base)
+                                        const char *url_base,
+                                        int *new_init)
 {
-    struct segment *sec;
+    struct segment *sec_ptr = NULL;
+    struct segment sec = {};
     char tmp_str[MAX_URL_SIZE], *ptr = tmp_str;
 
+    *new_init = 1;
     if (!info->uri[0])
         return NULL;
 
-    sec = av_mallocz(sizeof(*sec));
-    if (!sec)
-        return NULL;
-
     if (!av_strncasecmp(info->uri, "data:", 5)) {
         ptr = info->uri;
     } else {
         ff_make_absolute_url(tmp_str, sizeof(tmp_str), url_base, info->uri);
         if (!tmp_str[0]) {
-            av_free(sec);
             return NULL;
         }
     }
-    sec->url = av_strdup(ptr);
-    if (!sec->url) {
-        av_free(sec);
-        return NULL;
-    }
+    // Don't dup until make sure it's a new initialization section
+    sec.url = ptr;
 
     if (info->byterange[0]) {
-        sec->size = strtoll(info->byterange, NULL, 10);
+        sec.size = strtoll(info->byterange, NULL, 10);
         ptr = strchr(info->byterange, '@');
         if (ptr)
-            sec->url_offset = strtoll(ptr+1, NULL, 10);
+            sec.url_offset = strtoll(ptr+1, NULL, 10);
     } else {
         /* the entire file is the init section */
-        sec->size = -1;
+        sec.size = -1;
     }
 
-    dynarray_add(&pls->init_sections, &pls->n_init_sections, sec);
+    for (int i = 0; i < pls->n_init_sections; i++) {
+        sec_ptr = pls->init_sections[i];
+        if (!strcmp(sec_ptr->url, sec.url) &&
+            sec_ptr->size == sec.size &&
+            sec_ptr->url_offset == sec.url_offset) {
+            *new_init = 0;
+            return sec_ptr;
+        }
+    }
+
+    sec_ptr = av_malloc(sizeof(*sec_ptr));
+    if (!sec_ptr) return NULL;
+    *sec_ptr = sec;
+    sec_ptr->url = av_strdup(ptr);
+    if (!sec_ptr->url) {
+        av_free(sec_ptr);
+        return NULL;
+    }
+    dynarray_add(&pls->init_sections, &pls->n_init_sections, sec_ptr);
 
-    return sec;
+    return sec_ptr;
 }
 
 static void handle_init_section_args(struct init_section_info *info, const char *key,
@@ -851,13 +868,17 @@ static int parse_playlist(HLSContext *c, const char *url,
             else if (!strcmp(ptr, "VOD"))
                 pls->type = PLS_TYPE_VOD;
         } else if (av_strstart(line, "#EXT-X-MAP:", &ptr)) {
+            int new_init = 1;
             struct init_section_info info = {{0}};
             ret = ensure_playlist(c, &pls, url);
             if (ret < 0)
                 goto fail;
             ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_init_section_args,
                                &info);
-            cur_init_section = new_init_section(pls, &info, url);
+            cur_init_section = get_init_section(pls, &info, url, &new_init);
+            /* Skip if it's the same init section */
+            if (!new_init)
+                continue;
             if (!cur_init_section) {
                 ret = AVERROR(ENOMEM);
                 goto fail;
-- 
2.31.1



More information about the ffmpeg-devel mailing list