avformat/hlsenc: move init operations from write_header to init
authorSteven Liu <lq@chinaffmpeg.org>
Mon, 11 Dec 2017 03:03:25 +0000 (11:03 +0800)
committerSteven Liu <lq@chinaffmpeg.org>
Mon, 11 Dec 2017 03:03:25 +0000 (11:03 +0800)
Reviewed-by: Vishwanath Dixit <vdixit@akamai.com>
Signed-off-by: Steven Liu <lq@chinaffmpeg.org>
libavformat/hlsenc.c

index 7dc8f42..dd09739 100644 (file)
@@ -1640,329 +1640,12 @@ static int hls_write_header(AVFormatContext *s)
 {
     HLSContext *hls = s->priv_data;
     int ret, i, j;
-    char *p = NULL;
-    const char *pattern = "%d.ts";
-    const char *pattern_localtime_fmt = get_default_pattern_localtime_fmt(s);
-    const char *vtt_pattern = "%d.vtt";
     AVDictionary *options = NULL;
-    int basename_size = 0;
-    int vtt_basename_size = 0, m3u8_name_size = 0;
     VariantStream *vs = NULL;
-    int fmp4_init_filename_len = strlen(hls->fmp4_init_filename) + 1;
-
-    ret = update_variant_stream_info(s);
-    if (ret < 0) {
-        av_log(s, AV_LOG_ERROR, "Variant stream info update failed with status %x\n",
-                ret);
-        goto fail;
-    }
-
-    //TODO: Updates needed to encryption functionality with periodic re-key when more than one variant streams are present
-    if (hls->nb_varstreams > 1 && hls->flags & HLS_PERIODIC_REKEY) {
-        ret = AVERROR(EINVAL);
-        av_log(s, AV_LOG_ERROR, "Periodic re-key not supported when more than one variant streams are present\n");
-        goto fail;
-    }
-
-    if (hls->master_pl_name) {
-        ret = update_master_pl_info(s);
-        if (ret < 0) {
-            av_log(s, AV_LOG_ERROR, "Master stream info update failed with status %x\n",
-                    ret);
-            goto fail;
-        }
-    }
-
-    if (hls->segment_type == SEGMENT_TYPE_FMP4) {
-        pattern = "%d.m4s";
-    }
-    if ((hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH) ||
-        (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_FORMATTED_DATETIME)) {
-        time_t t = time(NULL); // we will need it in either case
-        if (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH) {
-            hls->start_sequence = (int64_t)t;
-        } else if (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_FORMATTED_DATETIME) {
-            char b[15];
-            struct tm *p, tmbuf;
-            if (!(p = localtime_r(&t, &tmbuf)))
-                return AVERROR(ENOMEM);
-            if (!strftime(b, sizeof(b), "%Y%m%d%H%M%S", p))
-                return AVERROR(ENOMEM);
-            hls->start_sequence = strtoll(b, NULL, 10);
-        }
-        av_log(hls, AV_LOG_DEBUG, "start_number evaluated to %"PRId64"\n", hls->start_sequence);
-    }
 
     for (i = 0; i < hls->nb_varstreams; i++) {
         vs = &hls->var_streams[i];
 
-    vs->sequence       = hls->start_sequence;
-    hls->recording_time = (hls->init_time ? hls->init_time : hls->time) * AV_TIME_BASE;
-    vs->start_pts      = AV_NOPTS_VALUE;
-    vs->end_pts      = AV_NOPTS_VALUE;
-    vs->current_segment_final_filename_fmt[0] = '\0';
-
-    if (hls->flags & HLS_SPLIT_BY_TIME && hls->flags & HLS_INDEPENDENT_SEGMENTS) {
-        // Independent segments cannot be guaranteed when splitting by time
-        hls->flags &= ~HLS_INDEPENDENT_SEGMENTS;
-        av_log(s, AV_LOG_WARNING,
-               "'split_by_time' and 'independent_segments' cannot be enabled together. "
-               "Disabling 'independent_segments' flag\n");
-    }
-
-    if (hls->flags & HLS_PROGRAM_DATE_TIME) {
-        time_t now0;
-        time(&now0);
-        vs->initial_prog_date_time = now0;
-    }
-
-    if (hls->format_options_str) {
-        ret = av_dict_parse_string(&hls->format_options, hls->format_options_str, "=", ":", 0);
-        if (ret < 0) {
-            av_log(s, AV_LOG_ERROR, "Could not parse format options list '%s'\n", hls->format_options_str);
-            goto fail;
-        }
-    }
-
-    for (j = 0; j < vs->nb_streams; j++) {
-        vs->has_video +=
-            vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO;
-        vs->has_subtitle +=
-            vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE;
-    }
-
-    if (vs->has_video > 1)
-        av_log(s, AV_LOG_WARNING,
-               "More than a single video stream present, "
-               "expect issues decoding it.\n");
-
-    if (hls->segment_type == SEGMENT_TYPE_FMP4) {
-        vs->oformat = av_guess_format("mp4", NULL, NULL);
-    } else {
-        vs->oformat = av_guess_format("mpegts", NULL, NULL);
-    }
-
-    if (!vs->oformat) {
-        ret = AVERROR_MUXER_NOT_FOUND;
-        goto fail;
-    }
-
-    if(vs->has_subtitle) {
-        vs->vtt_oformat = av_guess_format("webvtt", NULL, NULL);
-        if (!vs->oformat) {
-            ret = AVERROR_MUXER_NOT_FOUND;
-            goto fail;
-        }
-    }
-
-    if (hls->segment_filename) {
-        basename_size = strlen(hls->segment_filename) + 1;
-        if (hls->nb_varstreams > 1) {
-            basename_size += strlen(POSTFIX_PATTERN);
-        }
-        vs->basename = av_malloc(basename_size);
-        if (!vs->basename) {
-            ret = AVERROR(ENOMEM);
-            goto fail;
-        }
-
-        av_strlcpy(vs->basename, hls->segment_filename, basename_size);
-    } else {
-        if (hls->flags & HLS_SINGLE_FILE) {
-            if (hls->segment_type == SEGMENT_TYPE_FMP4) {
-                pattern = ".m4s";
-            } else {
-                pattern = ".ts";
-            }
-        }
-
-        if (hls->use_localtime) {
-            basename_size = strlen(s->filename) + strlen(pattern_localtime_fmt) + 1;
-        } else {
-            basename_size = strlen(s->filename) + strlen(pattern) + 1;
-        }
-
-        if (hls->nb_varstreams > 1) {
-            basename_size += strlen(POSTFIX_PATTERN);
-        }
-
-        vs->basename = av_malloc(basename_size);
-        if (!vs->basename) {
-            ret = AVERROR(ENOMEM);
-            goto fail;
-        }
-
-        av_strlcpy(vs->basename, s->filename, basename_size);
-
-        p = strrchr(vs->basename, '.');
-        if (p)
-            *p = '\0';
-        if (hls->use_localtime) {
-            av_strlcat(vs->basename, pattern_localtime_fmt, basename_size);
-        } else {
-            av_strlcat(vs->basename, pattern, basename_size);
-        }
-    }
-
-    m3u8_name_size = strlen(s->filename) + 1;
-    if (hls->nb_varstreams > 1) {
-        m3u8_name_size += strlen(POSTFIX_PATTERN);
-    }
-
-    vs->m3u8_name = av_malloc(m3u8_name_size);
-    if (!vs->m3u8_name ) {
-        ret = AVERROR(ENOMEM);
-        goto fail;
-    }
-
-    av_strlcpy(vs->m3u8_name, s->filename, m3u8_name_size);
-
-    if (hls->nb_varstreams > 1) {
-        ret = format_name(vs->basename, basename_size, i);
-        if (ret < 0)
-             goto fail;
-        ret = format_name(vs->m3u8_name, m3u8_name_size, i);
-        if (ret < 0)
-             goto fail;
-    }
-
-    if (hls->segment_type == SEGMENT_TYPE_FMP4) {
-        if (hls->nb_varstreams > 1)
-            fmp4_init_filename_len += strlen(POSTFIX_PATTERN);
-        vs->fmp4_init_filename = av_malloc(fmp4_init_filename_len);
-        if (!vs->fmp4_init_filename ) {
-            ret = AVERROR(ENOMEM);
-            goto fail;
-        }
-        av_strlcpy(vs->fmp4_init_filename, hls->fmp4_init_filename,
-                fmp4_init_filename_len);
-        if (hls->nb_varstreams > 1) {
-            ret = format_name(vs->fmp4_init_filename, fmp4_init_filename_len, i);
-            if (ret < 0)
-                 goto fail;
-        }
-
-        if (av_strcasecmp(hls->fmp4_init_filename, "init.mp4")) {
-            fmp4_init_filename_len = strlen(vs->fmp4_init_filename) + 1;
-            vs->base_output_dirname = av_malloc(fmp4_init_filename_len);
-            if (!vs->base_output_dirname) {
-                ret = AVERROR(ENOMEM);
-                goto fail;
-            }
-            av_strlcpy(vs->base_output_dirname, vs->fmp4_init_filename,
-                    fmp4_init_filename_len);
-        } else {
-            fmp4_init_filename_len = strlen(vs->m3u8_name) +
-                                         strlen(vs->fmp4_init_filename) + 1;
-
-            vs->base_output_dirname = av_malloc(fmp4_init_filename_len);
-            if (!vs->base_output_dirname) {
-                ret = AVERROR(ENOMEM);
-                goto fail;
-            }
-
-            av_strlcpy(vs->base_output_dirname, vs->m3u8_name,
-                    fmp4_init_filename_len);
-            p = strrchr(vs->base_output_dirname, '/');
-            if (p) {
-                *(p + 1) = '\0';
-                av_strlcat(vs->base_output_dirname, vs->fmp4_init_filename,
-                        fmp4_init_filename_len);
-            } else {
-                av_strlcpy(vs->base_output_dirname, vs->fmp4_init_filename,
-                        fmp4_init_filename_len);
-            }
-        }
-    }
-
-    if (!hls->use_localtime) {
-        ret = sls_flag_check_duration_size_index(hls);
-        if (ret < 0) {
-             goto fail;
-        }
-    } else {
-        ret = sls_flag_check_duration_size(hls, vs);
-        if (ret < 0) {
-             goto fail;
-        }
-    }
-    if(vs->has_subtitle) {
-
-        if (hls->flags & HLS_SINGLE_FILE)
-            vtt_pattern = ".vtt";
-        vtt_basename_size = strlen(s->filename) + strlen(vtt_pattern) + 1;
-        if (hls->nb_varstreams > 1) {
-            vtt_basename_size += strlen(POSTFIX_PATTERN);
-        }
-
-        vs->vtt_basename = av_malloc(vtt_basename_size);
-        if (!vs->vtt_basename) {
-            ret = AVERROR(ENOMEM);
-            goto fail;
-        }
-        vs->vtt_m3u8_name = av_malloc(vtt_basename_size);
-        if (!vs->vtt_m3u8_name ) {
-            ret = AVERROR(ENOMEM);
-            goto fail;
-        }
-        av_strlcpy(vs->vtt_basename, s->filename, vtt_basename_size);
-        p = strrchr(vs->vtt_basename, '.');
-        if (p)
-            *p = '\0';
-
-        if( hls->subtitle_filename ) {
-            strcpy(vs->vtt_m3u8_name, hls->subtitle_filename);
-        } else {
-            strcpy(vs->vtt_m3u8_name, vs->vtt_basename);
-            av_strlcat(vs->vtt_m3u8_name, "_vtt.m3u8", vtt_basename_size);
-        }
-        av_strlcat(vs->vtt_basename, vtt_pattern, vtt_basename_size);
-
-        if (hls->nb_varstreams > 1) {
-            ret= format_name(vs->vtt_basename, vtt_basename_size, i);
-            if (ret < 0)
-                 goto fail;
-            ret = format_name(vs->vtt_m3u8_name, vtt_basename_size, i);
-            if (ret < 0)
-                 goto fail;
-        }
-    }
-
-    if (hls->baseurl) {
-        vs->baseurl = av_strdup(hls->baseurl);
-        if (!vs->baseurl) {
-            ret = AVERROR(ENOMEM);
-            goto fail;
-        }
-    }
-
-    if ((hls->flags & HLS_SINGLE_FILE) && (hls->segment_type == SEGMENT_TYPE_FMP4)) {
-        vs->fmp4_init_filename  = av_strdup(vs->basename);
-        if (!vs->fmp4_init_filename) {
-            ret = AVERROR(ENOMEM);
-            goto fail;
-        }
-    }
-
-    if ((ret = hls_mux_init(s, vs)) < 0)
-        goto fail;
-
-    if (hls->flags & HLS_APPEND_LIST) {
-        parse_playlist(s, vs->m3u8_name, vs);
-        vs->discontinuity = 1;
-        if (hls->init_time > 0) {
-            av_log(s, AV_LOG_WARNING, "append_list mode does not support hls_init_time,"
-                   " hls_init_time value will have no effect\n");
-            hls->init_time = 0;
-            hls->recording_time = hls->time * AV_TIME_BASE;
-        }
-    }
-
-    if (hls->segment_type != SEGMENT_TYPE_FMP4 || hls->flags & HLS_SINGLE_FILE) {
-        if ((ret = hls_start(s, vs)) < 0)
-            goto fail;
-    }
-
     av_dict_copy(&options, hls->format_options, 0);
     ret = avformat_write_header(vs->avf, &options);
     if (av_dict_count(options)) {
@@ -2000,25 +1683,6 @@ static int hls_write_header(AVFormatContext *s)
     }
 fail:
 
-    if (ret < 0) {
-        av_freep(&hls->key_basename);
-        for (i = 0; i < hls->nb_varstreams && hls->var_streams; i++) {
-            vs = &hls->var_streams[i];
-            av_freep(&vs->basename);
-            av_freep(&vs->vtt_basename);
-            av_freep(&vs->fmp4_init_filename);
-            av_freep(&vs->m3u8_name);
-            av_freep(&vs->vtt_m3u8_name);
-            av_freep(&vs->streams);
-            av_freep(&vs->baseurl);
-            if (vs->avf)
-                avformat_free_context(vs->avf);
-            if (vs->vtt_avf)
-                avformat_free_context(vs->vtt_avf);
-        }
-        av_freep(&hls->var_streams);
-        av_freep(&hls->master_m3u8_url);
-    }
     return ret;
 }
 
@@ -2260,6 +1924,350 @@ static int hls_write_trailer(struct AVFormatContext *s)
     return 0;
 }
 
+
+static int hls_init(AVFormatContext *s)
+{
+    int ret = 0;
+    int i = 0;
+    int j = 0;
+    HLSContext *hls = s->priv_data;
+    const char *pattern = "%d.ts";
+    VariantStream *vs = NULL;
+    int basename_size = 0;
+    const char *pattern_localtime_fmt = get_default_pattern_localtime_fmt(s);
+    const char *vtt_pattern = "%d.vtt";
+    char *p = NULL;
+    int vtt_basename_size = 0, m3u8_name_size = 0;
+    int fmp4_init_filename_len = strlen(hls->fmp4_init_filename) + 1;
+
+    ret = update_variant_stream_info(s);
+    if (ret < 0) {
+        av_log(s, AV_LOG_ERROR, "Variant stream info update failed with status %x\n",
+                ret);
+        goto fail;
+    }
+    //TODO: Updates needed to encryption functionality with periodic re-key when more than one variant streams are present
+    if (hls->nb_varstreams > 1 && hls->flags & HLS_PERIODIC_REKEY) {
+        ret = AVERROR(EINVAL);
+        av_log(s, AV_LOG_ERROR, "Periodic re-key not supported when more than one variant streams are present\n");
+        goto fail;
+    }
+
+    if (hls->master_pl_name) {
+        ret = update_master_pl_info(s);
+        if (ret < 0) {
+            av_log(s, AV_LOG_ERROR, "Master stream info update failed with status %x\n",
+                    ret);
+            goto fail;
+        }
+    }
+
+    if (hls->segment_type == SEGMENT_TYPE_FMP4) {
+        pattern = "%d.m4s";
+    }
+    if ((hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH) ||
+        (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_FORMATTED_DATETIME)) {
+        time_t t = time(NULL); // we will need it in either case
+        if (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH) {
+            hls->start_sequence = (int64_t)t;
+        } else if (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_FORMATTED_DATETIME) {
+            char b[15];
+            struct tm *p, tmbuf;
+            if (!(p = localtime_r(&t, &tmbuf)))
+                return AVERROR(ENOMEM);
+            if (!strftime(b, sizeof(b), "%Y%m%d%H%M%S", p))
+                return AVERROR(ENOMEM);
+            hls->start_sequence = strtoll(b, NULL, 10);
+        }
+        av_log(hls, AV_LOG_DEBUG, "start_number evaluated to %"PRId64"\n", hls->start_sequence);
+    }
+
+    hls->recording_time = (hls->init_time ? hls->init_time : hls->time) * AV_TIME_BASE;
+    for (i = 0; i < hls->nb_varstreams; i++) {
+        vs = &hls->var_streams[i];
+        vs->sequence       = hls->start_sequence;
+        vs->start_pts      = AV_NOPTS_VALUE;
+        vs->end_pts      = AV_NOPTS_VALUE;
+        vs->current_segment_final_filename_fmt[0] = '\0';
+
+        if (hls->flags & HLS_SPLIT_BY_TIME && hls->flags & HLS_INDEPENDENT_SEGMENTS) {
+            // Independent segments cannot be guaranteed when splitting by time
+            hls->flags &= ~HLS_INDEPENDENT_SEGMENTS;
+            av_log(s, AV_LOG_WARNING,
+                   "'split_by_time' and 'independent_segments' cannot be enabled together. "
+                   "Disabling 'independent_segments' flag\n");
+        }
+
+        if (hls->flags & HLS_PROGRAM_DATE_TIME) {
+            time_t now0;
+            time(&now0);
+            vs->initial_prog_date_time = now0;
+        }
+        if (hls->format_options_str) {
+            ret = av_dict_parse_string(&hls->format_options, hls->format_options_str, "=", ":", 0);
+            if (ret < 0) {
+                av_log(s, AV_LOG_ERROR, "Could not parse format options list '%s'\n", hls->format_options_str);
+                goto fail;
+            }
+        }
+
+        for (j = 0; j < vs->nb_streams; j++) {
+            vs->has_video += vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO;
+            vs->has_subtitle += vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE;
+        }
+
+        if (vs->has_video > 1)
+            av_log(s, AV_LOG_WARNING, "More than a single video stream present, expect issues decoding it.\n");
+        if (hls->segment_type == SEGMENT_TYPE_FMP4) {
+            vs->oformat = av_guess_format("mp4", NULL, NULL);
+        } else {
+            vs->oformat = av_guess_format("mpegts", NULL, NULL);
+        }
+
+        if (!vs->oformat) {
+            ret = AVERROR_MUXER_NOT_FOUND;
+            goto fail;
+        }
+
+        if (vs->has_subtitle) {
+            vs->vtt_oformat = av_guess_format("webvtt", NULL, NULL);
+            if (!vs->oformat) {
+                ret = AVERROR_MUXER_NOT_FOUND;
+                goto fail;
+            }
+        }
+        if (hls->segment_filename) {
+            basename_size = strlen(hls->segment_filename) + 1;
+            if (hls->nb_varstreams > 1) {
+                basename_size += strlen(POSTFIX_PATTERN);
+            }
+            vs->basename = av_malloc(basename_size);
+            if (!vs->basename) {
+                ret = AVERROR(ENOMEM);
+                goto fail;
+            }
+
+            av_strlcpy(vs->basename, hls->segment_filename, basename_size);
+        } else {
+            if (hls->flags & HLS_SINGLE_FILE) {
+                if (hls->segment_type == SEGMENT_TYPE_FMP4) {
+                    pattern = ".m4s";
+                } else {
+                    pattern = ".ts";
+                }
+            }
+
+            if (hls->use_localtime) {
+                basename_size = strlen(s->filename) + strlen(pattern_localtime_fmt) + 1;
+            } else {
+                basename_size = strlen(s->filename) + strlen(pattern) + 1;
+            }
+
+            if (hls->nb_varstreams > 1) {
+                basename_size += strlen(POSTFIX_PATTERN);
+            }
+
+            vs->basename = av_malloc(basename_size);
+            if (!vs->basename) {
+                ret = AVERROR(ENOMEM);
+                goto fail;
+            }
+
+            av_strlcpy(vs->basename, s->filename, basename_size);
+
+            p = strrchr(vs->basename, '.');
+            if (p)
+                *p = '\0';
+            if (hls->use_localtime) {
+                av_strlcat(vs->basename, pattern_localtime_fmt, basename_size);
+            } else {
+                av_strlcat(vs->basename, pattern, basename_size);
+            }
+        }
+
+        m3u8_name_size = strlen(s->filename) + 1;
+        if (hls->nb_varstreams > 1) {
+            m3u8_name_size += strlen(POSTFIX_PATTERN);
+        }
+
+        vs->m3u8_name = av_malloc(m3u8_name_size);
+        if (!vs->m3u8_name ) {
+            ret = AVERROR(ENOMEM);
+            goto fail;
+        }
+
+        av_strlcpy(vs->m3u8_name, s->filename, m3u8_name_size);
+
+        if (hls->nb_varstreams > 1) {
+            ret = format_name(vs->basename, basename_size, i);
+            if (ret < 0)
+                goto fail;
+            ret = format_name(vs->m3u8_name, m3u8_name_size, i);
+            if (ret < 0)
+                goto fail;
+        }
+
+        if (hls->segment_type == SEGMENT_TYPE_FMP4) {
+            if (hls->nb_varstreams > 1)
+                fmp4_init_filename_len += strlen(POSTFIX_PATTERN);
+            vs->fmp4_init_filename = av_malloc(fmp4_init_filename_len);
+            if (!vs->fmp4_init_filename ) {
+                ret = AVERROR(ENOMEM);
+                goto fail;
+            }
+            av_strlcpy(vs->fmp4_init_filename, hls->fmp4_init_filename,
+                       fmp4_init_filename_len);
+            if (hls->nb_varstreams > 1) {
+                ret = format_name(vs->fmp4_init_filename, fmp4_init_filename_len, i);
+                if (ret < 0)
+                    goto fail;
+            }
+
+            if (av_strcasecmp(hls->fmp4_init_filename, "init.mp4")) {
+                fmp4_init_filename_len = strlen(vs->fmp4_init_filename) + 1;
+                vs->base_output_dirname = av_malloc(fmp4_init_filename_len);
+                if (!vs->base_output_dirname) {
+                    ret = AVERROR(ENOMEM);
+                    goto fail;
+                }
+                av_strlcpy(vs->base_output_dirname, vs->fmp4_init_filename,
+                           fmp4_init_filename_len);
+            } else {
+                fmp4_init_filename_len = strlen(vs->m3u8_name) +
+                    strlen(vs->fmp4_init_filename) + 1;
+
+                vs->base_output_dirname = av_malloc(fmp4_init_filename_len);
+                if (!vs->base_output_dirname) {
+                    ret = AVERROR(ENOMEM);
+                    goto fail;
+                }
+
+                av_strlcpy(vs->base_output_dirname, vs->m3u8_name,
+                           fmp4_init_filename_len);
+                p = strrchr(vs->base_output_dirname, '/');
+                if (p) {
+                    *(p + 1) = '\0';
+                    av_strlcat(vs->base_output_dirname, vs->fmp4_init_filename,
+                               fmp4_init_filename_len);
+                } else {
+                    av_strlcpy(vs->base_output_dirname, vs->fmp4_init_filename,
+                               fmp4_init_filename_len);
+                }
+            }
+        }
+
+        if (!hls->use_localtime) {
+            ret = sls_flag_check_duration_size_index(hls);
+            if (ret < 0) {
+                goto fail;
+            }
+        } else {
+            ret = sls_flag_check_duration_size(hls, vs);
+            if (ret < 0) {
+                goto fail;
+            }
+        }
+        if (vs->has_subtitle) {
+
+            if (hls->flags & HLS_SINGLE_FILE)
+                vtt_pattern = ".vtt";
+            vtt_basename_size = strlen(s->filename) + strlen(vtt_pattern) + 1;
+            if (hls->nb_varstreams > 1) {
+                vtt_basename_size += strlen(POSTFIX_PATTERN);
+            }
+
+            vs->vtt_basename = av_malloc(vtt_basename_size);
+            if (!vs->vtt_basename) {
+                ret = AVERROR(ENOMEM);
+                goto fail;
+            }
+            vs->vtt_m3u8_name = av_malloc(vtt_basename_size);
+            if (!vs->vtt_m3u8_name ) {
+                ret = AVERROR(ENOMEM);
+                goto fail;
+            }
+            av_strlcpy(vs->vtt_basename, s->filename, vtt_basename_size);
+            p = strrchr(vs->vtt_basename, '.');
+            if (p)
+                *p = '\0';
+
+            if ( hls->subtitle_filename ) {
+                strcpy(vs->vtt_m3u8_name, hls->subtitle_filename);
+            } else {
+                strcpy(vs->vtt_m3u8_name, vs->vtt_basename);
+                av_strlcat(vs->vtt_m3u8_name, "_vtt.m3u8", vtt_basename_size);
+            }
+            av_strlcat(vs->vtt_basename, vtt_pattern, vtt_basename_size);
+
+            if (hls->nb_varstreams > 1) {
+                ret= format_name(vs->vtt_basename, vtt_basename_size, i);
+                if (ret < 0)
+                    goto fail;
+                ret = format_name(vs->vtt_m3u8_name, vtt_basename_size, i);
+                if (ret < 0)
+                    goto fail;
+            }
+        }
+
+        if (hls->baseurl) {
+            vs->baseurl = av_strdup(hls->baseurl);
+            if (!vs->baseurl) {
+                ret = AVERROR(ENOMEM);
+                goto fail;
+            }
+        }
+
+        if ((hls->flags & HLS_SINGLE_FILE) && (hls->segment_type == SEGMENT_TYPE_FMP4)) {
+            vs->fmp4_init_filename  = av_strdup(vs->basename);
+            if (!vs->fmp4_init_filename) {
+                ret = AVERROR(ENOMEM);
+                goto fail;
+            }
+        }
+        if ((ret = hls_mux_init(s, vs)) < 0)
+            goto fail;
+
+        if (hls->flags & HLS_APPEND_LIST) {
+            parse_playlist(s, vs->m3u8_name, vs);
+            vs->discontinuity = 1;
+            if (hls->init_time > 0) {
+                av_log(s, AV_LOG_WARNING, "append_list mode does not support hls_init_time,"
+                       " hls_init_time value will have no effect\n");
+                hls->init_time = 0;
+                hls->recording_time = hls->time * AV_TIME_BASE;
+            }
+        }
+
+        if (hls->segment_type != SEGMENT_TYPE_FMP4 || hls->flags & HLS_SINGLE_FILE) {
+            if ((ret = hls_start(s, vs)) < 0)
+                goto fail;
+        }
+    }
+
+fail:
+    if (ret < 0) {
+        av_freep(&hls->key_basename);
+        for (i = 0; i < hls->nb_varstreams && hls->var_streams; i++) {
+            vs = &hls->var_streams[i];
+            av_freep(&vs->basename);
+            av_freep(&vs->vtt_basename);
+            av_freep(&vs->fmp4_init_filename);
+            av_freep(&vs->m3u8_name);
+            av_freep(&vs->vtt_m3u8_name);
+            av_freep(&vs->streams);
+            av_freep(&vs->baseurl);
+            if (vs->avf)
+                avformat_free_context(vs->avf);
+            if (vs->vtt_avf)
+                avformat_free_context(vs->vtt_avf);
+        }
+        av_freep(&hls->var_streams);
+        av_freep(&hls->master_m3u8_url);
+    }
+
+    return ret;
+}
+
 #define OFFSET(x) offsetof(HLSContext, x)
 #define E AV_OPT_FLAG_ENCODING_PARAM
 static const AVOption options[] = {
@@ -2336,6 +2344,7 @@ AVOutputFormat ff_hls_muxer = {
     .video_codec    = AV_CODEC_ID_H264,
     .subtitle_codec = AV_CODEC_ID_WEBVTT,
     .flags          = AVFMT_NOFILE | AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
+    .init           = hls_init,
     .write_header   = hls_write_header,
     .write_packet   = hls_write_packet,
     .write_trailer  = hls_write_trailer,