[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