options: move various mplayer.c options to option struct
[mplayer.git] / stream / tvi_bsdbt848.c
blob9e2a77a542355125bb7d4e79c510e191e393d860
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 "mp_msg.h"
86 static tvi_handle_t *tvi_init_bsdbt848(tv_param_t* tv_param);
87 /* information about this file */
88 const tvi_info_t tvi_info_bsdbt848 = {
89 tvi_init_bsdbt848,
90 "Brooktree848 Support",
91 "bsdbt848",
92 "Charles Henrich",
93 "in development"
96 typedef struct {
97 int dirty;
98 double timestamp;
99 char *buf;
100 } RBFRAME;
102 /* private data's */
103 typedef struct priv {
105 /* Audio */
106 char *dspdev;
107 int dspready;
108 int dspfd;
109 int dspsamplesize;
110 int dspstereo;
111 int dspspeed;
112 int dspfmt;
113 int dspframesize;
114 int dsprate;
115 long long dspbytesread;
117 /* Video */
118 char *btdev;
119 int videoready;
120 int btfd;
121 int source;
122 float maxfps;
123 float fps;
124 int iformat;
125 int maxheight;
126 int maxwidth;
127 struct meteor_geomet geom;
128 struct meteor_capframe capframe;
130 /* Frame Buffer */
132 int framebufsize;
133 float timestamp;
134 int curpaintframe;
135 int curbufframe;
136 unsigned char *livebuf;
137 RBFRAME framebuf[RINGSIZE];
139 /* Inputs */
141 int input;
143 /* Tuner */
145 char *tunerdev;
146 int tunerfd;
147 int tunerready;
148 u_long tunerfreq;
149 struct bktr_chnlset cset;
151 /* Other */
153 int immediatemode;
154 double starttime;
156 tv_param_t *tv_param;
157 } priv_t;
159 #include "tvi_def.h"
161 static priv_t *G_private=NULL;
163 static int getinput(int innumber);
165 static void processframe(int signal)
167 struct timeval curtime;
169 if(G_private->immediatemode == TRUE) return;
171 gettimeofday(&curtime, NULL);
173 if(G_private->framebuf[G_private->curpaintframe].dirty == TRUE)
175 memcpy(G_private->framebuf[G_private->curpaintframe].buf,
176 G_private->livebuf, G_private->framebufsize);
178 G_private->framebuf[G_private->curpaintframe].dirty = FALSE;
180 G_private->framebuf[G_private->curpaintframe].timestamp =
181 curtime.tv_sec + curtime.tv_usec*.000001;
183 G_private->curpaintframe++;
185 if(G_private->curpaintframe >= RINGSIZE) G_private->curpaintframe = 0;
188 return;
191 /* handler creator - entry point ! */
192 static tvi_handle_t *tvi_init_bsdbt848(tv_param_t* tv_param)
194 char* sep ;
195 tvi_handle_t* tvh;
196 priv_t* priv;
198 tvh = tv_new_handle(sizeof(priv_t), &functions);
199 if(!tvh)
200 return NULL;
201 priv=(priv_t*)tvh->priv;
203 if user needs to specify both /dev/bktr<n> and /dev/tuner<n>
204 it can do this with "-tv device=/dev/bktr1,/dev/tuner1"
207 /* set video device name */
208 if (!tv_param->device){
209 priv->btdev = strdup("/dev/bktr0");
210 priv->tunerdev = strdup("/dev/tuner0");
211 }else{
212 sep = strchr(tv_param->device,',');
213 priv->btdev = strdup(tv_param->device);
214 if(sep){
215 // tuner device is also passed
216 priv->tunerdev = strdup(sep+1);
217 priv->btdev[sep - tv_param->device] = 0;
218 }else{
219 priv->tunerdev = strdup("/dev/tuner0");
223 /* set audio device name */
224 if (!tv_param->adevice)
225 #ifdef CONFIG_SUN_AUDIO
226 priv->dspdev = strdup("/dev/sound");
227 #else
228 priv->dspdev = strdup("/dev/dsp");
229 #endif
230 else
231 priv->dspdev = strdup(tv_param->adevice);
233 priv->tv_param=tv_param;
234 return tvh;
237 static int control(priv_t *priv, int cmd, void *arg)
239 switch(cmd)
242 /* Tuner Controls */
244 case TVI_CONTROL_IS_TUNER:
245 if(priv->tunerready == FALSE) return TVI_CONTROL_FALSE;
246 return TVI_CONTROL_TRUE;
248 case TVI_CONTROL_TUN_GET_FREQ:
250 if(ioctl(priv->tunerfd, TVTUNER_GETFREQ, &priv->tunerfreq) < 0)
252 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "TVTUNER_GETFREQ", strerror(errno));
253 return TVI_CONTROL_FALSE;
256 *(int *)arg = priv->tunerfreq;
257 return TVI_CONTROL_TRUE;
260 case TVI_CONTROL_TUN_SET_FREQ:
262 priv->tunerfreq = *(int *)arg;
264 if(ioctl(priv->tunerfd, TVTUNER_SETFREQ, &priv->tunerfreq) < 0)
266 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "TVTUNER_SETFREQ", strerror(errno));
267 return 0;
270 return TVI_CONTROL_TRUE;
272 case TVI_CONTROL_TUN_GET_SIGNAL:
274 int status;
275 if(ioctl(priv->tunerfd, TVTUNER_GETSTATUS, &status) < 0)
277 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "GETSTATUS", strerror(errno));
278 return 0;
280 *(int*)arg=(status & 0x02)? 100 : 0;
281 return TVI_CONTROL_TRUE;
284 case TVI_CONTROL_TUN_GET_TUNER:
285 case TVI_CONTROL_TUN_SET_TUNER:
287 /* Inputs */
289 case TVI_CONTROL_SPC_GET_INPUT:
291 if(ioctl(priv->btfd, METEORGINPUT, &priv->input) < 0)
293 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORGINPUT", strerror(errno));
294 return TVI_CONTROL_FALSE;
297 *(int *)arg = priv->input;
298 return TVI_CONTROL_TRUE;
301 case TVI_CONTROL_SPC_SET_INPUT:
303 priv->input = getinput(*(int *)arg);
305 if(ioctl(priv->btfd, METEORSINPUT, &priv->input) < 0)
307 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSINPUT", strerror(errno));
308 return 0;
311 return TVI_CONTROL_TRUE;
314 /* Audio Controls */
316 case TVI_CONTROL_IS_AUDIO:
317 if(priv->dspready == FALSE) return TVI_CONTROL_FALSE;
318 return TVI_CONTROL_TRUE;
320 case TVI_CONTROL_AUD_GET_FORMAT:
322 *(int *)arg = AF_FORMAT_S16_LE;
323 return TVI_CONTROL_TRUE;
325 case TVI_CONTROL_AUD_GET_CHANNELS:
327 *(int *)arg = 2;
328 return TVI_CONTROL_TRUE;
330 case TVI_CONTROL_AUD_SET_SAMPLERATE:
332 int dspspeed = *(int *)arg;
334 if(ioctl(priv->dspfd, SNDCTL_DSP_SPEED, &dspspeed) == -1)
336 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Invalid audio rate. Error: %s\n", strerror(errno));
337 return TVI_CONTROL_FALSE;
340 priv->dspspeed = dspspeed;
342 priv->dspframesize = priv->dspspeed*priv->dspsamplesize/8/
343 priv->fps * (priv->dspstereo+1);
344 priv->dsprate = priv->dspspeed * priv->dspsamplesize/8*
345 (priv->dspstereo+1);
347 return TVI_CONTROL_TRUE;
349 case TVI_CONTROL_AUD_GET_SAMPLERATE:
351 *(int *)arg = priv->dspspeed;
352 return TVI_CONTROL_TRUE;
354 case TVI_CONTROL_AUD_GET_SAMPLESIZE:
356 *(int *)arg = priv->dspsamplesize/8;
357 return TVI_CONTROL_TRUE;
360 /* Video Controls */
362 case TVI_CONTROL_IS_VIDEO:
363 if(priv->videoready == FALSE) return TVI_CONTROL_FALSE;
364 return TVI_CONTROL_TRUE;
366 case TVI_CONTROL_TUN_SET_NORM:
368 int req_mode = *(int *)arg;
369 u_short tmp_fps;
371 priv->iformat = METEOR_FMT_AUTOMODE;
373 if(req_mode == TV_NORM_PAL)
375 priv->iformat = METEOR_FMT_PAL;
376 priv->maxheight = PAL_HEIGHT;
377 priv->maxwidth = PAL_WIDTH;
378 priv->maxfps = PAL_FPS;
379 priv->fps = PAL_FPS;
381 if(priv->fps > priv->maxfps) priv->fps = priv->maxfps;
383 if(priv->geom.rows > priv->maxheight)
385 priv->geom.rows = priv->maxheight;
388 if(priv->geom.columns > priv->maxwidth)
390 priv->geom.columns = priv->maxwidth;
394 if(req_mode == TV_NORM_NTSC)
396 priv->iformat = METEOR_FMT_NTSC;
397 priv->maxheight = NTSC_HEIGHT;
398 priv->maxwidth = NTSC_WIDTH;
399 priv->maxfps = NTSC_FPS;
400 priv->fps = NTSC_FPS;
402 priv->dspframesize = priv->dspspeed*priv->dspsamplesize/8/
403 priv->fps * (priv->dspstereo+1);
404 priv->dsprate = priv->dspspeed * priv->dspsamplesize/8 *
405 (priv->dspstereo+1);
407 if(priv->fps > priv->maxfps) priv->fps = priv->maxfps;
409 if(priv->geom.rows > priv->maxheight)
411 priv->geom.rows = priv->maxheight;
414 if(priv->geom.columns > priv->maxwidth)
416 priv->geom.columns = priv->maxwidth;
420 if(req_mode == TV_NORM_SECAM) priv->iformat = METEOR_FMT_SECAM;
422 if(ioctl(priv->btfd, METEORSFMT, &priv->iformat) < 0)
424 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSFMT", strerror(errno));
425 return TVI_CONTROL_FALSE;
428 if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0)
430 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSETGEO", strerror(errno));
431 return 0;
434 tmp_fps = priv->fps;
435 if(ioctl(priv->btfd, METEORSFPS, &tmp_fps) < 0)
437 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSFPS", strerror(errno));
438 return 0;
441 #ifdef BT848_SAUDIO
442 if(priv->tunerready == TRUE &&
443 ioctl(priv->tunerfd, BT848_SAUDIO, &priv->tv_param->audio_id) < 0)
445 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "BT848_SAUDIO", strerror(errno));
447 #endif
449 return TVI_CONTROL_TRUE;
452 case TVI_CONTROL_VID_GET_FORMAT:
453 *(int *)arg = IMGFMT_UYVY;
454 return TVI_CONTROL_TRUE;
456 case TVI_CONTROL_VID_SET_FORMAT:
458 int req_fmt = *(int *)arg;
460 if(req_fmt != IMGFMT_UYVY) return TVI_CONTROL_FALSE;
462 return TVI_CONTROL_TRUE;
464 case TVI_CONTROL_VID_SET_WIDTH:
465 priv->geom.columns = *(int *)arg;
467 if(priv->geom.columns > priv->maxwidth)
469 priv->geom.columns = priv->maxwidth;
472 if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0)
474 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Error setting picture width. Error: %s\n", strerror(errno));
475 return 0;
478 return TVI_CONTROL_TRUE;
480 case TVI_CONTROL_VID_GET_WIDTH:
481 *(int *)arg = priv->geom.columns;
482 return TVI_CONTROL_TRUE;
484 case TVI_CONTROL_VID_SET_HEIGHT:
485 priv->geom.rows = *(int *)arg;
487 if(priv->geom.rows > priv->maxheight)
489 priv->geom.rows = priv->maxheight;
492 if(priv->geom.rows <= priv->maxheight / 2)
494 priv->geom.oformat |= METEOR_GEO_EVEN_ONLY;
497 if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0)
499 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Error setting picture width. Error: %s\n", strerror(errno));
500 return 0;
503 return TVI_CONTROL_TRUE;
505 case TVI_CONTROL_VID_GET_HEIGHT:
506 *(int *)arg = priv->geom.rows;
507 return TVI_CONTROL_TRUE;
509 case TVI_CONTROL_VID_GET_FPS:
510 *(float *)arg = priv->fps;
511 return TVI_CONTROL_TRUE;
514 case TVI_CONTROL_VID_SET_FPS:
515 priv->fps = *(int *)arg;
517 if(priv->fps > priv->maxfps) priv->fps = priv->maxfps;
519 if(ioctl(priv->btfd, METEORSFPS, &priv->fps) < 0)
521 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSFPS", strerror(errno));
522 return 0;
525 return TVI_CONTROL_TRUE;
528 case TVI_CONTROL_VID_CHK_WIDTH:
529 case TVI_CONTROL_VID_CHK_HEIGHT:
530 return TVI_CONTROL_TRUE;
532 case TVI_CONTROL_IMMEDIATE:
533 priv->immediatemode = TRUE;
534 return TVI_CONTROL_TRUE;
537 return TVI_CONTROL_UNKNOWN;
540 static int init(priv_t *priv)
542 int marg;
543 int count;
544 u_short tmp_fps;
546 G_private = priv; /* Oooh, sick */
548 /* Video Configuration */
550 priv->videoready = TRUE;
551 priv->immediatemode = FALSE;
552 priv->iformat = METEOR_FMT_PAL;
553 priv->maxheight = PAL_HEIGHT;
554 priv->maxwidth = PAL_WIDTH;
555 priv->maxfps = PAL_FPS;
556 priv->source = METEOR_INPUT_DEV0;
557 priv->fps = priv->maxfps;
559 priv->starttime=0;
560 priv->curpaintframe=0;
561 priv->curbufframe=0;
563 priv->geom.columns = priv->maxwidth;
564 priv->geom.rows = priv->maxheight;
565 priv->geom.frames = 1;
566 priv->geom.oformat = METEOR_GEO_YUV_PACKED;
568 priv->btfd = open(priv->btdev, O_RDONLY);
570 if(priv->btfd < 0)
572 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Unable to open bktr device. Error: %s\n", strerror(errno));
573 priv->videoready = FALSE;
576 if(priv->videoready == TRUE &&
577 ioctl(priv->btfd, METEORSFMT, &priv->iformat) < 0)
579 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "SETEORSFMT", strerror(errno));
582 if(priv->videoready == TRUE &&
583 ioctl(priv->btfd, METEORSINPUT, &priv->source) < 0)
585 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSINPUT", strerror(errno));
588 tmp_fps = priv->fps;
589 if(priv->videoready == TRUE &&
590 ioctl(priv->btfd, METEORSFPS, &tmp_fps) < 0)
592 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSFPS", strerror(errno));
595 if(priv->videoready == TRUE &&
596 ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0)
598 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSGEQ", strerror(errno));
601 if(priv->videoready == TRUE)
603 priv->framebufsize = (priv->geom.columns * priv->geom.rows * 2);
605 priv->livebuf = (u_char *)mmap((caddr_t)0, priv->framebufsize, PROT_READ,
606 MAP_SHARED, priv->btfd, (off_t)0);
608 if(priv->livebuf == (u_char *) MAP_FAILED)
610 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: mmap failed. Error: %s\n", strerror(errno));
611 priv->videoready = FALSE;
614 for(count=0;count<RINGSIZE;count++)
616 priv->framebuf[count].buf = malloc(priv->framebufsize);
618 if(priv->framebuf[count].buf == NULL)
620 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Frame buffer allocation failed. Error: %s\n", strerror(errno));
621 priv->videoready = FALSE;
622 break;
625 priv->framebuf[count].dirty = TRUE;
626 priv->framebuf[count].timestamp = 0;
630 /* Tuner Configuration */
632 priv->tunerready = TRUE;
634 priv->tunerfd = open(priv->tunerdev, O_RDONLY);
636 if(priv->tunerfd < 0)
638 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Unable to open tuner device. Error: %s\n", strerror(errno));
639 priv->tunerready = FALSE;
642 /* Audio Configuration */
644 priv->dspready = TRUE;
645 priv->dspsamplesize = 16;
646 priv->dspstereo = 1;
647 priv->dspspeed = 44100;
648 priv->dspfmt = AFMT_S16_LE;
649 priv->dspbytesread = 0;
650 priv->dsprate = priv->dspspeed * priv->dspsamplesize/8*(priv->dspstereo+1);
651 priv->dspframesize = priv->dspspeed*priv->dspsamplesize/8/priv->fps *
652 (priv->dspstereo+1);
654 if((priv->dspfd = open (priv->dspdev, O_RDONLY, 0)) < 0)
656 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Unable to open dsp device. Error: %s\n", strerror(errno));
657 priv->dspready = FALSE;
660 marg = (256 << 16) | 12;
662 if (ioctl(priv->dspfd, SNDCTL_DSP_SETFRAGMENT, &marg ) < 0 )
664 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "SNDCTL_DSP_SETFRAGMENT", strerror(errno));
665 priv->dspready = FALSE;
668 if((priv->dspready == TRUE) &&
669 ((ioctl(priv->dspfd, SNDCTL_DSP_SAMPLESIZE, &priv->dspsamplesize) == -1) ||
670 (ioctl(priv->dspfd, SNDCTL_DSP_STEREO, &priv->dspstereo) == -1) ||
671 (ioctl(priv->dspfd, SNDCTL_DSP_SPEED, &priv->dspspeed) == -1) ||
672 (ioctl(priv->dspfd, SNDCTL_DSP_SETFMT, &priv->dspfmt) == -1)))
674 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Configuration of dsp failed. Error: %s\n", strerror(errno));
675 close(priv->dspfd);
676 priv->dspready = FALSE;
679 return 1;
682 /* that's the real start, we'got the format parameters (checked with control) */
683 static int start(priv_t *priv)
685 int tmp;
686 struct timeval curtime;
687 int marg;
689 fprintf(stderr,"START\n");
690 if(priv->videoready == FALSE) return 0;
692 signal(SIGUSR1, processframe);
693 signal(SIGALRM, processframe);
695 marg = SIGUSR1;
697 if(ioctl(priv->btfd, METEORSSIGNAL, &marg) < 0)
699 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSSIGNAL", strerror(errno));
700 return 0;
703 read(priv->dspfd, &tmp, 2);
705 gettimeofday(&curtime, NULL);
707 priv->starttime = curtime.tv_sec + (curtime.tv_usec *.000001);
709 marg = METEOR_CAP_CONTINOUS;
711 if(ioctl(priv->btfd, METEORCAPTUR, &marg) < 0)
713 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORCAPTUR", strerror(errno));
714 return 0;
717 return 1;
720 static int uninit(priv_t *priv)
722 int marg;
724 if(priv->videoready == FALSE) return 0;
726 marg = METEOR_SIG_MODE_MASK;
728 if(ioctl( priv->btfd, METEORSSIGNAL, &marg) < 0 )
730 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "METEORSSIGNAL", strerror(errno));
731 return 0;
734 marg = METEOR_CAP_STOP_CONT;
736 if(ioctl(priv->btfd, METEORCAPTUR, &marg) < 0 )
738 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Unable to stop capture. Error: %s\n", strerror(errno));
739 return 0;
742 close(priv->btfd);
743 close(priv->dspfd);
745 priv->dspfd = -1;
746 priv->btfd = -1;
748 priv->dspready = priv->videoready = FALSE;
750 return 1;
754 static double grabimmediate_video_frame(priv_t *priv, char *buffer, int len)
756 sigset_t sa_mask;
758 if(priv->videoready == FALSE) return 0;
760 alarm(1);
761 sigfillset(&sa_mask);
762 sigdelset(&sa_mask,SIGINT);
763 sigdelset(&sa_mask,SIGUSR1);
764 sigdelset(&sa_mask,SIGALRM);
765 sigsuspend(&sa_mask);
766 alarm(0);
768 memcpy(buffer, priv->livebuf, len);
770 /* PTS = 0, show the frame NOW, this routine is only used in playback mode
771 without audio capture .. */
773 return 0;
776 static double grab_video_frame(priv_t *priv, char *buffer, int len)
778 double timestamp=0;
779 sigset_t sa_mask;
781 if(priv->videoready == FALSE) return 0;
783 if(priv->immediatemode == TRUE)
785 return grabimmediate_video_frame(priv, buffer, len);
788 while(priv->framebuf[priv->curbufframe].dirty == TRUE)
790 alarm(1);
791 sigemptyset(&sa_mask);
792 sigsuspend(&sa_mask);
793 alarm(0);
796 memcpy(buffer, priv->framebuf[priv->curbufframe].buf, len);
797 timestamp = priv->framebuf[priv->curbufframe].timestamp;
798 priv->framebuf[priv->curbufframe].dirty = TRUE;
800 priv->curbufframe++;
801 if(priv->curbufframe >= RINGSIZE) priv->curbufframe = 0;
803 return timestamp-priv->starttime;
806 static int get_video_framesize(priv_t *priv)
808 return priv->geom.columns * priv->geom.rows * 16 / 8;
811 static double grab_audio_frame(priv_t *priv, char *buffer, int len)
813 struct timeval curtime;
814 double curpts;
815 double timeskew;
816 int bytesread;
817 int ret;
819 if(priv->dspready == FALSE) return 0;
821 gettimeofday(&curtime, NULL);
823 /* Get exactly one frame of audio, which forces video sync to audio.. */
825 bytesread=read(priv->dspfd, buffer, len);
827 while(bytesread < len)
829 ret=read(priv->dspfd, &buffer[bytesread], len-bytesread);
831 if(ret == -1)
833 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Error reading audio data. Error: %s\n", strerror(errno));
834 return 0;
837 bytesread+=ret;
840 priv->dspbytesread += bytesread;
842 curpts = curtime.tv_sec + curtime.tv_usec * .000001;
844 timeskew = priv->dspbytesread * 1.0 / priv->dsprate - (curpts-priv->starttime);
846 if(timeskew > .125/priv->fps)
848 priv->starttime -= timeskew;
850 else
852 if(timeskew < -.125/priv->fps)
854 priv->starttime -= timeskew;
858 return priv->dspbytesread * 1.0 / priv->dsprate;
861 static int get_audio_framesize(priv_t *priv)
863 int bytesavail;
864 #ifdef CONFIG_SUN_AUDIO
865 struct audio_info auinf;
866 #endif
868 if(priv->dspready == FALSE) return 0;
870 #ifdef CONFIG_SUN_AUDIO
871 if(ioctl(priv->dspfd, AUDIO_GETINFO, &auinf) < 0)
873 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "AUDIO_GETINFO", strerror(errno));
874 return TVI_CONTROL_FALSE;
876 else
877 bytesavail = auinf.record.seek; /* *priv->dspsamplesize; */
878 #else
879 if(ioctl(priv->dspfd, FIONREAD, &bytesavail) < 0)
881 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_bsdbt848: Call to %s ioctl failed. Error: %s\n", "FIONREAD", strerror(errno));
882 return TVI_CONTROL_FALSE;
884 #endif
886 /* When mencoder wants audio data, it wants data..
887 it won't go do anything else until it gets it :( */
889 if(bytesavail == 0) return FRAGSIZE;
891 return bytesavail;
894 static int getinput(int innumber)
896 switch(innumber)
898 case 0: return METEOR_INPUT_DEV0; /* RCA */
899 case 1: return METEOR_INPUT_DEV1; /* Tuner */
900 case 2: return METEOR_INPUT_DEV2; /* In 1 */
901 case 3: return METEOR_INPUT_DEV3; /* In 2 */
902 case 4: return METEOR_INPUT_DEV_RGB; /* RGB */
903 case 5: return METEOR_INPUT_DEV_SVIDEO; /* SVid */
906 return 0;