int64_t first_timestamp;
int64_t cur_timestamp;
AVIOInterruptCB *interrupt_callback;
+ char *referer; ///< holds HTTP referer set as an AVOption to the HTTP protocol context
char *user_agent; ///< holds HTTP user agent set as an AVOption to the HTTP protocol context
char *cookies; ///< holds HTTP cookie values set in either the initial response or as an AVOption to the HTTP protocol context
char *headers; ///< holds HTTP headers set as an AVOption to the HTTP protocol context
static int open_url_keepalive(AVFormatContext *s, AVIOContext **pb,
const char *url)
{
+#if !CONFIG_HTTP_PROTOCOL
+ return AVERROR_PROTOCOL_NOT_FOUND;
+#else
int ret;
URLContext *uc = ffio_geturlcontext(*pb);
av_assert0(uc);
ff_format_io_close(s, pb);
}
return ret;
+#endif
}
static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url,
- AVDictionary *opts, AVDictionary *opts2, int *is_http)
+ AVDictionary *opts, AVDictionary *opts2, int *is_http_out)
{
HLSContext *c = s->priv_data;
AVDictionary *tmp = NULL;
const char *proto_name = NULL;
int ret;
+ int is_http = 0;
av_dict_copy(&tmp, opts, 0);
av_dict_copy(&tmp, opts2, 0);
return AVERROR_INVALIDDATA;
}
} else if (av_strstart(proto_name, "http", NULL)) {
- ;
+ is_http = 1;
} else
return AVERROR_INVALIDDATA;
else if (strcmp(proto_name, "file") || !strncmp(url, "file,", 5))
return AVERROR_INVALIDDATA;
- if (c->http_persistent && *pb && av_strstart(proto_name, "http", NULL)) {
+ if (is_http && c->http_persistent && *pb) {
ret = open_url_keepalive(c->ctx, pb, url);
if (ret == AVERROR_EXIT) {
return ret;
av_dict_free(&tmp);
- if (is_http)
- *is_http = av_strstart(proto_name, "http", NULL);
+ if (is_http_out)
+ *is_http_out = is_http;
return ret;
}
struct variant_info variant_info;
char tmp_str[MAX_URL_SIZE];
struct segment *cur_init_section = NULL;
+ int is_http = av_strstart(url, "http", NULL);
- if (!in && c->http_persistent && c->playlist_pb) {
+ if (is_http && !in && c->http_persistent && c->playlist_pb) {
in = c->playlist_pb;
ret = open_url_keepalive(c->ctx, &c->playlist_pb, url);
if (ret == AVERROR_EXIT) {
if (ret < 0)
return ret;
- if (c->http_persistent)
+ if (is_http && c->http_persistent)
c->playlist_pb = in;
else
close_in = 1;
av_free(new_url);
if (close_in)
ff_format_io_close(c->ctx, &in);
+ c->ctx->ctx_flags = c->ctx->ctx_flags & ~(unsigned)AVFMTCTX_UNSEEKABLE;
+ if (!c->n_variants || !c->variants[0]->n_playlists ||
+ !(c->variants[0]->playlists[0]->finished ||
+ c->variants[0]->playlists[0]->type == PLS_TYPE_EVENT))
+ c->ctx->ctx_flags |= AVFMTCTX_UNSEEKABLE;
return ret;
}
/* demuxer not yet opened, defer picture attachment */
pls->id3_deferred_extra = extra_meta;
+ ff_id3v2_parse_priv_dict(&metadata, &extra_meta);
av_dict_copy(&pls->ctx->metadata, metadata, 0);
pls->id3_initial = metadata;
// broker prior HTTP options that should be consistent across requests
av_dict_set(&opts, "user_agent", c->user_agent, 0);
+ av_dict_set(&opts, "referer", c->referer, 0);
av_dict_set(&opts, "cookies", c->cookies, 0);
av_dict_set(&opts, "headers", c->headers, 0);
av_dict_set(&opts, "http_proxy", c->http_proxy, 0);
AVDictionary *opts2 = NULL;
char iv[33], key[33], url[MAX_URL_SIZE];
if (strcmp(seg->key, pls->key_url)) {
- AVIOContext *pb;
+ AVIOContext *pb = NULL;
if (open_url(pls->parent, &pb, seg->key, c->avio_opts, opts, NULL) == 0) {
ret = avio_read(pb, pls->key, sizeof(pls->key));
if (ret != sizeof(pls->key)) {
if (!v->finished &&
av_gettime_relative() - v->last_load_time >= reload_interval) {
if ((ret = parse_playlist(c, v->url, v, NULL)) < 0) {
- av_log(v->parent, AV_LOG_WARNING, "Failed to reload playlist %d\n",
- v->index);
+ if (ret != AVERROR_EXIT)
+ av_log(v->parent, AV_LOG_WARNING, "Failed to reload playlist %d\n",
+ v->index);
return ret;
}
/* If we need to reload the playlist again below (if
if (ret)
return ret;
- if (c->http_multiple && av_strstart(seg->url, "http", NULL) && v->input_next_requested) {
+ if (c->http_multiple == 1 && v->input_next_requested) {
FFSWAP(AVIOContext *, v->input, v->input_next);
v->input_next_requested = 0;
ret = 0;
just_opened = 1;
}
+ if (c->http_multiple == -1) {
+ uint8_t *http_version_opt = NULL;
+ int r = av_opt_get(v->input, "http_version", AV_OPT_SEARCH_CHILDREN, &http_version_opt);
+ if (r >= 0) {
+ c->http_multiple = strncmp((const char *)http_version_opt, "1.1", 3) == 0;
+ av_freep(&http_version_opt);
+ }
+ }
+
seg = next_segment(v);
- if (c->http_multiple && !v->input_next_requested && seg) {
+ if (c->http_multiple == 1 && !v->input_next_requested &&
+ seg && seg->key_type == KEY_NONE && av_strstart(seg->url, "http", NULL)) {
ret = open_input(c, v, seg, &v->input_next);
if (ret < 0) {
if (ff_check_interrupt(c->interrupt_callback))
return copy_size;
}
- ret = read_from_url(v, current_segment(v), buf, buf_size, READ_NORMAL);
+ seg = current_segment(v);
+ ret = read_from_url(v, seg, buf, buf_size, READ_NORMAL);
if (ret > 0) {
if (just_opened && v->is_id3_timestamped != 0) {
/* Intercept ID3 tags here, elementary audio streams are required
return ret;
}
- if (c->http_persistent) {
+ if (c->http_persistent &&
+ seg->key_type == KEY_NONE && av_strstart(seg->url, "http", NULL)) {
v->input_read_done = 1;
} else {
ff_format_io_close(v->parent, &v->input);
{
HLSContext *c = s->priv_data;
static const char * const opts[] = {
- "headers", "http_proxy", "user_agent", "user-agent", "cookies", NULL };
+ "headers", "http_proxy", "user_agent", "user-agent", "cookies", "referer", NULL };
const char * const * opt = opts;
uint8_t *buf;
int ret = 0;
av_log(s, AV_LOG_ERROR,
"A HLS playlist item '%s' referred to an external file '%s'. "
"Opening this file was forbidden for security reasons\n",
- s->filename, url);
+ s->url, url);
return AVERROR(EPERM);
}
update_options(&c->http_proxy, "http_proxy", u);
}
- if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0)
+ if ((ret = parse_playlist(c, s->url, NULL, s->pb)) < 0)
goto fail;
if ((ret = save_avio_options(s)) < 0)
if (pls->id3_deferred_extra && pls->ctx->nb_streams == 1) {
ff_id3v2_parse_apic(pls->ctx, &pls->id3_deferred_extra);
avformat_queue_attached_pictures(pls->ctx);
+ ff_id3v2_parse_priv(pls->ctx, &pls->id3_deferred_extra);
ff_id3v2_free_extra_meta(&pls->id3_deferred_extra);
pls->id3_deferred_extra = NULL;
}
if (ret < 0)
goto fail;
+ /*
+ * Copy any metadata from playlist to main streams, but do not set
+ * event flags.
+ */
+ if (pls->n_main_streams)
+ av_dict_copy(&pls->main_streams[0]->metadata, pls->ctx->metadata, 0);
+
add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_AUDIO);
add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_VIDEO);
add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_SUBTITLE);
return ret;
}
+ // If sub-demuxer reports updated metadata, copy it to the first stream
+ // and set its AVSTREAM_EVENT_FLAG_METADATA_UPDATED flag.
+ if (pls->ctx->event_flags & AVFMT_EVENT_FLAG_METADATA_UPDATED) {
+ if (pls->n_main_streams) {
+ st = pls->main_streams[0];
+ av_dict_copy(&st->metadata, pls->ctx->metadata, 0);
+ st->event_flags |= AVSTREAM_EVENT_FLAG_METADATA_UPDATED;
+ }
+ pls->ctx->event_flags &= ~AVFMT_EVENT_FLAG_METADATA_UPDATED;
+ }
+
/* check if noheader flag has been cleared by the subdemuxer */
if (pls->has_noheader_flag && !(pls->ctx->ctx_flags & AVFMTCTX_NOHEADER)) {
pls->has_noheader_flag = 0;
int stream_subdemuxer_index;
int64_t first_timestamp, seek_timestamp, duration;
- if ((flags & AVSEEK_FLAG_BYTE) ||
- !(c->variants[0]->playlists[0]->finished || c->variants[0]->playlists[0]->type == PLS_TYPE_EVENT))
+ if ((flags & AVSEEK_FLAG_BYTE) || (c->ctx->ctx_flags & AVFMTCTX_UNSEEKABLE))
return AVERROR(ENOSYS);
first_timestamp = c->first_timestamp == AV_NOPTS_VALUE ?
{"http_persistent", "Use persistent HTTP connections",
OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS },
{"http_multiple", "Use multiple HTTP connections for fetching segments",
- OFFSET(http_multiple), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS},
+ OFFSET(http_multiple), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, FLAGS},
{NULL}
};
.long_name = NULL_IF_CONFIG_SMALL("Apple HTTP Live Streaming"),
.priv_class = &hls_class,
.priv_data_size = sizeof(HLSContext),
+ .flags = AVFMT_NOGENSEARCH,
.read_probe = hls_probe,
.read_header = hls_read_header,
.read_packet = hls_read_packet,