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 | }
|
---|