annotate src/libvorbis-1.3.3/examples/decoder_example.c @ 168:ceec0dd9ec9c

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