@@ -1322,7 +1322,7 @@ static int write_manifest(AVFormatContext *s, int final)
av_strlcat(codec_str, audio_codec_str, sizeof(codec_str));
}
get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i);
- ff_hls_write_stream_info(st, c->m3u8_out, stream_bitrate,
+ ff_hls_write_stream_info(st, c->m3u8_out, stream_bitrate, 0,
playlist_file, agroup,
codec_str, NULL, NULL);
}
@@ -1348,7 +1348,7 @@ static int write_manifest(AVFormatContext *s, int final)
continue;
av_strlcpy(codec_str, os->codec_str, sizeof(codec_str));
get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i);
- ff_hls_write_stream_info(st, c->m3u8_out, stream_bitrate,
+ ff_hls_write_stream_info(st, c->m3u8_out, stream_bitrate, 0,
playlist_file, NULL,
codec_str, NULL, NULL);
}
@@ -150,6 +150,11 @@ typedef struct VariantStream {
int discontinuity;
int reference_stream_index;
+ int64_t total_size;
+ double total_duration;
+ int64_t avg_bitrate;
+ int64_t max_bitrate;
+
HLSSegment *segments;
HLSSegment *last_segment;
HLSSegment *old_segments;
@@ -1108,6 +1113,16 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls,
if (!en)
return AVERROR(ENOMEM);
+ vs->total_size += size;
+ vs->total_duration += duration;
+ if (duration > 0) {
+ int cur_bitrate = (int)(8 * size / duration);
+ if (cur_bitrate > vs->max_bitrate)
+ vs->max_bitrate = cur_bitrate;
+ }
+ if (vs->total_duration > 0)
+ vs->avg_bitrate = (int)(8 * vs->total_size / vs->total_duration);
+
en->var_stream_idx = vs->var_stream_idx;
ret = sls_flags_filename_process(s, hls, vs, en, duration, pos, size);
if (ret < 0) {
@@ -1362,14 +1377,15 @@ static int64_t get_stream_bit_rate(AVStream *stream)
}
static int create_master_playlist(AVFormatContext *s,
- VariantStream * const input_vs)
+ VariantStream * const input_vs,
+ int final)
{
HLSContext *hls = s->priv_data;
VariantStream *vs, *temp_vs;
AVStream *vid_st, *aud_st;
AVDictionary *options = NULL;
unsigned int i, j;
- int ret, bandwidth;
+ int ret, bandwidth, avg_bandwidth;
const char *m3u8_rel_name = NULL;
const char *vtt_m3u8_rel_name = NULL;
const char *ccgroup;
@@ -1389,8 +1405,8 @@ static int create_master_playlist(AVFormatContext *s,
return 0;
} else {
/* Keep publishing the master playlist at the configured rate */
- if (&hls->var_streams[0] != input_vs || !hls->master_publish_rate ||
- input_vs->number % hls->master_publish_rate)
+ if ((&hls->var_streams[0] != input_vs || !hls->master_publish_rate ||
+ input_vs->number % hls->master_publish_rate) && !final)
return 0;
}
@@ -1480,12 +1496,17 @@ static int create_master_playlist(AVFormatContext *s,
}
}
- bandwidth = 0;
- if (vid_st)
- bandwidth += get_stream_bit_rate(vid_st);
- if (aud_st)
- bandwidth += get_stream_bit_rate(aud_st);
- bandwidth += bandwidth / 10;
+ if (final) {
+ bandwidth = vs->max_bitrate;
+ avg_bandwidth = vs->avg_bitrate;
+ } else {
+ bandwidth = 0;
+ if (vid_st)
+ bandwidth += get_stream_bit_rate(vid_st);
+ if (aud_st)
+ bandwidth += get_stream_bit_rate(aud_st);
+ bandwidth += bandwidth / 10;
+ }
ccgroup = NULL;
if (vid_st && vs->ccgroup) {
@@ -1514,11 +1535,11 @@ static int create_master_playlist(AVFormatContext *s,
}
if (!hls->has_default_key || !hls->has_video_m3u8) {
- ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, m3u8_rel_name,
+ ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, avg_bandwidth, m3u8_rel_name,
aud_st ? vs->agroup : NULL, vs->codec_attr, ccgroup, sgroup);
} else {
if (vid_st) {
- ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, m3u8_rel_name,
+ ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, avg_bandwidth, m3u8_rel_name,
aud_st ? vs->agroup : NULL, vs->codec_attr, ccgroup, sgroup);
}
}
@@ -1671,7 +1692,7 @@ fail:
ff_rename(temp_vtt_filename, vs->vtt_m3u8_name, s);
}
if (ret >= 0 && hls->master_pl_name)
- if (create_master_playlist(s, vs) < 0)
+ if (create_master_playlist(s, vs, last) < 0)
av_log(s, AV_LOG_WARNING, "Master playlist creation failed\n");
return ret;
@@ -71,6 +71,7 @@ void ff_hls_write_subtitle_rendition(AVIOContext *out, const char *sgroup,
}
void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, int bandwidth,
+ int avg_bandwidth,
const char *filename, const char *agroup,
const char *codecs, const char *ccgroup,
const char *sgroup)
@@ -85,6 +86,8 @@ void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, int bandwidth,
}
avio_printf(out, "#EXT-X-STREAM-INF:BANDWIDTH=%d", bandwidth);
+ if (avg_bandwidth)
+ avio_printf(out, ",AVERAGE-BANDWIDTH=%d", avg_bandwidth);
if (st && st->codecpar->width > 0 && st->codecpar->height > 0)
avio_printf(out, ",RESOLUTION=%dx%d", st->codecpar->width,
st->codecpar->height);
@@ -43,6 +43,7 @@ void ff_hls_write_subtitle_rendition(AVIOContext *out, const char *sgroup,
const char *filename, const char *language,
int name_id, int is_default);
void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, int bandwidth,
+ int avg_bandwidth,
const char *filename, const char *agroup,
const char *codecs, const char *ccgroup,
const char *sgroup);