[FFmpeg-devel] [PATCH v1] lavf/dashenc: Add option for calculting pkt duration

Jun Li junli1026 at gmail.com
Mon Apr 22 03:51:24 EEST 2019


Fix #7144.
The current packet duration calculation is heuristic, which uses the
historical durtion as current duration. This commit adds the option
to buffer one packet and calcuate its duration when next packet arrives.
Obviously it adds one frame latency, which might be significant for
VFR live content, so expose it as an option for user to choose.
---
 doc/muxers.texi       |  4 ++++
 libavformat/dashenc.c | 44 +++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index ee99ef621e..76954877a6 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -321,6 +321,10 @@ This is an experimental feature.
 @item -master_m3u8_publish_rate @var{master_m3u8_publish_rate}
 Publish master playlist repeatedly every after specified number of segment intervals.
 
+ at item -skip_estimate_pkt_duration
+If this flag is set, packet duration will be calcuated as the diff of the current and next packet timestamp. The option is not for constant frame rate
+content because heuristic estimation will be accurate in this case. Default value is 0.
+
 @end table
 
 @anchor{framecrc}
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 5f1333e436..f89d68a51b 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -101,6 +101,7 @@ typedef struct OutputStream {
     double availability_time_offset;
     int total_pkt_size;
     int muxer_overhead;
+    AVPacket* prev_pkt;
 } OutputStream;
 
 typedef struct DASHContext {
@@ -145,6 +146,7 @@ typedef struct DASHContext {
     int ignore_io_errors;
     int lhls;
     int master_publish_rate;
+    int skip_estiamte_pkt_duration;
     int nr_of_streams_to_flush;
     int nr_of_streams_flushed;
 } DASHContext;
@@ -1559,7 +1561,7 @@ static int dash_flush(AVFormatContext *s, int final, int stream)
         } else {
             snprintf(os->full_path, sizeof(os->full_path), "%s%s", c->dirname, os->initfile);
         }
-
+        
         ret = flush_dynbuf(c, os, &range_length);
         if (ret < 0)
             break;
@@ -1643,7 +1645,7 @@ static int dash_flush(AVFormatContext *s, int final, int stream)
     return ret;
 }
 
-static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
+static int dash_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
 {
     DASHContext *c = s->priv_data;
     AVStream *st = s->streams[pkt->stream_index];
@@ -1789,11 +1791,47 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
     return ret;
 }
 
+static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+    DASHContext *c = s->priv_data;
+    if (!c->skip_estiamte_pkt_duration)
+        return dash_write_packet_internal(s, pkt);
+
+    AVStream *st = s->streams[pkt->stream_index];
+    OutputStream *os = &c->streams[pkt->stream_index];
+    int ret = 0;
+    
+    if (os->prev_pkt) {
+        if (!os->prev_pkt->duration && pkt->dts >= os->prev_pkt->dts)
+            os->prev_pkt->duration = pkt->dts - os->prev_pkt->dts;
+        ret = dash_write_packet_internal(s, os->prev_pkt);
+        av_packet_unref(os->prev_pkt);
+        if (av_packet_ref(os->prev_pkt, pkt)) {
+            av_log(s, AV_LOG_ERROR, "Failed to set up a reference to current packet, lost one packet for muxing.\n");
+            av_packet_free(&os->prev_pkt);
+        }
+    } else {
+        os->prev_pkt = av_packet_clone(pkt);
+    }
+    return ret;
+}
+
 static int dash_write_trailer(AVFormatContext *s)
 {
     DASHContext *c = s->priv_data;
     int i;
 
+    if (c->skip_estiamte_pkt_duration) {
+        for (i = 0; i < s->nb_streams; i++) {
+            OutputStream *os = &c->streams[i];
+            if (os->prev_pkt) {
+                // write last packet
+                dash_write_packet_internal(s, os->prev_pkt);
+                av_packet_free(&os->prev_pkt);
+            }
+        }
+    }
+
     if (s->nb_streams > 0) {
         OutputStream *os = &c->streams[0];
         // If no segments have been written so far, try to do a crude
@@ -1888,6 +1926,8 @@ static const AVOption options[] = {
     { "ignore_io_errors", "Ignore IO errors during open and write. Useful for long-duration runs with network output", OFFSET(ignore_io_errors), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
     { "lhls", "Enable Low-latency HLS(Experimental). Adds #EXT-X-PREFETCH tag with current segment's URI", OFFSET(lhls), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
     { "master_m3u8_publish_rate", "Publish master playlist every after this many segment intervals", OFFSET(master_publish_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, UINT_MAX, E},
+    { "skip_estimate_pkt_duration", "Skip estimate packet duration, buffer previous packet for calculating its duration.", OFFSET(skip_estiamte_pkt_duration), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
+
     { NULL },
 };
 
-- 
2.17.1



More information about the ffmpeg-devel mailing list