diff src/libvorbis-1.3.3/examples/decoder_example.c @ 1:05aa0afa9217

Bring in flac, ogg, vorbis
author Chris Cannam
date Tue, 19 Mar 2013 17:37:49 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libvorbis-1.3.3/examples/decoder_example.c	Tue Mar 19 17:37:49 2013 +0000
@@ -0,0 +1,314 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009             *
+ * by the Xiph.Org Foundation http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+ function: simple example decoder
+ last mod: $Id: decoder_example.c 16243 2009-07-10 02:49:31Z xiphmont $
+
+ ********************************************************************/
+
+/* Takes a vorbis bitstream from stdin and writes raw stereo PCM to
+   stdout. Decodes simple and chained OggVorbis files from beginning
+   to end. Vorbisfile.a is somewhat more complex than the code below.  */
+
+/* Note that this is POSIX, not ANSI code */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <vorbis/codec.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
+
+ogg_int16_t convbuffer[4096]; /* take 8k out of the data segment, not the stack */
+int convsize=4096;
+
+extern void _VDBG_dump(void);
+
+int main(){
+  ogg_sync_state   oy; /* sync and verify incoming physical bitstream */
+  ogg_stream_state os; /* take physical pages, weld into a logical
+                          stream of packets */
+  ogg_page         og; /* one Ogg bitstream page. Vorbis packets are inside */
+  ogg_packet       op; /* one raw packet of data for decode */
+
+  vorbis_info      vi; /* struct that stores all the static vorbis bitstream
+                          settings */
+  vorbis_comment   vc; /* struct that stores all the bitstream user comments */
+  vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
+  vorbis_block     vb; /* local working space for packet->PCM decode */
+
+  char *buffer;
+  int  bytes;
+
+#ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows. */
+  /* Beware the evil ifdef. We avoid these where we can, but this one we
+     cannot. Don't add any more, you'll probably go to hell if you do. */
+  _setmode( _fileno( stdin ), _O_BINARY );
+  _setmode( _fileno( stdout ), _O_BINARY );
+#endif
+
+#if defined(macintosh) && defined(__MWERKS__)
+  {
+    int argc;
+    char **argv;
+    argc=ccommand(&argv); /* get a "command line" from the Mac user */
+                     /* this also lets the user set stdin and stdout */
+  }
+#endif
+
+  /********** Decode setup ************/
+
+  ogg_sync_init(&oy); /* Now we can read pages */
+  
+  while(1){ /* we repeat if the bitstream is chained */
+    int eos=0;
+    int i;
+
+    /* grab some data at the head of the stream. We want the first page
+       (which is guaranteed to be small and only contain the Vorbis
+       stream initial header) We need the first page to get the stream
+       serialno. */
+
+    /* submit a 4k block to libvorbis' Ogg layer */
+    buffer=ogg_sync_buffer(&oy,4096);
+    bytes=fread(buffer,1,4096,stdin);
+    ogg_sync_wrote(&oy,bytes);
+    
+    /* Get the first page. */
+    if(ogg_sync_pageout(&oy,&og)!=1){
+      /* have we simply run out of data?  If so, we're done. */
+      if(bytes<4096)break;
+      
+      /* error case.  Must not be Vorbis data */
+      fprintf(stderr,"Input does not appear to be an Ogg bitstream.\n");
+      exit(1);
+    }
+  
+    /* Get the serial number and set up the rest of decode. */
+    /* serialno first; use it to set up a logical stream */
+    ogg_stream_init(&os,ogg_page_serialno(&og));
+    
+    /* extract the initial header from the first page and verify that the
+       Ogg bitstream is in fact Vorbis data */
+    
+    /* I handle the initial header first instead of just having the code
+       read all three Vorbis headers at once because reading the initial
+       header is an easy way to identify a Vorbis bitstream and it's
+       useful to see that functionality seperated out. */
+    
+    vorbis_info_init(&vi);
+    vorbis_comment_init(&vc);
+    if(ogg_stream_pagein(&os,&og)<0){ 
+      /* error; stream version mismatch perhaps */
+      fprintf(stderr,"Error reading first page of Ogg bitstream data.\n");
+      exit(1);
+    }
+    
+    if(ogg_stream_packetout(&os,&op)!=1){ 
+      /* no page? must not be vorbis */
+      fprintf(stderr,"Error reading initial header packet.\n");
+      exit(1);
+    }
+    
+    if(vorbis_synthesis_headerin(&vi,&vc,&op)<0){ 
+      /* error case; not a vorbis header */
+      fprintf(stderr,"This Ogg bitstream does not contain Vorbis "
+              "audio data.\n");
+      exit(1);
+    }
+    
+    /* At this point, we're sure we're Vorbis. We've set up the logical
+       (Ogg) bitstream decoder. Get the comment and codebook headers and
+       set up the Vorbis decoder */
+    
+    /* The next two packets in order are the comment and codebook headers.
+       They're likely large and may span multiple pages. Thus we read
+       and submit data until we get our two packets, watching that no
+       pages are missing. If a page is missing, error out; losing a
+       header page is the only place where missing data is fatal. */
+    
+    i=0;
+    while(i<2){
+      while(i<2){
+        int result=ogg_sync_pageout(&oy,&og);
+        if(result==0)break; /* Need more data */
+        /* Don't complain about missing or corrupt data yet. We'll
+           catch it at the packet output phase */
+        if(result==1){
+          ogg_stream_pagein(&os,&og); /* we can ignore any errors here
+                                         as they'll also become apparent
+                                         at packetout */
+          while(i<2){
+            result=ogg_stream_packetout(&os,&op);
+            if(result==0)break;
+            if(result<0){
+              /* Uh oh; data at some point was corrupted or missing!
+                 We can't tolerate that in a header.  Die. */
+              fprintf(stderr,"Corrupt secondary header.  Exiting.\n");
+              exit(1);
+            }
+            result=vorbis_synthesis_headerin(&vi,&vc,&op);
+            if(result<0){
+              fprintf(stderr,"Corrupt secondary header.  Exiting.\n");
+              exit(1);
+            }
+            i++;
+          }
+        }
+      }
+      /* no harm in not checking before adding more */
+      buffer=ogg_sync_buffer(&oy,4096);
+      bytes=fread(buffer,1,4096,stdin);
+      if(bytes==0 && i<2){
+        fprintf(stderr,"End of file before finding all Vorbis headers!\n");
+        exit(1);
+      }
+      ogg_sync_wrote(&oy,bytes);
+    }
+    
+    /* Throw the comments plus a few lines about the bitstream we're
+       decoding */
+    {
+      char **ptr=vc.user_comments;
+      while(*ptr){
+        fprintf(stderr,"%s\n",*ptr);
+        ++ptr;
+      }
+      fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",vi.channels,vi.rate);
+      fprintf(stderr,"Encoded by: %s\n\n",vc.vendor);
+    }
+    
+    convsize=4096/vi.channels;
+
+    /* OK, got and parsed all three headers. Initialize the Vorbis
+       packet->PCM decoder. */
+    if(vorbis_synthesis_init(&vd,&vi)==0){ /* central decode state */
+      vorbis_block_init(&vd,&vb);          /* local state for most of the decode
+                                              so multiple block decodes can
+                                              proceed in parallel. We could init
+                                              multiple vorbis_block structures
+                                              for vd here */
+      
+      /* The rest is just a straight decode loop until end of stream */
+      while(!eos){
+        while(!eos){
+          int result=ogg_sync_pageout(&oy,&og);
+          if(result==0)break; /* need more data */
+          if(result<0){ /* missing or corrupt data at this page position */
+            fprintf(stderr,"Corrupt or missing data in bitstream; "
+                    "continuing...\n");
+          }else{
+            ogg_stream_pagein(&os,&og); /* can safely ignore errors at
+                                           this point */
+            while(1){
+              result=ogg_stream_packetout(&os,&op);
+              
+              if(result==0)break; /* need more data */
+              if(result<0){ /* missing or corrupt data at this page position */
+                /* no reason to complain; already complained above */
+              }else{
+                /* we have a packet.  Decode it */
+                float **pcm;
+                int samples;
+                
+                if(vorbis_synthesis(&vb,&op)==0) /* test for success! */
+                  vorbis_synthesis_blockin(&vd,&vb);
+                /* 
+                   
+                **pcm is a multichannel float vector.  In stereo, for
+                example, pcm[0] is left, and pcm[1] is right.  samples is
+                the size of each channel.  Convert the float values
+                (-1.<=range<=1.) to whatever PCM format and write it out */
+                
+                while((samples=vorbis_synthesis_pcmout(&vd,&pcm))>0){
+                  int j;
+                  int clipflag=0;
+                  int bout=(samples<convsize?samples:convsize);
+                  
+                  /* convert floats to 16 bit signed ints (host order) and
+                     interleave */
+                  for(i=0;i<vi.channels;i++){
+                    ogg_int16_t *ptr=convbuffer+i;
+                    float  *mono=pcm[i];
+                    for(j=0;j<bout;j++){
+#if 1
+                      int val=floor(mono[j]*32767.f+.5f);
+#else /* optional dither */
+                      int val=mono[j]*32767.f+drand48()-0.5f;
+#endif
+                      /* might as well guard against clipping */
+                      if(val>32767){
+                        val=32767;
+                        clipflag=1;
+                      }
+                      if(val<-32768){
+                        val=-32768;
+                        clipflag=1;
+                      }
+                      *ptr=val;
+                      ptr+=vi.channels;
+                    }
+                  }
+                  
+                  if(clipflag)
+                    fprintf(stderr,"Clipping in frame %ld\n",(long)(vd.sequence));
+                  
+                  
+                  fwrite(convbuffer,2*vi.channels,bout,stdout);
+                  
+                  vorbis_synthesis_read(&vd,bout); /* tell libvorbis how
+                                                      many samples we
+                                                      actually consumed */
+                }            
+              }
+            }
+            if(ogg_page_eos(&og))eos=1;
+          }
+        }
+        if(!eos){
+          buffer=ogg_sync_buffer(&oy,4096);
+          bytes=fread(buffer,1,4096,stdin);
+          ogg_sync_wrote(&oy,bytes);
+          if(bytes==0)eos=1;
+        }
+      }
+      
+      /* ogg_page and ogg_packet structs always point to storage in
+         libvorbis.  They're never freed or manipulated directly */
+      
+      vorbis_block_clear(&vb);
+      vorbis_dsp_clear(&vd);
+    }else{
+      fprintf(stderr,"Error: Corrupt header during playback initialization.\n");
+    }
+
+    /* clean up this logical bitstream; before exit we see if we're
+       followed by another [chained] */
+    
+    ogg_stream_clear(&os);
+    vorbis_comment_clear(&vc);
+    vorbis_info_clear(&vi);  /* must be called last */
+  }
+
+  /* OK, clean up the framer */
+  ogg_sync_clear(&oy);
+  
+  fprintf(stderr,"Done.\n");
+  return(0);
+}