[FFmpeg-devel,v3,11/11] avformat/dashenc: addition of segment index correction logic

Submitted by Dixit, Vishwanath on April 11, 2018, 7:02 a.m.

Details

Message ID 1523430145-17663-1-git-send-email-vdixit@akamai.com
State New
Headers show

Commit Message

Dixit, Vishwanath April 11, 2018, 7:02 a.m.
From: Vishwanath Dixit <vdixit@akamai.com>

The logic is applicable only when use_template is enabled and use_timeline
is disabled. The logic monitors the flow of segment indexes. If a streams's
segment index value is not at the expected real time position, then
the logic corrects that index value.

Typically this logic is needed in live streaming use cases. The network
bandwidth fluctuations are common during long run streaming. Each
fluctuation can cause the segment indexes fall behind the expected real
time position. Without this logic, players will not be able to consume
the content, even after encoder's network condition comes back to
normal state.
---
 doc/muxers.texi       | 11 +++++++++++
 libavformat/dashenc.c | 31 ++++++++++++++++++++++++++-----
 2 files changed, 37 insertions(+), 5 deletions(-)

Patch hide | download patch | download mbox

diff --git a/doc/muxers.texi b/doc/muxers.texi
index e1b6666..fa528b6 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -271,6 +271,17 @@  To map all video (or audio) streams to an AdaptationSet, "v" (or "a") can be use
 When no assignment is defined, this defaults to an AdaptationSet for each stream.
 @item -timeout @var{timeout}
 Set timeout for socket I/O operations. Applicable only for HTTP output.
+@item -index_correction @var{index_correction}
+Enable (1) or Disable (0) segment index correction logic. Applicable only when
+@var{use_template} is enabled and @var{use_timeline} is disabled.
+
+When enabled, the logic monitors the flow of segment indexes. If a streams's
+segment index value is not at the expected real time position, then the logic
+corrects that index value.
+
+Typically this logic is needed in live streaming use cases. The network bandwidth
+fluctuations are common during long run streaming. Each fluctuation can cause
+the segment indexes fall behind the expected real time position.
 @end table
 
 @anchor{framecrc}
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index bf8698f..9e72636 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -76,7 +76,7 @@  typedef struct OutputStream {
     int nb_segments, segments_size, segment_index;
     Segment **segments;
     int64_t first_pts, start_pts, max_pts;
-    int64_t last_dts;
+    int64_t last_dts, last_pts;
     int bit_rate;
 
     char codec_str[100];
@@ -123,6 +123,7 @@  typedef struct DASHContext {
     AVIOContext *m3u8_out;
     int streaming;
     int64_t timeout;
+    int index_correction;
 } DASHContext;
 
 static struct codec_string {
@@ -1060,7 +1061,7 @@  static int dash_write_header(AVFormatContext *s)
 static int add_segment(OutputStream *os, const char *file,
                        int64_t time, int duration,
                        int64_t start_pos, int64_t range_length,
-                       int64_t index_length)
+                       int64_t index_length, int next_exp_index)
 {
     int err;
     Segment *seg;
@@ -1088,6 +1089,12 @@  static int add_segment(OutputStream *os, const char *file,
     seg->index_length = index_length;
     os->segments[os->nb_segments++] = seg;
     os->segment_index++;
+    //correcting the segment index if it has fallen behind the expected value
+    if (os->segment_index < next_exp_index) {
+        av_log(NULL, AV_LOG_WARNING, "Correcting the segment index after file %s: current=%d corrected=%d\n",
+               file, os->segment_index, next_exp_index);
+        os->segment_index = next_exp_index;
+    }
     return 0;
 }
 
@@ -1177,10 +1184,22 @@  static int dash_flush(AVFormatContext *s, int final, int stream)
     const char *proto = avio_find_protocol_name(s->url);
     int use_rename = proto && !strcmp(proto, "file");
 
-    int cur_flush_segment_index = 0;
-    if (stream >= 0)
+    int cur_flush_segment_index = 0, next_exp_index = -1;
+    if (stream >= 0) {
         cur_flush_segment_index = c->streams[stream].segment_index;
 
+        //finding the next segment's expected index, based on the current pts value
+        if (c->use_template && !c->use_timeline && c->index_correction &&
+            c->streams[stream].last_pts != AV_NOPTS_VALUE &&
+            c->streams[stream].first_pts != AV_NOPTS_VALUE) {
+            int64_t pts_diff = av_rescale_q(c->streams[stream].last_pts -
+                                            c->streams[stream].first_pts,
+                                            s->streams[stream]->time_base,
+                                            AV_TIME_BASE_Q);
+            next_exp_index = (pts_diff / c->seg_duration) + 1;
+        }
+    }
+
     for (i = 0; i < s->nb_streams; i++) {
         OutputStream *os = &c->streams[i];
         AVStream *st = s->streams[i];
@@ -1240,7 +1259,7 @@  static int dash_flush(AVFormatContext *s, int final, int stream)
             if (bitrate >= 0)
                 os->bit_rate = bitrate;
         }
-        add_segment(os, os->filename, os->start_pts, os->max_pts - os->start_pts, os->pos, range_length, index_length);
+        add_segment(os, os->filename, os->start_pts, os->max_pts - os->start_pts, os->pos, range_length, index_length, next_exp_index);
         av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written to: %s\n", i, os->segment_index, os->full_path);
 
         os->pos += range_length;
@@ -1303,6 +1322,7 @@  static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
 
     if (os->first_pts == AV_NOPTS_VALUE)
         os->first_pts = pkt->pts;
+    os->last_pts = pkt->pts;
 
     if (!c->availability_start_time[0])
         format_date_now(c->availability_start_time,
@@ -1485,6 +1505,7 @@  static const AVOption options[] = {
     { "hls_playlist", "Generate HLS playlist files(master.m3u8, media_%d.m3u8)", OFFSET(hls_playlist), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
     { "streaming", "Enable/Disable streaming mode of output. Each frame will be moof fragment", OFFSET(streaming), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
     { "timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E },
+    { "index_correction", "Enable/Disable segment index correction logic", OFFSET(index_correction), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
     { NULL },
 };