1 /*
2 * tvcapture.c
3 *
4 * API for controlling the capture card attributes and state.
5 *
6 * (C) 1997 Randall Hopper
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met: 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 2.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 */
29
30 /* ******************** Include Files ************** */
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <sys/types.h>
38 #include <sys/mman.h>
39 #ifdef __NetBSD__
40 # include <dev/ic/bt8xx.h>
41 #endif
42 #ifdef __FreeBSD__
43 #include <osreldate.h>
44 #if __FreeBSD_version > 500000
45 #include <dev/bktr/ioctl_bt848.h>
46 #else
47 #include <machine/ioctl_bt848.h>
48 #endif
49 #endif
50 #include <signal.h>
51 #include <sys/ioctl.h>
52 #include <unistd.h>
53 #include "tvdefines.h"
54 #include "tvtypes.h"
55 #include "tvcapture.h"
56 #include "app_rsrc.h"
57 #include "glob.h"
58
59 /* ******************** Local defines ************** */
60
61 /* For Fxtv 0.41/bktr driver Linux port -- remove when the latest is ported */
62 #ifdef OLD_TUNER_IFACE
63 # define BT848SFMT METEORSFMT
64 #endif
65
66 #ifndef linux
67 # define DEV_BT848 "/dev/bktr%d"
68 # define DEV_TUNER "/dev/tuner%d"
69 #else
70 # warning FIXME: Does/how does Linux name multiple devices of the same type
71 # warning Is there a consistent policy as in FreeBSD?
72 # define DEV_BT848 "/dev/bt848"
73 # define DEV_TUNER "/dev/bt848t"
74 #endif
75
76 /* Macros */
77 #define DO_IOCTL_GERR(str) fprintf(stderr, "ioctl(%s) failed: %s\n", \
78 str, strerror(errno) )
79 #define DO_IOCTL_SERR(str,arg) fprintf(stderr, "ioctl(%s, %ld) failed: %s\n",\
80 str, (long)arg, strerror(errno) )
81
82 #define HUE_MIN BT848_HUEMIN
83 #define HUE_MAX (BT848_HUEMIN + BT848_HUERANGE)
84 #define HUE_RANGE BT848_HUERANGE
85 #define HUE_DRV_MIN BT848_HUEREGMIN
86 #define HUE_DRV_RANGE (BT848_HUEREGMAX - BT848_HUEREGMIN + 1)
87
88 #define BRIGHT_MIN BT848_BRIGHTMIN
89 #define BRIGHT_MAX (BT848_BRIGHTMIN + BT848_BRIGHTRANGE)
90 #define BRIGHT_RANGE BT848_BRIGHTRANGE
91 #define BRIGHT_DRV_MIN BT848_BRIGHTREGMIN
92 #define BRIGHT_DRV_RANGE (BT848_BRIGHTREGMAX - BT848_BRIGHTREGMIN + 1)
93
94 #define CONTR_MIN BT848_CONTRASTMIN
95 #define CONTR_MAX (BT848_CONTRASTMIN + BT848_CONTRASTRANGE)
96 #define CONTR_RANGE BT848_CONTRASTRANGE
97 #define CONTR_DRV_MIN BT848_CONTRASTREGMIN
98 #define CONTR_DRV_RANGE (BT848_CONTRASTREGMAX - BT848_CONTRASTREGMIN + 1)
99
100 #define SATU_MIN BT848_SATUMIN
101 #define SATU_MAX (BT848_SATUMIN + BT848_SATURANGE)
102 #define SATU_RANGE BT848_SATURANGE
103 #define SATU_DRV_MIN BT848_SATUREGMIN
104 #define SATU_DRV_RANGE (BT848_SATUREGMAX - BT848_SATUREGMIN + 1)
105
106 #define SATV_MIN BT848_SATVMIN
107 #define SATV_MAX (BT848_SATVMIN + BT848_SATVRANGE)
108 #define SATV_RANGE BT848_SATVRANGE
109 #define SATV_DRV_MIN BT848_SATVREGMIN
110 #define SATV_DRV_RANGE (BT848_SATVREGMAX - BT848_SATVREGMIN + 1)
111
112 #define NTSC_DIM_X 640
113 #define NTSC_DIM_Y 480
114 #define NTSC_FPS 30
115 #define PAL_DIM_X 768
116 #define PAL_DIM_Y 576
117 #define PAL_FPS 25
118
119 /* Max Single Frame Size (in bytes) for NTSC & PAL (4Bpp max) */
120 #define MAX_MMAP_BUF_SIZE ( MAX( NTSC_DIM_X,PAL_DIM_X ) * \
121 MAX( NTSC_DIM_Y,PAL_DIM_Y ) * 4 )
122
123 #define FRAME_TIMER_DELAY_MS(fps) (1000/(fps))
124
125 /* ******************** Private variables ************** */
126
127 static TV_INT32 S_frame_done_count = 0;
128
129 static XtIntervalId S_frame_timer;
130 static TV_BOOL S_frame_timer_set = False;
131
132
133 /* ******************** Forward declarations ************** */
134 /* ******************** Function Definitions ************** */
135
136 /**@BEGINFUNC**************************************************************
137
138 Prototype : static void TVCAPTUREDestroy()
139
140 Purpose : Cleans up capture attributes (stops capture, closes files,
141 frees mem, etc.
142
143 Programmer : 07-Mar-97 Randall Hopper
144
145 Parameters : None.
146
147 Returns : None.
148
149 Globals : None.
150
151 **@ENDFUNC*****************************************************************/
152
TVCAPTUREDestroy()153 static void TVCAPTUREDestroy()
154 {
155 TV_CAPTURE *c = &G_glob.capture;
156
157 if ( c->fd >= 0 ) {
158 if ( c->contin_on )
159 TVCAPTUREStop( c );
160
161 close( c->fd );
162 }
163 if ( c->tfd >= 0 )
164 close( c->tfd );
165 }
166
167
168 /**@BEGINFUNC**************************************************************
169
170 Prototype : static void TVCAPTUREFrameDoneSigHdlr()
171
172 Purpose : Called when the driver finishes capturing a frame.
173
174 Programmer : 07-Mar-97 Randall Hopper
175
176 Parameters : None.
177
178 Returns : None.
179
180 Globals : None.
181
182 **@ENDFUNC*****************************************************************/
183
TVCAPTUREFrameDoneSigHdlr()184 static void TVCAPTUREFrameDoneSigHdlr()
185 {
186 S_frame_done_count++;
187 #ifdef linux
188 # warning Huh? Do signal handlers get unregistered in Linux after delivery?
189 signal( SIGUSR1, TVCAPTUREFrameDoneSigHdlr );
190 #endif
191 }
192
193 /**@BEGINFUNC**************************************************************
194
195 Prototype : void TVCAPTUREWorkProc()
196
197 Purpose : Xt work proc slave routine invoked to initiate behaviors
198 associated with capturing frames.
199
200 Programmer : 07-Mar-97 Randall Hopper
201
202 Parameters : None.
203
204 Returns : None.
205
206 Globals : None.
207
208 **@ENDFUNC*****************************************************************/
209
TVCAPTUREWorkProc()210 void TVCAPTUREWorkProc()
211 {
212 static TV_CAPTURE *c = &G_glob.capture;
213 TV_IMAGE img;
214
215 if (( S_frame_done_count == 0 ) || ( c->frame_done_cb == NULL ))
216 return;
217
218 /* if ( S_frame_done_count > 0 )
219 DRVPRINTF(( "%d frames behind\n", S_frame_done_count ));
220 */
221 S_frame_done_count--;
222
223 img.buf = c->drv_buf;
224 memcpy( &img.geom, &c->geom, sizeof( img.geom ) );
225 memcpy( &img.pix_geom, &c->pix_geom_list[ c->pix_geom_idx ],
226 sizeof( img.pix_geom ) );
227 c->frame_done_cb( &img );
228 }
229
230 /* TVCAPTUREClearPendingFrames: Reset/ignore any outstanding frames. */
TVCAPTUREClearPendingFrames()231 void TVCAPTUREClearPendingFrames()
232 {
233 S_frame_done_count = 0;
234 }
235
236 /* TVCAPTUREGetPendingFrame - Get pending frame & ret T (ret F if none) */
TVCAPTUREGetPendingFrame(TV_IMAGE ** img)237 TV_BOOL TVCAPTUREGetPendingFrame( TV_IMAGE **img )
238 {
239 if ( S_frame_done_count > 0 ) {
240 /* FIXME: Share this glob -- it's the WorkProc above w/o CB */
241 static TV_CAPTURE *c = &G_glob.capture;
242 static TV_IMAGE image;
243
244 if (( S_frame_done_count == 0 ) || ( c->frame_done_cb == NULL ))
245 return FALSE;
246
247 if ( S_frame_done_count-- > 0 )
248 DRVPRINTF(( "%ld frames behind\n", S_frame_done_count ));
249
250 image.buf = c->drv_buf;
251 memcpy( &image.geom, &c->geom, sizeof( image.geom ) );
252 memcpy( &image.pix_geom, &c->pix_geom_list[ c->pix_geom_idx ],
253 sizeof( image.pix_geom ) );
254 *img = ℑ
255 return TRUE;
256 }
257 else {
258 *img = NULL;
259 return FALSE;
260 }
261 }
262
263
264 #ifdef OLD_ALWAYS_USE_SIGNALS_NOW
265 /**@BEGINFUNC**************************************************************
266
267 Prototype : static void TVCAPTUREFrameTimeoutCB(
268 XtPointer cl_data,
269 XtIntervalId *timer )
270
271 Purpose : Invoked during continuous capture to let us kick in
272 frame done callback periodically (since signals aren't
273 issued by the driver for frame completes when in
274 continuous mode).
275
276 Programmer : 08-Mar-97 Randall Hopper
277
278 Parameters : cl_data - I: not used
279 timer - I: not used
280
281 Returns :
282
283 Globals : None.
284
285 **@ENDFUNC*****************************************************************/
286
TVCAPTUREFrameTimeoutCB(XtPointer cl_data,XtIntervalId * timer)287 static void TVCAPTUREFrameTimeoutCB(
288 XtPointer cl_data,
289 XtIntervalId *timer )
290 {
291 TV_CAPTURE *c = &G_glob.capture;
292 TV_IMAGE img;
293
294 /* Invoke user-defined frame completion callback */
295 if ( c->frame_done_cb != NULL ) {
296 img.buf = c->drv_buf;
297 memcpy( &img.geom, &c->geom, sizeof( img.geom ) );
298 memcpy( &img.pix_geom, &c->pix_geom_list[ c->pix_geom_idx ],
299 sizeof( img.pix_geom ) );
300 c->frame_done_cb( &img );
301 }
302
303 /* And restart timer for another "frame" */
304 S_frame_timer = XtAppAddTimeOut( TVAPPCTX,
305 FRAME_TIMER_DELAY_MS(c->fps_max),
306 TVCAPTUREFrameTimeoutCB, NULL );
307 }
308 #endif
309
310
TVCAPTURESetBrightness(TV_CAPTURE * c,double brightness)311 void TVCAPTURESetBrightness( TV_CAPTURE *c, double brightness )
312 {
313 TV_INT32 larg;
314
315 brightness = MAX( BRIGHT_MIN, MIN( BRIGHT_MAX, brightness ) );
316
317 larg = (brightness - BRIGHT_MIN) / (BRIGHT_RANGE + 0.01)
318 * BRIGHT_DRV_RANGE + BRIGHT_DRV_MIN;
319 larg = MAX( BRIGHT_DRV_MIN,
320 MIN( BRIGHT_DRV_MIN+BRIGHT_DRV_RANGE-1, larg ));
321
322 if ( ioctl( c->tfd, BT848_SBRIG, &larg ) < 0 ) {
323 DO_IOCTL_SERR( "BT848_SBRIG", larg );
324 return;
325 }
326
327 /* FIXME: Dead code */
328 c->brightness = brightness;
329 }
330
331
TVCAPTURESetContrast(TV_CAPTURE * c,double contrast)332 void TVCAPTURESetContrast( TV_CAPTURE *c, double contrast )
333 {
334 TV_INT32 larg;
335
336 contrast = MIN( CONTR_MAX, MAX( CONTR_MIN, contrast ) );
337
338 larg = (contrast - CONTR_MIN) / (CONTR_RANGE + 0.01)
339 * CONTR_DRV_RANGE + CONTR_DRV_MIN;
340 larg = MAX( CONTR_DRV_MIN,
341 MIN( CONTR_DRV_MIN+CONTR_DRV_RANGE-1, larg ) );
342
343 if ( ioctl( c->tfd, BT848_SCONT, &larg ) < 0 ) {
344 DO_IOCTL_SERR( "BT848_SCONT", larg );
345 return;
346 }
347
348 /* FIXME: Dead code */
349 c->contrast = contrast;
350 }
351
352
TVCAPTURESetHue(TV_CAPTURE * c,double hue)353 void TVCAPTURESetHue( TV_CAPTURE *c, double hue )
354 {
355 TV_INT32 larg;
356
357 hue = MIN( HUE_MAX, MAX( HUE_MIN, hue ) );
358 larg = (hue - HUE_MIN) / (HUE_RANGE + 0.01)
359 * HUE_DRV_RANGE + HUE_DRV_MIN;
360 larg = MAX( HUE_DRV_MIN,
361 MIN( HUE_DRV_MIN+HUE_DRV_RANGE-1, larg ));
362
363 if ( ioctl( c->tfd, BT848_SHUE, &larg ) < 0 ) {
364 DO_IOCTL_SERR( "BT848_SHUE", larg );
365 return;
366 }
367
368 /* FIXME: Dead code */
369 c->hue = hue;
370 }
371
372
TVCAPTURESetSatU(TV_CAPTURE * c,double sat_u)373 void TVCAPTURESetSatU( TV_CAPTURE *c, double sat_u )
374 {
375 TV_INT32 larg;
376
377 sat_u = MIN( SATU_MAX, MAX( SATU_MIN, sat_u ) );
378 larg = (sat_u - SATU_MIN) / (SATU_RANGE + 0.01)
379 * SATU_DRV_RANGE + SATU_DRV_MIN;
380 larg = MAX( SATU_DRV_MIN,
381 MIN( SATU_DRV_MIN+SATU_DRV_RANGE-1, larg ) );
382
383 if ( ioctl( c->tfd, BT848_SUSAT, &larg ) < 0 ) {
384 DO_IOCTL_SERR( "BT848_SUSAT", larg );
385 return;
386 }
387
388 /* FIXME: Dead code */
389 c->sat_u = sat_u;
390 }
391
392
TVCAPTURESetSatV(TV_CAPTURE * c,double sat_v)393 void TVCAPTURESetSatV( TV_CAPTURE *c, double sat_v )
394 {
395 TV_INT32 larg;
396
397 sat_v = MIN( SATV_MAX, MAX( SATV_MIN, sat_v ) );
398 larg = (sat_v - SATV_MIN) / (SATV_RANGE + 0.01)
399 * SATV_DRV_RANGE + SATV_DRV_MIN;
400 larg = MAX( SATV_DRV_MIN,
401 MIN( SATV_DRV_MIN+SATV_DRV_RANGE-1, larg ) );
402
403 if ( ioctl( c->tfd, BT848_SVSAT, &larg ) < 0 ) {
404 DO_IOCTL_SERR( "BT848_SVSAT", larg );
405 return;
406 }
407
408 /* FIXME: Dead code */
409 c->sat_v = sat_v;
410 }
411
TVCAPTURESetAppearanceParam(TV_CAPTURE * c,TV_DRIVER_PARAM p,double val)412 void TVCAPTURESetAppearanceParam( TV_CAPTURE *c, TV_DRIVER_PARAM p,
413 double val )
414 {
415 switch ( p ) {
416 case TV_PARAM_HUE : TVCAPTURESetHue ( c, val ); break;
417 case TV_PARAM_BRIGHT : TVCAPTURESetBrightness( c, val ); break;
418 case TV_PARAM_CONTRAST : TVCAPTURESetContrast ( c, val ); break;
419 case TV_PARAM_SATU : TVCAPTURESetSatU ( c, val ); break;
420 case TV_PARAM_SATV : TVCAPTURESetSatV ( c, val ); break;
421 default :
422 fprintf( stderr,
423 "TVCAPTURESetAppearanceParam: Unsupported param %d\n", p );
424 exit(1);
425 }
426 }
427
TVCAPTURESetInputFormat(TV_CAPTURE * c,TV_INPUT_FORMAT format)428 void TVCAPTURESetInputFormat( TV_CAPTURE *c, TV_INPUT_FORMAT format )
429 {
430 TV_INT32 larg;
431
432 switch ( format ) {
433 case TV_INPUT_NTSCM : larg = BT848_IFORM_F_NTSCM ; break;
434 case TV_INPUT_NTSCJ : larg = BT848_IFORM_F_NTSCJ ; break;
435 case TV_INPUT_PALBDGHI : larg = BT848_IFORM_F_PALBDGHI; break;
436 case TV_INPUT_PALM : larg = BT848_IFORM_F_PALM ; break;
437 case TV_INPUT_PALN : larg = BT848_IFORM_F_PALN ; break;
438 case TV_INPUT_SECAM : larg = BT848_IFORM_F_SECAM ; break;
439 case TV_INPUT_PALNCOMB : larg = BT848_IFORM_F_RSVD ; break;
440 default :
441 case TV_INPUT_AUTO :
442 fprintf( stderr,
443 "TVCAPTURESetInputFormat: Unsupported format %d\n", format );
444 exit(1);
445 }
446 if ( ioctl( c->fd, BT848SFMT, &larg ) < 0 ) {
447 DO_IOCTL_SERR( "BT848SFMT", larg );
448 return;
449 }
450
451 /* Update max capture size based on driver format */
452 /* FIXME: These belong in the driver/driver include file */
453 switch ( format ) {
454 case TV_INPUT_NTSCM :
455 case TV_INPUT_NTSCJ :
456 case TV_INPUT_PALM :
457 c->width_max = NTSC_DIM_X;
458 c->height_max = NTSC_DIM_Y;
459 c->fps_max = NTSC_FPS;
460 break;
461 case TV_INPUT_PALBDGHI :
462 case TV_INPUT_PALN :
463 case TV_INPUT_SECAM :
464 case TV_INPUT_PALNCOMB :
465 c->width_max = PAL_DIM_X;
466 c->height_max = PAL_DIM_Y;
467 c->fps_max = PAL_FPS;
468 break;
469 case TV_INPUT_AUTO :
470 abort();
471 }
472 /* FIXME: Dead code */
473 c->input_format = format;
474 }
475
476
TVCAPTURESetInputDevice(TV_CAPTURE * c,TV_INPUT_DEVICE dev)477 void TVCAPTURESetInputDevice( TV_CAPTURE *c, TV_INPUT_DEVICE dev )
478 {
479 int arg,
480 old_audio;
481
482 /* FIXME: Move all driver set calls out of Start() into these */
483 /* set calls. */
484 if ( c->contin_on ) {
485 fprintf( stderr,
486 "TVCAPTURESetInputDevice(): Called when capture is on\n" );
487 return;
488 }
489
490 /* Driver FIXME: Hack to get around driver unmuting audio across */
491 /* channel, freq, and input device changes. */
492 if ( ioctl( c->tfd, BT848_GAUDIO, &old_audio ) < 0 ) {
493 DO_IOCTL_GERR( "BT848_GAUDIO" );
494 return;
495 }
496
497 switch ( dev ) {
498 case TV_DEVICE_TUNER : arg = METEOR_INPUT_DEV1; break;
499 case TV_DEVICE_VIDEO : arg = METEOR_INPUT_DEV0; break;
500 case TV_DEVICE_SVIDEO : arg = METEOR_INPUT_DEV_SVIDEO; break;
501 case TV_DEVICE_CSVIDEO : arg = METEOR_INPUT_DEV2; break;
502 #ifdef METEOR_INPUT_DEV3
503 case TV_DEVICE_DEV3 : arg = METEOR_INPUT_DEV3; break;
504 #endif
505 default :
506 fprintf( stderr, "TVCAPTURESetInputDevice(): Bad value %d\n",
507 dev );
508 return;
509 }
510 if ( ioctl( c->fd, METEORSINPUT, &arg ) < 0 ) {
511 fprintf( stderr, "ioctl(METEORSINPUT, %d) failed: %s\n",
512 arg, strerror(errno) );
513 return;
514 }
515
516 /* FIXME: Dead code */
517 c->input_dev = arg;
518
519 /* When we did that last SINPUT, the driver auto-selected the */
520 /* audio input correct for that video input. Override it */
521 /* if the user has requested this. */
522 if ( c->audio_input_dev != TV_AUDIO_INPUT_AUTO ) {
523 switch ( c->audio_input_dev ) {
524 default :
525 case TV_AUDIO_INPUT_TUNER : arg = AUDIO_TUNER; break;
526 case TV_AUDIO_INPUT_EXTERN : arg = AUDIO_EXTERN; break;
527 case TV_AUDIO_INPUT_INTERN : arg = AUDIO_INTERN; break;
528 }
529 if ( ioctl( c->tfd, BT848_SAUDIO, &arg ) < 0 ) {
530 fprintf( stderr, "ioctl(BT848_SAUDIO, %d) failed: %s\n",
531 arg, strerror(errno) );
532 return;
533 }
534 }
535
536 /* Restore the old mute setting */
537 old_audio &= AUDIO_MUTE;
538 if ( old_audio )
539 TVCAPTURESetAudioMute( c, TRUE );
540 }
541
542
TVCAPTURESetAudioInputDevice(TV_CAPTURE * c,TV_AUDIO_INPUT_DEVICE dev)543 void TVCAPTURESetAudioInputDevice( TV_CAPTURE *c, TV_AUDIO_INPUT_DEVICE dev )
544 {
545 int arg;
546
547 /* FIXME: Move all driver set calls out of Start() into these */
548 /* set calls. */
549 if ( c->contin_on ) {
550 fprintf( stderr,
551 "TVCAPTURESetAudioInputDevice(): "
552 "Called when capture is on\n" );
553 return;
554 }
555
556 switch ( dev ) {
557 case TV_AUDIO_INPUT_AUTO : break;
558 case TV_AUDIO_INPUT_TUNER : arg = AUDIO_TUNER; break;
559 case TV_AUDIO_INPUT_EXTERN : arg = AUDIO_EXTERN; break;
560 case TV_AUDIO_INPUT_INTERN : arg = AUDIO_INTERN; break;
561 default :
562 fprintf( stderr, "TVCAPTURESetAudioInputDevice(): Bad value %d\n",
563 dev );
564 return;
565 }
566
567 /* NOTE: AUTO means we don't monkey with the defaults selected by */
568 /* the driver. Other values mean we always override the driver */
569 /* to keep that setting whenever it wants to change the setting. */
570 if ( dev != TV_AUDIO_INPUT_AUTO ) {
571 if ( ioctl( c->tfd, BT848_SAUDIO, &arg ) < 0 ) {
572 fprintf( stderr, "ioctl(BT848_SAUDIO, %d) failed: %s\n",
573 arg, strerror(errno) );
574 return;
575 }
576 c->audio_input_dev = dev;
577 }
578 else {
579 TV_DRIVER_STATE s;
580
581 c->audio_input_dev = dev;
582
583 /* Force driver to reset audio input back to its default */
584 if ( !TVCAPTUREQueryDriverState( c, &s ) ) {
585 fprintf( stderr, "TVCAPTUREQueryDriverState() failed\n" );
586 exit(1);
587 }
588
589 /* This funny business so the driver will actually reset the input */
590 TVCAPTURESetInputDevice( c, TV_DEVICE_TUNER );
591 TVCAPTURESetInputDevice( c, TV_DEVICE_VIDEO );
592 TVCAPTURESetInputDevice( c, s.input_dev );
593 }
594 }
595
596
TVCAPTURESetTunerChannel(TV_CAPTURE * c,TV_INT32 chan_num)597 void TVCAPTURESetTunerChannel( TV_CAPTURE *c, TV_INT32 chan_num )
598 {
599 TV_INT32 larg = chan_num;
600 int old_audio;
601
602 /* Driver FIXME: Hack to get around driver unmuting audio across */
603 /* channel, freq, and input device changes. */
604 if ( ioctl( c->tfd, BT848_GAUDIO, &old_audio ) < 0 ) {
605 DO_IOCTL_GERR( "BT848_GAUDIO" );
606 return;
607 }
608
609 if ( ioctl( c->tfd, TVTUNER_SETCHNL, &larg ) < 0 ) {
610 DO_IOCTL_SERR( "TVTUNER_SETCHNL", larg );
611 return;
612 }
613 c->tuner_chan_active = TRUE;
614
615 old_audio &= AUDIO_MUTE;
616 if ( old_audio )
617 TVCAPTURESetAudioMute( c, TRUE );
618 }
619
620
TVCAPTURESetTunerFreq(TV_CAPTURE * c,double freq)621 void TVCAPTURESetTunerFreq( TV_CAPTURE *c, double freq )
622 {
623 TV_INT32 larg = freq * FREQFACTOR;
624 int old_audio;
625
626 /* Driver FIXME: Hack to get around driver unmuting audio across */
627 /* channel, freq, and input device changes. */
628 if ( ioctl( c->tfd, BT848_GAUDIO, &old_audio ) < 0 ) {
629 DO_IOCTL_GERR( "BT848_GAUDIO" );
630 return;
631 }
632
633 if ( ioctl( c->tfd, TVTUNER_SETFREQ, &larg ) < 0 ) {
634 DO_IOCTL_SERR( "TVTUNER_SETFREQ", larg );
635 return;
636 }
637 c->tuner_chan_active = FALSE;
638
639 old_audio &= AUDIO_MUTE;
640 if ( old_audio )
641 TVCAPTURESetAudioMute( c, TRUE );
642 }
643
644
TVCAPTURESetTunerFreqSet(TV_CAPTURE * c,TV_FREQ_SET set)645 void TVCAPTURESetTunerFreqSet( TV_CAPTURE *c, TV_FREQ_SET set )
646 {
647 TV_INT32 larg;
648
649 larg = set;
650
651 if ( ioctl( c->tfd, TVTUNER_SETTYPE, &larg ) < 0 ) {
652 DO_IOCTL_SERR( "TVTUNER_SETTYPE", larg );
653 return;
654 }
655
656 /* FIXME: Hack to force a channel freq recompute in the driver */
657 /* when we change modes. */
658 {
659 TV_DRIVER_STATE s;
660 if ( !TVCAPTUREQueryDriverState( c, &s ) ) {
661 fprintf( stderr, "TVCAPTUREQueryDriverState() failed\n" );
662 exit(1);
663 }
664 TVCAPTURESetTunerChannel( c, s.tuner_chan );
665 }
666 }
667
TVCAPTUREGetTunerFreqSetName(TV_CAPTURE * c,TV_FREQ_SET set)668 char *TVCAPTUREGetTunerFreqSetName( TV_CAPTURE *c, TV_FREQ_SET set )
669 {
670 #ifdef TVTUNER_GETCHNLSET
671 static struct bktr_chnlset cset;
672 int ret;
673
674 cset.index = set;
675 if ( ( ret = ioctl( c->tfd, TVTUNER_GETCHNLSET, &cset ) ) == 0 ) {
676 return (char *)&cset.name;
677 } else {
678 if (ret == EINVAL) {
679 return NULL;
680 }
681 else {
682 #endif
683 switch (set) {
684 case CHNLSET_NABCST:
685 return "nabcst";
686 case CHNLSET_CABLEIRC:
687 return "cableirc";
688 case CHNLSET_CABLEHRC:
689 return "cablehrc";
690 case CHNLSET_WEUROPE:
691 return "weurope";
692 case CHNLSET_JPNBCST:
693 return "jpnbcst";
694 case CHNLSET_JPNCABLE:
695 return "jpncable";
696 /* FIXME: Remove these #ifdefs when these channel sets are standard */
697 #ifdef CHNLSET_XUSSR
698 case CHNLSET_XUSSR:
699 return "xussr";
700 #endif
701 #ifdef CHNLSET_AUSTRALIA
702 case CHNLSET_AUSTRALIA:
703 return "australia";
704 #endif
705 #ifdef CHNLSET_FRANCE
706 case CHNLSET_FRANCE:
707 return "france";
708 #endif
709 default:
710 return NULL;
711 }
712 #ifdef TVTUNER_GETCHNLSET
713 }
714 }
715 #endif
716
717 }
718
TVCAPTURESetAfc(TV_CAPTURE * c,TV_BOOL afc)719 void TVCAPTURESetAfc( TV_CAPTURE *c, TV_BOOL afc )
720 {
721 if ( ioctl( c->tfd, TVTUNER_SETAFC, &afc ) < 0 ) {
722 DO_IOCTL_SERR( "TVTUNER_SETAFC", afc );
723 return;
724 }
725 }
726
TVCAPTURESetAudioMute(TV_CAPTURE * c,TV_BOOL mute)727 void TVCAPTURESetAudioMute( TV_CAPTURE *c, TV_BOOL mute )
728 {
729 int arg = ( mute ? AUDIO_MUTE : AUDIO_UNMUTE );
730
731 /* If audio is disabled, don't ever unmute */
732 if ( !App_res.do_audio )
733 arg = AUDIO_MUTE;
734
735 /* Don't change audio source; just mute it */
736 if ( ioctl( c->tfd, BT848_SAUDIO, &arg ) < 0 ) {
737 DO_IOCTL_SERR( "BT848_SAUDIO", arg );
738 return;
739 }
740 }
741
TVCAPTURESetColorbars(TV_CAPTURE * c,TV_BOOL colorbars)742 void TVCAPTURESetColorbars ( TV_CAPTURE *c, TV_BOOL colorbars )
743 {
744 int ioctl_num = ( colorbars ? BT848_SCBARS : BT848_CCBARS );
745 char *ioctl_str = ( colorbars ? "BT848_SCBARS" : "BT848_CCBARS" );
746 int dummy;
747
748 /* Don't change audio source; just mute it */
749 if ( ioctl( c->tfd, ioctl_num, &dummy ) < 0 ) {
750 DO_IOCTL_SERR( ioctl_str, dummy );
751 return;
752 }
753 }
754
TVCAPTURESetFPS(TV_CAPTURE * c,TV_UINT32 fps)755 void TVCAPTURESetFPS ( TV_CAPTURE *c, TV_UINT32 fps )
756 {
757 TV_UINT16 usarg = MAX( 0, MIN( c->fps_max, fps ) );
758
759 if ( ioctl( c->fd, METEORSFPS, &usarg ) < 0 ) {
760 DO_IOCTL_SERR( "METEORSFPS", usarg );
761 return;
762 }
763
764 /* FIXME: Dead code */
765 c->fps = usarg;
766 }
767
768
TVCAPTURESetFrameDoneCBEnabled(TV_CAPTURE * c,TV_BOOL enable)769 void TVCAPTURESetFrameDoneCBEnabled( TV_CAPTURE *c, TV_BOOL enable )
770 {
771 c->frame_cb_enabled = enable;
772 }
773
774
TVCAPTUREGetFPSMax(TV_CAPTURE * c,TV_UINT32 * fps_max)775 void TVCAPTUREGetFPSMax( TV_CAPTURE *c, TV_UINT32 *fps_max )
776 {
777 *fps_max = c->fps_max;
778 }
779
780
781 /**@BEGINFUNC**************************************************************
782
783 Prototype : TV_BOOL TVCAPTUREQueryDriverState(
784 TV_CAPTURE *c,
785 TV_DRIVER_STATE *s )
786
787 Purpose : Queries the driver for all of its current parameters.
788
789 Programmer : 16-Mar-97 Randall Hopper
790
791 Parameters : c - I: capture device struct
792 s - O: driver state
793
794 Returns : None.
795
796 Globals : None.
797
798 **@ENDFUNC*****************************************************************/
799
TVCAPTUREQueryDriverState(TV_CAPTURE * c,TV_DRIVER_STATE * s)800 TV_BOOL TVCAPTUREQueryDriverState( TV_CAPTURE *c, TV_DRIVER_STATE *s )
801 {
802 TV_INT32 larg;
803 TV_UINT16 usarg;
804 #ifdef NOT_NEEDED
805 struct meteor_counts counts;
806 struct meteor_video video;
807 #endif
808
809 memset( s, '\0', sizeof( *s ) );
810
811 /* INPUT DEVICE */
812 if ( ioctl( c->fd, METEORGINPUT, &larg ) < 0 ) {
813 DO_IOCTL_GERR( "METEORGINPUT" );
814 return False;
815 }
816 switch ( larg ) {
817 case METEOR_INPUT_DEV0 : s->input_dev = TV_DEVICE_VIDEO ; break;
818 case METEOR_INPUT_DEV1 : s->input_dev = TV_DEVICE_TUNER ; break;
819 case METEOR_INPUT_DEV_SVIDEO : s->input_dev = TV_DEVICE_SVIDEO ; break;
820 case METEOR_INPUT_DEV2 : s->input_dev = TV_DEVICE_CSVIDEO; break;
821 #ifdef METEOR_INPUT_DEV3
822 case METEOR_INPUT_DEV3 : s->input_dev = TV_DEVICE_DEV3 ; break;
823 #endif
824 default :
825 fprintf( stderr, "TVCAPTUREQueryDriverState(): Bad INPUT %ld\n",
826 larg );
827 return False;
828 }
829
830 /* INPUT FORMAT */
831 if ( ioctl( c->fd, BT848GFMT, &larg ) < 0 ) {
832 DO_IOCTL_GERR( "BT848GFMT" );
833 return False;
834 }
835 switch ( larg ) {
836 case BT848_IFORM_F_AUTO : s->input_fmt = TV_INPUT_AUTO ; break;
837 case BT848_IFORM_F_NTSCM : s->input_fmt = TV_INPUT_NTSCM ; break;
838 case BT848_IFORM_F_NTSCJ : s->input_fmt = TV_INPUT_NTSCJ ; break;
839 case BT848_IFORM_F_PALBDGHI: s->input_fmt = TV_INPUT_PALBDGHI; break;
840 case BT848_IFORM_F_PALM : s->input_fmt = TV_INPUT_PALM ; break;
841 case BT848_IFORM_F_PALN : s->input_fmt = TV_INPUT_PALN ; break;
842 case BT848_IFORM_F_SECAM : s->input_fmt = TV_INPUT_SECAM ; break;
843 case BT848_IFORM_F_RSVD : s->input_fmt = TV_INPUT_PALNCOMB; break;
844 default :
845 fprintf( stderr, "TVCAPTUREQueryDriverState(): Bad FMT %ld\n",
846 larg );
847 return False;
848 }
849
850 /* CAPTURE DESTINATION */
851 #ifdef NOT_NEEDED
852 if ( ioctl( c->fd, METEOR_GVIDEO, &video ) < 0 ) {
853 DO_IOCTL_GERR( "METEOR_GVIDEO" );
854 return False;
855 }
856 #endif
857
858 /* FRAMES PER SEC */
859 if ( ioctl( c->fd, METEORGFPS, &usarg ) < 0 ) {
860 DO_IOCTL_GERR( "METEORGFPS" );
861 return False;
862 }
863 s->fps = usarg;
864
865 /* SIGNAL */
866 #ifdef NOT_NEEDED
867 if ( ioctl( c->fd, METEOR_GSIGNAL, &larg ) < 0 ) {
868 DO_IOCTL_GERR( "METEOR_GSIGNAL" );
869 return False;
870 }
871 s->signal = larg;
872 #endif
873
874 /* CAPTURE STATISTICS */
875 #ifdef NOT_NEEDED
876 if ( ioctl( c->fd, METEOR_GCOUNT, &counts ) < 0 ) {
877 DO_IOCTL_GERR( "METEOR_GCOUNT" );
878 return False;
879 }
880 s->stats.frames_captured = counts.frames_captured;
881 #endif
882
883 /* HUE */
884 if ( ioctl( c->tfd, BT848_GHUE, &larg ) < 0 ) {
885 DO_IOCTL_GERR( "BT848_GHUE" );
886 return False;
887 }
888
889 /* Driver FIXME: Hack needed since 970322 driver is using an int, but */
890 /* isn't returning -128-127 range as in SHUE, but rather 0..255. */
891 if ( larg >= 128 )
892 larg -= 256;
893
894 s->hue = ((double)larg - HUE_DRV_MIN) / HUE_DRV_RANGE
895 * HUE_RANGE + HUE_MIN;
896
897 /* BRIGHTNESS */
898 if ( ioctl( c->tfd, BT848_GBRIG, &larg ) < 0 ) {
899 DO_IOCTL_GERR( "BT848_GBRIG" );
900 return False;
901 }
902
903 /* Driver FIXME: Hack needed since 970322 driver is using an int, but */
904 /* isn't returning -128-127 range as in SHUE, but rather 0..255. */
905 if ( larg >= 128 )
906 larg -= 256;
907
908 s->brightness = ((double)larg - BRIGHT_DRV_MIN) / BRIGHT_DRV_RANGE
909 * BRIGHT_RANGE + BRIGHT_MIN;
910
911 /* CONTRAST */
912 if ( ioctl( c->tfd, BT848_GCONT, &larg ) < 0 ) {
913 DO_IOCTL_GERR( "BT848_GCONT" );
914 return False;
915 }
916 s->contrast = ((double)larg - CONTR_DRV_MIN) / CONTR_DRV_RANGE
917 * CONTR_RANGE + CONTR_MIN;
918
919 /* CHROMA U SATURATION */
920 if ( ioctl( c->tfd, BT848_GUSAT, &larg ) < 0 ) {
921 DO_IOCTL_GERR( "BT848_GUSAT" );
922 return False;
923 }
924 s->sat_u = ((double)larg - SATU_DRV_MIN) / SATU_DRV_RANGE
925 * SATU_RANGE + SATU_MIN;
926
927 /* CHROMA V SATURATION */
928 if ( ioctl( c->tfd, BT848_GVSAT, &larg ) < 0 ) {
929 DO_IOCTL_GERR( "BT848_GVSAT" );
930 return False;
931 }
932 s->sat_v = ((double)larg - SATV_DRV_MIN) / SATV_DRV_RANGE
933 * SATV_RANGE + SATV_MIN;
934
935 /* TUNER TYPE */
936 if ( ioctl( c->tfd, TVTUNER_GETTYPE, &larg ) < 0 ) {
937 DO_IOCTL_GERR( "TVTUNER_GETTYPE" );
938 return False;
939 }
940 s->tuner_freq_set = larg;
941
942 /* FIXME: This is a hack because we can't query this info */
943 /* from the driver. */
944 s->tuner_chan_active = c->tuner_chan_active;
945
946 /* TUNER CHANNEL */
947 if ( ioctl( c->tfd, TVTUNER_GETCHNL, &larg ) < 0 ) {
948 DO_IOCTL_GERR( "TVTUNER_GETCHNL" );
949 return False;
950 }
951 s->tuner_chan = larg;
952
953 /* TUNER FREQUENCY */
954 if ( ioctl( c->tfd, TVTUNER_GETFREQ, &larg ) < 0 ) {
955 DO_IOCTL_GERR( "TVTUNER_GETFREQ" );
956 return False;
957 }
958 s->tuner_freq = (double)larg / FREQFACTOR;
959
960 /* AUDIO MUTE AND INPUT STATE */
961 if ( ioctl( c->tfd, BT848_GAUDIO, &larg ) < 0 ) {
962 DO_IOCTL_GERR( "BT848_GAUDIO" );
963 return False;
964 }
965 s->audio_mute = (larg & AUDIO_MUTE) != 0;
966 switch ( larg & ~AUDIO_MUTE ) {
967 default :
968 case AUDIO_TUNER : s->audio_input_dev = TV_AUDIO_INPUT_TUNER ; break;
969 case AUDIO_EXTERN : s->audio_input_dev = TV_AUDIO_INPUT_EXTERN; break;
970 case AUDIO_INTERN : s->audio_input_dev = TV_AUDIO_INPUT_INTERN; break;
971 }
972
973 return True;
974 }
975
976
TVCAPTUREQueryParamLimits(TV_CAPTURE * c,TV_DRIVER_PARAM p,double lim[2])977 void TVCAPTUREQueryParamLimits( TV_CAPTURE *c, TV_DRIVER_PARAM p,
978 double lim[2] )
979 {
980 static struct {
981 TV_DRIVER_PARAM p;
982 double lim[2];
983 } S_param_lim[] = {
984 { TV_PARAM_HUE , { HUE_MIN , HUE_MAX } },
985 { TV_PARAM_BRIGHT , { BRIGHT_MIN, BRIGHT_MAX } },
986 { TV_PARAM_CONTRAST, { CONTR_MIN , CONTR_MAX } },
987 { TV_PARAM_SATU , { SATU_MIN , SATU_MAX } },
988 { TV_PARAM_SATV , { SATV_MIN , SATV_MAX } }
989 };
990
991 TV_INT32 i;
992
993 for ( i = 0; i < XtNumber( S_param_lim ); i++ )
994 if ( S_param_lim[i].p == p )
995 break;
996
997 if ( i >= XtNumber( S_param_lim ) ) {
998 fprintf( stderr,
999 "TVCAPTUREQueryParamLimits: Unsupported driver param (%d)", p );
1000 exit(1);
1001 }
1002
1003 memcpy( lim, S_param_lim[i].lim, sizeof( S_param_lim[i].lim ) );
1004 }
1005
1006
1007 /**@BEGINFUNC**************************************************************
1008
1009 Prototype : void TVCAPTUREQueryPixelFormats(
1010 TV_CAPTURE *c,
1011 TV_PIXEL_GEOM **list,
1012 TV_UINT32 *list_size )
1013
1014 Purpose : Query all the support RGB pixel formats from the capture
1015 driver and store them in a local list for fast access.
1016
1017 Programmer : 20-Apr-97 Randall Hopper
1018
1019 Parameters : c - I: capture definition structure
1020 list - O: allocated/filled in list of pixel formats
1021 list_size - O: resulting size of list
1022
1023 Returns : None.
1024
1025 Globals : None.
1026
1027 **@ENDFUNC*****************************************************************/
1028
TVCAPTUREQueryPixelFormats(TV_CAPTURE * c,TV_PIXEL_GEOM ** list,TV_UINT32 * list_size)1029 void TVCAPTUREQueryPixelFormats( TV_CAPTURE *c,
1030 TV_PIXEL_GEOM **list,
1031 TV_UINT32 *list_size )
1032 {
1033 /* FIXME: This belongs in the driver where we can query it using */
1034 /* the pixmap formats interface. */
1035 static TV_PIXEL_GEOM
1036 YUV_h422_v111 =
1037 { -1,TV_PIXELTYPE_YUV,0,{},0,0,
1038 {8,8,8},{1,2,2},{1,1,1},TV_FRAME_PLANAR,"YUV",1,1,0 },
1039 YUV_h422_v422 =
1040 { -1,TV_PIXELTYPE_YUV,0,{},0,0,
1041 {8,8,8},{1,2,2},{1,2,2},TV_FRAME_PLANAR,"YUV",1,1,0 };
1042
1043 struct meteor_pixfmt pf;
1044 TV_UINT32 i;
1045 TV_PIXEL_GEOM *pg;
1046
1047 *list = NULL;
1048 *list_size = 0;
1049
1050 for ( i = 0; ; i++ ) {
1051 pf.index = i;
1052 if ( ioctl( c->fd, METEORGSUPPIXFMT, &pf ) < 0 ) {
1053 if ( errno == EINVAL )
1054 break;
1055 DO_IOCTL_GERR( "METEORGSUPPIXFMT" );
1056 }
1057
1058 /* Expand list */
1059 (*list_size)++;
1060 *list = realloc( *list, *list_size * sizeof( (*list)[0] ) );
1061 if ( *list == NULL )
1062 TVUTILOutOfMemory();
1063
1064 /* Store new record */
1065 pg = &(*list)[ *list_size - 1 ];
1066 memset( pg, '\0', sizeof( *pg ) );
1067
1068 if ( pf.type == METEOR_PIXTYPE_RGB ) {
1069 pg->type = TV_PIXELTYPE_RGB;
1070 pg->Bpp = pf.Bpp;
1071 pg->mask[0] = pf.masks[0];
1072 pg->mask[1] = pf.masks[1];
1073 pg->mask[2] = pf.masks[2];
1074 pg->swap_bytes = pf.swap_bytes;
1075 pg->swap_shorts = pf.swap_shorts;
1076 }
1077
1078 /* FIXME: These should be parameterized subtypes of YUV in */
1079 /* the driver, not separate types. This would eliminate */
1080 /* confusion due to these legacy names, and make us */
1081 /* more independent of the capabilities of the driver. */
1082 /* FIXME: Extend the driver interface to pass us these YUV */
1083 /* parms for each YUV subtype */
1084 else if (( pf.type == METEOR_PIXTYPE_YUV ) ||
1085 ( pf.type == METEOR_PIXTYPE_YUV_PACKED ) ||
1086 ( pf.type == METEOR_PIXTYPE_YUV_12 )) {
1087
1088 pg->type = TV_PIXELTYPE_YUV;
1089
1090 switch ( pf.type ) {
1091
1092 case METEOR_PIXTYPE_YUV :
1093 memcpy( pg, &YUV_h422_v111, sizeof(*pg) );
1094 pg->frame_packing = TV_FRAME_PLANAR;
1095 strcpy( pg->comp_order, "YUV" );
1096 break;
1097
1098 case METEOR_PIXTYPE_YUV_PACKED : /* 4CC Code: YUY2 */
1099 memcpy( pg, &YUV_h422_v111, sizeof(*pg) );
1100 pg->frame_packing = TV_FRAME_PACKED;
1101 strcpy( pg->comp_order, "YUYV" );
1102 break;
1103
1104 case METEOR_PIXTYPE_YUV_12 : /* 4CC Code: IYUV/I420 */
1105 memcpy( pg, &YUV_h422_v422, sizeof(*pg) );
1106 pg->frame_packing = TV_FRAME_PLANAR;
1107 strcpy( pg->comp_order, "YUV" );
1108 break;
1109
1110 default: break; /* Won't happen */
1111 }
1112 }
1113 else {
1114 fprintf( stderr, "Unsupported pixel type: %d\n", pg->type );
1115 exit(1);
1116 }
1117
1118 pg->index = pf.index;
1119 }
1120 }
1121
1122 /**@BEGINFUNC**************************************************************
1123
1124 Prototype : void TVCAPTUREGetNumPixFmts(
1125 TV_CAPTURE *c,
1126 TV_UINT32 *num )
1127
1128 Prototype : void TVCAPTUREGetNthPixFmt (
1129 TV_CAPTURE *c,
1130 TV_UINT32 index,
1131 TV_PIXEL_GEOM *geom )
1132
1133 Prototype : void TVCAPTUREGetPixFmtByDriverHandle(
1134 TV_CAPTURE *c,
1135 TV_UINT32 handle,
1136 TV_INT32 *index )
1137
1138 Prototype : void TVCAPTUREGetPixFmtByPixGeom(
1139 TV_CAPTURE *c,
1140 TV_PIXEL_GEOM *geom,
1141 TV_INT32 *index )
1142
1143 Purpose : Query API for the pixel formats supported by out capture
1144 device.
1145
1146 Programmer : 20-Apr-97 Randall Hopper
1147
1148 Parameters : c - I: capture struct
1149 num - O: num pixel formats
1150 index - I: index into pixel formats list
1151 handle - I: driver handle for pixel format
1152 geom - O: nth pixel format definition
1153
1154 Returns : None.
1155
1156 Globals : None.
1157
1158 **@ENDFUNC*****************************************************************/
1159
TVCAPTUREGetNumPixFmts(TV_CAPTURE * c,TV_UINT32 * num)1160 void TVCAPTUREGetNumPixFmts( TV_CAPTURE *c, TV_UINT32 *num )
1161 {
1162 *num = c->pix_geom_list_len;
1163 }
1164
TVCAPTUREGetNthPixFmt(TV_CAPTURE * c,TV_UINT32 index,TV_PIXEL_GEOM * geom)1165 void TVCAPTUREGetNthPixFmt ( TV_CAPTURE *c, TV_UINT32 index,
1166 TV_PIXEL_GEOM *geom )
1167 {
1168 if ( index >= c->pix_geom_list_len ) {
1169 fprintf( stderr, "TVCAPTUREGetNthPixFmt: Index out of range\n" );
1170 exit(1);
1171 }
1172 *geom = c->pix_geom_list[ index ];
1173 }
1174
TVCAPTUREGetPixFmtByDriverHandle(TV_CAPTURE * c,TV_UINT32 handle,TV_INT32 * index)1175 void TVCAPTUREGetPixFmtByDriverHandle( TV_CAPTURE *c, TV_UINT32 handle,
1176 TV_INT32 *index )
1177 {
1178 TV_UINT32 i;
1179
1180 for ( i = 0; i < c->pix_geom_list_len; i++ )
1181 if ( handle == c->pix_geom_list[i].index )
1182 break;
1183
1184 *index = ( i >= c->pix_geom_list_len ) ? -1 : i;
1185 }
1186
TVCAPTUREMaskIsaByte(TV_UINT32 mask)1187 static TV_BOOL TVCAPTUREMaskIsaByte ( TV_UINT32 mask )
1188 {
1189 TV_BOOL isa_byte = FALSE;
1190 TV_INT32 i;
1191
1192 for ( i = 0; i < sizeof( mask ); i++, mask >>= 8 )
1193 if ( mask & 0xff ) {
1194 if (( (mask & 0xff) == 0xff ) && ( (mask >> 8) == 0 ))
1195 isa_byte = TRUE;
1196 break;
1197 }
1198 return isa_byte;
1199 }
1200
1201
TVCAPTUREGetPixFmtByPixGeom(TV_CAPTURE * c,TV_PIXEL_GEOM * geom,TV_INT32 * index)1202 void TVCAPTUREGetPixFmtByPixGeom( TV_CAPTURE *c, TV_PIXEL_GEOM *geom,
1203 TV_INT32 *index )
1204 {
1205 TV_UINT32 i;
1206
1207 for ( i = 0; i < c->pix_geom_list_len; i++ )
1208 if (( geom->type == c->pix_geom_list[i].type ) &&
1209 ( geom->Bpp == c->pix_geom_list[i].Bpp ) &&
1210 !memcmp( geom->mask, c->pix_geom_list[i].mask,
1211 sizeof( geom->mask ) ) &&
1212 ( geom->swap_bytes == c->pix_geom_list[i].swap_bytes ) &&
1213 ( geom->swap_shorts == c->pix_geom_list[i].swap_shorts ))
1214 break;
1215
1216 /* Handle a few of the strange byte-swapped combinations for */
1217 /* 3 and 4 bpp. */
1218 /* This lets us deal with visuals that return masks like */
1219 /* the Mach64 which is RGBA frame buffer (with pixmap */
1220 /* depth of 32 with visual masks of ff,ff00,ff0000) */
1221 if ( ( i >= c->pix_geom_list_len ) &&
1222 (( geom->Bpp == 3 ) || ( geom->Bpp == 4 )) &&
1223 TVCAPTUREMaskIsaByte( geom->mask[0] ) &&
1224 TVCAPTUREMaskIsaByte( geom->mask[1] ) &&
1225 TVCAPTUREMaskIsaByte( geom->mask[2] ) ) {
1226
1227 TV_PIXEL_GEOM g = *geom;
1228
1229 g.mask[0] = geom->mask[2],
1230 g.mask[2] = geom->mask[0];
1231 g.swap_bytes = !g.swap_bytes;
1232 if ( g.Bpp == 4 )
1233 g.swap_shorts = !g.swap_shorts;
1234 }
1235
1236 *index = ( i >= c->pix_geom_list_len ) ? -1 : i;
1237 }
1238
1239
TVCAPTUREPrintPixelFormats(TV_CAPTURE * c)1240 void TVCAPTUREPrintPixelFormats( TV_CAPTURE *c )
1241 {
1242 TV_INT32 i,
1243 bpp,
1244 swap;
1245 TV_UINT32 mask;
1246 TV_PIXEL_GEOM *pg;
1247
1248 /* Dump capture pixel formats for debugging purposes */
1249
1250
1251 /* PRINT RGB FORMATS */
1252 SUPRINTF(( "\nSupported RGB Capture Pixel Formats:\n"
1253 " bpp Bpp RGB Masks Swap\n"
1254 " --- --- ---------------------------- ----\n" ));
1255
1256 for ( i = 0; i < c->pix_geom_list_len; i++ ) {
1257 char swap_chars[5];
1258 TV_INT32 j;
1259 TV_PIXEL_GEOM scratch;
1260 TV_BOOL printit = TRUE;
1261
1262 pg = &c->pix_geom_list[ i ];
1263
1264 if ( pg->type != TV_PIXELTYPE_RGB )
1265 continue;
1266
1267 /* Browse list and see if we've got other pixel formats */
1268 /* with the same type/Bpp/mask but different swap permutations */
1269 memset( swap_chars, ' ', sizeof( swap_chars ) );
1270 swap_chars[4] = '\0';
1271
1272 for ( swap = 0; swap < 4; swap++ ) {
1273 scratch = *pg;
1274 scratch.swap_bytes = (swap & 0x01) != 0;
1275 scratch.swap_shorts = (swap & 0x02) != 0;
1276
1277 TVCAPTUREGetPixFmtByPixGeom( c, &scratch, &j );
1278 if ( j < 0 )
1279 continue;
1280 if ( j < i ) {
1281 printit = FALSE;
1282 break;
1283 }
1284 swap_chars[ swap ] = "NBWb"[ swap ];
1285 }
1286 if ( !printit )
1287 continue;
1288
1289 /* Calculate bpp from masks */
1290 mask = pg->mask[0] | pg->mask[1] | pg->mask[2];
1291 bpp = 0;
1292 while ( mask != 0 ) {
1293 if ( mask & 0x01 )
1294 bpp++;
1295 mask >>= 1;
1296 }
1297
1298 SUPRINTF((
1299 " %2ld %2ld %.8lx, %.8lx, %.8lx %s\n",
1300 bpp, pg->Bpp, pg->mask[0], pg->mask[1], pg->mask[2],
1301 swap_chars ));
1302 }
1303
1304 /* PRINT YUV FORMATS */
1305 SUPRINTF(( "\nSupported YUV Capture Pixel Formats:\n"
1306 " YUVSize HSamp VSamp Pack CompOrder T->B L->R YTrans\n"
1307 " ------- ----- ----- ------ --------- ---- ---- ------\n" ));
1308
1309 for ( i = 0; i < c->pix_geom_list_len; i++ ) {
1310 pg = &c->pix_geom_list[ i ];
1311
1312 if ( pg->type != TV_PIXELTYPE_YUV )
1313 continue;
1314
1315 SUPRINTF((
1316 " %ld,%ld,%ld %ld,%ld,%ld %ld,%ld,%ld %-7s %-10s "
1317 "%-5s %-6s %s\n",
1318 pg->samp_size [0], pg->samp_size [1], pg->samp_size [2],
1319 pg->samp_int_h[0], pg->samp_int_h[1], pg->samp_int_h[2],
1320 pg->samp_int_v[0], pg->samp_int_v[1], pg->samp_int_v[2],
1321 (pg->frame_packing == TV_FRAME_PLANAR ? "PLANAR" : "PACKED"),
1322 pg->comp_order,
1323 (pg->order_t_to_b ? "Y" : "N"), (pg->order_l_to_r ? "Y" : "N"),
1324 (pg->y_trans ? "Y" : "N") ));
1325 }
1326
1327 SUPRINTF(( "\n" ));
1328 }
1329
1330
1331 /**@BEGINFUNC**************************************************************
1332
1333 Prototype : static void TVCAPTUREDumpCaptureCardInfo(
1334 TV_CAPTURE *c )
1335
1336 Purpose : Dump useful info about the capture card that can be
1337 used by developers for debugging.
1338
1339 Programmer : 09-Mar-98 Randall Hopper
1340
1341 Parameters : c - I: capture definition struct
1342 (with open handles to tuner and capture devices)
1343
1344 Returns : None.
1345
1346 Globals : None.
1347
1348 **@ENDFUNC*****************************************************************/
1349
TVCAPTUREDumpCaptureCardInfo(TV_CAPTURE * c)1350 static void TVCAPTUREDumpCaptureCardInfo( TV_CAPTURE *c )
1351 {
1352 struct eeProm eeprom;
1353 u_char *p;
1354 int x;
1355 int cnt;
1356 FILE *fp;
1357 char linebuf[128];
1358
1359 /* Grab the pertinent dmesg output */
1360 printf( "DETECTED CAPTURE CARD(S) [DRIVER PROBES]:\n" );
1361 if ( (fp = popen( "dmesg", "r" )) == NULL )
1362 fprintf( stderr, " Failed to dump dmesg output.\n" );
1363 else {
1364 /* FIXME: Parsing boot-ups is BAD. Make the driver return this */
1365 /* via ioctl. */
1366 while ( !feof(fp) ) {
1367 if ( fgets( linebuf, sizeof(linebuf)-1, fp ) == NULL )
1368 break;
1369 if ( strncmp( linebuf, "bktr", 4 ) == 0 ) {
1370 printf( " %s", linebuf );
1371 if ( fgets( linebuf, sizeof(linebuf)-1, fp) != NULL )
1372 printf( " %s", linebuf );
1373 }
1374 }
1375 pclose(fp);
1376 }
1377
1378 /* Dump the relevent bktr driver sysctl values (if present) */
1379 printf( "\nSYSCTL MIB VALUES:\n" );
1380 if ( (fp = popen( "sysctl kern.version hw.bt848", "r" )) == NULL )
1381 fprintf( stderr, " Failed to dump sysctl output.\n" );
1382 else {
1383 while ( !feof(fp) ) {
1384 if ( fgets( linebuf, sizeof(linebuf)-1, fp ) == NULL )
1385 break;
1386 printf( " %s", linebuf );
1387 }
1388 pclose(fp);
1389 }
1390
1391
1392 /* Read the card signature */
1393 eeprom.offset = 0x01;
1394 eeprom.count = 128;
1395
1396 if ( ioctl( c->tfd, BT848_SIGNATURE, &eeprom ) < 0 )
1397 DO_IOCTL_GERR( "BT848_SIGNATURE" );
1398 else {
1399 printf( "\nTUNER SIGNATURE (0x%02x - 0x%02x):\n",
1400 eeprom.offset,
1401 (2 * ((eeprom.offset - 1) + eeprom.count)) - 1 );
1402 for ( p = &eeprom.bytes[ 0 ], x = 0; x < 16; ++x ) {
1403 if ( (x % 16) == 0 )
1404 printf( "%s ", ((x > 0) ? "\n" : "") );
1405 printf( " %02x", p[ x ] );
1406 }
1407 printf( "\n" );
1408
1409 printf( "\nTUNER I2C DEVICES FOUND AT:\n " );
1410 cnt = 0;
1411 for ( p = &eeprom.bytes[ 0 ], x = 0; x < 128; ++x )
1412 if ( p[ x / 8 ] & (1 << (x % 8)) ) {
1413 printf( "%s 0x%02x", ((cnt > 0) ? "," : ""), x * 2 );
1414 cnt++;
1415 }
1416 printf( "\n" );
1417 }
1418
1419 /* Read the EEPROM */
1420 /* FIXME: There's no way to query the size of the EEPROM from the */
1421 /* app, and the driver bails if the request is too big. Modify the */
1422 /* driver to return the EEPROM size. For now, use a heuristic. */
1423 eeprom.offset = 0;
1424 eeprom.count = 256;
1425 if ( ioctl( c->tfd, BT848_REEPROM, &eeprom ) < 0 ) {
1426 eeprom.count = 128;
1427 if ( ioctl( c->tfd, BT848_REEPROM, &eeprom ) < 0 ) {
1428 eeprom.count = 0;
1429 DO_IOCTL_GERR( "BT848_REEPROM" );
1430 }
1431 }
1432 printf( "\nCAPTURE CARD EEPROM CONTENTS:\n"
1433 " Read %d EEPROM bytes ", eeprom.count );
1434 if ( eeprom.count == 0 )
1435 printf( "\n" );
1436 else {
1437 printf( "(0x00 - 0x%.2x)\n", eeprom.count-1 );
1438
1439 for ( p = &eeprom.bytes[ 0 ], x = 0; x < eeprom.count; ++x ) {
1440 if ( (x % 16) == 0 )
1441 printf( "%s ", ((x > 0) ? "\n" : "") );
1442 printf( " %02x", p[ x ] );
1443 }
1444 printf( "\n" );
1445 }
1446
1447 /* Dump supported Frequency Sets */
1448 printf( "\nSUPPORTED FREQUENCY SETS:\n");
1449
1450 cnt=1;
1451 while ( (p = TVCAPTUREGetTunerFreqSetName( c, cnt )) != NULL )
1452 printf( " %2d %s\n", cnt++, p );
1453
1454 /* It'd also be helpful to be able to print the bktr driver version */
1455 }
1456
1457
1458
1459
1460 /**@BEGINFUNC**************************************************************
1461
1462 Prototype : void TVCAPTUREInit(
1463 TV_CAPTURE *c )
1464
1465 Purpose : Initialize the capture attributes.
1466
1467 Programmer : 03-Mar-97 Randall Hopper
1468
1469 Parameters : c - I/O: Capture definition structure
1470
1471 Returns : None.
1472
1473 Globals : G_tvcapture
1474
1475 **@ENDFUNC*****************************************************************/
1476
TVCAPTUREInit(TV_CAPTURE * c)1477 void TVCAPTUREInit( TV_CAPTURE *c )
1478 {
1479 char dev_capture[80],
1480 dev_tuner [80];
1481
1482 /* Build names of capture and tuner devices */
1483 sprintf( dev_capture, DEV_BT848, App_res.device_number );
1484 sprintf( dev_tuner , DEV_TUNER, App_res.device_number );
1485
1486 c->fd = open( dev_capture, O_RDONLY );
1487 if ( c->fd < 0 ) {
1488 fprintf( stderr, "open(\"%s\") failed: %s\n",
1489 dev_capture, strerror(errno) );
1490 exit(1);
1491 }
1492 c->tfd = open( dev_tuner, O_RDONLY );
1493 if ( c->tfd < 0 ) {
1494 fprintf( stderr, "open(\"%s\") failed: %s\n",
1495 dev_tuner , strerror(errno) );
1496 exit(1);
1497 }
1498
1499 /* Dump debug info on capture card */
1500 if ( G_debug & DEBUG_STARTUP )
1501 TVCAPTUREDumpCaptureCardInfo( c );
1502
1503 /* Mute the audio until such time as we're ready to display */
1504 TVCAPTURESetAudioMute( c, TRUE );
1505
1506 /* Just mmap the biggest buffer we'll need and be done with it. */
1507 /* (Buffer used for non-directvideo captures) */
1508 c->drv_buf = (TV_UINT8 *) mmap( (caddr_t)0, MAX_MMAP_BUF_SIZE,
1509 PROT_READ, MAP_SHARED, c->fd, (off_t)0 );
1510 if ( c->drv_buf == (TV_UINT8 *) -1 ) {
1511 fprintf( stderr, "mmap of driver buffer failed: %s\n",
1512 strerror(errno) );
1513 exit(1);
1514 }
1515
1516 c->input_format = TV_INPUT_NTSCM;
1517 c->input_dev = METEOR_INPUT_DEV0;
1518 c->audio_input_dev = TV_AUDIO_INPUT_AUTO;
1519
1520 c->bpp_format = METEOR_GEO_RGB16;
1521 c->cap_mode = TV_CAPTURE_CONTINUOUS;
1522 c->xfer_mode = TV_TRANSFER_DIRECT;
1523
1524 TVCAPTUREQueryPixelFormats( c, &c->pix_geom_list, &c->pix_geom_list_len);
1525 if ( c->pix_geom_list_len == 0 ) {
1526 fprintf( stderr, "capture device supports 0 pixel formats\n" );
1527 exit(1);
1528 }
1529 c->pix_geom_idx = 0;
1530
1531 /* FIXME: This is a hack -- here because we can't query whether the */
1532 /* the tuner is set to a specific channel number or whether an */
1533 /* off-channel frequency override is in-place. */
1534 c->tuner_chan_active = TRUE;
1535
1536 TVCAPTUREPrintPixelFormats( c );
1537
1538 c->field_targ[0] = TV_FIELD_DISPLAY;
1539 c->field_targ[1] = TV_FIELD_DISPLAY;
1540 c->hue = 0.0; /* % */
1541 c->brightness = +20.0; /* % */
1542 c->contrast = 70.0; /* % */
1543 c->sat_u = 100.0; /* % */
1544 c->sat_v = 100.0; /* % */
1545 c->addr = NULL;
1546 /* geom -- see below */
1547
1548 c->frame_done_cb = NULL;
1549 c->frame_cb_enabled = FALSE;
1550
1551 /* FIXME: These belong in the driver/driver include file */
1552 c->width_min = 2;
1553 c->width_res = 2;
1554 c->height_min = 2;
1555 c->height_res = 2;
1556 switch ( c->input_format ) {
1557 case TV_INPUT_NTSCM :
1558 case TV_INPUT_NTSCJ :
1559 case TV_INPUT_PALM :
1560 c->width_max = NTSC_DIM_X;
1561 c->height_max = NTSC_DIM_Y;
1562 c->fps_max = NTSC_FPS;
1563 break;
1564 case TV_INPUT_PALBDGHI :
1565 case TV_INPUT_PALN :
1566 case TV_INPUT_SECAM :
1567 case TV_INPUT_PALNCOMB :
1568 c->width_max = PAL_DIM_X;
1569 c->height_max = PAL_DIM_Y;
1570 c->fps_max = PAL_FPS;
1571 break;
1572 default :
1573 case TV_INPUT_AUTO :
1574 fprintf( stderr,
1575 "TVCAPTUREInit: Unsupported input format %ld\n",
1576 c->input_format );
1577 exit(1);
1578 }
1579 c->fps = c->fps_max;
1580
1581 c->geom.x = c->geom.y = 0; /* Unused */
1582 c->geom.w = c->width_max ;
1583 c->geom.h = c->height_max;
1584
1585 c->contin_on = False;
1586
1587 signal( SIGUSR1, TVCAPTUREFrameDoneSigHdlr );
1588 atexit( TVCAPTUREDestroy );
1589 }
1590
1591
1592 /**@BEGINFUNC**************************************************************
1593
1594 Prototype : void TVCAPTURESetCaptureMode(
1595 Prototype : void TVCAPTURESetTransferMode(
1596 Prototype : void TVCAPTURESetRegionGeom(
1597 Prototype : void TVCAPTURESetPixelGeom(
1598
1599 Purpose : Routines which set the core capture parameters.
1600
1601 It would be good policy to set all these before every
1602 capture.
1603
1604 Programmer : 06-Jun-97 Randall Hopper
1605
1606 Parameters : c - I: capture definition
1607 cap_mode - I: new capture/transfer modes (single/contin)
1608 xfer_mode - I: images (driver buf) or direct video
1609 reg_geom - I: image res (& origin, for direct video)
1610 pix_geom - I: captured pixel geometry
1611 (images only; ignored for xfer_mode = DIRECT)
1612
1613 Returns : None.
1614
1615 Globals : None.
1616
1617 **@ENDFUNC*****************************************************************/
1618
TVCAPTURESetCaptureMode(TV_CAPTURE * c,TV_CAPTURE_MODE cap_mode)1619 void TVCAPTURESetCaptureMode(
1620 TV_CAPTURE *c,
1621 TV_CAPTURE_MODE cap_mode )
1622 {
1623 if ( c->contin_on == TRUE ) {
1624 fprintf( stderr, "SetCaptureMode called when contin running\n" );
1625 return;
1626 }
1627 c->cap_mode = cap_mode;
1628 }
1629
1630
TVCAPTURESetTransferMode(TV_CAPTURE * c,TV_TRANSFER_MODE xfer_mode)1631 void TVCAPTURESetTransferMode(
1632 TV_CAPTURE *c,
1633 TV_TRANSFER_MODE xfer_mode )
1634 {
1635 if ( c->contin_on == TRUE ) {
1636 fprintf( stderr, "SetTransferMode called when contin running\n" );
1637 return;
1638 }
1639 c->xfer_mode = xfer_mode;
1640 }
1641
1642
TVCAPTURESetRegionGeom(TV_CAPTURE * c,TV_GEOM * reg_geom)1643 void TVCAPTURESetRegionGeom(
1644 TV_CAPTURE *c,
1645 TV_GEOM *reg_geom )
1646 {
1647 if ( c->contin_on == TRUE ) {
1648 fprintf( stderr, "SetRegionGeom called when contin running\n" );
1649 return;
1650 }
1651 c->geom = *reg_geom;
1652 }
1653
1654
TVCAPTURESetPixelGeom(TV_CAPTURE * c,TV_PIXEL_GEOM * pix_geom)1655 void TVCAPTURESetPixelGeom(
1656 TV_CAPTURE *c,
1657 TV_PIXEL_GEOM *pix_geom )
1658 {
1659 TV_INT32 idx;
1660
1661 if ( c->contin_on == TRUE ) {
1662 fprintf( stderr, "SetPixelGeom called when contin running\n" );
1663 return;
1664 }
1665
1666 TVCAPTUREGetPixFmtByDriverHandle( c, pix_geom->index, &idx );
1667 if (( idx < 0 ) || ( idx >= c->pix_geom_list_len )) {
1668 fprintf( stderr, "TVCAPTUREConfigure: Bad pixel format index\n" );
1669 exit(1);
1670 }
1671 c->pix_geom_idx = idx;
1672 }
1673
1674 /* TVCAPTUREValidRegionGeom - Validates capture resolution */
TVCAPTUREValidRegionGeom(TV_CAPTURE * c,TV_GEOM * reg_geom)1675 TV_BOOL TVCAPTUREValidRegionGeom(
1676 TV_CAPTURE *c,
1677 TV_GEOM *reg_geom )
1678 {
1679 TV_INT32 w, h;
1680
1681 w = reg_geom->w / c->width_res * c->width_res;
1682 h = reg_geom->h / c->height_res * c->height_res;
1683
1684 w = MAX( c->width_min , MIN( c->width_max , w ) );
1685 h = MAX( c->height_min, MIN( c->height_max, h ) );
1686
1687 return (( w == reg_geom->w ) || ( h == reg_geom->h ));
1688 }
1689
1690
1691
1692 /**@BEGINFUNC**************************************************************
1693
1694 Prototype : TV_BOOL TVCAPTUREConfigure(
1695 TV_CAPTURE *c,
1696 char **fail_reason )
1697
1698 Purpose : Looks at the requested capture parameters and determines
1699 whether capture can be started using the current settings.
1700
1701 Programmer : 03-Mar-97 Randall Hopper
1702
1703 Parameters : c - I: capture definition
1704 fail_reason - O: if configure failed, reason why (string)
1705
1706 Returns : T = Params OK - capture away; F = Nope, tweak somethin'
1707
1708 Globals : None.
1709
1710 **@ENDFUNC*****************************************************************/
1711
TVCAPTUREConfigure(TV_CAPTURE * c,char ** fail_reason)1712 TV_BOOL TVCAPTUREConfigure( TV_CAPTURE *c,
1713 char **fail_reason )
1714 {
1715 static char S_err_msg[ 128 ];
1716
1717 TV_BOOL ok = FALSE;
1718 TV_XSCREEN *x = &G_glob.x;
1719 TV_DISPLAY *d = &G_glob.display;
1720 TV_GEOM g;
1721 TV_UINT32 addr;
1722 TV_INT32 Bpp;
1723
1724 if ( c->contin_on == TRUE ) {
1725 strcpy( S_err_msg, "Continuous is running" );
1726 goto RETURN;
1727 }
1728
1729 if ( c->frame_cb_enabled && !c->frame_done_cb ) {
1730 strcpy( S_err_msg, "Frame done callback on, but no frame handler" );
1731 goto RETURN;
1732 }
1733
1734 if (( c->xfer_mode == TV_TRANSFER_DIRECT ) && ( d->win == None )) {
1735 strcpy( S_err_msg, "No X Window set for video" );
1736 goto RETURN;
1737 }
1738
1739 if ( c->xfer_mode == TV_TRANSFER_DIRECT )
1740 if ( !( x->visual_modes[ x->active_visual ] & TV_TRANSFER_DIRECT )) {
1741 strcpy( S_err_msg, "Active visual does not support direct video");
1742 goto RETURN;
1743 }
1744 else if ( !d->enabled ) {
1745 strcpy( S_err_msg, "Direct transfer only supported for video" );
1746 goto RETURN;
1747 }
1748
1749 /* Get capture geometry */
1750 if ( c->xfer_mode == TV_TRANSFER_DIRECT ) {
1751 TVSCREENUpdateWinGeometry();
1752 TVSCREENGetVideoWinGeom( &g );
1753 g.w = g.w / c->width_res * c->width_res;
1754 g.h = g.h / c->height_res * c->height_res;
1755 }
1756 else
1757 g = c->geom;
1758
1759 /* Verify res limits and precision (all modes) */
1760 if (( g.w != g.w / c->width_res * c->width_res ) ||
1761 ( g.h != g.h / c->height_res * c->height_res )) {
1762 sprintf( S_err_msg, "Capture geometry must be a multiple of %ldx%ld",
1763 c->width_res, c->height_res );
1764 goto RETURN;
1765 }
1766
1767 if (( g.w < c->width_min ) || ( g.w > c->width_max ) ||
1768 ( g.h < c->height_min ) || ( g.h > c->height_max )) {
1769 strcpy( S_err_msg,
1770 "Resolution beyond hardware or driver capabilities" );
1771 goto RETURN;
1772 }
1773
1774 /* Direct-video mode specific checks */
1775 if ( c->xfer_mode == TV_TRANSFER_DIRECT ) {
1776
1777 if ( !(x->visual_modes[ x->active_visual ] & TV_TRANSFER_DIRECT) ) {
1778 strcpy( S_err_msg,
1779 "Active X Visual does not support direct video" );
1780 goto RETURN;
1781 }
1782 if ( x->visual[ x->active_visual ].visualid !=
1783 x->fb_visual->visualid ) {
1784 strcpy( S_err_msg,
1785 "Active X Visual is not the visual of the frame buffer" );
1786 goto RETURN;
1787 }
1788 if ( d->win == None ) {
1789 strcpy( S_err_msg,
1790 "Direct video attempted with no window set" );
1791 goto RETURN;
1792 }
1793
1794 /* Make sure capture region lies entirely within video memory */
1795 /* (we don't have complex capture clipping support in the */
1796 /* driver yet, but when we do, update this). */
1797
1798 XUTILGetVisualBpp( TVDISPLAY, x->fb_visual, NULL, &Bpp );
1799 addr = x->base_addr + (g.y * x->pitch + g.x) * Bpp;
1800
1801 if (( g.x < 0 ) || ( g.y < 0 ) ||
1802 ( ( g.x+g.w-1 ) >= DisplayWidth ( TVDISPLAY, TVSCREEN ) ) ||
1803 ( ( g.y+g.h-1 ) >= DisplayHeight( TVDISPLAY, TVSCREEN ) )) {
1804 strcpy( S_err_msg,
1805 "Direct video region outside bounds of display" );
1806 goto RETURN;
1807 }
1808 else if ( addr + ( (g.h-1) * x->pitch + g.w ) * Bpp
1809 >= x->base_addr + x->bank_size ) {
1810 strcpy( S_err_msg,
1811 "Direct video region outside bounds of display" );
1812 goto RETURN;
1813 }
1814 }
1815
1816 ok = TRUE;
1817
1818 RETURN:
1819 if ( fail_reason != NULL )
1820 *fail_reason = ok ? NULL : S_err_msg;
1821 return ok;
1822 }
1823
1824 /**@BEGINFUNC**************************************************************
1825
1826 Prototype : void TVCAPTUREStart(
1827 TV_CAPTURE *c )
1828
1829 Purpose : Initiates capture using the mode/geom/etc. parameters
1830 set up previously.
1831
1832 Note: ALWAYS call TVCAPTUREStart before calling this
1833 function.
1834
1835 Programmer : 08-Mar-97 Randall Hopper
1836
1837 Parameters : c - I: capture state struct
1838
1839 Returns : None.
1840
1841 Globals : None.
1842
1843 **@ENDFUNC*****************************************************************/
1844
TVCAPTUREStart(TV_CAPTURE * c)1845 void TVCAPTUREStart( TV_CAPTURE *c )
1846 {
1847 static TV_BOOL S_done_a_single = False;
1848
1849 TV_XSCREEN *x = &G_glob.x;
1850 TV_INT32 larg;
1851 struct meteor_video video;
1852 struct meteor_geomet geom;
1853 TV_GEOM g;
1854 TV_PIXEL_GEOM pix_geom;
1855 TV_INT32 Bpp,
1856 idx;
1857 char *cfg_fail_msg;
1858 TV_BOOL audio_mute,
1859 flush_buf;
1860
1861 DRVPRINTF(( "\tCAPTURE Start %s\n",
1862 c->cap_mode == TV_CAPTURE_CONTINUOUS ? "Continuous":"Single"));
1863
1864 /* FIXME: Also lock out start when single captures in progress */
1865 if ( c->contin_on ) {
1866 fprintf( stderr, "TVCAPTUREStart when already running...ignored\n" );
1867 return;
1868 }
1869
1870 /* Double-check parameters (the caller should have already done this) */
1871 if ( !TVCAPTUREConfigure( c, &cfg_fail_msg ) ) {
1872 fprintf( stderr,
1873 "TVCAPTUREConfigure() in TVCAPTUREStart() failed: %s\n",
1874 cfg_fail_msg );
1875 return;
1876 }
1877
1878 /*-- Set destination attributes & geometry --*/
1879 g = c->geom;
1880
1881 geom.columns = g.w;
1882 geom.rows = g.h;
1883 geom.frames = 1;
1884 flush_buf = FALSE;
1885
1886 if ( c->xfer_mode == TV_TRANSFER_DIRECT ) {
1887 TV_BOOL swap_b,
1888 swap_s;
1889
1890 XUTILGetVisualBpp( TVDISPLAY, x->fb_visual, NULL, &Bpp );
1891
1892 video.addr = x->base_addr + (g.y * x->pitch + g.x) * Bpp;
1893 /*printf( "\n\tbase + (y * pitch + x) * Bpp = "
1894 "0x%x + (%d * %d + %d) * %d\n",
1895 x->base_addr, g.y, x->pitch, g.x, Bpp );*/
1896 video.width = x->pitch * Bpp;
1897 video.banksize = x->bank_size;
1898 video.ramsize = x->ram_size / 1024;
1899
1900 memset( &pix_geom, '\0', sizeof( pix_geom ) );
1901 pix_geom.type = TV_PIXELTYPE_RGB;
1902 pix_geom.Bpp = Bpp;
1903 pix_geom.mask[0] = x->fb_visual->red_mask;
1904 pix_geom.mask[1] = x->fb_visual->green_mask;
1905 pix_geom.mask[2] = x->fb_visual->blue_mask;
1906
1907 XUTILGetVisualSwaps( TVDISPLAY, x->fb_visual, &swap_b, &swap_s );
1908 pix_geom.swap_bytes = swap_b;
1909 pix_geom.swap_shorts = swap_s;
1910
1911 TVCAPTUREGetPixFmtByPixGeom( c, &pix_geom, &idx );
1912 if ( idx < 0 ) {
1913 fprintf( stderr, "TVCAPTUREStart: Visual pixel format not direct "
1914 "video capable\n" );
1915 return;
1916 }
1917 c->pix_geom_idx = idx;
1918 }
1919 else {
1920 video.addr = 0,
1921 video.width = 0,
1922 video.banksize = 0,
1923 video.ramsize = 0;
1924
1925 /* If TDEC is on, may be a while before old trash gets written on. */
1926 /* So tell the driver to flush the frame buffer before starting */
1927 /* capture. */
1928 if ( c->fps != c->fps_max )
1929 flush_buf = TRUE;
1930 }
1931 memcpy( &pix_geom, &c->pix_geom_list[ c->pix_geom_idx ],
1932 sizeof( pix_geom ) );
1933
1934 geom.oformat = c->bpp_format;
1935 if ( geom.rows <= c->height_max / 2 )
1936 geom.oformat |= METEOR_GEO_ODD_ONLY;
1937
1938 c->addr = (TV_UINT32) video.addr;
1939
1940 /*printf( "VIDEO = { addr 0x%.8x, width %d, banksize %d, ramsize %d }\n",
1941 video.addr, video.width, video.banksize, video.ramsize );*/
1942 if ( ioctl( c->fd, METEORSVIDEO, &video ) < 0 ) {
1943 DO_IOCTL_SERR( "METEORSVIDEO", &video );
1944 return;
1945 }
1946 /*printf( "GEOM = { %dx%d, frames %d, oformat 0x%.8x }\n",
1947 geom.columns, geom.rows, geom.frames, geom.oformat );*/
1948 if ( ioctl( c->fd, METEORSETGEO, &geom ) < 0 ) {
1949 DO_IOCTL_SERR( "METEORSETGEO", &geom );
1950 return;
1951 }
1952 /*printf( "SACTPIXFMT = { idx %d, Bpp %d, masks { %x,%x,%x }, "
1953 "swapb/s %d,%d }\n",
1954 pix_geom.index, pix_geom.Bpp, pix_geom.mask[0],
1955 pix_geom.mask[1], pix_geom.mask[2], pix_geom.swap_bytes,
1956 pix_geom.swap_shorts );*/
1957 if ( ioctl( c->fd, METEORSACTPIXFMT, &pix_geom.index ) < 0 ) {
1958 DO_IOCTL_SERR( "METEORSACTPIXFMT", &geom );
1959 return;
1960 }
1961
1962 #ifdef BT848SCBUF
1963 larg = flush_buf;
1964 if ( ioctl( c->fd, BT848SCBUF, &larg ) < 0 ) {
1965 DO_IOCTL_SERR( "BT848SCBUF", larg );
1966 return;
1967 }
1968 #endif
1969
1970 /* If user wants to know whenever a/the frame is complete, */
1971 /* add in a signal handler for this for single captures, or an Xt */
1972 /* timer for continuous captures. */
1973 /* NOTE: Done callback makes no sense for direct video transfers. */
1974 larg = METEOR_SIG_MODE_MASK;
1975
1976 #ifdef OLD__ALWAYS_USE_SIGNALS_NOW
1977 if ( c->frame_done_cb && c->frame_cb_enabled )
1978 if ( c->cap_mode == TV_CAPTURE_SINGLE )
1979 larg = SIGUSR1;
1980 else {
1981 S_frame_timer = XtAppAddTimeOut( TVAPPCTX,
1982 FRAME_TIMER_DELAY_MS(c->fps_max),
1983 TVCAPTUREFrameTimeoutCB, NULL );
1984 S_frame_timer_set = True;
1985 }
1986 #else
1987 if ( c->frame_done_cb && c->frame_cb_enabled )
1988 larg = SIGUSR1;
1989 #endif
1990
1991 if ( ioctl( c->fd, METEORSSIGNAL, &larg ) < 0 ) {
1992 DO_IOCTL_SERR( "METEORSSIGNAL", larg );
1993 return;
1994 }
1995
1996 /* Verify audio mute state is in sync (in case it didn't get started */
1997 /* on the initial map). */
1998 TVAUDIOGetMuteState( &audio_mute );
1999 TVCAPTURESetAudioMute( c, audio_mute );
2000
2001 /* OK, NOW FIRE IT UP */
2002
2003 if ( c->cap_mode == TV_CAPTURE_CONTINUOUS ) {
2004
2005 /* Queue up a CAP_SINGLE -- turns on audio on Wincast board */
2006 /* FIXME: We may not need to do this anymore */
2007 if ( !S_done_a_single ) {
2008 larg = METEOR_CAP_SINGLE;
2009 if ( ioctl( c->fd, METEORCAPTUR, &larg ) < 0 ) {
2010 DO_IOCTL_SERR( "METEOR_CAP_SINGLE", 0 );
2011 return;
2012 }
2013 S_done_a_single = True;
2014 }
2015
2016 /* FIXME: Fix spelling of "continuous" in the driver sometime */
2017 larg = METEOR_CAP_CONTINOUS;
2018 if ( ioctl( c->fd, METEORCAPTUR, &larg ) < 0 ) {
2019 DO_IOCTL_SERR( "METEOR_CAP_CONTINUOUS", 0 );
2020 return;
2021 }
2022 c->contin_on = True;
2023 }
2024 else {
2025 larg = METEOR_CAP_SINGLE;
2026 if ( ioctl( c->fd, METEORCAPTUR, &larg ) < 0 ) {
2027 DO_IOCTL_SERR( "METEOR_CAP_SINGLE", 0 );
2028 return;
2029 }
2030 S_done_a_single = True;
2031 }
2032 }
2033
2034
2035 /**@BEGINFUNC**************************************************************
2036
2037 Prototype : void TVCAPTUREStop(
2038 TV_CAPTURE *c )
2039
2040 Purpose : Stop a continuous capture, if one is running.
2041
2042 Programmer : 08-Mar-97 Randall Hopper
2043
2044 Parameters : c - I: capture state struct
2045
2046 Returns : None.
2047
2048 Globals : None.
2049
2050 **@ENDFUNC*****************************************************************/
2051
TVCAPTUREStop(TV_CAPTURE * c)2052 void TVCAPTUREStop( TV_CAPTURE *c )
2053 {
2054 TV_INT32 larg;
2055
2056 DRVPRINTF(( "\tCAPTURE Stop\n" ));
2057
2058 if ( !c->contin_on ) {
2059 fprintf( stderr, "TVCAPTUREStop called when not running...ignored\n");
2060 return;
2061 }
2062
2063 if ( S_frame_timer_set ) {
2064 if ( !G_in_x_error )
2065 XtRemoveTimeOut( S_frame_timer );
2066 S_frame_timer_set = False;
2067 }
2068
2069 /* Reset driver's signal so we don't keep getting interrupted */
2070 larg = METEOR_SIG_MODE_MASK;
2071 if ( ioctl( c->fd, METEORSSIGNAL, &larg ) < 0 ) {
2072 DO_IOCTL_SERR( "METEORSSIGNAL", larg );
2073 return;
2074 }
2075
2076 larg = METEOR_CAP_STOP_CONT;
2077 if ( ioctl( c->fd, METEORCAPTUR, &larg ) < 0 ) {
2078 DO_IOCTL_SERR( "METEOR_CAP_STOP_CONT", 0 );
2079 return;
2080 }
2081 c->contin_on = False;
2082
2083
2084 TVCAPTUREClearPendingFrames();
2085 }
2086