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