ogg: Detect missing ogg pages.
authorAndre Noll <maan@tuebingen.mpg.de>
Sat, 22 Dec 2018 17:04:28 +0000 (18:04 +0100)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 24 Feb 2019 13:23:57 +0000 (14:23 +0100)
If pages of an ogg file were cut out, for example with a command like

para_afh -r 'afh -b 100 -f foo.ogg'

the ogg audio format handler still reports the duration of the
full file. This commit makes it detect this case and adjust the
duration accordingly.

This affects all audio formats which employ the ogg container format.

ogg_afh_common.c

index 62cde3d..4fc3795 100644 (file)
@@ -124,8 +124,9 @@ int oac_get_file_info(char *map, size_t numbytes, struct afh_info *afhi,
        ogg_sync_state oss;
        ogg_page op;
        char *buf;
-       int ret, i, j, frames_per_chunk, ct_size;
-       long long unsigned num_frames = 0;
+       int ret, i, j, frames_per_chunk, ct_size, prev_pageno = 0;
+       long long unsigned granule = 0, granule_skip = 0, num_frames = 0;
+       int64_t prev_granule = 0;
 
        ogg_sync_init(&oss);
        ret = -E_OGG_SYNC;
@@ -145,8 +146,16 @@ int oac_get_file_info(char *map, size_t numbytes, struct afh_info *afhi,
        oss.returned = 0;
        oss.fill = numbytes;
        /* count ogg pages and get duration of the file */
-       for (i = 0; ogg_sync_pageseek(&oss, &op) > 0; i++)
-               num_frames = ogg_page_granulepos(&op);
+       for (i = 0; ogg_sync_pageseek(&oss, &op) > 0; i++) {
+               int this_pageno = ogg_page_pageno(&op);
+
+               granule = ogg_page_granulepos(&op);
+               if (i > 0 && this_pageno != prev_pageno + 1) /* hole */
+                       granule_skip += granule - prev_granule;
+               prev_pageno = this_pageno;
+               prev_granule = granule;
+       }
+       num_frames = granule - granule_skip;
        PARA_INFO_LOG("%d pages, %llu frames\n", i, num_frames);
        ret = -E_OGG_EMPTY;
        if (i == 0)
@@ -163,7 +172,7 @@ int oac_get_file_info(char *map, size_t numbytes, struct afh_info *afhi,
        oss.returned = afhi->header_len;
        oss.fill = numbytes;
        for (j = 1; ogg_sync_pageseek(&oss, &op) > 0; /* nothing */) {
-               int granule = ogg_page_granulepos(&op);
+               granule = ogg_page_granulepos(&op);
 
                while (granule >= (j + 1) * frames_per_chunk) {
                        j++;