changeset 5818:1a3c4f74f17d libavformat

oggdec: Seek to keyframes
author conrad
date Thu, 11 Mar 2010 07:18:00 +0000
parents eb9c746c3584
children 53c5a5d40ee7
files oggdec.c oggdec.h
diffstat 2 files changed, 34 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- 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,
--- 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;
 };