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