1 /********************************************************************
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. *
8 * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
9 * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
11 ********************************************************************
13 function: example SDL player application; plays Ogg Theora files (with
14 optional Vorbis audio second stream)
15 last mod: $Id: player_example.c 16551 2009-09-09 17:53:13Z gmaxwell $
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,
28 #if !defined(_GNU_SOURCE)
31 #if !defined(_LARGEFILE_SOURCE)
32 #define _LARGEFILE_SOURCE
34 #if !defined(_LARGEFILE64_SOURCE)
35 #define _LARGEFILE64_SOURCE
37 #if !defined(_FILE_OFFSET_BITS)
38 #define _FILE_OFFSET_BITS 64
54 #include <sys/types.h>
59 #include "theora/theoradec.h"
60 #include "vorbis/codec.h"
63 /* yes, this makes us OSS-specific for now. None of SDL, libao, libao2
64 give us any way to determine hardware timing, and since the
65 hard/kernel buffer is going to be most of or > a second, that's
66 just a little bit important */
67 #if defined(__FreeBSD__)
68 #include <machine/soundcard.h>
69 #define AUDIO_DEVICE "/dev/audio"
70 #elif defined(__NetBSD__) || defined(__OpenBSD__)
71 #include <soundcard.h>
72 #define AUDIO_DEVICE "/dev/audio"
74 #include <sys/soundcard.h>
75 #define AUDIO_DEVICE "/dev/dsp"
77 #include <sys/ioctl.h>
79 /* Helper; just grab some more compressed bitstream and sync it for
81 int buffer_data(FILE *in,ogg_sync_state *oy){
82 char *buffer=ogg_sync_buffer(oy,4096);
83 int bytes=fread(buffer,1,4096,in);
84 ogg_sync_wrote(oy,bytes);
88 /* never forget that globals are a one-way ticket to Hell */
89 /* Ogg and codec state for demux/decode */
108 /* SDL Video playback structures */
110 SDL_Overlay *yuv_overlay;
113 /* single frame video buffering */
114 int videobuf_ready=0;
115 ogg_int64_t videobuf_granulepos=-1;
116 double videobuf_time=0;
118 /* single audio fragment audio buffering */
120 int audiobuf_ready=0;
121 ogg_int16_t *audiobuf;
122 ogg_int64_t audiobuf_granulepos=0; /* time position of last sample */
124 /* audio / video synchronization tracking:
126 Since this will make it to Google at some point and lots of people
127 search for how to do this, a quick rundown of a practical A/V sync
128 strategy under Linux [the UNIX where Everything Is Hard]. Naturally,
129 this works on other platforms using OSS for sound as well.
131 In OSS, we don't have reliable access to any precise information on
132 the exact current playback position (that, of course would have been
133 too easy; the kernel folks like to keep us app people working hard
134 doing simple things that should have been solved once and abstracted
135 long ago). Hopefully ALSA solves this a little better; we'll probably
136 use that once ALSA is the standard in the stable kernel.
138 We can't use the system clock for a/v sync because audio is hard
139 synced to its own clock, and both the system and audio clocks suffer
140 from wobble, drift, and a lack of accuracy that can be guaranteed to
141 add a reliable percent or so of error. After ten seconds, that's
142 100ms. We can't drift by half a second every minute.
144 Although OSS can't generally tell us where the audio playback pointer
145 is, we do know that if we work in complete audio fragments and keep
146 the kernel buffer full, a blocking select on the audio buffer will
147 give us a writable fragment immediately after playback finishes with
148 it. We assume at that point that we know the exact number of bytes in
149 the kernel buffer that have not been played (total fragments minus
150 one) and calculate clock drift between audio and system then (and only
151 then). Damp the sync correction fraction, apply, and walla: A
152 reliable A/V clock that even works if it's interrupted. */
154 long audiofd_totalsize=-1;
155 int audiofd_fragsize; /* read and write only complete fragments
156 so that SNDCTL_DSP_GETOSPACE is
157 accurate immediately after a bank
160 ogg_int64_t audiofd_timer_calibrate=-1;
162 static void open_audio(){
164 int format=AFMT_S16_NE; /* host endian */
165 int channels=vi.channels;
169 audiofd=open(AUDIO_DEVICE,O_RDWR);
171 fprintf(stderr,"Could not open audio device " AUDIO_DEVICE ".\n");
175 ret=ioctl(audiofd,SNDCTL_DSP_SETFMT,&format);
177 fprintf(stderr,"Could not set 16 bit host-endian playback\n");
181 ret=ioctl(audiofd,SNDCTL_DSP_CHANNELS,&channels);
183 fprintf(stderr,"Could not set %d channel playback\n",channels);
187 ret=ioctl(audiofd,SNDCTL_DSP_SPEED,&rate);
189 fprintf(stderr,"Could not set %d Hz playback\n",rate);
193 ioctl(audiofd,SNDCTL_DSP_GETOSPACE,&info);
194 audiofd_fragsize=info.fragsize;
195 audiofd_totalsize=info.fragstotal*info.fragsize;
197 audiobuf=malloc(audiofd_fragsize);
200 static void audio_close(void){
202 ioctl(audiofd,SNDCTL_DSP_RESET,NULL);
208 /* call this only immediately after unblocking from a full kernel
209 having a newly empty fragment or at the point of DMA restart */
210 void audio_calibrate_timer(int restart){
212 ogg_int64_t current_sample;
213 ogg_int64_t new_time;
216 new_time=tv.tv_sec*1000+tv.tv_usec/1000;
219 current_sample=audiobuf_granulepos-audiobuf_fill/2/vi.channels;
221 current_sample=audiobuf_granulepos-
222 (audiobuf_fill+audiofd_totalsize-audiofd_fragsize)/2/vi.channels;
224 new_time-=1000*current_sample/vi.rate;
226 audiofd_timer_calibrate=new_time;
229 /* get relative time since beginning playback, compensating for A/V
232 static ogg_int64_t last=0;
233 static ogg_int64_t up=0;
238 now=tv.tv_sec*1000+tv.tv_usec/1000;
240 if(audiofd_timer_calibrate==-1)audiofd_timer_calibrate=last=now;
243 /* no audio timer to worry about, we can just use the system clock */
244 /* only one complication: If the process is suspended, we should
245 reset timing to account for the gap in play time. Do it the
247 if(now-last>1000)audiofd_timer_calibrate+=(now-last);
252 double timebase=(now-audiofd_timer_calibrate)*.001;
253 int hundredths=timebase*100-(long)timebase*100;
254 int seconds=(long)timebase%60;
255 int minutes=((long)timebase/60)%60;
256 int hours=(long)timebase/3600;
258 fprintf(stderr," Playing: %d:%02d:%02d.%02d \r",
259 hours,minutes,seconds,hundredths);
263 return (now-audiofd_timer_calibrate)*.001;
267 /* write a fragment to the OSS kernel audio API, but only if we can
268 stuff in a whole fragment without blocking */
269 void audio_write_nonblocking(void){
275 ioctl(audiofd,SNDCTL_DSP_GETOSPACE,&info);
277 if(bytes>=audiofd_fragsize){
278 if(bytes==audiofd_totalsize)audio_calibrate_timer(1);
281 bytes=write(audiofd,audiobuf+(audiofd_fragsize-audiobuf_fill),
286 if(bytes!=audiobuf_fill){
287 /* shouldn't actually be possible... but eh */
288 audiobuf_fill-=bytes;
301 /* clean quit on Ctrl-C for SDL and thread shutdown as per SDL example
302 (we don't use any threads, but libSDL does) */
304 static void sigint_handler (int signal) {
308 static void open_video(void){
311 w=(ti.pic_x+ti.frame_width+1&~1)-(ti.pic_x&~1);
312 h=(ti.pic_y+ti.frame_height+1&~1)-(ti.pic_y&~1);
313 if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
314 fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
318 screen = SDL_SetVideoMode(w, h, 0, SDL_SWSURFACE);
319 if ( screen == NULL ) {
320 fprintf(stderr, "Unable to set %dx%d video: %s\n",
325 if (px_fmt==TH_PF_422)
326 yuv_overlay = SDL_CreateYUVOverlay(w, h,
330 yuv_overlay = SDL_CreateYUVOverlay(w, h,
334 if ( yuv_overlay == NULL ) {
335 fprintf(stderr, "SDL: Couldn't create SDL_yuv_overlay: %s\n",
344 SDL_DisplayYUVOverlay(yuv_overlay, &rect);
347 static void video_write(void){
350 int y_offset, uv_offset;
351 th_decode_ycbcr_out(td,yuv);
352 /* Lock SDL_yuv_overlay */
353 if ( SDL_MUSTLOCK(screen) ) {
354 if ( SDL_LockSurface(screen) < 0 ) return;
356 if (SDL_LockYUVOverlay(yuv_overlay) < 0) return;
358 /* let's draw the data on a SDL screen (*screen) */
359 /* deal with border stride */
360 /* reverse u and v for SDL */
361 /* and crop input properly, respecting the encoded frame rect */
362 /* problems may exist for odd frame rect for some encodings */
364 y_offset=(ti.pic_x&~1)+yuv[0].stride*(ti.pic_y&~1);
366 if (px_fmt==TH_PF_422) {
367 uv_offset=(ti.pic_x/2)+(yuv[1].stride)*(ti.pic_y);
368 /* SDL doesn't have a planar 4:2:2 */
369 for(i=0;i<yuv_overlay->h;i++) {
371 char *in_y = (char *)yuv[0].data+y_offset+yuv[0].stride*i;
372 char *out = (char *)(yuv_overlay->pixels[0]+yuv_overlay->pitches[0]*i);
373 for (j=0;j<yuv_overlay->w;j++)
375 char *in_u = (char *)yuv[1].data+uv_offset+yuv[1].stride*i;
376 char *in_v = (char *)yuv[2].data+uv_offset+yuv[2].stride*i;
377 for (j=0;j<yuv_overlay->w>>1;j++) {
378 out[j*4+1] = in_u[j];
379 out[j*4+3] = in_v[j];
383 uv_offset=(ti.pic_x/2)+(yuv[1].stride)*(ti.pic_y/2);
384 for(i=0;i<yuv_overlay->h;i++)
385 memcpy(yuv_overlay->pixels[0]+yuv_overlay->pitches[0]*i,
386 yuv[0].data+y_offset+yuv[0].stride*i,
388 for(i=0;i<yuv_overlay->h/2;i++){
389 memcpy(yuv_overlay->pixels[1]+yuv_overlay->pitches[1]*i,
390 yuv[2].data+uv_offset+yuv[2].stride*i,
392 memcpy(yuv_overlay->pixels[2]+yuv_overlay->pitches[2]*i,
393 yuv[1].data+uv_offset+yuv[1].stride*i,
398 /* Unlock SDL_yuv_overlay */
399 if ( SDL_MUSTLOCK(screen) ) {
400 SDL_UnlockSurface(screen);
402 SDL_UnlockYUVOverlay(yuv_overlay);
405 /* Show, baby, show! */
406 SDL_DisplayYUVOverlay(yuv_overlay, &rect);
409 /* dump the theora (or vorbis) comment header */
410 static int dump_comments(th_comment *tc){
415 fprintf(out,"Encoded by %s\n",tc->vendor);
417 fprintf(out, "theora comment header:\n");
418 for(i=0;i<tc->comments;i++){
419 if(tc->user_comments[i]){
420 len=tc->comment_lengths[i];
422 memcpy(value,tc->user_comments[i],len);
424 fprintf(out, "\t%s\n", value);
432 /* Report the encoder-specified colorspace for the video, if any.
433 We don't actually make use of the information in this example;
434 a real player should attempt to perform color correction for
435 whatever display device it supports. */
436 static void report_colorspace(th_info *ti)
438 switch(ti->colorspace){
439 case TH_CS_UNSPECIFIED:
440 /* nothing to report */
442 case TH_CS_ITU_REC_470M:
443 fprintf(stderr," encoder specified ITU Rec 470M (NTSC) color.\n");
445 case TH_CS_ITU_REC_470BG:
446 fprintf(stderr," encoder specified ITU Rec 470BG (PAL) color.\n");
449 fprintf(stderr,"warning: encoder specified unknown colorspace (%d).\n",
455 /* helper: push a page into the appropriate steam */
456 /* this can be done blindly; a stream won't accept a page
457 that doesn't belong to it */
458 static int queue_page(ogg_page *page){
459 if(theora_p)ogg_stream_pagein(&to,page);
460 if(vorbis_p)ogg_stream_pagein(&vo,page);
464 static void usage(void){
466 "Usage: player_example <file.ogv>\n"
467 "input is read from stdin if no file is passed on the command line\n"
472 int main(int argc,char *const *argv){
480 FILE *infile = stdin;
485 #ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows. */
486 /* Beware the evil ifdef. We avoid these where we can, but this one we
487 cannot. Don't add any more, you'll probably go to hell if you do. */
488 _setmode( _fileno( stdin ), _O_BINARY );
491 /* open the input file if any */
493 infile=fopen(argv[1],"rb");
495 fprintf(stderr,"Unable to open '%s' for playback.\n", argv[1]);
504 /* start up Ogg stream synchronization layer */
507 /* init supporting Vorbis structures needed in header parsing */
508 vorbis_info_init(&vi);
509 vorbis_comment_init(&vc);
511 /* init supporting Theora structures needed in header parsing */
512 th_comment_init(&tc);
515 /* Ogg file open; parse the headers */
516 /* Only interested in Vorbis/Theora streams */
518 int ret=buffer_data(infile,&oy);
520 while(ogg_sync_pageout(&oy,&og)>0){
521 ogg_stream_state test;
523 /* is this a mandated initial header? If not, stop parsing */
524 if(!ogg_page_bos(&og)){
525 /* don't leak the page; get it into the appropriate stream */
531 ogg_stream_init(&test,ogg_page_serialno(&og));
532 ogg_stream_pagein(&test,&og);
533 ogg_stream_packetout(&test,&op);
536 /* identify the codec: try theora */
537 if(!theora_p && th_decode_headerin(&ti,&tc,&ts,&op)>=0){
539 memcpy(&to,&test,sizeof(test));
541 }else if(!vorbis_p && vorbis_synthesis_headerin(&vi,&vc,&op)>=0){
543 memcpy(&vo,&test,sizeof(test));
546 /* whatever it is, we don't care about it */
547 ogg_stream_clear(&test);
550 /* fall through to non-bos page parsing */
553 /* we're expecting more header packets. */
554 while((theora_p && theora_p<3) || (vorbis_p && vorbis_p<3)){
557 /* look for further theora headers */
558 while(theora_p && (theora_p<3) && (ret=ogg_stream_packetout(&to,&op))){
560 fprintf(stderr,"Error parsing Theora stream headers; "
561 "corrupt stream?\n");
564 if(!th_decode_headerin(&ti,&tc,&ts,&op)){
565 fprintf(stderr,"Error parsing Theora stream headers; "
566 "corrupt stream?\n");
572 /* look for more vorbis header packets */
573 while(vorbis_p && (vorbis_p<3) && (ret=ogg_stream_packetout(&vo,&op))){
575 fprintf(stderr,"Error parsing Vorbis stream headers; corrupt stream?\n");
578 if(vorbis_synthesis_headerin(&vi,&vc,&op)){
579 fprintf(stderr,"Error parsing Vorbis stream headers; corrupt stream?\n");
583 if(vorbis_p==3)break;
586 /* The header pages/packets will arrive before anything else we
587 care about, or the stream is not obeying spec */
589 if(ogg_sync_pageout(&oy,&og)>0){
590 queue_page(&og); /* demux into the appropriate stream */
592 int ret=buffer_data(infile,&oy); /* someone needs more data */
594 fprintf(stderr,"End of file while searching for codec headers.\n");
600 /* and now we have it all. initialize decoders */
602 td=th_decode_alloc(&ti,ts);
603 printf("Ogg logical stream %lx is Theora %dx%d %.02f fps",
604 to.serialno,ti.pic_width,ti.pic_height,
605 (double)ti.fps_numerator/ti.fps_denominator);
607 switch(ti.pixel_fmt){
608 case TH_PF_420: printf(" 4:2:0 video\n"); break;
609 case TH_PF_422: printf(" 4:2:2 video\n"); break;
610 case TH_PF_444: printf(" 4:4:4 video\n"); break;
613 printf(" video\n (UNKNOWN Chroma sampling!)\n");
616 if(ti.pic_width!=ti.frame_width || ti.pic_height!=ti.frame_height)
617 printf(" Frame content is %dx%d with offset (%d,%d).\n",
618 ti.frame_width, ti.frame_height, ti.pic_x, ti.pic_y);
619 report_colorspace(&ti);
621 th_decode_ctl(td,TH_DECCTL_GET_PPLEVEL_MAX,&pp_level_max,
622 sizeof(pp_level_max));
623 pp_level=pp_level_max;
624 th_decode_ctl(td,TH_DECCTL_SET_PPLEVEL,&pp_level,sizeof(pp_level));
629 th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_MBMODE,&arg,sizeof(arg));
630 th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_MV,&arg,sizeof(arg));
631 th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_QI,&arg,sizeof(arg));
633 th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_BITS,&arg,sizeof(arg));
636 /* tear down the partial theora setup */
638 th_comment_clear(&tc);
644 vorbis_synthesis_init(&vd,&vi);
645 vorbis_block_init(&vd,&vb);
646 fprintf(stderr,"Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.\n",
647 vo.serialno,vi.channels,vi.rate);
649 /* tear down the partial vorbis setup */
650 vorbis_info_clear(&vi);
651 vorbis_comment_clear(&vc);
655 if(vorbis_p)open_audio();
658 if(theora_p)open_video();
660 /* install signal handler as SDL clobbered the default */
661 signal (SIGINT, sigint_handler);
663 /* on to the main decode loop. We assume in this example that audio
664 and video start roughly together, and don't begin playback until
665 we have a start frame for both. This is not necessarily a valid
666 assumption in Ogg A/V streams! It will always be true of the
667 example_encoder (and most streams) though. */
669 stateflag=0; /* playback has not begun */
672 /* we want a video and audio frame ready to go at all times. If
673 we have to buffer incoming, buffer the compressed data (ie, let
674 ogg do the buffering) */
675 while(vorbis_p && !audiobuf_ready){
679 /* if there's pending, decoded audio, grab it */
680 if((ret=vorbis_synthesis_pcmout(&vd,&pcm))>0){
681 int count=audiobuf_fill/2;
682 int maxsamples=(audiofd_fragsize-audiobuf_fill)/2/vi.channels;
683 for(i=0;i<ret && i<maxsamples;i++)
684 for(j=0;j<vi.channels;j++){
685 int val=rint(pcm[j][i]*32767.f);
686 if(val>32767)val=32767;
687 if(val<-32768)val=-32768;
688 audiobuf[count++]=val;
690 vorbis_synthesis_read(&vd,i);
691 audiobuf_fill+=i*vi.channels*2;
692 if(audiobuf_fill==audiofd_fragsize)audiobuf_ready=1;
694 audiobuf_granulepos=vd.granulepos-ret+i;
696 audiobuf_granulepos+=i;
700 /* no pending audio; is there a pending packet to decode? */
701 if(ogg_stream_packetout(&vo,&op)>0){
702 if(vorbis_synthesis(&vb,&op)==0) /* test for success! */
703 vorbis_synthesis_blockin(&vd,&vb);
704 }else /* we need more data; break out to suck in another page */
709 while(theora_p && !videobuf_ready){
710 /* theora is one in, one out... */
711 if(ogg_stream_packetout(&to,&op)>0){
715 th_decode_ctl(td,TH_DECCTL_SET_PPLEVEL,&pp_level,
719 /*HACK: This should be set after a seek or a gap, but we might not have
720 a granulepos for the first packet (we only have them for the last
721 packet on a page), so we just set it as often as we get it.
722 To do this right, we should back-track from the last packet on the
723 page and compute the correct granulepos for the first packet after
725 if(op.granulepos>=0){
726 th_decode_ctl(td,TH_DECCTL_SET_GRANPOS,&op.granulepos,
727 sizeof(op.granulepos));
729 if(th_decode_packetin(td,&op,&videobuf_granulepos)==0){
730 videobuf_time=th_granule_time(td,videobuf_granulepos);
733 /* is it already too old to be useful? This is only actually
734 useful cosmetically after a SIGSTOP. Note that we have to
735 decode the frame even if we don't show it (for now) due to
736 keyframing. Soon enough libtheora will be able to deal
737 with non-keyframe seeks. */
739 if(videobuf_time>=get_time())
742 /*If we are too slow, reduce the pp level.*/
743 pp_inc=pp_level>0?-1:0;
752 if(!videobuf_ready && !audiobuf_ready && feof(infile))break;
754 if(!videobuf_ready || !audiobuf_ready){
755 /* no data yet for somebody. Grab another page */
756 buffer_data(infile,&oy);
757 while(ogg_sync_pageout(&oy,&og)>0){
762 /* If playback has begun, top audio buffer off immediately. */
763 if(stateflag) audio_write_nonblocking();
765 /* are we at or past time for this video frame? */
766 if(stateflag && videobuf_ready && videobuf_time<=get_time()){
772 (audiobuf_ready || !vorbis_p) &&
773 (videobuf_ready || !theora_p) &&
775 /* we have an audio frame ready (which means the audio buffer is
776 full), it's not time to play video, so wait until one of the
777 audio buffer is ready or it's near time to play video */
779 /* set up select wait on the audiobuffer and a timeout for video */
780 struct timeval timeout;
788 FD_SET(audiofd,&writefs);
795 tdiff=videobuf_time-get_time();
796 /*If we have lots of extra time, increase the post-processing level.*/
797 if(tdiff>ti.fps_denominator*0.25/ti.fps_numerator){
798 pp_inc=pp_level<pp_level_max?1:0;
800 else if(tdiff<ti.fps_denominator*0.05/ti.fps_numerator){
801 pp_inc=pp_level>0?-1:0;
803 milliseconds=tdiff*1000-5;
804 if(milliseconds>500)milliseconds=500;
806 timeout.tv_sec=milliseconds/1000;
807 timeout.tv_usec=(milliseconds%1000)*1000;
809 n=select(n,&empty,&writefs,&empty,&timeout);
810 if(n)audio_calibrate_timer(0);
813 select(n,&empty,&writefs,&empty,NULL);
817 /* if our buffers either don't exist or are ready to go,
818 we can begin playback */
819 if((!theora_p || videobuf_ready) &&
820 (!vorbis_p || audiobuf_ready))stateflag=1;
821 /* same if we've run out of input */
822 if(feof(infile))stateflag=1;
826 /* tear it all down */
832 ogg_stream_clear(&vo);
833 vorbis_block_clear(&vb);
834 vorbis_dsp_clear(&vd);
835 vorbis_comment_clear(&vc);
836 vorbis_info_clear(&vi);
839 ogg_stream_clear(&to);
841 th_comment_clear(&tc);
846 if(infile && infile!=stdin)fclose(infile);
850 fprintf(stderr, "%d frames", frames);
851 if (dropped) fprintf(stderr, " (%d dropped)", dropped);
852 fprintf(stderr, "\n");
853 fprintf(stderr, "\nDone.\n");