PR #25384 opened by danog
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25384
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25384.patch

Opening a Master Playlist fetches every Media Playlist, and then the key and 
first segment of each, strictly one after another, each over a new connection. 
With several variants or renditions this takes seconds before the first packet.

This adds `parallel_open`, the maximum number of playlists to load at once. 
Above 1, Media Playlist parsing and the opening of the per-playlist demuxers 
run in up to that many threads. Streams are still created in playlist order. 
The default (0) is unchanged and takes the original code path. Opening live 
streams with several audio renditions went from 1.8 s to 0.6 s, 4.0 s to 1.5 s 
and 1.7 s to 0.5 s in testing.

- Shared state is protected by a mutex, and concurrent responses that set 
cookies are merged into the cookie jar.
- The persistent playlist connection isn't used while threads run, and 
playlists with SAMPLE-AES segments are opened one after another.
- With the option above 1, the `io_open`, `io_close2` and interrupt callbacks 
can be called from several threads; this is documented.
- Checked with ThreadSanitizer, including over HTTP with cookies.
- A FATE test opens a stream with two audio renditions and a subtitle playlist 
both ways and compares the result with the same reference.

The first commit is a no-functional-change refactor.

Kodi carries this as a patch in https://github.com/xbmc/xbmc/pull/30046; its 
maintainers asked for it to be submitted here instead.



>From 2491dd254d064e871e67edbe6bd2c481a40f1b75 Mon Sep 17 00:00:00 2001
From: Daniil Gentili <[email protected]>
Date: Thu, 22 Oct 2026 23:41:56 +0200
Subject: [PATCH 1/2] avformat/hls: factor out opening the demuxer of a
 playlist

Move the code opening the demuxer of each playlist on its first segment
from hls_read_header() to its own function. No functional change.

Signed-off-by: Daniil Gentili <[email protected]>
---
 libavformat/hls.c | 339 ++++++++++++++++++++++++----------------------
 1 file changed, 176 insertions(+), 163 deletions(-)

diff --git a/libavformat/hls.c b/libavformat/hls.c
index c68b5e88cf5..e36f6d30723 100644
--- a/libavformat/hls.c
+++ b/libavformat/hls.c
@@ -2469,6 +2469,181 @@ static int hls_close(AVFormatContext *s)
     return 0;
 }
 
+/* Open the demuxer of one playlist on its first segment */
+static int open_playlist_demuxer(AVFormatContext *s, struct playlist *pls,
+                                 int64_t highest_cur_seq_no)
+{
+    HLSContext *c = s->priv_data;
+    const AVInputFormat *in_fmt = NULL;
+    char *url;
+    AVDictionary *options = NULL;
+    struct segment *seg = NULL;
+    uint8_t *buf;
+    int buf_size;
+    int ret = 0;
+
+    /*
+     * If this is a live stream and this playlist looks like it is one segment
+     * behind, try to sync it up so that every substream starts at the same
+     * time position (so e.g. avformat_find_stream_info() will see packets from
+     * all active streams within the first few seconds). This is not very 
generic,
+     * though, as the sequence numbers are technically independent.
+     */
+    if (!pls->finished && pls->cur_seq_no == highest_cur_seq_no - 1 &&
+        highest_cur_seq_no < pls->start_seq_no + pls->n_segments) {
+        pls->cur_seq_no = highest_cur_seq_no;
+    }
+
+    if (pls->is_subtitle) {
+        buf_size = strlen("WEBVTT\n");
+        buf = av_memdup("WEBVTT\n", buf_size);
+    } else {
+        buf_size = INITIAL_BUFFER_SIZE;
+        buf = av_malloc(buf_size);
+    }
+    if (!buf) {
+        avformat_free_context(pls->ctx);
+        pls->ctx = NULL;
+        return AVERROR(ENOMEM);
+    }
+
+    ffio_init_context(&pls->pb, buf, buf_size, 0, pls,
+                      pls->is_subtitle ? NULL : read_data_continuous, NULL, 
NULL);
+
+    /*
+     * If encryption scheme is SAMPLE-AES, try to read  ID3 tags of
+     * external audio track that contains audio setup information
+     */
+    seg = current_segment(pls);
+    if (seg && seg->key_type == KEY_SAMPLE_AES && pls->n_renditions > 0 &&
+        pls->renditions[0]->type == AVMEDIA_TYPE_AUDIO) {
+        uint8_t buf[HLS_MAX_ID3_TAGS_DATA_LEN];
+        if ((ret = avio_read(&pls->pb.pub, buf, HLS_MAX_ID3_TAGS_DATA_LEN)) < 
0) {
+            /* Fail if error was not end of file */
+            if (ret != AVERROR_EOF) {
+                avformat_free_context(pls->ctx);
+                pls->ctx = NULL;
+                return ret;
+            }
+        }
+        ret = 0;
+        /* Reset reading */
+        ff_format_io_close(pls->parent, &pls->input);
+        pls->input = NULL;
+        pls->input_read_done = 0;
+        ff_format_io_close(pls->parent, &pls->input_next);
+        pls->input_next = NULL;
+        pls->input_next_requested = 0;
+        pls->cur_seg_offset = 0;
+        pls->cur_init_section = NULL;
+        /* Reset EOF flag */
+        pls->pb.pub.eof_reached = 0;
+        /* Clear any buffered data */
+        pls->pb.pub.buf_end = pls->pb.pub.buf_ptr = pls->pb.pub.buffer;
+        /* Reset the position */
+        pls->pb.pub.pos = 0;
+    }
+
+    /*
+     * If encryption scheme is SAMPLE-AES and audio setup information is 
present in external audio track,
+     * use that information to find the media format, otherwise probe input 
data
+     */
+    seg = current_segment(pls);
+    if (seg && seg->key_type == KEY_SAMPLE_AES && pls->is_id3_timestamped &&
+        pls->audio_setup_info.codec_id != AV_CODEC_ID_NONE) {
+        av_assert1(pls->audio_setup_info.codec_id == AV_CODEC_ID_AAC ||
+                   pls->audio_setup_info.codec_id == AV_CODEC_ID_AC3 ||
+                   pls->audio_setup_info.codec_id == AV_CODEC_ID_EAC3);
+        // Keep this list in sync with ff_hls_senc_read_audio_setup_info()
+        in_fmt = av_find_input_format(pls->audio_setup_info.codec_id == 
AV_CODEC_ID_AAC ? "aac" :
+                                      pls->audio_setup_info.codec_id == 
AV_CODEC_ID_AC3 ? "ac3" : "eac3");
+    } else {
+        pls->ctx->probesize = s->probesize > 0 ? s->probesize : 1024 * 4;
+        pls->ctx->max_analyze_duration = s->max_analyze_duration > 0 ? 
s->max_analyze_duration : 4 * AV_TIME_BASE;
+        pls->ctx->interrupt_callback = s->interrupt_callback;
+        url = av_strdup(pls->segments[0]->url);
+        ret = av_probe_input_buffer(&pls->pb.pub, &in_fmt, url, NULL, 0, 0);
+
+        for (int n = 0; n < pls->n_segments; n++)
+            if (ret >= 0)
+                ret = test_segment(s, in_fmt, pls, pls->segments[n]);
+
+        if (ret < 0) {
+            /* Free the ctx - it isn't initialized properly at this point,
+            * so avformat_close_input shouldn't be called. If
+            * avformat_open_input fails below, it frees and zeros the
+            * context, so it doesn't need any special treatment like this. */
+            av_log(s, AV_LOG_ERROR, "Error when loading first segment '%s'\n", 
url);
+            avformat_free_context(pls->ctx);
+            pls->ctx = NULL;
+            av_free(url);
+            return ret;
+        }
+        av_free(url);
+    }
+
+    seg = current_segment(pls);
+    if (seg && seg->key_type == KEY_SAMPLE_AES) {
+        if (strstr(in_fmt->name, "mov")) {
+            char key[33];
+            ff_data_to_hex(key, pls->key, sizeof(pls->key), 0);
+            av_dict_set(&options, "decryption_key", key, 0);
+        } else if (!c->crypto_ctx.aes_ctx) {
+            c->crypto_ctx.aes_ctx = av_aes_alloc();
+            if (!c->crypto_ctx.aes_ctx) {
+                avformat_free_context(pls->ctx);
+                pls->ctx = NULL;
+                return AVERROR(ENOMEM);
+            }
+        }
+    }
+
+    pls->ctx->pb       = &pls->pb.pub;
+    pls->ctx->io_open  = nested_io_open;
+    pls->ctx->flags   |= s->flags & ~AVFMT_FLAG_CUSTOM_IO;
+
+    if ((ret = ff_copy_whiteblacklists(pls->ctx, s)) < 0)
+        return ret;
+
+    av_dict_copy(&options, c->seg_format_opts, 0);
+
+    ret = avformat_open_input(&pls->ctx, pls->segments[0]->url, in_fmt, 
&options);
+    av_dict_free(&options);
+    if (ret < 0)
+        return ret;
+
+    if (pls->id3_deferred_extra && pls->ctx->nb_streams == 1) {
+        if (av_match_name(pls->ctx->iformat->name, PACKED_AUDIO_FORMATS))
+            ff_id3v2_parse_apic(pls->ctx, pls->id3_deferred_extra);
+        avformat_queue_attached_pictures(pls->ctx);
+        ff_id3v2_parse_priv(pls->ctx, pls->id3_deferred_extra);
+        ff_id3v2_free_extra_meta(&pls->id3_deferred_extra);
+    }
+
+    if (pls->is_id3_timestamped == -1)
+        av_log(s, AV_LOG_WARNING, "No expected HTTP requests have been 
made\n");
+
+    /*
+     * For ID3 timestamped raw audio streams we need to detect the packet
+     * durations to calculate timestamps in 
fill_timing_for_id3_timestamped_stream(),
+     * but for other streams we can rely on our user calling 
avformat_find_stream_info()
+     * on us if they want to.
+     */
+    if (pls->is_id3_timestamped || (pls->n_renditions > 0 && 
pls->renditions[0]->type == AVMEDIA_TYPE_AUDIO)) {
+        seg = current_segment(pls);
+        if (seg && seg->key_type == KEY_SAMPLE_AES && 
pls->audio_setup_info.setup_data_length > 0 &&
+            pls->ctx->nb_streams == 1)
+            ret = ff_hls_senc_parse_audio_setup_info(pls->ctx->streams[0], 
&pls->audio_setup_info);
+        else
+            ret = avformat_find_stream_info(pls->ctx, NULL);
+
+        if (ret < 0)
+            return ret;
+    }
+
+    return 0;
+}
+
 static int hls_read_header(AVFormatContext *s)
 {
     HLSContext *c = s->priv_data;
@@ -2593,12 +2768,6 @@ static int hls_read_header(AVFormatContext *s)
     /* Open the demuxer for each playlist */
     for (i = 0; i < c->n_playlists; i++) {
         struct playlist *pls = c->playlists[i];
-        const AVInputFormat *in_fmt = NULL;
-        char *url;
-        AVDictionary *options = NULL;
-        struct segment *seg = NULL;
-        uint8_t *buf;
-        int buf_size;
 
         if (!(pls->ctx = avformat_alloc_context()))
             return AVERROR(ENOMEM);
@@ -2610,165 +2779,9 @@ static int hls_read_header(AVFormatContext *s)
         pls->needed = 1;
         pls->parent = s;
 
-        /*
-         * If this is a live stream and this playlist looks like it is one 
segment
-         * behind, try to sync it up so that every substream starts at the same
-         * time position (so e.g. avformat_find_stream_info() will see packets 
from
-         * all active streams within the first few seconds). This is not very 
generic,
-         * though, as the sequence numbers are technically independent.
-         */
-        if (!pls->finished && pls->cur_seq_no == highest_cur_seq_no - 1 &&
-            highest_cur_seq_no < pls->start_seq_no + pls->n_segments) {
-            pls->cur_seq_no = highest_cur_seq_no;
-        }
-
-        if (pls->is_subtitle) {
-            buf_size = strlen("WEBVTT\n");
-            buf = av_memdup("WEBVTT\n", buf_size);
-        } else {
-            buf_size = INITIAL_BUFFER_SIZE;
-            buf = av_malloc(buf_size);
-        }
-        if (!buf) {
-            avformat_free_context(pls->ctx);
-            pls->ctx = NULL;
-            return AVERROR(ENOMEM);
-        }
-
-        ffio_init_context(&pls->pb, buf, buf_size, 0, pls,
-                          pls->is_subtitle ? NULL : read_data_continuous, 
NULL, NULL);
-
-        /*
-         * If encryption scheme is SAMPLE-AES, try to read  ID3 tags of
-         * external audio track that contains audio setup information
-         */
-        seg = current_segment(pls);
-        if (seg && seg->key_type == KEY_SAMPLE_AES && pls->n_renditions > 0 &&
-            pls->renditions[0]->type == AVMEDIA_TYPE_AUDIO) {
-            uint8_t buf[HLS_MAX_ID3_TAGS_DATA_LEN];
-            if ((ret = avio_read(&pls->pb.pub, buf, 
HLS_MAX_ID3_TAGS_DATA_LEN)) < 0) {
-                /* Fail if error was not end of file */
-                if (ret != AVERROR_EOF) {
-                    avformat_free_context(pls->ctx);
-                    pls->ctx = NULL;
-                    return ret;
-                }
-            }
-            ret = 0;
-            /* Reset reading */
-            ff_format_io_close(pls->parent, &pls->input);
-            pls->input = NULL;
-            pls->input_read_done = 0;
-            ff_format_io_close(pls->parent, &pls->input_next);
-            pls->input_next = NULL;
-            pls->input_next_requested = 0;
-            pls->cur_seg_offset = 0;
-            pls->cur_init_section = NULL;
-            /* Reset EOF flag */
-            pls->pb.pub.eof_reached = 0;
-            /* Clear any buffered data */
-            pls->pb.pub.buf_end = pls->pb.pub.buf_ptr = pls->pb.pub.buffer;
-            /* Reset the position */
-            pls->pb.pub.pos = 0;
-        }
-
-        /*
-         * If encryption scheme is SAMPLE-AES and audio setup information is 
present in external audio track,
-         * use that information to find the media format, otherwise probe 
input data
-         */
-        seg = current_segment(pls);
-        if (seg && seg->key_type == KEY_SAMPLE_AES && pls->is_id3_timestamped 
&&
-            pls->audio_setup_info.codec_id != AV_CODEC_ID_NONE) {
-            av_assert1(pls->audio_setup_info.codec_id == AV_CODEC_ID_AAC ||
-                       pls->audio_setup_info.codec_id == AV_CODEC_ID_AC3 ||
-                       pls->audio_setup_info.codec_id == AV_CODEC_ID_EAC3);
-            // Keep this list in sync with ff_hls_senc_read_audio_setup_info()
-            in_fmt = av_find_input_format(pls->audio_setup_info.codec_id == 
AV_CODEC_ID_AAC ? "aac" :
-                                          pls->audio_setup_info.codec_id == 
AV_CODEC_ID_AC3 ? "ac3" : "eac3");
-        } else {
-            pls->ctx->probesize = s->probesize > 0 ? s->probesize : 1024 * 4;
-            pls->ctx->max_analyze_duration = s->max_analyze_duration > 0 ? 
s->max_analyze_duration : 4 * AV_TIME_BASE;
-            pls->ctx->interrupt_callback = s->interrupt_callback;
-            url = av_strdup(pls->segments[0]->url);
-            ret = av_probe_input_buffer(&pls->pb.pub, &in_fmt, url, NULL, 0, 
0);
-
-            for (int n = 0; n < pls->n_segments; n++)
-                if (ret >= 0)
-                    ret = test_segment(s, in_fmt, pls, pls->segments[n]);
-
-            if (ret < 0) {
-                /* Free the ctx - it isn't initialized properly at this point,
-                * so avformat_close_input shouldn't be called. If
-                * avformat_open_input fails below, it frees and zeros the
-                * context, so it doesn't need any special treatment like this. 
*/
-                av_log(s, AV_LOG_ERROR, "Error when loading first segment 
'%s'\n", url);
-                avformat_free_context(pls->ctx);
-                pls->ctx = NULL;
-                av_free(url);
-                return ret;
-            }
-            av_free(url);
-        }
-
-        seg = current_segment(pls);
-        if (seg && seg->key_type == KEY_SAMPLE_AES) {
-            if (strstr(in_fmt->name, "mov")) {
-                char key[33];
-                ff_data_to_hex(key, pls->key, sizeof(pls->key), 0);
-                av_dict_set(&options, "decryption_key", key, 0);
-            } else if (!c->crypto_ctx.aes_ctx) {
-                c->crypto_ctx.aes_ctx = av_aes_alloc();
-                if (!c->crypto_ctx.aes_ctx) {
-                    avformat_free_context(pls->ctx);
-                    pls->ctx = NULL;
-                    return AVERROR(ENOMEM);
-                }
-            }
-        }
-
-        pls->ctx->pb       = &pls->pb.pub;
-        pls->ctx->io_open  = nested_io_open;
-        pls->ctx->flags   |= s->flags & ~AVFMT_FLAG_CUSTOM_IO;
-
-        if ((ret = ff_copy_whiteblacklists(pls->ctx, s)) < 0)
+        if ((ret = open_playlist_demuxer(s, pls, highest_cur_seq_no)) < 0)
             return ret;
 
-        av_dict_copy(&options, c->seg_format_opts, 0);
-
-        ret = avformat_open_input(&pls->ctx, pls->segments[0]->url, in_fmt, 
&options);
-        av_dict_free(&options);
-        if (ret < 0)
-            return ret;
-
-        if (pls->id3_deferred_extra && pls->ctx->nb_streams == 1) {
-            if (av_match_name(pls->ctx->iformat->name, PACKED_AUDIO_FORMATS))
-                ff_id3v2_parse_apic(pls->ctx, pls->id3_deferred_extra);
-            avformat_queue_attached_pictures(pls->ctx);
-            ff_id3v2_parse_priv(pls->ctx, pls->id3_deferred_extra);
-            ff_id3v2_free_extra_meta(&pls->id3_deferred_extra);
-        }
-
-        if (pls->is_id3_timestamped == -1)
-            av_log(s, AV_LOG_WARNING, "No expected HTTP requests have been 
made\n");
-
-        /*
-         * For ID3 timestamped raw audio streams we need to detect the packet
-         * durations to calculate timestamps in 
fill_timing_for_id3_timestamped_stream(),
-         * but for other streams we can rely on our user calling 
avformat_find_stream_info()
-         * on us if they want to.
-         */
-        if (pls->is_id3_timestamped || (pls->n_renditions > 0 && 
pls->renditions[0]->type == AVMEDIA_TYPE_AUDIO)) {
-            seg = current_segment(pls);
-            if (seg && seg->key_type == KEY_SAMPLE_AES && 
pls->audio_setup_info.setup_data_length > 0 &&
-                pls->ctx->nb_streams == 1)
-                ret = ff_hls_senc_parse_audio_setup_info(pls->ctx->streams[0], 
&pls->audio_setup_info);
-            else
-                ret = avformat_find_stream_info(pls->ctx, NULL);
-
-            if (ret < 0)
-                return ret;
-        }
-
         pls->has_noheader_flag = !!(pls->ctx->ctx_flags & AVFMTCTX_NOHEADER);
 
         /* Create new AVStreams for each stream in this playlist */
-- 
2.54.0


>From 8ec233898aa13c94c22d0bcae92b275e43db0778 Mon Sep 17 00:00:00 2001
From: Daniil Gentili <[email protected]>
Date: Thu, 22 Oct 2026 23:42:15 +0200
Subject: [PATCH 2/2] avformat/hls: add an option to open playlists in parallel

When opening a Master Playlist, the demuxer fetches every Media
Playlist, and then the key and first segment of each of them, strictly
one after another, each over a new connection. With several variants or
renditions this takes seconds before the first packet.

Add parallel_open, the maximum number of playlists to load at once.
Above 1, the Media Playlist parsing and the opening of the per-playlist
demuxers run in up to that many threads, one per playlist. Streams are
still created in playlist order, so the result is the same as with
sequential opening, which stays the default and is unchanged. State
shared between playlists is protected by a mutex, and the persistent
playlist connection is not used while the threads run. If any segment is
SAMPLE-AES, the per-playlist demuxers are opened one after another.

Opening a live stream with 5 variants and 3 audio renditions went from
1.8 s to 0.6 s in testing, and two others from 4.0 s to 1.5 s and from
1.7 s to 0.5 s.

Signed-off-by: Daniil Gentili <[email protected]>
---
 doc/demuxers.texi                      |   9 +
 libavformat/hls.c                      | 298 ++++++++++++++++++++++---
 tests/fate/demux.mak                   |  23 ++
 tests/ref/fate/hls-parallel-open-demux |  92 ++++++++
 4 files changed, 385 insertions(+), 37 deletions(-)
 create mode 100644 tests/ref/fate/hls-parallel-open-demux

diff --git a/doc/demuxers.texi b/doc/demuxers.texi
index 76100551931..9432650edde 100644
--- a/doc/demuxers.texi
+++ b/doc/demuxers.texi
@@ -619,6 +619,15 @@ Set options for the demuxer of media segments using a list 
of key=value pairs se
 @item seg_max_retry
 Maximum number of times to reload a segment on error, useful when segment skip 
on network error is not desired.
 Default value is 0.
+
+@item parallel_open
+Maximum number of Media Playlists to load at the same time when opening a
+Master Playlist, each with its first segment and in its own thread. This
+reduces the time to open streams with several variants or renditions.
+With a value above 1, the @code{io_open}, @code{io_close2} and interrupt
+callbacks of the format context can be called from several threads at
+once, so they must be thread-safe. Default value is 0, which like 1 loads
+the playlists one after another.
 @end table
 
 @section image2
diff --git a/libavformat/hls.c b/libavformat/hls.c
index e36f6d30723..230758892e9 100644
--- a/libavformat/hls.c
+++ b/libavformat/hls.c
@@ -33,11 +33,13 @@
 #include "libavutil/aes.h"
 #include "libavutil/avstring.h"
 #include "libavutil/avassert.h"
+#include "libavutil/bprint.h"
 #include "libavutil/intreadwrite.h"
 #include "libavutil/mathematics.h"
 #include "libavutil/mem.h"
 #include "libavutil/opt.h"
 #include "libavutil/dict.h"
+#include "libavutil/thread.h"
 #include "libavutil/time.h"
 #include "libavutil/tree.h"
 #include "avformat.h"
@@ -281,6 +283,10 @@ typedef struct HLSContext {
     int http_multiple;
     int http_seekable;
     int seg_max_retry;
+    int parallel_open;
+    int in_parallel;
+    int lock_initialized;
+    AVMutex lock;
     AVIOContext *playlist_pb;
     HLSCryptoContext  crypto_ctx;
 } HLSContext;
@@ -804,6 +810,54 @@ static int is_native_http(AVIOContext *pb)
 #endif
 }
 
+/* Protects state shared between playlists opened in parallel */
+static void hls_lock(HLSContext *c)
+{
+    if (c->in_parallel)
+        ff_mutex_lock(&c->lock);
+}
+
+static void hls_unlock(HLSContext *c)
+{
+    if (c->in_parallel)
+        ff_mutex_unlock(&c->lock);
+}
+
+static int has_line(const char *str, const char *line, size_t len)
+{
+    while (*str) {
+        size_t n = strcspn(str, "\n");
+        if (n == len && !memcmp(str, line, len))
+            return 1;
+        str += n + (str[n] == '\n');
+    }
+    return 0;
+}
+
+/* Parallel requests all start from the same cookie jar, so add the cookies
+ * a response set to the current jar instead of replacing it. */
+static char *merge_cookies(const char *jar, const char *cookies)
+{
+    AVBPrint bp;
+    char *ret;
+
+    av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
+    av_bprintf(&bp, "%s", jar);
+    while (*cookies) {
+        size_t n = strcspn(cookies, "\n");
+        if (n && !has_line(jar, cookies, n)) {
+            if (bp.len && bp.str[bp.len - 1] != '\n')
+                av_bprint_chars(&bp, '\n', 1);
+            av_bprint_append_data(&bp, cookies, n);
+            av_bprint_chars(&bp, '\n', 1);
+        }
+        cookies += n + (cookies[n] == '\n');
+    }
+    if (av_bprint_finalize(&bp, &ret) < 0)
+        return NULL;
+    return ret;
+}
+
 static int open_url_keepalive(AVFormatContext *s, AVIOContext **pb,
                               const char *url, AVDictionary **options)
 {
@@ -870,7 +924,9 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, 
const char *url,
     else if (strcmp(proto_name, "file") || !strncmp(url, "file,", 5))
         return AVERROR_INVALIDDATA;
 
+    hls_lock(c);
     av_dict_copy(&tmp, *opts, 0);
+    hls_unlock(c);
     av_dict_copy(&tmp, opts2, 0);
 
     if (is_http && c->http_persistent && is_native_http(*pb)) {
@@ -883,7 +939,9 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, 
const char *url,
                 av_log(s, AV_LOG_WARNING,
                     "keepalive request failed for '%s' with error: '%s' when 
opening url, retrying with new connection\n",
                     url, av_err2str(ret));
+            hls_lock(c);
             av_dict_copy(&tmp, *opts, 0);
+            hls_unlock(c);
             av_dict_copy(&tmp, opts2, 0);
             ret = s->io_open(s, pb, url, AVIO_FLAG_READ, &tmp);
         }
@@ -898,8 +956,19 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, 
const char *url,
         if (!(s->flags & AVFMT_FLAG_CUSTOM_IO))
             av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, 
(uint8_t**)&new_cookies);
 
-        if (new_cookies)
-            av_dict_set(opts, "cookies", new_cookies, AV_DICT_DONT_STRDUP_VAL);
+        if (new_cookies) {
+            const AVDictionaryEntry *jar;
+
+            hls_lock(c);
+            if (c->in_parallel && (jar = av_dict_get(*opts, "cookies", NULL, 
0))) {
+                char *merged = merge_cookies(jar->value, new_cookies);
+                av_free(new_cookies);
+                new_cookies = merged;
+            }
+            if (new_cookies)
+                av_dict_set(opts, "cookies", new_cookies, 
AV_DICT_DONT_STRDUP_VAL);
+            hls_unlock(c);
+        }
     }
 
     av_dict_free(&tmp);
@@ -957,6 +1026,24 @@ static int test_segment(AVFormatContext *s, const 
AVInputFormat *in_fmt, struct
     return 0;
 }
 
+static void update_seekability(HLSContext *c)
+{
+    c->ctx->ctx_flags = c->ctx->ctx_flags & ~(unsigned)AVFMTCTX_UNSEEKABLE;
+    if (!c->n_variants || !c->variants[0]->n_playlists ||
+        !c->variants[0]->playlists[0]->n_segments)
+        c->ctx->ctx_flags |= AVFMTCTX_UNSEEKABLE;
+
+    if (c->n_variants && c->variants[0]->n_playlists &&
+        c->variants[0]->playlists[0]->type == PLS_TYPE_EVENT &&
+        !c->variants[0]->playlists[0]->finished) {
+        struct playlist *p = c->variants[0]->playlists[0];
+        int64_t duration = 0;
+        for (int i = 0; i < p->n_segments; i++)
+            duration += p->segments[i]->duration;
+        c->ctx->duration = duration;
+    }
+}
+
 static int parse_playlist(HLSContext *c, const char *url,
                           struct playlist *pls, AVIOContext *in)
 {
@@ -984,7 +1071,7 @@ static int parse_playlist(HLSContext *c, const char *url,
     int time_offset_flag = 0;
     int finished = 0;
 
-    if (is_http && !in && c->http_persistent && c->playlist_pb) {
+    if (is_http && !in && c->http_persistent && !c->in_parallel && 
c->playlist_pb) {
         in = c->playlist_pb;
         ret = open_url_keepalive(c->ctx, &c->playlist_pb, url, NULL);
         if (ret == AVERROR_EXIT) {
@@ -1000,7 +1087,9 @@ static int parse_playlist(HLSContext *c, const char *url,
 
     if (!in) {
         AVDictionary *opts = NULL;
+        hls_lock(c);
         av_dict_copy(&opts, c->avio_opts, 0);
+        hls_unlock(c);
 
         if (c->http_persistent)
             av_dict_set(&opts, "multiple_requests", "1", 0);
@@ -1010,7 +1099,7 @@ static int parse_playlist(HLSContext *c, const char *url,
         if (ret < 0)
             return ret;
 
-        if (is_http && c->http_persistent && is_native_http(in))
+        if (is_http && c->http_persistent && !c->in_parallel && 
is_native_http(in))
             c->playlist_pb = in;
         else
             close_in = 1;
@@ -1318,20 +1407,8 @@ fail:
     av_free(new_url);
     if (close_in)
         ff_format_io_close(c->ctx, &in);
-    c->ctx->ctx_flags = c->ctx->ctx_flags & ~(unsigned)AVFMTCTX_UNSEEKABLE;
-    if (!c->n_variants || !c->variants[0]->n_playlists ||
-        !c->variants[0]->playlists[0]->n_segments)
-        c->ctx->ctx_flags |= AVFMTCTX_UNSEEKABLE;
-
-    if (c->n_variants && c->variants[0]->n_playlists &&
-        c->variants[0]->playlists[0]->type == PLS_TYPE_EVENT &&
-        !c->variants[0]->playlists[0]->finished) {
-        struct playlist *p = c->variants[0]->playlists[0];
-        int64_t duration = 0;
-        for (int i = 0; i < p->n_segments; i++)
-            duration += p->segments[i]->duration;
-        c->ctx->duration = duration;
-    }
+    if (!c->in_parallel)
+        update_seekability(c);
 
     return ret;
 }
@@ -1901,6 +1978,7 @@ static int read_data_continuous(void *opaque, uint8_t 
*buf, int buf_size)
     int ret;
     int just_opened = 0;
     int segment_retries = 0;
+    int http_multiple;
     struct segment *seg;
 
     if (c->http_persistent && v->input_read_done) {
@@ -1925,7 +2003,10 @@ restart:
         if (ret)
             return ret;
 
-        if (c->http_multiple == 1 && v->input_next_requested) {
+        hls_lock(c);
+        http_multiple = c->http_multiple;
+        hls_unlock(c);
+        if (http_multiple == 1 && v->input_next_requested) {
             FFSWAP(AVIOContext *, v->input, v->input_next);
             FFSWAP(int64_t, v->input_end, v->input_next_end);
             v->cur_seg_offset = 0;
@@ -1958,6 +2039,7 @@ restart:
             v->first_read_seq_no = v->cur_seq_no;
     }
 
+    hls_lock(c);
     if (c->http_multiple == -1) {
         uint8_t *http_version_opt = NULL;
         int r = av_opt_get(v->input, "http_version", AV_OPT_SEARCH_CHILDREN, 
&http_version_opt);
@@ -1966,9 +2048,11 @@ restart:
             av_freep(&http_version_opt);
         }
     }
+    http_multiple = c->http_multiple;
+    hls_unlock(c);
 
     seg = next_segment(v);
-    if (c->http_multiple == 1 && !v->input_next_requested &&
+    if (http_multiple == 1 && !v->input_next_requested &&
         seg && seg->key_type == KEY_NONE && av_strstart(seg->url, "http", 
NULL) &&
         !segment_continues(current_segment(v), seg, v->input_end)) {
         ret = open_input(c, v, seg, &v->input_next, &v->input_next_end);
@@ -2006,7 +2090,9 @@ restart:
         /* The next segment follows within the requested range and is read
          * on from the same input. */
         v->cur_seq_no++;
+        hls_lock(c);
         c->cur_seq_no = v->cur_seq_no;
+        hls_unlock(c);
         v->cur_seg_offset = 0;
         just_opened = 1;
         goto restart;
@@ -2023,7 +2109,9 @@ restart:
     }
     v->cur_seq_no++;
 
+    hls_lock(c);
     c->cur_seq_no = v->cur_seq_no;
+    hls_unlock(c);
 
     goto restart;
 }
@@ -2132,7 +2220,9 @@ restart:
     }
     ff_format_io_close(v->parent, &v->input);
     v->cur_seq_no++;
+    hls_lock(c);
     c->cur_seq_no = v->cur_seq_no;
+    hls_unlock(c);
 
     avformat_close_input(&v->ctx);
 
@@ -2465,10 +2555,86 @@ static int hls_close(AVFormatContext *s)
 
     av_dict_free(&c->avio_opts);
     ff_format_io_close(c->ctx, &c->playlist_pb);
+    if (c->lock_initialized)
+        ff_mutex_destroy(&c->lock);
 
     return 0;
 }
 
+typedef int (*playlist_job_func)(AVFormatContext *s, struct playlist *pls, 
int64_t arg);
+
+#if HAVE_THREADS
+struct playlist_job {
+    AVFormatContext *s;
+    struct playlist *pls;
+    playlist_job_func func;
+    int64_t arg;
+    pthread_t thread;
+    int started;
+    int ret;
+};
+
+static void *playlist_job_thread(void *opaque)
+{
+    struct playlist_job *job = opaque;
+    job->ret = job->func(job->s, job->pls, job->arg);
+    return NULL;
+}
+#endif
+
+/*
+ * Run func on every playlist and store the results in rets. When
+ * c->in_parallel is set, up to c->parallel_open playlists are run at once,
+ * each in its own thread.
+ */
+static int run_playlist_jobs(AVFormatContext *s, playlist_job_func func, 
int64_t arg, int *rets)
+{
+    HLSContext *c = s->priv_data;
+
+#if HAVE_THREADS
+    if (c->in_parallel && c->n_playlists > 1) {
+        int max_jobs = FFMIN(c->parallel_open, c->n_playlists);
+        struct playlist_job *jobs = av_calloc(max_jobs, sizeof(*jobs));
+        if (!jobs)
+            return AVERROR(ENOMEM);
+
+        for (int start = 0; start < c->n_playlists; start += max_jobs) {
+            int n = FFMIN(max_jobs, c->n_playlists - start);
+
+            for (int i = 0; i < n; i++) {
+                struct playlist_job *job = &jobs[i];
+                job->s    = s;
+                job->pls  = c->playlists[start + i];
+                job->func = func;
+                job->arg  = arg;
+                job->started = !pthread_create(&job->thread, NULL, 
playlist_job_thread, job);
+                if (!job->started)
+                    job->ret = func(s, job->pls, arg);
+            }
+            for (int i = 0; i < n; i++) {
+                if (jobs[i].started)
+                    pthread_join(jobs[i].thread, NULL);
+                rets[start + i] = jobs[i].ret;
+            }
+        }
+        av_free(jobs);
+        return 0;
+    }
+#endif
+
+    for (int i = 0; i < c->n_playlists; i++)
+        rets[i] = func(s, c->playlists[i], arg);
+    return 0;
+}
+
+static int parse_media_playlist(AVFormatContext *s, struct playlist *pls, 
int64_t unused)
+{
+    HLSContext *c = s->priv_data;
+
+    pls->m3u8_hold_counters = 0;
+    return parse_playlist(c, pls->url, pls, NULL);
+}
+
 /* Open the demuxer of one playlist on its first segment */
 static int open_playlist_demuxer(AVFormatContext *s, struct playlist *pls,
                                  int64_t highest_cur_seq_no)
@@ -2482,6 +2648,9 @@ static int open_playlist_demuxer(AVFormatContext *s, 
struct playlist *pls,
     int buf_size;
     int ret = 0;
 
+    if (pls->n_segments == 0)
+        return 0;
+
     /*
      * If this is a live stream and this playlist looks like it is one segment
      * behind, try to sync it up so that every substream starts at the same
@@ -2588,8 +2757,11 @@ static int open_playlist_demuxer(AVFormatContext *s, 
struct playlist *pls,
             char key[33];
             ff_data_to_hex(key, pls->key, sizeof(pls->key), 0);
             av_dict_set(&options, "decryption_key", key, 0);
-        } else if (!c->crypto_ctx.aes_ctx) {
-            c->crypto_ctx.aes_ctx = av_aes_alloc();
+        } else {
+            hls_lock(c);
+            if (!c->crypto_ctx.aes_ctx)
+                c->crypto_ctx.aes_ctx = av_aes_alloc();
+            hls_unlock(c);
             if (!c->crypto_ctx.aes_ctx) {
                 avformat_free_context(pls->ctx);
                 pls->ctx = NULL;
@@ -2649,6 +2821,12 @@ static int hls_read_header(AVFormatContext *s)
     HLSContext *c = s->priv_data;
     int ret = 0, i;
     int64_t highest_cur_seq_no = 0;
+    int *rets = NULL;
+    int has_sample_aes = 0, parallel;
+
+    if ((ret = ff_mutex_init(&c->lock, NULL)))
+        return AVERROR(ret);
+    c->lock_initialized = 1;
 
     c->ctx                = s;
     c->interrupt_callback = &s->interrupt_callback;
@@ -2690,20 +2868,33 @@ static int hls_read_header(AVFormatContext *s)
         av_log(s, AV_LOG_WARNING, "Empty playlist\n");
         return AVERROR_EOF;
     }
+    rets = av_calloc(c->n_playlists, sizeof(*rets));
+    if (!rets)
+        return AVERROR(ENOMEM);
+
     /* If the playlist only contained playlists (Master Playlist),
      * parse each individual playlist. */
     if (c->n_playlists > 1 || c->playlists[0]->n_segments == 0) {
+        c->in_parallel = HAVE_THREADS && c->parallel_open > 1;
+        ret = run_playlist_jobs(s, parse_media_playlist, 0, rets);
+        if (c->in_parallel) {
+            c->in_parallel = 0;
+            update_seekability(c);
+        }
+        if (ret < 0)
+            goto fail;
+
         for (i = 0; i < c->n_playlists; i++) {
             struct playlist *pls = c->playlists[i];
-            pls->m3u8_hold_counters = 0;
-            if ((ret = parse_playlist(c, pls->url, pls, NULL)) < 0) {
+            if ((ret = rets[i]) < 0) {
                 av_log(s, AV_LOG_WARNING, "parse_playlist error %s [%s]\n", 
av_err2str(ret), pls->url);
                 pls->broken = 1;
                 if (c->n_playlists > 1)
                     continue;
-                return ret;
+                goto fail;
             }
         }
+        ret = 0;
     }
 
     for (i = 0; i < c->n_variants; i++) {
@@ -2729,17 +2920,17 @@ static int hls_read_header(AVFormatContext *s)
 
         if (var->audio_group[0] &&
             (ret = add_renditions_to_variant(c, var, AVMEDIA_TYPE_AUDIO, 
var->audio_group)) < 0)
-            return ret;
+            goto fail;
         if (var->video_group[0] &&
             (ret = add_renditions_to_variant(c, var, AVMEDIA_TYPE_VIDEO, 
var->video_group)) < 0)
-            return ret;
+            goto fail;
         if (var->subtitles_group[0] &&
             (ret = add_renditions_to_variant(c, var, AVMEDIA_TYPE_SUBTITLE, 
var->subtitles_group)) < 0)
-            return ret;
+            goto fail;
     }
     if ((ret = add_renditions_to_playlists(c, AVMEDIA_TYPE_AUDIO)) < 0 ||
         (ret = add_renditions_to_playlists(c, AVMEDIA_TYPE_VIDEO)) < 0)
-        return ret;
+        goto fail;
 
     /* Create a program for each variant */
     for (i = 0; i < c->n_variants; i++) {
@@ -2747,8 +2938,10 @@ static int hls_read_header(AVFormatContext *s)
         AVProgram *program;
 
         program = av_new_program(s, i);
-        if (!program)
-            return AVERROR(ENOMEM);
+        if (!program) {
+            ret = AVERROR(ENOMEM);
+            goto fail;
+        }
         av_dict_set_int(&program->metadata, "variant_bitrate", v->bandwidth, 
0);
     }
 
@@ -2769,8 +2962,10 @@ static int hls_read_header(AVFormatContext *s)
     for (i = 0; i < c->n_playlists; i++) {
         struct playlist *pls = c->playlists[i];
 
-        if (!(pls->ctx = avformat_alloc_context()))
-            return AVERROR(ENOMEM);
+        if (!(pls->ctx = avformat_alloc_context())) {
+            ret = AVERROR(ENOMEM);
+            goto fail;
+        }
 
         if (pls->n_segments == 0)
             continue;
@@ -2779,15 +2974,39 @@ static int hls_read_header(AVFormatContext *s)
         pls->needed = 1;
         pls->parent = s;
 
-        if ((ret = open_playlist_demuxer(s, pls, highest_cur_seq_no)) < 0)
-            return ret;
+        for (int n = 0; n < pls->n_segments; n++)
+            if (pls->segments[n]->key_type == KEY_SAMPLE_AES)
+                has_sample_aes = 1;
+    }
+
+    /* Opening SAMPLE-AES playlists sets up decryption state shared by all
+     * playlists (c->crypto_ctx), so they are opened one after another. */
+    parallel = HAVE_THREADS && c->parallel_open > 1 && !has_sample_aes;
+    if (parallel) {
+        c->in_parallel = 1;
+        ret = run_playlist_jobs(s, open_playlist_demuxer, highest_cur_seq_no, 
rets);
+        c->in_parallel = 0;
+        update_seekability(c);
+        if (ret < 0)
+            goto fail;
+    }
+
+    for (i = 0; i < c->n_playlists; i++) {
+        struct playlist *pls = c->playlists[i];
+
+        if (pls->n_segments == 0)
+            continue;
+
+        ret = parallel ? rets[i] : open_playlist_demuxer(s, pls, 
highest_cur_seq_no);
+        if (ret < 0)
+            goto fail;
 
         pls->has_noheader_flag = !!(pls->ctx->ctx_flags & AVFMTCTX_NOHEADER);
 
         /* Create new AVStreams for each stream in this playlist */
         ret = update_streams_from_subdemuxer(s, pls);
         if (ret < 0)
-            return ret;
+            goto fail;
 
         /*
          * Copy any metadata from playlist to main streams, but do not set
@@ -2809,8 +3028,11 @@ static int hls_read_header(AVFormatContext *s)
     }
 
     update_noheader_flag(s);
+    ret = 0;
 
-    return 0;
+fail:
+    av_free(rets);
+    return ret;
 }
 
 static int recheck_discard_flags(AVFormatContext *s, int first)
@@ -3365,6 +3587,8 @@ static const AVOption hls_options[] = {
         OFFSET(seg_format_opts), AV_OPT_TYPE_DICT, {.str = NULL}, 0, 0, FLAGS},
     {"seg_max_retry", "Maximum number of times to reload a segment on error.",
      OFFSET(seg_max_retry), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS},
+    {"parallel_open", "Maximum number of playlists to load in parallel when 
opening (0 or 1 loads them one after another)",
+        OFFSET(parallel_open), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS},
     {NULL}
 };
 
diff --git a/tests/fate/demux.mak b/tests/fate/demux.mak
index d4ac666f810..5d2427e585e 100644
--- a/tests/fate/demux.mak
+++ b/tests/fate/demux.mak
@@ -233,6 +233,29 @@ fate-hls-shared-renditions-demux: 
tests/data/hls-shared-renditions.m3u8
 fate-hls-shared-renditions-demux: CLEANFILES = 
tests/data/hls-shared-renditions*.m3u8 tests/data/hls-shared-renditions-*.ts 
tests/data/hls-shared-renditions-*.vtt
 fate-hls-shared-renditions-demux: CMD = ffprobe_demux 
$(TARGET_PATH)/tests/data/hls-shared-renditions.m3u8 -show_programs
 
+tests/data/hls-parallel.m3u8: TAG = GEN
+tests/data/hls-parallel.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data
+       $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< -nostdin \
+        -f lavfi -i "aevalsrc=0:s=16000:d=2" -c:a mp2fixed -flags +bitexact 
-muxdelay 0 -muxpreload 0 \
+        -f hls -hls_time 2 -hls_list_size 0 \
+        -hls_segment_filename $(TARGET_PATH)/tests/data/hls-parallel-a%d.ts \
+        $(TARGET_PATH)/tests/data/hls-parallel-a.m3u8 2>/dev/null
+       $(Q)$(TARGET_EXEC) $(TARGET_PATH)/$< -nostdin \
+        -f lavfi -i "aevalsrc=0:s=32000:d=2" -c:a mp2fixed -flags +bitexact 
-muxdelay 0 -muxpreload 0 \
+        -f hls -hls_time 2 -hls_list_size 0 \
+        -hls_segment_filename $(TARGET_PATH)/tests/data/hls-parallel-b%d.ts \
+        $(TARGET_PATH)/tests/data/hls-parallel-b.m3u8 2>/dev/null
+       $(Q)printf 
'#EXTM3U\n#EXT-X-TARGETDURATION:2\n#EXTINF:2,\nhls-parallel-s0.vtt\n#EXT-X-ENDLIST\n'
 > tests/data/hls-parallel-s.m3u8
+       $(Q)printf 'WEBVTT\n\n00:00.500 --> 00:01.500\nfirst\n' > 
tests/data/hls-parallel-s0.vtt
+       $(Q)printf 
'#EXTM3U\n#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="a",NAME="German",LANGUAGE="de",URI="hls-parallel-b.m3u8"\n#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="s",NAME="English",LANGUAGE="en",URI="hls-parallel-s.m3u8"\n#EXT-X-STREAM-INF:BANDWIDTH=64000,AUDIO="a",SUBTITLES="s"\nhls-parallel-a.m3u8\n'
 > $@
+
+FATE_HLS_PARALLEL-$(call FILTERDEMDECENCMUX, AEVALSRC ARESAMPLE, HLS MPEGTS 
WEBVTT, MP3FLOAT PCM_F64LE, MP2FIXED, HLS MPEGTS, LAVFI_INDEV MPEGAUDIO_PARSER) 
+= fate-hls-parallel-open-demux fate-hls-parallel-open-sequential-demux
+FATE_FFMPEG_FFPROBE += $(FATE_HLS_PARALLEL-yes)
+fate-hls-parallel-open-demux fate-hls-parallel-open-sequential-demux: 
tests/data/hls-parallel.m3u8
+fate-hls-parallel-open-demux: CMD = ffprobe_demux 
$(TARGET_PATH)/tests/data/hls-parallel.m3u8 -show_programs -parallel_open 4
+fate-hls-parallel-open-sequential-demux: CMD = ffprobe_demux 
$(TARGET_PATH)/tests/data/hls-parallel.m3u8 -show_programs
+fate-hls-parallel-open-sequential-demux: REF = 
$(SRC_PATH)/tests/ref/fate/hls-parallel-open-demux
+
 FATE_SAMPLES_DEMUX-$(call PARSERDEM, JPEGXS, IMAGE_JPEGXS_PIPE, 
CONCAT_PROTOCOL) += fate-jxs-concat-demux
 fate-jxs-concat-demux: CMD = framecrc "-i 
concat:$(TARGET_SAMPLES)/jxs/lena.jxs|$(TARGET_SAMPLES)/jxs/lena.jxs -c:v copy"
 
diff --git a/tests/ref/fate/hls-parallel-open-demux 
b/tests/ref/fate/hls-parallel-open-demux
new file mode 100644
index 00000000000..522b52fc50a
--- /dev/null
+++ b/tests/ref/fate/hls-parallel-open-demux
@@ -0,0 +1,92 @@
+packet|codec_type=audio|stream_index=0|pts=0|pts_time=0.000000|dts=0|dts_time=0.000000|duration=3240|duration_time=0.036000|size=1728|pos=564|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=0|pts_time=0.000000|dts=0|dts_time=0.000000|duration=N/A|duration_time=N/A|size=1440|pos=564|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=3240|pts_time=0.036000|dts=3240|dts_time=0.036000|duration=3240|duration_time=0.036000|size=1728|pos=2444|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=6480|pts_time=0.072000|dts=6480|dts_time=0.072000|duration=3240|duration_time=0.036000|size=1728|pos=4324|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=6480|pts_time=0.072000|dts=6480|dts_time=0.072000|duration=6480|duration_time=0.072000|size=1440|pos=2068|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=9720|pts_time=0.108000|dts=9720|dts_time=0.108000|duration=3240|duration_time=0.036000|size=1728|pos=6204|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=12960|pts_time=0.144000|dts=12960|dts_time=0.144000|duration=3240|duration_time=0.036000|size=1728|pos=8084|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=12960|pts_time=0.144000|dts=12960|dts_time=0.144000|duration=6480|duration_time=0.072000|size=1440|pos=3572|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=16200|pts_time=0.180000|dts=16200|dts_time=0.180000|duration=3240|duration_time=0.036000|size=1728|pos=9964|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=19440|pts_time=0.216000|dts=19440|dts_time=0.216000|duration=3240|duration_time=0.036000|size=1728|pos=11844|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=19440|pts_time=0.216000|dts=19440|dts_time=0.216000|duration=6480|duration_time=0.072000|size=1440|pos=5076|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=22680|pts_time=0.252000|dts=22680|dts_time=0.252000|duration=3240|duration_time=0.036000|size=1728|pos=13724|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=25920|pts_time=0.288000|dts=25920|dts_time=0.288000|duration=3240|duration_time=0.036000|size=1728|pos=15604|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=25920|pts_time=0.288000|dts=25920|dts_time=0.288000|duration=6480|duration_time=0.072000|size=1440|pos=6580|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=29160|pts_time=0.324000|dts=29160|dts_time=0.324000|duration=3240|duration_time=0.036000|size=1728|pos=17484|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=32400|pts_time=0.360000|dts=32400|dts_time=0.360000|duration=3240|duration_time=0.036000|size=1728|pos=19364|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=32400|pts_time=0.360000|dts=32400|dts_time=0.360000|duration=6480|duration_time=0.072000|size=1440|pos=8084|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=35640|pts_time=0.396000|dts=35640|dts_time=0.396000|duration=3240|duration_time=0.036000|size=1728|pos=21244|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=38880|pts_time=0.432000|dts=38880|dts_time=0.432000|duration=3240|duration_time=0.036000|size=1728|pos=23124|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=38880|pts_time=0.432000|dts=38880|dts_time=0.432000|duration=6480|duration_time=0.072000|size=1440|pos=9588|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=42120|pts_time=0.468000|dts=42120|dts_time=0.468000|duration=3240|duration_time=0.036000|size=1728|pos=25004|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=45360|pts_time=0.504000|dts=45360|dts_time=0.504000|duration=3240|duration_time=0.036000|size=1728|pos=26884|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=45360|pts_time=0.504000|dts=45360|dts_time=0.504000|duration=6480|duration_time=0.072000|size=1440|pos=11092|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=48600|pts_time=0.540000|dts=48600|dts_time=0.540000|duration=3240|duration_time=0.036000|size=1728|pos=28764|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=51840|pts_time=0.576000|dts=51840|dts_time=0.576000|duration=3240|duration_time=0.036000|size=1728|pos=30644|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=51840|pts_time=0.576000|dts=51840|dts_time=0.576000|duration=6480|duration_time=0.072000|size=1440|pos=12596|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=55080|pts_time=0.612000|dts=55080|dts_time=0.612000|duration=3240|duration_time=0.036000|size=1728|pos=32524|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=58320|pts_time=0.648000|dts=58320|dts_time=0.648000|duration=3240|duration_time=0.036000|size=1728|pos=34404|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=58320|pts_time=0.648000|dts=58320|dts_time=0.648000|duration=6480|duration_time=0.072000|size=1440|pos=14100|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=61560|pts_time=0.684000|dts=61560|dts_time=0.684000|duration=3240|duration_time=0.036000|size=1728|pos=36284|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=64800|pts_time=0.720000|dts=64800|dts_time=0.720000|duration=3240|duration_time=0.036000|size=1728|pos=38164|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=64800|pts_time=0.720000|dts=64800|dts_time=0.720000|duration=6480|duration_time=0.072000|size=1440|pos=15604|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=68040|pts_time=0.756000|dts=68040|dts_time=0.756000|duration=3240|duration_time=0.036000|size=1728|pos=40044|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=71280|pts_time=0.792000|dts=71280|dts_time=0.792000|duration=3240|duration_time=0.036000|size=1728|pos=41924|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=71280|pts_time=0.792000|dts=71280|dts_time=0.792000|duration=6480|duration_time=0.072000|size=1440|pos=17108|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=74520|pts_time=0.828000|dts=74520|dts_time=0.828000|duration=3240|duration_time=0.036000|size=1728|pos=43804|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=77760|pts_time=0.864000|dts=77760|dts_time=0.864000|duration=3240|duration_time=0.036000|size=1728|pos=45684|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=77760|pts_time=0.864000|dts=77760|dts_time=0.864000|duration=6480|duration_time=0.072000|size=1440|pos=18612|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=81000|pts_time=0.900000|dts=81000|dts_time=0.900000|duration=3240|duration_time=0.036000|size=1728|pos=47564|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=84240|pts_time=0.936000|dts=84240|dts_time=0.936000|duration=3240|duration_time=0.036000|size=1728|pos=49444|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=84240|pts_time=0.936000|dts=84240|dts_time=0.936000|duration=6480|duration_time=0.072000|size=1440|pos=20116|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=87480|pts_time=0.972000|dts=87480|dts_time=0.972000|duration=3240|duration_time=0.036000|size=1728|pos=51324|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=90720|pts_time=1.008000|dts=90720|dts_time=1.008000|duration=3240|duration_time=0.036000|size=1728|pos=53204|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=90720|pts_time=1.008000|dts=90720|dts_time=1.008000|duration=6480|duration_time=0.072000|size=1440|pos=21620|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=93960|pts_time=1.044000|dts=93960|dts_time=1.044000|duration=3240|duration_time=0.036000|size=1728|pos=55084|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=97200|pts_time=1.080000|dts=97200|dts_time=1.080000|duration=3240|duration_time=0.036000|size=1728|pos=56964|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=97200|pts_time=1.080000|dts=97200|dts_time=1.080000|duration=6480|duration_time=0.072000|size=1440|pos=23124|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=100440|pts_time=1.116000|dts=100440|dts_time=1.116000|duration=3240|duration_time=0.036000|size=1728|pos=58844|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=103680|pts_time=1.152000|dts=103680|dts_time=1.152000|duration=3240|duration_time=0.036000|size=1728|pos=60724|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=103680|pts_time=1.152000|dts=103680|dts_time=1.152000|duration=6480|duration_time=0.072000|size=1440|pos=24628|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=106920|pts_time=1.188000|dts=106920|dts_time=1.188000|duration=3240|duration_time=0.036000|size=1728|pos=62604|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=110160|pts_time=1.224000|dts=110160|dts_time=1.224000|duration=3240|duration_time=0.036000|size=1728|pos=64484|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=110160|pts_time=1.224000|dts=110160|dts_time=1.224000|duration=6480|duration_time=0.072000|size=1440|pos=26132|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=113400|pts_time=1.260000|dts=113400|dts_time=1.260000|duration=3240|duration_time=0.036000|size=1728|pos=66364|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=116640|pts_time=1.296000|dts=116640|dts_time=1.296000|duration=3240|duration_time=0.036000|size=1728|pos=68244|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=116640|pts_time=1.296000|dts=116640|dts_time=1.296000|duration=6480|duration_time=0.072000|size=1440|pos=27636|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=119880|pts_time=1.332000|dts=119880|dts_time=1.332000|duration=3240|duration_time=0.036000|size=1728|pos=70124|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=123120|pts_time=1.368000|dts=123120|dts_time=1.368000|duration=3240|duration_time=0.036000|size=1728|pos=72004|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=123120|pts_time=1.368000|dts=123120|dts_time=1.368000|duration=6480|duration_time=0.072000|size=1440|pos=29140|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=126360|pts_time=1.404000|dts=126360|dts_time=1.404000|duration=3240|duration_time=0.036000|size=1728|pos=73884|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=129600|pts_time=1.440000|dts=129600|dts_time=1.440000|duration=3240|duration_time=0.036000|size=1728|pos=75764|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=129600|pts_time=1.440000|dts=129600|dts_time=1.440000|duration=6480|duration_time=0.072000|size=1440|pos=30644|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=132840|pts_time=1.476000|dts=132840|dts_time=1.476000|duration=3240|duration_time=0.036000|size=1728|pos=77644|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=136080|pts_time=1.512000|dts=136080|dts_time=1.512000|duration=3240|duration_time=0.036000|size=1728|pos=79524|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=136080|pts_time=1.512000|dts=136080|dts_time=1.512000|duration=6480|duration_time=0.072000|size=1440|pos=32148|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=139320|pts_time=1.548000|dts=139320|dts_time=1.548000|duration=3240|duration_time=0.036000|size=1728|pos=81404|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=142560|pts_time=1.584000|dts=142560|dts_time=1.584000|duration=3240|duration_time=0.036000|size=1728|pos=83284|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=142560|pts_time=1.584000|dts=142560|dts_time=1.584000|duration=6480|duration_time=0.072000|size=1440|pos=33652|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=145800|pts_time=1.620000|dts=145800|dts_time=1.620000|duration=3240|duration_time=0.036000|size=1728|pos=85164|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=149040|pts_time=1.656000|dts=149040|dts_time=1.656000|duration=3240|duration_time=0.036000|size=1728|pos=87044|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=149040|pts_time=1.656000|dts=149040|dts_time=1.656000|duration=6480|duration_time=0.072000|size=1440|pos=35156|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=152280|pts_time=1.692000|dts=152280|dts_time=1.692000|duration=3240|duration_time=0.036000|size=1728|pos=88924|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=155520|pts_time=1.728000|dts=155520|dts_time=1.728000|duration=3240|duration_time=0.036000|size=1728|pos=90804|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=155520|pts_time=1.728000|dts=155520|dts_time=1.728000|duration=6480|duration_time=0.072000|size=1440|pos=36660|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=158760|pts_time=1.764000|dts=158760|dts_time=1.764000|duration=3240|duration_time=0.036000|size=1728|pos=92684|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=162000|pts_time=1.800000|dts=162000|dts_time=1.800000|duration=3240|duration_time=0.036000|size=1728|pos=94564|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=162000|pts_time=1.800000|dts=162000|dts_time=1.800000|duration=6480|duration_time=0.072000|size=1440|pos=38164|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=165240|pts_time=1.836000|dts=165240|dts_time=1.836000|duration=3240|duration_time=0.036000|size=1728|pos=96444|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=168480|pts_time=1.872000|dts=168480|dts_time=1.872000|duration=3240|duration_time=0.036000|size=1728|pos=98324|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=168480|pts_time=1.872000|dts=168480|dts_time=1.872000|duration=6480|duration_time=0.072000|size=1440|pos=39668|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=171720|pts_time=1.908000|dts=171720|dts_time=1.908000|duration=3240|duration_time=0.036000|size=1728|pos=100204|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=174960|pts_time=1.944000|dts=174960|dts_time=1.944000|duration=3240|duration_time=0.036000|size=1728|pos=102084|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=2|pts=174960|pts_time=1.944000|dts=174960|dts_time=1.944000|duration=6480|duration_time=0.072000|size=1440|pos=41172|flags=K__|data_hash=CRC32:cb00dd5b|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+packet|codec_type=audio|stream_index=0|pts=178200|pts_time=1.980000|dts=178200|dts_time=1.980000|duration=3240|duration_time=0.036000|size=1728|pos=103964|flags=K__|data_hash=CRC32:9e22ed1d|side_datum/mpegts_stream_id:side_data_type=MPEGTS
 Stream ID|side_datum/mpegts_stream_id:id=192
+program|program_id=0|program_num=0|nb_streams=3|pmt_pid=0|pcr_pid=0|tag:variant_bitrate=64000
+stream|index=0|codec_name=mp2|profile=unknown|level=-99|codec_type=audio|codec_tag_string=[3][0][0][0]|codec_tag=0x0003|mime_codec_string=mp4a.40.33|sample_fmt=fltp|sample_rate=32000|channels=1|channel_layout=mono|bits_per_sample=0|initial_padding=0|id=0x0|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/90000|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=384000|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=56|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:variant_bitrate=64000|tag:language=de|tag
 :comment=German
+stream|index=1|codec_name=webvtt|profile=unknown|level=-99|codec_type=subtitle|codec_tag_string=[0][0][0][0]|codec_tag=0x0000|width=N/A|height=N/A|id=0x1|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/1000|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=N/A|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:variant_bitrate=64000|tag:language=en|tag:comment=English
+stream|index=2|codec_name=mp2|profile=unknown|level=-99|codec_type=audio|codec_tag_string=[4][0][0][0]|codec_tag=0x0004|mime_codec_string=mp4a.40.33|sample_fmt=unknown|sample_rate=16000|channels=1|channel_layout=mono|bits_per_sample=0|initial_padding=0|id=0x2|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/90000|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=160000|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=28|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:variant_bitrate=64000
+stream|index=0|codec_name=mp2|profile=unknown|level=-99|codec_type=audio|codec_tag_string=[3][0][0][0]|codec_tag=0x0003|mime_codec_string=mp4a.40.33|sample_fmt=fltp|sample_rate=32000|channels=1|channel_layout=mono|bits_per_sample=0|initial_padding=0|id=0x0|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/90000|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=384000|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=56|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:variant_bitrate=64000|tag:language=de|tag
 :comment=German
+stream|index=1|codec_name=webvtt|profile=unknown|level=-99|codec_type=subtitle|codec_tag_string=[0][0][0][0]|codec_tag=0x0000|width=N/A|height=N/A|id=0x1|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/1000|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=N/A|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:variant_bitrate=64000|tag:language=en|tag:comment=English
+stream|index=2|codec_name=mp2|profile=unknown|level=-99|codec_type=audio|codec_tag_string=[4][0][0][0]|codec_tag=0x0004|mime_codec_string=mp4a.40.33|sample_fmt=unknown|sample_rate=16000|channels=1|channel_layout=mono|bits_per_sample=0|initial_padding=0|id=0x2|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/90000|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=160000|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=28|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:variant_bitrate=64000
+format|filename=hls-parallel.m3u8|nb_streams=3|nb_programs=1|nb_stream_groups=0|format_name=hls|start_time=0.000000|duration=2.016000|size=273|bit_rate=1083|probe_score=100
-- 
2.54.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to