Reviewed-by: Steven Liu <lingjiujianke@gmail.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
... | ... |
@@ -522,6 +522,9 @@ behavior on some players when the time between keyframes is inconsistent, |
522 | 522 |
but may make things worse on others, and can cause some oddities during |
523 | 523 |
seeking. This flag should be used with the @code{hls_time} option. |
524 | 524 |
|
525 |
+@item hls_flags program_date_time |
|
526 |
+Generate @code{EXT-X-PROGRAM-DATE-TIME} tags. |
|
527 |
+ |
|
525 | 528 |
@item hls_playlist_type event |
526 | 529 |
Emit @code{#EXT-X-PLAYLIST-TYPE:EVENT} in the m3u8 header. Forces |
527 | 530 |
@option{hls_list_size} to 0; the playlist can only be appended to. |
... | ... |
@@ -64,6 +64,7 @@ typedef enum HLSFlags { |
64 | 64 |
HLS_OMIT_ENDLIST = (1 << 4), |
65 | 65 |
HLS_SPLIT_BY_TIME = (1 << 5), |
66 | 66 |
HLS_APPEND_LIST = (1 << 6), |
67 |
+ HLS_PROGRAM_DATE_TIME = (1 << 7), |
|
67 | 68 |
} HLSFlags; |
68 | 69 |
|
69 | 70 |
typedef enum { |
... | ... |
@@ -128,6 +129,7 @@ typedef struct HLSContext { |
128 | 128 |
|
129 | 129 |
char *method; |
130 | 130 |
|
131 |
+ double initial_prog_date_time; |
|
131 | 132 |
} HLSContext; |
132 | 133 |
|
133 | 134 |
static int hls_delete_old_segments(HLSContext *hls) { |
... | ... |
@@ -481,6 +483,7 @@ static int hls_window(AVFormatContext *s, int last) |
481 | 481 |
char *key_uri = NULL; |
482 | 482 |
char *iv_string = NULL; |
483 | 483 |
AVDictionary *options = NULL; |
484 |
+ double prog_date_time = hls->initial_prog_date_time; |
|
484 | 485 |
|
485 | 486 |
if (!use_rename && !warned_non_file++) |
486 | 487 |
av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this may lead to races and temporarly partial files\n"); |
... | ... |
@@ -533,6 +536,19 @@ static int hls_window(AVFormatContext *s, int last) |
533 | 533 |
if (hls->flags & HLS_SINGLE_FILE) |
534 | 534 |
avio_printf(out, "#EXT-X-BYTERANGE:%"PRIi64"@%"PRIi64"\n", |
535 | 535 |
en->size, en->pos); |
536 |
+ if (hls->flags & HLS_PROGRAM_DATE_TIME) { |
|
537 |
+ time_t tt; |
|
538 |
+ int milli; |
|
539 |
+ struct tm *tm, tmpbuf; |
|
540 |
+ char buf0[128], buf1[128]; |
|
541 |
+ tt = (int64_t)prog_date_time; |
|
542 |
+ milli = av_clip(lrint(1000*(prog_date_time - tt)), 0, 999); |
|
543 |
+ tm = localtime_r(&tt, &tmpbuf); |
|
544 |
+ strftime(buf0, sizeof(buf0), "%FT%T", tm); |
|
545 |
+ strftime(buf1, sizeof(buf1), "%z", tm); |
|
546 |
+ avio_printf(out, "#EXT-X-PROGRAM-DATE-TIME:%s.%03d%s\n", buf0, milli, buf1); |
|
547 |
+ prog_date_time += en->duration; |
|
548 |
+ } |
|
536 | 549 |
if (hls->baseurl) |
537 | 550 |
avio_printf(out, "%s", hls->baseurl); |
538 | 551 |
avio_printf(out, "%s\n", en->filename); |
... | ... |
@@ -710,6 +726,12 @@ static int hls_write_header(AVFormatContext *s) |
710 | 710 |
hls->recording_time = (hls->init_time ? hls->init_time : hls->time) * AV_TIME_BASE; |
711 | 711 |
hls->start_pts = AV_NOPTS_VALUE; |
712 | 712 |
|
713 |
+ if (hls->flags & HLS_PROGRAM_DATE_TIME) { |
|
714 |
+ time_t now0; |
|
715 |
+ time(&now0); |
|
716 |
+ hls->initial_prog_date_time = now0; |
|
717 |
+ } |
|
718 |
+ |
|
713 | 719 |
if (hls->format_options_str) { |
714 | 720 |
ret = av_dict_parse_string(&hls->format_options, hls->format_options_str, "=", ":", 0); |
715 | 721 |
if (ret < 0) { |
... | ... |
@@ -1005,6 +1027,7 @@ static const AVOption options[] = { |
1005 | 1005 |
{"omit_endlist", "Do not append an endlist when ending stream", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_OMIT_ENDLIST }, 0, UINT_MAX, E, "flags"}, |
1006 | 1006 |
{"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"}, |
1007 | 1007 |
{"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"}, |
1008 |
+ {"program_date_time", "add EXT-X-PROGRAM-DATE-TIME", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_PROGRAM_DATE_TIME }, 0, UINT_MAX, E, "flags"}, |
|
1008 | 1009 |
{"use_localtime", "set filename expansion with strftime at segment creation", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, |
1009 | 1010 |
{"use_localtime_mkdir", "create last directory component in strftime-generated filename", OFFSET(use_localtime_mkdir), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, |
1010 | 1011 |
{"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" }, |
... | ... |
@@ -33,7 +33,7 @@ |
33 | 33 |
// Also please add any ticket numbers that you believe might be affected here |
34 | 34 |
#define LIBAVFORMAT_VERSION_MAJOR 57 |
35 | 35 |
#define LIBAVFORMAT_VERSION_MINOR 48 |
36 |
-#define LIBAVFORMAT_VERSION_MICRO 102 |
|
36 |
+#define LIBAVFORMAT_VERSION_MICRO 103 |
|
37 | 37 |
|
38 | 38 |
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ |
39 | 39 |
LIBAVFORMAT_VERSION_MINOR, \ |