Commit 1b552f55db for ffmpeg
commit 1b552f55dbb4f3f2a240c7f9ac4d6d6c451bb64b
Author: Romain Beauxis <romain.beauxis@gmail.com>
Date: Sat Oct 17 06:31:11 2026 +0200
libavformat/tests: add an HLS playlist parsing test program
Parse a playlist, then optionally a Media Playlist into the first
playlist it declared, as hls_read_header() does, and print the parsed
playlists with their finished state and EXT-X-START offset.
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 7c17892c22..61b4cfb26c 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -797,6 +797,7 @@ TESTPROGS-$(CONFIG_RTPDEC) += rtpdec
FIFO-MUXER-TESTPROGS-$(CONFIG_NETWORK) += fifo_muxer
TESTPROGS-$(CONFIG_FIFO_MUXER) += $(FIFO-MUXER-TESTPROGS-yes)
TESTPROGS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpdh
+TESTPROGS-$(CONFIG_HLS_DEMUXER) += hls
TESTPROGS-$(CONFIG_HTTP_PROTOCOL) += http
TESTPROGS-$(CONFIG_NETWORK) += noproxy
TESTPROGS-$(CONFIG_SRTP) += srtp
diff --git a/libavformat/tests/.gitignore b/libavformat/tests/.gitignore
index 40603e70a5..6e59411112 100644
--- a/libavformat/tests/.gitignore
+++ b/libavformat/tests/.gitignore
@@ -13,3 +13,4 @@
/seek_utils
/http
/ogg_pages
+/hls
diff --git a/libavformat/tests/hls.c b/libavformat/tests/hls.c
new file mode 100644
index 0000000000..267e66650e
--- /dev/null
+++ b/libavformat/tests/hls.c
@@ -0,0 +1,100 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavformat/hls.c"
+
+static void print_playlists(const HLSContext *c, int parse_ret)
+{
+ if (parse_ret < 0) {
+ printf("error: %s\n", av_err2str(parse_ret));
+ return;
+ }
+ printf("%d variant(s), %d playlist(s)\n", c->n_variants, c->n_playlists);
+ for (int i = 0; i < c->n_playlists; i++) {
+ const struct playlist *pls = c->playlists[i];
+ printf("%s: %s, ", av_basename(pls->url), pls->finished ? "finished" : "live");
+ if (pls->time_offset_flag)
+ printf("start offset %"PRId64"\n", pls->start_time_offset);
+ else
+ printf("no start offset\n");
+ }
+}
+
+/**
+ * Parse a playlist, then optionally a Media Playlist into the first
+ * playlist it declared, as hls_read_header() does, and print the parsed
+ * playlists with their finished state and EXT-X-START offset.
+ * Parsing errors are part of the output; only I/O and allocation errors
+ * make the program fail.
+ */
+int main(int argc, char **argv)
+{
+ AVIOContext *top_level = NULL, *first_media = NULL;
+ AVFormatContext *s = NULL;
+ HLSContext *c;
+ int ret, parse_ret;
+
+ if (argc < 2 || argc > 3) {
+ fprintf(stderr, "Usage: %s <playlist> [<media playlist>]\n", argv[0]);
+ return 1;
+ }
+
+ av_log_set_level(AV_LOG_QUIET);
+
+ ret = avio_open(&top_level, argv[1], AVIO_FLAG_READ);
+ if (ret < 0)
+ goto end;
+ if (argc > 2) {
+ ret = avio_open(&first_media, argv[2], AVIO_FLAG_READ);
+ if (ret < 0)
+ goto end;
+ }
+
+ s = avformat_alloc_context();
+ if (!s) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ s->iformat = &ff_hls_demuxer.p;
+ s->priv_data = av_mallocz(ff_hls_demuxer.priv_data_size);
+ if (!s->priv_data) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ *(const AVClass **)s->priv_data = ff_hls_demuxer.p.priv_class;
+ av_opt_set_defaults(s->priv_data);
+ c = s->priv_data;
+ c->ctx = s;
+
+ parse_ret = parse_playlist(c, argv[1], NULL, top_level);
+ if (parse_ret >= 0 && first_media && c->n_playlists)
+ parse_ret = parse_playlist(c, argv[2], c->playlists[0], first_media);
+ print_playlists(c, parse_ret);
+
+end:
+ if (s && s->priv_data)
+ hls_close(s);
+ avformat_free_context(s);
+ avio_closep(&top_level);
+ avio_closep(&first_media);
+ if (ret < 0) {
+ fprintf(stderr, "%s\n", av_err2str(ret));
+ return 1;
+ }
+ return 0;
+}