Clarify that chroma upsampling is what any signal processing engineer would
[xiph/unicode.git] / theora-tools / theora123 / theora123.c
blob9342a1fb11d0f3839504967c31ac0218d3a866bc
1 /********************************************************************
2 * *
3 * THIS FILE IS PART OF THE OggTheora 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 Theora SOURCE CODE IS COPYRIGHT (C) 2002-2003 *
9 * by the Xiph.Org Foundation http://www.xiph.org/ *
10 * *
11 ********************************************************************
13 function: example SDL player application; plays Ogg Theora files (with
14 optional Vorbis audio second stream)
15 last mod: $Id: theora_player.c,v 1.29 2004/03/08 06:44:26 giles Exp $
17 ********************************************************************/
19 /* far more complex than most Ogg 'example' programs. The complexity
20 of maintaining A/V sync is pretty much unavoidable. It's necessary
21 to actually have audio/video playback to make the hard audio clock
22 sync actually work. If there's audio playback, there might as well
23 be simple video playback as well...
25 A simple 'demux and write back streams' would have been easier,
26 it's true. */
28 #define _GNU_SOURCE
29 #define _LARGEFILE_SOURCE
30 #define _LARGEFILE64_SOURCE
31 #define _FILE_OFFSET_BITS 64
33 #ifdef HAVE_CONFIG_H
34 # include <config.h>
35 #endif
37 #ifndef _REENTRANT
38 # define _REENTRANT
39 #endif
41 #include <stdio.h>
42 #include <unistd.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <sys/time.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <fcntl.h>
49 #include <math.h>
50 #include <signal.h>
51 #include "theora/theora.h"
52 #include "vorbis/codec.h"
53 #include <SDL.h>
55 /* yes, this makes us OSS-specific for now. None of SDL, libao, libao2
56 give us any way to determine hardware timing, and since the
57 hard/kernel buffer is going to be most of or > a second, that's
58 just a little bit important */
59 #if defined(__FreeBSD__)
60 #include <machine/soundcard.h>
61 #define AUDIO_DEVICE "/dev/audio"
62 #elif defined(__NetBSD__) || defined(__OpenBSD__)
63 #include <soundcard.h>
64 #define AUDIO_DEVICE "/dev/audio"
65 #else
66 #include <sys/soundcard.h>
67 #define AUDIO_DEVICE "/dev/dsp"
68 #endif
69 #include <sys/ioctl.h>
71 /* Helper; just grab some more compressed bitstream and sync it for
72 page extraction */
73 int buffer_data(FILE *in,ogg_sync_state *oy){
74 char *buffer=ogg_sync_buffer(oy,4096);
75 int bytes=fread(buffer,1,4096,in);
76 ogg_sync_wrote(oy,bytes);
77 return(bytes);
80 /* never forget that globals are a one-way ticket to Hell */
81 /* Ogg and codec state for demux/decode */
82 ogg_sync_state oy;
83 ogg_page og;
84 ogg_stream_state vo;
85 ogg_stream_state to;
86 theora_info ti;
87 theora_comment tc;
88 theora_state td;
89 vorbis_info vi;
90 vorbis_dsp_state vd;
91 vorbis_block vb;
92 vorbis_comment vc;
94 int theora_p=0;
95 int vorbis_p=0;
96 int stateflag=0;
98 /* SDL Video playback structures */
99 SDL_Surface *screen;
100 SDL_Overlay *yuv_overlay;
101 SDL_Rect rect;
103 /* single frame video buffering */
104 int videobuf_ready=0;
105 ogg_int64_t videobuf_granulepos=-1;
106 double videobuf_time=0;
108 /* single audio fragment audio buffering */
109 int audiobuf_fill=0;
110 int audiobuf_ready=0;
111 ogg_int16_t *audiobuf;
112 ogg_int64_t audiobuf_granulepos=0; /* time position of last sample */
114 /* audio / video synchronization tracking:
116 Since this will make it to Google at some point and lots of people
117 search for how to do this, a quick rundown of a practical A/V sync
118 strategy under Linux [the UNIX where Everything Is Hard]. Naturally,
119 this works on other platforms using OSS for sound as well.
121 In OSS, we don't have reliable access to any precise information on
122 the exact current playback position (that, of course would have been
123 too easy; the kernel folks like to keep us app people working hard
124 doing simple things that should have been solved once and abstracted
125 long ago). Hopefully ALSA solves this a little better; we'll probably
126 use that once ALSA is the standard in the stable kernel.
128 We can't use the system clock for a/v sync because audio is hard
129 synced to its own clock, and both the system and audio clocks suffer
130 from wobble, drift, and a lack of accuracy that can be guaranteed to
131 add a reliable percent or so of error. After ten seconds, that's
132 100ms. We can't drift by half a second every minute.
134 Although OSS can't generally tell us where the audio playback pointer
135 is, we do know that if we work in complete audio fragments and keep
136 the kernel buffer full, a blocking select on the audio buffer will
137 give us a writable fragment immediately after playback finishes with
138 it. We assume at that point that we know the exact number of bytes in
139 the kernel buffer that have not been played (total fragments minus
140 one) and calculate clock drift between audio and system then (and only
141 then). Damp the sync correction fraction, apply, and walla: A
142 reliable A/V clock that even works if it's interrupted. */
144 long audiofd_totalsize=-1;
145 int audiofd_fragsize; /* read and write only complete fragments
146 so that SNDCTL_DSP_GETOSPACE is
147 accurate immediately after a bank
148 switch */
149 int audiofd=-1;
150 ogg_int64_t audiofd_timer_calibrate=-1;
152 static void open_audio(){
153 audio_buf_info info;
154 int format=AFMT_S16_NE; /* host endian */
155 int channels=vi.channels;
156 int rate=vi.rate;
157 int ret;
159 audiofd=open(AUDIO_DEVICE,O_RDWR);
160 if(audiofd<0){
161 fprintf(stderr,"Could not open audio device " AUDIO_DEVICE ".\n");
162 exit(1);
165 ret=ioctl(audiofd,SNDCTL_DSP_SETFMT,&format);
166 if(ret){
167 fprintf(stderr,"Could not set 16 bit host-endian playback\n");
168 exit(1);
171 ret=ioctl(audiofd,SNDCTL_DSP_CHANNELS,&channels);
172 if(ret){
173 fprintf(stderr,"Could not set %d channel playback\n",channels);
174 exit(1);
177 ret=ioctl(audiofd,SNDCTL_DSP_SPEED,&rate);
178 if(ret){
179 fprintf(stderr,"Could not set %d Hz playback\n",rate);
180 exit(1);
183 ioctl(audiofd,SNDCTL_DSP_GETOSPACE,&info);
184 audiofd_fragsize=info.fragsize;
185 audiofd_totalsize=info.fragstotal*info.fragsize;
187 audiobuf=malloc(audiofd_fragsize);
190 static void audio_close(void){
191 if(audiofd>-1){
192 ioctl(audiofd,SNDCTL_DSP_RESET,NULL);
193 close(audiofd);
194 free(audiobuf);
198 /* call this only immediately after unblocking from a full kernel
199 having a newly empty fragment or at the point of DMA restart */
200 void audio_calibrate_timer(int restart){
201 struct timeval tv;
202 ogg_int64_t current_sample;
203 ogg_int64_t new_time;
205 gettimeofday(&tv,0);
206 new_time=tv.tv_sec*1000+tv.tv_usec/1000;
208 if(restart){
209 current_sample=audiobuf_granulepos-audiobuf_fill/2/vi.channels;
210 }else
211 current_sample=audiobuf_granulepos-
212 (audiobuf_fill+audiofd_totalsize-audiofd_fragsize)/2/vi.channels;
214 new_time-=1000*current_sample/vi.rate;
216 audiofd_timer_calibrate=new_time;
219 /* get relative time since beginning playback, compensating for A/V
220 drift */
221 double get_time(){
222 static ogg_int64_t last=0;
223 static ogg_int64_t up=0;
224 ogg_int64_t now;
225 struct timeval tv;
227 gettimeofday(&tv,0);
228 now=tv.tv_sec*1000+tv.tv_usec/1000;
230 if(audiofd_timer_calibrate==-1)audiofd_timer_calibrate=last=now;
232 if(audiofd<0){
233 /* no audio timer to worry about, we can just use the system clock */
234 /* only one complication: If the process is suspended, we should
235 reset timing to account for the gap in play time. Do it the
236 easy/hack way */
237 if(now-last>1000)audiofd_timer_calibrate+=(now-last);
238 last=now;
241 if(now-up>200){
242 double timebase=(now-audiofd_timer_calibrate)*.001;
243 int hundredths=timebase*100-(long)timebase*100;
244 int seconds=(long)timebase%60;
245 int minutes=((long)timebase/60)%60;
246 int hours=(long)timebase/3600;
248 fprintf(stderr," Playing: %d:%02d:%02d.%02d \r",
249 hours,minutes,seconds,hundredths);
250 up=now;
253 return (now-audiofd_timer_calibrate)*.001;
257 /* write a fragment to the OSS kernel audio API, but only if we can
258 stuff in a whole fragment without blocking */
259 void audio_write_nonblocking(void){
261 if(audiobuf_ready){
262 audio_buf_info info;
263 long bytes;
265 ioctl(audiofd,SNDCTL_DSP_GETOSPACE,&info);
266 bytes=info.bytes;
267 if(bytes>=audiofd_fragsize){
268 if(bytes==audiofd_totalsize)audio_calibrate_timer(1);
270 while(1){
271 bytes=write(audiofd,audiobuf+(audiofd_fragsize-audiobuf_fill),
272 audiofd_fragsize);
274 if(bytes>0){
276 if(bytes!=audiobuf_fill){
277 /* shouldn't actually be possible... but eh */
278 audiobuf_fill-=bytes;
279 }else
280 break;
284 audiobuf_fill=0;
285 audiobuf_ready=0;
291 /* clean quit on Ctrl-C for SDL and thread shutdown as per SDL example
292 (we don't use any threads, but libSDL does) */
293 int got_sigint=0;
294 static void sigint_handler (int signal) {
295 got_sigint = 1;
298 static void open_video(void){
299 if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
300 fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
301 exit(1);
304 screen = SDL_SetVideoMode(ti.frame_width, ti.frame_height, 0, SDL_SWSURFACE);
305 if ( screen == NULL ) {
306 fprintf(stderr, "Unable to set %dx%d video: %s\n",
307 ti.frame_width,ti.frame_height,SDL_GetError());
308 exit(1);
311 yuv_overlay = SDL_CreateYUVOverlay(ti.frame_width, ti.frame_height,
312 SDL_YV12_OVERLAY,
313 screen);
314 if ( yuv_overlay == NULL ) {
315 fprintf(stderr, "SDL: Couldn't create SDL_yuv_overlay: %s\n",
316 SDL_GetError());
317 exit(1);
319 rect.x = 0;
320 rect.y = 0;
321 rect.w = ti.frame_width;
322 rect.h = ti.frame_height;
324 SDL_DisplayYUVOverlay(yuv_overlay, &rect);
327 static void video_write(void){
328 int i;
329 yuv_buffer yuv;
330 int crop_offset;
331 theora_decode_YUVout(&td,&yuv);
333 /* Lock SDL_yuv_overlay */
334 if ( SDL_MUSTLOCK(screen) ) {
335 if ( SDL_LockSurface(screen) < 0 ) return;
337 if (SDL_LockYUVOverlay(yuv_overlay) < 0) return;
339 /* let's draw the data (*yuv[3]) on a SDL screen (*screen) */
340 /* deal with border stride */
341 /* reverse u and v for SDL */
342 /* and crop input properly, respecting the encoded frame rect */
343 crop_offset=ti.offset_x+yuv.y_stride*ti.offset_y;
344 for(i=0;i<yuv_overlay->h;i++)
345 memcpy(yuv_overlay->pixels[0]+yuv_overlay->pitches[0]*i,
346 yuv.y+crop_offset+yuv.y_stride*i,
347 yuv_overlay->w);
348 crop_offset=(ti.offset_x/2)+(yuv.uv_stride)*(ti.offset_y/2);
349 for(i=0;i<yuv_overlay->h/2;i++){
350 memcpy(yuv_overlay->pixels[1]+yuv_overlay->pitches[1]*i,
351 yuv.v+crop_offset+yuv.uv_stride*i,
352 yuv_overlay->w/2);
353 memcpy(yuv_overlay->pixels[2]+yuv_overlay->pitches[2]*i,
354 yuv.u+crop_offset+yuv.uv_stride*i,
355 yuv_overlay->w/2);
358 /* Unlock SDL_yuv_overlay */
359 if ( SDL_MUSTLOCK(screen) ) {
360 SDL_UnlockSurface(screen);
362 SDL_UnlockYUVOverlay(yuv_overlay);
365 /* Show, baby, show! */
366 SDL_DisplayYUVOverlay(yuv_overlay, &rect);
369 /* dump the theora (or vorbis) comment header */
370 static int dump_comments(theora_comment *tc){
371 int i, len;
372 char *value;
373 FILE *out=stdout;
375 fprintf(out,"Encoded by %s\n",tc->vendor);
376 if(tc->comments){
377 fprintf(out, "theora comment header:\n");
378 for(i=0;i<tc->comments;i++){
379 if(tc->user_comments[i]){
380 len=tc->comment_lengths[i];
381 value=malloc(len+1);
382 memcpy(value,tc->user_comments[i],len);
383 value[len]='\0';
384 fprintf(out, "\t%s\n", value);
385 free(value);
389 return(0);
392 /* Report the encoder-specified colorspace for the video, if any.
393 We don't actually make use of the information in this example;
394 a real player should attempt to perform color correction for
395 whatever display device it supports. */
396 static void report_colorspace(theora_info *ti)
398 switch(ti->colorspace){
399 case OC_CS_UNSPECIFIED:
400 /* nothing to report */
401 break;;
402 case OC_CS_ITU_REC_470M:
403 fprintf(stderr," encoder specified ITU Rec 470M (NTSC) color.\n");
404 break;;
405 case OC_CS_ITU_REC_470BG:
406 fprintf(stderr," encoder specified ITU Rec 470BG (PAL) color.\n");
407 break;;
408 default:
409 fprintf(stderr,"warning: encoder specified unknown colorspace (%d).\n",
410 ti->colorspace);
411 break;;
415 /* helper: push a page into the appropriate steam */
416 /* this can be done blindly; a stream won't accept a page
417 that doesn't belong to it */
418 static int queue_page(ogg_page *page){
419 if(theora_p)ogg_stream_pagein(&to,&og);
420 if(vorbis_p)ogg_stream_pagein(&vo,&og);
421 return 0;
424 static void usage(void){
425 fprintf(stderr,
426 "Usage: theora_player <file.ogg>\n"
427 "input is read from stdin if no file is passed on the command line\n"
428 "\n"
432 int main(int argc,char *argv[]){
434 int i,j;
435 ogg_packet op;
437 FILE *infile = stdin;
439 #ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows. */
440 /* Beware the evil ifdef. We avoid these where we can, but this one we
441 cannot. Don't add any more, you'll probably go to hell if you do. */
442 _setmode( _fileno( stdin ), _O_BINARY );
443 #endif
445 /* open the input file if any */
446 if(argc==2){
447 infile=fopen(argv[1],"rb");
448 if(infile==NULL){
449 fprintf(stderr,"Unable to open '%s' for playback.\n", argv[1]);
450 exit(1);
453 if(argc>2){
454 usage();
455 exit(1);
458 /* start up Ogg stream synchronization layer */
459 ogg_sync_init(&oy);
461 /* init supporting Vorbis structures needed in header parsing */
462 vorbis_info_init(&vi);
463 vorbis_comment_init(&vc);
465 /* init supporting Theora structures needed in header parsing */
466 theora_comment_init(&tc);
467 theora_info_init(&ti);
469 /* Ogg file open; parse the headers */
470 /* Only interested in Vorbis/Theora streams */
471 while(!stateflag){
472 int ret=buffer_data(infile,&oy);
473 if(ret==0)break;
474 while(ogg_sync_pageout(&oy,&og)>0){
475 ogg_stream_state test;
477 /* is this a mandated initial header? If not, stop parsing */
478 if(!ogg_page_bos(&og)){
479 /* don't leak the page; get it into the appropriate stream */
480 queue_page(&og);
481 stateflag=1;
482 break;
485 ogg_stream_init(&test,ogg_page_serialno(&og));
486 ogg_stream_pagein(&test,&og);
487 ogg_stream_packetout(&test,&op);
489 /* identify the codec: try theora */
490 if(!theora_p && theora_decode_header(&ti,&tc,&op)>=0){
491 /* it is theora */
492 memcpy(&to,&test,sizeof(test));
493 theora_p=1;
494 }else if(!vorbis_p && vorbis_synthesis_headerin(&vi,&vc,&op)>=0){
495 /* it is vorbis */
496 memcpy(&vo,&test,sizeof(test));
497 vorbis_p=1;
498 }else{
499 /* whatever it is, we don't care about it */
500 ogg_stream_clear(&test);
503 /* fall through to non-bos page parsing */
506 /* we're expecting more header packets. */
507 while((theora_p && theora_p<3) || (vorbis_p && vorbis_p<3)){
508 int ret;
510 /* look for further theora headers */
511 while(theora_p && (theora_p<3) && (ret=ogg_stream_packetout(&to,&op))){
512 if(ret<0){
513 fprintf(stderr,"Error parsing Theora stream headers; corrupt stream?\n");
514 exit(1);
516 if(theora_decode_header(&ti,&tc,&op)){
517 printf("Error parsing Theora stream headers; corrupt stream?\n");
518 exit(1);
520 theora_p++;
521 if(theora_p==3)break;
524 /* look for more vorbis header packets */
525 while(vorbis_p && (vorbis_p<3) && (ret=ogg_stream_packetout(&vo,&op))){
526 if(ret<0){
527 fprintf(stderr,"Error parsing Vorbis stream headers; corrupt stream?\n");
528 exit(1);
530 if(vorbis_synthesis_headerin(&vi,&vc,&op)){
531 fprintf(stderr,"Error parsing Vorbis stream headers; corrupt stream?\n");
532 exit(1);
534 vorbis_p++;
535 if(vorbis_p==3)break;
538 /* The header pages/packets will arrive before anything else we
539 care about, or the stream is not obeying spec */
541 if(ogg_sync_pageout(&oy,&og)>0){
542 queue_page(&og); /* demux into the appropriate stream */
543 }else{
544 int ret=buffer_data(infile,&oy); /* someone needs more data */
545 if(ret==0){
546 fprintf(stderr,"End of file while searching for codec headers.\n");
547 exit(1);
552 /* and now we have it all. initialize decoders */
553 if(theora_p){
554 theora_decode_init(&td,&ti);
555 printf("Ogg logical stream %x is Theora %dx%d %.02f fps",
556 (unsigned int)to.serialno,ti.width,ti.height,
557 (double)ti.fps_numerator/ti.fps_denominator);
558 switch(ti.pixelformat){
559 case OC_PF_420: printf(" 4:2:0 video\n"); break;
560 case OC_PF_422: printf(" 4:2:2 video\n"); break;
561 case OC_PF_444: printf(" 4:4:4 video\n"); break;
562 case OC_PF_RSVD:
563 default:
564 printf(" video\n (UNKNOWN Chroma sampling!)\n");
565 break;
567 if(ti.width!=ti.frame_width || ti.height!=ti.frame_height)
568 printf(" Frame content is %dx%d with offset (%d,%d).\n",
569 ti.frame_width, ti.frame_height, ti.offset_x, ti.offset_y);
570 report_colorspace(&ti);
571 dump_comments(&tc);
572 }else{
573 /* tear down the partial theora setup */
574 theora_info_clear(&ti);
575 theora_comment_clear(&tc);
577 if(vorbis_p){
578 vorbis_synthesis_init(&vd,&vi);
579 vorbis_block_init(&vd,&vb);
580 fprintf(stderr,"Ogg logical stream %x is Vorbis %d channel %d Hz audio.\n",
581 (unsigned int)vo.serialno,vi.channels,(int)vi.rate);
582 }else{
583 /* tear down the partial vorbis setup */
584 vorbis_info_clear(&vi);
585 vorbis_comment_clear(&vc);
588 /* open audio */
589 if(vorbis_p)open_audio();
591 /* open video */
592 if(theora_p)open_video();
594 /* install signal handler as SDL clobbered the default */
595 signal (SIGINT, sigint_handler);
597 /* on to the main decode loop. We assume in this example that audio
598 and video start roughly together, and don't begin playback until
599 we have a start frame for both. This is not necessarily a valid
600 assumption in Ogg A/V streams! It will always be true of the
601 example_encoder (and most streams) though. */
603 stateflag=0; /* playback has not begun */
604 while(!got_sigint){
606 /* we want a video and audio frame ready to go at all times. If
607 we have to buffer incoming, buffer the compressed data (ie, let
608 ogg do the buffering) */
609 while(vorbis_p && !audiobuf_ready){
610 int ret;
611 float **pcm;
613 /* if there's pending, decoded audio, grab it */
614 if((ret=vorbis_synthesis_pcmout(&vd,&pcm))>0){
615 int count=audiobuf_fill/2;
616 int maxsamples=(audiofd_fragsize-audiobuf_fill)/2/vi.channels;
617 for(i=0;i<ret && i<maxsamples;i++)
618 for(j=0;j<vi.channels;j++){
619 int val=rint(pcm[j][i]*32767.f);
620 if(val>32767)val=32767;
621 if(val<-32768)val=-32768;
622 audiobuf[count++]=val;
624 vorbis_synthesis_read(&vd,i);
625 audiobuf_fill+=i*vi.channels*2;
626 if(audiobuf_fill==audiofd_fragsize)audiobuf_ready=1;
627 if(vd.granulepos>=0)
628 audiobuf_granulepos=vd.granulepos-ret+i;
629 else
630 audiobuf_granulepos+=i;
632 }else{
634 /* no pending audio; is there a pending packet to decode? */
635 if(ogg_stream_packetout(&vo,&op)>0){
636 if(vorbis_synthesis(&vb,&op)==0) /* test for success! */
637 vorbis_synthesis_blockin(&vd,&vb);
638 }else /* we need more data; break out to suck in another page */
639 break;
643 while(theora_p && !videobuf_ready){
644 /* theora is one in, one out... */
645 if(ogg_stream_packetout(&to,&op)>0){
647 theora_decode_packetin(&td,&op);
648 videobuf_granulepos=td.granulepos;
650 videobuf_time=theora_granule_time(&td,videobuf_granulepos);
652 /* is it already too old to be useful? This is only actually
653 useful cosmetically after a SIGSTOP. Note that we have to
654 decode the frame even if we don't show it (for now) due to
655 keyframing. Soon enough libtheora will be able to deal
656 with non-keyframe seeks. */
658 if(videobuf_time>=get_time())
659 videobuf_ready=1;
661 }else
662 break;
665 if(!videobuf_ready && !audiobuf_ready && feof(infile))break;
667 if(!videobuf_ready || !audiobuf_ready){
668 /* no data yet for somebody. Grab another page */
669 int bytes=buffer_data(infile,&oy);
670 while(ogg_sync_pageout(&oy,&og)>0){
671 queue_page(&og);
675 /* If playback has begun, top audio buffer off immediately. */
676 if(stateflag) audio_write_nonblocking();
678 /* are we at or past time for this video frame? */
679 if(stateflag && videobuf_ready && videobuf_time<=get_time()){
680 video_write();
681 videobuf_ready=0;
684 if(stateflag &&
685 (audiobuf_ready || !vorbis_p) &&
686 (videobuf_ready || !theora_p) &&
687 !got_sigint){
688 /* we have an audio frame ready (which means the audio buffer is
689 full), it's not time to play video, so wait until one of the
690 audio buffer is ready or it's near time to play video */
692 /* set up select wait on the audiobuffer and a timeout for video */
693 struct timeval timeout;
694 fd_set writefs;
695 fd_set empty;
696 int n=0;
698 FD_ZERO(&writefs);
699 FD_ZERO(&empty);
700 if(audiofd>=0){
701 FD_SET(audiofd,&writefs);
702 n=audiofd+1;
705 if(theora_p){
706 long milliseconds=(videobuf_time-get_time())*1000-5;
707 if(milliseconds>500)milliseconds=500;
708 if(milliseconds>0){
709 timeout.tv_sec=milliseconds/1000;
710 timeout.tv_usec=(milliseconds%1000)*1000;
712 n=select(n,&empty,&writefs,&empty,&timeout);
713 if(n)audio_calibrate_timer(0);
715 }else{
716 select(n,&empty,&writefs,&empty,NULL);
720 /* if our buffers either don't exist or are ready to go,
721 we can begin playback */
722 if((!theora_p || videobuf_ready) &&
723 (!vorbis_p || audiobuf_ready))stateflag=1;
724 /* same if we've run out of input */
725 if(feof(infile))stateflag=1;
729 /* tear it all down */
731 audio_close();
732 SDL_Quit();
734 if(vorbis_p){
735 ogg_stream_clear(&vo);
736 vorbis_block_clear(&vb);
737 vorbis_dsp_clear(&vd);
738 vorbis_comment_clear(&vc);
739 vorbis_info_clear(&vi);
741 if(theora_p){
742 ogg_stream_clear(&to);
743 theora_clear(&td);
744 theora_comment_clear(&tc);
745 theora_info_clear(&ti);
747 ogg_sync_clear(&oy);
749 if(infile && infile!=stdin)fclose(infile);
751 fprintf(stderr,
752 "\r "
753 "\nDone.\n");
754 return(0);