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