Date: Fri, 10 Jul 1998 00:26:18 -0700 From: Amancio Hasty <hasty@rah.star-gate.com> To: Kevin Day <toasty@home.dragondata.com> Cc: multimedia@FreeBSD.ORG Subject: Re: bt848 driver will be checked in this Friday Message-ID: <199807100726.AAA10706@rah.star-gate.com> In-Reply-To: Your message of "Fri, 10 Jul 1998 02:15:39 CDT." <199807100715.CAA16725@home.dragondata.com>
next in thread | previous in thread | raw e-mail | index | archive | help
[-- Attachment #1 --] Please mail me the output of ./eeprom 0 128 which is available from http://www.freebsd.org/~ahasty/Bt848.html The Bt878 is an upgrade to the Bt848. Please recompile fxtv-0.47 with this tvcapture.c the problem is that your model has one extra MUX which Hauppauge uses for video input. Tnks, Amancio > > Download the latest driver from my ftp and it looks like you have a Bt878. > > > > ftp://rah.star-gate.com/pub/bt848.tar.gz > > > > Have Fun, > > Amancio > > > > I've already got the latest from there.... Still no go. > > Yeah, looking now... the picture of the card on the box shows a bt848... the > box says it's a bt848, but the chip itself has writing too smudged to read > what it really is.... > > Are bt878's compatible? > > Kevin [-- Attachment #2 --] /* * tvcapture.c * * API for controlling the capture card attributes and state. * * (C) 1997 Randall Hopper * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. 2. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* ******************** Include Files ************** */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <fcntl.h> #include <errno.h> #include <sys/mman.h> #include <machine/ioctl_bt848.h> #include <signal.h> #include "tvdefines.h" #include "tvtypes.h" #include "tvcapture.h" #include "app_rsrc.h" #include "glob.h" /* ******************** Local defines ************** */ /* For Fxtv 0.41/bktr driver Linux port -- remove when the latest is ported */ #ifdef OLD_TUNER_IFACE # define BT848SFMT METEORSFMT #endif #if defined(__FreeBSD__) # define DEV_BT848 "/dev/bktr%d" # define DEV_TUNER "/dev/tuner%d" #elif defined(linux) # warning FIXME: Does/how does Linux name multiple devices of the same type # warning Is there a consistent policy as in FreeBSD? # define DEV_BT848 "/dev/bt848" # define DEV_TUNER "/dev/bt848t" #endif /* Macros */ #define DO_IOCTL_GERR(str) fprintf(stderr, "ioctl(%s) failed: %s\n", \ str, strerror(errno) ) #define DO_IOCTL_SERR(str,arg) fprintf(stderr, "ioctl(%s, %ld) failed: %s\n",\ str, (long)arg, strerror(errno) ) #define HUE_MIN BT848_HUEMIN #define HUE_MAX (BT848_HUEMIN + BT848_HUERANGE) #define HUE_RANGE BT848_HUERANGE #define HUE_DRV_MIN BT848_HUEREGMIN #define HUE_DRV_RANGE (BT848_HUEREGMAX - BT848_HUEREGMIN + 1) #define BRIGHT_MIN BT848_BRIGHTMIN #define BRIGHT_MAX (BT848_BRIGHTMIN + BT848_BRIGHTRANGE) #define BRIGHT_RANGE BT848_BRIGHTRANGE #define BRIGHT_DRV_MIN BT848_BRIGHTREGMIN #define BRIGHT_DRV_RANGE (BT848_BRIGHTREGMAX - BT848_BRIGHTREGMIN + 1) #define CONTR_MIN BT848_CONTRASTMIN #define CONTR_MAX (BT848_CONTRASTMIN + BT848_CONTRASTRANGE) #define CONTR_RANGE BT848_CONTRASTRANGE #define CONTR_DRV_MIN BT848_CONTRASTREGMIN #define CONTR_DRV_RANGE (BT848_CONTRASTREGMAX - BT848_CONTRASTREGMIN + 1) #define SATU_MIN BT848_SATUMIN #define SATU_MAX (BT848_SATUMIN + BT848_SATURANGE) #define SATU_RANGE BT848_SATURANGE #define SATU_DRV_MIN BT848_SATUREGMIN #define SATU_DRV_RANGE (BT848_SATUREGMAX - BT848_SATUREGMIN + 1) #define SATV_MIN BT848_SATVMIN #define SATV_MAX (BT848_SATVMIN + BT848_SATVRANGE) #define SATV_RANGE BT848_SATVRANGE #define SATV_DRV_MIN BT848_SATVREGMIN #define SATV_DRV_RANGE (BT848_SATVREGMAX - BT848_SATVREGMIN + 1) #define NTSC_DIM_X 640 #define NTSC_DIM_Y 480 #define NTSC_FPS 30 #define PAL_DIM_X 768 #define PAL_DIM_Y 576 #define PAL_FPS 25 /* Max Single Frame Size (in bytes) for NTSC & PAL (4Bpp max) */ #define MAX_MMAP_BUF_SIZE ( MAX( NTSC_DIM_X,PAL_DIM_X ) * \ MAX( NTSC_DIM_Y,PAL_DIM_Y ) * 4 ) #define FRAME_TIMER_DELAY_MS(fps) (1000/(fps)) /* ******************** Private variables ************** */ static TV_INT32 S_frame_done_count = 0; static XtIntervalId S_frame_timer; static TV_BOOL S_frame_timer_set = False; /* ******************** Forward declarations ************** */ /* ******************** Function Definitions ************** */ /**@BEGINFUNC************************************************************** Prototype : static void TVCAPTUREDestroy() Purpose : Cleans up capture attributes (stops capture, closes files, frees mem, etc. Programmer : 07-Mar-97 Randall Hopper Parameters : None. Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ static void TVCAPTUREDestroy() { TV_CAPTURE *c = &G_glob.capture; if ( c->fd >= 0 ) { if ( c->contin_on ) TVCAPTUREStop( c ); close( c->fd ); } if ( c->tfd >= 0 ) close( c->tfd ); } /**@BEGINFUNC************************************************************** Prototype : static void TVCAPTUREFrameDoneSigHdlr() Purpose : Called when the driver finishes capturing a frame. Programmer : 07-Mar-97 Randall Hopper Parameters : None. Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ static void TVCAPTUREFrameDoneSigHdlr() { S_frame_done_count++; #ifdef linux # warning Huh? Do signal handlers get unregistered in Linux after delivery? signal( SIGUSR1, TVCAPTUREFrameDoneSigHdlr ); #endif } /**@BEGINFUNC************************************************************** Prototype : void TVCAPTUREWorkProc() Purpose : Xt work proc slave routine invoked to initiate behaviors associated with capturing frames. Programmer : 07-Mar-97 Randall Hopper Parameters : None. Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ void TVCAPTUREWorkProc() { static TV_CAPTURE *c = &G_glob.capture; TV_IMAGE img; if (( S_frame_done_count == 0 ) || ( c->frame_done_cb == NULL )) return; /* if ( S_frame_done_count > 0 ) DRVPRINTF(( "%d frames behind\n", S_frame_done_count )); */ S_frame_done_count--; img.buf = c->drv_buf; memcpy( &img.geom, &c->geom, sizeof( img.geom ) ); memcpy( &img.pix_geom, &c->pix_geom_list[ c->pix_geom_idx ], sizeof( img.pix_geom ) ); c->frame_done_cb( &img ); } /* TVCAPTUREClearPendingFrames: Reset/ignore any outstanding frames. */ void TVCAPTUREClearPendingFrames() { S_frame_done_count = 0; } /* TVCAPTUREGetPendingFrame - Get pending frame & ret T (ret F if none) */ TV_BOOL TVCAPTUREGetPendingFrame( TV_IMAGE **img ) { if ( S_frame_done_count > 0 ) { /* FIXME: Share this glob -- it's the WorkProc above w/o CB */ static TV_CAPTURE *c = &G_glob.capture; static TV_IMAGE image; if (( S_frame_done_count == 0 ) || ( c->frame_done_cb == NULL )) return; if ( S_frame_done_count-- > 0 ) DRVPRINTF(( "%d frames behind\n", S_frame_done_count )); image.buf = c->drv_buf; memcpy( &image.geom, &c->geom, sizeof( image.geom ) ); memcpy( &image.pix_geom, &c->pix_geom_list[ c->pix_geom_idx ], sizeof( image.pix_geom ) ); *img = ℑ return TRUE; } else { *img = NULL; return False; } } #ifdef OLD_ALWAYS_USE_SIGNALS_NOW /**@BEGINFUNC************************************************************** Prototype : static void TVCAPTUREFrameTimeoutCB( XtPointer cl_data, XtIntervalId *timer ) Purpose : Invoked during continuous capture to let us kick in frame done callback periodically (since signals aren't issued by the driver for frame completes when in continuous mode). Programmer : 08-Mar-97 Randall Hopper Parameters : cl_data - I: not used timer - I: not used Returns : Globals : None. **@ENDFUNC*****************************************************************/ static void TVCAPTUREFrameTimeoutCB( XtPointer cl_data, XtIntervalId *timer ) { TV_CAPTURE *c = &G_glob.capture; TV_IMAGE img; /* Invoke user-defined frame completion callback */ if ( c->frame_done_cb != NULL ) { img.buf = c->drv_buf; memcpy( &img.geom, &c->geom, sizeof( img.geom ) ); memcpy( &img.pix_geom, &c->pix_geom_list[ c->pix_geom_idx ], sizeof( img.pix_geom ) ); c->frame_done_cb( &img ); } /* And restart timer for another "frame" */ S_frame_timer = XtAppAddTimeOut( TVAPPCTX, FRAME_TIMER_DELAY_MS(c->fps_max), TVCAPTUREFrameTimeoutCB, NULL ); } #endif void TVCAPTURESetBrightness( TV_CAPTURE *c, double brightness ) { TV_INT32 larg; brightness = MAX( BRIGHT_MIN, MIN( BRIGHT_MAX, brightness ) ); larg = (brightness - BRIGHT_MIN) / (BRIGHT_RANGE + 0.01) * BRIGHT_DRV_RANGE + BRIGHT_DRV_MIN; larg = MAX( BRIGHT_DRV_MIN, MIN( BRIGHT_DRV_MIN+BRIGHT_DRV_RANGE-1, larg )); if ( ioctl( c->tfd, BT848_SBRIG, &larg ) < 0 ) { DO_IOCTL_SERR( "BT848_SBRIG", larg ); return; } /* FIXME: Dead code */ c->brightness = brightness; } void TVCAPTURESetContrast( TV_CAPTURE *c, double contrast ) { TV_INT32 larg; contrast = MIN( CONTR_MAX, MAX( CONTR_MIN, contrast ) ); larg = (contrast - CONTR_MIN) / (CONTR_RANGE + 0.01) * CONTR_DRV_RANGE + CONTR_DRV_MIN; larg = MAX( CONTR_DRV_MIN, MIN( CONTR_DRV_MIN+CONTR_DRV_RANGE-1, larg ) ); if ( ioctl( c->tfd, BT848_SCONT, &larg ) < 0 ) { DO_IOCTL_SERR( "BT848_SCONT", larg ); return; } /* FIXME: Dead code */ c->contrast = contrast; } void TVCAPTURESetHue( TV_CAPTURE *c, double hue ) { TV_INT32 larg; hue = MIN( HUE_MAX, MAX( HUE_MIN, hue ) ); larg = (hue - HUE_MIN) / (HUE_RANGE + 0.01) * HUE_DRV_RANGE + HUE_DRV_MIN; larg = MAX( HUE_DRV_MIN, MIN( HUE_DRV_MIN+HUE_DRV_RANGE-1, larg )); if ( ioctl( c->tfd, BT848_SHUE, &larg ) < 0 ) { DO_IOCTL_SERR( "BT848_SHUE", larg ); return; } /* FIXME: Dead code */ c->hue = hue; } void TVCAPTURESetSatU( TV_CAPTURE *c, double sat_u ) { TV_INT32 larg; sat_u = MIN( SATU_MAX, MAX( SATU_MIN, sat_u ) ); larg = (sat_u - SATU_MIN) / (SATU_RANGE + 0.01) * SATU_DRV_RANGE + SATU_DRV_MIN; larg = MAX( SATU_DRV_MIN, MIN( SATU_DRV_MIN+SATU_DRV_RANGE-1, larg ) ); if ( ioctl( c->tfd, BT848_SUSAT, &larg ) < 0 ) { DO_IOCTL_SERR( "BT848_SUSAT", larg ); return; } /* FIXME: Dead code */ c->sat_u = sat_u; } void TVCAPTURESetSatV( TV_CAPTURE *c, double sat_v ) { TV_INT32 larg; sat_v = MIN( SATV_MAX, MAX( SATV_MIN, sat_v ) ); larg = (sat_v - SATV_MIN) / (SATV_RANGE + 0.01) * SATV_DRV_RANGE + SATV_DRV_MIN; larg = MAX( SATV_DRV_MIN, MIN( SATV_DRV_MIN+SATV_DRV_RANGE-1, larg ) ); if ( ioctl( c->tfd, BT848_SVSAT, &larg ) < 0 ) { DO_IOCTL_SERR( "BT848_SVSAT", larg ); return; } /* FIXME: Dead code */ c->sat_v = sat_v; } void TVCAPTURESetAppearanceParam( TV_CAPTURE *c, TV_DRIVER_PARAM p, double val ) { switch ( p ) { case TV_PARAM_HUE : TVCAPTURESetHue ( c, val ); break; case TV_PARAM_BRIGHT : TVCAPTURESetBrightness( c, val ); break; case TV_PARAM_CONTRAST : TVCAPTURESetContrast ( c, val ); break; case TV_PARAM_SATU : TVCAPTURESetSatU ( c, val ); break; case TV_PARAM_SATV : TVCAPTURESetSatV ( c, val ); break; default : fprintf( stderr, "TVCAPTURESetAppearanceParam: Unsupported param %d\n", p ); exit(1); } } void TVCAPTURESetInputFormat( TV_CAPTURE *c, TV_INPUT_FORMAT format ) { TV_INT32 larg; switch ( format ) { case TV_INPUT_NTSCM : larg = BT848_IFORM_F_NTSCM ; break; case TV_INPUT_NTSCJ : larg = BT848_IFORM_F_NTSCJ ; break; case TV_INPUT_PALBDGHI : larg = BT848_IFORM_F_PALBDGHI; break; case TV_INPUT_PALM : larg = BT848_IFORM_F_PALM ; break; case TV_INPUT_PALN : larg = BT848_IFORM_F_PALN ; break; case TV_INPUT_SECAM : larg = BT848_IFORM_F_SECAM ; break; case TV_INPUT_PALNCOMB : larg = BT848_IFORM_F_RSVD ; break; default : case TV_INPUT_AUTO : fprintf( stderr, "TVCAPTURESetInputFormat: Unsupported format %d\n", format ); exit(1); } if ( ioctl( c->fd, BT848SFMT, &larg ) < 0 ) { DO_IOCTL_SERR( "BT848SFMT", larg ); return; } /* Update max capture size based on driver format */ /* FIXME: These belong in the driver/driver include file */ switch ( format ) { case TV_INPUT_NTSCM : case TV_INPUT_NTSCJ : case TV_INPUT_PALM : c->width_max = NTSC_DIM_X; c->height_max = NTSC_DIM_Y; c->fps_max = NTSC_FPS; break; case TV_INPUT_PALBDGHI : case TV_INPUT_PALN : case TV_INPUT_SECAM : case TV_INPUT_PALNCOMB : c->width_max = PAL_DIM_X; c->height_max = PAL_DIM_Y; c->fps_max = PAL_FPS; break; } /* FIXME: Dead code */ c->input_format = format; } void TVCAPTURESetInputDevice( TV_CAPTURE *c, TV_INPUT_DEVICE dev ) { int arg, old_audio; /* FIXME: Move all driver set calls out of Start() into these */ /* set calls. */ if ( c->contin_on ) { fprintf( stderr, "TVCAPTURESetInputDevice(): Called when capture is on\n" ); return; } /* Driver FIXME: Hack to get around driver unmuting audio across */ /* channel, freq, and input device changes. */ if ( ioctl( c->tfd, BT848_GAUDIO, &old_audio ) < 0 ) { DO_IOCTL_GERR( "BT848_GAUDIO" ); return; } switch ( dev ) { case TV_DEVICE_TUNER : arg = METEOR_DEV1; break; case TV_DEVICE_VIDEO : arg = METEOR_INPUT_DEV3; break; case TV_DEVICE_SVIDEO : arg = METEOR_DEV2; break; default : fprintf( stderr, "TVCAPTURESetInputDevice(): Bad value %d\n", dev ); return; } if ( ioctl( c->fd, METEORSINPUT, &arg ) < 0 ) { fprintf( stderr, "ioctl(METEORSINPUT, %d) failed: %s\n", arg, strerror(errno) ); return; } /* FIXME: Dead code */ c->input_dev = arg; /* When we did that last SINPUT, the driver auto-selected the */ /* audio input correct for that video input. Override it */ /* if the user has requested this. */ if ( c->audio_input_dev != TV_AUDIO_INPUT_AUTO ) { switch ( c->audio_input_dev ) { default : case TV_AUDIO_INPUT_TUNER : arg = AUDIO_TUNER; break; case TV_AUDIO_INPUT_EXTERN : arg = AUDIO_EXTERN; break; case TV_AUDIO_INPUT_INTERN : arg = AUDIO_INTERN; break; } if ( ioctl( c->tfd, BT848_SAUDIO, &arg ) < 0 ) { fprintf( stderr, "ioctl(BT848_SAUDIO, %d) failed: %s\n", arg, strerror(errno) ); return; } } /* Restore the old mute setting */ old_audio &= AUDIO_MUTE; if ( old_audio ) TVCAPTURESetAudioMute( c, TRUE ); } void TVCAPTURESetAudioInputDevice( TV_CAPTURE *c, TV_AUDIO_INPUT_DEVICE dev ) { int arg; /* FIXME: Move all driver set calls out of Start() into these */ /* set calls. */ if ( c->contin_on ) { fprintf( stderr, "TVCAPTURESetAudioInputDevice(): " "Called when capture is on\n" ); return; } switch ( dev ) { case TV_AUDIO_INPUT_AUTO : break; case TV_AUDIO_INPUT_TUNER : arg = AUDIO_TUNER; break; case TV_AUDIO_INPUT_EXTERN : arg = AUDIO_EXTERN; break; case TV_AUDIO_INPUT_INTERN : arg = AUDIO_INTERN; break; default : fprintf( stderr, "TVCAPTURESetAudioInputDevice(): Bad value %d\n", dev ); return; } /* NOTE: AUTO means we don't monkey with the defaults selected by */ /* the driver. Other values mean we always override the driver */ /* to keep that setting whenever it wants to change the setting. */ if ( dev != TV_AUDIO_INPUT_AUTO ) { if ( ioctl( c->tfd, BT848_SAUDIO, &arg ) < 0 ) { fprintf( stderr, "ioctl(BT848_SAUDIO, %d) failed: %s\n", arg, strerror(errno) ); return; } c->audio_input_dev = dev; } else { TV_DRIVER_STATE s; c->audio_input_dev = dev; /* Force driver to reset audio input back to its default */ if ( !TVCAPTUREQueryDriverState( c, &s ) ) { fprintf( stderr, "TVCAPTUREQueryDriverState() failed\n" ); exit(1); } /* This funny business so the driver will actually reset the input */ TVCAPTURESetInputDevice( c, TV_DEVICE_TUNER ); TVCAPTURESetInputDevice( c, TV_DEVICE_VIDEO ); TVCAPTURESetInputDevice( c, s.input_dev ); } } void TVCAPTURESetTunerChannel( TV_CAPTURE *c, TV_INT32 chan_num ) { TV_INT32 larg = chan_num; int old_audio; /* Driver FIXME: Hack to get around driver unmuting audio across */ /* channel, freq, and input device changes. */ if ( ioctl( c->tfd, BT848_GAUDIO, &old_audio ) < 0 ) { DO_IOCTL_GERR( "BT848_GAUDIO" ); return; } if ( ioctl( c->tfd, TVTUNER_SETCHNL, &larg ) < 0 ) { DO_IOCTL_SERR( "TVTUNER_SETCHNL", larg ); return; } c->tuner_chan_active = TRUE; old_audio &= AUDIO_MUTE; if ( old_audio ) TVCAPTURESetAudioMute( c, TRUE ); } void TVCAPTURESetTunerFreq( TV_CAPTURE *c, double freq ) { TV_INT32 larg = freq * FREQFACTOR; int old_audio; /* Driver FIXME: Hack to get around driver unmuting audio across */ /* channel, freq, and input device changes. */ if ( ioctl( c->tfd, BT848_GAUDIO, &old_audio ) < 0 ) { DO_IOCTL_GERR( "BT848_GAUDIO" ); return; } if ( ioctl( c->tfd, TVTUNER_SETFREQ, &larg ) < 0 ) { DO_IOCTL_SERR( "TVTUNER_SETFREQ", larg ); return; } c->tuner_chan_active = FALSE; old_audio &= AUDIO_MUTE; if ( old_audio ) TVCAPTURESetAudioMute( c, TRUE ); } void TVCAPTURESetTunerFreqSet( TV_CAPTURE *c, TV_FREQ_SET set ) { TV_INT32 larg; switch ( set ) { case TV_FREQ_SET_NABCST : larg = CHNLSET_NABCST ; break; case TV_FREQ_SET_CABLEIRC : larg = CHNLSET_CABLEIRC; break; case TV_FREQ_SET_CABLEHRC : larg = CHNLSET_CABLEHRC; break; case TV_FREQ_SET_WEUROPE : larg = CHNLSET_WEUROPE ; break; case TV_FREQ_SET_JPNBCST : larg = CHNLSET_JPNBCST ; break; case TV_FREQ_SET_JPNCABLE : larg = CHNLSET_JPNCABLE; break; default : fprintf( stderr, "TVCAPTURESetTunerFreqSet(): Bad freq set %d\n", set ); return; } if ( ioctl( c->tfd, TVTUNER_SETTYPE, &larg ) < 0 ) { DO_IOCTL_SERR( "TVTUNER_SETTYPE", larg ); return; } /* FIXME: Hack to force a channel freq recompute in the driver */ /* when we change modes. */ { TV_DRIVER_STATE s; if ( !TVCAPTUREQueryDriverState( c, &s ) ) { fprintf( stderr, "TVCAPTUREQueryDriverState() failed\n" ); exit(1); } TVCAPTURESetTunerChannel( c, s.tuner_chan ); } } void TVCAPTURESetAfc( TV_CAPTURE *c, TV_BOOL afc ) { if ( ioctl( c->tfd, TVTUNER_SETAFC, &afc ) < 0 ) { DO_IOCTL_SERR( "TVTUNER_SETAFC", afc ); return; } } void TVCAPTURESetAudioMute( TV_CAPTURE *c, TV_BOOL mute ) { int arg = ( mute ? AUDIO_MUTE : AUDIO_UNMUTE ); /* If audio is disabled, don't ever unmute */ if ( !App_res.do_audio ) arg = AUDIO_MUTE; /* Don't change audio source; just mute it */ if ( ioctl( c->tfd, BT848_SAUDIO, &arg ) < 0 ) { DO_IOCTL_SERR( "BT848_SAUDIO", arg ); return; } } void TVCAPTURESetColorbars ( TV_CAPTURE *c, TV_BOOL colorbars ) { int ioctl_num = ( colorbars ? BT848_SCBARS : BT848_CCBARS ); char *ioctl_str = ( colorbars ? "BT848_SCBARS" : "BT848_CCBARS" ); int dummy; /* Don't change audio source; just mute it */ if ( ioctl( c->tfd, ioctl_num, &dummy ) < 0 ) { DO_IOCTL_SERR( ioctl_str, dummy ); return; } } void TVCAPTURESetFPS ( TV_CAPTURE *c, TV_UINT32 fps ) { TV_UINT16 usarg = MAX( 0, MIN( c->fps_max, fps ) ); if ( ioctl( c->fd, METEORSFPS, &usarg ) < 0 ) { DO_IOCTL_SERR( "METEORSFPS", usarg ); return; } /* FIXME: Dead code */ c->fps = usarg; } void TVCAPTURESetFrameDoneCBEnabled( TV_CAPTURE *c, TV_BOOL enable ) { c->frame_cb_enabled = enable; } void TVCAPTUREGetFPSMax( TV_CAPTURE *c, TV_UINT32 *fps_max ) { *fps_max = c->fps_max; } /**@BEGINFUNC************************************************************** Prototype : TV_BOOL TVCAPTUREQueryDriverState( TV_CAPTURE *c, TV_DRIVER_STATE *s ) Purpose : Queries the driver for all of its current parameters. Programmer : 16-Mar-97 Randall Hopper Parameters : c - I: capture device struct s - O: driver state Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ TV_BOOL TVCAPTUREQueryDriverState( TV_CAPTURE *c, TV_DRIVER_STATE *s ) { TV_INT32 larg; TV_UINT16 usarg; #ifdef NOT_NEEDED struct meteor_counts counts; struct meteor_video video; #endif memset( s, '\0', sizeof( *s ) ); /* INPUT DEVICE */ if ( ioctl( c->fd, METEORGINPUT, &larg ) < 0 ) { DO_IOCTL_GERR( "METEORGINPUT" ); return False; } switch ( larg ) { case METEOR_DEV0: case METEOR_INPUT_DEV3 : s->input_dev = TV_DEVICE_VIDEO ; break; case METEOR_DEV1 : s->input_dev = TV_DEVICE_TUNER ; break; case METEOR_DEV2 : s->input_dev = TV_DEVICE_SVIDEO; break; default : fprintf( stderr, "TVCAPTUREQueryDriverState(): Bad INPUT %d\n", larg ); return False; } /* INPUT FORMAT */ if ( ioctl( c->fd, BT848GFMT, &larg ) < 0 ) { DO_IOCTL_GERR( "BT848GFMT" ); return False; } switch ( larg ) { case BT848_IFORM_F_AUTO : s->input_fmt = TV_INPUT_AUTO ; break; case BT848_IFORM_F_NTSCM : s->input_fmt = TV_INPUT_NTSCM ; break; case BT848_IFORM_F_NTSCJ : s->input_fmt = TV_INPUT_NTSCJ ; break; case BT848_IFORM_F_PALBDGHI: s->input_fmt = TV_INPUT_PALBDGHI; break; case BT848_IFORM_F_PALM : s->input_fmt = TV_INPUT_PALM ; break; case BT848_IFORM_F_PALN : s->input_fmt = TV_INPUT_PALN ; break; case BT848_IFORM_F_SECAM : s->input_fmt = TV_INPUT_SECAM ; break; case BT848_IFORM_F_RSVD : s->input_fmt = TV_INPUT_PALNCOMB; break; default : fprintf( stderr, "TVCAPTUREQueryDriverState(): Bad FMT %d\n", larg ); return False; } /* CAPTURE DESTINATION */ #ifdef NOT_NEEDED if ( ioctl( c->fd, METEOR_GVIDEO, &video ) < 0 ) { DO_IOCTL_GERR( "METEOR_GVIDEO" ); return False; } #endif /* FRAMES PER SEC */ if ( ioctl( c->fd, METEORGFPS, &usarg ) < 0 ) { DO_IOCTL_GERR( "METEORGFPS" ); return False; } s->fps = usarg; /* SIGNAL */ #ifdef NOT_NEEDED if ( ioctl( c->fd, METEOR_GSIGNAL, &larg ) < 0 ) { DO_IOCTL_GERR( "METEOR_GSIGNAL" ); return False; } s->signal = larg; #endif /* CAPTURE STATISTICS */ #ifdef NOT_NEEDED if ( ioctl( c->fd, METEOR_GCOUNT, &counts ) < 0 ) { DO_IOCTL_GERR( "METEOR_GCOUNT" ); return False; } s->stats.frames_captured = counts.frames_captured; #endif /* HUE */ if ( ioctl( c->tfd, BT848_GHUE, &larg ) < 0 ) { DO_IOCTL_GERR( "BT848_GHUE" ); return False; } /* Driver FIXME: Hack needed since 970322 driver is using an int, but */ /* isn't returning -128-127 range as in SHUE, but rather 0..255. */ if ( larg >= 128 ) larg -= 256; s->hue = ((double)larg - HUE_DRV_MIN) / HUE_DRV_RANGE * HUE_RANGE + HUE_MIN; /* BRIGHTNESS */ if ( ioctl( c->tfd, BT848_GBRIG, &larg ) < 0 ) { DO_IOCTL_GERR( "BT848_GBRIG" ); return False; } /* Driver FIXME: Hack needed since 970322 driver is using an int, but */ /* isn't returning -128-127 range as in SHUE, but rather 0..255. */ if ( larg >= 128 ) larg -= 256; s->brightness = ((double)larg - BRIGHT_DRV_MIN) / BRIGHT_DRV_RANGE * BRIGHT_RANGE + BRIGHT_MIN; /* CONTRAST */ if ( ioctl( c->tfd, BT848_GCONT, &larg ) < 0 ) { DO_IOCTL_GERR( "BT848_GCONT" ); return False; } s->contrast = ((double)larg - CONTR_DRV_MIN) / CONTR_DRV_RANGE * CONTR_RANGE + CONTR_MIN; /* CHROMA U SATURATION */ if ( ioctl( c->tfd, BT848_GUSAT, &larg ) < 0 ) { DO_IOCTL_GERR( "BT848_GUSAT" ); return False; } s->sat_u = ((double)larg - SATU_DRV_MIN) / SATU_DRV_RANGE * SATU_RANGE + SATU_MIN; /* CHROMA V SATURATION */ if ( ioctl( c->tfd, BT848_GVSAT, &larg ) < 0 ) { DO_IOCTL_GERR( "BT848_GVSAT" ); return False; } s->sat_v = ((double)larg - SATV_DRV_MIN) / SATV_DRV_RANGE * SATV_RANGE + SATV_MIN; /* TUNER TYPE */ if ( ioctl( c->tfd, TVTUNER_GETTYPE, &larg ) < 0 ) { DO_IOCTL_GERR( "TVTUNER_GETTYPE" ); return False; } switch ( larg ) { case CHNLSET_NABCST : s->tuner_freq_set = TV_FREQ_SET_NABCST ; break; case CHNLSET_CABLEIRC : s->tuner_freq_set = TV_FREQ_SET_CABLEIRC; break; case CHNLSET_CABLEHRC : s->tuner_freq_set = TV_FREQ_SET_CABLEHRC; break; case CHNLSET_WEUROPE : s->tuner_freq_set = TV_FREQ_SET_WEUROPE ; break; case CHNLSET_JPNBCST : s->tuner_freq_set = TV_FREQ_SET_JPNBCST ; break; case CHNLSET_JPNCABLE : s->tuner_freq_set = TV_FREQ_SET_JPNCABLE; break; default : fprintf( stderr, "TVCAPTUREQueryDriverState(): Bad CHNLSET %d\n", larg ); return False; } /* FIXME: This is a hack because we can't query this info */ /* from the driver. */ s->tuner_chan_active = c->tuner_chan_active; /* TUNER CHANNEL */ if ( ioctl( c->tfd, TVTUNER_GETCHNL, &larg ) < 0 ) { DO_IOCTL_GERR( "TVTUNER_GETCHNL" ); return False; } s->tuner_chan = larg; /* TUNER FREQUENCY */ if ( ioctl( c->tfd, TVTUNER_GETFREQ, &larg ) < 0 ) { DO_IOCTL_GERR( "TVTUNER_GETFREQ" ); return False; } s->tuner_freq = (double)larg / FREQFACTOR; /* AUDIO MUTE AND INPUT STATE */ if ( ioctl( c->tfd, BT848_GAUDIO, &larg ) < 0 ) { DO_IOCTL_GERR( "BT848_GAUDIO" ); return False; } s->audio_mute = (larg & AUDIO_MUTE) != 0; switch ( larg & ~AUDIO_MUTE ) { default : case AUDIO_TUNER : s->audio_input_dev = TV_AUDIO_INPUT_TUNER ; break; case AUDIO_EXTERN : s->audio_input_dev = TV_AUDIO_INPUT_EXTERN; break; case AUDIO_INTERN : s->audio_input_dev = TV_AUDIO_INPUT_INTERN; break; } return True; } void TVCAPTUREQueryParamLimits( TV_CAPTURE *c, TV_DRIVER_PARAM p, double lim[2] ) { static struct { TV_DRIVER_PARAM p; double lim[2]; } S_param_lim[] = { { TV_PARAM_HUE , { HUE_MIN , HUE_MAX } }, { TV_PARAM_BRIGHT , { BRIGHT_MIN, BRIGHT_MAX } }, { TV_PARAM_CONTRAST, { CONTR_MIN , CONTR_MAX } }, { TV_PARAM_SATU , { SATU_MIN , SATU_MAX } }, { TV_PARAM_SATV , { SATV_MIN , SATV_MAX } } }; TV_INT32 i; for ( i = 0; i < XtNumber( S_param_lim ); i++ ) if ( S_param_lim[i].p == p ) break; if ( i >= XtNumber( S_param_lim ) ) { fprintf( stderr, "TVCAPTUREQueryParamLimits: Unsupported driver param (%d)", p ); exit(1); } memcpy( lim, S_param_lim[i].lim, sizeof( S_param_lim[i].lim ) ); } /**@BEGINFUNC************************************************************** Prototype : void TVCAPTUREQueryPixelFormats( TV_CAPTURE *c, TV_PIXEL_GEOM **list, TV_UINT32 *list_size ) Purpose : Query all the support RGB pixel formats from the capture driver and store them in a local list for fast access. Programmer : 20-Apr-97 Randall Hopper Parameters : c - I: capture definition structure list - O: allocated/filled in list of pixel formats list_size - O: resulting size of list Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ void TVCAPTUREQueryPixelFormats( TV_CAPTURE *c, TV_PIXEL_GEOM **list, TV_UINT32 *list_size ) { /* FIXME: This belongs in the driver where we can query it using */ /* the pixmap formats interface. */ static TV_PIXEL_GEOM YUV_h422_v111 = { -1,TV_PIXELTYPE_YUV,0,{},0,0, {8,8,8},{1,2,2},{1,1,1},TV_FRAME_PLANAR,"YUV",1,1,0 }, YUV_h422_v422 = { -1,TV_PIXELTYPE_YUV,0,{},0,0, {8,8,8},{1,2,2},{1,2,2},TV_FRAME_PLANAR,"YUV",1,1,0 }; struct meteor_pixfmt pf; TV_UINT32 i; TV_PIXEL_GEOM *pg; *list = NULL; *list_size = 0; for ( i = 0; ; i++ ) { pf.index = i; if ( ioctl( c->fd, METEORGSUPPIXFMT, &pf ) < 0 ) { if ( errno == EINVAL ) break; DO_IOCTL_GERR( "METEORGSUPPIXFMT" ); } /* Expand list */ (*list_size)++; *list = realloc( *list, *list_size * sizeof( (*list)[0] ) ); if ( *list == NULL ) TVUTILOutOfMemory(); /* Store new record */ pg = &(*list)[ *list_size - 1 ]; memset( pg, '\0', sizeof( *pg ) ); if ( pf.type == METEOR_PIXTYPE_RGB ) { pg->type = TV_PIXELTYPE_RGB; pg->Bpp = pf.Bpp; pg->mask[0] = pf.masks[0]; pg->mask[1] = pf.masks[1]; pg->mask[2] = pf.masks[2]; pg->swap_bytes = pf.swap_bytes; pg->swap_shorts = pf.swap_shorts; } /* FIXME: These should be parameterized subtypes of YUV in */ /* the driver, not separate types. This would eliminate */ /* confusion due to these legacy names, and make us */ /* more independent of the capabilities of the driver. */ /* FIXME: Extend the driver interface to pass us these YUV */ /* parms for each YUV subtype */ else if (( pf.type == METEOR_PIXTYPE_YUV ) || ( pf.type == METEOR_PIXTYPE_YUV_PACKED ) || ( pf.type == METEOR_PIXTYPE_YUV_12 )) { pg->type = TV_PIXELTYPE_YUV; switch ( pf.type ) { case METEOR_PIXTYPE_YUV : memcpy( pg, &YUV_h422_v111, sizeof(*pg) ); pg->frame_packing = TV_FRAME_PLANAR; strcpy( pg->comp_order, "YUV" ); break; case METEOR_PIXTYPE_YUV_PACKED : /* 4CC Code: YUY2 */ memcpy( pg, &YUV_h422_v111, sizeof(*pg) ); pg->frame_packing = TV_FRAME_PACKED; strcpy( pg->comp_order, "YUYV" ); break; case METEOR_PIXTYPE_YUV_12 : /* 4CC Code: IYUV/I420 */ memcpy( pg, &YUV_h422_v422, sizeof(*pg) ); pg->frame_packing = TV_FRAME_PLANAR; strcpy( pg->comp_order, "YUV" ); break; } } else { fprintf( stderr, "Unsupported pixel type: %d\n", pg->type ); exit(1); } pg->index = pf.index; } } /**@BEGINFUNC************************************************************** Prototype : void TVCAPTUREGetNumPixFmts( TV_CAPTURE *c, TV_UINT32 *num ) Prototype : void TVCAPTUREGetNthPixFmt ( TV_CAPTURE *c, TV_UINT32 index, TV_PIXEL_GEOM *geom ) Prototype : void TVCAPTUREGetPixFmtByDriverHandle( TV_CAPTURE *c, TV_UINT32 handle, TV_INT32 *index ) Prototype : void TVCAPTUREGetPixFmtByPixGeom( TV_CAPTURE *c, TV_PIXEL_GEOM *geom, TV_INT32 *index ) Purpose : Query API for the pixel formats supported by out capture device. Programmer : 20-Apr-97 Randall Hopper Parameters : c - I: capture struct num - O: num pixel formats index - I: index into pixel formats list handle - I: driver handle for pixel format geom - O: nth pixel format definition Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ void TVCAPTUREGetNumPixFmts( TV_CAPTURE *c, TV_UINT32 *num ) { *num = c->pix_geom_list_len; } void TVCAPTUREGetNthPixFmt ( TV_CAPTURE *c, TV_UINT32 index, TV_PIXEL_GEOM *geom ) { if ( index >= c->pix_geom_list_len ) { fprintf( stderr, "TVCAPTUREGetNthPixFmt: Index out of range\n" ); exit(1); } *geom = c->pix_geom_list[ index ]; } void TVCAPTUREGetPixFmtByDriverHandle( TV_CAPTURE *c, TV_UINT32 handle, TV_INT32 *index ) { TV_UINT32 i; for ( i = 0; i < c->pix_geom_list_len; i++ ) if ( handle == c->pix_geom_list[i].index ) break; *index = ( i >= c->pix_geom_list_len ) ? -1 : i; } static TV_BOOL TVCAPTUREMaskIsaByte ( TV_UINT32 mask ) { TV_BOOL isa_byte = FALSE; TV_INT32 i; for ( i = 0; i < sizeof( mask ); i++, mask >>= 8 ) if ( mask & 0xff ) { if (( (mask & 0xff) == 0xff ) && ( (mask >> 8) == 0 )) isa_byte = TRUE; break; } return isa_byte; } void TVCAPTUREGetPixFmtByPixGeom( TV_CAPTURE *c, TV_PIXEL_GEOM *geom, TV_INT32 *index ) { static TV_BOOL S_recursive_lock = FALSE; TV_UINT32 i; for ( i = 0; i < c->pix_geom_list_len; i++ ) if (( geom->type == c->pix_geom_list[i].type ) && ( geom->Bpp == c->pix_geom_list[i].Bpp ) && !memcmp( geom->mask, c->pix_geom_list[i].mask, sizeof( geom->mask ) ) && ( geom->swap_bytes == c->pix_geom_list[i].swap_bytes ) && ( geom->swap_shorts == c->pix_geom_list[i].swap_shorts )) break; /* Handle a few of the strange byte-swapped combinations for */ /* 3 and 4 bpp. */ /* This lets us deal with visuals that return masks like */ /* the Mach64 which is RGBA frame buffer (with pixmap */ /* depth of 32 with visual masks of ff,ff00,ff0000) */ if ( ( i >= c->pix_geom_list_len ) && (( geom->Bpp == 3 ) || ( geom->Bpp == 4 )) && TVCAPTUREMaskIsaByte( geom->mask[0] ) && TVCAPTUREMaskIsaByte( geom->mask[1] ) && TVCAPTUREMaskIsaByte( geom->mask[2] ) ) { TV_PIXEL_GEOM g = *geom; g.mask[0] = geom->mask[2], g.mask[2] = geom->mask[0]; g.swap_bytes = !g.swap_bytes; if ( g.Bpp == 4 ) g.swap_shorts = !g.swap_shorts; } *index = ( i >= c->pix_geom_list_len ) ? -1 : i; } void TVCAPTUREPrintPixelFormats( TV_CAPTURE *c ) { TV_INT32 i, j, bpp, swap; TV_UINT32 mask; TV_PIXEL_GEOM *pg; /* Dump capture pixel formats for debugging purposes */ /* PRINT RGB FORMATS */ SUPRINTF(( "\nSupported RGB Capture Pixel Formats:\n" " bpp Bpp RGB Masks Swap\n" " --- --- ---------------------------- ----\n" )); for ( i = 0; i < c->pix_geom_list_len; i++ ) { char swap_chars[5]; TV_INT32 j; TV_PIXEL_GEOM scratch; TV_BOOL printit = TRUE; pg = &c->pix_geom_list[ i ]; if ( pg->type != TV_PIXELTYPE_RGB ) continue; /* Browse list and see if we've got other pixel formats */ /* with the same type/Bpp/mask but different swap permutations */ memset( swap_chars, ' ', sizeof( swap_chars ) ); swap_chars[4] = '\0'; for ( swap = 0; swap < 4; swap++ ) { scratch = *pg; scratch.swap_bytes = (swap & 0x01) != 0; scratch.swap_shorts = (swap & 0x02) != 0; TVCAPTUREGetPixFmtByPixGeom( c, &scratch, &j ); if ( j < 0 ) continue; if ( j < i ) { printit = FALSE; break; } swap_chars[ swap ] = "NBWb"[ swap ]; } if ( !printit ) continue; /* Calculate bpp from masks */ mask = pg->mask[0] | pg->mask[1] | pg->mask[2]; bpp = 0; while ( mask != 0 ) { if ( mask & 0x01 ) bpp++; mask >>= 1; } SUPRINTF(( " %2d %2d %.8x, %.8x, %.8x %s\n", bpp, pg->Bpp, pg->mask[0], pg->mask[1], pg->mask[2], swap_chars )); } /* PRINT YUV FORMATS */ SUPRINTF(( "\nSupported YUV Capture Pixel Formats:\n" " YUVSize HSamp VSamp Pack CompOrder T->B L->R YTrans\n" " ------- ----- ----- ------ --------- ---- ---- ------\n" )); for ( i = 0; i < c->pix_geom_list_len; i++ ) { char swap_chars[5]; TV_INT32 j; TV_PIXEL_GEOM scratch; TV_BOOL printit = TRUE; pg = &c->pix_geom_list[ i ]; if ( pg->type != TV_PIXELTYPE_YUV ) continue; SUPRINTF(( " %d,%d,%d %d,%d,%d %d,%d,%d %-7s %-10s %-5s %-6s %s\n", pg->samp_size [0], pg->samp_size [1], pg->samp_size [2], pg->samp_int_h[0], pg->samp_int_h[1], pg->samp_int_h[2], pg->samp_int_v[0], pg->samp_int_v[1], pg->samp_int_v[2], (pg->frame_packing == TV_FRAME_PLANAR ? "PLANAR" : "PACKED"), pg->comp_order, (pg->order_t_to_b ? "Y" : "N"), (pg->order_l_to_r ? "Y" : "N"), (pg->y_trans ? "Y" : "N") )); } SUPRINTF(( "\n" )); } /**@BEGINFUNC************************************************************** Prototype : static void TVCAPTUREDumpCaptureCardInfo( TV_CAPTURE *c ) Purpose : Dump useful info about the capture card that can be used by developers for debugging. Programmer : 09-Mar-98 Randall Hopper Parameters : c - I: capture definition struct (with open handles to tuner and capture devices) Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ static void TVCAPTUREDumpCaptureCardInfo( TV_CAPTURE *c ) { struct eeProm eeprom; u_char *p; int x; int cnt; TV_INT32 eeprom_size; FILE *fp; char linebuf[128]; /* Grab the pertinent dmesg output */ printf( "DETECTED CAPTURE CARD(S) [DRIVER PROBES]:\n" ); if ( (fp = popen( "dmesg", "r" )) == NULL ) fprintf( stderr, " Failed to dump dmesg output.\n" ); else { /* FIXME: Parsing boot-ups is BAD. Make the driver return this */ /* via ioctl. */ while ( !feof(fp) ) { if ( fgets( linebuf, sizeof(linebuf)-1, fp ) == NULL ) break; if ( strncmp( linebuf, "bktr", 4 ) == 0 ) { printf( " %s", linebuf ); if ( fgets( linebuf, sizeof(linebuf)-1, fp) != NULL ) printf( " %s", linebuf ); } } pclose(fp); } /* Dump the relevent bktr driver sysctl values (if present) */ printf( "\nSYSCTL MIB VALUES:\n" ); if ( (fp = popen( "sysctl kern.version hw.bt848", "r" )) == NULL ) fprintf( stderr, " Failed to dump sysctl output.\n" ); else { while ( !feof(fp) ) { if ( fgets( linebuf, sizeof(linebuf)-1, fp ) == NULL ) break; printf( " %s", linebuf ); } pclose(fp); } /* Read the card signature */ eeprom.offset = 0x01; eeprom.count = 128; if ( ioctl( c->tfd, BT848_SIGNATURE, &eeprom ) < 0 ) DO_IOCTL_GERR( "BT848_SIGNATURE" ); else { printf( "\nTUNER SIGNATURE (0x%02x - 0x%02x):\n", eeprom.offset, (2 * ((eeprom.offset - 1) + eeprom.count)) - 1 ); for ( p = &eeprom.bytes[ 0 ], x = 0; x < 16; ++x ) { if ( (x % 16) == 0 ) printf( "%s ", ((x > 0) ? "\n" : "") ); printf( " %02x", p[ x ] ); } printf( "\n" ); printf( "\nTUNER I2C DEVICES FOUND AT:\n " ); cnt = 0; for ( p = &eeprom.bytes[ 0 ], x = 0; x < 128; ++x ) if ( p[ x / 8 ] & (1 << (x % 8)) ) { printf( "%s 0x%02x", ((cnt > 0) ? "," : ""), x * 2 ); cnt++; } printf( "\n" ); } /* Read the EEPROM */ /* FIXME: There's no way to query the size of the EEPROM from the */ /* app, and the driver bails if the request is too big. Modify the */ /* driver to return the EEPROM size. For now, use a heuristic. */ eeprom.offset = 0; eeprom.count = 256; if ( ioctl( c->tfd, BT848_REEPROM, &eeprom ) < 0 ) { eeprom.count = 128; if ( ioctl( c->tfd, BT848_REEPROM, &eeprom ) < 0 ) { eeprom.count = 0; DO_IOCTL_GERR( "BT848_REEPROM" ); } } printf( "\nCAPTURE CARD EEPROM CONTENTS:\n" " Read %d EEPROM bytes ", eeprom.count ); if ( eeprom.count == 0 ) printf( "\n" ); else { printf( "(0x00 - 0x%.2x)\n", eeprom.count-1 ); for ( p = &eeprom.bytes[ 0 ], x = 0; x < eeprom.count; ++x ) { if ( (x % 16) == 0 ) printf( "%s ", ((x > 0) ? "\n" : "") ); printf( " %02x", p[ x ] ); } printf( "\n" ); } /* It'd also be helpful to be able to print the bktr driver version */ } /**@BEGINFUNC************************************************************** Prototype : void TVCAPTUREInit( TV_CAPTURE *c ) Purpose : Initialize the capture attributes. Programmer : 03-Mar-97 Randall Hopper Parameters : c - I/O: Capture definition structure Returns : None. Globals : G_tvcapture **@ENDFUNC*****************************************************************/ void TVCAPTUREInit( TV_CAPTURE *c ) { char dev_capture[80], dev_tuner [80]; /* Build names of capture and tuner devices */ sprintf( dev_capture, DEV_BT848, App_res.device_number ); sprintf( dev_tuner , DEV_TUNER, App_res.device_number ); c->fd = open( dev_capture, O_RDONLY ); if ( c->fd < 0 ) { fprintf( stderr, "open(\"%s\") failed: %s\n", dev_capture, strerror(errno) ); exit(1); } c->tfd = open( dev_tuner, O_RDONLY ); if ( c->tfd < 0 ) { fprintf( stderr, "open(\"%s\") failed: %s\n", dev_tuner , strerror(errno) ); exit(1); } /* Dump debug info on capture card */ if ( G_debug & DEBUG_STARTUP ) TVCAPTUREDumpCaptureCardInfo( c ); /* Mute the audio until such time as we're ready to display */ TVCAPTURESetAudioMute( c, TRUE ); /* Just mmap the biggest buffer we'll need and be done with it. */ /* (Buffer used for non-directvideo captures) */ c->drv_buf = (TV_UINT8 *) mmap( (caddr_t)0, MAX_MMAP_BUF_SIZE, PROT_READ, MAP_SHARED, c->fd, (off_t)0 ); if ( c->drv_buf == (TV_UINT8 *) -1 ) { fprintf( stderr, "mmap of driver buffer failed: %s\n", strerror(errno) ); exit(1); } c->input_format = TV_INPUT_NTSCM; c->input_dev = METEOR_INPUT_DEV0; c->audio_input_dev = TV_AUDIO_INPUT_AUTO; c->bpp_format = METEOR_GEO_RGB16; c->cap_mode = TV_CAPTURE_CONTINUOUS; c->xfer_mode = TV_TRANSFER_DIRECT; TVCAPTUREQueryPixelFormats( c, &c->pix_geom_list, &c->pix_geom_list_len); if ( c->pix_geom_list_len == 0 ) { fprintf( stderr, "capture device supports 0 pixel formats\n" ); exit(1); } c->pix_geom_idx = 0; /* FIXME: This is a hack -- here because we can't query whether the */ /* the tuner is set to a specific channel number or whether an */ /* off-channel frequency override is in-place. */ c->tuner_chan_active = TRUE; TVCAPTUREPrintPixelFormats( c ); c->field_targ[0] = TV_FIELD_DISPLAY; c->field_targ[1] = TV_FIELD_DISPLAY; c->hue = 0.0; /* % */ c->brightness = +20.0; /* % */ c->contrast = 70.0; /* % */ c->sat_u = 100.0; /* % */ c->sat_v = 100.0; /* % */ c->addr = NULL; /* geom -- see below */ c->frame_done_cb = NULL; c->frame_cb_enabled = FALSE; /* FIXME: These belong in the driver/driver include file */ c->width_min = 2; c->width_res = 2; c->height_min = 2; c->height_res = 2; switch ( c->input_format ) { case TV_INPUT_NTSCM : case TV_INPUT_NTSCJ : case TV_INPUT_PALM : c->width_max = NTSC_DIM_X; c->height_max = NTSC_DIM_Y; c->fps_max = NTSC_FPS; break; case TV_INPUT_PALBDGHI : case TV_INPUT_PALN : case TV_INPUT_SECAM : case TV_INPUT_PALNCOMB : c->width_max = PAL_DIM_X; c->height_max = PAL_DIM_Y; c->fps_max = PAL_FPS; break; default : case TV_INPUT_AUTO : fprintf( stderr, "TVCAPTUREInit: Unsupported input format %d\n", c->input_format ); exit(1); } c->fps = c->fps_max; c->geom.x = c->geom.y = 0; /* Unused */ c->geom.w = c->width_max ; c->geom.h = c->height_max; c->contin_on = False; signal( SIGUSR1, TVCAPTUREFrameDoneSigHdlr ); atexit( TVCAPTUREDestroy ); } /**@BEGINFUNC************************************************************** Prototype : void TVCAPTURESetCaptureMode( Prototype : void TVCAPTURESetTransferMode( Prototype : void TVCAPTURESetRegionGeom( Prototype : void TVCAPTURESetPixelGeom( Purpose : Routines which set the core capture parameters. It would be good policy to set all these before every capture. Programmer : 06-Jun-97 Randall Hopper Parameters : c - I: capture definition cap_mode - I: new capture/transfer modes (single/contin) xfer_mode - I: images (driver buf) or direct video reg_geom - I: image res (& origin, for direct video) pix_geom - I: captured pixel geometry (images only; ignored for xfer_mode = DIRECT) Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ void TVCAPTURESetCaptureMode( TV_CAPTURE *c, TV_CAPTURE_MODE cap_mode ) { if ( c->contin_on == TRUE ) { fprintf( stderr, "SetCaptureMode called when contin running\n" ); return; } c->cap_mode = cap_mode; } void TVCAPTURESetTransferMode( TV_CAPTURE *c, TV_TRANSFER_MODE xfer_mode ) { if ( c->contin_on == TRUE ) { fprintf( stderr, "SetTransferMode called when contin running\n" ); return; } c->xfer_mode = xfer_mode; } void TVCAPTURESetRegionGeom( TV_CAPTURE *c, TV_GEOM *reg_geom ) { if ( c->contin_on == TRUE ) { fprintf( stderr, "SetRegionGeom called when contin running\n" ); return; } c->geom = *reg_geom; } void TVCAPTURESetPixelGeom( TV_CAPTURE *c, TV_PIXEL_GEOM *pix_geom ) { TV_INT32 idx; if ( c->contin_on == TRUE ) { fprintf( stderr, "SetPixelGeom called when contin running\n" ); return; } TVCAPTUREGetPixFmtByDriverHandle( c, pix_geom->index, &idx ); if (( idx < 0 ) || ( idx >= c->pix_geom_list_len )) { fprintf( stderr, "TVCAPTUREConfigure: Bad pixel format index\n" ); exit(1); } c->pix_geom_idx = idx; } /* TVCAPTUREValidRegionGeom - Validates capture resolution */ TV_BOOL TVCAPTUREValidRegionGeom( TV_CAPTURE *c, TV_GEOM *reg_geom ) { TV_INT32 w, h; w = reg_geom->w / c->width_res * c->width_res; h = reg_geom->h / c->height_res * c->height_res; w = MAX( c->width_min , MIN( c->width_max , w ) ); h = MAX( c->height_min, MIN( c->height_max, h ) ); return (( w == reg_geom->w ) || ( h == reg_geom->h )); } /**@BEGINFUNC************************************************************** Prototype : TV_BOOL TVCAPTUREConfigure( TV_CAPTURE *c, char **fail_reason ) Purpose : Looks at the requested capture parameters and determines whether capture can be started using the current settings. Programmer : 03-Mar-97 Randall Hopper Parameters : c - I: capture definition fail_reason - O: if configure failed, reason why (string) Returns : T = Params OK - capture away; F = Nope, tweak somethin' Globals : None. **@ENDFUNC*****************************************************************/ TV_BOOL TVCAPTUREConfigure( TV_CAPTURE *c, char **fail_reason ) { static char S_err_msg[ 128 ]; TV_BOOL ok = FALSE; TV_XSCREEN *x = &G_glob.x; TV_DISPLAY *d = &G_glob.display; TV_GEOM g; TV_UINT32 addr; TV_INT32 Bpp, idx; if ( c->contin_on == TRUE ) { strcpy( S_err_msg, "Continuous is running" ); goto RETURN; } if ( c->frame_cb_enabled && !c->frame_done_cb ) { strcpy( S_err_msg, "Frame done callback on, but no frame handler" ); goto RETURN; } if (( c->xfer_mode == TV_TRANSFER_DIRECT ) && ( d->win == None )) { strcpy( S_err_msg, "No X Window set for video" ); goto RETURN; } if ( c->xfer_mode == TV_TRANSFER_DIRECT ) if ( !( x->visual_modes[ x->active_visual ] & TV_TRANSFER_DIRECT )) { strcpy( S_err_msg, "Active visual does not support direct video"); goto RETURN; } else if ( !d->enabled ) { strcpy( S_err_msg, "Direct transfer only supported for video" ); goto RETURN; } /* Get capture geometry */ if ( c->xfer_mode == TV_TRANSFER_DIRECT ) { TVSCREENUpdateWinGeometry(); TVSCREENGetVideoWinGeom( &g ); g.w = g.w / c->width_res * c->width_res; g.h = g.h / c->height_res * c->height_res; } else g = c->geom; /* Verify res limits and precision (all modes) */ if (( g.w != g.w / c->width_res * c->width_res ) || ( g.h != g.h / c->height_res * c->height_res )) { sprintf( S_err_msg, "Capture geometry must be a multiple of %dx%d", c->width_res, c->height_res ); goto RETURN; } if (( g.w < c->width_min ) || ( g.w > c->width_max ) || ( g.h < c->height_min ) || ( g.h > c->height_max )) { strcpy( S_err_msg, "Resolution beyond hardware or driver capabilities" ); goto RETURN; } /* Direct-video mode specific checks */ if ( c->xfer_mode == TV_TRANSFER_DIRECT ) { if ( !(x->visual_modes[ x->active_visual ] & TV_TRANSFER_DIRECT) ) { strcpy( S_err_msg, "Active X Visual does not support direct video" ); goto RETURN; } if ( x->visual[ x->active_visual ].visualid != x->fb_visual->visualid ) { strcpy( S_err_msg, "Active X Visual is not the default visual" ); goto RETURN; } if ( d->win == None ) { strcpy( S_err_msg, "Direct video attempted with no window set" ); goto RETURN; } /* Make sure capture region lies entirely within video memory */ /* (we don't have complex capture clipping support in the */ /* driver yet, but when we do, update this). */ XUTILGetVisualBpp( TVDISPLAY, x->fb_visual, NULL, &Bpp ); addr = x->base_addr + (g.y * x->pitch + g.x) * Bpp; if (( g.x < 0 ) || ( g.y < 0 ) || ( ( g.x+g.w-1 ) >= DisplayWidth ( TVDISPLAY, TVSCREEN ) ) || ( ( g.y+g.h-1 ) >= DisplayHeight( TVDISPLAY, TVSCREEN ) )) { strcpy( S_err_msg, "Direct video region outside bounds of display" ); goto RETURN; } else if ( addr + ( (g.h-1) * x->pitch + g.w ) * Bpp >= x->base_addr + x->bank_size ) { strcpy( S_err_msg, "Direct video region outside bounds of display" ); goto RETURN; } } ok = TRUE; RETURN: if ( fail_reason != NULL ) *fail_reason = ok ? NULL : S_err_msg; return ok; } /**@BEGINFUNC************************************************************** Prototype : void TVCAPTUREStart( TV_CAPTURE *c ) Purpose : Initiates capture using the mode/geom/etc. parameters set up previously. Note: ALWAYS call TVCAPTUREStart before calling this function. Programmer : 08-Mar-97 Randall Hopper Parameters : c - I: capture state struct Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ void TVCAPTUREStart( TV_CAPTURE *c ) { static TV_BOOL S_done_a_single = False; TV_DISPLAY *d = &G_glob.display; TV_XSCREEN *x = &G_glob.x; TV_INT32 larg; struct meteor_video video; struct meteor_geomet geom; TV_GEOM g; TV_PIXEL_GEOM pix_geom; TV_INT32 Bpp, idx; char *cfg_fail_msg; TV_BOOL audio_mute, flush_buf; DRVPRINTF(( "\tCAPTURE Start %s\n", c->cap_mode == TV_CAPTURE_CONTINUOUS ? "Continuous":"Single")); /* FIXME: Also lock out start when single captures in progress */ if ( c->contin_on ) { fprintf( stderr, "TVCAPTUREStart when already running...ignored\n" ); return; } /* Double-check parameters (the caller should have already done this) */ if ( !TVCAPTUREConfigure( c, &cfg_fail_msg ) ) { fprintf( stderr, "TVCAPTUREConfigure() in TVCAPTUREStart() failed: %s\n", cfg_fail_msg ); return; } /*-- Set destination attributes & geometry --*/ g = c->geom; geom.columns = g.w; geom.rows = g.h; geom.frames = 1; flush_buf = FALSE; if ( c->xfer_mode == TV_TRANSFER_DIRECT ) { TV_BOOL swap_b, swap_s; XUTILGetVisualBpp( TVDISPLAY, x->fb_visual, NULL, &Bpp ); video.addr = x->base_addr + (g.y * x->pitch + g.x) * Bpp; /*printf( "\n\tbase + (y * pitch + x) * Bpp = " "0x%x + (%d * %d + %d) * %d\n", x->base_addr, g.y, x->pitch, g.x, Bpp );*/ video.width = x->pitch * Bpp; video.banksize = x->bank_size; video.ramsize = x->ram_size / 1024; memset( &pix_geom, '\0', sizeof( pix_geom ) ); pix_geom.type = TV_PIXELTYPE_RGB; pix_geom.Bpp = Bpp; pix_geom.mask[0] = x->fb_visual->red_mask; pix_geom.mask[1] = x->fb_visual->green_mask; pix_geom.mask[2] = x->fb_visual->blue_mask; XUTILGetVisualSwaps( TVDISPLAY, x->fb_visual, &swap_b, &swap_s ); pix_geom.swap_bytes = swap_b; pix_geom.swap_shorts = swap_s; TVCAPTUREGetPixFmtByPixGeom( c, &pix_geom, &idx ); if ( idx < 0 ) { fprintf( stderr, "TVCAPTUREStart: Visual pixel format not direct " "video capable\n" ); return; } c->pix_geom_idx = idx; } else { video.addr = 0, video.width = 0, video.banksize = 0, video.ramsize = 0; /* If TDEC is on, may be a while before old trash gets written on. */ /* So tell the driver to flush the frame buffer before starting */ /* capture. */ if ( c->fps != c->fps_max ) flush_buf = TRUE; } memcpy( &pix_geom, &c->pix_geom_list[ c->pix_geom_idx ], sizeof( pix_geom ) ); geom.oformat = c->bpp_format; if ( geom.rows <= c->height_max / 2 ) geom.oformat |= METEOR_GEO_ODD_ONLY; c->addr = (TV_UINT32) video.addr; /*printf( "VIDEO = { addr 0x%.8x, width %d, banksize %d, ramsize %d }\n", video.addr, video.width, video.banksize, video.ramsize );*/ if ( ioctl( c->fd, METEORSVIDEO, &video ) < 0 ) { DO_IOCTL_SERR( "METEORSVIDEO", &video ); return; } /*printf( "GEOM = { %dx%d, frames %d, oformat 0x%.8x }\n", geom.columns, geom.rows, geom.frames, geom.oformat );*/ if ( ioctl( c->fd, METEORSETGEO, &geom ) < 0 ) { DO_IOCTL_SERR( "METEORSETGEO", &geom ); return; } /*printf( "SACTPIXFMT = { idx %d, Bpp %d, masks { %x,%x,%x }, " "swapb/s %d,%d }\n", pix_geom.index, pix_geom.Bpp, pix_geom.mask[0], pix_geom.mask[1], pix_geom.mask[2], pix_geom.swap_bytes, pix_geom.swap_shorts );*/ if ( ioctl( c->fd, METEORSACTPIXFMT, &pix_geom.index ) < 0 ) { DO_IOCTL_SERR( "METEORSACTPIXFMT", &geom ); return; } larg = flush_buf; if ( ioctl( c->fd, BT848SCBUF, &larg ) < 0 ) { DO_IOCTL_SERR( "BT848SCBUF", larg ); return; } /* If user wants to know whenever a/the frame is complete, */ /* add in a signal handler for this for single captures, or an Xt */ /* timer for continuous captures. */ /* NOTE: Done callback makes no sense for direct video transfers. */ larg = METEOR_SIG_MODE_MASK; #ifdef OLD__ALWAYS_USE_SIGNALS_NOW if ( c->frame_done_cb && c->frame_cb_enabled ) if ( c->cap_mode == TV_CAPTURE_SINGLE ) larg = SIGUSR1; else { S_frame_timer = XtAppAddTimeOut( TVAPPCTX, FRAME_TIMER_DELAY_MS(c->fps_max), TVCAPTUREFrameTimeoutCB, NULL ); S_frame_timer_set = True; } #else if ( c->frame_done_cb && c->frame_cb_enabled ) larg = SIGUSR1; #endif if ( ioctl( c->fd, METEORSSIGNAL, &larg ) < 0 ) { DO_IOCTL_SERR( "METEORSSIGNAL", larg ); return; } /* Verify audio mute state is in sync (in case it didn't get started */ /* on the initial map). */ TVAUDIOGetMuteState( &audio_mute ); TVCAPTURESetAudioMute( c, audio_mute ); /* OK, NOW FIRE IT UP */ if ( c->cap_mode == TV_CAPTURE_CONTINUOUS ) { /* Queue up a CAP_SINGLE -- turns on audio on Wincast board */ /* FIXME: We may not need to do this anymore */ if ( !S_done_a_single ) { larg = METEOR_CAP_SINGLE; if ( ioctl( c->fd, METEORCAPTUR, &larg ) < 0 ) { DO_IOCTL_SERR( "METEOR_CAP_SINGLE", 0 ); return; } S_done_a_single = True; } /* FIXME: Fix spelling of "continuous" in the driver sometime */ larg = METEOR_CAP_CONTINOUS; if ( ioctl( c->fd, METEORCAPTUR, &larg ) < 0 ) { DO_IOCTL_SERR( "METEOR_CAP_CONTINUOUS", 0 ); return; } c->contin_on = True; } else { larg = METEOR_CAP_SINGLE; if ( ioctl( c->fd, METEORCAPTUR, &larg ) < 0 ) { DO_IOCTL_SERR( "METEOR_CAP_SINGLE", 0 ); return; } S_done_a_single = True; } } /**@BEGINFUNC************************************************************** Prototype : void TVCAPTUREStop( TV_CAPTURE *c ) Purpose : Stop a continuous capture, if one is running. Programmer : 08-Mar-97 Randall Hopper Parameters : c - I: capture state struct Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ void TVCAPTUREStop( TV_CAPTURE *c ) { TV_INT32 larg; DRVPRINTF(( "\tCAPTURE Stop\n" )); if ( !c->contin_on ) { fprintf( stderr, "TVCAPTUREStop called when not running...ignored\n"); return; } if ( S_frame_timer_set ) { XtRemoveTimeOut( S_frame_timer ); S_frame_timer_set = False; } /* Reset driver's signal so we don't keep getting interrupted */ larg = METEOR_SIG_MODE_MASK; if ( ioctl( c->fd, METEORSSIGNAL, &larg ) < 0 ) { DO_IOCTL_SERR( "METEORSSIGNAL", larg ); return; } larg = METEOR_CAP_STOP_CONT; if ( ioctl( c->fd, METEORCAPTUR, &larg ) < 0 ) { DO_IOCTL_SERR( "METEOR_CAP_STOP_CONT", 0 ); return; } c->contin_on = False; TVCAPTUREClearPendingFrames(); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199807100726.AAA10706>
