diff --git a/doc/muxers.texi b/doc/muxers.texi index 6195575951..a10bd95493 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 bf8698f292..9e72636f0e 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 }, };