Merge svn changes up to r30475
[mplayer/glamo.git] / stream / tvi_bsdbt848.c
blob627540b09b33c56b78b2821da4ede545c025950f
1 /*
2 * *BSD (hopefully, requires working driver!) BrookTree capture support.
4 * Still in (active) development!
6 * v1.1 Mar 13 2002 Fully functional, need to move ring buffer to
7 * the kernel driver.
8 * v1.0 Feb 19 2002 First Release, need to add support for changing
9 * audio parameters.
11 * Copyright (C) 2002 Charles R. Henrich (henrich@msu.edu)
13 * This file is part of MPlayer.
15 * MPlayer is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * MPlayer is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License along
26 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include "config.h"
32 #define RINGSIZE 8
33 #define FRAGSIZE 4096 /* (2^12 see SETFRAGSIZE below) */
35 #define TRUE (1==1)
36 #define FALSE (1==0)
38 #define PAL_WIDTH 768
39 #define PAL_HEIGHT 576
40 #define PAL_FPS 25
42 #define NTSC_WIDTH 640
43 #define NTSC_HEIGHT 480
44 #define NTSC_FPS 29.97
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <unistd.h>
49 #include <fcntl.h>
50 #include <sys/types.h>
51 #include <sys/mman.h>
52 #include <sys/filio.h>
53 #include <sys/time.h>
54 #include <signal.h>
55 #include <string.h>
56 #include <errno.h>
58 #include <sys/param.h>
59 #ifdef CONFIG_SUN_AUDIO
60 #include <sys/audioio.h>
61 #endif
63 #ifdef IOCTL_METEOR_H_NAME
64 #include IOCTL_METEOR_H_NAME
65 #endif
67 #ifdef IOCTL_BT848_H_NAME
68 #include IOCTL_BT848_H_NAME
69 #endif
71 #ifdef HAVE_SYS_SOUNDCARD_H
72 #include <sys/soundcard.h>
73 #else
74 #ifdef HAVE_SOUNDCARD_H
75 #include <soundcard.h>
76 #else
77 #include <machine/soundcard.h>
78 #endif
79 #endif
81 #include "libaf/af_format.h"
82 #include "libmpcodecs/img_format.h"
83 #include "tv.h"
84 #include "help_mp.h"
85 #include "mp_msg.h"
87 static tvi_handle_t *tvi_init_bsdbt848(tv_param_t* tv_param);
88 /* information about this file */
89 const tvi_info_t tvi_info_bsdbt848 = {
90 tvi_init_bsdbt848,
91 "Brooktree848 Support",
92 "bsdbt848",
93 "Charles Henrich",
94 "in development"
97 typedef struct {
98 int dirty;
99 double timestamp;
100 char *buf;
101 } RBFRAME;
103 /* private data's */
104 typedef struct {
106 /* Audio */
107 char *dspdev;
108 int dspready;
109 int dspfd;
110 int dspsamplesize;
111 int dspstereo;
112 int dspspeed;
113 int dspfmt;
114 int dspframesize;
115 int dsprate;
116 long long dspbytesread;
118 /* Video */
119 char *btdev;
120 int videoready;
121 int btfd;
122 int source;
123 float maxfps;
124 float fps;
125 int iformat;
126 int maxheight;
127 int maxwidth;
128 struct meteor_geomet geom;
129 struct meteor_capframe capframe;
131 /* Frame Buffer */
133 int framebufsize;
134 float timestamp;
135 int curpaintframe;
136 int curbufframe;
137 unsigned char *livebuf;
138 RBFRAME framebuf[RINGSIZE];
140 /* Inputs */
142 int input;
144 /* Tuner */
146 char *tunerdev;
147 int tunerfd;
148 int tunerready;
149 u_long tunerfreq;
150 struct bktr_chnlset cset;
152 /* Other */
154 int immediatemode;
155 double starttime;
157 tv_param_t *tv_param;
158 } priv_t;
160 #include "tvi_def.h"
162 static priv_t *G_private=NULL;
164 static int getinput(int innumber);
166 static void processframe(int signal)
168 struct timeval curtime;
170 if(G_private->immediatemode == TRUE) return;
172 gettimeofday(&curtime, NULL);
174 if(G_private->framebuf[G_private->curpaintframe].dirty == TRUE)
176 memcpy(G_private->framebuf[G_private->curpaintframe].buf,
177 G_private->livebuf, G_private->framebufsize);
179 G_private->framebuf[G_private->curpaintframe].dirty = FALSE;
181 G_private->framebuf[G_private->curpaintframe].timestamp =
182 curtime.tv_sec + curtime.tv_usec*.000001;
184 G_private->curpaintframe++;
186 if(G_private->curpaintframe >= RINGSIZE) G_private->curpaintframe = 0;
189 return;
192 /* handler creator - entry point ! */
193 static tvi_handle_t *tvi_init_bsdbt848(tv_param_t* tv_param)
195 char* sep ;
196 tvi_handle_t* tvh;
197 priv_t* priv;
199 tvh=new_handle();
200 if(!tvh)
201 return NULL;
202 priv=(priv_t*)tvh->priv;
204 if user needs to specify both /dev/bktr<n> and /dev/tuner<n>
205 it can do this with "-tv device=/dev/bktr1,/dev/tuner1"
208 /* set video device name */
209 if (!tv_param->device){
210 priv->btdev = strdup("/dev/bktr0");
211 priv->tunerdev = strdup("/dev/tuner0");
212 }else{
213 sep = strchr(tv_param->device,',');
214 priv->btdev = strdup(tv_param->device);
215 if(sep){
216 // tuner device is also passed
217 priv->tunerdev = strdup(sep+1);
218 priv->btdev[sep - tv_param->device] = 0;
219 }else{
220 priv->tunerdev = strdup("/dev/tuner0");
224 /* set audio device name */
225 if (!tv_param->adevice)
226 #ifdef CONFIG_SUN_AUDIO
227 priv->dspdev = strdup("/dev/sound");
228 #else
229 priv->dspdev = strdup("/dev/dsp");
230 #endif
231 else
232 priv->dspdev = strdup(tv_param->adevice);
234 priv->tv_param=tv_param;
235 return tvh;
238 static int control(priv_t *priv, int cmd, void *arg)
240 switch(cmd)
243 /* Tuner Controls */
245 case TVI_CONTROL_IS_TUNER:
246 if(priv->tunerready == FALSE) return TVI_CONTROL_FALSE;
247 return TVI_CONTROL_TRUE;
249 case TVI_CONTROL_TUN_GET_FREQ:
251 if(ioctl(priv->tunerfd, TVTUNER_GETFREQ, &priv->tunerfreq) < 0)
253 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "TVTUNER_GETFREQ", strerror(errno));
254 return TVI_CONTROL_FALSE;
257 *(int *)arg = priv->tunerfreq;
258 return TVI_CONTROL_TRUE;
261 case TVI_CONTROL_TUN_SET_FREQ:
263 priv->tunerfreq = *(int *)arg;
265 if(ioctl(priv->tunerfd, TVTUNER_SETFREQ, &priv->tunerfreq) < 0)
267 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "TVTUNER_SETFREQ", strerror(errno));
268 return 0;
271 return TVI_CONTROL_TRUE;
273 case TVI_CONTROL_TUN_GET_SIGNAL:
275 int status;
276 if(ioctl(priv->tunerfd, TVTUNER_GETSTATUS, &status) < 0)
278 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "GETSTATUS", strerror(errno));
279 return 0;
281 *(int*)arg=(status & 0x02)? 100 : 0;
282 return TVI_CONTROL_TRUE;
285 case TVI_CONTROL_TUN_GET_TUNER:
286 case TVI_CONTROL_TUN_SET_TUNER:
288 /* Inputs */
290 case TVI_CONTROL_SPC_GET_INPUT:
292 if(ioctl(priv->btfd, METEORGINPUT, &priv->input) < 0)
294 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORGINPUT", strerror(errno));
295 return TVI_CONTROL_FALSE;
298 *(int *)arg = priv->input;
299 return TVI_CONTROL_TRUE;
302 case TVI_CONTROL_SPC_SET_INPUT:
304 priv->input = getinput(*(int *)arg);
306 if(ioctl(priv->btfd, METEORSINPUT, &priv->input) < 0)
308 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSINPUT", strerror(errno));
309 return 0;
312 return TVI_CONTROL_TRUE;
315 /* Audio Controls */
317 case TVI_CONTROL_IS_AUDIO:
318 if(priv->dspready == FALSE) return TVI_CONTROL_FALSE;
319 return TVI_CONTROL_TRUE;
321 case TVI_CONTROL_AUD_GET_FORMAT:
323 *(int *)arg = AF_FORMAT_S16_LE;
324 return TVI_CONTROL_TRUE;
326 case TVI_CONTROL_AUD_GET_CHANNELS:
328 *(int *)arg = 2;
329 return TVI_CONTROL_TRUE;
331 case TVI_CONTROL_AUD_SET_SAMPLERATE:
333 int dspspeed = *(int *)arg;
335 if(ioctl(priv->dspfd, SNDCTL_DSP_SPEED, &dspspeed) == -1)
337 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Invalid audio rate. Error: %s\n", strerror(errno));
338 return TVI_CONTROL_FALSE;
341 priv->dspspeed = dspspeed;
343 priv->dspframesize = priv->dspspeed*priv->dspsamplesize/8/
344 priv->fps * (priv->dspstereo+1);
345 priv->dsprate = priv->dspspeed * priv->dspsamplesize/8*
346 (priv->dspstereo+1);
348 return TVI_CONTROL_TRUE;
350 case TVI_CONTROL_AUD_GET_SAMPLERATE:
352 *(int *)arg = priv->dspspeed;
353 return TVI_CONTROL_TRUE;
355 case TVI_CONTROL_AUD_GET_SAMPLESIZE:
357 *(int *)arg = priv->dspsamplesize/8;
358 return TVI_CONTROL_TRUE;
361 /* Video Controls */
363 case TVI_CONTROL_IS_VIDEO:
364 if(priv->videoready == FALSE) return TVI_CONTROL_FALSE;
365 return TVI_CONTROL_TRUE;
367 case TVI_CONTROL_TUN_SET_NORM:
369 int req_mode = *(int *)arg;
370 u_short tmp_fps;
372 priv->iformat = METEOR_FMT_AUTOMODE;
374 if(req_mode == TV_NORM_PAL)
376 priv->iformat = METEOR_FMT_PAL;
377 priv->maxheight = PAL_HEIGHT;
378 priv->maxwidth = PAL_WIDTH;
379 priv->maxfps = PAL_FPS;
380 priv->fps = PAL_FPS;
382 if(priv->fps > priv->maxfps) priv->fps = priv->maxfps;
384 if(priv->geom.rows > priv->maxheight)
386 priv->geom.rows = priv->maxheight;
389 if(priv->geom.columns > priv->maxwidth)
391 priv->geom.columns = priv->maxwidth;
395 if(req_mode == TV_NORM_NTSC)
397 priv->iformat = METEOR_FMT_NTSC;
398 priv->maxheight = NTSC_HEIGHT;
399 priv->maxwidth = NTSC_WIDTH;
400 priv->maxfps = NTSC_FPS;
401 priv->fps = NTSC_FPS;
403 priv->dspframesize = priv->dspspeed*priv->dspsamplesize/8/
404 priv->fps * (priv->dspstereo+1);
405 priv->dsprate = priv->dspspeed * priv->dspsamplesize/8 *
406 (priv->dspstereo+1);
408 if(priv->fps > priv->maxfps) priv->fps = priv->maxfps;
410 if(priv->geom.rows > priv->maxheight)
412 priv->geom.rows = priv->maxheight;
415 if(priv->geom.columns > priv->maxwidth)
417 priv->geom.columns = priv->maxwidth;
421 if(req_mode == TV_NORM_SECAM) priv->iformat = METEOR_FMT_SECAM;
423 if(ioctl(priv->btfd, METEORSFMT, &priv->iformat) < 0)
425 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSFMT", strerror(errno));
426 return TVI_CONTROL_FALSE;
429 if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0)
431 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSETGEO", strerror(errno));
432 return 0;
435 tmp_fps = priv->fps;
436 if(ioctl(priv->btfd, METEORSFPS, &tmp_fps) < 0)
438 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSFPS", strerror(errno));
439 return 0;
442 #ifdef BT848_SAUDIO
443 if(priv->tunerready == TRUE &&
444 ioctl(priv->tunerfd, BT848_SAUDIO, &priv->tv_param->audio_id) < 0)
446 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "BT848_SAUDIO", strerror(errno));
448 #endif
450 return TVI_CONTROL_TRUE;
453 case TVI_CONTROL_VID_GET_FORMAT:
454 *(int *)arg = IMGFMT_UYVY;
455 return TVI_CONTROL_TRUE;
457 case TVI_CONTROL_VID_SET_FORMAT:
459 int req_fmt = *(int *)arg;
461 if(req_fmt != IMGFMT_UYVY) return TVI_CONTROL_FALSE;
463 return TVI_CONTROL_TRUE;
465 case TVI_CONTROL_VID_SET_WIDTH:
466 priv->geom.columns = *(int *)arg;
468 if(priv->geom.columns > priv->maxwidth)
470 priv->geom.columns = priv->maxwidth;
473 if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0)
475 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Error setting picture width. Error: %s\n", strerror(errno));
476 return 0;
479 return TVI_CONTROL_TRUE;
481 case TVI_CONTROL_VID_GET_WIDTH:
482 *(int *)arg = priv->geom.columns;
483 return TVI_CONTROL_TRUE;
485 case TVI_CONTROL_VID_SET_HEIGHT:
486 priv->geom.rows = *(int *)arg;
488 if(priv->geom.rows > priv->maxheight)
490 priv->geom.rows = priv->maxheight;
493 if(priv->geom.rows <= priv->maxheight / 2)
495 priv->geom.oformat |= METEOR_GEO_EVEN_ONLY;
498 if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0)
500 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Error setting picture width. Error: %s\n", strerror(errno));
501 return 0;
504 return TVI_CONTROL_TRUE;
506 case TVI_CONTROL_VID_GET_HEIGHT:
507 *(int *)arg = priv->geom.rows;
508 return TVI_CONTROL_TRUE;
510 case TVI_CONTROL_VID_GET_FPS:
511 *(float *)arg = priv->fps;
512 return TVI_CONTROL_TRUE;
515 case TVI_CONTROL_VID_SET_FPS:
516 priv->fps = *(int *)arg;
518 if(priv->fps > priv->maxfps) priv->fps = priv->maxfps;
520 if(ioctl(priv->btfd, METEORSFPS, &priv->fps) < 0)
522 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSFPS", strerror(errno));
523 return 0;
526 return TVI_CONTROL_TRUE;
529 case TVI_CONTROL_VID_CHK_WIDTH:
530 case TVI_CONTROL_VID_CHK_HEIGHT:
531 return TVI_CONTROL_TRUE;
533 case TVI_CONTROL_IMMEDIATE:
534 priv->immediatemode = TRUE;
535 return TVI_CONTROL_TRUE;
538 return TVI_CONTROL_UNKNOWN;
541 static int init(priv_t *priv)
543 int marg;
544 int count;
545 u_short tmp_fps;
547 G_private = priv; /* Oooh, sick */
549 /* Video Configuration */
551 priv->videoready = TRUE;
552 priv->immediatemode = FALSE;
553 priv->iformat = METEOR_FMT_PAL;
554 priv->maxheight = PAL_HEIGHT;
555 priv->maxwidth = PAL_WIDTH;
556 priv->maxfps = PAL_FPS;
557 priv->source = METEOR_INPUT_DEV0;
558 priv->fps = priv->maxfps;
560 priv->starttime=0;
561 priv->curpaintframe=0;
562 priv->curbufframe=0;
564 priv->geom.columns = priv->maxwidth;
565 priv->geom.rows = priv->maxheight;
566 priv->geom.frames = 1;
567 priv->geom.oformat = METEOR_GEO_YUV_PACKED;
569 priv->btfd = open(priv->btdev, O_RDONLY);
571 if(priv->btfd < 0)
573 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Unable to open bktr device. Error: %s\n", strerror(errno));
574 priv->videoready = FALSE;
577 if(priv->videoready == TRUE &&
578 ioctl(priv->btfd, METEORSFMT, &priv->iformat) < 0)
580 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "SETEORSFMT", strerror(errno));
583 if(priv->videoready == TRUE &&
584 ioctl(priv->btfd, METEORSINPUT, &priv->source) < 0)
586 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSINPUT", strerror(errno));
589 tmp_fps = priv->fps;
590 if(priv->videoready == TRUE &&
591 ioctl(priv->btfd, METEORSFPS, &tmp_fps) < 0)
593 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSFPS", strerror(errno));
596 if(priv->videoready == TRUE &&
597 ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0)
599 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSGEQ", strerror(errno));
602 if(priv->videoready == TRUE)
604 priv->framebufsize = (priv->geom.columns * priv->geom.rows * 2);
606 priv->livebuf = (u_char *)mmap((caddr_t)0, priv->framebufsize, PROT_READ,
607 MAP_SHARED, priv->btfd, (off_t)0);
609 if(priv->livebuf == (u_char *) MAP_FAILED)
611 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: mmap failed. Error: %s\n", strerror(errno));
612 priv->videoready = FALSE;
615 for(count=0;count<RINGSIZE;count++)
617 priv->framebuf[count].buf = malloc(priv->framebufsize);
619 if(priv->framebuf[count].buf == NULL)
621 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Frame buffer allocation failed. Error: %s\n", strerror(errno));
622 priv->videoready = FALSE;
623 break;
626 priv->framebuf[count].dirty = TRUE;
627 priv->framebuf[count].timestamp = 0;
631 /* Tuner Configuration */
633 priv->tunerready = TRUE;
635 priv->tunerfd = open(priv->tunerdev, O_RDONLY);
637 if(priv->tunerfd < 0)
639 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Unable to open tuner device. Error: %s\n", strerror(errno));
640 priv->tunerready = FALSE;
643 /* Audio Configuration */
645 priv->dspready = TRUE;
646 priv->dspsamplesize = 16;
647 priv->dspstereo = 1;
648 priv->dspspeed = 44100;
649 priv->dspfmt = AFMT_S16_LE;
650 priv->dspbytesread = 0;
651 priv->dsprate = priv->dspspeed * priv->dspsamplesize/8*(priv->dspstereo+1);
652 priv->dspframesize = priv->dspspeed*priv->dspsamplesize/8/priv->fps *
653 (priv->dspstereo+1);
655 if((priv->dspfd = open (priv->dspdev, O_RDONLY, 0)) < 0)
657 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Unable to open dsp device. Error: %s\n", strerror(errno));
658 priv->dspready = FALSE;
661 marg = (256 << 16) | 12;
663 if (ioctl(priv->dspfd, SNDCTL_DSP_SETFRAGMENT, &marg ) < 0 )
665 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "SNDCTL_DSP_SETFRAGMENT", strerror(errno));
666 priv->dspready = FALSE;
669 if((priv->dspready == TRUE) &&
670 ((ioctl(priv->dspfd, SNDCTL_DSP_SAMPLESIZE, &priv->dspsamplesize) == -1) ||
671 (ioctl(priv->dspfd, SNDCTL_DSP_STEREO, &priv->dspstereo) == -1) ||
672 (ioctl(priv->dspfd, SNDCTL_DSP_SPEED, &priv->dspspeed) == -1) ||
673 (ioctl(priv->dspfd, SNDCTL_DSP_SETFMT, &priv->dspfmt) == -1)))
675 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Configuration of dsp failed. Error: %s\n", strerror(errno));
676 close(priv->dspfd);
677 priv->dspready = FALSE;
680 return 1;
683 /* that's the real start, we'got the format parameters (checked with control) */
684 static int start(priv_t *priv)
686 int tmp;
687 struct timeval curtime;
688 int marg;
690 fprintf(stderr,"START\n");
691 if(priv->videoready == FALSE) return 0;
693 signal(SIGUSR1, processframe);
694 signal(SIGALRM, processframe);
696 marg = SIGUSR1;
698 if(ioctl(priv->btfd, METEORSSIGNAL, &marg) < 0)
700 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSSIGNAL", strerror(errno));
701 return 0;
704 read(priv->dspfd, &tmp, 2);
706 gettimeofday(&curtime, NULL);
708 priv->starttime = curtime.tv_sec + (curtime.tv_usec *.000001);
710 marg = METEOR_CAP_CONTINOUS;
712 if(ioctl(priv->btfd, METEORCAPTUR, &marg) < 0)
714 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORCAPTUR", strerror(errno));
715 return 0;
718 return 1;
721 static int uninit(priv_t *priv)
723 int marg;
725 if(priv->videoready == FALSE) return 0;
727 marg = METEOR_SIG_MODE_MASK;
729 if(ioctl( priv->btfd, METEORSSIGNAL, &marg) < 0 )
731 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSSIGNAL", strerror(errno));
732 return 0;
735 marg = METEOR_CAP_STOP_CONT;
737 if(ioctl(priv->btfd, METEORCAPTUR, &marg) < 0 )
739 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Unable to stop capture. Error: %s\n", strerror(errno));
740 return 0;
743 close(priv->btfd);
744 close(priv->dspfd);
746 priv->dspfd = -1;
747 priv->btfd = -1;
749 priv->dspready = priv->videoready = FALSE;
751 return 1;
755 static double grabimmediate_video_frame(priv_t *priv, char *buffer, int len)
757 sigset_t sa_mask;
759 if(priv->videoready == FALSE) return 0;
761 alarm(1);
762 sigfillset(&sa_mask);
763 sigdelset(&sa_mask,SIGINT);
764 sigdelset(&sa_mask,SIGUSR1);
765 sigdelset(&sa_mask,SIGALRM);
766 sigsuspend(&sa_mask);
767 alarm(0);
769 memcpy(buffer, priv->livebuf, len);
771 /* PTS = 0, show the frame NOW, this routine is only used in playback mode
772 without audio capture .. */
774 return 0;
777 static double grab_video_frame(priv_t *priv, char *buffer, int len)
779 double timestamp=0;
780 sigset_t sa_mask;
782 if(priv->videoready == FALSE) return 0;
784 if(priv->immediatemode == TRUE)
786 return grabimmediate_video_frame(priv, buffer, len);
789 while(priv->framebuf[priv->curbufframe].dirty == TRUE)
791 alarm(1);
792 sigemptyset(&sa_mask);
793 sigsuspend(&sa_mask);
794 alarm(0);
797 memcpy(buffer, priv->framebuf[priv->curbufframe].buf, len);
798 timestamp = priv->framebuf[priv->curbufframe].timestamp;
799 priv->framebuf[priv->curbufframe].dirty = TRUE;
801 priv->curbufframe++;
802 if(priv->curbufframe >= RINGSIZE) priv->curbufframe = 0;
804 return timestamp-priv->starttime;
807 static int get_video_framesize(priv_t *priv)
809 return priv->geom.columns * priv->geom.rows * 16 / 8;
812 static double grab_audio_frame(priv_t *priv, char *buffer, int len)
814 struct timeval curtime;
815 double curpts;
816 double timeskew;
817 int bytesread;
818 int ret;
820 if(priv->dspready == FALSE) return 0;
822 gettimeofday(&curtime, NULL);
824 /* Get exactly one frame of audio, which forces video sync to audio.. */
826 bytesread=read(priv->dspfd, buffer, len);
828 while(bytesread < len)
830 ret=read(priv->dspfd, &buffer[bytesread], len-bytesread);
832 if(ret == -1)
834 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Error reading audio data. Error: %s\n", strerror(errno));
835 return 0;
838 bytesread+=ret;
841 priv->dspbytesread += bytesread;
843 curpts = curtime.tv_sec + curtime.tv_usec * .000001;
845 timeskew = priv->dspbytesread * 1.0 / priv->dsprate - (curpts-priv->starttime);
847 if(timeskew > .125/priv->fps)
849 priv->starttime -= timeskew;
851 else
853 if(timeskew < -.125/priv->fps)
855 priv->starttime -= timeskew;
859 return priv->dspbytesread * 1.0 / priv->dsprate;
862 static int get_audio_framesize(priv_t *priv)
864 int bytesavail;
865 #ifdef CONFIG_SUN_AUDIO
866 struct audio_info auinf;
867 #endif
869 if(priv->dspready == FALSE) return 0;
871 #ifdef CONFIG_SUN_AUDIO
872 if(ioctl(priv->dspfd, AUDIO_GETINFO, &auinf) < 0)
874 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "AUDIO_GETINFO", strerror(errno));
875 return TVI_CONTROL_FALSE;
877 else
878 bytesavail = auinf.record.seek; /* *priv->dspsamplesize; */
879 #else
880 if(ioctl(priv->dspfd, FIONREAD, &bytesavail) < 0)
882 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "FIONREAD", strerror(errno));
883 return TVI_CONTROL_FALSE;
885 #endif
887 /* When mencoder wants audio data, it wants data..
888 it won't go do anything else until it gets it :( */
890 if(bytesavail == 0) return FRAGSIZE;
892 return bytesavail;
895 static int getinput(int innumber)
897 switch(innumber)
899 case 0: return METEOR_INPUT_DEV0; /* RCA */
900 case 1: return METEOR_INPUT_DEV1; /* Tuner */
901 case 2: return METEOR_INPUT_DEV2; /* In 1 */
902 case 3: return METEOR_INPUT_DEV3; /* In 2 */
903 case 4: return METEOR_INPUT_DEV_RGB; /* RGB */
904 case 5: return METEOR_INPUT_DEV_SVIDEO; /* SVid */
907 return 0;