summaryrefslogtreecommitdiff
path: root/libavformat/hlsenc.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavformat/hlsenc.c')
-rw-r--r--libavformat/hlsenc.c54
1 files changed, 43 insertions, 11 deletions
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index a2c606cb6e..3bb15d3f92 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -39,6 +39,12 @@
#include "internal.h"
#include "os_support.h"
+typedef enum {
+ HLS_START_SEQUENCE_AS_START_NUMBER = 0,
+ HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH = 1,
+ HLS_START_SEQUENCE_AS_FORMATTED_DATETIME = 2, // YYYYMMDDhhmmss
+} StartSequenceSourceType;
+
#define KEYSIZE 16
#define LINE_BUFFER_SIZE 1024
@@ -83,6 +89,7 @@ typedef struct HLSContext {
unsigned number;
int64_t sequence;
int64_t start_sequence;
+ uint32_t start_sequence_source_type; // enum StartSequenceSourceType
AVOutputFormat *oformat;
AVOutputFormat *vtt_oformat;
@@ -594,7 +601,16 @@ static int parse_playlist(AVFormatContext *s, const char *url)
while (!avio_feof(in)) {
read_chomp_line(in, line, sizeof(line));
if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) {
- hls->sequence = atoi(ptr);
+ int64_t tmp_sequence = strtoll(ptr, NULL, 10);
+ if (tmp_sequence < hls->sequence)
+ av_log(hls, AV_LOG_VERBOSE,
+ "Found playlist sequence number was smaller """
+ "than specified start sequence number: %"PRId64" < %"PRId64", "
+ "omitting\n", tmp_sequence, hls->start_sequence);
+ else {
+ av_log(hls, AV_LOG_DEBUG, "Found playlist sequence number: %"PRId64"\n", tmp_sequence);
+ hls->sequence = tmp_sequence;
+ }
} else if (av_strstart(line, "#EXT-X-DISCONTINUITY", &ptr)) {
is_segment = 1;
hls->discontinuity = 1;
@@ -805,9 +821,8 @@ static int hls_start(AVFormatContext *s)
av_strlcpy(vtt_oc->filename, c->vtt_basename,
sizeof(vtt_oc->filename));
} else if (c->max_seg_size > 0) {
- if (av_get_frame_filename2(oc->filename, sizeof(oc->filename),
- c->basename, c->wrap ? c->sequence % c->wrap : c->sequence,
- AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) {
+ if (replace_int_data_in_filename(oc->filename, sizeof(oc->filename),
+ c->basename, 'd', c->wrap ? c->sequence % c->wrap : c->sequence) < 1) {
av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s', you can try to use -use_localtime 1 with it\n", c->basename);
return AVERROR(EINVAL);
}
@@ -882,16 +897,14 @@ static int hls_start(AVFormatContext *s)
}
av_free(fn_copy);
}
- } else if (av_get_frame_filename2(oc->filename, sizeof(oc->filename),
- c->basename, c->wrap ? c->sequence % c->wrap : c->sequence,
- AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) {
+ } else if (replace_int_data_in_filename(oc->filename, sizeof(oc->filename),
+ c->basename, 'd', c->wrap ? c->sequence % c->wrap : c->sequence) < 1) {
av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s' you can try to use -use_localtime 1 with it\n", c->basename);
return AVERROR(EINVAL);
}
if( c->vtt_basename) {
- if (av_get_frame_filename2(vtt_oc->filename, sizeof(vtt_oc->filename),
- c->vtt_basename, c->wrap ? c->sequence % c->wrap : c->sequence,
- AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) {
+ if (replace_int_data_in_filename(vtt_oc->filename, sizeof(vtt_oc->filename),
+ c->vtt_basename, 'd', c->wrap ? c->sequence % c->wrap : c->sequence) < 1) {
av_log(vtt_oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", c->vtt_basename);
return AVERROR(EINVAL);
}
@@ -979,6 +992,22 @@ static int hls_write_header(AVFormatContext *s)
int basename_size;
int vtt_basename_size;
+ if (hls->start_sequence_source_type == HLS_START_SEQUNCE_AS_SECONDS_SINCE_EPOCH || hls->start_sequence_source_type == HLS_START_SEQUNCE_AS_FORMATTED_DATETIME) {
+ time_t t = time(NULL); // we will need it in either case
+ if (hls->start_sequence_source_type == HLS_START_SEQUNCE_AS_SECONDS_SINCE_EPOCH) {
+ hls->start_sequence = (int64_t)t;
+ } else if (hls->start_sequence_source_type == HLS_START_SEQUNCE_AS_FORMATTED_DATETIME) {
+ char b[15];
+ struct tm *p, tmbuf;
+ if (!(p = localtime_r(&t, &tmbuf)))
+ return AVERROR(ENOMEM);
+ if (!strftime(b, sizeof(b), "%Y%m%d%H%M%S", p))
+ return AVERROR(ENOMEM);
+ hls->start_sequence = strtoll(b, NULL, 10);
+ }
+ av_log(hls, AV_LOG_DEBUG, "start_number evaluated to %"PRId64"\n", hls->start_sequence);
+ }
+
hls->sequence = hls->start_sequence;
hls->recording_time = (hls->init_time ? hls->init_time : hls->time) * AV_TIME_BASE;
hls->start_pts = AV_NOPTS_VALUE;
@@ -1366,7 +1395,10 @@ static const AVOption options[] = {
{"event", "EVENT playlist", 0, AV_OPT_TYPE_CONST, {.i64 = PLAYLIST_TYPE_EVENT }, INT_MIN, INT_MAX, E, "pl_type" },
{"vod", "VOD playlist", 0, AV_OPT_TYPE_CONST, {.i64 = PLAYLIST_TYPE_VOD }, INT_MIN, INT_MAX, E, "pl_type" },
{"method", "set the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
-
+ {"hls_start_number_source", "set source of first number in sequence", OFFSET(start_sequence_source_type), AV_OPT_TYPE_INT, {.i64 = HLS_START_SEQUNCE_AS_START_NUMBER }, 0, HLS_START_SEQUNCE_AS_FORMATTED_DATETIME, E, "start_sequence_source_type" },
+ {"generic", "start_number value (default)", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_START_SEQUNCE_AS_START_NUMBER }, INT_MIN, INT_MAX, E, "start_sequence_source_type" },
+ {"epoch", "seconds since epoch", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_START_SEQUNCE_AS_SECONDS_SINCE_EPOCH }, INT_MIN, INT_MAX, E, "start_sequence_source_type" },
+ {"datetime", "current datetime as YYYYMMDDhhmmss", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_START_SEQUNCE_AS_FORMATTED_DATETIME }, INT_MIN, INT_MAX, E, "start_sequence_source_type" },
{ NULL },
};