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-2003 *
9 * by the Xiph.Org Foundation http://www.xiph.org/ *
11 ********************************************************************
13 function: example SDL player application; plays Ogg Theora files (with
14 optional Vorbis audio second stream)
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,
29 #define _LARGEFILE_SOURCE
30 #define _LARGEFILE64_SOURCE
31 #define _FILE_OFFSET_BITS 64
46 #include <sys/types.h>
51 #include "theora/theora.h"
52 #include "vorbis/codec.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"
66 #include <sys/soundcard.h>
67 #define AUDIO_DEVICE "/dev/dsp"
69 #include <sys/ioctl.h>
71 /* Helper; just grab some more compressed bitstream and sync it for
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
);
80 /* never forget that globals are a one-way ticket to Hell */
81 /* Ogg and codec state for demux/decode */
98 /* SDL Video playback structures */
100 SDL_Overlay
*yuv_overlay
;
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 */
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
150 ogg_int64_t audiofd_timer_calibrate
=-1;
152 static void open_audio(){
154 int format
=AFMT_S16_NE
; /* host endian */
155 int channels
=vi
.channels
;
159 audiofd
=open(AUDIO_DEVICE
,O_RDWR
);
161 fprintf(stderr
,"Could not open audio device " AUDIO_DEVICE
".\n");
165 ret
=ioctl(audiofd
,SNDCTL_DSP_SETFMT
,&format
);
167 fprintf(stderr
,"Could not set 16 bit host-endian playback\n");
171 ret
=ioctl(audiofd
,SNDCTL_DSP_CHANNELS
,&channels
);
173 fprintf(stderr
,"Could not set %d channel playback\n",channels
);
177 ret
=ioctl(audiofd
,SNDCTL_DSP_SPEED
,&rate
);
179 fprintf(stderr
,"Could not set %d Hz playback\n",rate
);
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){
192 ioctl(audiofd
,SNDCTL_DSP_RESET
,NULL
);
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
){
202 ogg_int64_t current_sample
;
203 ogg_int64_t new_time
;
206 new_time
=tv
.tv_sec
*1000+tv
.tv_usec
/1000;
209 current_sample
=audiobuf_granulepos
-audiobuf_fill
/2/vi
.channels
;
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
222 static ogg_int64_t last
=0;
223 static ogg_int64_t up
=0;
228 now
=tv
.tv_sec
*1000+tv
.tv_usec
/1000;
230 if(audiofd_timer_calibrate
==-1)audiofd_timer_calibrate
=last
=now
;
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
237 if(now
-last
>1000)audiofd_timer_calibrate
+=(now
-last
);
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
);
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){
265 ioctl(audiofd
,SNDCTL_DSP_GETOSPACE
,&info
);
267 if(bytes
>=audiofd_fragsize
){
268 if(bytes
==audiofd_totalsize
)audio_calibrate_timer(1);
271 bytes
=write(audiofd
,audiobuf
+(audiofd_fragsize
-audiobuf_fill
),
276 if(bytes
!=audiobuf_fill
){
277 /* shouldn't actually be possible... but eh */
278 audiobuf_fill
-=bytes
;
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) */
294 static void sigint_handler (int signal
) {
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());
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());
311 yuv_overlay
= SDL_CreateYUVOverlay(ti
.frame_width
, ti
.frame_height
,
314 if ( yuv_overlay
== NULL
) {
315 fprintf(stderr
, "SDL: Couldn't create SDL_yuv_overlay: %s\n",
321 rect
.w
= ti
.frame_width
;
322 rect
.h
= ti
.frame_height
;
324 SDL_DisplayYUVOverlay(yuv_overlay
, &rect
);
327 static void video_write(void){
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
,
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
,
353 memcpy(yuv_overlay
->pixels
[2]+yuv_overlay
->pitches
[2]*i
,
354 yuv
.u
+crop_offset
+yuv
.uv_stride
*i
,
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
){
375 fprintf(out
,"Encoded by %s\n",tc
->vendor
);
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
];
382 memcpy(value
,tc
->user_comments
[i
],len
);
384 fprintf(out
, "\t%s\n", value
);
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 */
402 case OC_CS_ITU_REC_470M
:
403 fprintf(stderr
," encoder specified ITU Rec 470M (NTSC) color.\n");
405 case OC_CS_ITU_REC_470BG
:
406 fprintf(stderr
," encoder specified ITU Rec 470BG (PAL) color.\n");
409 fprintf(stderr
,"warning: encoder specified unknown colorspace (%d).\n",
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
);
424 static void usage(void){
426 "Usage: player_example <file.ogg>\n"
427 "input is read from stdin if no file is passed on the command line\n"
432 int main(int argc
,char *argv
[]){
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
);
445 /* open the input file if any */
447 infile
=fopen(argv
[1],"rb");
449 fprintf(stderr
,"Unable to open '%s' for playback.\n", argv
[1]);
458 /* start up Ogg stream synchronization layer */
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 */
472 int ret
=buffer_data(infile
,&oy
);
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 */
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){
492 memcpy(&to
,&test
,sizeof(test
));
494 }else if(!vorbis_p
&& vorbis_synthesis_headerin(&vi
,&vc
,&op
)>=0){
496 memcpy(&vo
,&test
,sizeof(test
));
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)){
510 /* look for further theora headers */
511 while(theora_p
&& (theora_p
<3) && (ret
=ogg_stream_packetout(&to
,&op
))){
513 fprintf(stderr
,"Error parsing Theora stream headers; corrupt stream?\n");
516 if(theora_decode_header(&ti
,&tc
,&op
)){
517 printf("Error parsing Theora stream headers; corrupt stream?\n");
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
))){
527 fprintf(stderr
,"Error parsing Vorbis stream headers; corrupt stream?\n");
530 if(vorbis_synthesis_headerin(&vi
,&vc
,&op
)){
531 fprintf(stderr
,"Error parsing Vorbis stream headers; corrupt stream?\n");
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 */
544 int ret
=buffer_data(infile
,&oy
); /* someone needs more data */
546 fprintf(stderr
,"End of file while searching for codec headers.\n");
552 /* and now we have it all. initialize decoders */
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;
564 printf(" video\n (UNKNOWN Chroma sampling!)\n");
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
);
573 /* tear down the partial theora setup */
574 theora_info_clear(&ti
);
575 theora_comment_clear(&tc
);
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
);
583 /* tear down the partial vorbis setup */
584 vorbis_info_clear(&vi
);
585 vorbis_comment_clear(&vc
);
589 if(vorbis_p
)open_audio();
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 */
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
){
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;
628 audiobuf_granulepos
=vd
.granulepos
-ret
+i
;
630 audiobuf_granulepos
+=i
;
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 */
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())
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){
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()){
685 (audiobuf_ready
|| !vorbis_p
) &&
686 (videobuf_ready
|| !theora_p
) &&
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
;
701 FD_SET(audiofd
,&writefs
);
706 long milliseconds
=(videobuf_time
-get_time())*1000-5;
707 if(milliseconds
>500)milliseconds
=500;
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);
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 */
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
);
742 ogg_stream_clear(&to
);
744 theora_comment_clear(&tc
);
745 theora_info_clear(&ti
);
749 if(infile
&& infile
!=stdin
)fclose(infile
);