Create three ogg pages when skipping vorbis comments.
authorAndre Noll <maan@systemlinux.org>
Thu, 10 Feb 2011 20:06:27 +0000 (21:06 +0100)
committerAndre Noll <maan@systemlinux.org>
Thu, 10 Feb 2011 20:06:27 +0000 (21:06 +0100)
This works around a shortcoming in older versions of libogg. It
makes get_header() create a separate ogg page for each of the
three header packets in an ogg/vorbis stream instead of combining
packets #2 and #3.

The patch also adds a couple of debug log messages which print the
size of the individual ogg packets and ogg pages.

ogg_afh.c
ogg_afh_common.c

index 2837db6..e2d8dbc 100644 (file)
--- a/ogg_afh.c
+++ b/ogg_afh.c
@@ -85,6 +85,18 @@ static void add_ogg_page(ogg_page *og, struct vorbis_get_header_data *vghd)
                og->header_len, og->body_len, old_len, new_len);
 }
 
+/*
+ * Process the first three ogg packets.
+ *
+ * This creates chunk zero (the audio file header) from the first three ogg
+ * packets of the input file with metadata (vorbis comments) stripped off. Page
+ * 0 of the input file always contains only ogg packet #0 while page 1 usually
+ * contains both packets 1 (comments) and 2 (setup).  However, we always create
+ * an separate ogg page for each packet to circumvent a bug in older libogg
+ * versions which causes too little data being copied to the second ogg page.
+ * This affects at least Ubuntu Hardy, and there is no real disadvantage in
+ * creating three pages instead of two.
+ */
 static int vorbis_get_header_callback(ogg_packet *packet, int packet_num,
                int serial, __a_unused struct afh_info *afhi, void *private_data)
 {
@@ -100,7 +112,8 @@ static int vorbis_get_header_callback(ogg_packet *packet, int packet_num,
                0xff /* framing bit */
        };
 
-       PARA_DEBUG_LOG("processing ogg packet #%d\n", packet_num);
+       PARA_DEBUG_LOG("processing ogg packet #%d (%li bytes)\n",
+               packet_num, packet->bytes);
        if (packet_num > 2)
                return 0;
        if (packet_num == 0) {
@@ -116,15 +129,19 @@ static int vorbis_get_header_callback(ogg_packet *packet, int packet_num,
                return 1;
        }
        if (packet_num == 1) {
-               PARA_INFO_LOG("replacing metadata packet\n");
+               PARA_INFO_LOG("replacing metadata packet (saved %ld bytes)\n",
+                       packet->bytes - sizeof(dummy_packet));
                ogg_packet replacement = *packet;
                replacement.packet = dummy_packet;
                replacement.bytes = sizeof(dummy_packet);
-               ret = ogg_stream_packetin(&vghd->os, &replacement);
-               if (ret >= 0)
-                       return 1;
                ret = -E_OGG_PACKET_IN;
-               goto out;
+               if (ogg_stream_packetin(&vghd->os, &replacement) < 0)
+                       goto out;
+               ret = -E_OGG_STREAM_FLUSH;
+               if (ogg_stream_flush(&vghd->os, &og) == 0)
+                       goto out;
+               add_ogg_page(&og, vghd);
+               return 1;
        }
        ret = -E_OGG_PACKET_IN;
        if (ogg_stream_packetin(&vghd->os, packet) < 0)
@@ -154,7 +171,7 @@ static void vorbis_get_header(void *map, size_t mapsize, char **buf,
                goto fail;
        *buf = vghd.buf;
        *len = vghd.len;
-       PARA_INFO_LOG("created %zu byte ogg vorbis header\n", *len);
+       PARA_INFO_LOG("created %zu byte ogg/vorbis header chunk\n", *len);
        return;
 fail:
        PARA_ERROR_LOG("%s\n", para_strerror(-ret));
index ad5963e..777e213 100644 (file)
@@ -32,15 +32,19 @@ static int process_packets_2_and_3(ogg_sync_state *oss,
                                break; /* Need more data */
                        if (ret != 1)
                                continue;
+                       PARA_DEBUG_LOG("next input page (header/body): %lu/%lu\n",
+                               page.header_len, page.body_len);
                        /*
                         * We can ignore any errors here as they'll also become
                         * apparent at packetout.
                         */
                        ogg_stream_pagein(stream, &page);
-                       PARA_INFO_LOG("ogg page serial: %d\n",
+                       PARA_DEBUG_LOG("ogg page serial: %d\n",
                                ogg_page_serialno(&page));
                        while (i < 2) {
                                ret = ogg_stream_packetout(stream, &packet);
+                               PARA_DEBUG_LOG("packet #%d: %lu bytes\n", i + 1,
+                                       packet.bytes);
                                if (ret == 0)
                                        break;
                                if (ret < 0)
@@ -69,6 +73,8 @@ static int process_ogg_packets(ogg_sync_state *oss, struct afh_info *afhi,
 
        if (ogg_sync_pageout(oss, &page) != 1)
                return -E_SYNC_PAGEOUT;
+       PARA_DEBUG_LOG("first input page (header/body): %lu/%lu\n",
+               page.header_len, page.body_len);
 
        ret = ogg_page_serialno(&page);
        ogg_stream_init(&stream, ret);
@@ -80,6 +86,7 @@ static int process_ogg_packets(ogg_sync_state *oss, struct afh_info *afhi,
        ret = -E_STREAM_PACKETOUT;
        if (ogg_stream_packetout(&stream, &packet) != 1)
                goto out;
+       PARA_DEBUG_LOG("packet #0: %lu bytes\n", packet.bytes);
        ret = ci->packet_callback(&packet, 0, ogg_page_serialno(&page),
                afhi, ci->private_data);
        if (ret < 0)