mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2025-02-04 13:53:26 +00:00
hlsenc: Calculate the average and actual maximum bitrate of segments
Previously, the bitrate advertised in the master playlist would only be based on the nominal values in either AVCodecParameters bit_rate, or via AVCPBProperties max_bitrate. On top of this, a fudge factor of 10% is added, to account for container overhead. Neither of these bitrates may be known, and if the encoder is running in VBR mode, there is no such value to be known. And the container overhead may be more or less than the given constant factor of 10%. Instead, calculate the maximum bitrate per segment based on what actually gets output from the muxer, and average bitrate across all segments. When muxing of the file finishes, update the master playlist with these values, exposing both the maximum (which previously was a guesstimate based on the nominal values) via EXT-X-STREAM-INF BANDWIDTH, and the average via EXT-X-STREAM-INF AVERAGE-BANDWIDTH. This makes it possible to use the hlsenc muxer with VBR encodes, for VOD style muxing. Signed-off-by: Martin Storsjö <martin@martin.st>
This commit is contained in:
parent
9246cca7f7
commit
e14cdf9990
@ -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,18 @@ 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.5) {
|
||||
// Don't include the final, possibly very short segment in the
|
||||
// calculation of the max bitrate.
|
||||
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 +1379,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 +1407,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 +1498,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 +1537,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 +1694,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);
|
||||
|
Loading…
Reference in New Issue
Block a user