summaryrefslogtreecommitdiff
path: root/libavformat/hls.c
diff options
context:
space:
mode:
authorPanagiotis H.M. Issaris <takis.issaris@uhasselt.be>2012-01-10 14:48:57 +0100
committerMartin Storsjö <martin@martin.st>2012-02-19 23:03:42 +0200
commit2b3d041cdc88fe556e61f70130a3a7eb024e0958 (patch)
tree9f66b6684c1a9123dc7bf6d0d084ec95a8febe82 /libavformat/hls.c
parent6b8b0fe2bc57fdd606074e52ba73cd9b3d95e644 (diff)
applehttp: Do seeking within segments, too
Enhance seeking by demuxing until the requested timestamp is reached within the segment selected by the seek code using the playlist info. Some mpegts streams don't have dts set for all packets though, this seeking method doesn't work well for that case. Signed-off-by: Martin Storsjö <martin@martin.st>
Diffstat (limited to 'libavformat/hls.c')
-rw-r--r--libavformat/hls.c55
1 files changed, 47 insertions, 8 deletions
diff --git a/libavformat/hls.c b/libavformat/hls.c
index 82aa7647ae..c4046f29c6 100644
--- a/libavformat/hls.c
+++ b/libavformat/hls.c
@@ -100,6 +100,8 @@ typedef struct HLSContext {
int end_of_segment;
int first_packet;
int64_t first_timestamp;
+ int64_t seek_timestamp;
+ int seek_flags;
AVIOInterruptCB *interrupt_callback;
} HLSContext;
@@ -545,6 +547,7 @@ static int hls_read_header(AVFormatContext *s)
c->first_packet = 1;
c->first_timestamp = AV_NOPTS_VALUE;
+ c->seek_timestamp = AV_NOPTS_VALUE;
return 0;
fail:
@@ -604,14 +607,37 @@ 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 (!var->pb.eof_reached)
- 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;
+ AVStream *st;
+ ret = av_read_frame(var->ctx, &var->pkt);
+ if (ret < 0) {
+ if (!var->pb.eof_reached)
+ return ret;
+ reset_packet(&var->pkt);
+ break;
+ } 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;
+ }
+
+ st = var->ctx->streams[var->pkt.stream_index];
+ ts_diff = av_rescale_rnd(var->pkt.dts, AV_TIME_BASE,
+ st->time_base.den, AV_ROUND_DOWN) -
+ c->seek_timestamp;
+ if (ts_diff >= 0 && (c->seek_flags & AVSEEK_FLAG_ANY ||
+ 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 +678,21 @@ static int hls_read_seek(AVFormatContext *s, int stream_index,
if ((flags & AVSEEK_FLAG_BYTE) || !c->variants[0]->finished)
return AVERROR(ENOSYS);
+ c->seek_flags = flags;
+ c->seek_timestamp = stream_index < 0 ? timestamp :
+ av_rescale_rnd(timestamp, AV_TIME_BASE,
+ s->streams[stream_index]->time_base.den,
+ flags & AVSEEK_FLAG_BACKWARD ?
+ AV_ROUND_DOWN : AV_ROUND_UP);
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 */
@@ -682,6 +719,8 @@ static int hls_read_seek(AVFormatContext *s, int stream_index,
}
pos += var->segments[j]->duration;
}
+ if (ret)
+ c->seek_timestamp = AV_NOPTS_VALUE;
}
return ret;
}