/* * *BSD (hopefully, requires working driver!) BrookTree capture support. * * Still in (active) development! * * 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. * * Copyright (C) 2002 Charles R. Henrich (henrich@msu.edu) * * This file is part of MPlayer. * * MPlayer is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * MPlayer is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with MPlayer; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #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 NTSC_WIDTH 640 #define NTSC_HEIGHT 480 #define NTSC_FPS 29.97 #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_SUN_AUDIO #include #endif #ifdef IOCTL_METEOR_H_NAME #include IOCTL_METEOR_H_NAME #endif #ifdef IOCTL_BT848_H_NAME #include IOCTL_BT848_H_NAME #endif #ifdef HAVE_SYS_SOUNDCARD_H #include #else #ifdef HAVE_SOUNDCARD_H #include #else #include #endif #endif #include "libaf/af_format.h" #include "libmpcodecs/img_format.h" #include "tv.h" #include "mp_msg.h" static tvi_handle_t *tvi_init_bsdbt848(tv_param_t* tv_param); /* information about this file */ const tvi_info_t tvi_info_bsdbt848 = { tvi_init_bsdbt848, "Brooktree848 Support", "bsdbt848", "Charles Henrich", "in development" }; typedef struct { int dirty; double timestamp; char *buf; } RBFRAME; /* private data's */ typedef struct priv { /* Audio */ 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; float maxfps; float 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; /* Tuner */ char *tunerdev; int tunerfd; int tunerready; u_long tunerfreq; struct bktr_chnlset cset; /* Other */ int immediatemode; double starttime; tv_param_t *tv_param; } priv_t; #include "tvi_def.h" static priv_t *G_private=NULL; static int getinput(int innumber); static void processframe(int signal) { 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; } /* handler creator - entry point ! */ static tvi_handle_t *tvi_init_bsdbt848(tv_param_t* tv_param) { char* sep ; tvi_handle_t* tvh; priv_t* priv; tvh = tv_new_handle(sizeof(priv_t), &functions); if(!tvh) return NULL; priv=(priv_t*)tvh->priv; /* if user needs to specify both /dev/bktr and /dev/tuner it can do this with "-tv device=/dev/bktr1,/dev/tuner1" */ /* set video device name */ if (!tv_param->device){ priv->btdev = strdup("/dev/bktr0"); priv->tunerdev = strdup("/dev/tuner0"); }else{ sep = strchr(tv_param->device,','); priv->btdev = strdup(tv_param->device); if(sep){ // tuner device is also passed priv->tunerdev = strdup(sep+1); priv->btdev[sep - tv_param->device] = 0; }else{ priv->tunerdev = strdup("/dev/tuner0"); } } /* set audio device name */ if (!tv_param->adevice) #ifdef CONFIG_SUN_AUDIO priv->dspdev = strdup("/dev/sound"); #else priv->dspdev = strdup("/dev/dsp"); #endif else priv->dspdev = strdup(tv_param->adevice); priv->tv_param=tv_param; return tvh; } 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) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "TVTUNER_GETFREQ", strerror(errno)); return TVI_CONTROL_FALSE; } *(int *)arg = priv->tunerfreq; return TVI_CONTROL_TRUE; } case TVI_CONTROL_TUN_SET_FREQ: { priv->tunerfreq = *(int *)arg; if(ioctl(priv->tunerfd, TVTUNER_SETFREQ, &priv->tunerfreq) < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "TVTUNER_SETFREQ", strerror(errno)); return 0; } return TVI_CONTROL_TRUE; } case TVI_CONTROL_TUN_GET_SIGNAL: { int status; if(ioctl(priv->tunerfd, TVTUNER_GETSTATUS, &status) < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "GETSTATUS", strerror(errno)); return 0; } *(int*)arg=(status & 0x02)? 100 : 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) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORGINPUT", strerror(errno)); return TVI_CONTROL_FALSE; } *(int *)arg = priv->input; return TVI_CONTROL_TRUE; } case TVI_CONTROL_SPC_SET_INPUT: { priv->input = getinput(*(int *)arg); if(ioctl(priv->btfd, METEORSINPUT, &priv->input) < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSINPUT", strerror(errno)); 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 *)arg = AF_FORMAT_S16_LE; return TVI_CONTROL_TRUE; } case TVI_CONTROL_AUD_GET_CHANNELS: { *(int *)arg = 2; return TVI_CONTROL_TRUE; } case TVI_CONTROL_AUD_SET_SAMPLERATE: { int dspspeed = *(int *)arg; if(ioctl(priv->dspfd, SNDCTL_DSP_SPEED, &dspspeed) == -1) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Invalid audio rate. Error: %s\n", strerror(errno)); 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 *)arg = priv->dspspeed; return TVI_CONTROL_TRUE; } case TVI_CONTROL_AUD_GET_SAMPLESIZE: { *(int *)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_TUN_SET_NORM: { int req_mode = *(int *)arg; u_short tmp_fps; 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); priv->dsprate = priv->dspspeed * priv->dspsamplesize/8 * (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) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSFMT", strerror(errno)); return TVI_CONTROL_FALSE; } if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSETGEO", strerror(errno)); return 0; } tmp_fps = priv->fps; if(ioctl(priv->btfd, METEORSFPS, &tmp_fps) < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSFPS", strerror(errno)); return 0; } #ifdef BT848_SAUDIO if(priv->tunerready == TRUE && ioctl(priv->tunerfd, BT848_SAUDIO, &priv->tv_param->audio_id) < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "BT848_SAUDIO", strerror(errno)); } #endif return TVI_CONTROL_TRUE; } case TVI_CONTROL_VID_GET_FORMAT: *(int *)arg = IMGFMT_UYVY; return TVI_CONTROL_TRUE; case TVI_CONTROL_VID_SET_FORMAT: { int req_fmt = *(int *)arg; if(req_fmt != IMGFMT_UYVY) return TVI_CONTROL_FALSE; return TVI_CONTROL_TRUE; } case TVI_CONTROL_VID_SET_WIDTH: priv->geom.columns = *(int *)arg; if(priv->geom.columns > priv->maxwidth) { priv->geom.columns = priv->maxwidth; } if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Error setting picture width. Error: %s\n", strerror(errno)); return 0; } return TVI_CONTROL_TRUE; case TVI_CONTROL_VID_GET_WIDTH: *(int *)arg = priv->geom.columns; return TVI_CONTROL_TRUE; case TVI_CONTROL_VID_SET_HEIGHT: priv->geom.rows = *(int *)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) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Error setting picture width. Error: %s\n", strerror(errno)); return 0; } return TVI_CONTROL_TRUE; case TVI_CONTROL_VID_GET_HEIGHT: *(int *)arg = priv->geom.rows; return TVI_CONTROL_TRUE; case TVI_CONTROL_VID_GET_FPS: *(float *)arg = priv->fps; return TVI_CONTROL_TRUE; /* case TVI_CONTROL_VID_SET_FPS: priv->fps = *(int *)arg; if(priv->fps > priv->maxfps) priv->fps = priv->maxfps; if(ioctl(priv->btfd, METEORSFPS, &priv->fps) < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSFPS", strerror(errno)); return 0; } return TVI_CONTROL_TRUE; */ case TVI_CONTROL_VID_CHK_WIDTH: case TVI_CONTROL_VID_CHK_HEIGHT: return TVI_CONTROL_TRUE; 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; u_short tmp_fps; G_private = priv; /* Oooh, sick */ /* Video Configuration */ priv->videoready = TRUE; priv->immediatemode = FALSE; 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->starttime=0; priv->curpaintframe=0; priv->curbufframe=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) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Unable to open bktr device. Error: %s\n", strerror(errno)); priv->videoready = FALSE; } if(priv->videoready == TRUE && ioctl(priv->btfd, METEORSFMT, &priv->iformat) < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "SETEORSFMT", strerror(errno)); } if(priv->videoready == TRUE && ioctl(priv->btfd, METEORSINPUT, &priv->source) < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSINPUT", strerror(errno)); } tmp_fps = priv->fps; if(priv->videoready == TRUE && ioctl(priv->btfd, METEORSFPS, &tmp_fps) < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSFPS", strerror(errno)); } if(priv->videoready == TRUE && ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSGEQ", strerror(errno)); } if(priv->videoready == TRUE) { 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); if(priv->livebuf == (u_char *) MAP_FAILED) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: mmap failed. Error: %s\n", strerror(errno)); priv->videoready = FALSE; } for(count=0;countframebuf[count].buf = malloc(priv->framebufsize); if(priv->framebuf[count].buf == NULL) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Frame buffer allocation failed. Error: %s\n", strerror(errno)); priv->videoready = FALSE; break; } priv->framebuf[count].dirty = TRUE; priv->framebuf[count].timestamp = 0; } } /* Tuner Configuration */ priv->tunerready = TRUE; priv->tunerfd = open(priv->tunerdev, O_RDONLY); if(priv->tunerfd < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Unable to open tuner device. Error: %s\n", strerror(errno)); priv->tunerready = FALSE; } /* Audio Configuration */ priv->dspready = TRUE; priv->dspsamplesize = 16; 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); if((priv->dspfd = open (priv->dspdev, O_RDONLY, 0)) < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Unable to open dsp device. Error: %s\n", strerror(errno)); priv->dspready = FALSE; } marg = (256 << 16) | 12; if (ioctl(priv->dspfd, SNDCTL_DSP_SETFRAGMENT, &marg ) < 0 ) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "SNDCTL_DSP_SETFRAGMENT", strerror(errno)); 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))) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Configuration of dsp failed. Error: %s\n", strerror(errno)); 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 tmp; struct timeval curtime; int marg; fprintf(stderr,"START\n"); if(priv->videoready == FALSE) return 0; signal(SIGUSR1, processframe); signal(SIGALRM, processframe); marg = SIGUSR1; if(ioctl(priv->btfd, METEORSSIGNAL, &marg) < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSSIGNAL", strerror(errno)); 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) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORCAPTUR", strerror(errno)); 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 ) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSSIGNAL", strerror(errno)); return 0; } marg = METEOR_CAP_STOP_CONT; if(ioctl(priv->btfd, METEORCAPTUR, &marg) < 0 ) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Unable to stop capture. Error: %s\n", strerror(errno)); return 0; } close(priv->btfd); close(priv->dspfd); priv->dspfd = -1; priv->btfd = -1; priv->dspready = priv->videoready = FALSE; return 1; } static double grabimmediate_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->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) { double timestamp=0; sigset_t sa_mask; if(priv->videoready == FALSE) return 0; 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) { return priv->geom.columns * priv->geom.rows * 16 / 8; } static double grab_audio_frame(priv_t *priv, char *buffer, int len) { struct timeval curtime; double curpts; double timeskew; 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); if(ret == -1) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Error reading audio data. Error: %s\n", strerror(errno)); return 0; } bytesread+=ret; } priv->dspbytesread += bytesread; curpts = curtime.tv_sec + curtime.tv_usec * .000001; timeskew = priv->dspbytesread * 1.0 / priv->dsprate - (curpts-priv->starttime); if(timeskew > .125/priv->fps) { priv->starttime -= timeskew; } else { if(timeskew < -.125/priv->fps) { priv->starttime -= timeskew; } } return priv->dspbytesread * 1.0 / priv->dsprate; } static int get_audio_framesize(priv_t *priv) { int bytesavail; #ifdef CONFIG_SUN_AUDIO struct audio_info auinf; #endif if(priv->dspready == FALSE) return 0; #ifdef CONFIG_SUN_AUDIO if(ioctl(priv->dspfd, AUDIO_GETINFO, &auinf) < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "AUDIO_GETINFO", strerror(errno)); return TVI_CONTROL_FALSE; } else bytesavail = auinf.record.seek; /* *priv->dspsamplesize; */ #else if(ioctl(priv->dspfd, FIONREAD, &bytesavail) < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "FIONREAD", strerror(errno)); return TVI_CONTROL_FALSE; } #endif /* When mencoder wants audio data, it wants data.. it won't 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 */ } return 0; }