summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libavformat/oggdec.c36
-rw-r--r--libavformat/oggdec.h1
2 files changed, 34 insertions, 3 deletions
diff --git a/libavformat/oggdec.c b/libavformat/oggdec.c
index ca88140cc6..fda1eb2633 100644
--- a/libavformat/oggdec.c
+++ b/libavformat/oggdec.c
@@ -531,9 +531,10 @@ ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
struct ogg_stream *os;
int idx = -1;
int pstart, psize;
- int64_t fpos;
+ int64_t fpos, pts, dts;
//Get an ogg packet
+retry:
do{
if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0)
return AVERROR(EIO);
@@ -542,13 +543,21 @@ ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
ogg = s->priv_data;
os = ogg->streams + idx;
+ // pflags might not be set until after this
+ pts = ogg_calc_pts(s, idx, &dts);
+
+ if (os->keyframe_seek && !(os->pflags & PKT_FLAG_KEY))
+ goto retry;
+ os->keyframe_seek = 0;
+
//Alloc a pkt
if (av_new_packet (pkt, psize) < 0)
return AVERROR(EIO);
pkt->stream_index = idx;
memcpy (pkt->data, os->buf + pstart, psize);
- pkt->pts = ogg_calc_pts(s, idx, &pkt->dts);
+ pkt->pts = pts;
+ pkt->dts = dts;
pkt->flags = os->pflags;
pkt->duration = os->pduration;
pkt->pos = fpos;
@@ -577,6 +586,7 @@ ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
int64_t pos_limit)
{
struct ogg *ogg = s->priv_data;
+ struct ogg_stream *os = ogg->streams + stream_index;
ByteIOContext *bc = s->pb;
int64_t pts = AV_NOPTS_VALUE;
int i;
@@ -586,6 +596,8 @@ ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
while (url_ftell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
if (i == stream_index) {
pts = ogg_calc_pts(s, i, NULL);
+ if (os->keyframe_seek && !(os->pflags & PKT_FLAG_KEY))
+ pts = AV_NOPTS_VALUE;
}
if (pts != AV_NOPTS_VALUE)
break;
@@ -594,6 +606,24 @@ ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
return pts;
}
+static int ogg_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
+{
+ struct ogg *ogg = s->priv_data;
+ struct ogg_stream *os = ogg->streams + stream_index;
+ int ret;
+
+ // Try seeking to a keyframe first. If this fails (very possible),
+ // av_seek_frame will fall back to ignoring keyframes
+ if (s->streams[stream_index]->codec->codec_type == CODEC_TYPE_VIDEO
+ && !(flags & AVSEEK_FLAG_ANY))
+ os->keyframe_seek = 1;
+
+ ret = av_seek_frame_binary(s, stream_index, timestamp, flags);
+ if (ret < 0)
+ os->keyframe_seek = 0;
+ return ret;
+}
+
static int ogg_probe(AVProbeData *p)
{
if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
@@ -612,7 +642,7 @@ AVInputFormat ogg_demuxer = {
ogg_read_header,
ogg_read_packet,
ogg_read_close,
- NULL,
+ ogg_read_seek,
ogg_read_timestamp,
.extensions = "ogg",
.metadata_conv = ff_vorbiscomment_metadata_conv,
diff --git a/libavformat/oggdec.h b/libavformat/oggdec.h
index 6a0ec592da..8733d411b2 100644
--- a/libavformat/oggdec.h
+++ b/libavformat/oggdec.h
@@ -75,6 +75,7 @@ struct ogg_stream {
uint8_t segments[255];
int incomplete; ///< whether we're expecting a continuation in the next page
int page_end; ///< current packet is the last one completed in the page
+ int keyframe_seek;
void *private;
};