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
8 * v1.0 Feb 19 2002 First Release, need to add support for changing
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.
33 #define FRAGSIZE 4096 /* (2^12 see SETFRAGSIZE below) */
39 #define PAL_HEIGHT 576
42 #define NTSC_WIDTH 640
43 #define NTSC_HEIGHT 480
44 #define NTSC_FPS 29.97
50 #include <sys/types.h>
52 #include <sys/filio.h>
58 #include <sys/param.h>
59 #ifdef CONFIG_SUN_AUDIO
60 #include <sys/audioio.h>
63 #ifdef IOCTL_METEOR_H_NAME
64 #include IOCTL_METEOR_H_NAME
67 #ifdef IOCTL_BT848_H_NAME
68 #include IOCTL_BT848_H_NAME
71 #ifdef HAVE_SYS_SOUNDCARD_H
72 #include <sys/soundcard.h>
74 #ifdef HAVE_SOUNDCARD_H
75 #include <soundcard.h>
77 #include <machine/soundcard.h>
81 #include "libaf/af_format.h"
82 #include "libmpcodecs/img_format.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
= {
90 "Brooktree848 Support",
103 typedef struct priv
{
115 long long dspbytesread
;
127 struct meteor_geomet geom
;
128 struct meteor_capframe capframe
;
136 unsigned char *livebuf
;
137 RBFRAME framebuf
[RINGSIZE
];
149 struct bktr_chnlset cset
;
156 tv_param_t
*tv_param
;
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;
191 /* handler creator - entry point ! */
192 static tvi_handle_t
*tvi_init_bsdbt848(tv_param_t
* tv_param
)
198 tvh
= tv_new_handle(sizeof(priv_t
), &functions
);
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");
212 sep
= strchr(tv_param
->device
,',');
213 priv
->btdev
= strdup(tv_param
->device
);
215 // tuner device is also passed
216 priv
->tunerdev
= strdup(sep
+1);
217 priv
->btdev
[sep
- tv_param
->device
] = 0;
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");
228 priv
->dspdev
= strdup("/dev/dsp");
231 priv
->dspdev
= strdup(tv_param
->adevice
);
233 priv
->tv_param
=tv_param
;
237 static int control(priv_t
*priv
, int cmd
, void *arg
)
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
));
270 return TVI_CONTROL_TRUE
;
272 case TVI_CONTROL_TUN_GET_SIGNAL
:
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
));
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
:
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
));
311 return TVI_CONTROL_TRUE
;
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
:
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*
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
;
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
;
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
;
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 *
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
));
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
));
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
));
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
));
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
));
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));
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
)
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
;
560 priv
->curpaintframe
=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
);
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
));
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
;
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;
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
*
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
));
676 priv
->dspready
= FALSE
;
682 /* that's the real start, we'got the format parameters (checked with control) */
683 static int start(priv_t
*priv
)
686 struct timeval curtime
;
689 fprintf(stderr
,"START\n");
690 if(priv
->videoready
== FALSE
) return 0;
692 signal(SIGUSR1
, processframe
);
693 signal(SIGALRM
, processframe
);
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
));
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
));
720 static int uninit(priv_t
*priv
)
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
));
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
));
748 priv
->dspready
= priv
->videoready
= FALSE
;
754 static double grabimmediate_video_frame(priv_t
*priv
, char *buffer
, int len
)
758 if(priv
->videoready
== FALSE
) return 0;
761 sigfillset(&sa_mask
);
762 sigdelset(&sa_mask
,SIGINT
);
763 sigdelset(&sa_mask
,SIGUSR1
);
764 sigdelset(&sa_mask
,SIGALRM
);
765 sigsuspend(&sa_mask
);
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 .. */
776 static double grab_video_frame(priv_t
*priv
, char *buffer
, int len
)
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
)
791 sigemptyset(&sa_mask
);
792 sigsuspend(&sa_mask
);
796 memcpy(buffer
, priv
->framebuf
[priv
->curbufframe
].buf
, len
);
797 timestamp
= priv
->framebuf
[priv
->curbufframe
].timestamp
;
798 priv
->framebuf
[priv
->curbufframe
].dirty
= TRUE
;
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
;
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
);
833 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_bsdbt848: Error reading audio data. Error: %s\n", strerror(errno
));
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
;
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
)
864 #ifdef CONFIG_SUN_AUDIO
865 struct audio_info auinf
;
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
;
877 bytesavail
= auinf
.record
.seek
; /* *priv->dspsamplesize; */
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
;
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
;
894 static int getinput(int 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 */