From patchwork Mon Feb 5 10:11:54 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amit Kale X-Patchwork-Id: 7510 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.2.150.1 with SMTP id c1csp2620502jai; Mon, 5 Feb 2018 02:18:26 -0800 (PST) X-Google-Smtp-Source: AH8x226ysDXTPZuHn4Ye7N1wCse97QNwrcEYcTLdsZuEo/6dCKTPgPrBWQVslvJtERJ3lW5GeosA X-Received: by 10.28.105.214 with SMTP id z83mr37811961wmh.77.1517825906394; Mon, 05 Feb 2018 02:18:26 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1517825906; cv=none; d=google.com; s=arc-20160816; b=hp7r4RWCexKP8BpO1fhJBQXgW/sjVNthOZ8PhYtICNb3wBjvF+ICeNnrq+QznYeCPS W2gdI/wp6S6UI5CFQ1hzP037WV3ra0Amvf881MUEDaDnFDLLGsjoEIhwwgnRm2+i7U0P 5pMHd3U5t7ftByHRkogCrOz2pDCx/ldqeKkQIal4ARupdT+IylpenGJIabzpwBy1tp/i 2nqVfKg4OSnCpK/+DG4rzilaGf6z3gRmXCkUdpBFO0i9MKwDArCjNgAxa4MBaIGDFJT4 arLVa+Zva76DYpvqozG5/6W5ITbkR1JO+DzNQ9XPgY5M5n372+qn/iE309TtfRwstvZQ 9Eog== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:to:message-id:date:from:mime-version :dkim-signature:delivered-to:arc-authentication-results; bh=9qjjDJuvWgcCz9FoJYvzq2znHYqchSa24kgQBl9xXwM=; b=JUn7jJnkVhX5kKLtrQ5MB+vzmcB5ffcYsCA8+QHxAIP15iq38AMvASzBCrRDu4Z2RY Li3nt4+tIlWBmbhVY8uqgJ3/yXnJTx0Vr3uUlQu2KIexu6HiyWPwCcJ2hATj9nlB0Dd2 yYAY+WNDMPKGcEXrZj424WxGhtUQQVAD5Eq3MMJ9M5uhUR1hKyINHKQTauFm4uYHp7b0 jMsdxtoLHGap0bEV2tCaiSBljXH0qfP7nSZpJxXHZLflhFtPyWu8gnRy656yB7rKSuj8 qJU4kCXsXR8RfGIgNkFIhl2cl2EeoFmKSMVAk2OOhmM+iyDwR0RVGsps7ZPfP/Rhsucm gUsA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@hotstar-com.20150623.gappssmtp.com header.s=20150623 header.b=oBnirMlN; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id y13si6824138wrc.2.2018.02.05.02.18.25; Mon, 05 Feb 2018 02:18:26 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@hotstar-com.20150623.gappssmtp.com header.s=20150623 header.b=oBnirMlN; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id C0D12689A95; Mon, 5 Feb 2018 12:18:16 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-yw0-f182.google.com (mail-yw0-f182.google.com [209.85.161.182]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 4D78B689A70 for ; Mon, 5 Feb 2018 12:18:10 +0200 (EET) Received: by mail-yw0-f182.google.com with SMTP id j128so17994811ywg.7 for ; Mon, 05 Feb 2018 02:18:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=hotstar-com.20150623.gappssmtp.com; s=20150623; h=mime-version:from:date:message-id:subject:to; bh=WdHr9iogifNBYDnWSJG/kI5puNkK/3YaIoHpMcMDEnU=; b=oBnirMlNQBJdUU65BunpJrx/6MveX3nCalZGbxLKlkM5OQppx+MNwC7RFsUnz6Q7c5 0XlNbI1Fl92FTt+ywUeL3sjGw+Pw0mK77tEL5+0dgjUrElPl3Sj4YU5vXHV/5jbw/B1o /Z5KSzWpd70euPHOjdRwuk1HE7IgDHJ8CB9CYl7T3qs5wcGS8MqGWjL29wF7fwnU+hSI YittAdocexJ9N0TMy0a7OoLsEYBe9uIes+8sjw5W36O4TGCe0qmxjKdIjk2ZpaYnp+hp DC6XIIeAzhtOUNCAmkJwQYD6n3cm51EjMJbe+2Qbni2t3TyUsKdzJaRgBACOv0E4Tws4 8NNA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=WdHr9iogifNBYDnWSJG/kI5puNkK/3YaIoHpMcMDEnU=; b=NMw+wn+mDbSVntB7lq4YEgmimmkxBsul72Xgfij/c5KJzau2qxEI03PlOkOyFgyK0T UMzpEsKcecamMBF3fp2enNxtCzanOlnXcvYI22jR15DksosEGOP9IckRjCtjYZSwHLfP u2gmepstsTJ+R7ehXnr19VxbK3dnatHoog2zUEJGRdS4j+Pzb1IhnBylPEfAuS5M1AUG GagnVLYQV2oAT8bI609fnn26dRHykOJTV43krr4bl9tX4QY6EH9BN04WqrqPPxB3Bwtc EmHivIkoVbYahL/EdBkFH4GoT6eIofKVRnits132ea5Vur53QvWJsuqLiwZirYpVktvD QxMA== X-Gm-Message-State: AKwxytdN2SttmmY72st5Tsp64gdCx4ZuR1FEfeoQSytwgyZPQGD5O0CT R4wDRdq+nsYM4iGADk/Vw6xz33vibunzYfeDXl1nCYhAmHrgKNtbV7wDrt1QM/R2SenjF3Qp4vA Y8EY70BwffbWVDLHpOeCbXu5S4+WhgdFU X-Received: by 10.129.52.151 with SMTP id b145mr31666713ywa.487.1517825515139; Mon, 05 Feb 2018 02:11:55 -0800 (PST) MIME-Version: 1.0 Received: by 10.37.204.18 with HTTP; Mon, 5 Feb 2018 02:11:54 -0800 (PST) From: Amit Kale Date: Mon, 5 Feb 2018 15:41:54 +0530 Message-ID: To: ffmpeg-devel@ffmpeg.org X-Content-Filtered-By: Mailman/MimeDel 2.1.20 Subject: [FFmpeg-devel] [PATCH] HLS master playlist - peak and average bandwidth settings X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" 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 --- char *codecs, char *ccgroup); void ff_hls_write_playlist_header(AVIOContext *out, int version, int allowcache, int target_duration, int64_t sequence, 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,