Commit 8466b39e7b for ffmpeg
commit 8466b39e7ba0f3b3d69a38ad1fc88abcfb991327
Author: Kacper Michajłow <kasper93@gmail.com>
Date: Wed Oct 14 10:16:49 2026 +0200
avformat/hls: look playlists up by URL in a tree
Keep the playlists in an AVTree keyed by URL, so new_playlist() finds a
playlist shared by several variants or renditions in logarithmic time
instead of comparing the URL with every known playlist.
Signed-off-by: Kacper Michajłow <kasper93@gmail.com>
diff --git a/libavformat/hls.c b/libavformat/hls.c
index 506c8c0f49..272fb8c2d6 100644
--- a/libavformat/hls.c
+++ b/libavformat/hls.c
@@ -39,6 +39,7 @@
#include "libavutil/opt.h"
#include "libavutil/dict.h"
#include "libavutil/time.h"
+#include "libavutil/tree.h"
#include "avformat.h"
#include "demux.h"
#include "internal.h"
@@ -225,6 +226,7 @@ typedef struct HLSContext {
struct variant **variants;
int n_playlists;
struct playlist **playlists;
+ struct AVTreeNode *playlists_by_url;
int n_renditions;
struct rendition **renditions;
@@ -309,6 +311,8 @@ static void free_playlist_list(HLSContext *c)
}
av_freep(&c->playlists);
c->n_playlists = 0;
+ av_tree_destroy(c->playlists_by_url);
+ c->playlists_by_url = NULL;
}
static void free_variant_list(HLSContext *c)
@@ -332,29 +336,43 @@ static void free_rendition_list(HLSContext *c)
c->n_renditions = 0;
}
+static int cmp_url_playlist(const void *key, const void *b)
+{
+ const struct playlist *pls = b;
+ return strcmp(key, pls->url);
+}
+
+static int cmp_playlist_url(const void *a, const void *b)
+{
+ const struct playlist *pa = a, *pb = b;
+ return strcmp(pa->url, pb->url);
+}
+
static struct playlist *new_playlist(HLSContext *c, const char *url,
const char *base)
{
struct playlist *pls;
+ struct AVTreeNode *node;
char abs_url[MAX_URL_SIZE];
ff_make_absolute_url(abs_url, sizeof(abs_url), base, url);
if (!abs_url[0])
return NULL;
- for (int i = 0; i < c->n_playlists; i++) {
- if (!strcmp(c->playlists[i]->url, abs_url))
- return c->playlists[i];
- }
+ /* the same URL in several variants or renditions shares one playlist */
+ pls = av_tree_find(c->playlists_by_url, abs_url, cmp_url_playlist, NULL);
+ if (pls)
+ return pls;
+
+ pls = av_mallocz(sizeof(struct playlist));
+ node = av_tree_node_alloc();
+ if (!pls || !node)
+ goto fail;
- pls = av_mallocz(sizeof(struct playlist));
- if (!pls)
- return NULL;
pls->pkt = av_packet_alloc();
- if (!pls->pkt) {
- av_free(pls);
- return NULL;
- }
+ if (!pls->pkt)
+ goto fail;
+
av_strlcpy(pls->url, abs_url, sizeof(pls->url));
pls->ts_offset = AV_NOPTS_VALUE;
pls->seek_timestamp = AV_NOPTS_VALUE;
@@ -364,8 +382,17 @@ static struct playlist *new_playlist(HLSContext *c, const char *url,
pls->id3_mpegts_timestamp = AV_NOPTS_VALUE;
pls->timed_id3_stream_index = -1;
- dynarray_add(&c->playlists, &c->n_playlists, pls);
+ if (av_dynarray_add_nofree(&c->playlists, &c->n_playlists, pls) < 0)
+ goto fail;
+ av_tree_insert(&c->playlists_by_url, pls, cmp_playlist_url, &node);
return pls;
+
+fail:
+ if (pls)
+ av_packet_free(&pls->pkt);
+ av_free(pls);
+ av_free(node);
+ return NULL;
}
struct variant_info {