changeset 5572:8cd761968f35

BSD-BT848 TV update patch by Charles Henrich <henrich@sigbus.com> - tvi interface changes, grab_audio/video now returns timestamp! - tv demuxer gets 'ds' hint too - some verbose skip/dup counters to mencoder - tvi_bsdbt848.c updates - aviwrite/mencoder size types int->off_t
author arpi
date Fri, 12 Apr 2002 10:40:38 +0000
parents 124bfc43c044
children b8a8ab95c73d
files cfg-common.h configure libmpdemux/aviwrite.c libmpdemux/aviwrite.h libmpdemux/demuxer.c libmpdemux/tv.c libmpdemux/tv.h libmpdemux/tvi_bsdbt848.c libmpdemux/tvi_def.h libmpdemux/tvi_dummy.c libmpdemux/tvi_v4l.c libmpdemux/video.c mencoder.c mplayer.c
diffstat 14 files changed, 668 insertions(+), 417 deletions(-) [+]
line wrap: on
line diff
--- a/cfg-common.h	Fri Apr 12 10:17:24 2002 +0000
+++ b/cfg-common.h	Fri Apr 12 10:40:38 2002 +0000
@@ -107,7 +107,11 @@
 #ifdef USE_TV
 struct config tvopts_conf[]={
 	{"on", &tv_param_on, CONF_TYPE_FLAG, 0, 0, 1, NULL},
+#ifdef HAVE_TV_BSDBT848
+	{"immediatemode", &tv_param_immediate, CONF_TYPE_FLAG, 0, 0, 0, NULL},
+#endif
 	{"noaudio", &tv_param_noaudio, CONF_TYPE_FLAG, 0, 0, 1, NULL},
+	{"audiorate", &tv_param_audiorate, CONF_TYPE_INT, 0, 0, 0, NULL},
 	{"driver", &tv_param_driver, CONF_TYPE_STRING, 0, 0, 0, NULL},
 	{"device", &tv_param_device, CONF_TYPE_STRING, 0, 0, 0, NULL},
 	{"freq", &tv_param_freq, CONF_TYPE_STRING, 0, 0, 0, NULL},
--- a/configure	Fri Apr 12 10:17:24 2002 +0000
+++ b/configure	Fri Apr 12 10:40:38 2002 +0000
@@ -3228,6 +3228,21 @@
   fi
 fi
 
+echocheck "ftello()"
+# if we dont have ftello map it to ftell
+cat > $TMPC << EOF
+#include <stdio.h>
+int main (void) { ftello(stdin); return 0; }
+EOF
+_ftello=no
+cc_check && _ftello=yes
+if test "$_ftello" = yes ; then
+ _def_ftello='#define HAVE_FTELLO 1'
+else
+ _def_ftello='#undef HAVE_FTELLO'
+fi
+echores "$_ftello"
+
 # Determine OS dependent libs
 if cygwin ; then
   _confcygwin='TARGET_CYGWIN = yes'
@@ -3507,6 +3522,13 @@
 /* Define this if your system has the header file for the OSS sound interface */
 $_def_sys_soundcard
 
+/* Define this if your system uses ftello() for off_t seeking */
+
+$_def_ftello
+#ifndef HAVE_FTELLO
+# define ftello(a) ftell(a)
+#endif
+
 /* Define this if your system has the "malloc.h" header file */
 $_def_malloc
 
--- a/libmpdemux/aviwrite.c	Fri Apr 12 10:17:24 2002 +0000
+++ b/libmpdemux/aviwrite.c	Fri Apr 12 10:40:38 2002 +0000
@@ -2,6 +2,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/types.h>
 
 #include "config.h"
 
--- a/libmpdemux/aviwrite.h	Fri Apr 12 10:17:24 2002 +0000
+++ b/libmpdemux/aviwrite.h	Fri Apr 12 10:40:38 2002 +0000
@@ -10,7 +10,7 @@
   int id;    // stream no
   unsigned int ckid; // chunk id (00dc 01wb etc)
   double timer;
-  unsigned int size;
+  off_t size;
   // buffering:
   unsigned char *buffer;
   unsigned int buffer_size;
--- a/libmpdemux/demuxer.c	Fri Apr 12 10:17:24 2002 +0000
+++ b/libmpdemux/demuxer.c	Fri Apr 12 10:40:38 2002 +0000
@@ -214,7 +214,7 @@
 extern tvi_handle_t *tv_handler;
 extern int tv_param_on;
 
-extern int demux_tv_fill_buffer(demuxer_t *demux, tvi_handle_t *tvh);
+extern int demux_tv_fill_buffer(demuxer_t *demux, demux_stream_t *ds, tvi_handle_t *tvh);
 extern int demux_open_tv(demuxer_t *demuxer, tvi_handle_t *tvh);
 #endif
 int demux_y4m_fill_buffer(demuxer_t *demux);
@@ -242,7 +242,7 @@
     case DEMUXER_TYPE_REAL: return demux_real_fill_buffer(demux);
     case DEMUXER_TYPE_NUV: return demux_nuv_fill_buffer(demux);
 #ifdef USE_TV
-    case DEMUXER_TYPE_TV: return demux_tv_fill_buffer(demux, tv_handler);
+    case DEMUXER_TYPE_TV: return demux_tv_fill_buffer(demux, ds, tv_handler);
 #endif
     case DEMUXER_TYPE_Y4M: return demux_y4m_fill_buffer(demux);
     case DEMUXER_TYPE_AUDIO: return demux_audio_fill_buffer(ds);
--- a/libmpdemux/tv.c	Fri Apr 12 10:17:24 2002 +0000
+++ b/libmpdemux/tv.c	Fri Apr 12 10:40:38 2002 +0000
@@ -6,7 +6,7 @@
  API idea based on libvo2
 
  Feb 19, 2002: Significant rewrites by Charles R. Henrich (henrich@msu.edu)
-	       try to fix audio support, and bktr *BSD support.
+				to add support for audio, and bktr *BSD support.
 
 */
 
@@ -37,7 +37,11 @@
 #include "frequencies.h"
 
 /* some default values */
+int tv_param_audiorate = 44100;
 int tv_param_noaudio = 0;
+#ifdef HAVE_TV_BSDBT848
+int tv_param_immediate = 0;
+#endif
 char *tv_param_freq = NULL;
 char *tv_param_channel = NULL;
 char *tv_param_norm = "pal";
@@ -58,57 +62,39 @@
 */
 /* fill demux->video and demux->audio */
 
-int demux_tv_fill_buffer(demuxer_t *demux, tvi_handle_t *tvh)
+int demux_tv_fill_buffer(demuxer_t *demux, demux_stream_t *ds, tvi_handle_t *tvh)
 {
     demux_packet_t* dp;
 
     sh_video_t *sh_video = demux->video->sh;
     u_int len;
-    u_int cframe;
     int aframeswaiting;
 
-    len = cframe = -1;
+    len = 0;
 
     /* ================== ADD AUDIO PACKET =================== */
 
-    if (tv_param_noaudio == 0 && 
+    if (ds==demux->audio && tv_param_noaudio == 0 && 
         tvh->functions->control(tvh->priv, 
                                 TVI_CONTROL_IS_AUDIO, 0) == TVI_CONTROL_TRUE)
         {
         len = tvh->functions->get_audio_framesize(tvh->priv);
 
-        do {
-            dp=new_demux_packet(len);
-            aframeswaiting=tvh->functions->grab_audio_frame(tvh->priv,
-                                                            dp->buffer,len);
-            dp->pts=tvh->seq/sh_video->fps;
-            dp->pos=tvh->seq*len;
-            ds_add_packet(demux->audio,dp);
-
-            tvh->seq++;
-
-           } while (aframeswaiting > 0);
+        dp=new_demux_packet(len);
+        dp->pts=tvh->functions->grab_audio_frame(tvh->priv, dp->buffer,len);
+        ds_add_packet(demux->audio,dp);
         }
 
     /* ================== ADD VIDEO PACKET =================== */
 
-    if (tvh->functions->control(tvh->priv, 
+    if (ds==demux->video && tvh->functions->control(tvh->priv, 
                             TVI_CONTROL_IS_VIDEO, 0) == TVI_CONTROL_TRUE)
         {
-        len = tvh->functions->get_video_framesize(tvh->priv);
-
-        dp=new_demux_packet(len);
-
-        cframe=tvh->functions->grab_video_frame(tvh->priv, dp->buffer, 
-                                                len);
-
-        if(tv_param_noaudio == 1) tvh->seq = cframe;
-
-        dp->pos=tvh->seq*len;
-        dp->pts=tvh->seq/sh_video->fps;
-
-        ds_add_packet(demux->video,dp);
-        }
+		len = tvh->functions->get_video_framesize(tvh->priv);
+       	dp=new_demux_packet(len);
+  		dp->pts=tvh->functions->grab_video_frame(tvh->priv, dp->buffer, len);
+   		ds_add_packet(demux->video,dp);
+	 }
 
     return 1;
 }
@@ -190,7 +176,7 @@
     if (funcs->control(tvh->priv, TVI_CONTROL_IS_TUNER, 0) != TVI_CONTROL_TRUE)
     {
 	mp_msg(MSGT_TV, MSGL_WARN, "Selected input hasn't got a tuner!\n");	
-	goto start_device;
+	goto done;
     }
 
     /* select channel list */
@@ -214,7 +200,7 @@
     if (tv_param_freq && tv_param_channel)
     {
 	mp_msg(MSGT_TV, MSGL_WARN, "You can't set frequency and channel simultanly!\n");
-	goto start_device;
+	goto done;
     }
 
     /* we need to set frequency */
@@ -251,9 +237,9 @@
 	}
     }
 
-start_device:    
+done:    
     /* also start device! */
-    return(funcs->start(tvh->priv));	
+	return 1;
 }
 
 int demux_open_tv(demuxer_t *demuxer, tvi_handle_t *tvh)
@@ -286,6 +272,15 @@
 
     printf("fps: %f, frametime: %f\n", sh_video->fps, sh_video->frametime);
 
+#ifdef HAVE_TV_BSDBT848
+    /* If playback only mode, go to immediate mode, fail silently */
+    if(tv_param_immediate == 1)
+        {
+        funcs->control(tvh->priv, TVI_CONTROL_IMMEDIATE, 0);
+        tv_param_noaudio = 1; 
+        }
+#endif
+
     /* set width */
     funcs->control(tvh->priv, TVI_CONTROL_VID_GET_WIDTH, &sh_video->disp_w);
 
@@ -308,6 +303,10 @@
 	int sh_audio_format;
 
 	/* yeah, audio is present */
+
+	funcs->control(tvh->priv, TVI_CONTROL_AUD_SET_SAMPLERATE, 
+				  &tv_param_audiorate);
+
 	if (funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_FORMAT, &audio_format) != TVI_CONTROL_TRUE)
 	    goto no_audio;
 
@@ -334,7 +333,6 @@
 	}
 	
 	sh_audio = new_sh_audio(demuxer, 0);
-	sh_audio->wf = (WAVEFORMATEX *)malloc(sizeof(WAVEFORMATEX));
 
 	funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_SAMPLERATE, 
                    &sh_audio->samplerate);
@@ -347,33 +345,21 @@
 	sh_audio->sample_format = audio_format;
 
 	sh_audio->i_bps = sh_audio->o_bps =
-	    sh_audio->samplerate * sh_audio->samplesize/8 * 
+	    sh_audio->samplerate * sh_audio->samplesize * 
 	    sh_audio->channels;
 
+	// emulate WF for win32 codecs:
+	sh_audio->wf = (WAVEFORMATEX *)malloc(sizeof(WAVEFORMATEX));
 	sh_audio->wf->wFormatTag = sh_audio->format;
 	sh_audio->wf->nChannels = sh_audio->channels;
-	switch(audio_format)
-	{
-	    case AFMT_U8:
-	    case AFMT_S8:
-		sh_audio->wf->wBitsPerSample = 8;
-		break;
-	    case AFMT_U16_LE:
-	    case AFMT_U16_BE:
-	    case AFMT_S16_LE:
-	    case AFMT_S16_BE:
-		sh_audio->wf->wBitsPerSample = 16;
-		break;
-	    case AFMT_S32_LE:
-	    case AFMT_S32_BE:
-		sh_audio->wf->wBitsPerSample = 32;
-		break;
-	}
+	sh_audio->wf->wBitsPerSample = sh_audio->samplesize * 8;
 	sh_audio->wf->nSamplesPerSec = sh_audio->samplerate;
-	sh_audio->wf->nBlockAlign = sh_audio->wf->nAvgBytesPerSec;
-	sh_audio->wf->nAvgBytesPerSec = sh_audio->wf->nChannels * 
-                                    sh_audio->samplesize/8 * 
-                                    sh_audio->samplerate;
+	sh_audio->wf->nBlockAlign = sh_audio->samplesize * sh_audio->channels;
+	sh_audio->wf->nAvgBytesPerSec = sh_audio->i_bps;
+
+	mp_msg(MSGT_DECVIDEO, MSGL_V, "  TV audio: %d channels, %d bits, %d Hz\n",
+          sh_audio->wf->nChannels, sh_audio->wf->wBitsPerSample,
+          sh_audio->wf->nSamplesPerSec);
 
 	demuxer->audio->sh = sh_audio;
 	sh_audio->ds = demuxer->audio;
@@ -381,7 +367,7 @@
     }
 no_audio:
 
-    return(1);
+    return(funcs->start(tvh->priv));	
 }
 
 /* ================== STREAM_TV ===================== */
--- a/libmpdemux/tv.h	Fri Apr 12 10:17:24 2002 +0000
+++ b/libmpdemux/tv.h	Fri Apr 12 10:40:38 2002 +0000
@@ -21,6 +21,8 @@
 extern char *tv_param_outfmt;
 extern float tv_param_fps;
 extern int tv_param_noaudio;
+extern int tv_param_immediate;
+extern int tv_param_audiorate;
 
 typedef struct tvi_info_s
 {
@@ -36,9 +38,12 @@
     int (*uninit)();
     int (*control)();
     int (*start)();
-    int (*grab_video_frame)();
+    double (*grab_video_frame)();
+#ifdef HAVE_TV_BSDBT848
+    double (*grabimmediate_video_frame)();
+#endif
     int (*get_video_framesize)();
-    int (*grab_audio_frame)();
+    double (*grab_audio_frame)();
     int (*get_audio_framesize)();
 } tvi_functions_t;
 
@@ -67,6 +72,9 @@
 #define TVI_CONTROL_IS_AUDIO		0x1
 #define TVI_CONTROL_IS_VIDEO		0x2
 #define TVI_CONTROL_IS_TUNER		0x3
+#ifdef HAVE_TV_BSDBT848
+#define TVI_CONTROL_IMMEDIATE       0x4
+#endif
 
 /* VIDEO controls */
 #define TVI_CONTROL_VID_GET_FPS		0x101
@@ -107,6 +115,7 @@
 #define TVI_CONTROL_AUD_GET_SAMPLERATE	0x302
 #define TVI_CONTROL_AUD_GET_SAMPLESIZE	0x303
 #define TVI_CONTROL_AUD_GET_CHANNELS	0x304
+#define TVI_CONTROL_AUD_SET_SAMPLERATE	0x305
 
 /* SPECIFIC controls */
 #define TVI_CONTROL_SPC_GET_INPUT	0x401	/* set input channel (tv,s-video,composite..) */
--- a/libmpdemux/tvi_bsdbt848.c	Fri Apr 12 10:17:24 2002 +0000
+++ b/libmpdemux/tvi_bsdbt848.c	Fri Apr 12 10:40:38 2002 +0000
@@ -1,27 +1,32 @@
 /*
-	(C)2002 Charles R. Henrich (henrich@msu.edu)
-	*BSD (hopefully, requires working driver!) BrookTree capture support.
+    (C)2002 Charles R. Henrich (henrich@msu.edu)
+    *BSD (hopefully, requires working driver!) BrookTree capture support.
 
-	Still in (active) development!
+    Still in (active) development!
 
-	v1.0	Feb 19 2002		First Release, need to add support for changing
-							audio parameters.
+	v1.1	Mar 13 2002   Fully functional, need to move ring buffer to
+						  the kernel driver. 
+    v1.0    Feb 19 2002   First Release, need to add support for changing
+                            audio parameters.
 */
 
 #include "config.h"
 
 #if defined(USE_TV) && defined(HAVE_TV_BSDBT848)
 
+#define RINGSIZE 8
+#define FRAGSIZE 4096 /* (2^12 see SETFRAGSIZE below) */
+
 #define TRUE  (1==1)
 #define FALSE (1==0)
 
 #define PAL_WIDTH  768
 #define PAL_HEIGHT 576
-#define PAL_FPS	25
+#define PAL_FPS    25
 
 #define NTSC_WIDTH  640
 #define NTSC_HEIGHT 480
-#define NTSC_FPS	30
+#define NTSC_FPS    30
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -29,11 +34,14 @@
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/mman.h>
+#include <sys/filio.h>
+#include <sys/time.h>
 #include <signal.h>
 #include <string.h>
 
 #include <machine/ioctl_meteor.h>
 #include <machine/ioctl_bt848.h>
+
 #ifdef HAVE_SYS_SOUNDCARD_H
 #include <sys/soundcard.h>
 #else
@@ -45,52 +53,71 @@
 
 /* information about this file */
 static tvi_info_t info = {
-	"Brooktree848 Support",
-	"bt848",
-	"Charles Henrich",
-	"in development"
+    "Brooktree848 Support",
+    "bsdbt848",
+    "Charles Henrich",
+    "in development"
 };
 
+typedef struct {
+    int dirty;
+    double timestamp;
+    char *buf;
+} RBFRAME;
+
 /* private data's */
 typedef struct {
 
 /* Audio */
-	char *dspdev;
-	int dspready;
-	int dspfd;
-	int dspsamplesize;
-	int dspstereo;
-	int dspspeed;
-	int dspfmt;
-	int dspframesize;
+    char *dspdev;
+    int dspready;
+    int dspfd;
+    int dspsamplesize;
+    int dspstereo;
+    int dspspeed;
+    int dspfmt;
+    int dspframesize;
+    int dsprate;
+    long long dspbytesread;
 
 /* Video */
-	char *btdev;
-	int videoready;
-	int btfd;
-	int source;
-	int maxfps;
-	int fps;
-	int iformat;
-	int maxheight;
-	int maxwidth;
-	struct meteor_geomet geom;
-	struct meteor_capframe capframe;
-	int buffersize;
-	unsigned char *buffer;
-	int currentframe;
+    char *btdev;
+    int videoready;
+    int btfd;
+    int source;
+    int maxfps;
+    int fps;
+    int iformat;
+    int maxheight;
+    int maxwidth;
+    struct meteor_geomet geom;
+    struct meteor_capframe capframe;
+
+/* Frame Buffer */
+
+    int framebufsize;
+    float timestamp;
+    int curpaintframe;
+    int curbufframe;
+    unsigned char *livebuf;
+    RBFRAME framebuf[RINGSIZE];
 
 /* Inputs */
 
-	int input;
+    int input;
 
 /* Tuner */
 
-	char *tunerdev;
-	int tunerfd;
-	int tunerready;
-	u_long tunerfreq;
-	struct bktr_chnlset cset;
+    char *tunerdev;
+    int tunerfd;
+    int tunerready;
+    u_long tunerfreq;
+    struct bktr_chnlset cset;
+
+/* Other */
+
+    int immediatemode;
+    double starttime;
 
 } priv_t;
 
@@ -98,10 +125,30 @@
 
 static priv_t *G_private=NULL;
 
+static int getinput(int innumber);
 
 static void processframe(int signal)
 {
-G_private->currentframe++;
+struct timeval curtime;
+
+if(G_private->immediatemode == TRUE) return;
+
+gettimeofday(&curtime, NULL);
+
+if(G_private->framebuf[G_private->curpaintframe].dirty == TRUE)
+    {
+    memcpy(G_private->framebuf[G_private->curpaintframe].buf, 
+            G_private->livebuf, G_private->framebufsize);
+
+    G_private->framebuf[G_private->curpaintframe].dirty = FALSE;
+
+    G_private->framebuf[G_private->curpaintframe].timestamp = 
+            curtime.tv_sec + curtime.tv_usec*.000001;
+
+    G_private->curpaintframe++;
+
+    if(G_private->curpaintframe >= RINGSIZE) G_private->curpaintframe = 0;
+    }
 
 return;
 }
@@ -109,269 +156,295 @@
 /* handler creator - entry point ! */
 tvi_handle_t *tvi_init_bsdbt848(char *device)
 {
-	return(new_handle());
+    return(new_handle());
 }
 
 static int control(priv_t *priv, int cmd, void *arg)
 {
-	switch(cmd)
-	{
+    switch(cmd)
+    {
 
 /* Tuner Controls */
 
-	case TVI_CONTROL_IS_TUNER:
-		if(priv->tunerready == FALSE) return TVI_CONTROL_FALSE;
-		return(TVI_CONTROL_TRUE);
+    case TVI_CONTROL_IS_TUNER:
+        if(priv->tunerready == FALSE) return TVI_CONTROL_FALSE;
+        return(TVI_CONTROL_TRUE);
 
-	case TVI_CONTROL_TUN_GET_FREQ:
-		{
-		if(ioctl(priv->tunerfd, TVTUNER_GETFREQ, &priv->tunerfreq) < 0)
-			{
-			perror("GETFREQ:ioctl");
-			return(TVI_CONTROL_FALSE);
-			}
+    case TVI_CONTROL_TUN_GET_FREQ:
+        {
+        if(ioctl(priv->tunerfd, TVTUNER_GETFREQ, &priv->tunerfreq) < 0)
+            {
+            perror("GETFREQ:ioctl");
+            return(TVI_CONTROL_FALSE);
+            }
 
-		(int)*(void **)arg = priv->tunerfreq;
-		return(TVI_CONTROL_TRUE);
-		}
-	
-	case TVI_CONTROL_TUN_SET_FREQ:
-		{
-		priv->tunerfreq = (int)*(void **)arg;
+        (int)*(void **)arg = priv->tunerfreq;
+        return(TVI_CONTROL_TRUE);
+        }
+    
+    case TVI_CONTROL_TUN_SET_FREQ:
+        {
+        priv->tunerfreq = (int)*(void **)arg;
 
-		if(ioctl(priv->tunerfd, TVTUNER_SETFREQ, &priv->tunerfreq) < 0) 
-			{
-			perror("SETFREQ:ioctl");
-			return(0);
-			}
+        if(ioctl(priv->tunerfd, TVTUNER_SETFREQ, &priv->tunerfreq) < 0) 
+            {
+            perror("SETFREQ:ioctl");
+            return(0);
+            }
 
-		return(TVI_CONTROL_TRUE);		
-		}
+        return(TVI_CONTROL_TRUE);        
+        }
 
-	case TVI_CONTROL_TUN_GET_TUNER:
-	case TVI_CONTROL_TUN_SET_TUNER:
+    case TVI_CONTROL_TUN_GET_TUNER:
+    case TVI_CONTROL_TUN_SET_TUNER:
 
 /* Inputs */
 
     case TVI_CONTROL_SPC_GET_INPUT:
-		{
-		if(ioctl(priv->btfd, METEORGINPUT, &priv->input) < 0)
-			{
-			perror("GINPUT:ioctl");
-			return(TVI_CONTROL_FALSE);
-			}
+        {
+        if(ioctl(priv->btfd, METEORGINPUT, &priv->input) < 0)
+            {
+            perror("GINPUT:ioctl");
+            return(TVI_CONTROL_FALSE);
+            }
 
-		(int)*(void **)arg = priv->input;
-		return(TVI_CONTROL_TRUE);
-		}
-	
+        (int)*(void **)arg = priv->input;
+        return(TVI_CONTROL_TRUE);
+        }
+    
     case TVI_CONTROL_SPC_SET_INPUT:
-		{
-		priv->input = getinput((int)*(void **)arg);
+        {
+        priv->input = getinput((int)*(void **)arg);
 
-		if(ioctl(priv->btfd, METEORSINPUT, &priv->input) < 0) 
-			{
-			perror("tunerfreq:ioctl");
-			return(0);
-			}
+        if(ioctl(priv->btfd, METEORSINPUT, &priv->input) < 0) 
+            {
+            perror("tunerfreq:ioctl");
+            return(0);
+            }
 
-		return(TVI_CONTROL_TRUE);		
-		}
+        return(TVI_CONTROL_TRUE);        
+        }
 
 /* Audio Controls */
 
-	case TVI_CONTROL_IS_AUDIO:
-		if(priv->dspready == FALSE) return TVI_CONTROL_FALSE;
-		return(TVI_CONTROL_TRUE);
+    case TVI_CONTROL_IS_AUDIO:
+        if(priv->dspready == FALSE) return TVI_CONTROL_FALSE;
+        return(TVI_CONTROL_TRUE);
+
+    case TVI_CONTROL_AUD_GET_FORMAT:
+        {
+        (int)*(void **)arg = AFMT_S16_LE;
+        return(TVI_CONTROL_TRUE);
+        }
+    case TVI_CONTROL_AUD_GET_CHANNELS:
+        {
+        (int)*(void **)arg = 2;
+        return(TVI_CONTROL_TRUE);
+        }
+    case TVI_CONTROL_AUD_SET_SAMPLERATE:
+        {
+        int dspspeed = (int)*(void **)arg;
 
-	case TVI_CONTROL_AUD_GET_FORMAT:
-		{
-		(int)*(void **)arg = AFMT_S16_LE;
-		return(TVI_CONTROL_TRUE);
-		}
-	case TVI_CONTROL_AUD_GET_CHANNELS:
-		{
-		(int)*(void **)arg = 2;
-		return(TVI_CONTROL_TRUE);
-		}
-	case TVI_CONTROL_AUD_GET_SAMPLERATE:
-		{
-		(int)*(void **)arg = 44100;
-		return(TVI_CONTROL_TRUE);
-		}
-	case TVI_CONTROL_AUD_GET_SAMPLESIZE:
-		{
-		(int)*(void **)arg = priv->dspsamplesize;
-		return(TVI_CONTROL_TRUE);
-		}
+           if(ioctl(priv->dspfd, SNDCTL_DSP_SPEED, &dspspeed) == -1) 
+            {
+            perror("invalidaudiorate");
+            return(TVI_CONTROL_FALSE);
+            }
+
+        priv->dspspeed = dspspeed;
+
+        priv->dspframesize = priv->dspspeed*priv->dspsamplesize/8/
+                                priv->fps * (priv->dspstereo+1);
+        priv->dsprate = priv->dspspeed * priv->dspsamplesize/8*
+                                (priv->dspstereo+1);
+
+        return(TVI_CONTROL_TRUE);
+        }
+    case TVI_CONTROL_AUD_GET_SAMPLERATE:
+        {
+        (int)*(void **)arg = priv->dspspeed;
+        return(TVI_CONTROL_TRUE);
+        }
+    case TVI_CONTROL_AUD_GET_SAMPLESIZE:
+        {
+        (int)*(void **)arg = priv->dspsamplesize/8;
+        return(TVI_CONTROL_TRUE);
+        }
 
 /* Video Controls */
 
-	case TVI_CONTROL_IS_VIDEO:
-		if(priv->videoready == FALSE) return TVI_CONTROL_FALSE;
-		return(TVI_CONTROL_TRUE);
+    case TVI_CONTROL_IS_VIDEO:
+        if(priv->videoready == FALSE) return TVI_CONTROL_FALSE;
+        return(TVI_CONTROL_TRUE);
 
-	case TVI_CONTROL_TUN_SET_NORM:
-		{
-		int req_mode = (int)*(void **)arg;
+    case TVI_CONTROL_TUN_SET_NORM:
+        {
+        int req_mode = (int)*(void **)arg;
 
-		priv->iformat = METEOR_FMT_AUTOMODE;
+        priv->iformat = METEOR_FMT_AUTOMODE;
 
-		if(req_mode == TV_NORM_PAL) 
-			{
-			priv->iformat = METEOR_FMT_PAL;
-			priv->maxheight = PAL_HEIGHT;
-			priv->maxwidth = PAL_WIDTH;
-			priv->maxfps = PAL_FPS;
-			priv->fps = PAL_FPS;
-
-			if(priv->fps > priv->maxfps) priv->fps = priv->maxfps;
+        if(req_mode == TV_NORM_PAL) 
+            {
+            priv->iformat = METEOR_FMT_PAL;
+            priv->maxheight = PAL_HEIGHT;
+            priv->maxwidth = PAL_WIDTH;
+            priv->maxfps = PAL_FPS;
+            priv->fps = PAL_FPS;
 
-			if(priv->geom.rows > priv->maxheight) 
-				{
-				priv->geom.rows = priv->maxheight;
-				}
+            if(priv->fps > priv->maxfps) priv->fps = priv->maxfps;
 
-			if(priv->geom.columns > priv->maxwidth) 
-				{
-				priv->geom.columns = priv->maxwidth;
-				}
-			}
+            if(priv->geom.rows > priv->maxheight) 
+                {
+                priv->geom.rows = priv->maxheight;
+                }
 
-		if(req_mode == TV_NORM_NTSC) 
-			{
-			priv->iformat = METEOR_FMT_NTSC;
-			priv->maxheight = NTSC_HEIGHT;
-			priv->maxwidth = NTSC_WIDTH;
-			priv->maxfps = NTSC_FPS;
-			priv->fps = NTSC_FPS;
+            if(priv->geom.columns > priv->maxwidth) 
+                {
+                priv->geom.columns = priv->maxwidth;
+                }
+            }
 
-			priv->dspframesize = priv->dspspeed*priv->dspsamplesize/8/
-								 priv->fps * (priv->dspstereo+1);
-
-			if(priv->fps > priv->maxfps) priv->fps = priv->maxfps;
-
-			if(priv->geom.rows > priv->maxheight) 
-				{
-				priv->geom.rows = priv->maxheight;
-				}
+        if(req_mode == TV_NORM_NTSC) 
+            {
+            priv->iformat = METEOR_FMT_NTSC;
+            priv->maxheight = NTSC_HEIGHT;
+            priv->maxwidth = NTSC_WIDTH;
+            priv->maxfps = NTSC_FPS;
+            priv->fps = NTSC_FPS;
 
-			if(priv->geom.columns > priv->maxwidth) 
-				{
-				priv->geom.columns = priv->maxwidth;
-				}
-			}
+            priv->dspframesize = priv->dspspeed*priv->dspsamplesize/8/
+                                 priv->fps * (priv->dspstereo+1);
+            priv->dsprate = priv->dspspeed * priv->dspsamplesize/8 *
+                                (priv->dspstereo+1);
 
-		if(req_mode == TV_NORM_SECAM) priv->iformat = METEOR_FMT_SECAM;
+            if(priv->fps > priv->maxfps) priv->fps = priv->maxfps;
 
-		if(ioctl(priv->btfd, METEORSFMT, &priv->iformat) < 0) 
-			{
-			perror("format:ioctl");
-			return(TVI_CONTROL_FALSE);
-			}
-	
-		if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) 
-			{
-			perror("geo:ioctl");
-			return(0);
-			}
+            if(priv->geom.rows > priv->maxheight) 
+                {
+                priv->geom.rows = priv->maxheight;
+                }
+
+            if(priv->geom.columns > priv->maxwidth) 
+                {
+                priv->geom.columns = priv->maxwidth;
+                }
+            }
+
+        if(req_mode == TV_NORM_SECAM) priv->iformat = METEOR_FMT_SECAM;
 
-		if(ioctl(priv->btfd, METEORSFPS, &priv->fps) < 0) 
-			{
-			perror("fps:ioctl");
-			return(0);
-			}
+        if(ioctl(priv->btfd, METEORSFMT, &priv->iformat) < 0) 
+            {
+            perror("format:ioctl");
+            return(TVI_CONTROL_FALSE);
+            }
+    
+        if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) 
+            {
+            perror("geo:ioctl");
+            return(0);
+            }
 
-		return(TVI_CONTROL_TRUE);
-		}
-	
-	case TVI_CONTROL_VID_GET_FORMAT:
-		(int)*(void **)arg = IMGFMT_UYVY;
-		return(TVI_CONTROL_TRUE);
-
-	case TVI_CONTROL_VID_SET_FORMAT:
-		{
-		int req_fmt = (int)*(void **)arg;
+        if(ioctl(priv->btfd, METEORSFPS, &priv->fps) < 0) 
+            {
+            perror("fps:ioctl");
+            return(0);
+            }
 
-		if(req_fmt != IMGFMT_UYVY) return(TVI_CONTROL_FALSE);
+        return(TVI_CONTROL_TRUE);
+        }
+    
+    case TVI_CONTROL_VID_GET_FORMAT:
+        (int)*(void **)arg = IMGFMT_UYVY;
+        return(TVI_CONTROL_TRUE);
 
-		return(TVI_CONTROL_TRUE);
-		}
-	case TVI_CONTROL_VID_SET_WIDTH:
-		priv->geom.columns = (int)*(void **)arg;
+    case TVI_CONTROL_VID_SET_FORMAT:
+        {
+        int req_fmt = (int)*(void **)arg;
 
-		if(priv->geom.columns > priv->maxwidth) 
-			{
-			priv->geom.columns = priv->maxwidth;
-			}
+        if(req_fmt != IMGFMT_UYVY) return(TVI_CONTROL_FALSE);
 
-		if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) 
-			{
-			perror("width:ioctl");
-			return(0);
-			}
+        return(TVI_CONTROL_TRUE);
+        }
+    case TVI_CONTROL_VID_SET_WIDTH:
+        priv->geom.columns = (int)*(void **)arg;
+
+        if(priv->geom.columns > priv->maxwidth) 
+            {
+            priv->geom.columns = priv->maxwidth;
+            }
 
-		return(TVI_CONTROL_TRUE);
+        if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) 
+            {
+            perror("width:ioctl");
+            return(0);
+            }
 
-	case TVI_CONTROL_VID_GET_WIDTH:
-		(int)*(void **)arg = priv->geom.columns;
-		return(TVI_CONTROL_TRUE);
+        return(TVI_CONTROL_TRUE);
 
-	case TVI_CONTROL_VID_SET_HEIGHT:
-		priv->geom.rows = (int)*(void **)arg;
+    case TVI_CONTROL_VID_GET_WIDTH:
+        (int)*(void **)arg = priv->geom.columns;
+        return(TVI_CONTROL_TRUE);
 
-		if(priv->geom.rows > priv->maxheight) 
-			{
-			priv->geom.rows = priv->maxheight;
-			}
+    case TVI_CONTROL_VID_SET_HEIGHT:
+        priv->geom.rows = (int)*(void **)arg;
+
+        if(priv->geom.rows > priv->maxheight) 
+            {
+            priv->geom.rows = priv->maxheight;
+            }
 
-		if(priv->geom.rows <= priv->maxheight / 2)
-			{
-			priv->geom.oformat |= METEOR_GEO_EVEN_ONLY;
-			}  
+        if(priv->geom.rows <= priv->maxheight / 2)
+            {
+            priv->geom.oformat |= METEOR_GEO_EVEN_ONLY;
+            }  
 
-		if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) 
-			{
-			perror("height:ioctl");
-			return(0);
-			}
+        if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) 
+            {
+            perror("height:ioctl");
+            return(0);
+            }
 
-		return(TVI_CONTROL_TRUE);		
+        return(TVI_CONTROL_TRUE);        
 
-	case TVI_CONTROL_VID_GET_HEIGHT:
-		(int)*(void **)arg = priv->geom.rows;
-		return(TVI_CONTROL_TRUE);		
+    case TVI_CONTROL_VID_GET_HEIGHT:
+        (int)*(void **)arg = priv->geom.rows;
+        return(TVI_CONTROL_TRUE);        
 
-	case TVI_CONTROL_VID_GET_FPS:
-		(int)*(void **)arg = (int)priv->fps;
-		return(TVI_CONTROL_TRUE);		
+    case TVI_CONTROL_VID_GET_FPS:
+        (int)*(void **)arg = (int)priv->fps;
+        return(TVI_CONTROL_TRUE);        
 
 /*
-	case TVI_CONTROL_VID_SET_FPS:
-		priv->fps = (int)*(void **)arg;
+    case TVI_CONTROL_VID_SET_FPS:
+        priv->fps = (int)*(void **)arg;
 
-		if(priv->fps > priv->maxfps) priv->fps = priv->maxfps;
+        if(priv->fps > priv->maxfps) priv->fps = priv->maxfps;
 
-		if(ioctl(priv->btfd, METEORSFPS, &priv->fps) < 0) 
-			{
-			perror("fps:ioctl");
-			return(0);
-			}
+        if(ioctl(priv->btfd, METEORSFPS, &priv->fps) < 0) 
+            {
+            perror("fps:ioctl");
+            return(0);
+            }
 
-		return(TVI_CONTROL_TRUE);		
+        return(TVI_CONTROL_TRUE);        
 */
 
-	case TVI_CONTROL_VID_CHK_WIDTH:
-	case TVI_CONTROL_VID_CHK_HEIGHT:
-		return(TVI_CONTROL_TRUE);
+    case TVI_CONTROL_VID_CHK_WIDTH:
+    case TVI_CONTROL_VID_CHK_HEIGHT:
+        return(TVI_CONTROL_TRUE);
 
-	}
-	return(TVI_CONTROL_UNKNOWN);
+    case TVI_CONTROL_IMMEDIATE:
+        priv->immediatemode = TRUE;
+        return(TVI_CONTROL_TRUE);
+    }
+
+    return(TVI_CONTROL_UNKNOWN);
 }
 
 static int init(priv_t *priv)
 {
 int marg;
+int count;
 
 G_private = priv; /* Oooh, sick */
 
@@ -379,6 +452,7 @@
 
 priv->videoready = TRUE;
 priv->btdev = strdup("/dev/bktr0");
+priv->immediatemode = FALSE;
 priv->iformat = METEOR_FMT_PAL;
 priv->maxheight = PAL_HEIGHT;
 priv->maxwidth = PAL_WIDTH;
@@ -386,7 +460,9 @@
 priv->source = METEOR_INPUT_DEV0;
 priv->fps = priv->maxfps;
 
-priv->currentframe=0;
+priv->starttime=0;
+priv->curpaintframe=0;
+priv->curbufframe=0;
 
 priv->geom.columns = priv->maxwidth;
 priv->geom.rows = priv->maxheight;
@@ -396,49 +472,63 @@
 priv->btfd = open(priv->btdev, O_RDONLY);
 
 if(priv->btfd < 0)
-	{
-	perror("bktr open");
-	priv->videoready = FALSE;
-	}
+    {
+    perror("bktr open");
+    priv->videoready = FALSE;
+    }
 
 if(priv->videoready == TRUE && 
    ioctl(priv->btfd, METEORSFMT, &priv->iformat) < 0) 
-	{
-	perror("FMT:ioctl");
-	}
+    {
+    perror("FMT:ioctl");
+    }
 
 if(priv->videoready == TRUE &&
    ioctl(priv->btfd, METEORSINPUT, &priv->source) < 0) 
-	{
-	perror("SINPUT:ioctl");
-	}
+    {
+    perror("SINPUT:ioctl");
+    }
 
 if(priv->videoready == TRUE &&
    ioctl(priv->btfd, METEORSFPS, &priv->fps) < 0) 
-	{
-	perror("SFPS:ioctl");
-	}
+    {
+    perror("SFPS:ioctl");
+    }
 
 if(priv->videoready == TRUE &&
    ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) 
-	{
-	perror("SGEO:ioctl");
-	}
+    {
+    perror("SGEO:ioctl");
+    }
 
 if(priv->videoready == TRUE)
-	{
-	priv->buffersize = (priv->geom.columns * priv->geom.rows * 2);
+    {
+    priv->framebufsize = (priv->geom.columns * priv->geom.rows * 2);
+
+    priv->livebuf = (u_char *)mmap((caddr_t)0, priv->framebufsize, PROT_READ,
+                                MAP_SHARED, priv->btfd, (off_t)0);
 
-	priv->buffer = (u_char *)mmap((caddr_t)0, priv->buffersize, PROT_READ,
-							MAP_SHARED, priv->btfd, (off_t)0);
+    if(priv->livebuf == (u_char *) MAP_FAILED)
+        {
+        perror("mmap");
+        priv->videoready = FALSE;
+        }
 
-	if(priv->buffer == (u_char *) MAP_FAILED)
-		{
-		perror("mmap");
-		priv->videoready = FALSE;
-		}
+    for(count=0;count<RINGSIZE;count++)
+        {
+        priv->framebuf[count].buf = malloc(priv->framebufsize);
 
-	}
+        if(priv->framebuf[count].buf == NULL)
+            {
+            perror("framebufmalloc");
+            priv->videoready = FALSE;
+            break;
+            }
+
+        priv->framebuf[count].dirty = TRUE;
+        priv->framebuf[count].timestamp = 0;
+        }
+    }
 
 /* Tuner Configuration */
 
@@ -448,10 +538,10 @@
 priv->tunerfd = open(priv->tunerdev, O_RDONLY);
 
 if(priv->tunerfd < 0)
-	{
-	perror("tune open");
-	priv->tunerready = FALSE;
-	}
+    {
+    perror("tune open");
+    priv->tunerready = FALSE;
+    }
 
 /* Audio Configuration */
 
@@ -461,33 +551,35 @@
 priv->dspstereo = 1;
 priv->dspspeed = 44100;
 priv->dspfmt = AFMT_S16_LE;
+priv->dspbytesread = 0;
+priv->dsprate = priv->dspspeed * priv->dspsamplesize/8*(priv->dspstereo+1);
 priv->dspframesize = priv->dspspeed*priv->dspsamplesize/8/priv->fps * 
-					 (priv->dspstereo+1);
+                     (priv->dspstereo+1);
 
-if((priv->dspfd = open ("/dev/dsp", O_RDWR, 0)) < 0)
-	{
-	perror("/dev/dsp open");
-	priv->dspready = FALSE;
-	} 
+if((priv->dspfd = open ("/dev/dsp", O_RDONLY, 0)) < 0)
+    {
+    perror("/dev/dsp open");
+    priv->dspready = FALSE;
+    } 
 
-marg = (256 << 16) | 13;
+marg = (256 << 16) | 12;
 
 if (ioctl(priv->dspfd, SNDCTL_DSP_SETFRAGMENT, &marg ) < 0 ) 
-	{
-	perror("setfrag");
-	priv->dspready = FALSE;
-	}
+    {
+    perror("setfrag");
+    priv->dspready = FALSE;
+    }
 
 if((priv->dspready == TRUE) &&
-   (ioctl(priv->dspfd, SNDCTL_DSP_SAMPLESIZE, &priv->dspsamplesize) == -1) ||
+   ((ioctl(priv->dspfd, SNDCTL_DSP_SAMPLESIZE, &priv->dspsamplesize) == -1) ||
    (ioctl(priv->dspfd, SNDCTL_DSP_STEREO, &priv->dspstereo) == -1) ||
    (ioctl(priv->dspfd, SNDCTL_DSP_SPEED, &priv->dspspeed) == -1) ||
-   (ioctl(priv->dspfd, SNDCTL_DSP_SETFMT, &priv->dspfmt) == -1))
-	{
-	perror ("configuration of /dev/dsp failed");
-	close(priv->dspfd);
-	priv->dspready = FALSE;
-	}
+   (ioctl(priv->dspfd, SNDCTL_DSP_SETFMT, &priv->dspfmt) == -1)))
+    {
+    perror ("configuration of /dev/dsp failed");
+    close(priv->dspfd);
+    priv->dspready = FALSE;
+    }
 
 return(1);
 }
@@ -495,8 +587,11 @@
 /* that's the real start, we'got the format parameters (checked with control) */
 static int start(priv_t *priv)
 {
+int tmp;
+struct timeval curtime;
 int marg;
 
+fprintf(stderr,"START\n");
 if(priv->videoready == FALSE) return(0);
 
 signal(SIGUSR1, processframe);
@@ -505,18 +600,24 @@
 marg = SIGUSR1;
 
 if(ioctl(priv->btfd, METEORSSIGNAL, &marg) < 0) 
-	{
-	perror("METEORSSIGNAL failed");
-	return(0);
-	}
+    {
+    perror("METEORSSIGNAL failed");
+    return(0);
+    }
+
+read(priv->dspfd, &tmp, 2);
+
+gettimeofday(&curtime, NULL);
+
+priv->starttime = curtime.tv_sec + (curtime.tv_usec *.000001);
 
 marg = METEOR_CAP_CONTINOUS;
 
 if(ioctl(priv->btfd, METEORCAPTUR, &marg) < 0) 
-	{
-	perror("METEORCAPTUR failed");
-	return(0);
-	}
+    {
+    perror("METEORCAPTUR failed");
+    return(0);
+    }
 
 return(1);
 }
@@ -530,18 +631,18 @@
 marg = METEOR_SIG_MODE_MASK;
 
 if(ioctl( priv->btfd, METEORSSIGNAL, &marg) < 0 ) 
-	{
-	perror("METEORSSIGNAL");
-	return(0);
-	}
+    {
+    perror("METEORSSIGNAL");
+    return(0);
+    }
 
 marg = METEOR_CAP_STOP_CONT;
 
 if(ioctl(priv->btfd, METEORCAPTUR, &marg) < 0 ) 
-	{
-	perror("METEORCAPTUR STOP");
-	return(0);
-	}
+    {
+    perror("METEORCAPTUR STOP");
+    return(0);
+    }
 
 close(priv->btfd);
 close(priv->dspfd);
@@ -555,8 +656,9 @@
 }
 
 
-static int grab_video_frame(priv_t *priv, char *buffer, int len)
+static double grabimmediate_video_frame(priv_t *priv, char *buffer, int len)
 {
+struct timeval curtime;
 sigset_t sa_mask;
 
 if(priv->videoready == FALSE) return(0);
@@ -569,9 +671,43 @@
 sigsuspend(&sa_mask);
 alarm(0);
 
-memcpy(buffer, priv->buffer, len);
+memcpy(buffer, priv->livebuf, len);
+
+/* PTS = 0, show the frame NOW, this routine is only used in playback mode
+    without audio capture .. */
+
+return(0); 
+}
+
+static double grab_video_frame(priv_t *priv, char *buffer, int len)
+{
+struct timeval curtime;
+double timestamp=0;
+sigset_t sa_mask;
+
+if(priv->videoready == FALSE) return(0);
 
-return(priv->currentframe);
+if(priv->immediatemode == TRUE) 
+    {
+    return grabimmediate_video_frame(priv, buffer, len);
+    }
+
+while(priv->framebuf[priv->curbufframe].dirty == TRUE)
+    {
+    alarm(1);
+    sigemptyset(&sa_mask);
+    sigsuspend(&sa_mask);
+    alarm(0);
+    }
+
+memcpy(buffer, priv->framebuf[priv->curbufframe].buf, len);
+timestamp = priv->framebuf[priv->curbufframe].timestamp;
+priv->framebuf[priv->curbufframe].dirty = TRUE;
+
+priv->curbufframe++;
+if(priv->curbufframe >= RINGSIZE) priv->curbufframe = 0;
+
+return(timestamp-priv->starttime);
 }
 
 static int get_video_framesize(priv_t *priv)
@@ -579,58 +715,88 @@
 return(priv->geom.columns*priv->geom.rows*16/8);
 }
 
-static int grab_audio_frame(priv_t *priv, char *buffer, int len)
+static double grab_audio_frame(priv_t *priv, char *buffer, int len)
 {
-struct audio_buf_info abi;
+struct timeval curtime;
+double curpts;
+double timeskew;
+int bytesavail;
 int bytesread;
 int ret;
 
 if(priv->dspready == FALSE) return 0;
 
+gettimeofday(&curtime, NULL);
+
 /* Get exactly one frame of audio, which forces video sync to audio.. */
 
 bytesread=read(priv->dspfd, buffer, len); 
 
 while(bytesread < len)
-	{
-	ret=read(priv->dspfd, &buffer[bytesread], len-bytesread);
+    {
+    ret=read(priv->dspfd, &buffer[bytesread], len-bytesread);
 
-	if(ret == -1)
-		{
-		perror("Audio read failed!");
-		return 0;
-		}
+    if(ret == -1)
+        {
+        perror("Audio read failed!");
+        return 0;
+        }
+
+    bytesread+=ret;
+    }
+
+priv->dspbytesread += bytesread;
+
+curpts = curtime.tv_sec + curtime.tv_usec * .000001;
 
-	bytesread+=ret;
-	}
+timeskew = priv->dspbytesread * 1.0 / priv->dsprate - (curpts-priv->starttime);
 
-if(ioctl(priv->dspfd, SNDCTL_DSP_GETISPACE, &abi) < 0) 
-	{
-	perror("abi:ioctl");
-	return(TVI_CONTROL_FALSE);
-	}
+if(timeskew > .125/priv->fps) 
+    {
+    priv->starttime -= timeskew;
+    }
+else
+    {
+    if(timeskew < -.125/priv->fps) 
+        {
+        priv->starttime -= timeskew;
+        }
+    }
 
-return(abi.bytes/len);
+return(priv->dspbytesread * 1.0 / priv->dsprate);
 }
 
 static int get_audio_framesize(priv_t *priv)
 {
+int bytesavail;
+
 if(priv->dspready == FALSE) return 0;
 
-return(priv->dspframesize);
+if(ioctl(priv->dspfd, FIONREAD, &bytesavail) < 0) 
+    {
+    perror("FIONREAD");
+    return(TVI_CONTROL_FALSE);
+    }
+
+/* When mencoder wants audio data, it wants data..
+   it wont go do anything else until it gets it :( */
+
+if(bytesavail == 0) return FRAGSIZE;
+
+return(bytesavail);
 }
 
 static int getinput(int innumber)
 {
 switch(innumber)
-	{
-	case 0: return METEOR_INPUT_DEV0; 	/* RCA   */
-	case 1: return METEOR_INPUT_DEV1; 	/* Tuner */
-	case 2: return METEOR_INPUT_DEV2; 	/* In 1  */
-	case 3: return METEOR_INPUT_DEV3; 	/* In 2  */
-	case 4: return METEOR_INPUT_DEV_RGB; 	/* RGB   */
-	case 5: return METEOR_INPUT_DEV_SVIDEO; /* SVid  */
-	}
+    {
+    case 0: return METEOR_INPUT_DEV0;     /* RCA   */
+    case 1: return METEOR_INPUT_DEV1;     /* Tuner */
+    case 2: return METEOR_INPUT_DEV2;     /* In 1  */
+    case 3: return METEOR_INPUT_DEV3;     /* In 2  */
+    case 4: return METEOR_INPUT_DEV_RGB;     /* RGB   */
+    case 5: return METEOR_INPUT_DEV_SVIDEO; /* SVid  */
+    }
 
 return 0;
 }
--- a/libmpdemux/tvi_def.h	Fri Apr 12 10:17:24 2002 +0000
+++ b/libmpdemux/tvi_def.h	Fri Apr 12 10:40:38 2002 +0000
@@ -4,9 +4,12 @@
 static int uninit(priv_t *priv);
 static int control(priv_t *priv, int cmd, void *arg);
 static int start(priv_t *priv);
-static int grab_video_frame(priv_t *priv, char *buffer, int len);
+static double grab_video_frame(priv_t *priv, char *buffer, int len);
+#ifdef HAVE_TV_BSDBT848
+static double grabimmediate_video_frame(priv_t *priv, char *buffer, int len);
+#endif
 static int get_video_framesize(priv_t *priv);
-static int grab_audio_frame(priv_t *priv, char *buffer, int len);
+static double grab_audio_frame(priv_t *priv, char *buffer, int len);
 static int get_audio_framesize(priv_t *priv);
 
 static tvi_functions_t functions =
@@ -16,6 +19,9 @@
     control,
     start,
     grab_video_frame,
+#ifdef HAVE_TV_BSDBT848
+    grabimmediate_video_frame,
+#endif
     get_video_framesize,
     grab_audio_frame,
     get_audio_framesize
--- a/libmpdemux/tvi_dummy.c	Fri Apr 12 10:17:24 2002 +0000
+++ b/libmpdemux/tvi_dummy.c	Fri Apr 12 10:40:38 2002 +0000
@@ -86,7 +86,15 @@
     return(TVI_CONTROL_UNKNOWN);
 }
 
-static int grab_video_frame(priv_t *priv, char *buffer, int len)
+#ifdef HAVE_TV_BSDBT848
+static double grabimmediate_video_frame(priv_t *priv, char *buffer, int len)
+{
+    memset(buffer, 0xCC, len);
+    return(1);
+}
+#endif
+
+static double grab_video_frame(priv_t *priv, char *buffer, int len)
 {
     memset(buffer, 0x42, len);
     return(1);
@@ -98,7 +106,7 @@
     return(priv->width*priv->height*12/8);
 }
 
-static int grab_audio_frame(priv_t *priv, char *buffer, int len)
+static double grab_audio_frame(priv_t *priv, char *buffer, int len)
 {
     memset(buffer, 0x42, len);
     return(1);
--- a/libmpdemux/tvi_v4l.c	Fri Apr 12 10:17:24 2002 +0000
+++ b/libmpdemux/tvi_v4l.c	Fri Apr 12 10:40:38 2002 +0000
@@ -63,7 +63,6 @@
     struct video_mmap		*buf;
     int				nbuf;
     int				queue;
-	int				currentframe;
 
     /* audio */
     int				audio_id;
@@ -807,13 +806,11 @@
     return(TVI_CONTROL_UNKNOWN);
 }
 
-static int grab_video_frame(priv_t *priv, char *buffer, int len)
+static double grab_video_frame(priv_t *priv, char *buffer, int len)
 {
     int frame = priv->queue % priv->nbuf;
     int nextframe = (priv->queue+1) % priv->nbuf;
 
-	priv->currentframe++;
-
     mp_dbg(MSGT_TV, MSGL_DBG2, "grab_video_frame(priv=%p, buffer=%p, len=%d)\n",
 	priv, buffer, len);
 
@@ -841,7 +838,7 @@
     /* copy the actual frame */
     memcpy(buffer, priv->mmap+priv->mbuf.offsets[frame], len);
 
-    return(priv->currentframe);
+    return(0);
 }
 
 static int get_video_framesize(priv_t *priv)
@@ -849,7 +846,7 @@
     return(priv->bytesperline * priv->height);
 }
 
-static int grab_audio_frame(priv_t *priv, char *buffer, int len)
+static double grab_audio_frame(priv_t *priv, char *buffer, int len)
 {
     int in_len = 0;
 //    int max_tries = 128;
@@ -874,7 +871,7 @@
     }
 //    printf("tries: %d\n", 128-max_tries);
 
-    return(in_len);
+    return 0; //(in_len); // FIXME!
 }
 
 static int get_audio_framesize(priv_t *priv)
--- a/libmpdemux/video.c	Fri Apr 12 10:17:24 2002 +0000
+++ b/libmpdemux/video.c	Fri Apr 12 10:40:38 2002 +0000
@@ -291,6 +291,10 @@
           sh_video->fps=1.0f/d;
         }
     } else
+    if(demuxer->file_format==DEMUXER_TYPE_TV && !force_fps){
+        // TV has variable video frame rate, fixed audio...
+	frame_time=d_video->pts-pts1;
+	} else
     if(demuxer->file_format==DEMUXER_TYPE_MOV && !force_fps){
         // .MOV files has no fixed FPS - just frame durations!
 	frame_time=d_video->pts-pts1;
--- a/mencoder.c	Fri Apr 12 10:17:24 2002 +0000
+++ b/mencoder.c	Fri Apr 12 10:40:38 2002 +0000
@@ -15,6 +15,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <signal.h>
+#include <sys/time.h>
 
 #include "config.h"
 #include "mp_msg.h"
@@ -212,6 +213,7 @@
   }
 }
 
+
 //---------------------------------------------------------------------------
 
 void *vo_spudec=NULL;
@@ -278,9 +280,17 @@
 int file_format=DEMUXER_TYPE_UNKNOWN;
 int i;
 
+uint32_t ptimer_start;
+uint32_t audiorate=0;
+uint32_t videorate=0;
+uint32_t audiosamples=1;
+uint32_t videosamples=1;
+uint32_t skippedframes=0;
+uint32_t duplicatedframes=0;
+
 aviwrite_stream_t* mux_a=NULL;
 aviwrite_stream_t* mux_v=NULL;
-int muxer_f_size=0;
+off_t muxer_f_size=0;
 
 #ifdef HAVE_MP3LAME
 lame_global_flags *lame;
@@ -714,6 +724,13 @@
     demux_seek(demuxer, d, 1);
 }
 
+if(tv_param_on == 1) 
+	{
+	fprintf(stderr,"Forcing audio preload to 0, max pts correction to 0\n");
+	audio_preload = 0.0;
+	default_max_pts_correction = 0;
+	}
+
 while(!eof){
 
     float frame_time=0;
@@ -724,7 +741,7 @@
     int in_size;
     int skip_flag=0; // 1=skip  -1=duplicate
 
-    if((end_at_type == END_AT_SIZE && end_at <= ftell(muxer_f))  ||
+    if((end_at_type == END_AT_SIZE && end_at <= ftello(muxer_f))  ||
        (end_at_type == END_AT_TIME && end_at < sh_video->timer))
         break;
 
@@ -737,6 +754,9 @@
     // get audio:
     while(mux_a->timer-audio_preload<mux_v->timer){
 	int len=0;
+
+	ptimer_start = GetTimerMS();
+
 	if(mux_a->h.dwSampleSize){
 	    // CBR - copy 0.5 sec of audio
 	    switch(mux_a->codec){
@@ -796,14 +816,19 @@
 	    mux_a->buffer_len-=len;
 	    memcpy(mux_a->buffer,mux_a->buffer+len,mux_a->buffer_len);
 	}
+
+
+	audiosamples++;
+	audiorate+= (GetTimerMS() - ptimer_start);
     }
 }
 
     // get video frame!
+
     in_size=video_read_frame(sh_video,&frame_time,&start,force_fps);
     if(in_size<0){ eof=1; break; }
     sh_video->timer+=frame_time; ++decoded_frameno;
-    
+
     v_timer_corr-=frame_time-(float)mux_v->h.dwScale/mux_v->h.dwRate;
 
 if(demuxer2){	// 3-pass encoding, read control file (frameno.avi)
@@ -816,7 +841,7 @@
 	    if(len==4) next_frameno=start[0];
 	}
     if(eof) break;
-	if(skip_flag) printf("!!!!!!!!!!!!\n");
+	// if(skip_flag) printf("!!!!!!!!!!!!\n");
 	skip_flag=next_frameno-decoded_frameno;
     // find next frame:
 	while(next_frameno<=decoded_frameno){
@@ -868,6 +893,8 @@
  }
 #endif
 
+ptimer_start = GetTimerMS();
+
 switch(mux_v->codec){
 case VCODEC_COPY:
     mux_v->buffer=start;
@@ -884,17 +911,22 @@
     if(!blit_frame) aviwrite_write_chunk(muxer,mux_v,muxer_f,0,0); // empty.
 }
 
+videosamples++;
+videorate+=(GetTimerMS() - ptimer_start);
+
 if(skip_flag<0){
     // duplicate frame
-    printf("\nduplicate %d frame(s)!!!    \n",-skip_flag);
+	if(!tv_param_on && !verbose) printf("\nduplicate %d frame(s)!!!    \n",-skip_flag);
     while(skip_flag<0){
+	duplicatedframes++;
 	aviwrite_write_chunk(muxer,mux_v,muxer_f,0,0);
 	++skip_flag;
     }
 } else
 if(skip_flag>0){
     // skip frame
-    printf("\nskip frame!!!    \n");
+	if(!tv_param_on && !verbose) printf("\nskip frame!!!    \n");
+	skippedframes++;
     --skip_flag;
 }
 
@@ -961,6 +993,19 @@
 	    (int)demuxer->filepos,
 	    (int)demuxer->movi_end);
 #else
+	if(verbose) {
+		mp_msg(MSGT_AVSYNC,MSGL_STATUS,"Pos:%6.1fs %6df (%2d%%) %3dfps Trem:%4dmin %3dmb  A-V:%5.3f [%d:%d] A/Vms %d/%d D/S %d/%d \r",
+	    	mux_v->timer, decoded_frameno, (int)(p*100),
+	    	(t>1) ? (int)(decoded_frameno/t) : 0,
+	    	(p>0.001) ? (int)((t/p-t)/60) : 0, 
+	    	(p>0.001) ? (int)(ftello(muxer_f)/p/1024/1024) : 0,
+	    	v_pts_corr,
+	    	(mux_v->timer>1) ? (int)(mux_v->size/mux_v->timer/125) : 0,
+	    	(mux_a && mux_a->timer>1) ? (int)(mux_a->size/mux_a->timer/125) : 0,
+			audiorate/audiosamples, videorate/videosamples,
+			duplicatedframes, skippedframes
+		);
+	} else
 	mp_msg(MSGT_AVSYNC,MSGL_STATUS,"Pos:%6.1fs %6df (%2d%%) %3dfps Trem:%4dmin %3dmb  A-V:%5.3f [%d:%d]\r",
 	    mux_v->timer, decoded_frameno, (int)(p*100),
 	    (t>1) ? (int)(decoded_frameno/t) : 0,
@@ -972,7 +1017,6 @@
 	);
 #endif
     }
-
         fflush(stdout);
 
 
@@ -992,7 +1036,7 @@
 
 printf("\nWriting AVI index...\n");
 aviwrite_write_index(muxer,muxer_f);
-muxer_f_size=ftell(muxer_f);
+muxer_f_size=ftello(muxer_f);
 printf("Fixup AVI header...\n");
 fseek(muxer_f,0,SEEK_SET);
 aviwrite_write_header(muxer,muxer_f); // update header
@@ -1005,10 +1049,10 @@
 }
 
 printf("\nVideo stream: %8.3f kbit/s  (%d bps)  size: %d bytes  %5.3f secs  %d frames\n",
-    (float)(mux_v->size/mux_v->timer*8.0f/1000.0f), (int)(mux_v->size/mux_v->timer), mux_v->size, (float)mux_v->timer, decoded_frameno);
+    (float)(mux_v->size/mux_v->timer*8.0f/1000.0f), (int)(mux_v->size/mux_v->timer), (int)mux_v->size, (float)mux_v->timer, decoded_frameno);
 if(sh_audio)
 printf("\nAudio stream: %8.3f kbit/s  (%d bps)  size: %d bytes  %5.3f secs\n",
-    (float)(mux_a->size/mux_a->timer*8.0f/1000.0f), (int)(mux_a->size/mux_a->timer), mux_a->size, (float)mux_a->timer);
+    (float)(mux_a->size/mux_a->timer*8.0f/1000.0f), (int)(mux_a->size/mux_a->timer), (int)mux_a->size, (float)mux_a->timer);
 
 if(stream) free_stream(stream); // kill cache thread
 
--- a/mplayer.c	Fri Apr 12 10:17:24 2002 +0000
+++ b/mplayer.c	Fri Apr 12 10:40:38 2002 +0000
@@ -546,6 +546,10 @@
 
 #endif
 
+#ifdef HAVE_TV_BSDBT848
+  tv_param_immediate = 1;
+#endif
+
   if ( argv[0] )
     if(!strcmp(argv[0],"gmplayer") ||
       (strrchr(argv[0],'/') && !strcmp(strrchr(argv[0],'/'),"/gmplayer") ) )