# HG changeset patch # User conrad # Date 1268291880 0 # Node ID 1a3c4f74f17d99263e40805f36db0efd138ea949 # Parent eb9c746c3584cb27c1572ad5dc75d71ded5ad1d9 oggdec: Seek to keyframes diff -r eb9c746c3584 -r 1a3c4f74f17d oggdec.c --- a/oggdec.c Thu Mar 11 07:17:56 2010 +0000 +++ b/oggdec.c Thu Mar 11 07:18:00 2010 +0000 @@ -531,9 +531,10 @@ 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 = 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 @@ 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 @@ 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 @@ 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 @@ 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 -r eb9c746c3584 -r 1a3c4f74f17d oggdec.h --- a/oggdec.h Thu Mar 11 07:17:56 2010 +0000 +++ b/oggdec.h Thu Mar 11 07:18:00 2010 +0000 @@ -75,6 +75,7 @@ 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; };