Hi, Kindly below a patch to add peak and average bandwidth settings for HLS master playlist. It adds two hls_flags as described below.
peak_segment_bw If this flag is set, BANDWIDTH value in a master playlist entry will be set to the peak segment bandwidth. avg_bw If this flag is set, AVERAGE-BANDWIDTH value will be added to a master playlist entry. This flag implies peak_segment_bw. It changes behaviors of other codepaths as follows 1. Corrects setting of start_pos single file is not used in hls_write_packet. 2. Adds a new parameter avgbw to ff_hls_write_playlist_version. If this parameter is non-null AVERAGE-BANDWIDTH is emitted. Thanks. -Amit Signed-off-by: Amit Kale <am...@hotstar.com> -- diff --git a/doc/muxers.texi b/doc/muxers.texi index d9a5cc03dc..428d4009b3 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -741,6 +741,14 @@ subdirectories. Possible values: @table @samp +@item peak_segment_bw +If this flag is set, BANDWIDTH value in a master playlist entry will be +set to the peak segment bandwidth. + +@item avg_bw +If this flag is set, AVERAGE-BANDWIDTH value will be added to a master +playlist entry. This flag implies peak_segment_bw. + @item single_file If this flag is set, the muxer will store all segments in a single MPEG-TS file, and will use byte ranges in the playlist. HLS playlists generated with diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c index 0f6f4f22fa..a918f7e649 100644 --- a/libavformat/dashenc.c +++ b/libavformat/dashenc.c @@ -827,7 +827,7 @@ static int write_manifest(AVFormatContext *s, int final) stream_bitrate += max_audio_bitrate; } get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i); - ff_hls_write_stream_info(st, out, stream_bitrate, playlist_file, agroup, NULL, NULL); + ff_hls_write_stream_info(st, out, stream_bitrate, 0, playlist_file, agroup, NULL, NULL); } avio_close(out); if (use_rename) diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index cc13c94e97..e1592e0577 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -98,6 +98,8 @@ typedef enum HLSFlags { HLS_TEMP_FILE = (1 << 11), HLS_PERIODIC_REKEY = (1 << 12), HLS_INDEPENDENT_SEGMENTS = (1 << 13), + HLS_PEAK_SEGMENT_BW = (1 << 14), + HLS_AVG_BW = (1 << 15), } HLSFlags; typedef enum { @@ -112,11 +114,14 @@ typedef struct VariantStream { AVOutputFormat *vtt_oformat; AVIOContext *out; int packets_written; + int64_t bytes_written; + double total_duration; int init_range_length; AVFormatContext *avf; AVFormatContext *vtt_avf; + int avg_bandwidth; int has_video; int has_subtitle; int new_start; @@ -1168,14 +1173,15 @@ static int get_relative_url(const char *master_url, const char *media_url, } static int create_master_playlist(AVFormatContext *s, - VariantStream * const input_vs) + VariantStream * const input_vs, + int last) { HLSContext *hls = s->priv_data; VariantStream *vs, *temp_vs; AVStream *vid_st, *aud_st; AVDictionary *options = NULL; unsigned int i, j; - int m3u8_name_size, ret, bandwidth; + int m3u8_name_size, ret, bandwidth, avgbw; char *m3u8_rel_name, *ccgroup; ClosedCaptionsStream *ccs; @@ -1185,7 +1191,7 @@ static int create_master_playlist(AVFormatContext *s, for (i = 0; i < hls->nb_varstreams; i++) if (!hls->var_streams[i].m3u8_created) return 0; - } else { + } else if (!last) { /* 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) @@ -1290,13 +1296,28 @@ static int create_master_playlist(AVFormatContext *s, } } } - - bandwidth = 0; - if (vid_st) - bandwidth += vid_st->codecpar->bit_rate; - if (aud_st) - bandwidth += aud_st->codecpar->bit_rate; - bandwidth += bandwidth / 10; + + avgbw = 0; + if (last && (hls->flags & HLS_PEAK_SEGMENT_BW || hls->flags & HLS_AVG_BW)) { + HLSSegment *hs = vs->segments; + bandwidth = 0; + while (hs) { + int64_t segment_bandwidth = hs->size * 8 / hs->duration; + if (bandwidth < segment_bandwidth) + bandwidth = segment_bandwidth; + hs = hs->next; + } + if (hls->flags & HLS_AVG_BW) + avgbw = vs->bytes_written / vs->total_duration; + } else { + bandwidth = 0; + avgbw = 0; + if (vid_st) + bandwidth += vid_st->codecpar->bit_rate; + if (aud_st) + bandwidth += aud_st->codecpar->bit_rate; + bandwidth += bandwidth / 10; + } ccgroup = NULL; if (vid_st && vs->ccgroup) { @@ -1313,7 +1334,7 @@ static int create_master_playlist(AVFormatContext *s, vs->ccgroup); } - 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, avgbw, m3u8_rel_name, aud_st ? vs->agroup : NULL, vs->codec_attr, ccgroup); av_freep(&m3u8_rel_name); @@ -1437,7 +1458,7 @@ fail: ff_rename(temp_filename, vs->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; @@ -2179,6 +2200,8 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) new_start_pos = avio_tell(vs->avf->pb); vs->size = new_start_pos - vs->start_pos; + vs->bytes_written += vs->size; + vs->total_duration += vs->duration; if (!byterange_mode) { if (hls->segment_type == SEGMENT_TYPE_FMP4) { @@ -2227,7 +2250,11 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) ff_format_io_close(s, &vs->out); } ret = hls_append_segment(s, hls, vs, vs->duration, vs->start_pos, vs->size); - vs->start_pos = new_start_pos; + + if (hls->flags & HLS_SINGLE_FILE) + vs->start_pos = new_start_pos; + else + vs->start_pos = 0; if (ret < 0) { av_free(old_filename); return ret; @@ -2268,7 +2295,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) vs->packets_written++; ret = ff_write_chained(oc, stream_index, pkt, s, 0); - + return ret; } @@ -2311,6 +2338,9 @@ failed: av_write_trailer(oc); if (oc->pb) { vs->size = avio_tell(vs->avf->pb) - vs->start_pos; + vs->bytes_written += vs->size; + vs->total_duration += vs->duration; + if (hls->segment_type != SEGMENT_TYPE_FMP4) ff_format_io_close(s, &oc->pb); @@ -2750,6 +2780,8 @@ static const AVOption options[] = { {"fmp4", "make segment file to fragment mp4 files in m3u8", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_FMP4 }, 0, UINT_MAX, E, "segment_type"}, {"hls_fmp4_init_filename", "set fragment mp4 file init filename", OFFSET(fmp4_init_filename), AV_OPT_TYPE_STRING, {.str = "init.mp4"}, 0, 0, E}, {"hls_flags", "set flags affecting HLS playlist and media file generation", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, 0, UINT_MAX, E, "flags"}, + {"avg_bandwidth", "sets AVERAGE-BANDWIDTH in master play list, implies peak_segment_bw flag", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_AVG_BW }, 0, UINT_MAX, E, "flags"}, + {"peak_segment_bw", "sets bandwidth in master play list to peak segment bandwidth", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_PEAK_SEGMENT_BW }, 0, UINT_MAX, E, "flags"}, {"single_file", "generate a single media file indexed with byte ranges", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SINGLE_FILE }, 0, UINT_MAX, E, "flags"}, {"temp_file", "write segment to temporary file and rename when complete", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_TEMP_FILE }, 0, UINT_MAX, E, "flags"}, {"delete_segments", "delete segment files that are no longer part of the playlist", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_DELETE_SEGMENTS }, 0, UINT_MAX, E, "flags"}, diff --git a/libavformat/hlsplaylist.c b/libavformat/hlsplaylist.c index efcbff0009..e101cb7777 100644 --- a/libavformat/hlsplaylist.c +++ b/libavformat/hlsplaylist.c @@ -46,7 +46,7 @@ void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup, } void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, - int bandwidth, char *filename, char *agroup, + int bandwidth, int avgbw, char *filename, char *agroup, char *codecs, char *ccgroup) { if (!out || !filename) @@ -59,6 +59,8 @@ void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, } avio_printf(out, "#EXT-X-STREAM-INF:BANDWIDTH=%d", bandwidth); + if (avgbw != 0) + avio_printf(out, ",AVERAGE-BANDWIDTH=%d", avgbw); if (st && st->codecpar->width > 0 && st->codecpar->height > 0) avio_printf(out, ",RESOLUTION=%dx%d", st->codecpar->width, st->codecpar->height); diff --git a/libavformat/hlsplaylist.h b/libavformat/hlsplaylist.h index 5054b01c8f..2b7970b4c5 100644 --- a/libavformat/hlsplaylist.h +++ b/libavformat/hlsplaylist.h @@ -40,7 +40,7 @@ void ff_hls_write_playlist_version(AVIOContext *out, int version); void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup, char *filename, int name_id, int is_default); void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, - int bandwidth, char *filename, char *agroup, + int bandwidth, int avgbw, char *filename, char *agroup, char *codecs, char *ccgroup); void ff_hls_write_playlist_header(AVIOContext *out, int version, int allowcache, int target_duration, int64_t sequence, -- This message and its attachments are confidential (or legally privileged) information and are meant solely for the addressee of such message. Any unauthorized use of the message / its attachments is strictly prohibited. _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel