[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