Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
Adam Kent authored on 2015/12/17 12:16:45... | ... |
@@ -408,6 +408,14 @@ Will produce the playlist, @file{out.m3u8}, and a single segment file, |
408 | 408 |
@item hls_flags delete_segments |
409 | 409 |
Segment files removed from the playlist are deleted after a period of time |
410 | 410 |
equal to the duration of the segment plus the duration of the playlist. |
411 |
+ |
|
412 |
+@item hls_playlist_type event |
|
413 |
+Emit @code{#EXT-X-PLAYLIST-TYPE:EVENT} in the m3u8 header. Forces |
|
414 |
+@option{hls_list_size} to 0; the playlist can only be appended to. |
|
415 |
+ |
|
416 |
+@item hls_playlist_type vod |
|
417 |
+Emit @code{#EXT-X-PLAYLIST-TYPE:VOD} in the m3u8 header. Forces |
|
418 |
+@option{hls_list_size} to 0; the playlist must not change. |
|
411 | 419 |
@end table |
412 | 420 |
|
413 | 421 |
@anchor{ico} |
... | ... |
@@ -64,6 +64,13 @@ typedef enum HLSFlags { |
64 | 64 |
HLS_OMIT_ENDLIST = (1 << 4), |
65 | 65 |
} HLSFlags; |
66 | 66 |
|
67 |
+typedef enum { |
|
68 |
+ PLAYLIST_TYPE_NONE, |
|
69 |
+ PLAYLIST_TYPE_EVENT, |
|
70 |
+ PLAYLIST_TYPE_VOD, |
|
71 |
+ PLAYLIST_TYPE_NB, |
|
72 |
+} PlaylistType; |
|
73 |
+ |
|
67 | 74 |
typedef struct HLSContext { |
68 | 75 |
const AVClass *class; // Class for private options. |
69 | 76 |
unsigned number; |
... | ... |
@@ -79,6 +86,7 @@ typedef struct HLSContext { |
79 | 79 |
int max_nb_segments; // Set by a private option. |
80 | 80 |
int wrap; // Set by a private option. |
81 | 81 |
uint32_t flags; // enum HLSFlags |
82 |
+ uint32_t pl_type; // enum PlaylistType |
|
82 | 83 |
char *segment_filename; |
83 | 84 |
|
84 | 85 |
int use_localtime; ///< flag to expand filename with localtime |
... | ... |
@@ -357,6 +365,10 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, double |
357 | 357 |
|
358 | 358 |
hls->last_segment = en; |
359 | 359 |
|
360 |
+ // EVENT or VOD playlists imply sliding window cannot be used |
|
361 |
+ if (hls->pl_type != PLAYLIST_TYPE_NONE) |
|
362 |
+ hls->max_nb_segments = 0; |
|
363 |
+ |
|
360 | 364 |
if (hls->max_nb_segments && hls->nb_entries >= hls->max_nb_segments) { |
361 | 365 |
en = hls->segments; |
362 | 366 |
hls->segments = en->next; |
... | ... |
@@ -432,6 +444,11 @@ static int hls_window(AVFormatContext *s, int last) |
432 | 432 |
} |
433 | 433 |
avio_printf(out, "#EXT-X-TARGETDURATION:%d\n", target_duration); |
434 | 434 |
avio_printf(out, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence); |
435 |
+ if (hls->pl_type == PLAYLIST_TYPE_EVENT) { |
|
436 |
+ avio_printf(out, "#EXT-X-PLAYLIST-TYPE:EVENT\n"); |
|
437 |
+ } else if (hls->pl_type == PLAYLIST_TYPE_VOD) { |
|
438 |
+ avio_printf(out, "#EXT-X-PLAYLIST-TYPE:VOD\n"); |
|
439 |
+ } |
|
435 | 440 |
|
436 | 441 |
av_log(s, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", |
437 | 442 |
sequence); |
... | ... |
@@ -908,6 +925,9 @@ static const AVOption options[] = { |
908 | 908 |
{"omit_endlist", "Do not append an endlist when ending stream", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_OMIT_ENDLIST }, 0, UINT_MAX, E, "flags"}, |
909 | 909 |
{"use_localtime", "set filename expansion with strftime at segment creation", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, |
910 | 910 |
{"use_localtime_mkdir", "create last directory component in strftime-generated filename", OFFSET(use_localtime_mkdir), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, |
911 |
+ {"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" }, |
|
912 |
+ {"event", "EVENT playlist", 0, AV_OPT_TYPE_CONST, {.i64 = PLAYLIST_TYPE_EVENT }, INT_MIN, INT_MAX, E, "pl_type" }, |
|
913 |
+ {"vod", "VOD playlist", 0, AV_OPT_TYPE_CONST, {.i64 = PLAYLIST_TYPE_VOD }, INT_MIN, INT_MAX, E, "pl_type" }, |
|
911 | 914 |
{"method", "set the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, |
912 | 915 |
|
913 | 916 |
{ NULL }, |