Browse code

Parse index chunk so that seeking in modern .rm files becomes a lot faster. Has been tested against streamed / non-seekable input and passes make seektest. See "[PATCH] rmdec.c: parse INDX chunk" thread on mailinglist.

Originally committed as revision 18013 to svn://svn.ffmpeg.org/ffmpeg/trunk

Ronald S. Bultje authored on 2009/03/16 22:03:23
Showing 1 changed files
... ...
@@ -292,6 +292,49 @@ skip:
292 292
     return 0;
293 293
 }
294 294
 
295
+/** this function assumes that the demuxer has already seeked to the start
296
+ * of the INDX chunk, and will bail out if not. */
297
+static int rm_read_index(AVFormatContext *s)
298
+{
299
+    ByteIOContext *pb = s->pb;
300
+    unsigned int size, n_pkts, str_id, next_off, n, pos, pts;
301
+    AVStream *st;
302
+
303
+    do {
304
+        if (get_le32(pb) != MKTAG('I','N','D','X'))
305
+            return -1;
306
+        size     = get_be32(pb);
307
+        if (size < 20)
308
+            return -1;
309
+        url_fskip(pb, 2);
310
+        n_pkts   = get_be32(pb);
311
+        str_id   = get_be16(pb);
312
+        next_off = get_be32(pb);
313
+        for (n = 0; n < s->nb_streams; n++)
314
+            if (s->streams[n]->id == str_id) {
315
+                st = s->streams[n];
316
+                break;
317
+            }
318
+        if (n == s->nb_streams)
319
+            goto skip;
320
+
321
+        for (n = 0; n < n_pkts; n++) {
322
+            url_fskip(pb, 2);
323
+            pts = get_be32(pb);
324
+            pos = get_be32(pb);
325
+            url_fskip(pb, 4); /* packet no. */
326
+
327
+            av_add_index_entry(st, pos, pts, 0, 0, AVINDEX_KEYFRAME);
328
+        }
329
+
330
+skip:
331
+        if (next_off && url_ftell(pb) != next_off &&
332
+            url_fseek(pb, next_off, SEEK_SET) < 0)
333
+            return -1;
334
+    } while (next_off);
335
+
336
+    return 0;
337
+}
295 338
 
296 339
 static int rm_read_header_old(AVFormatContext *s, AVFormatParameters *ap)
297 340
 {
... ...
@@ -314,6 +357,7 @@ static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap)
314 314
     unsigned int tag;
315 315
     int tag_size;
316 316
     unsigned int start_time, duration;
317
+    unsigned int data_off = 0, indx_off = 0;
317 318
     char buf[128];
318 319
     int flags = 0;
319 320
 
... ...
@@ -357,8 +401,8 @@ static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap)
357 357
             get_be32(pb); /* nb packets */
358 358
             get_be32(pb); /* duration */
359 359
             get_be32(pb); /* preroll */
360
-            get_be32(pb); /* index offset */
361
-            get_be32(pb); /* data offset */
360
+            indx_off = get_be32(pb); /* index offset */
361
+            data_off = get_be32(pb); /* data offset */
362 362
             get_be16(pb); /* nb streams */
363 363
             flags = get_be16(pb); /* flags */
364 364
             break;
... ...
@@ -400,6 +444,14 @@ static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap)
400 400
     if (!rm->nb_packets && (flags & 4))
401 401
         rm->nb_packets = 3600 * 25;
402 402
     get_be32(pb); /* next data header */
403
+
404
+    if (!data_off)
405
+        data_off = url_ftell(pb) - 18;
406
+    if (indx_off && url_fseek(pb, indx_off, SEEK_SET) >= 0) {
407
+        rm_read_index(s);
408
+        url_fseek(pb, data_off + 18, SEEK_SET);
409
+    }
410
+
403 411
     return 0;
404 412
 }
405 413