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