view libmpdemux/tvi_bsdbt848.c @ 5400:fe8e63e808b3

fixed -hr-mp3-seek description
author gabucino
date Sat, 30 Mar 2002 07:58:22 +0000
parents 7fc559dbc607
children 8cd761968f35
line wrap: on
line source

/*
	(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>
#ifdef HAVE_SYS_SOUNDCARD_H
#include <sys/soundcard.h>
#else
#include <machine/soundcard.h>
#endif

#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 */