|
|
|
@@ -1348,25 +1348,6 @@ reload: |
|
|
|
goto restart; |
|
|
|
} |
|
|
|
|
|
|
|
static int playlist_in_multiple_variants(HLSContext *c, struct playlist *pls) |
|
|
|
{ |
|
|
|
int variant_count = 0; |
|
|
|
int i, j; |
|
|
|
|
|
|
|
for (i = 0; i < c->n_variants && variant_count < 2; i++) { |
|
|
|
struct variant *v = c->variants[i]; |
|
|
|
|
|
|
|
for (j = 0; j < v->n_playlists; j++) { |
|
|
|
if (v->playlists[j] == pls) { |
|
|
|
variant_count++; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return variant_count >= 2; |
|
|
|
} |
|
|
|
|
|
|
|
static void add_renditions_to_variant(HLSContext *c, struct variant *var, |
|
|
|
enum AVMediaType type, const char *group_id) |
|
|
|
{ |
|
|
|
@@ -1520,11 +1501,65 @@ static int nested_io_open(AVFormatContext *s, AVIOContext **pb, const char *url, |
|
|
|
return AVERROR(EPERM); |
|
|
|
} |
|
|
|
|
|
|
|
static void add_stream_to_programs(AVFormatContext *s, struct playlist *pls, AVStream *stream) |
|
|
|
{ |
|
|
|
HLSContext *c = s->priv_data; |
|
|
|
int i, j; |
|
|
|
int bandwidth = -1; |
|
|
|
|
|
|
|
for (i = 0; i < c->n_variants; i++) { |
|
|
|
struct variant *v = c->variants[i]; |
|
|
|
|
|
|
|
for (j = 0; j < v->n_playlists; j++) { |
|
|
|
if (v->playlists[j] != pls) |
|
|
|
continue; |
|
|
|
|
|
|
|
av_program_add_stream_index(s, i, stream->index); |
|
|
|
|
|
|
|
if (bandwidth < 0) |
|
|
|
bandwidth = v->bandwidth; |
|
|
|
else if (bandwidth != v->bandwidth) |
|
|
|
bandwidth = -1; /* stream in multiple variants with different bandwidths */ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (bandwidth >= 0) |
|
|
|
av_dict_set_int(&stream->metadata, "variant_bitrate", bandwidth, 0); |
|
|
|
} |
|
|
|
|
|
|
|
/* add new subdemuxer streams to our context, if any */ |
|
|
|
static int update_streams_from_subdemuxer(AVFormatContext *s, struct playlist *pls) |
|
|
|
{ |
|
|
|
while (pls->n_main_streams < pls->ctx->nb_streams) { |
|
|
|
int ist_idx = pls->n_main_streams; |
|
|
|
AVStream *st = avformat_new_stream(s, NULL); |
|
|
|
AVStream *ist = pls->ctx->streams[ist_idx]; |
|
|
|
|
|
|
|
if (!st) |
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
st->id = pls->index; |
|
|
|
|
|
|
|
avcodec_parameters_copy(st->codecpar, ist->codecpar); |
|
|
|
|
|
|
|
if (pls->is_id3_timestamped) /* custom timestamps via id3 */ |
|
|
|
avpriv_set_pts_info(st, 33, 1, MPEG_TIME_BASE); |
|
|
|
else |
|
|
|
avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den); |
|
|
|
|
|
|
|
dynarray_add(&pls->main_streams, &pls->n_main_streams, st); |
|
|
|
|
|
|
|
add_stream_to_programs(s, pls, st); |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int hls_read_header(AVFormatContext *s) |
|
|
|
{ |
|
|
|
void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; |
|
|
|
HLSContext *c = s->priv_data; |
|
|
|
int ret = 0, i, j; |
|
|
|
int ret = 0, i; |
|
|
|
int highest_cur_seq_no = 0; |
|
|
|
|
|
|
|
c->ctx = s; |
|
|
|
@@ -1600,6 +1635,17 @@ static int hls_read_header(AVFormatContext *s) |
|
|
|
add_renditions_to_variant(c, var, AVMEDIA_TYPE_SUBTITLE, var->subtitles_group); |
|
|
|
} |
|
|
|
|
|
|
|
/* Create a program for each variant */ |
|
|
|
for (i = 0; i < c->n_variants; i++) { |
|
|
|
struct variant *v = c->variants[i]; |
|
|
|
AVProgram *program; |
|
|
|
|
|
|
|
program = av_new_program(s, i); |
|
|
|
if (!program) |
|
|
|
goto fail; |
|
|
|
av_dict_set_int(&program->metadata, "variant_bitrate", v->bandwidth, 0); |
|
|
|
} |
|
|
|
|
|
|
|
/* Select the starting segments */ |
|
|
|
for (i = 0; i < c->n_playlists; i++) { |
|
|
|
struct playlist *pls = c->playlists[i]; |
|
|
|
@@ -1688,57 +1734,15 @@ static int hls_read_header(AVFormatContext *s) |
|
|
|
av_log(s, AV_LOG_WARNING, "No expected HTTP requests have been made\n"); |
|
|
|
|
|
|
|
/* Create new AVStreams for each stream in this playlist */ |
|
|
|
for (j = 0; j < pls->ctx->nb_streams; j++) { |
|
|
|
AVStream *st = avformat_new_stream(s, NULL); |
|
|
|
AVStream *ist = pls->ctx->streams[j]; |
|
|
|
if (!st) { |
|
|
|
ret = AVERROR(ENOMEM); |
|
|
|
goto fail; |
|
|
|
} |
|
|
|
st->id = i; |
|
|
|
|
|
|
|
avcodec_parameters_copy(st->codecpar, pls->ctx->streams[j]->codecpar); |
|
|
|
|
|
|
|
if (pls->is_id3_timestamped) /* custom timestamps via id3 */ |
|
|
|
avpriv_set_pts_info(st, 33, 1, MPEG_TIME_BASE); |
|
|
|
else |
|
|
|
avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den); |
|
|
|
|
|
|
|
dynarray_add(&pls->main_streams, &pls->n_main_streams, st); |
|
|
|
} |
|
|
|
ret = update_streams_from_subdemuxer(s, pls); |
|
|
|
if (ret < 0) |
|
|
|
goto fail; |
|
|
|
|
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
/* Create a program for each variant */ |
|
|
|
for (i = 0; i < c->n_variants; i++) { |
|
|
|
struct variant *v = c->variants[i]; |
|
|
|
AVProgram *program; |
|
|
|
|
|
|
|
program = av_new_program(s, i); |
|
|
|
if (!program) |
|
|
|
goto fail; |
|
|
|
av_dict_set_int(&program->metadata, "variant_bitrate", v->bandwidth, 0); |
|
|
|
|
|
|
|
for (j = 0; j < v->n_playlists; j++) { |
|
|
|
struct playlist *pls = v->playlists[j]; |
|
|
|
int is_shared = playlist_in_multiple_variants(c, pls); |
|
|
|
int k; |
|
|
|
|
|
|
|
for (k = 0; k < pls->n_main_streams; k++) { |
|
|
|
struct AVStream *st = pls->main_streams[k]; |
|
|
|
|
|
|
|
av_program_add_stream_index(s, i, st->index); |
|
|
|
|
|
|
|
/* Set variant_bitrate for streams unique to this variant */ |
|
|
|
if (!is_shared && v->bandwidth) |
|
|
|
av_dict_set_int(&st->metadata, "variant_bitrate", v->bandwidth, 0); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
fail: |
|
|
|
free_playlist_list(c); |
|
|
|
|