Blame examples/decoder_example.c

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