changeset 5081:7473fca49ca0

initial
author alex
date Fri, 15 Mar 2002 14:59:32 +0000
parents f333b10ec34f
children 08a1abb25244
files libmpdemux/tvi_bsdbt848.c
diffstat 1 files changed, 634 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmpdemux/tvi_bsdbt848.c	Fri Mar 15 14:59:32 2002 +0000
@@ -0,0 +1,634 @@
+/*
+	(C)2002 Charles R. Henrich (henrich@msu.edu)
+	*BSD (hopefully, requires working driver!) BrookTree capture support.
+
+	Still in (active) development!
+
+	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 TRUE  (1==1)
+#define FALSE (1==0)
+
+#define PAL_WIDTH  768
+#define PAL_HEIGHT 576
+#define PAL_FPS	25
+
+#define NTSC_WIDTH  640
+#define NTSC_HEIGHT 480
+#define NTSC_FPS	30
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <string.h>
+
+#include <machine/ioctl_meteor.h>
+#include <machine/ioctl_bt848.h>
+#include <machine/soundcard.h>
+
+#include "../libvo/img_format.h"
+#include "tv.h"
+
+/* information about this file */
+static tvi_info_t info = {
+	"Brooktree848 Support",
+	"bt848",
+	"Charles Henrich",
+	"in development"
+};
+
+/* private data's */
+typedef struct {
+
+/* Audio */
+	char *dspdev;
+	int dspready;
+	int dspfd;
+	int dspsamplesize;
+	int dspstereo;
+	int dspspeed;
+	int dspfmt;
+	int dspframesize;
+
+/* 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;
+
+/* Inputs */
+
+	int input;
+
+/* Tuner */
+
+	char *tunerdev;
+	int tunerfd;
+	int tunerready;
+	u_long tunerfreq;
+	struct bktr_chnlset cset;
+
+} priv_t;
+
+#include "tvi_def.h"
+
+static priv_t *G_private=NULL;
+
+
+static void processframe(int signal)
+{
+G_private->currentframe++;
+
+return;
+}
+
+/* handler creator - entry point ! */
+tvi_handle_t *tvi_init_bsdbt848(char *device)
+{
+	return(new_handle());
+}
+
+static int control(priv_t *priv, int cmd, void *arg)
+{
+	switch(cmd)
+	{
+
+/* Tuner Controls */
+
+	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);
+			}
+
+		(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);
+			}
+
+		return(TVI_CONTROL_TRUE);		
+		}
+
+	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);
+			}
+
+		(int)*(void **)arg = priv->input;
+		return(TVI_CONTROL_TRUE);
+		}
+	
+    case TVI_CONTROL_SPC_SET_INPUT:
+		{
+		priv->input = getinput((int)*(void **)arg);
+
+		if(ioctl(priv->btfd, METEORSINPUT, &priv->input) < 0) 
+			{
+			perror("tunerfreq:ioctl");
+			return(0);
+			}
+
+		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_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);
+		}
+
+/* Video Controls */
+
+	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;
+
+		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(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_NTSC) 
+			{
+			priv->iformat = METEOR_FMT_NTSC;
+			priv->maxheight = NTSC_HEIGHT;
+			priv->maxwidth = NTSC_WIDTH;
+			priv->maxfps = NTSC_FPS;
+			priv->fps = NTSC_FPS;
+
+			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(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, 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(ioctl(priv->btfd, METEORSFPS, &priv->fps) < 0) 
+			{
+			perror("fps: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(req_fmt != IMGFMT_UYVY) return(TVI_CONTROL_FALSE);
+
+		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;
+			}
+
+		if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) 
+			{
+			perror("width:ioctl");
+			return(0);
+			}
+
+		return(TVI_CONTROL_TRUE);
+
+	case TVI_CONTROL_VID_GET_WIDTH:
+		(int)*(void **)arg = priv->geom.columns;
+		return(TVI_CONTROL_TRUE);
+
+	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(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) 
+			{
+			perror("height:ioctl");
+			return(0);
+			}
+
+		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_SET_FPS:
+		priv->fps = (int)*(void **)arg;
+
+		if(priv->fps > priv->maxfps) priv->fps = priv->maxfps;
+
+		if(ioctl(priv->btfd, METEORSFPS, &priv->fps) < 0) 
+			{
+			perror("fps:ioctl");
+			return(0);
+			}
+
+		return(TVI_CONTROL_TRUE);		
+*/
+
+	case TVI_CONTROL_VID_CHK_WIDTH:
+	case TVI_CONTROL_VID_CHK_HEIGHT:
+		return(TVI_CONTROL_TRUE);
+
+	}
+	return(TVI_CONTROL_UNKNOWN);
+}
+
+static int init(priv_t *priv)
+{
+int marg;
+
+G_private = priv; /* Oooh, sick */
+
+/* Video Configuration */
+
+priv->videoready = TRUE;
+priv->btdev = strdup("/dev/bktr0");
+priv->iformat = METEOR_FMT_PAL;
+priv->maxheight = PAL_HEIGHT;
+priv->maxwidth = PAL_WIDTH;
+priv->maxfps = PAL_FPS;
+priv->source = METEOR_INPUT_DEV0;
+priv->fps = priv->maxfps;
+
+priv->currentframe=0;
+
+priv->geom.columns = priv->maxwidth;
+priv->geom.rows = priv->maxheight;
+priv->geom.frames = 1;
+priv->geom.oformat = METEOR_GEO_YUV_PACKED;
+
+priv->btfd = open(priv->btdev, O_RDONLY);
+
+if(priv->btfd < 0)
+	{
+	perror("bktr open");
+	priv->videoready = FALSE;
+	}
+
+if(priv->videoready == TRUE && 
+   ioctl(priv->btfd, METEORSFMT, &priv->iformat) < 0) 
+	{
+	perror("FMT:ioctl");
+	}
+
+if(priv->videoready == TRUE &&
+   ioctl(priv->btfd, METEORSINPUT, &priv->source) < 0) 
+	{
+	perror("SINPUT:ioctl");
+	}
+
+if(priv->videoready == TRUE &&
+   ioctl(priv->btfd, METEORSFPS, &priv->fps) < 0) 
+	{
+	perror("SFPS:ioctl");
+	}
+
+if(priv->videoready == TRUE &&
+   ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) 
+	{
+	perror("SGEO:ioctl");
+	}
+
+if(priv->videoready == TRUE)
+	{
+	priv->buffersize = (priv->geom.columns * priv->geom.rows * 2);
+
+	priv->buffer = (u_char *)mmap((caddr_t)0, priv->buffersize, PROT_READ,
+							MAP_SHARED, priv->btfd, (off_t)0);
+
+	if(priv->buffer == (u_char *) MAP_FAILED)
+		{
+		perror("mmap");
+		priv->videoready = FALSE;
+		}
+
+	}
+
+/* Tuner Configuration */
+
+priv->tunerdev = strdup("/dev/tuner0");
+priv->tunerready = TRUE;
+
+priv->tunerfd = open(priv->tunerdev, O_RDONLY);
+
+if(priv->tunerfd < 0)
+	{
+	perror("tune open");
+	priv->tunerready = FALSE;
+	}
+
+/* Audio Configuration */
+
+priv->dspready = TRUE;
+priv->dspdev = strdup("/dev/dsp");
+priv->dspsamplesize = 16;
+priv->dspstereo = 1;
+priv->dspspeed = 44100;
+priv->dspfmt = AFMT_S16_LE;
+priv->dspframesize = priv->dspspeed*priv->dspsamplesize/8/priv->fps * 
+					 (priv->dspstereo+1);
+
+if((priv->dspfd = open ("/dev/dsp", O_RDWR, 0)) < 0)
+	{
+	perror("/dev/dsp open");
+	priv->dspready = FALSE;
+	} 
+
+marg = (256 << 16) | 13;
+
+if (ioctl(priv->dspfd, SNDCTL_DSP_SETFRAGMENT, &marg ) < 0 ) 
+	{
+	perror("setfrag");
+	priv->dspready = FALSE;
+	}
+
+if((priv->dspready == TRUE) &&
+   (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;
+	}
+
+return(1);
+}
+
+/* that's the real start, we'got the format parameters (checked with control) */
+static int start(priv_t *priv)
+{
+int marg;
+
+if(priv->videoready == FALSE) return(0);
+
+signal(SIGUSR1, processframe);
+signal(SIGALRM, processframe);
+
+marg = SIGUSR1;
+
+if(ioctl(priv->btfd, METEORSSIGNAL, &marg) < 0) 
+	{
+	perror("METEORSSIGNAL failed");
+	return(0);
+	}
+
+marg = METEOR_CAP_CONTINOUS;
+
+if(ioctl(priv->btfd, METEORCAPTUR, &marg) < 0) 
+	{
+	perror("METEORCAPTUR failed");
+	return(0);
+	}
+
+return(1);
+}
+
+static int uninit(priv_t *priv)
+{
+int marg;
+
+if(priv->videoready == FALSE) return(0);
+
+marg = METEOR_SIG_MODE_MASK;
+
+if(ioctl( priv->btfd, METEORSSIGNAL, &marg) < 0 ) 
+	{
+	perror("METEORSSIGNAL");
+	return(0);
+	}
+
+marg = METEOR_CAP_STOP_CONT;
+
+if(ioctl(priv->btfd, METEORCAPTUR, &marg) < 0 ) 
+	{
+	perror("METEORCAPTUR STOP");
+	return(0);
+	}
+
+close(priv->btfd);
+close(priv->dspfd);
+
+priv->dspfd = -1;
+priv->btfd = -1;
+
+priv->dspready = priv->videoready = FALSE;
+
+return(1);
+}
+
+
+static int grab_video_frame(priv_t *priv, char *buffer, int len)
+{
+sigset_t sa_mask;
+
+if(priv->videoready == FALSE) return(0);
+
+alarm(1);
+sigfillset(&sa_mask);
+sigdelset(&sa_mask,SIGINT);
+sigdelset(&sa_mask,SIGUSR1);
+sigdelset(&sa_mask,SIGALRM);
+sigsuspend(&sa_mask);
+alarm(0);
+
+memcpy(buffer, priv->buffer, len);
+
+return(priv->currentframe);
+}
+
+static int get_video_framesize(priv_t *priv)
+{
+return(priv->geom.columns*priv->geom.rows*16/8);
+}
+
+static int grab_audio_frame(priv_t *priv, char *buffer, int len)
+{
+struct audio_buf_info abi;
+int bytesread;
+int ret;
+
+if(priv->dspready == FALSE) return 0;
+
+/* 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);
+
+	if(ret == -1)
+		{
+		perror("Audio read failed!");
+		return 0;
+		}
+
+	bytesread+=ret;
+	}
+
+if(ioctl(priv->dspfd, SNDCTL_DSP_GETISPACE, &abi) < 0) 
+	{
+	perror("abi:ioctl");
+	return(TVI_CONTROL_FALSE);
+	}
+
+return(abi.bytes/len);
+}
+
+static int get_audio_framesize(priv_t *priv)
+{
+if(priv->dspready == FALSE) return 0;
+
+return(priv->dspframesize);
+}
+
+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  */
+	}
+
+return 0;
+}
+
+#endif /* USE_TV */