From patchwork Mon Dec 4 09:48:11 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Liu Steven X-Patchwork-Id: 6540 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.2.161.94 with SMTP id m30csp4178632jah; Mon, 4 Dec 2017 01:50:02 -0800 (PST) X-Google-Smtp-Source: AGs4zMahKsV2x67ppxmjdK6kTamGwZYPwoLlBREdoqXmLSJT8q8OyDqkE0ohX04/qwnE7tGt5Yiq X-Received: by 10.28.109.5 with SMTP id i5mr2543716wmc.20.1512381002381; Mon, 04 Dec 2017 01:50:02 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1512381002; cv=none; d=google.com; s=arc-20160816; b=dI1mYJbyxiuSefBhjwesiFZ6uwb5vzgaEXKYphba94Dx9tZjCF9KMMtF6JbgjFmVAp zlU9cdaWvw3Sg0eFcvQi+EH/6r9E1gSSSg6G0K54nmIm3Oh+YWe6yiN+cQ+cwQ9waasV X8ucJizRYhwP7GcG3suWwZ7Ba9oo2uDstgwb4nObd+NXRf7lXc/e81zExCoMH/asNaSP 5FILs/SNrnSLQEOfRYyY339v1RNFdF/OoN7UfJ1+Dz4XE7N6MZ2JVMaeiXGx9n3rbgk6 myvWi2R+UTEm/FRB0BwHjWQ6Ds9cKhUGPR5C9EwUNMLRKFR1igWvuUZ8MfAiisPOn50R IFFw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:feedback-id:message-id:date:to:from :delivered-to:arc-authentication-results; bh=4rrH1LsSrDEUN8x4csjovfXL+g0WqYpC66NGo5AVGII=; b=TwcCTIUBYDetZgKbyVUFTe1qyv1HqJhGkfKkM/z7dcj7yPaUIZeyOO+kzfTSktVS97 DS8ZjdIJCYkCpP2FJX02LYW3JES59+EHaGZnwETF7dNHYEQG7Ypwodyq2Q+gIj/s7I+b hp12H60Q0NI3kbueKr6suJXwupWwFs5WclKlO1jW291+wbCdJ/0NXRvv+PVuQxlGZ4OK JA2Sb9wYkzem4dN57IJHXA+ui41ccSisgF0PLaID92c+u5uSpE7SNv/osMxEJLGVh1Qq ovy96AB9/Ikn2P3E099uY3bAqP70y9Kz08P6IQDZbp0/XM5Y4h+tptClIJ+8zedeL6C3 fOtQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id z55si10235927wrz.49.2017.12.04.01.50.01; Mon, 04 Dec 2017 01:50:02 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 35C8D68A468; Mon, 4 Dec 2017 11:49:56 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from smtpbg320.qq.com (SMTPBG19.QQ.COM [183.60.61.236]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id CD1D768A452 for ; Mon, 4 Dec 2017 11:49:48 +0200 (EET) X-QQ-mid: bizesmtp8t1512380893tyknzoqxp Received: from localhost (unknown [47.90.47.25]) by esmtp4.qq.com (ESMTP) with id ; Mon, 04 Dec 2017 17:48:13 +0800 (CST) X-QQ-SSF: 01100000002000F0FJ90B00A0000000 X-QQ-FEAT: oIoGrveFQB8VgBpYlkY5dL9wTpQ0dUU3aFlkeOI0osuJpaVXsqrSbvmtfw03y zj5lNCDJ6fYjUsi+MkZumUXsc8a/5Y/6zYdMz/1U+WISBPIEvkVch4uwKqPeBcBTeDoLYWK frQ1JtMcKB1KZcYmqpg3Ypq62CUJi4V1vmJ4O+eL1Dx0ac/02YslzxBNcZcPkevW35bh3Vx NuPdkcWanVsmk0foL+/pdviOc02dpeRW99AAo4PcapjmfiSrJ7zJQ1z9lmeiTpdsFS4IrID MF+HIDTx6lNXHx0EQvfgLzQ9tCeyjblXMHYg== X-QQ-GoodBg: 0 From: Steven Liu To: ffmpeg-devel@ffmpeg.org Date: Mon, 4 Dec 2017 17:48:11 +0800 Message-Id: <20171204094811.17172-1-lq@chinaffmpeg.org> X-Mailer: git-send-email 2.10.1.382.ga23ca1b.dirty X-QQ-SENDSIZE: 520 Feedback-ID: bizesmtp:chinaffmpeg.org:qybgforeign:qybgforeign1 X-QQ-Bgrelay: 1 Subject: [FFmpeg-devel] [PATCH] avformat/hlsenc: move init operations from write_header to init X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Steven Liu MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Signed-off-by: Steven Liu --- libavformat/hlsenc.c | 681 ++++++++++++++++++++++++++------------------------- 1 file changed, 345 insertions(+), 336 deletions(-) diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index aeeed5bcd2..852663d28f 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -1636,329 +1636,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)) { @@ -1996,25 +1679,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; } @@ -2256,6 +1920,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[] = { @@ -2332,6 +2340,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,