[FFmpeg-devel,1/1] libavformat/dashenc: separate segments based on segment duration instead of total duration

Submitted by Peter Große on Jan. 21, 2017, 9:11 p.m.

Details

Message ID 20170121211108.10616-1-pegro@friiks.de
State New
Headers show

Commit Message

Peter Große Jan. 21, 2017, 9:11 p.m.
The current implementation creates new segments comparing

  pkt->pts - first_pts > total_duration

This works fine, but if the keyframe interval is smaller than "min_seg_duration"
segments shorter than the minimum segment duration are created.

Example: keyint=50, min_seg_duration=3000000
 segment 1 contains keyframe 1 (duration=2s <  total_duration=3s)
                and keyframe 2 (duration=4s >= total_duration=3s)
 segment 2 contains keyframe 3 (duration=6s >= total_duration=6s)
 segment 3 contains keyframe 4 (duration=8s <  total_duration=9s)
                and keyframe 5 (duration=10s >= total_duration=9s)
 ...

Segment 2 is only 2s long, shorter than min_seg_duration = 3s.

To fix this, either rename "min_seg_duration" to something more accurate.
Or apply this patch to create new segments based on the actual
written duration.

Signed-off-by: Peter Große <pegro@friiks.de>
---
 libavformat/dashenc.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

Patch hide | download patch | download mbox

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index e4bb923..c3a5dc5 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -73,7 +73,7 @@  typedef struct OutputStream {
     AVFormatContext *ctx;
     int ctx_inited, as_idx;
     AVIOContext *out;
-    int packets_written;
+    int duration_written;
     char initfile[1024];
     int64_t init_start_pos, pos;
     int init_range_length;
@@ -1032,7 +1032,7 @@  static int dash_flush(AVFormatContext *s, int final, int stream)
         char filename[1024] = "", full_path[1024], temp_path[1024];
         int range_length, index_length = 0;
 
-        if (!os->packets_written)
+        if (!os->duration_written)
             continue;
 
         // Flush the single stream that got a keyframe right now.
@@ -1081,7 +1081,7 @@  static int dash_flush(AVFormatContext *s, int final, int stream)
         av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written to: %s\n", i, os->segment_index, full_path);
 
         // set new position
-        os->packets_written = 0;
+        os->duration_written = 0;
         os->pos += range_length;
 
         // write chunk header
@@ -1119,7 +1119,6 @@  static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
     DASHContext *c = s->priv_data;
     AVStream *st = s->streams[pkt->stream_index];
     OutputStream *os = &c->streams[pkt->stream_index];
-    int64_t seg_end_duration = (os->segment_index) * (int64_t) c->min_seg_duration;
     int ret;
 
     ret = update_stream_extradata(s, os, st->codecpar);
@@ -1148,9 +1147,9 @@  static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
         os->first_pts = pkt->pts;
 
     if ((!c->has_video || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) &&
-        pkt->flags & AV_PKT_FLAG_KEY && os->packets_written &&
-        av_compare_ts(pkt->pts - os->first_pts, st->time_base,
-                      seg_end_duration, AV_TIME_BASE_Q) >= 0) {
+        pkt->flags & AV_PKT_FLAG_KEY && os->duration_written &&
+        av_compare_ts(os->duration_written + pkt->duration, st->time_base,
+                      c->min_seg_duration, AV_TIME_BASE_Q) >= 0) {
         int64_t prev_duration = c->last_duration;
 
         c->last_duration = av_rescale_q(pkt->pts - os->start_pts,
@@ -1173,7 +1172,7 @@  static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
             return ret;
     }
 
-    if (!os->packets_written) {
+    if (!os->duration_written) {
         // If we wrote a previous segment, adjust the start time of the segment
         // to the end of the previous one (which is the same as the mp4 muxer
         // does). This avoids gaps in the timeline.
@@ -1186,7 +1185,7 @@  static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
         os->max_pts = pkt->pts + pkt->duration;
     else
         os->max_pts = FFMAX(os->max_pts, pkt->pts + pkt->duration);
-    os->packets_written++;
+    os->duration_written += pkt->duration;
     return ff_write_chained(os->ctx, 0, pkt, s, 0);
 }