[xiph-cvs] cvs commit: theora/lib toplevel.c

Monty xiphmont at xiph.org
Tue Sep 24 04:18:22 PDT 2002



xiphmont    02/09/24 07:18:22

  Modified:    examples Makefile.am player_example.c
               lib      toplevel.c
  Log:
  player is running, currently it busywaits, hardware audio sync is still a mess

Revision  Changes    Path
1.4       +2 -1      theora/examples/Makefile.am

Index: Makefile.am
===================================================================
RCS file: /usr/local/cvsroot/theora/examples/Makefile.am,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- Makefile.am	24 Sep 2002 05:05:49 -0000	1.3
+++ Makefile.am	24 Sep 2002 11:18:22 -0000	1.4
@@ -7,9 +7,10 @@
 noinst_PROGRAMS = encoder_example player_example 
 
 LDFLAGS = -all-static 
-LDADD = ../lib/libtheora.la -lm -logg -lvorbis 
+LDADD = ../lib/libtheora.la -lm -logg -lvorbis
 
 player_example_SOURCES = player_example.c
+player_example_LDADD = $(LDADD) -lSDL -lpthread
 encoder_example_SOURCES = encoder_example.c
 encoder_example_LDADD = $(LDADD) -lvorbisenc
 

<p><p>1.2       +302 -24   theora/examples/player_example.c

Index: player_example.c
===================================================================
RCS file: /usr/local/cvsroot/theora/examples/player_example.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- player_example.c	24 Sep 2002 05:05:49 -0000	1.1
+++ player_example.c	24 Sep 2002 11:18:22 -0000	1.2
@@ -12,7 +12,7 @@
 
   function: example SDL player application; plays Ogg Theora files (with
             optional Vorbis audio second stream)
-  last mod: $Id: player_example.c,v 1.1 2002/09/24 05:05:49 xiphmont Exp $
+  last mod: $Id: player_example.c,v 1.2 2002/09/24 11:18:22 xiphmont Exp $
 
  ********************************************************************/
 
@@ -20,17 +20,19 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
-#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 #include <math.h>
+#include <signal.h>
 #include "theora/theora.h"
 #include "vorbis/codec.h"
 #include <SDL/SDL.h>
 
-/*
-int open_audio(){}
-double get_audio_time(){}
-double get_time(){}
-*/
+/* yes, this makes us OSS-specific for now */
+#include <sys/soundcard.h>
+#include <sys/ioctl.h>
+
 
 int buffer_data(ogg_sync_state *oy){
   char *buffer=ogg_sync_buffer(oy,4096);
@@ -39,23 +41,122 @@
   return(bytes);
 }
 
-int main(void){
+/* never forget that globals are a one-way ticket to Hell */
+
+ogg_sync_state   oy; /* sync and verify incoming physical bitstream */
+ogg_page         og;
+ogg_stream_state vo;
+ogg_stream_state to;
+theora_info      ti;
+theora_state     td;
+vorbis_info      vi;
+vorbis_dsp_state vd;
+vorbis_block     vb;
+vorbis_comment   vc;
+
+
+SDL_Surface *screen;
+SDL_Overlay *yuv_overlay;
+SDL_Rect rect;
+
+int videobuf_fill=0;
+ogg_int64_t videobuf_granulepos=0;
+double videobuf_time=0;
+
+int audiobuf_fill=0;
+int audiobuf_written=0;
+ogg_int16_t audiobuf[4096];
+ogg_int64_t audiobuf_granulepos=0; /* time position of last sample */
+double audiobuf_time=0; /* time position of last sample */
+long audio_totalsize=-1;
+int  audiofd=-1;
+int audio_buffstate=0;
+
+int got_sigint=0;
+static void sigint_handler (int signal) {
+  got_sigint = 1;
+}
+
+static ogg_int64_t cali_time;
+void calibrate_timer(int bytes){
+  struct timeval tv;
+  ogg_int64_t samples;
+  gettimeofday(&tv,0);
+  cali_time=tv.tv_sec*1000+tv.tv_usec/1000;
+
+  samples=audiobuf_granulepos-
+    audiobuf_fill+
+    audiobuf_written-
+    (bytes/2/vi.channels);
+  
+  cali_time-=1000.*samples/vi.rate;
+  fprintf(stderr,"cali_time: %ld\n",(long)cali_time);
+}
+
+double get_time(){
+  static int init=0;
+  static ogg_int64_t start; 
   
-  ogg_sync_state   oy; /* sync and verify incoming physical bitstream */
-  ogg_page         og;
-  ogg_stream_state vo;
-  ogg_stream_state to;
-  theora_info      ti;
-  theora_state     td;
-  vorbis_info      vi;
-  vorbis_dsp_state vd;
-  vorbis_block     vb;
-  vorbis_comment   vc;
+  if(!init){
+    struct timeval tv;
+    gettimeofday(&tv,0);
+    start=tv.tv_sec*1000+tv.tv_usec/1000;
+    init=1;
+  }
+
+  {
+    struct timeval tv;
+    ogg_int64_t now;
+    gettimeofday(&tv,0);
+    now=tv.tv_sec*1000+tv.tv_usec/1000;
+
+    if(audiofd<0) return(now-start*.001);
+
+    return (now-cali_time)*.001;
+  }
+}
+
+void audio_write_nonblocking(void){
+
+  if(audiobuf_fill){
+    audio_buf_info info;
+    long bytes;
+
+    ioctl(audiofd,SNDCTL_DSP_GETOSPACE,&info);
+    bytes=info.bytes;
+    if(bytes){
+      if(audio_buffstate || bytes==audio_totalsize){
+	/* *just* bank switched a fragment.  For a split second, 
+	   the OSPACE is accurate for timing */
+	calibrate_timer(audio_totalsize-bytes);
+      }
+      audio_buffstate=0;
+      if(bytes>audiobuf_fill-audiobuf_written)
+	bytes=audiobuf_fill-audiobuf_written;
+
+      bytes=write(audiofd,audiobuf+audiobuf_written,bytes);
+      if(bytes>0){
+	audiobuf_written+=bytes;
+	if(audiobuf_written>=audiobuf_fill){
+	  audiobuf_fill=0;
+	  audiobuf_written=0;
+	}
+      }
+    }else audio_buffstate=1;
+  } 
+}
 
+int main(void){
+  
   int theora_p=0;
   int vorbis_p=0;
   int stateflag=0;
 
+  if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
+    fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
+    exit(1);
+  }
+
 #ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows. */
   /* Beware the evil ifdef. We avoid these where we can, but this one we 
      cannot. Don't add any more, you'll probably go to hell if you do. */
@@ -165,21 +266,198 @@
     vorbis_comment_clear(&vc);
   }
 
-  /* on to the main decode loop */
-
+  /* open audio */
+  if(vorbis_p){
+    audio_buf_info info;
+    int format=AFMT_S16_NE;
+    int channels=vi.channels;
+    int rate=vi.rate;
+    int ret;
 
+    audiofd=open("/dev/dsp",O_RDWR);
+    if(audiofd<0){
+      fprintf(stderr,"Could not open audio device /dev/dsp.\n");
+      exit(1);
+    }
 
+    ret=ioctl(audiofd,SNDCTL_DSP_SETFMT,&format);
+    if(ret){
+      fprintf(stderr,"Could not set 16 bit host-endian playback\n");
+      exit(1);
+    }
+    
+    ret=ioctl(audiofd,SNDCTL_DSP_CHANNELS,&vi.channels);
+    if(ret){
+      fprintf(stderr,"Could not set %d channel playback\n",channels);
+      exit(1);
+    }
 
-#if 0
-    if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
-      fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
+    ioctl(audiofd,SNDCTL_DSP_SPEED,&rate);
+    if(ret){
+      fprintf(stderr,"Could not set %d Hz playback\n",rate);
       exit(1);
     }
 
+    ioctl(audiofd,SNDCTL_DSP_GETOSPACE,&info);
+    audio_totalsize=info.fragstotal*info.fragsize;
 
+  }
 
+  /* open video */
 
-    SDL_Quit();
-#endif
+  screen = SDL_SetVideoMode(ti.width, ti.height, 0, SDL_SWSURFACE);
+  if ( screen == NULL ) {
+    fprintf(stderr, "Unable to set 640x480 video: %s\n", SDL_GetError());
+    exit(1);
+  }
+
+  yuv_overlay = SDL_CreateYUVOverlay(ti.width, ti.height,
+				     SDL_YV12_OVERLAY,
+				     screen);
+  if ( yuv_overlay == NULL ) {
+    fprintf(stderr, "SDL: Couldn't create SDL_yuv_overlay: %s\n", SDL_GetError());
+    exit(1);
+  }
+  rect.x = 0;
+  rect.y = 0;
+  rect.w = ti.width;
+  rect.h = ti.height;
+
+  SDL_DisplayYUVOverlay(yuv_overlay, &rect);
+  signal (SIGINT, sigint_handler);
+
+
+  /* on to the main decode loop.  We assume in this example that audio
+     and video start roughly together, and don't begin playback until
+     we have a start frame for both */
+  {
+    int i,j;
+    ogg_packet op;
+
+    while(!got_sigint){
+      
+      /* we want a video and audio frame ready to go at all times.  If
+	 we have to buffer incoming, buffer the compressed data (ie, let
+	 ogg do the buffering) */
+      while(vorbis_p && !audiobuf_fill){
+	int ret;
+	float **pcm;
+
+	/* if there's pending, decoded audio, grab it */
+	if((ret=vorbis_synthesis_pcmout(&vd,&pcm))>0){
+	  int count=0;
+	  int maxsamples=4096/vi.channels;
+	  for(i=0;i<ret && i<maxsamples;i++)
+	    for(j=0;j<vi.channels;j++){
+	      int val=rint(pcm[j][i]*32767.f);
+	      if(val>32767)val=32767;
+	      if(val<-32768)val=-32768;
+	      audiobuf[count++]=val;
+	    }
+	  vorbis_synthesis_read(&vd,i);
+	  audiobuf_fill=i*vi.channels*2;
+
+	  if(vd.granulepos>=0)
+	    audiobuf_granulepos=vd.granulepos-ret+i;
+	  else
+	    audiobuf_granulepos+=i;
+
+
+	  audiobuf_time=vorbis_granule_time(&vd,audiobuf_granulepos);
+	}else{
+	  
+	  /* no pending audio; is there a pending packet to decode? */
+	  if(ogg_stream_packetout(&vo,&op)>0){
+	    if(vorbis_synthesis(&vb,&op)==0) /* test for success! */
+	      vorbis_synthesis_blockin(&vd,&vb);
+	  }else	/* we need more data; break out to suck in another page */
+	    break;
+	}
+      }
+      
+      if(!videobuf_fill){
+	/* theora is one in, one out... */
+	if(ogg_stream_packetout(&to,&op)>0){
+	  theora_decode_packetin(&td,&op);
+	  videobuf_fill=1;
+
+	  if(op.granulepos>=0)
+	    videobuf_granulepos=op.granulepos;
+	  else
+	    videobuf_granulepos++;
+	    
+	  videobuf_time=theora_granule_time(&td,videobuf_granulepos);
+
+	}
+      }
+
+      if(!videobuf_fill && !audiobuf_fill && feof(stdin))break;
+      
+      if(!videobuf_fill || !audiobuf_fill){
+	/* no data yet for somebody.  Grab another page */
+	int ret=buffer_data(&oy);
+	while(ogg_sync_pageout(&oy,&og)>0){
+	  if(ogg_stream_pagein(&to,&og))
+	    if(vorbis_p)ogg_stream_pagein(&vo,&og);
+	}
+      }
+      
+      /* Top audio buffer off immediately; nonblocking write */
+      audio_write_nonblocking();
+      
+      /* are we at or past time for this video frame? */
+      if(videobuf_fill && videobuf_time<=get_time()){
+	yuv_buffer yuv;
+	theora_decode_YUVout(&td,&yuv);
+
+	/* Lock SDL_yuv_overlay */
+	if ( SDL_MUSTLOCK(screen) ) {
+	  if ( SDL_LockSurface(screen) < 0 ) break;
+	}
+	if (SDL_LockYUVOverlay(yuv_overlay) < 0) break;
+
+	/* let's draw the data (*yuv[3]) on a SDL screen (*screen) */
+	/* deal with border stride */
+	for(i=0;i<yuv.y_height;i++)
+	  memcpy(yuv_overlay->pixels[0]+yuv.y_width*i, 
+		 yuv.y+yuv.y_stride*i, 
+		 yuv.y_width);
+	for(i=0;i<yuv.uv_height;i++){
+	  memcpy(yuv_overlay->pixels[1]+yuv.uv_width*i, 
+		 yuv.v+yuv.uv_stride*i, 
+		 yuv.uv_width);
+	  memcpy(yuv_overlay->pixels[2]+yuv.uv_width*i, 
+		 yuv.u+yuv.uv_stride*i, 
+		 yuv.uv_width);
+	}
+
+	/* Unlock SDL_yuv_overlay */
+	if ( SDL_MUSTLOCK(screen) ) {
+	  SDL_UnlockSurface(screen);
+	}
+	SDL_UnlockYUVOverlay(yuv_overlay);
+
+
+	/* Show, baby, show! */
+	SDL_DisplayYUVOverlay(yuv_overlay, &rect);
+	videobuf_fill=0;
+
+      }
+
+      
+      /* block if there's nothing else to do */
+      if(audiobuf_fill && videobuf_fill){
+	
+	
+
+
+      }
+
+    }
+
+  }
+
+  SDL_Quit();
 }
+
 

<p><p>1.11      +2 -2      theora/lib/toplevel.c

Index: toplevel.c
===================================================================
RCS file: /usr/local/cvsroot/theora/lib/toplevel.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- toplevel.c	24 Sep 2002 05:06:14 -0000	1.10
+++ toplevel.c	24 Sep 2002 11:18:22 -0000	1.11
@@ -11,7 +11,7 @@
  ********************************************************************
 
   function: 
-  last mod: $Id: toplevel.c,v 1.10 2002/09/24 05:06:14 xiphmont Exp $
+  last mod: $Id: toplevel.c,v 1.11 2002/09/24 11:18:22 xiphmont Exp $
 
  ********************************************************************/
 
@@ -995,7 +995,7 @@
   op->packetno=cpi->CurrentFrame;
 
   op->granulepos=
-    ((cpi->CurrentFrame-cpi->LastKeyFrame)<<cpi->pb.keyframe_granule_shift)+ 
+    ((cpi->CurrentFrame-cpi->LastKeyFrame-1)<<cpi->pb.keyframe_granule_shift)+ 
     cpi->LastKeyFrame-1;
 
   cpi->packetflag=0;

<p><p>--- >8 ----
List archives:  http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.



More information about the commits mailing list