@@ -1898,6 +1898,42 @@ typedef struct AVFormatContext {
* - decoding: set by user
*/
int max_streams;
+
+ /**
+ * If this is set to 1, this is a live stream. Typically it will be
+ * unseekable, or allow seeking within a time window only.
+ *
+ * If this is set to 0, it is unknown what kind of stream this is. For
+ * specific protocols (such as HLS), it will indicate that it is
+ * definitely a static stream.
+ *
+ * Other values are reserved for the future, but if used will also indicate
+ * some kind of seek-restricted stream.
+ *
+ * - encoding: unused
+ * - decoding: set by libavformat
+ */
+ int is_live_stream;
+
+ /**
+ * If this field and available_range_end are set to a value other than
+ * AV_NOPTS_VALUE, they indicate the currently available media range in
+ * AV_TIME_BASE fractional seconds. This is supported by specific network
+ * protocols only, such as HLS. Generally this means you can seek within
+ * this range.
+ *
+ * - encoding: unused
+ * - decoding: set by libavformat
+ */
+ int64_t available_range_start;
+
+ /**
+ * See available_range_start field.
+ *
+ * - encoding: unused
+ * - decoding: set by libavformat
+ */
+ int64_t available_range_end;
} AVFormatContext;
#if FF_API_FORMAT_GET_SET
@@ -215,6 +215,8 @@ typedef struct HLSContext {
AVIOContext *playlist_pb;
} HLSContext;
+static int playlist_needed(struct playlist *pls);
+
static int read_chomp_line(AVIOContext *s, char *buf, int maxlen)
{
int len = ff_get_line(s, buf, maxlen);
@@ -707,6 +709,40 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url,
return ret;
}
+static void update_available_range(HLSContext *c)
+{
+ int n, i;
+
+ c->ctx->available_range_start = AV_NOPTS_VALUE;
+ c->ctx->available_range_end = AV_NOPTS_VALUE;
+ c->ctx->is_live_stream = 0;
+
+ for (n = 0; n < c->n_playlists; n++) {
+ struct playlist *pls = c->playlists[n];
+ int64_t ts;
+
+ if (!playlist_needed(pls) || !pls->n_segments)
+ continue;
+
+ // Not sure where to get the actual start timestamp - might require
+ // waiting until the first packet for every active stream on pls is read.
+ ts = c->first_timestamp == AV_NOPTS_VALUE ? 0 : c->first_timestamp;
+ if (c->ctx->available_range_start == AV_NOPTS_VALUE ||
+ c->ctx->available_range_start < ts)
+ c->ctx->available_range_start = ts;
+
+ for (i = 0; 0 < pls->n_segments; i++)
+ ts += pls->segments[i]->duration;
+
+ if (c->ctx->available_range_end == AV_NOPTS_VALUE ||
+ c->ctx->available_range_end > ts)
+ c->ctx->available_range_end = ts;
+
+ if (!pls->finished)
+ c->ctx->is_live_stream = 1;
+ }
+}
+
static int parse_playlist(HLSContext *c, const char *url,
struct playlist *pls, AVIOContext *in)
{
@@ -930,6 +966,7 @@ fail:
av_free(new_url);
if (close_in)
ff_format_io_close(c->ctx, &in);
+ update_available_range(c);
return ret;
}
@@ -138,6 +138,9 @@ static void avformat_get_context_defaults(AVFormatContext *s)
s->io_open = io_open_default;
s->io_close = io_close_default;
+ s->available_range_start = AV_NOPTS_VALUE;
+ s->available_range_end = AV_NOPTS_VALUE;
+
av_opt_set_defaults(s);
}