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