diff --git a/libavformat/applehttp.c b/libavformat/applehttp.c index 5733f5fb27..883427ce97 100644 --- a/libavformat/applehttp.c +++ b/libavformat/applehttp.c @@ -100,6 +100,8 @@ typedef struct AppleHTTPContext { int end_of_segment; int first_packet; int64_t first_timestamp; + int64_t seek_timestamp; + int seek_flags; AVIOInterruptCB *interrupt_callback; } AppleHTTPContext; @@ -545,6 +547,7 @@ static int applehttp_read_header(AVFormatContext *s, AVFormatParameters *ap) c->first_packet = 1; c->first_timestamp = AV_NOPTS_VALUE; + c->seek_timestamp = AV_NOPTS_VALUE; return 0; fail: @@ -604,14 +607,44 @@ start: /* Make sure we've got one buffered packet from each open variant * stream */ if (var->needed && !var->pkt.data) { - ret = av_read_frame(var->ctx, &var->pkt); - if (ret < 0) { - if (!url_feof(&var->pb)) - return ret; - reset_packet(&var->pkt); - } else { - if (c->first_timestamp == AV_NOPTS_VALUE) - c->first_timestamp = var->pkt.dts; + while (1) { + int64_t ts_diff; + ret = av_read_frame(var->ctx, &var->pkt); + if (ret < 0) { + if (!url_feof(&var->pb)) { + return ret; + } else { + if ((var->cur_seq_no - var->start_seq_no) == (var->n_segments)) { + return AVERROR_EOF; + } + } + reset_packet(&var->pkt); + } else { + if (c->first_timestamp == AV_NOPTS_VALUE) + c->first_timestamp = var->pkt.dts; + } + + if (c->seek_timestamp == AV_NOPTS_VALUE) + break; + + if (var->pkt.dts == AV_NOPTS_VALUE) { + c->seek_timestamp = AV_NOPTS_VALUE; + break; + } + + ts_diff = var->pkt.dts - c->seek_timestamp; + if (ts_diff >= 0) { + if (c->seek_flags & AVSEEK_FLAG_ANY) { + c->seek_timestamp = AV_NOPTS_VALUE; + break; + } + + /* Seek to keyframe */ + if (var->pkt.flags & AV_PKT_FLAG_KEY) { + c->seek_timestamp = AV_NOPTS_VALUE; + break; + } + } } } /* Check if this stream has the packet with the lowest dts */ @@ -652,10 +685,17 @@ static int applehttp_read_seek(AVFormatContext *s, int stream_index, if ((flags & AVSEEK_FLAG_BYTE) || !c->variants[0]->finished) return AVERROR(ENOSYS); + c->seek_timestamp = timestamp; + c->seek_flags = flags; timestamp = av_rescale_rnd(timestamp, 1, stream_index >= 0 ? s->streams[stream_index]->time_base.den : AV_TIME_BASE, flags & AVSEEK_FLAG_BACKWARD ? AV_ROUND_DOWN : AV_ROUND_UP); + if (s->duration < c->seek_timestamp) { + c->seek_timestamp = AV_NOPTS_VALUE; + return AVERROR(EIO); + } + ret = AVERROR(EIO); for (i = 0; i < c->n_variants; i++) { /* Reset reading */ @@ -683,6 +723,8 @@ static int applehttp_read_seek(AVFormatContext *s, int stream_index, } pos += var->segments[j]->duration; } + if (ret != 0) + c->seek_timestamp = AV_NOPTS_VALUE; } return ret; }