Add support for named files on the command line, while maintaining
[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.21 2001/09/15 04:47:48 cwolf 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   FILE *fpin=NULL;
57   FILE *fpout=NULL;
58   char msg[512];
59
60 #ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows. */
61   /* Beware the evil ifdef. We avoid these where we can, but this one we 
62      cannot. Don't add any more, you'll probably go to hell if you do. */
63   _setmode( _fileno( stdin ), _O_BINARY );
64   _setmode( _fileno( stdout ), _O_BINARY );
65 #endif
66
67 #if defined(macintosh) && defined(__MWERKS__)
68
69   argc = ccommand(&argv); /* get a "command line" from the Mac user */
70                           /* this also lets the user set stdin and stdout */
71 #endif
72
73   /* If command line args were supplied, open the named file(s)
74      for i/o, else maintain use of stdin/stdout.*/
75   if (argc == 3)
76   {
77     if ((fpin = fopen(argv[1], "rb")) == (FILE*)NULL)
78     {
79       (void)sprintf(msg, "Can't open %s for reading.", argv[1]);
80       perror(msg);
81       return 1;
82     }
83
84     if ((fpout = fopen(argv[2], "wb")) == (FILE*)NULL)
85     {
86       (void)sprintf(msg, "Can't open %s for writing.", argv[2]);
87       perror(msg);
88       return 1;
89     }
90   }
91   else
92   {
93     fpin = stdin;
94     fpout = stdout;
95   }
96   /********** Decode setup ************/
97
98   ogg_sync_init(&oy); /* Now we can read pages */
99   
100   while(1){ /* we repeat if the bitstream is chained */
101     int eos=0;
102     int i;
103
104     /* grab some data at the head of the stream.  We want the first page
105        (which is guaranteed to be small and only contain the Vorbis
106        stream initial header) We need the first page to get the stream
107        serialno. */
108
109     /* submit a 4k block to libvorbis' Ogg layer */
110     buffer=ogg_sync_buffer(&oy,4096);
111     bytes=fread(buffer,1,4096,fpin);
112     ogg_sync_wrote(&oy,bytes);
113     
114     /* Get the first page. */
115     if(ogg_sync_pageout(&oy,&og)!=1){
116       /* have we simply run out of data?  If so, we're done. */
117       if(bytes<4096)break;
118       
119       /* error case.  Must not be Vorbis data */
120       fprintf(stderr,"Input does not appear to be an Ogg bitstream.\n");
121       exit(1);
122     }
123   
124     /* Get the serial number and set up the rest of decode. */
125     /* serialno first; use it to set up a logical stream */
126     ogg_stream_init(&os,ogg_page_serialno(&og));
127     
128     /* extract the initial header from the first page and verify that the
129        Ogg bitstream is in fact Vorbis data */
130     
131     /* I handle the initial header first instead of just having the code
132        read all three Vorbis headers at once because reading the initial
133        header is an easy way to identify a Vorbis bitstream and it's
134        useful to see that functionality seperated out. */
135     
136     vorbis_info_init(&vi);
137     vorbis_comment_init(&vc);
138     if(ogg_stream_pagein(&os,&og)<0){ 
139       /* error; stream version mismatch perhaps */
140       fprintf(stderr,"Error reading first page of Ogg bitstream data.\n");
141       exit(1);
142     }
143     
144     if(ogg_stream_packetout(&os,&op)!=1){ 
145       /* no page? must not be vorbis */
146       fprintf(stderr,"Error reading initial header packet.\n");
147       exit(1);
148     }
149     
150     if(vorbis_synthesis_headerin(&vi,&vc,&op)<0){ 
151       /* error case; not a vorbis header */
152       fprintf(stderr,"This Ogg bitstream does not contain Vorbis "
153               "audio data.\n");
154       exit(1);
155     }
156     
157     /* At this point, we're sure we're Vorbis.  We've set up the logical
158        (Ogg) bitstream decoder.  Get the comment and codebook headers and
159        set up the Vorbis decoder */
160     
161     /* The next two packets in order are the comment and codebook headers.
162        They're likely large and may span multiple pages.  Thus we reead
163        and submit data until we get our two pacakets, watching that no
164        pages are missing.  If a page is missing, error out; losing a
165        header page is the only place where missing data is fatal. */
166     
167     i=0;
168     while(i<2){
169       while(i<2){
170         int result=ogg_sync_pageout(&oy,&og);
171         if(result==0)break; /* Need more data */
172         /* Don't complain about missing or corrupt data yet.  We'll
173            catch it at the packet output phase */
174         if(result==1){
175           ogg_stream_pagein(&os,&og); /* we can ignore any errors here
176                                          as they'll also become apparent
177                                          at packetout */
178           while(i<2){
179             result=ogg_stream_packetout(&os,&op);
180             if(result==0)break;
181             if(result<0){
182               /* Uh oh; data at some point was corrupted or missing!
183                  We can't tolerate that in a header.  Die. */
184               fprintf(stderr,"Corrupt secondary header.  Exiting.\n");
185               exit(1);
186             }
187             vorbis_synthesis_headerin(&vi,&vc,&op);
188             i++;
189           }
190         }
191       }
192       /* no harm in not checking before adding more */
193       buffer=ogg_sync_buffer(&oy,4096);
194       bytes=fread(buffer,1,4096,fpin);
195       if(bytes==0 && i<2){
196         fprintf(stderr,"End of file before finding all Vorbis headers!\n");
197         exit(1);
198       }
199       ogg_sync_wrote(&oy,bytes);
200     }
201     
202     /* Throw the comments plus a few lines about the bitstream we're
203        decoding */
204     {
205       char **ptr=vc.user_comments;
206       while(*ptr){
207         fprintf(stderr,"%s\n",*ptr);
208         ++ptr;
209       }
210       fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",vi.channels,vi.rate);
211       fprintf(stderr,"Encoded by: %s\n\n",vc.vendor);
212     }
213     
214     convsize=4096/vi.channels;
215
216     /* OK, got and parsed all three headers. Initialize the Vorbis
217        packet->PCM decoder. */
218     vorbis_synthesis_init(&vd,&vi); /* central decode state */
219     vorbis_block_init(&vd,&vb);     /* local state for most of the decode
220                                        so multiple block decodes can
221                                        proceed in parallel.  We could init
222                                        multiple vorbis_block structures
223                                        for vd here */
224     
225     /* The rest is just a straight decode loop until end of stream */
226     while(!eos){
227       while(!eos){
228         int result=ogg_sync_pageout(&oy,&og);
229         if(result==0)break; /* need more data */
230         if(result<0){ /* missing or corrupt data at this page position */
231           fprintf(stderr,"Corrupt or missing data in bitstream; "
232                   "continuing...\n");
233         }else{
234           ogg_stream_pagein(&os,&og); /* can safely ignore errors at
235                                          this point */
236           while(1){
237             result=ogg_stream_packetout(&os,&op);
238
239             if(result==0)break; /* need more data */
240             if(result<0){ /* missing or corrupt data at this page position */
241               /* no reason to complain; already complained above */
242             }else{
243               /* we have a packet.  Decode it */
244               float **pcm;
245               int samples;
246               
247               if(vorbis_synthesis(&vb,&op)==0) /* test for success! */
248                 vorbis_synthesis_blockin(&vd,&vb);
249               /* 
250                  
251               **pcm is a multichannel float vector.  In stereo, for
252               example, pcm[0] is left, and pcm[1] is right.  samples is
253               the size of each channel.  Convert the float values
254               (-1.<=range<=1.) to whatever PCM format and write it out */
255               
256               while((samples=vorbis_synthesis_pcmout(&vd,&pcm))>0){
257                 int j;
258                 int clipflag=0;
259                 int bout=(samples<convsize?samples:convsize);
260                 
261                 /* convert floats to 16 bit signed ints (host order) and
262                    interleave */
263                 for(i=0;i<vi.channels;i++){
264                   ogg_int16_t *ptr=convbuffer+i;
265                   float  *mono=pcm[i];
266                   for(j=0;j<bout;j++){
267 #if 1
268                     int val=mono[j]*32767.f;
269 #else /* optional dither */
270                     int val=mono[j]*32767.f+drand48()-0.5f;
271 #endif
272                     /* might as well guard against clipping */
273                     if(val>32767){
274                       val=32767;
275                       clipflag=1;
276                     }
277                     if(val<-32768){
278                       val=-32768;
279                       clipflag=1;
280                     }
281                     *ptr=val;
282                     ptr+=vi.channels;
283                   }
284                 }
285                 
286                 if(clipflag)
287                   fprintf(stderr,"Clipping in frame %ld\n",(long)(vd.sequence));
288                 
289                 
290                 fwrite(convbuffer,2*vi.channels,bout,fpout);
291                 
292                 vorbis_synthesis_read(&vd,bout); /* tell libvorbis how
293                                                    many samples we
294                                                    actually consumed */
295               }     
296             }
297           }
298           if(ogg_page_eos(&og))eos=1;
299         }
300       }
301       if(!eos){
302         buffer=ogg_sync_buffer(&oy,4096);
303         bytes=fread(buffer,1,4096,fpin);
304         ogg_sync_wrote(&oy,bytes);
305         if(bytes==0)eos=1;
306       }
307     }
308     
309     /* clean up this logical bitstream; before exit we see if we're
310        followed by another [chained] */
311
312     ogg_stream_clear(&os);
313   
314     /* ogg_page and ogg_packet structs always point to storage in
315        libvorbis.  They're never freed or manipulated directly */
316     
317     vorbis_block_clear(&vb);
318     vorbis_dsp_clear(&vd);
319         vorbis_comment_clear(&vc);
320     vorbis_info_clear(&vi);  /* must be called last */
321   }
322
323   /* OK, clean up the framer */
324   ogg_sync_clear(&oy);
325   
326   fprintf(stderr,"Done.\n");
327   return(0);
328 }
329