Date: Wed, 15 Apr 1998 20:05:14 -0700 From: Amancio Hasty <hasty@rah.star-gate.com> To: Mark Handley <mjh@east.isi.edu> Cc: freebsd-multimedia@FreeBSD.ORG Subject: Re: vic, image corruption with Wincast/TV card Message-ID: <199804160305.UAA16569@rah.star-gate.com> In-Reply-To: Your message of "Mon, 13 Apr 1998 12:26:39 EDT." <14875.892484799@north.lcs.mit.edu>
next in thread | previous in thread | raw e-mail | index | archive | help
[-- Attachment #1 --] > > I'm running vic 2.8 built with a grabber-meteor.cc I obtained from UCL > using a Wincast/TV card and FreeBSD 2.2.6-RELEASE. Only problem is > that I'm getting corruption of the captured image. This only seems to > happen when the frame rate is limited by the frame rate limiter and > not the bandwidth limiter. Given that I can control it on the > bandwidth slider alone, this isn't a big deal, but I'm still puzzled. > > Three questions: > > - has anyone seen this before? > > - can someone point me at a version of grabber-meteor.cc that they > think works OK with BT848 cards? > > - is there a later version of the BT848 driver than the one in > 2.2.6-RELEASE and 3.0-CURRENT? > > Thanks, > Mark > > To Unsubscribe: send mail to majordomo@FreeBSD.org > with "unsubscribe freebsd-multimedia" in the body of the message Hi Mark, The latest version of the bt848 driver can always be found at: http://www.freebsd.org/~ahasty/Bt848.html ftp://rah.star-gate.com/pub/bt848.tar.gz We typically don't have multiple versions of the bt848 driver floating around and this used to be a problem last year. Here is a version of grabber-meteor.cc which I am using and it is also available thru the Bt848 web page. Amancio [-- Attachment #2 --] /* * Copyright (c) Jim Lowe, 1995, All rights reserved. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Jim Lowe * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. */ /* * 1.0 11/09/95 * Initial Release. * 1.1 12/20/95 * Changed to use new mode in meteor driver (METEOR_GEO_YUV_422) and * allow even only fields to be captured under certain conditions. * Added FRAME_CNTS debugging option. * 1.2 3/25/96 * Changed the conditions EVEN_ONLY mode was specified. We now check * the status to determine if we can run in EVEN_ONLY mode. * 1.3 5/13/96 * Added the fps code to the grabber so we only transfer what we need. * */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/ioctl.h> #include <sys/mman.h> #include "grabber.h" #include "crdef.h" #include "Tcl.h" #include "device-input.h" #include "module.h" #include "bsd-endian.h" #include <machine/ioctl_meteor.h> /*XXX*/ #define NTSC_WIDTH 320 #define NTSC_HEIGHT 240 #define PAL_WIDTH 384 #define PAL_HEIGHT 288 #define CIF_WIDTH 352 #define CIF_HEIGHT 288 class MeteorGrabber : public Grabber { public: MeteorGrabber(const char* name); virtual ~MeteorGrabber(); virtual int command(int argc, const char*const* argv); virtual void fps(int); virtual void start(); virtual void stop(); virtual int grab(); protected: void format(); virtual void setsize() = 0; void suppress(const u_char* in, int istride); virtual void saveblks(const u_char* in, int istride) = 0; void set_size_meteor(int w, int h); int video_format_; /* video input format: NTSC or PAL */ int dev_; /* device fd */ int port_; /* video input port */ u_int basewidth_; /* Height of frame to be captured */ u_int baseheight_; /* Width of frame to be captured */ u_int decimate_; /* division of base sizes */ volatile u_int* pyuv_; /* pointer to yuv data */ }; class Meteor422Grabber : public MeteorGrabber { public: Meteor422Grabber(const char* name); protected: void setsize(); void saveblk(const u_char* in, u_char* yp, u_char* up, u_char* vp, int stride, int istride); void saveblks(const u_char* in, int istride); }; class MeteorCIFGrabber : public MeteorGrabber { public: MeteorCIFGrabber(const char* name); protected: void setsize(); void saveblk(const u_char* in, u_char* yp, u_char* up, u_char* vp, int stride, int istride); void saveblks(const u_char* in, int istride); }; class MeteorDevice : public InputDevice { public: MeteorDevice(const char* nickname, const char* devname, int free); virtual int command(int argc, const char*const* argv); protected: const char* name_; }; class MeteorScanner { public: MeteorScanner(const int n); }; static MeteorScanner find_meteor_devices(4); MeteorScanner::MeteorScanner(const int n) { char* devname_template = "/dev/meteor%d"; char* nickname_template = "Matrox Meteor %d"; char* devname_template1 = "/dev/bktr%d"; char* nickname_template1 = "BrookTree848 %d"; for(int i = 0; i < n; i++) { char *devname = new char[strlen(devname_template) + 3]; char *nickname = new char[strlen(nickname_template) + 3]; char *devname1 = new char[strlen(devname_template1) + 3]; char *nickname1 = new char[strlen(nickname_template1) + 3]; sprintf(nickname, nickname_template, i + 1); sprintf(devname, devname_template, i); sprintf(nickname1, nickname_template1, i + 1); sprintf(devname1, devname_template1, i); if(access(devname, R_OK) == 0) { int fd = open(devname, O_RDONLY); if(fd < 0) { new MeteorDevice(nickname, devname, 0); } else { (void)close(fd); new MeteorDevice(nickname, devname, 1); } } else { delete nickname; delete devname; } if(access(devname1, R_OK) == 0) { int fd = open(devname1, O_RDONLY); if(fd < 0) { new MeteorDevice(nickname1, devname1, 0); } else { (void)close(fd); new MeteorDevice(nickname1, devname1, 1); } } else { delete nickname1; delete devname1; } } } MeteorDevice::MeteorDevice(const char* nickname, const char *devname, int free): InputDevice(nickname), name_(devname) { if(free) attributes_ = "\ format {422 411} \ size {large normal small cif} \ port {RCA Port-1 Port-2 Port-3 S-Video RGB}"; else attributes_ = "disabled"; } int MeteorDevice::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if ((argc == 3) && (strcmp(argv[1], "open") == 0)) { TclObject* o = 0; if (strcmp(argv[2], "422") == 0) o = new Meteor422Grabber(name_); else if (strcmp(argv[2], "cif") == 0) o = new MeteorCIFGrabber(name_); if (o != 0) tcl.result(o->name()); return (TCL_OK); } return (InputDevice::command(argc, argv)); } MeteorGrabber::MeteorGrabber(const char* name) { dev_ = open(name, O_RDONLY); if (dev_ == -1) { status_ = -1; return; } port_ = METEOR_INPUT_DEV0; video_format_ = METEOR_FMT_AUTOMODE; decimate_ = 2; basewidth_ = PAL_WIDTH * 2; baseheight_ = PAL_HEIGHT * 2; int temp = ((basewidth_ * baseheight_ * 2 + 4095)/4096)*4096; pyuv_ = (u_int*) mmap((caddr_t)0, temp, PROT_READ, 0, dev_, (off_t)0); if(pyuv_ == (u_int*)-1) pyuv_ = 0; } MeteorGrabber::~MeteorGrabber() { if (dev_ != -1) { close(dev_); } } void MeteorGrabber::set_size_meteor(int w, int h) { struct meteor_geomet geom; geom.rows = h &~0xf; /* 0xf, ugh! */ geom.columns = w &~0xf; geom.frames = 1; geom.oformat = METEOR_GEO_UNSIGNED | METEOR_GEO_YUV_PACKED; /* * If we can get by with only reading even fields, then by all * means do so. */ unsigned short status; ioctl(dev_, METEORSTATUS, &status); if(status & METEOR_STATUS_HCLK) { /* No source, assume ntsc */ if(geom.rows <= NTSC_HEIGHT && geom.columns <= NTSC_WIDTH) geom.oformat |= METEOR_GEO_EVEN_ONLY; } else { /* is it pal or ntsc? */ if(status & METEOR_STATUS_FIDT) { /* 60 hz */ if(geom.rows<=NTSC_HEIGHT && geom.columns<=NTSC_WIDTH) geom.oformat |= METEOR_GEO_EVEN_ONLY; } else { /* 50 hz */ if(geom.rows<=PAL_HEIGHT && geom.columns<=PAL_WIDTH) geom.oformat |= METEOR_GEO_EVEN_ONLY; } } if(ioctl(dev_, METEORSETGEO, &geom) < 0) perror("vic: METERSETGEO: "); } void MeteorGrabber::format() { unsigned short status; int fmt; ioctl(dev_, METEORSINPUT, &port_); ioctl(dev_, METEORSFMT, &video_format_); sleep(1); /* wait for signal lock... */ ioctl(dev_, METEORSTATUS, &status); if(video_format_ == METEOR_FMT_AUTOMODE) { switch (status & (METEOR_STATUS_HCLK|METEOR_STATUS_FIDT)) { default: fprintf(stderr, "vic: meteor sees no signal(%d)-using ntsc.\n", (status&METEOR_STATUS_HCLK) > 0 ); /* fall through */ case METEOR_STATUS_FIDT: fmt = METEOR_FMT_NTSC; break; case 0: fmt= METEOR_FMT_PAL; break; } } else fmt = video_format_; if(fmt == METEOR_FMT_NTSC) { baseheight_ = NTSC_HEIGHT * 2; basewidth_ = NTSC_WIDTH * 2; } else { /* PAL and SECAM */ baseheight_ = PAL_HEIGHT * 2; basewidth_ = PAL_WIDTH * 2; } setsize(); } void MeteorGrabber::start() { format(); int cmd = METEOR_CAP_SINGLE; ioctl(dev_, METEORCAPTUR, (char*)&cmd); cmd = METEOR_CAP_CONTINOUS; ioctl(dev_, METEORCAPTUR, (char*)&cmd); Grabber::start(); } void MeteorGrabber::stop() { int cmd = METEOR_CAP_STOP_CONT; ioctl(dev_, METEORCAPTUR, (char*)&cmd); Grabber::stop(); } void MeteorGrabber::fps(int f) { u_short met_fps = (u_short)f; (void)ioctl(dev_, METEORSFPS, &met_fps); Grabber::fps(f); } int MeteorGrabber::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 3) { if (strcmp(argv[1], "decimate") == 0) { int dec = atoi(argv[2]); if (dec <= 0) { tcl.resultf("%s: divide by zero", argv[0]); return (TCL_ERROR); } if ((u_int)dec != decimate_) { decimate_ = dec; if(running_) { stop(); setsize(); start(); } } return (TCL_OK); } if (strcmp(argv[1], "port") == 0) { int p = port_; if(!strcmp(argv[2], "RCA")) p = METEOR_INPUT_DEV0; if(!strcmp(argv[2], "Port-1")) p = METEOR_INPUT_DEV1; if(!strcmp(argv[2], "Port-2")) p = METEOR_INPUT_DEV2; if(!strcmp(argv[2], "Port-3")) p = METEOR_INPUT_DEV3; if(!strcmp(argv[2], "S-Video")) p = METEOR_INPUT_DEV_SVIDEO; if(!strcmp(argv[2], "RGB")) p = METEOR_INPUT_DEV_RGB; if (p != port_) { port_ = p; ioctl(dev_, METEORSINPUT, &port_); } return (TCL_OK); } if (strcmp(argv[1], "format") == 0 || strcmp(argv[1], "type") == 0) { if (strcmp(argv[2], "auto") == 0) video_format_ = METEOR_FMT_AUTOMODE; else if (strcmp(argv[2], "pal") == 0) video_format_ = METEOR_FMT_PAL; else if (strcmp(argv[2], "secam") == 0) video_format_ = METEOR_FMT_SECAM; else video_format_ = METEOR_FMT_NTSC; if (running_) format(); return (TCL_OK); } if (strcmp(argv[1], "brightness") == 0) { u_char val = atoi(argv[2]); ioctl(dev_, METEORSBRIG, &val); return (TCL_OK); } if (strcmp(argv[1], "contrast") == 0) { u_char val = atoi(argv[2]); ioctl(dev_, METEORSCONT, &val); return (TCL_OK); } if (strcmp(argv[1], "hue") == 0) { char val = atoi(argv[2]); ioctl(dev_, METEORSHUE, &val); return (TCL_OK); } if (strcmp(argv[1], "saturation") == 0) { u_char val = atoi(argv[2]); ioctl(dev_, METEORSCSAT, &val); return (TCL_OK); } if (strcmp(argv[1], "uvgain") == 0) { u_char val = atoi(argv[2]); ioctl(dev_, METEORSCHCV, &val); return (TCL_OK); } } else if (argc == 2) { if (strcmp(argv[1], "format") == 0 || strcmp(argv[1], "type") == 0) { switch (video_format_) { case METEOR_FMT_AUTOMODE: tcl.result("auto"); break; case METEOR_FMT_NTSC: tcl.result("ntsc"); break; case METEOR_FMT_PAL: tcl.result("pal"); break; case METEOR_FMT_SECAM: tcl.result("secam"); break; default: tcl.result(""); break; } return (TCL_OK); } if (strcmp(argv[1], "brightness") == 0) { u_char val; ioctl(dev_, METEORGBRIG, &val); tcl.resultf("%d", (int)val); return (TCL_OK); } if (strcmp(argv[1], "contrast") == 0) { u_char val; ioctl(dev_, METEORGCONT, &val); tcl.resultf("%d", (int)val); return (TCL_OK); } if (strcmp(argv[1], "hue") == 0) { char val; ioctl(dev_, METEORGHUE, &val); tcl.resultf("%d", (int)val); return (TCL_OK); } if (strcmp(argv[1], "saturation") == 0) { u_char val; ioctl(dev_, METEORGCSAT, &val); tcl.resultf("%d", (int)val); return (TCL_OK); } if (strcmp(argv[1], "uvgain") == 0) { u_char val; ioctl(dev_, METEORGCHCV, &val); tcl.resultf("%d", (int)val); return (TCL_OK); } } return (Grabber::command(argc, argv)); } #define U 0 #define Y0 1 #define V 2 #define Y1 3 /* * define these for REPLENISH macro used below */ #define DIFF4(in, frm, v) \ v += (in)[Y0] - (frm)[0]; \ v += (in)[Y1] - (frm)[1]; \ v += (in)[Y0+4] - (frm)[2]; \ v += (in)[Y1+4] - (frm)[3]; #define DIFFLINE(in, frm, left, center, right) \ DIFF4(in + 0*8, frm + 0*4, left); \ DIFF4(in + 1*8, frm + 1*4, center); \ DIFF4(in + 2*8, frm + 2*4, center); \ DIFF4(in + 3*8, frm + 3*4, right); \ if (right < 0) \ right = -right; \ if (left < 0) \ left = -left; \ if (center < 0) \ center = -center; void MeteorGrabber::suppress(const u_char* devbuf, int is) { const u_char* start = frame_ + 16 * vstart_ * outw_ + 16 * hstart_; REPLENISH(devbuf, start, is, 2, hstart_, hstop_, vstart_, vstop_); } int MeteorGrabber::grab() { if (pyuv_ == 0) return 0; int istride = inw_ * 2; suppress((u_char*)pyuv_, istride); saveblks((u_char*)pyuv_, istride); u_int32_t ts = media_ts(); YuvFrame f(ts, frame_, crvec_, outw_, outh_); return (target_->consume(&f)); } Meteor422Grabber::Meteor422Grabber(const char* name) : MeteorGrabber(name) { } MeteorCIFGrabber::MeteorCIFGrabber(const char* name) : MeteorGrabber(name) { } void Meteor422Grabber::setsize() { int w = basewidth_ / decimate_; int h = baseheight_ / decimate_; set_size_meteor(w, h); set_size_422(w, h); } inline void Meteor422Grabber::saveblk(const u_char* in, u_char* yp, u_char* up, u_char* vp, int stride, int istride) { for (int i = 16; --i >= 0; ) { /* * Each iteration of this loop grabs 16 Ys & 8 U/Vs. */ register u_int y0, y1, u, v; u = in[U + 0*4] << SHIFT(24) | in[U + 1*4] << SHIFT(16) | in[U + 2*4] << SHIFT(8) | in[U + 3*4] << SHIFT(0); v = in[V + 0*4] << SHIFT(24) | in[V + 1*4] << SHIFT(16) | in[V + 2*4] << SHIFT(8) | in[V + 3*4] << SHIFT(0); y0 = in[Y0 + 0*4] << SHIFT(24) | in[Y1 + 0*4] << SHIFT(16) | in[Y0 + 1*4] << SHIFT(8) | in[Y1 + 1*4] << SHIFT(0); y1 = in[Y0 + 2*4] << SHIFT(24) | in[Y1 + 2*4] << SHIFT(16) | in[Y0 + 3*4] << SHIFT(8) | in[Y1 + 3*4] << SHIFT(0); ((u_int*)yp)[0] = y0; ((u_int*)yp)[1] = y1; ((u_int*)up)[0] = u; ((u_int*)vp)[0] = v; u = in[U + 4*4] << SHIFT(24) | in[U + 5*4] << SHIFT(16) | in[U + 6*4] << SHIFT(8) | in[U + 7*4] << SHIFT(0); v = in[V + 4*4] << SHIFT(24) | in[V + 5*4] << SHIFT(16) | in[V + 6*4] << SHIFT(8) | in[V + 7*4] << SHIFT(0); y0 = in[Y0 + 4*4] << SHIFT(24) | in[Y1 + 4*4] << SHIFT(16) | in[Y0 + 5*4] << SHIFT(8) | in[Y1 + 5*4] << SHIFT(0); y1 = in[Y0 + 6*4] << SHIFT(24) | in[Y1 + 6*4] << SHIFT(16) | in[Y0 + 7*4] << SHIFT(8) | in[Y1 + 7*4] << SHIFT(0); ((u_int*)yp)[2] = y0; ((u_int*)yp)[3] = y1; ((u_int*)up)[1] = u; ((u_int*)vp)[1] = v; in += istride; yp += stride; up += stride >> 1; vp += stride >> 1; } } void Meteor422Grabber::saveblks(const u_char* devbuf, int is) { u_char* crv = crvec_; int off = framesize_; u_char* lum = frame_; u_char* chm = lum + off; off >>= 1; int stride = 15 * outw_; int istride = is * 15; for (int y = 0; y < blkh_; ++y) { for (int x = 0; x < blkw_; ++x) { int s = *crv++; if ((s & CR_SEND) != 0) saveblk(devbuf, lum, chm, chm + off, outw_, is); devbuf += 32; lum += 16; chm += 8; } lum += stride; chm += stride >> 1; devbuf += istride; } } void MeteorCIFGrabber::setsize() { int w = basewidth_ / decimate_; int h = baseheight_ / decimate_; set_size_meteor(w, h); set_size_cif(w, h); } inline void MeteorCIFGrabber::saveblk(const u_char* in, u_char* yp, u_char* up, u_char* vp, int stride, int istride) { for (int i = 8; --i >= 0; ) { /* * Each iteration of this loop grabs 32 Ys & 16 U/Vs. */ register u_int y0, y1, u, v; u = in[U + 0*4] << SHIFT(24) | in[U + 1*4] << SHIFT(16) | in[U + 2*4] << SHIFT(8) | in[U + 3*4] << SHIFT(0); v = in[V + 0*4] << SHIFT(24) | in[V + 1*4] << SHIFT(16) | in[V + 2*4] << SHIFT(8) | in[V + 3*4] << SHIFT(0); y0 = in[Y0 + 0*4] << SHIFT(24) | in[Y1 + 0*4] << SHIFT(16) | in[Y0 + 1*4] << SHIFT(8) | in[Y1 + 1*4] << SHIFT(0); y1 = in[Y0 + 2*4] << SHIFT(24) | in[Y1 + 2*4] << SHIFT(16) | in[Y0 + 3*4] << SHIFT(8) | in[Y1 + 3*4] << SHIFT(0); ((u_int*)yp)[0] = y0; ((u_int*)yp)[1] = y1; ((u_int*)up)[0] = u; ((u_int*)vp)[0] = v; u = in[U + 4*4] << SHIFT(24) | in[U + 5*4] << SHIFT(16) | in[U + 6*4] << SHIFT(8) | in[U + 7*4] << SHIFT(0); v = in[V + 4*4] << SHIFT(24) | in[V + 5*4] << SHIFT(16) | in[V + 6*4] << SHIFT(8) | in[V + 7*4] << SHIFT(0); y0 = in[Y0 + 4*4] << SHIFT(24) | in[Y1 + 4*4] << SHIFT(16) | in[Y0 + 5*4] << SHIFT(8) | in[Y1 + 5*4] << SHIFT(0); y1 = in[Y0 + 6*4] << SHIFT(24) | in[Y1 + 6*4] << SHIFT(16) | in[Y0 + 7*4] << SHIFT(8) | in[Y1 + 7*4] << SHIFT(0); ((u_int*)yp)[2] = y0; ((u_int*)yp)[3] = y1; ((u_int*)up)[1] = u; ((u_int*)vp)[1] = v; in += istride; yp += stride; up += stride >> 1; vp += stride >> 1; /* do the 2nd (y only instead of yuv) line */ y0 = in[Y0 + 0*4] << SHIFT(24) | in[Y1 + 0*4] << SHIFT(16) | in[Y0 + 1*4] << SHIFT(8) | in[Y1 + 1*4] << SHIFT(0); y1 = in[Y0 + 2*4] << SHIFT(24) | in[Y1 + 2*4] << SHIFT(16) | in[Y0 + 3*4] << SHIFT(8) | in[Y1 + 3*4] << SHIFT(0); ((u_int*)yp)[0] = y0; ((u_int*)yp)[1] = y1; y0 = in[Y0 + 4*4] << SHIFT(24) | in[Y1 + 4*4] << SHIFT(16) | in[Y0 + 5*4] << SHIFT(8) | in[Y1 + 5*4] << SHIFT(0); y1 = in[Y0 + 6*4] << SHIFT(24) | in[Y1 + 6*4] << SHIFT(16) | in[Y0 + 7*4] << SHIFT(8) | in[Y1 + 7*4] << SHIFT(0); ((u_int*)yp)[2] = y0; ((u_int*)yp)[3] = y1; in += istride; yp += stride; } } void MeteorCIFGrabber::saveblks(const u_char* in, int is) { u_char* crv = crvec_; int off = framesize_; u_char* lum = frame_; u_char* chm = lum + off; off >>= 2; crv += vstart_ * blkw_ + hstart_; lum += vstart_ * outw_ * 16 + hstart_ * 16; chm += vstart_ * (outw_ >> 1) * 8 + hstart_ * 8; int skip = hstart_ + (blkw_ - hstop_); for (int y = vstart_; y < vstop_; ++y) { const u_char* nin = in; for (int x = hstart_; x < hstop_; ++x) { int s = *crv++; if ((s & CR_SEND) != 0) saveblk(in, lum, chm, chm + off, outw_, is); in += 32; lum += 16; chm += 8; } crv += skip; lum += 15 * outw_ + skip * 16; chm += 7 * (outw_ >> 1) + skip * 8; in = nin + 16 * is; } }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199804160305.UAA16569>
