Browse code

lavf/hlsenc: add append_list flag into hlsenc

When ffmpeg exit by exception, start a new ffmpeg will
cover the old segment list, add this flag can continue
append the new segments into old hls segment list

Signed-off-by: LiuQi <liuqi@gosun.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>

Steven Liu authored on 2016/08/21 13:55:45
Showing 2 changed files
... ...
@@ -495,6 +495,10 @@ Will produce the playlist, @file{out.m3u8}, and a single segment file,
495 495
 Segment files removed from the playlist are deleted after a period of time
496 496
 equal to the duration of the segment plus the duration of the playlist.
497 497
 
498
+@item hls_flags append_list
499
+Append new segments into the end of old segment list,
500
+and remove the @code{#EXT-X-ENDLIST} from the old segment list.
501
+
498 502
 @item hls_flags round_durations
499 503
 Round the duration info in the playlist file segment info to integer
500 504
 values, instead of using floating point.
... ...
@@ -63,6 +63,7 @@ typedef enum HLSFlags {
63 63
     HLS_DISCONT_START = (1 << 3),
64 64
     HLS_OMIT_ENDLIST = (1 << 4),
65 65
     HLS_SPLIT_BY_TIME = (1 << 5),
66
+    HLS_APPEND_LIST = (1 << 6),
66 67
 } HLSFlags;
67 68
 
68 69
 typedef enum {
... ...
@@ -265,6 +266,14 @@ static int hls_encryption_start(AVFormatContext *s)
265 265
     return 0;
266 266
 }
267 267
 
268
+static int read_chomp_line(AVIOContext *s, char *buf, int maxlen)
269
+{
270
+    int len = ff_get_line(s, buf, maxlen);
271
+    while (len > 0 && av_isspace(buf[len - 1]))
272
+        buf[--len] = '\0';
273
+    return len;
274
+}
275
+
268 276
 static int hls_mux_init(AVFormatContext *s)
269 277
 {
270 278
     HLSContext *hls = s->priv_data;
... ...
@@ -389,6 +398,54 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, double
389 389
     return 0;
390 390
 }
391 391
 
392
+static int parse_playlist(AVFormatContext *s, const char *url)
393
+{
394
+    HLSContext *hls = s->priv_data;
395
+    AVIOContext *in;
396
+    int ret = 0, is_segment = 0;
397
+    int64_t new_start_pos;
398
+    char line[1024];
399
+    const char *ptr;
400
+
401
+    if ((ret = ffio_open_whitelist(&in, url, AVIO_FLAG_READ,
402
+                                   &s->interrupt_callback, NULL,
403
+                                   s->protocol_whitelist, s->protocol_blacklist)) < 0)
404
+        return ret;
405
+
406
+    read_chomp_line(in, line, sizeof(line));
407
+    if (strcmp(line, "#EXTM3U")) {
408
+        ret = AVERROR_INVALIDDATA;
409
+        goto fail;
410
+    }
411
+
412
+    while (!avio_feof(in)) {
413
+        read_chomp_line(in, line, sizeof(line));
414
+        if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) {
415
+            hls->sequence = atoi(ptr);
416
+        } else if (av_strstart(line, "#EXTINF:", &ptr)) {
417
+            is_segment = 1;
418
+            hls->duration = atof(ptr);
419
+        } else if (av_strstart(line, "#", NULL)) {
420
+            continue;
421
+        } else if (line[0]) {
422
+            if (is_segment) {
423
+                is_segment = 0;
424
+                new_start_pos = avio_tell(hls->avf->pb);
425
+                hls->size = new_start_pos - hls->start_pos;
426
+                av_strlcpy(hls->avf->filename, line, sizeof(line));
427
+                ret = hls_append_segment(s, hls, hls->duration, hls->start_pos, hls->size);
428
+                if (ret < 0)
429
+                    goto fail;
430
+                hls->start_pos = new_start_pos;
431
+            }
432
+        }
433
+    }
434
+
435
+fail:
436
+    avio_close(in);
437
+    return ret;
438
+}
439
+
392 440
 static void hls_free_segments(HLSSegment *p)
393 441
 {
394 442
     HLSSegment *en;
... ...
@@ -752,6 +809,10 @@ static int hls_write_header(AVFormatContext *s)
752 752
     if ((ret = hls_mux_init(s)) < 0)
753 753
         goto fail;
754 754
 
755
+    if (hls->flags & HLS_APPEND_LIST) {
756
+        parse_playlist(s, s->filename);
757
+    }
758
+
755 759
     if ((ret = hls_start(s)) < 0)
756 760
         goto fail;
757 761
 
... ...
@@ -927,6 +988,7 @@ static const AVOption options[] = {
927 927
     {"discont_start", "start the playlist with a discontinuity tag", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_DISCONT_START }, 0, UINT_MAX,   E, "flags"},
928 928
     {"omit_endlist", "Do not append an endlist when ending stream", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_OMIT_ENDLIST }, 0, UINT_MAX,   E, "flags"},
929 929
     {"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"},
930
+    {"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"},
930 931
     {"use_localtime", "set filename expansion with strftime at segment creation", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
931 932
     {"use_localtime_mkdir", "create last directory component in strftime-generated filename", OFFSET(use_localtime_mkdir), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
932 933
     {"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" },