diff --git a/libavformat/hls.c b/libavformat/hls.c index acaebed..2439c7c 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -66,7 +66,9 @@ enum KeyType { }; struct segment { + int64_t previous_duration; int64_t duration; + int64_t start_time; int64_t url_offset; int64_t size; char *url; @@ -716,7 +718,7 @@ static int parse_playlist(HLSContext *c, const char *url, struct playlist *pls, AVIOContext *in) { int ret = 0, is_segment = 0, is_variant = 0; - int64_t duration = 0; + int64_t duration = 0, previous_duration1 = 0, previous_duration = 0, total_duration = 0; enum KeyType key_type = KEY_NONE; uint8_t iv[16] = ""; int has_iv = 0; @@ -874,6 +876,8 @@ static int parse_playlist(HLSContext *c, const char *url, } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) { if (pls) pls->finished = 1; + } else if (av_strstart(line, "#EXT-X-DISCONTINUITY", &ptr)) { + previous_duration = previous_duration1; } else if (av_strstart(line, "#EXTINF:", &ptr)) { is_segment = 1; duration = atof(ptr) * AV_TIME_BASE; @@ -903,6 +907,14 @@ static int parse_playlist(HLSContext *c, const char *url, ret = AVERROR(ENOMEM); goto fail; } + + previous_duration1 += duration; + seg->previous_duration = previous_duration; + seg->start_time = total_duration; + total_duration += duration; + seg->duration = duration; + seg->key_type = key_type; + if (has_iv) { memcpy(seg->iv, iv, sizeof(iv)); } else { @@ -949,8 +961,9 @@ static int parse_playlist(HLSContext *c, const char *url, " set to default value to 1ms.\n", seg->url); duration = 0.001 * AV_TIME_BASE; } - seg->duration = duration; - seg->key_type = key_type; + // seg->duration = duration; + // seg->key_type = key_type; + dynarray_add(&pls->segments, &pls->n_segments, seg); is_segment = 0; @@ -2257,6 +2270,29 @@ static int hls_read_packet(AVFormatContext *s, AVPacket *pkt) ist->time_base, AV_TIME_BASE_Q); + if (c->playlists[minplaylist]->finished) { + struct playlist *pls = c->playlists[minplaylist]; + int seq_no = pls->cur_seq_no - pls->start_seq_no; + if (seq_no < pls->n_segments && s->streams[pkt->stream_index]) { + struct segment *seg = pls->segments[seq_no]; + int64_t pred = av_rescale_q(seg->previous_duration, + AV_TIME_BASE_Q, + s->streams[pkt->stream_index]->time_base); + int64_t max_ts = av_rescale_q(seg->start_time + seg->duration, + AV_TIME_BASE_Q, + s->streams[pkt->stream_index]->time_base); + /* EXTINF duration is not precise enough */ + max_ts += 2 * AV_TIME_BASE; + if (s->start_time > 0) { + max_ts += av_rescale_q(s->start_time, + AV_TIME_BASE_Q, + s->streams[pkt->stream_index]->time_base); + } + if (pkt->dts != AV_NOPTS_VALUE && pkt->dts + pred < max_ts) pkt->dts += pred; + if (pkt->pts != AV_NOPTS_VALUE && pkt->pts + pred < max_ts) pkt->pts += pred; + } + } + /* There may be more situations where this would be useful, but this at least * handles newly probed codecs properly (i.e. request_probe by mpegts). */ if (ist->codecpar->codec_id != st->codecpar->codec_id) {