avformat/hlsenc: move init operations from write_header to init
Reviewed-by: Vishwanath Dixit <vdixit@akamai.com> Signed-off-by: Steven Liu <lq@chinaffmpeg.org>
This commit is contained in:
parent
918de766f5
commit
08d28ee182
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user