Commit 1c639fa6 authored by Christian Suloway's avatar Christian Suloway Committed by Michael Niedermayer

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: 's avatarChristian Suloway <csuloway@globaleagleent.com>
Signed-off-by: 's avatarMichael Niedermayer <michaelni@gmx.at>
parent ce800d46
...@@ -254,6 +254,15 @@ and it is not to be confused with the segment filename sequence number ...@@ -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 which can be cyclic, for example if the @option{wrap} option is
specified. 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 @item hls_flags single_file
If this flag is set, the muxer will store all segments in a single MPEG-TS 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 file, and will use byte ranges in the playlist. HLS playlists generated with
......
...@@ -59,6 +59,7 @@ typedef struct HLSContext { ...@@ -59,6 +59,7 @@ typedef struct HLSContext {
int max_nb_segments; // Set by a private option. int max_nb_segments; // Set by a private option.
int wrap; // Set by a private option. int wrap; // Set by a private option.
uint32_t flags; // enum HLSFlags uint32_t flags; // enum HLSFlags
char *segment_filename;
int allowcache; int allowcache;
int64_t recording_time; int64_t recording_time;
...@@ -237,15 +238,12 @@ static int hls_write_header(AVFormatContext *s) ...@@ -237,15 +238,12 @@ static int hls_write_header(AVFormatContext *s)
char *p; char *p;
const char *pattern = "%d.ts"; const char *pattern = "%d.ts";
AVDictionary *options = NULL; AVDictionary *options = NULL;
int basename_size = strlen(s->filename) + strlen(pattern) + 1; int basename_size;
hls->sequence = hls->start_sequence; hls->sequence = hls->start_sequence;
hls->recording_time = hls->time * AV_TIME_BASE; hls->recording_time = hls->time * AV_TIME_BASE;
hls->start_pts = AV_NOPTS_VALUE; hls->start_pts = AV_NOPTS_VALUE;
if (hls->flags & HLS_SINGLE_FILE)
pattern = ".ts";
if (hls->format_options_str) { if (hls->format_options_str) {
ret = av_dict_parse_string(&hls->format_options, hls->format_options_str, "=", ":", 0); ret = av_dict_parse_string(&hls->format_options, hls->format_options_str, "=", ":", 0);
if (ret < 0) { if (ret < 0) {
...@@ -270,21 +268,30 @@ static int hls_write_header(AVFormatContext *s) ...@@ -270,21 +268,30 @@ static int hls_write_header(AVFormatContext *s)
goto fail; goto fail;
} }
hls->basename = av_malloc(basename_size); if (hls->segment_filename) {
hls->basename = av_strdup(hls->segment_filename);
if (!hls->basename) { if (!hls->basename) {
ret = AVERROR(ENOMEM); ret = AVERROR(ENOMEM);
goto fail; goto fail;
} }
} else {
strcpy(hls->basename, s->filename); if (hls->flags & HLS_SINGLE_FILE)
pattern = ".ts";
p = strrchr(hls->basename, '.'); basename_size = strlen(s->filename) + strlen(pattern) + 1;
hls->basename = av_malloc(basename_size);
if (!hls->basename) {
ret = AVERROR(ENOMEM);
goto fail;
}
if (p) av_strlcpy(hls->basename, s->filename, basename_size);
*p = '\0';
av_strlcat(hls->basename, pattern, basename_size); p = strrchr(hls->basename, '.');
if (p)
*p = '\0';
av_strlcat(hls->basename, pattern, basename_size);
}
if ((ret = hls_mux_init(s)) < 0) if ((ret = hls_mux_init(s)) < 0)
goto fail; goto fail;
...@@ -410,6 +417,7 @@ static const AVOption options[] = { ...@@ -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_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_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_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"}, {"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"}, {"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"},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment