Putting date/time values into segment filenames is very usefull.
But to produce non-conflicting segment filenames with -use_localtime
option with date/time
values in hls_segment_filename option, sometimes is not enough.
Like in cases when multiple segments produced in the same second.
But hlsenc currently does not make possible to use segment index (%d) at
the
same time whe use_localtime is in effect, due to identifier conflict.
This patch makes possible to use strftime identifiers and still put
segment index (%d) at same time in segment filenames by introducing
second_level_segment_index flag. When -use_localtime is active,
identifier %d is for month day index, so %%d is the segment index
placeholder. This enhanced behaviour only exists when new
second_level_segment_index flag is specified.
For instance putting 'segment_%Y%m%d%H%M%S_%%05d.ts' value into
-hls_segment_filename option and specifing -hls_flags
second_level_segment_index and -use_localtime 1, may produce segment
filename as 'segment_20161230235758_00002.ts'
An example:
ffmpeg -loglevel info -y -f lavfi -i color=c=red:size=640x480:r=25 -f
lavfi -i anullsrc=r=44100:cl=stereo -c:v mpeg2video -g 25 -acodec aac
-cutoff 20000 -ac 2 -ar 44100 -ab 192k -f hls -hls_time 3 -hls_list_size
5 -hls_flags delete_segments+second_level_segment_index -use_localtime 1
-hls_segment_filename "segment_%Y%m%d%H%M%S_%%05d.ts" stream.m3u8
will produce segments filenames:
....
segment_20161227005902_00013.ts
segment_20161227005902_00014.ts
segment_20161227005902_00015.ts
segment_20161227005903_00016.ts
segment_20161227005903_00017.ts
segment_20161227005903_00018.ts
segment_20161227005903_00019.ts
segment_20161227005903_00020.ts
....
Signed-off-by: Bela Bodecs <bodecsb@vivanet.hu>
... | ... |
@@ -443,12 +443,18 @@ This example will produce the playlist, @file{out.m3u8}, and segment files: |
443 | 443 |
|
444 | 444 |
@item use_localtime |
445 | 445 |
Use strftime on @var{filename} to expand the segment filename with localtime. |
446 |
-The segment number (%d) is not available in this mode. |
|
446 |
+The segment number is also available in this mode, but to use it, you need to specify second_level_segment_index |
|
447 |
+hls_flag and %%d will be the specifier. |
|
447 | 448 |
@example |
448 | 449 |
ffmpeg -i in.nut -use_localtime 1 -hls_segment_filename 'file-%Y%m%d-%s.ts' out.m3u8 |
449 | 450 |
@end example |
450 | 451 |
This example will produce the playlist, @file{out.m3u8}, and segment files: |
451 | 452 |
@file{file-20160215-1455569023.ts}, @file{file-20160215-1455569024.ts}, etc. |
453 |
+@example |
|
454 |
+ffmpeg -i in.nut -use_localtime 1 -hls_flags second_level_segment_index -hls_segment_filename 'file-%Y%m%d-%%04d.ts' out.m3u8 |
|
455 |
+@end example |
|
456 |
+This example will produce the playlist, @file{out.m3u8}, and segment files: |
|
457 |
+@file{file-20160215-0001.ts}, @file{file-20160215-0002.ts}, etc. |
|
452 | 458 |
|
453 | 459 |
@item use_localtime_mkdir |
454 | 460 |
Used together with -use_localtime, it will create up to one subdirectory which |
... | ... |
@@ -556,6 +562,9 @@ seeking. This flag should be used with the @code{hls_time} option. |
556 | 556 |
@item hls_flags program_date_time |
557 | 557 |
Generate @code{EXT-X-PROGRAM-DATE-TIME} tags. |
558 | 558 |
|
559 |
+@item hls_flags second_level_segment_index |
|
560 |
+Makes it possible to use segment indexes as %%d besides date/time values when use_localtime is on. |
|
561 |
+ |
|
559 | 562 |
@item hls_playlist_type event |
560 | 563 |
Emit @code{#EXT-X-PLAYLIST-TYPE:EVENT} in the m3u8 header. Forces |
561 | 564 |
@option{hls_list_size} to 0; the playlist can only be appended to. |
... | ... |
@@ -66,6 +66,7 @@ typedef enum HLSFlags { |
66 | 66 |
HLS_SPLIT_BY_TIME = (1 << 5), |
67 | 67 |
HLS_APPEND_LIST = (1 << 6), |
68 | 68 |
HLS_PROGRAM_DATE_TIME = (1 << 7), |
69 |
+ HLS_SECOND_LEVEL_SEGMENT_INDEX = (1 << 8), // include segment index in segment filenames when use_localtime e.g.: %%03d |
|
69 | 70 |
} HLSFlags; |
70 | 71 |
|
71 | 72 |
typedef enum { |
... | ... |
@@ -717,7 +718,19 @@ static int hls_start(AVFormatContext *s) |
717 | 717 |
av_log(oc, AV_LOG_ERROR, "Could not get segment filename with use_localtime\n"); |
718 | 718 |
return AVERROR(EINVAL); |
719 | 719 |
} |
720 |
- |
|
720 |
+ if (c->flags & HLS_SECOND_LEVEL_SEGMENT_INDEX) { |
|
721 |
+ char * filename = av_strdup(oc->filename); // %%d will be %d after strftime |
|
722 |
+ if (!filename) |
|
723 |
+ return AVERROR(ENOMEM); |
|
724 |
+ if (av_get_frame_filename2(oc->filename, sizeof(oc->filename), |
|
725 |
+ filename, c->wrap ? c->sequence % c->wrap : c->sequence, |
|
726 |
+ AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) { |
|
727 |
+ av_log(c, AV_LOG_ERROR, "Invalid second level segment filename template '%s', you can try to remove second_level_segment_index flag\n", filename); |
|
728 |
+ av_free(filename); |
|
729 |
+ return AVERROR(EINVAL); |
|
730 |
+ } |
|
731 |
+ av_free(filename); |
|
732 |
+ } |
|
721 | 733 |
if (find_segment_by_filename(c->segments, oc->filename) |
722 | 734 |
|| find_segment_by_filename(c->old_segments, oc->filename)) { |
723 | 735 |
av_log(c, AV_LOG_WARNING, "Duplicated segment filename detected: %s\n", oc->filename); |
... | ... |
@@ -900,7 +913,11 @@ static int hls_write_header(AVFormatContext *s) |
900 | 900 |
av_strlcat(hls->basename, pattern, basename_size); |
901 | 901 |
} |
902 | 902 |
} |
903 |
- |
|
903 |
+ if (!hls->use_localtime && (hls->flags & HLS_SECOND_LEVEL_SEGMENT_INDEX)) { |
|
904 |
+ av_log(hls, AV_LOG_ERROR, "second_level_segment_index hls_flag requires use_localtime to be true\n"); |
|
905 |
+ ret = AVERROR(EINVAL); |
|
906 |
+ goto fail; |
|
907 |
+ } |
|
904 | 908 |
if(hls->has_subtitle) { |
905 | 909 |
|
906 | 910 |
if (hls->flags & HLS_SINGLE_FILE) |
... | ... |
@@ -1156,6 +1173,7 @@ static const AVOption options[] = { |
1156 | 1156 |
{"split_by_time", "split the hls segment by time which user set by hls_time", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SPLIT_BY_TIME }, 0, UINT_MAX, E, "flags"}, |
1157 | 1157 |
{"append_list", "append the new segments into old hls segment list", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_APPEND_LIST }, 0, UINT_MAX, E, "flags"}, |
1158 | 1158 |
{"program_date_time", "add EXT-X-PROGRAM-DATE-TIME", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_PROGRAM_DATE_TIME }, 0, UINT_MAX, E, "flags"}, |
1159 |
+ {"second_level_segment_index", "include segment index in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_INDEX }, 0, UINT_MAX, E, "flags"}, |
|
1159 | 1160 |
{"use_localtime", "set filename expansion with strftime at segment creation", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, |
1160 | 1161 |
{"use_localtime_mkdir", "create last directory component in strftime-generated filename", OFFSET(use_localtime_mkdir), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, |
1161 | 1162 |
{"hls_playlist_type", "set the HLS playlist type", OFFSET(pl_type), AV_OPT_TYPE_INT, {.i64 = PLAYLIST_TYPE_NONE }, 0, PLAYLIST_TYPE_NB-1, E, "pl_type" }, |