[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