Parse the playlist to recover the start sequence and previously
generated segments and continue muxing from there.
Mainly useful for near-seamless recovery in live scenarios.
---
libavformat/hlsenc.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 78 insertions(+), 6 deletions(-)
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index b6dccf359e..cc8e95fa98 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -119,7 +119,7 @@ static int setup_encryption(AVFormatContext *s)
AVIOContext *out = NULL;
int len, ret;
uint8_t buf[16];
- uint8_t *k;
+ uint8_t *k = NULL;
len = strlen(hls->basename) + 4 + 1;
hls->key_basename = av_mallocz(len);
@@ -141,9 +141,22 @@ static int setup_encryption(AVFormatContext *s)
return ret;
k = hls->key;
} else {
- if ((ret = randomize(buf, sizeof(buf))) < 0) {
- av_log(s, AV_LOG_ERROR, "Cannot generate a strong random key\n");
- return ret;
+ if (hls->start_sequence < 0) {
+ ret = s->io_open(s, &out, hls->key_basename, AVIO_FLAG_READ, NULL);
+ if (ret < 0) {
+ av_log(s, AV_LOG_WARNING,
+ "Cannot recover the key, generating a new one.\n");
+ } else {
+ avio_read(out, buf, 16);
+ k = buf;
+ avio_close(out);
+ }
+ }
+ if (!k) {
+ if ((ret = randomize(buf, sizeof(buf))) < 0) {
+ av_log(s, AV_LOG_ERROR, "Cannot generate a strong random
key\n");
+ return ret;
+ }
}
if ((ret = dict_set_bin(&hls->enc_opts, "key", buf, sizeof(buf))) < 0)
@@ -356,12 +369,64 @@ fail:
return err;
}
+static int read_chomp_line(AVIOContext *s, char *buf, int maxlen)
+{
+ int len = ff_get_line(s, buf, maxlen);
+ while (len > 0 && av_isspace(buf[len - 1]))
+ buf[--len] = '\0';
+ return len;
+}
+
+static int hls_recover(AVFormatContext *s)
+{
+ HLSContext *hls = s->priv_data;
+ char line[1024];
+ AVIOContext *io;
+ const char *ptr;
+ int ret, is_segment = 0;
+ int64_t duration = 0;
+
+ ret = s->io_open(s, &io, s->filename, AVIO_FLAG_READ, NULL);
+ if (ret < 0) {
+ av_log(s, AV_LOG_WARNING,
+ "Cannot recover the playlist, generating a new one.\n");
+ hls->start_sequence = 0;
+ hls->sequence = 0;
+ return 0;
+ }
+
+ read_chomp_line(io, line, sizeof(line));
+ if (strcmp(line, "#EXTM3U")) {
+ return AVERROR_INVALIDDATA;
+ }
+
+ while (!io->eof_reached) {
+ read_chomp_line(io, line, sizeof(line));
+ if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) {
+ hls->sequence = hls->start_sequence = atoi(ptr);
+ } else if (av_strstart(line, "#EXTINF:", &ptr)) {
+ is_segment = 1;
+ duration = atof(ptr) * AV_TIME_BASE;
+ } else if (av_strstart(line, "#", NULL)) {
+ continue;
+ } else if (line[0]) {
+ if (is_segment) {
+ append_entry(hls, duration, av_basename(line));
+ is_segment = 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
static int hls_setup(AVFormatContext *s)
{
HLSContext *hls = s->priv_data;
const char *pattern = "%d.ts";
int basename_size = strlen(s->filename) + strlen(pattern) + 1;
char *p;
+ int ret;
if (hls->encrypt)
basename_size += 7;
@@ -382,7 +447,13 @@ static int hls_setup(AVFormatContext *s)
*p = '\0';
if (hls->encrypt) {
- int ret = setup_encryption(s);
+ ret = setup_encryption(s);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (hls->start_sequence < 0) {
+ ret = hls_recover(s);
if (ret < 0)
return ret;
}
@@ -511,7 +582,8 @@ static int hls_write_trailer(struct AVFormatContext *s)
#define OFFSET(x) offsetof(HLSContext, x)
#define E AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
- {"start_number", "first number in the sequence",
OFFSET(start_sequence),AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, E},
+ {"start_number", "first number in the sequence",
OFFSET(start_sequence),AV_OPT_TYPE_INT64, {.i64 = 0}, -1, INT64_MAX, E,
"start_number"},
+ {"recover", "If there is already a m3u8 file in the path, populate the
sequence from it", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, E, "start_number"},
{"hls_time", "segment length in seconds", OFFSET(time),
AV_OPT_TYPE_FLOAT, {.dbl = 2}, 0, FLT_MAX, E},
{"hls_list_size", "maximum number of playlist entries", OFFSET(size),
AV_OPT_TYPE_INT, {.i64 = 5}, 0, INT_MAX, E},
{"hls_wrap", "number after which the index wraps", OFFSET(wrap),
AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E},
--
2.12.2
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel