[FFmpeg-devel] [RFC] better ogg seeking, keyframes only

Reimar Döffinger Reimar.Doeffinger
Wed Mar 19 13:16:16 CET 2008


Hello,
I admit this is a rather ugly patch, but it improves things a lot, so
maybe you can have a look and get it committable.
There are several issues with seeking: for audio, PKT_FLAG_KEY is never
set, so the patch ignores it there, the data_offset set by the code in
util.c is wrong, so this code overrides it, and the most annoying
thing: a keyframe most likely is split over multiple ogg pages, so
this code just returns the start of the last page read by the last
get_packet as start offset for the keyframe - this means we might
actually end up a few frames before the key frame (in theory up to 255),
if the encoded frames are very small.

Greetings,
Reimar D?ffinger
-------------- next part --------------
Index: libavformat/oggdec.c
===================================================================
--- libavformat/oggdec.c	(revision 12478)
+++ libavformat/oggdec.c	(working copy)
@@ -251,6 +251,7 @@
     }
 
     os = ogg->streams + idx;
+    os->file_offset = url_ftell(bc) - 27;
 
     if(os->psize > 0)
         ogg_new_buf(ogg, idx);
@@ -371,6 +372,7 @@
           os->header = os->seq;
           os->segp = segp;
           os->psize = psize;
+          if (s->data_offset <= 0) s->data_offset = os->file_offset;
           ogg->headers = 1;
         }else{
           os->pstart += os->psize;
@@ -556,18 +558,28 @@
     ogg_t *ogg = s->priv_data;
     ByteIOContext *bc = s->pb;
     int64_t pts = AV_NOPTS_VALUE;
+    int64_t last_pos = -1;
+    uint64_t granule;
     int i;
     url_fseek(bc, *pos_arg, SEEK_SET);
-    while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
-        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
-            ogg->streams[i].codec && i == stream_index) {
-            pts = ogg_gptopts(s, i, ogg->streams[i].granule);
-            // FIXME: this is the position of the packet after the one with above
-            // pts.
-            *pos_arg = url_ftell(bc);
-            break;
+    ogg_reset(ogg);
+    do {
+        if (ogg_packet(s, &i, NULL, NULL) < 0) goto err_out;
+        if (i != stream_index) continue;
+        granule = ogg->streams[i].lastgp != -1 ? ogg->streams[i].lastgp : ogg->streams[i].granule;
+        if (granule != -1) {
+            int64_t next_pts = ogg_gptopts(s, i, granule);
+            if (s->streams[i]->codec->codec_type != CODEC_TYPE_VIDEO ||
+                (ogg->streams[i].pflags & PKT_FLAG_KEY)) {
+                // use last_pos, since part of the required data may be in previous pages
+                *pos_arg = last_pos == -1 ? ogg->streams[i].file_offset : last_pos;
+                pts = next_pts;
+                break;
+            }
         }
-    }
+        last_pos = ogg->streams[i].file_offset;
+    } while (last_pos < pos_limit);
+err_out:
     ogg_reset(ogg);
     return pts;
 }
Index: libavformat/oggdec.h
===================================================================
--- libavformat/oggdec.h	(revision 12478)
+++ libavformat/oggdec.h	(working copy)
@@ -46,6 +46,7 @@
     uint32_t serial;
     uint32_t seq;
     uint64_t granule, lastgp;
+    int64_t file_offset;
     int flags;
     ogg_codec_t *codec;
     int header;



More information about the ffmpeg-devel mailing list