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 = &image;
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