From 1c639fa6e02ed122dc41c318acb875f8d76537c5 Mon Sep 17 00:00:00 2001 From: Christian Suloway Date: Fri, 5 Dec 2014 21:20:15 +0000 Subject: [PATCH] avformat/hlsenc: added segment filename option This option allows segment filenames to be specified. Unless -hls_flags single_file is set the filename is used as a string format with the segment number. Example: ffmpeg -f lavfi -i testsrc -c:v h264 -map 0 -hls_segment_filename bar%03d.ts foo.m3u8 Signed-off-by: Christian Suloway Signed-off-by: Michael Niedermayer --- doc/muxers.texi | 9 +++++++++ libavformat/hlsenc.c | 42 +++++++++++++++++++++++++----------------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/doc/muxers.texi b/doc/muxers.texi index c6ba6045b8..34e827cde7 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -254,6 +254,15 @@ and it is not to be confused with the segment filename sequence number which can be cyclic, for example if the @option{wrap} option is specified. +@item hls_segment_filename @var{filename} +Set the segment filename. Unless hls_flags single_file is set @var{filename} +is used as a string format with the segment number: +@example +ffmpeg in.nut -hls_segment_filename 'file%03d.ts' out.m3u8 +@end example +This example will produce the playlist, @file{out.m3u8}, and segment files: +@file{file000.ts}, @file{file001.ts}, @file{file002.ts}, etc. + @item hls_flags single_file If this flag is set, the muxer will store all segments in a single MPEG-TS file, and will use byte ranges in the playlist. HLS playlists generated with diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index e13f438a2f..d5ea990476 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -59,6 +59,7 @@ typedef struct HLSContext { int max_nb_segments; // Set by a private option. int wrap; // Set by a private option. uint32_t flags; // enum HLSFlags + char *segment_filename; int allowcache; int64_t recording_time; @@ -237,15 +238,12 @@ static int hls_write_header(AVFormatContext *s) char *p; const char *pattern = "%d.ts"; AVDictionary *options = NULL; - int basename_size = strlen(s->filename) + strlen(pattern) + 1; + int basename_size; hls->sequence = hls->start_sequence; hls->recording_time = hls->time * AV_TIME_BASE; hls->start_pts = AV_NOPTS_VALUE; - if (hls->flags & HLS_SINGLE_FILE) - pattern = ".ts"; - if (hls->format_options_str) { ret = av_dict_parse_string(&hls->format_options, hls->format_options_str, "=", ":", 0); if (ret < 0) { @@ -270,22 +268,31 @@ static int hls_write_header(AVFormatContext *s) goto fail; } - hls->basename = av_malloc(basename_size); + if (hls->segment_filename) { + hls->basename = av_strdup(hls->segment_filename); + if (!hls->basename) { + ret = AVERROR(ENOMEM); + goto fail; + } + } else { + if (hls->flags & HLS_SINGLE_FILE) + pattern = ".ts"; - if (!hls->basename) { - ret = AVERROR(ENOMEM); - goto fail; + basename_size = strlen(s->filename) + strlen(pattern) + 1; + hls->basename = av_malloc(basename_size); + if (!hls->basename) { + ret = AVERROR(ENOMEM); + goto fail; + } + + av_strlcpy(hls->basename, s->filename, basename_size); + + p = strrchr(hls->basename, '.'); + if (p) + *p = '\0'; + av_strlcat(hls->basename, pattern, basename_size); } - strcpy(hls->basename, s->filename); - - p = strrchr(hls->basename, '.'); - - if (p) - *p = '\0'; - - av_strlcat(hls->basename, pattern, basename_size); - if ((ret = hls_mux_init(s)) < 0) goto fail; @@ -410,6 +417,7 @@ static const AVOption options[] = { {"hls_wrap", "set number after which the index wraps", OFFSET(wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E}, {"hls_allow_cache", "explicitly set whether the client MAY (1) or MUST NOT (0) cache media segments", OFFSET(allowcache), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, E}, {"hls_base_url", "url to prepend to each playlist entry", OFFSET(baseurl), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, + {"hls_segment_filename", "filename template for segment files", OFFSET(segment_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, {"hls_flags", "set flags affecting HLS playlist and media file generation", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, 0, UINT_MAX, E, "flags"}, {"single_file", "generate a single media file indexed with byte ranges", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SINGLE_FILE }, 0, UINT_MAX, E, "flags"},