[FFmpeg-devel] HLS master playlist - peak and average bandwidth settings

Submitted by Amit Kale on Feb. 5, 2018, 10:11 a.m.

Details

Message ID CANPx1XJzU+NKUs38ogm8F6XqSUQzp5R5Qek+7LXXk341ngmLog@mail.gmail.com
State New
Headers show

Commit Message

Amit Kale Feb. 5, 2018, 10:11 a.m.
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 <amitk@hotstar.com>
--
                               char *codecs, char *ccgroup);
 void ff_hls_write_playlist_header(AVIOContext *out, int version, int
allowcache,
                                   int target_duration, int64_t sequence,

Comments

Carl Eugen Hoyos Feb. 5, 2018, 12:22 p.m.
2018-02-05 11:11 GMT+01:00 Amit Kale <amitk@hotstar.com>:
> 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

This sentence indicates that you should split your patch
to ease both reviewing now and later in the history of the
changed file.

> 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.

> 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.

Please remove this from emails sent to a public mailing list (or use
another mail provider).

Carl Eugen
Amit Kale Feb. 5, 2018, 12:41 p.m.
On Mon, Feb 5, 2018 at 5:52 PM, Carl Eugen Hoyos <ceffmpeg@gmail.com> wrote:

> 2018-02-05 11:11 GMT+01:00 Amit Kale <amitk@hotstar.com>:
> > 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
>
> This sentence indicates that you should split your patch
> to ease both reviewing now and later in the history of the
> changed file.
>

Will send out split patches.


>
> > 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.
>
> > 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.
>
> Please remove this from emails sent to a public mailing list (or use
> another mail provider).
>

Apologies for being so ignorant. Will figure out a way to handle this.
Thanks.
-Amit


>
> Carl Eugen
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
Michael Niedermayer Feb. 5, 2018, 9 p.m.
On Mon, Feb 05, 2018 at 03:41:54PM +0530, Amit Kale wrote:
> 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

This patch is corrupted by linebreaks

Applying: HLS master playlist - peak and average bandwidth settings
error: corrupt patch at line 29
error: could not build fake ancestor
Patch failed at 0001 HLS master playlist - peak and average bandwidth settings
The copy of the patch that failed is found in: .git/rebase-apply/patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".


[...]

Patch hide | download patch | download mbox

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,