final beta 4 commit
[platform/upstream/libvorbis.git] / examples / decoder_example.c
1 /********************************************************************
2  *                                                                  *
3  * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
4  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
5  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
7  *                                                                  *
8  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001             *
9  * by the XIPHOPHORUS Company http://www.xiph.org/                  *
10
11  ********************************************************************
12
13  function: simple example decoder
14  last mod: $Id: decoder_example.c,v 1.18 2001/02/26 03:50:38 xiphmont Exp $
15
16  ********************************************************************/
17
18 /* Takes a vorbis bitstream from stdin and writes raw stereo PCM to
19    stdout.  Decodes simple and chained OggVorbis files from beginning
20    to end.  Vorbisfile.a is somewhat more complex than the code below.  */
21
22 /* Note that this is POSIX, not ANSI code */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <math.h>
27 #include <vorbis/codec.h>
28
29 #ifdef _WIN32 /* We need the following two to set stdin/stdout to binary */
30 #include <io.h>
31 #include <fcntl.h>
32 #endif
33
34 #if defined(macintosh) && defined(__MWERKS__)
35 #include <console.h>      /* CodeWarrior's Mac "command-line" support */
36 #endif
37
38 ogg_int16_t convbuffer[4096]; /* take 8k out of the data segment, not the stack */
39 int convsize=4096;
40
41 int main(int argc, char **argv){
42   ogg_sync_state   oy; /* sync and verify incoming physical bitstream */
43   ogg_stream_state os; /* take physical pages, weld into a logical
44                           stream of packets */
45   ogg_page         og; /* one Ogg bitstream page.  Vorbis packets are inside */
46   ogg_packet       op; /* one raw packet of data for decode */
47   
48   vorbis_info      vi; /* struct that stores all the static vorbis bitstream
49                           settings */
50   vorbis_comment   vc; /* struct that stores all the bitstream user comments */
51   vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
52   vorbis_block     vb; /* local working space for packet->PCM decode */
53   
54   char *buffer;
55   int  bytes;
56
57 #ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows. */
58   /* Beware the evil ifdef. We avoid these where we can, but this one we 
59      cannot. Don't add any more, you'll probably go to hell if you do. */
60   _setmode( _fileno( stdin ), _O_BINARY );
61   _setmode( _fileno( stdout ), _O_BINARY );
62 #endif
63
64 #if defined(macintosh) && defined(__MWERKS__)
65
66   argc = ccommand(&argv); /* get a "command line" from the Mac user */
67                           /* this also lets the user set stdin and stdout */
68 #endif
69
70   /********** Decode setup ************/
71
72   ogg_sync_init(&oy); /* Now we can read pages */
73   
74   while(1){ /* we repeat if the bitstream is chained */
75     int eos=0;
76     int i;
77
78     /* grab some data at the head of the stream.  We want the first page
79        (which is guaranteed to be small and only contain the Vorbis
80        stream initial header) We need the first page to get the stream
81        serialno. */
82
83     /* submit a 4k block to libvorbis' Ogg layer */
84     buffer=ogg_sync_buffer(&oy,4096);
85     bytes=fread(buffer,1,4096,stdin);
86     ogg_sync_wrote(&oy,bytes);
87     
88     /* Get the first page. */
89     if(ogg_sync_pageout(&oy,&og)!=1){
90       /* have we simply run out of data?  If so, we're done. */
91       if(bytes<4096)break;
92       
93       /* error case.  Must not be Vorbis data */
94       fprintf(stderr,"Input does not appear to be an Ogg bitstream.\n");
95       exit(1);
96     }
97   
98     /* Get the serial number and set up the rest of decode. */
99     /* serialno first; use it to set up a logical stream */
100     ogg_stream_init(&os,ogg_page_serialno(&og));
101     
102     /* extract the initial header from the first page and verify that the
103        Ogg bitstream is in fact Vorbis data */
104     
105     /* I handle the initial header first instead of just having the code
106        read all three Vorbis headers at once because reading the initial
107        header is an easy way to identify a Vorbis bitstream and it's
108        useful to see that functionality seperated out. */
109     
110     vorbis_info_init(&vi);
111     vorbis_comment_init(&vc);
112     if(ogg_stream_pagein(&os,&og)<0){ 
113       /* error; stream version mismatch perhaps */
114       fprintf(stderr,"Error reading first page of Ogg bitstream data.\n");
115       exit(1);
116     }
117     
118     if(ogg_stream_packetout(&os,&op)!=1){ 
119       /* no page? must not be vorbis */
120       fprintf(stderr,"Error reading initial header packet.\n");
121       exit(1);
122     }
123     
124     if(vorbis_synthesis_headerin(&vi,&vc,&op)<0){ 
125       /* error case; not a vorbis header */
126       fprintf(stderr,"This Ogg bitstream does not contain Vorbis "
127               "audio data.\n");
128       exit(1);
129     }
130     
131     /* At this point, we're sure we're Vorbis.  We've set up the logical
132        (Ogg) bitstream decoder.  Get the comment and codebook headers and
133        set up the Vorbis decoder */
134     
135     /* The next two packets in order are the comment and codebook headers.
136        They're likely large and may span multiple pages.  Thus we reead
137        and submit data until we get our two pacakets, watching that no
138        pages are missing.  If a page is missing, error out; losing a
139        header page is the only place where missing data is fatal. */
140     
141     i=0;
142     while(i<2){
143       while(i<2){
144         int result=ogg_sync_pageout(&oy,&og);
145         if(result==0)break; /* Need more data */
146         /* Don't complain about missing or corrupt data yet.  We'll
147            catch it at the packet output phase */
148         if(result==1){
149           ogg_stream_pagein(&os,&og); /* we can ignore any errors here
150                                          as they'll also become apparent
151                                          at packetout */
152           while(i<2){
153             result=ogg_stream_packetout(&os,&op);
154             if(result==0)break;
155             if(result<0){
156               /* Uh oh; data at some point was corrupted or missing!
157                  We can't tolerate that in a header.  Die. */
158               fprintf(stderr,"Corrupt secondary header.  Exiting.\n");
159               exit(1);
160             }
161             vorbis_synthesis_headerin(&vi,&vc,&op);
162             i++;
163           }
164         }
165       }
166       /* no harm in not checking before adding more */
167       buffer=ogg_sync_buffer(&oy,4096);
168       bytes=fread(buffer,1,4096,stdin);
169       if(bytes==0 && i<2){
170         fprintf(stderr,"End of file before finding all Vorbis headers!\n");
171         exit(1);
172       }
173       ogg_sync_wrote(&oy,bytes);
174     }
175     
176     /* Throw the comments plus a few lines about the bitstream we're
177        decoding */
178     {
179       char **ptr=vc.user_comments;
180       while(*ptr){
181         fprintf(stderr,"%s\n",*ptr);
182         ++ptr;
183       }
184       fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",vi.channels,vi.rate);
185       fprintf(stderr,"Encoded by: %s\n\n",vc.vendor);
186     }
187     
188     convsize=4096/vi.channels;
189
190     /* OK, got and parsed all three headers. Initialize the Vorbis
191        packet->PCM decoder. */
192     vorbis_synthesis_init(&vd,&vi); /* central decode state */
193     vorbis_block_init(&vd,&vb);     /* local state for most of the decode
194                                        so multiple block decodes can
195                                        proceed in parallel.  We could init
196                                        multiple vorbis_block structures
197                                        for vd here */
198     
199     /* The rest is just a straight decode loop until end of stream */
200     while(!eos){
201       while(!eos){
202         int result=ogg_sync_pageout(&oy,&og);
203         if(result==0)break; /* need more data */
204         if(result<0){ /* missing or corrupt data at this page position */
205           fprintf(stderr,"Corrupt or missing data in bitstream; "
206                   "continuing...\n");
207         }else{
208           ogg_stream_pagein(&os,&og); /* can safely ignore errors at
209                                          this point */
210           while(1){
211             result=ogg_stream_packetout(&os,&op);
212
213             if(result==0)break; /* need more data */
214             if(result<0){ /* missing or corrupt data at this page position */
215               /* no reason to complain; already complained above */
216             }else{
217               /* we have a packet.  Decode it */
218               float **pcm;
219               int samples;
220               
221               if(vorbis_synthesis(&vb,&op)==0) /* test for success! */
222                 vorbis_synthesis_blockin(&vd,&vb);
223               /* 
224                  
225               **pcm is a multichannel float vector.  In stereo, for
226               example, pcm[0] is left, and pcm[1] is right.  samples is
227               the size of each channel.  Convert the float values
228               (-1.<=range<=1.) to whatever PCM format and write it out */
229               
230               while((samples=vorbis_synthesis_pcmout(&vd,&pcm))>0){
231                 int j;
232                 int clipflag=0;
233                 int bout=(samples<convsize?samples:convsize);
234                 
235                 /* convert floats to 16 bit signed ints (host order) and
236                    interleave */
237                 for(i=0;i<vi.channels;i++){
238                   ogg_int16_t *ptr=convbuffer+i;
239                   float  *mono=pcm[i];
240                   for(j=0;j<bout;j++){
241 #if 1
242                     int val=mono[j]*32767.f;
243 #else /* optional dither */
244                     int val=mono[j]*32767.f+drand48()-0.5f;
245 #endif
246                     /* might as well guard against clipping */
247                     if(val>32767){
248                       val=32767;
249                       clipflag=1;
250                     }
251                     if(val<-32768){
252                       val=-32768;
253                       clipflag=1;
254                     }
255                     *ptr=val;
256                     ptr+=2;
257                   }
258                 }
259                 
260                 if(clipflag)
261                   fprintf(stderr,"Clipping in frame %ld\n",(long)(vd.sequence));
262                 
263                 
264                 fwrite(convbuffer,2*vi.channels,bout,stdout);
265                 
266                 vorbis_synthesis_read(&vd,bout); /* tell libvorbis how
267                                                    many samples we
268                                                    actually consumed */
269               }     
270             }
271           }
272           if(ogg_page_eos(&og))eos=1;
273         }
274       }
275       if(!eos){
276         buffer=ogg_sync_buffer(&oy,4096);
277         bytes=fread(buffer,1,4096,stdin);
278         ogg_sync_wrote(&oy,bytes);
279         if(bytes==0)eos=1;
280       }
281     }
282     
283     /* clean up this logical bitstream; before exit we see if we're
284        followed by another [chained] */
285
286     ogg_stream_clear(&os);
287   
288     /* ogg_page and ogg_packet structs always point to storage in
289        libvorbis.  They're never freed or manipulated directly */
290     
291     vorbis_block_clear(&vb);
292     vorbis_dsp_clear(&vd);
293         vorbis_comment_clear(&vc);
294     vorbis_info_clear(&vi);  /* must be called last */
295   }
296
297   /* OK, clean up the framer */
298   ogg_sync_clear(&oy);
299   
300   fprintf(stderr,"Done.\n");
301   return(0);
302 }
303