[Vorbis] Re: Vorbis primitive API examples (LONG)
Andrew Lentvorski
bsder at allcaps.org
Tue Oct 10 00:14:05 PDT 2006
Ralph Giles wrote:
> Thanks for posting. Are you licensing these under the same BSD as the
> main code? Do you want to assign copyright?
Absolutely. Whatever license and assignment makes things easiest for
everybody I will happily execute.
Full patch is attached.
-a
-------------- next part --------------
Index: decoder_example.c
===================================================================
--- decoder_example.c (revision 0)
+++ decoder_example.c (revision 0)
@@ -0,0 +1,360 @@
+/*
+ * Takes a stereo ogg stream from stdin and writes 16 bit pcm out to
+ * the stdout. It writes lots of debugging info to stderr.
+ *
+ * This is meant as a skeleton so that people can see how to
+ * use the lower level vorbis API.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "ivorbiscodec.h"
+#include "misc.h"
+
+#ifdef _WIN32 /* We need the following two to set stdin/stdout to binary */
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+#if defined(__MACOS__) && defined(__MWERKS__)
+#include <console.h> /* CodeWarrior's Mac "command-line" support */
+#endif
+
+/* FIXME: Shouldn't this be declared somewhere else? Like ivorbiscode.h or something? */
+#define LAST_VORBIS_HEADER_PACKET 2
+
+#define dprintf(...) fprintf(stderr, __VA_ARGS__)
+
+#define BCHUNKSIZE 8192
+
+static long bytesConsumed = 0;
+
+int main() {
+ int o_rv0 = 0;
+ int s_rv0 = 0;
+ int v_rv0 = 0;
+
+ /*
+ // These abbreviations use the ogg internal conventions
+
+ // Caution: libogg uses NULL as a sentinel in places. If you feed non-NULL,
+ // on initial calls you can get into trouble
+ */
+
+ /* OGG data structures */
+ ogg_sync_state *oy = NULL;
+
+ /* FIXME: Why is this magic required to make ogg_page work? */
+ /* FIXME: Why is there no ogg_page_create? Or ogg_page_init? */
+ ogg_page og_allocated = {0, 0, 0, 0};
+ ogg_page* og = &og_allocated;
+
+
+ /* Stream data structures */
+ ogg_stream_state *os = NULL;
+
+ /* FIXME: Why is this magic required to make ogg_page work? */
+ /* FIXME: Why is there no ogg_packet_create? Or ogg_packet_init? */
+ ogg_packet op_allocated = {0, 0, 0, 0, 0, 0};
+ ogg_packet* op = &op_allocated;
+
+
+ /*
+ // Vorbis data structures
+
+ // FIXME: These should probably get a *_create or similar so that
+ // they don't have to be manually managed but instead are managed
+ // by the system.
+ */
+ vorbis_info vi_allocated;
+ vorbis_info* vi = &vi_allocated;
+
+ vorbis_comment vc_allocated;
+ vorbis_comment* vc = &vc_allocated;
+
+ vorbis_dsp_state vd_allocated;
+ vorbis_dsp_state* vd = &vd_allocated;
+
+ vorbis_block vb_allocated;
+ vorbis_block *vb = &vb_allocated;
+
+
+ /*
+ // CAUTION: Just about anything you do wrong pops a bus error.
+ // You need to be fairly aggressive about checking return codes
+ // and initializing properly.
+ */
+
+ int flgBailError = 0;
+
+ int flgInitialPageRead = 0xdeadbeef;
+ int flgPacketsConsumed = 0xdeadbeef;
+ int packetCount = 0xdeadbeef;
+
+ int flgEOSPage = 0xdecafbad;
+ int flgBailEOS = 0xc0ffee00;
+
+ /* Ogg init */
+ oy = ogg_sync_create();
+
+ /* Stream init */
+ /* Need to set the serial number later, or the stream will reject input */
+ os = ogg_stream_create(-1);
+
+ /*
+ // There is only one physical stream here. Do *NOT* reinitialize
+ // it upon changing logical streams or you will lose any data which
+ // has already been read and buffered by the ogg system.
+ */
+
+ while(!flgBailError) { /* This while loop iterates over ogg logical streams */
+ /* Vorbis init */
+ vorbis_info_init(vi);
+ vorbis_comment_init(vc);
+
+ /* Page iteration init */
+ flgInitialPageRead = 0;
+ packetCount = -1;
+
+ flgEOSPage = 0;
+
+ /*
+ // This is probably redundant with flgEOSPage. However, it is
+ // easier to keep track of a separate flag which is set only
+ // after all packets have been consumed rather than: at the
+ // beginning of the page, but before the stream has been decoded
+ // and before the packets have been consumed, and ...
+ */
+
+ flgBailEOS = 0;
+
+ while(!flgBailEOS && !flgBailError) { /* This while loop iterates over ogg pages */
+
+ if (flgInitialPageRead) { /* Page system has been initialized and is valid */
+ dprintf("Page: %d\n", ogg_page_pageno(og));
+
+ if (ogg_page_bos(og)) {
+ dprintf("Beginning of stream found: %d\n", ogg_page_bos(og));
+
+ // Use hex to match ogginfo return
+ dprintf("Setting serial number: %x\n", ogg_page_serialno(og));
+ ogg_stream_reset_serialno(os, ogg_page_serialno(og));
+ }
+
+ /*
+ // EOS test has to be up front because, of course, everything in the universe
+ // releases the page so you have to get to it *before* it disappears
+ // and store it yourself in spite of the fact that the page stores it
+ // very nicely (until it gets freed). Grrrrrrr ...
+ */
+ if (ogg_page_eos(og)) {
+ flgEOSPage = 1;
+ dprintf("End of stream found\n");
+ }
+
+ s_rv0 = ogg_stream_pagein(os, og);
+ dprintf("Page in: %d %p %p\n", s_rv0, os, og);
+
+ if (s_rv0 < 0) {
+ /*
+ // FIXME: ARRRGGGGHHH!!! ogg_stream_pagein releases the page on error.
+ // This is silly on serial number mismatch. Actually, it's probably
+ // silly in general on an error because it means you can't actually
+ // examine the page to see what's wrong because it just disappeared.
+ */
+
+ if (s_rv0 == OGG_ESERIAL) {
+ /* Useless, because page is gone and can't be examined. Grrrrr. */
+ dprintf("Bailing on serial submit fail\n");
+ flgBailError = 1;
+ } else {
+ dprintf("Bailing on stream submit fail\n");
+ flgBailError = 1;
+ }
+ }
+
+ flgPacketsConsumed = 0;
+ while (!flgPacketsConsumed && !flgBailError) { /* Iterates over packets */
+ /*
+ // Valid page submitted to stream, now pull out as packets
+ // There may be more than 1 packet per page. Pull all packets
+ // before asking for another page.
+ */
+ s_rv0 = ogg_stream_packetout(os, op);
+ dprintf("Packet out: %d %d %p %p\n", packetCount, s_rv0, os, op);
+
+ if (s_rv0 < 0) {
+ flgBailError = 1;
+ dprintf("Packet consumption error bail\n");
+ } else if (s_rv0 == 0) {
+ dprintf("Packets consumed. Get more data.\n");
+ flgPacketsConsumed = 1;
+ }
+
+ if (s_rv0 > 0) { /* Packet valid */
+ /* Only increment packet counter on valid packet */
+ ++packetCount;
+
+ /* Packet valid & counts valid ... do something with it */
+ dprintf("Packet val: %d %d %lld %p %p\n", packetCount, s_rv0,
+ ogg_packet_get_packetno(op), os, op);
+
+ /*
+ // Use the actual packet for packet numbers as a dropped packet will
+ // mess up the running packetCount total (which should be removed eventually)
+ */
+ if (ogg_packet_get_packetno(op) <= LAST_VORBIS_HEADER_PACKET) {
+ // Currently decoding inside the vorbis headers (first three packets)
+ v_rv0 = vorbis_synthesis_headerin(vi, vc, op);
+ dprintf("Header decode: %d %p %p %p\n", v_rv0, vi, vc, op);
+
+ if (ogg_packet_get_packetno(op) == LAST_VORBIS_HEADER_PACKET) {
+ /*
+ // WARNING! DO NOT CALL vorbis_synthesis_init BEFORE YOU HAVE
+ // PROCESSED **ALL** THE HEADERS. FAILURE TO DO SO WILL CAUSE
+ // MALLOC/FREE PROBLEMS LATER.
+
+ // FIXME: vorbis_synthesis_init needs a renaming/refactoring. It
+ // really isn't an independent init like others. It has a
+ // dependency upon having a fully filled out vorbis_info structure.
+ // Such a dependency really should cause a change in the name
+ // to something like vorbis_synthesis_postheader_init.
+
+ // FIXME: Does vorbis_block_init have a post-dependency upon
+ // vorbis_synthesis_init?
+ */
+ vorbis_synthesis_init(vd, vi);
+ vorbis_block_init(vd, vb);
+ }
+ } else {
+ /* Stream packet, not a header packet */
+ v_rv0 = vorbis_synthesis(vb, op, 1);
+ dprintf("Vorbis synthesis: %d %p %p\n", v_rv0, vb, op);
+
+ if (v_rv0 == 0) {
+ /* Block is valid for synthesis and synthesis is ready */
+ v_rv0 = vorbis_synthesis_blockin(vd, vb);
+
+ if (v_rv0 == 0) {
+ /* Synthesis was successful. Pull out the data */
+ int pcmSamples = 1;
+ ogg_int32_t **pcm;
+ int numChannels = 2; /* FIXME: Should really pull this from info */
+ int ii, jj;
+ while(pcmSamples > 0) {
+ pcmSamples = vorbis_synthesis_pcmout(vd, &pcm);
+
+ /* Interleaver for output PCM */
+ for(ii=0; ii<pcmSamples; ++ii) {
+ for(jj=0; jj<numChannels; ++jj) {
+ ogg_int32_t *srcChannelArray = pcm[jj];
+ ogg_int32_t srcValue = srcChannelArray[ii];
+ short dstValue = CLIP_TO_15(srcValue>>9);
+
+ long bytesWritten = fwrite(&dstValue, 2, 1, stdout);
+ }
+ }
+
+ /* Let the decoder know how many samples we actually consumed */
+ vorbis_synthesis_read(vd, pcmSamples);
+ }
+ }
+ }
+ }
+
+ } /* Packet valid */
+ } /* Iterates over packets */
+ } /* Page system has been initialized and is valid */
+
+ /*
+ // Don't pull another page at EOS. Let that occur after reset on another
+ // trip through so that we match the normal uninitialized case.
+ */
+ if (!flgEOSPage && !flgBailError) {
+ o_rv0 = 0;
+ while(o_rv0 != 1 && !flgBailError) {
+ o_rv0 = ogg_sync_pageout(oy, og);
+
+ if (o_rv0 > 0) {
+ flgInitialPageRead = 1;
+ }
+
+ if (o_rv0 <= 0) {
+ if (o_rv0 < 0) {
+ dprintf("Skipping bytes...\n");
+ } else {
+ dprintf("Need more data...\n");
+ }
+
+ if (o_rv0 == 0) {
+ unsigned char* bb = ogg_sync_bufferin(oy, BCHUNKSIZE);
+ long bytesRead = fread(bb, 1, BCHUNKSIZE, stdin);
+
+ dprintf("Consumed: %ld bytes\n", bytesRead);
+
+ if (bytesRead > 0) {
+ // Got bytes
+ ogg_sync_wrote(oy, bytesRead);
+ bytesConsumed += bytesRead;
+ } else if (bytesRead == 0) {
+ // EOF
+ dprintf("EOF error bail\n");
+ flgBailError = 1;
+ } else {
+ // Error
+ dprintf("Data error encountered: %ld\n", bytesRead);
+ flgBailError = 1;
+ }
+ }
+ }
+ }
+ }
+
+ if (flgEOSPage && !flgBailError) {
+ dprintf("EOS flagged\n");
+
+ /*
+ // System has eaten all available stream packets
+ // System should now reset and recycle
+ */
+ flgBailEOS = 1;
+ }
+
+ if (flgBailEOS || flgBailError) {
+ dprintf("Bailing\n");
+
+ /*
+ // FIXME: This is effectively broken.
+
+ // CAUTION: If you do not manage to do a clean vorbis_synthesis_init
+ // these functions will have nasty malloc/free problems. You may *NOT*
+ // just clear these and hope for the best. It doesn't work.
+ //
+ // Originally, I was calling vorbis_synthesis_init too early and then
+ // vorbis_info_clear was throwing malloc/free failures.
+ */
+ vorbis_block_clear(vb);
+ vorbis_dsp_clear(vd); // Inverse of vorbis_synthesis_init() ???
+ vorbis_comment_clear(vc);
+ vorbis_info_clear(vi);
+ }
+
+ } /* This while loop iterates over ogg pages */
+
+ } /* This while loop iterates over ogg logical streams */
+
+ dprintf("Destroying stream state\n");
+
+ /* System has terminated -- clean up */
+ ogg_stream_destroy(os);
+ ogg_sync_destroy(oy);
+
+ dprintf("System bailing\n");
+
+ dprintf("Done. Consumed: %ld\n", bytesConsumed);
+
+ return(0);
+}
+
Index: synthesis.c.patch
===================================================================
--- synthesis.c.patch (revision 0)
+++ synthesis.c.patch (revision 0)
@@ -0,0 +1,57 @@
+*** synthesis.c Sun Oct 8 03:08:16 2006
+--- ../Tremor-patched-libogg1/synthesis.c Sat Oct 7 18:00:17 2006
+***************
+*** 34,40 ****
+
+ /* first things first. Make sure decode is ready */
+ _vorbis_block_ripcord(vb);
+! oggpack_readinit(opb,op->packet);
+
+ /* Check the packet type */
+ if(oggpack_read(opb,1)!=0){
+--- 34,40 ----
+
+ /* first things first. Make sure decode is ready */
+ _vorbis_block_ripcord(vb);
+! oggpack_readinit_opaque(opb,op);
+
+ /* Check the packet type */
+ if(oggpack_read(opb,1)!=0){
+***************
+*** 58,66 ****
+ }
+
+ /* more setup */
+! vb->granulepos=op->granulepos;
+! vb->sequence=op->packetno-3; /* first block is third packet */
+! vb->eofflag=op->e_o_s;
+
+ if(decodep){
+ /* alloc pcm passback storage */
+--- 58,66 ----
+ }
+
+ /* more setup */
+! vb->granulepos=ogg_packet_get_granulepos(op);
+! vb->sequence=ogg_packet_get_packetno(op)-3; /* FIXME: This doesn't match libvorbis anymore /* first block is third packet */
+! vb->eofflag=ogg_packet_get_e_o_s(op);
+
+ if(decodep){
+ /* alloc pcm passback storage */
+***************
+*** 87,93 ****
+ oggpack_buffer opb;
+ int mode;
+
+! oggpack_readinit(&opb,op->packet);
+
+ /* Check the packet type */
+ if(oggpack_read(&opb,1)!=0){
+--- 87,93 ----
+ oggpack_buffer opb;
+ int mode;
+
+! oggpack_readinit_opaque(&opb,op);
+
+ /* Check the packet type */
+ if(oggpack_read(&opb,1)!=0){
Index: ivorbisfile_example.c
===================================================================
--- ivorbisfile_example.c (revision 11894)
+++ ivorbisfile_example.c (working copy)
@@ -21,8 +21,8 @@
#include <stdio.h>
#include <stdlib.h>
-#include <vorbis/ivorbiscodec.h>
-#include <vorbis/ivorbisfile.h>
+#include "ivorbiscodec.h"
+#include "ivorbisfile.h"
#ifdef _WIN32 /* We need the following two to set stdin/stdout to binary */
#include <io.h>
Index: synthesis.c
===================================================================
--- synthesis.c (revision 11894)
+++ synthesis.c (working copy)
@@ -34,7 +34,7 @@
/* first things first. Make sure decode is ready */
_vorbis_block_ripcord(vb);
- oggpack_readinit(opb,op->packet);
+ oggpack_readinit_opaque(opb,op);
/* Check the packet type */
if(oggpack_read(opb,1)!=0){
@@ -58,9 +58,9 @@
}
/* more setup */
- vb->granulepos=op->granulepos;
- vb->sequence=op->packetno-3; /* first block is third packet */
- vb->eofflag=op->e_o_s;
+ vb->granulepos=ogg_packet_get_granulepos(op);
+ vb->sequence=ogg_packet_get_packetno(op)-3; /* FIXME: This doesn't match libvorbis anymore /* first block is third packet */
+ vb->eofflag=ogg_packet_get_e_o_s(op);
if(decodep){
/* alloc pcm passback storage */
@@ -87,7 +87,7 @@
oggpack_buffer opb;
int mode;
- oggpack_readinit(&opb,op->packet);
+ oggpack_readinit_opaque(&opb,op);
/* Check the packet type */
if(oggpack_read(&opb,1)!=0){
Index: info.c.patch
===================================================================
--- info.c.patch (revision 0)
+++ info.c.patch (revision 0)
@@ -0,0 +1,36 @@
+*** info.c Sun Oct 8 03:08:16 2006
+--- ../Tremor-patched-libogg1/info.c Sat Oct 7 18:10:02 2006
+***************
+*** 299,305 ****
+ oggpack_buffer opb;
+
+ if(op){
+! oggpack_readinit(&opb,op->packet);
+
+ /* Which of the three types of header is this? */
+ /* Also verify header-ness, vorbis */
+--- 299,305 ----
+ oggpack_buffer opb;
+
+ if(op){
+! oggpack_readinit_opaque(&opb,op);
+
+ /* Which of the three types of header is this? */
+ /* Also verify header-ness, vorbis */
+***************
+*** 314,320 ****
+ }
+ switch(packtype){
+ case 0x01: /* least significant *bit* is read first */
+! if(!op->b_o_s){
+ /* Not the initial packet */
+ return(OV_EBADHEADER);
+ }
+--- 314,320 ----
+ }
+ switch(packtype){
+ case 0x01: /* least significant *bit* is read first */
+! if(!ogg_packet_get_b_o_s(op)){
+ /* Not the initial packet */
+ return(OV_EBADHEADER);
+ }
Index: info.c
===================================================================
--- info.c (revision 11894)
+++ info.c (working copy)
@@ -299,7 +299,7 @@
oggpack_buffer opb;
if(op){
- oggpack_readinit(&opb,op->packet);
+ oggpack_readinit_opaque(&opb,op);
/* Which of the three types of header is this? */
/* Also verify header-ness, vorbis */
@@ -314,7 +314,7 @@
}
switch(packtype){
case 0x01: /* least significant *bit* is read first */
- if(!op->b_o_s){
+ if(!ogg_packet_get_b_o_s(op)){
/* Not the initial packet */
return(OV_EBADHEADER);
}
Index: streamer_example.c
===================================================================
--- streamer_example.c (revision 0)
+++ streamer_example.c (revision 0)
@@ -0,0 +1,223 @@
+/*
+ * Takes an ogg stream from stdin and reads all of the pages.
+ * as well as all of the packets. It is capable of crossing
+ * a boundary of a concatenated stream.
+ *
+ * It writes nothing out. It is meant as a basic skeleton to
+ * demonstrate how to cope with the ogg2 included in tremor.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "ivorbiscodec.h"
+
+#ifdef _WIN32 /* We need the following two to set stdin/stdout to binary */
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+#if defined(__MACOS__) && defined(__MWERKS__)
+#include <console.h> /* CodeWarrior's Mac "command-line" support */
+#endif
+
+#define dprintf(...) fprintf(stderr, __VA_ARGS__)
+
+#define BCHUNKSIZE 8192
+
+static long bytesConsumed = 0;
+
+// FIXME: This is one of the places that can throw errors
+int grabData(ogg_sync_state *oy) {
+ unsigned char* bb = ogg_sync_bufferin(oy, BCHUNKSIZE);
+ long bytesRead = fread(bb, 1, BCHUNKSIZE, stdin);
+
+ dprintf("Consumed: %ld bytes\n", bytesRead);
+
+ if (bytesRead == 0) {
+ // For now, EOF
+ return(-1);
+ }
+
+ ogg_sync_wrote(oy, bytesRead);
+ bytesConsumed += bytesRead;
+
+ return(0);
+}
+
+int main() {
+ int o_rv0 = 0;
+ int o_dr0 = 0;
+ int s_rv0 = 0;
+
+ // These abbreviations use the ogg internal conventions
+
+ // Caution: libogg uses NULL as a sentinel in places. If you feed non-NULL,
+ // on initial calls you can get into trouble
+
+ // OGG data structures
+ ogg_sync_state *oy = NULL;
+
+ // FIXME: Why is this magic required to make ogg_page work?
+ // FIXME: Why is there no ogg_page_create?
+ ogg_page og_allocated = {0, 0, 0, 0};
+ ogg_page* og = &og_allocated;
+
+
+ // Stream data structures
+ ogg_stream_state *os = NULL;
+
+ // FIXME: Why is this magic required to make ogg_page work?
+ // FIXME: Why is there no ogg_packet_create?
+ ogg_packet op_allocated = {0, 0, 0, 0, 0, 0};
+ ogg_packet* op = &op_allocated;
+
+
+ // Ogg init
+ oy = ogg_sync_create();
+
+ // Stream init
+ // Need to set the serial number later
+ os = ogg_stream_create(-1);
+
+
+
+ // CAUTION: Just about anything you do wrong pops a bus error.
+ // You need to be fairly aggressive about checking return codes
+ // and initializing properly.
+
+ int flgBailError = 0;
+ int pageCount = -1;
+
+ int flgPacketsConsumed = 0;
+ int packetCount = -1;
+
+ int flgEOSPage = 0;
+
+ while(!flgBailError) {
+ dprintf("Page: %d\n", pageCount);
+
+ if (pageCount != -1) {
+ if (pageCount == 0) {
+ // FIXME: Silly pageCount used to indicate serial number change
+ // because ogg_stream_pagein does braindead release on error and
+ // ogg_page_bos() doesn't seem to work for a concatenated stream.
+ dprintf("Beginning of stream found\n");
+
+ // Use hex to match ogginfo return
+ dprintf("Setting serial number: %x\n", ogg_page_serialno(og));
+ ogg_stream_reset_serialno(os, ogg_page_serialno(og));
+ }
+
+ // EOS test has to be up front because, of course, everything in the universe
+ // releases the page so you have to get to it *before* it disappears
+ // and store it yourself in spite of the fact that the page stores it
+ // very nicely (until it gets freed). Grrrrrrr ...
+ if (ogg_page_eos(og)) {
+ flgEOSPage = 1;
+ dprintf("End of stream found\n");
+ }
+
+ s_rv0 = ogg_stream_pagein(os, og);
+ dprintf("Page in: %d %d %p %p\n", pageCount, s_rv0, os, og);
+
+ if (s_rv0 < 0) {
+ // FIXME: ARRRGGGGHHH!!! ogg_stream_pagein releases the page on error.
+ // This is silly on serial number mismatch. Actually, it's probably
+ // silly in general on an error because it means you can't actually
+ // examine the page to see what's wrong because it just disappeared.
+
+ if (s_rv0 == OGG_ESERIAL) {
+ // Useless, because page is gone and can't be resubmitted. Grrrrr.
+ dprintf("Bailing on stream submit fail\n");
+ flgBailError = 1;
+
+ // FIXME: What we would like to do if ogg_stream_pagein wasn't braindead ...
+ // Serial number mismatch -- generally indicates start of stream
+ // Go back around and resubmit after resetting serial number
+ } else {
+ dprintf("Bailing on stream submit fail\n");
+ flgBailError = 1;
+ }
+ }
+
+ flgPacketsConsumed = 0;
+ while (!flgPacketsConsumed && !flgBailError) {
+ // Valid page submitted to stream, now pull out as packets
+ // There may be more than 1 packet per page. Pull all packets
+ // before asking for another page.
+ s_rv0 = ogg_stream_packetout(os, op);
+ dprintf("Packet out: %d %d %d %p %p\n", pageCount, packetCount, s_rv0, os, op);
+
+ if (s_rv0 < 0) {
+ flgBailError = 1;
+ dprintf("Packet consumption error bail\n");
+ } else if (s_rv0 == 0) {
+ dprintf("Packets consumed. Get more data.\n");
+ flgPacketsConsumed = 1;
+ }
+
+ if (s_rv0 > 0) {
+ // Only increment packet counter on valid packet
+ ++packetCount;
+
+ // Packet valid & counts valid ... do something with it
+ dprintf("Packet val: %d %d %d %p %p\n", pageCount, packetCount, s_rv0, os, op);
+ }
+ }
+ }
+
+ // Don't pull another page at EOS. Let that occur after reset on another
+ // trip through so that we match the normal uninitialized case.
+ if (!flgEOSPage) {
+ o_rv0 = 0;
+ while(o_rv0 != 1 && !flgBailError) {
+ o_rv0 = ogg_sync_pageout(oy, og);
+
+ if (o_rv0 > 0) {
+ // Only increment page on valid packet
+ ++pageCount;
+ }
+
+ if (o_rv0 <= 0) {
+ if (o_rv0 < 0) {
+ dprintf("Skipping bytes...\n");
+ }
+
+ if (o_rv0 == 0) {
+ dprintf("Need more data...\n");
+ }
+
+ o_dr0 = grabData(oy);
+ if (o_dr0 < 0) {
+ dprintf("Data error encountered.\n");
+ flgBailError = 1;
+ }
+ }
+ }
+ }
+
+ if (flgEOSPage) {
+ // More data might still available, reset system
+ flgEOSPage = 0;
+ pageCount = -1;
+ packetCount = -1;
+
+ ogg_stream_destroy(os);
+ os = ogg_stream_create(-1);
+ }
+ }
+
+ dprintf("System bailing\n");
+
+ // System has bailed -- clean up
+ ogg_stream_destroy(os);
+
+ ogg_page_release(og);
+ ogg_sync_destroy(oy);
+
+ dprintf("Done. Consumed: %ld\n", bytesConsumed);
+
+ return(0);
+}
+
Index: vorbisfile.c.patch
===================================================================
--- vorbisfile.c.patch (revision 0)
+++ vorbisfile.c.patch (revision 0)
@@ -0,0 +1,158 @@
+*** vorbisfile.c Sun Oct 8 03:08:16 2006
+--- ../Tremor-patched-libogg1/vorbisfile.c.patched Sat Oct 7 19:22:34 2006
+***************
+*** 201,207 ****
+ endsearched=bisect;
+ if(ret>=0)next=ret;
+ }else{
+! searched=ret+og.header_len+og.body_len;
+ }
+ ogg_page_release(&og);
+ }
+--- 201,207 ----
+ endsearched=bisect;
+ if(ret>=0)next=ret;
+ }else{
+! searched=ret+ogg_page_header_len(&og)+ogg_page_body_len(&og);
+ }
+ ogg_page_release(&og);
+ }
+***************
+*** 249,255 ****
+ }
+
+ ogg_stream_reset_serialno(vf->os,ogg_page_serialno(og_ptr));
+! if(serialno)*serialno=vf->os->serialno;
+ vf->ready_state=STREAMSET;
+
+ /* extract the initial header from the first page and verify that the
+--- 249,255 ----
+ }
+
+ ogg_stream_reset_serialno(vf->os,ogg_page_serialno(og_ptr));
+! if(serialno)*serialno=ogg_stream_state_get_serialno(vf->os);
+ vf->ready_state=STREAMSET;
+
+ /* extract the initial header from the first page and verify that the
+***************
+*** 500,506 ****
+ }
+ if(result>0){
+ /* got a packet. process it */
+! granulepos=op.granulepos;
+ if(!vorbis_synthesis(&vf->vb,&op,1)){ /* lazy check for lazy
+ header handling. The
+ header packets aren't
+--- 500,506 ----
+ }
+ if(result>0){
+ /* got a packet. process it */
+! granulepos=ogg_packet_get_granulepos(&op);
+ if(!vorbis_synthesis(&vf->vb,&op,1)){ /* lazy check for lazy
+ header handling. The
+ header packets aren't
+***************
+*** 521,531 ****
+
+ vorbis_synthesis_blockin(&vf->vd,&vf->vb);
+ vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples;
+! vf->bittrack+=op.bytes*8;
+ }
+
+ /* update the pcm offset. */
+! if(granulepos!=-1 && !op.e_o_s){
+ int link=(vf->seekable?vf->current_link:0);
+ int i,samples;
+
+--- 521,531 ----
+
+ vorbis_synthesis_blockin(&vf->vd,&vf->vb);
+ vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples;
+! vf->bittrack+=ogg_packet_get_bytes(&op)*8;
+ }
+
+ /* update the pcm offset. */
+! if(granulepos!=-1 && !ogg_packet_get_e_o_s(&op)){
+ int link=(vf->seekable?vf->current_link:0);
+ int i,samples;
+
+***************
+*** 578,584 ****
+
+ /* bitrate tracking; add the header's bytes here, the body bytes
+ are done by packet above */
+! vf->bittrack+=og.header_len*8;
+
+ /* has our decoding just traversed a bitstream boundary? */
+ if(vf->ready_state==INITSET){
+--- 578,584 ----
+
+ /* bitrate tracking; add the header's bytes here, the body bytes
+ are done by packet above */
+! vf->bittrack+=ogg_page_header_len(&og)*8;
+
+ /* has our decoding just traversed a bitstream boundary? */
+ if(vf->ready_state==INITSET){
+***************
+*** 1010,1018 ****
+ if(lastblock)accblock+=(lastblock+thisblock)>>2;
+ }
+
+! if(op.granulepos!=-1){
+ int i,link=vf->current_link;
+! ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2];
+ if(granulepos<0)granulepos=0;
+
+ for(i=0;i<link;i++)
+--- 1010,1018 ----
+ if(lastblock)accblock+=(lastblock+thisblock)>>2;
+ }
+
+! if(ogg_packet_get_granulepos(&op)!=-1){
+ int i,link=vf->current_link;
+! ogg_int64_t granulepos=ogg_packet_get_granulepos(&op)-vf->pcmlengths[link*2];
+ if(granulepos<0)granulepos=0;
+
+ for(i=0;i<link;i++)
+***************
+*** 1239,1246 ****
+ result = OV_EBADPACKET;
+ goto seek_error;
+ }
+! if(op.granulepos!=-1){
+! vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
+ if(vf->pcm_offset<0)vf->pcm_offset=0;
+ vf->pcm_offset+=total;
+ break;
+--- 1239,1246 ----
+ result = OV_EBADPACKET;
+ goto seek_error;
+ }
+! if(ogg_packet_get_granulepos(&op)!=-1){
+! vf->pcm_offset=ogg_packet_get_granulepos(&op)-vf->pcmlengths[vf->current_link*2];
+ if(vf->pcm_offset<0)vf->pcm_offset=0;
+ vf->pcm_offset+=total;
+ break;
+***************
+*** 1311,1320 ****
+ /* end of logical stream case is hard, especially with exact
+ length positioning. */
+
+! if(op.granulepos>-1){
+ int i;
+ /* always believe the stream markers */
+! vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
+ if(vf->pcm_offset<0)vf->pcm_offset=0;
+ for(i=0;i<vf->current_link;i++)
+ vf->pcm_offset+=vf->pcmlengths[i*2+1];
+--- 1311,1320 ----
+ /* end of logical stream case is hard, especially with exact
+ length positioning. */
+
+! if(ogg_packet_get_granulepos(&op)>-1){
+ int i;
+ /* always believe the stream markers */
+! vf->pcm_offset=ogg_packet_get_granulepos(&op)-vf->pcmlengths[vf->current_link*2];
+ if(vf->pcm_offset<0)vf->pcm_offset=0;
+ for(i=0;i<vf->current_link;i++)
+ vf->pcm_offset+=vf->pcmlengths[i*2+1];
Index: vorbisfile.c
===================================================================
--- vorbisfile.c (revision 11894)
+++ vorbisfile.c (working copy)
@@ -201,7 +201,7 @@
endsearched=bisect;
if(ret>=0)next=ret;
}else{
- searched=ret+og.header_len+og.body_len;
+ searched=ret+ogg_page_header_len(&og)+ogg_page_body_len(&og);
}
ogg_page_release(&og);
}
@@ -249,7 +249,7 @@
}
ogg_stream_reset_serialno(vf->os,ogg_page_serialno(og_ptr));
- if(serialno)*serialno=vf->os->serialno;
+ if(serialno)*serialno=ogg_stream_state_get_serialno(vf->os);
vf->ready_state=STREAMSET;
/* extract the initial header from the first page and verify that the
@@ -500,7 +500,7 @@
}
if(result>0){
/* got a packet. process it */
- granulepos=op.granulepos;
+ granulepos=ogg_packet_get_granulepos(&op);
if(!vorbis_synthesis(&vf->vb,&op,1)){ /* lazy check for lazy
header handling. The
header packets aren't
@@ -521,11 +521,11 @@
vorbis_synthesis_blockin(&vf->vd,&vf->vb);
vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples;
- vf->bittrack+=op.bytes*8;
+ vf->bittrack+=ogg_packet_get_bytes(&op)*8;
}
/* update the pcm offset. */
- if(granulepos!=-1 && !op.e_o_s){
+ if(granulepos!=-1 && !ogg_packet_get_e_o_s(&op)){
int link=(vf->seekable?vf->current_link:0);
int i,samples;
@@ -578,7 +578,7 @@
/* bitrate tracking; add the header's bytes here, the body bytes
are done by packet above */
- vf->bittrack+=og.header_len*8;
+ vf->bittrack+=ogg_page_header_len(&og)*8;
/* has our decoding just traversed a bitstream boundary? */
if(vf->ready_state==INITSET){
@@ -1010,9 +1010,9 @@
if(lastblock)accblock+=(lastblock+thisblock)>>2;
}
- if(op.granulepos!=-1){
+ if(ogg_packet_get_granulepos(&op)!=-1){
int i,link=vf->current_link;
- ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2];
+ ogg_int64_t granulepos=ogg_packet_get_granulepos(&op)-vf->pcmlengths[link*2];
if(granulepos<0)granulepos=0;
for(i=0;i<link;i++)
@@ -1239,8 +1239,8 @@
result = OV_EBADPACKET;
goto seek_error;
}
- if(op.granulepos!=-1){
- vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
+ if(ogg_packet_get_granulepos(&op)!=-1){
+ vf->pcm_offset=ogg_packet_get_granulepos(&op)-vf->pcmlengths[vf->current_link*2];
if(vf->pcm_offset<0)vf->pcm_offset=0;
vf->pcm_offset+=total;
break;
@@ -1311,10 +1311,10 @@
/* end of logical stream case is hard, especially with exact
length positioning. */
- if(op.granulepos>-1){
+ if(ogg_packet_get_granulepos(&op)>-1){
int i;
/* always believe the stream markers */
- vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
+ vf->pcm_offset=ogg_packet_get_granulepos(&op)-vf->pcmlengths[vf->current_link*2];
if(vf->pcm_offset<0)vf->pcm_offset=0;
for(i=0;i<vf->current_link;i++)
vf->pcm_offset+=vf->pcmlengths[i*2+1];
Index: ogg_reader_example.c
===================================================================
--- ogg_reader_example.c (revision 0)
+++ ogg_reader_example.c (revision 0)
@@ -0,0 +1,105 @@
+/*
+ * Takes an ogg stream from stdin and reads all of the pages.
+ * It will happily read all pages of even concatenated ogg streams.
+ * It writes nothing out. It is meant as a basic skeleton to
+ * demonstrate how to cope with the ogg2 included in tremor.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "ivorbiscodec.h"
+
+#ifdef _WIN32 /* We need the following two to set stdin/stdout to binary */
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+#if defined(__MACOS__) && defined(__MWERKS__)
+#include <console.h> /* CodeWarrior's Mac "command-line" support */
+#endif
+
+#define dprintf(...) fprintf(stderr, __VA_ARGS__)
+
+#define BCHUNKSIZE 8192
+
+static long bytesConsumed = 0;
+
+// FIXME: This is one of the places that can throw errors
+int grabData(ogg_sync_state *oy) {
+ unsigned char* bb = ogg_sync_bufferin(oy, BCHUNKSIZE);
+ long bytesRead = fread(bb, 1, BCHUNKSIZE, stdin);
+
+ dprintf("Consumed: %ld bytes\n", bytesRead);
+
+ if (bytesRead == 0) {
+ // For now, EOF
+ return(-1);
+ }
+
+ ogg_sync_wrote(oy, bytesRead);
+ bytesConsumed += bytesRead;
+
+ return(0);
+}
+
+int main() {
+ int rv0 = 0;
+ int dr0 = 0;
+
+ // These abbreviations use the ogg internal conventions
+
+ // Caution: libogg uses NULL as a sentinel in places. If you feed non-NULL,
+ // on initial calls you can get into trouble
+ ogg_sync_state *oy = NULL;
+
+ // FIXME: Why is this magic required to make ogg_page work?
+ // FIXME: Why is there no ogg_page_create?
+ ogg_page og_allocated = {0, 0, 0, 0};
+ ogg_page *og = &og_allocated;
+
+ oy = ogg_sync_create();
+
+ int flgBail = 0;
+ int pageCount = -1;
+ while(!flgBail) {
+ dprintf("Page: %d\n", pageCount);
+
+ rv0 = 0;
+ while(rv0 != 1 && !flgBail) {
+ rv0 = ogg_sync_pageout(oy, og);
+
+ if (rv0 > 0) {
+ // Only increment page on valid packet
+ ++pageCount;
+ }
+
+ if (rv0 <= 0) {
+ if (rv0 < 0) {
+ dprintf("Skipping bytes...\n");
+ }
+
+ if (rv0 == 0) {
+ dprintf("Need more data...\n");
+ }
+
+ dr0 = grabData(oy);
+ if (dr0 < 0) {
+ dprintf("Data error encountered.\n");
+ flgBail = 1;
+ }
+ }
+ }
+ }
+
+ dprintf("System bailing\n");
+
+ // System has bailed -- clean up
+ ogg_page_release(og);
+ ogg_sync_destroy(oy);
+
+ dprintf("Done. Consumed: %ld\n", bytesConsumed);
+
+ return(0);
+}
+
Index: ogg.h
===================================================================
--- ogg.h (revision 11894)
+++ ogg.h (working copy)
@@ -199,6 +199,21 @@
#define OGG_EEOS -15
+/* Static inline accessors to avoid hitting the struct directly */
+static inline long ogg_stream_state_get_serialno(ogg_stream_state* os) {return os->serialno;};
+
+static inline long ogg_packet_get_bytes(ogg_packet* op) {return op->bytes;};
+static inline ogg_int64_t ogg_packet_get_granulepos(ogg_packet* op) {return op->granulepos;};
+static inline ogg_int64_t ogg_packet_get_packetno(ogg_packet* op) {return op->packetno;};
+static inline long ogg_packet_get_b_o_s(ogg_packet* op) {return op->b_o_s;};
+static inline long ogg_packet_get_e_o_s(ogg_packet* op) {return op->e_o_s;};
+
+static inline int ogg_page_header_len(ogg_page* og) {return og->header_len;};
+static inline long ogg_page_body_len(ogg_page* og) {return og->body_len;};
+
+static inline void oggpack_readinit_opaque(oggpack_buffer *b, ogg_packet *op) {oggpack_readinit(b, op->packet);};
+
+
#ifdef __cplusplus
}
#endif
More information about the Vorbis
mailing list