--- grabber-meteor.cc.orig	Fri Jun 26 11:25:55 1998
+++ grabber-meteor.cc	Fri Jun 26 11:18:53 1998
@@ -43,7 +43,6 @@
  *	
  */
 
-/*#define FRAME_CNTS /* print frame counts and fps when device stops -- debug */
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -51,16 +50,16 @@
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
-#ifdef FRAME_CNTS
-#include <sys/time.h>
-#endif
 
 #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>
+#include <machine/ioctl_bt848.h>
 
 /*XXX*/
 #define NTSC_WIDTH 320
@@ -72,62 +71,78 @@
 
 
 class MeteorGrabber : public Grabber {
- public:
-	MeteorGrabber(const char* name, const char* format);
+    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 void fps(int);
- protected:
-	virtual int command(int argc, const char*const* argv);
-	virtual int capture();
 	virtual int grab();
+    protected:
 	void format();
-	void setsize();
+	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 */
-	int coder_format_;	/* 411, 422, or cif */
 	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 */
-#ifdef FRAME_CNTS
-	struct meteor_counts cnts_;	/* pointer to counters */
-	double	start_time_;
-#endif
+	int tuner_ ;		/* tuner device... */
 };
 
-static const int	f_411 = 0;	/* coder_format_s */
-static const int	f_422 = 1;
-static const int	f_cif = 2;
+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:
+    public:
 	MeteorDevice(const char* nickname, const char* devname, int free);
 	virtual int command(int argc, const char*const* argv);
- protected:
+    protected:
 	const char* name_;
 };
 
 class MeteorScanner {
- public:
+    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";
+    static char *d[] = { "/dev/bktr%d", "/dev/meteor%d", NULL };
+    char *nickname_template = "meteor-%d";
 
 	for(int i = 0; i < n; i++) {
-		char	*devname  = new char[strlen(devname_template)  + 3];
+	for (int j = 0 ; d[j] != NULL ; j++) {
+	    char *devname  = new char[strlen(d[j]) + 3];
 		char	*nickname = new char[strlen(nickname_template) + 3];
 
+	    sprintf(devname, d[j], i);
 		sprintf(nickname, nickname_template, i + 1);
-		sprintf(devname, devname_template, i);
 		if(access(devname, R_OK) == 0) {
 			int fd = open(devname, O_RDONLY);
 			if(fd < 0) {
@@ -140,8 +155,9 @@
 			delete nickname;
 			delete devname;
 		}
+			}
+		}
 	}
-}
 
 MeteorDevice::MeteorDevice(const char* nickname, const char *devname, int free):
 					InputDevice(nickname), name_(devname)
@@ -149,6 +165,7 @@
 	if(free)
 		attributes_ = "\
 format {422 411} \
+type {pal ntsc secam auto} \
 size {large normal small cif} \
 port {RCA Port-1 Port-2 Port-3 S-Video RGB}";
 	else
@@ -160,7 +177,10 @@
 	Tcl& tcl = Tcl::instance();
 	if ((argc == 3) && (strcmp(argv[1], "open") == 0)) {
 		TclObject* o = 0;
-		o = new MeteorGrabber(name_, argv[2]);
+		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);
@@ -168,19 +188,15 @@
 	return (InputDevice::command(argc, argv));
 }
 
-MeteorGrabber::MeteorGrabber(const char* name, const char* format)
+MeteorGrabber::MeteorGrabber(const char* name)
 {
-	coder_format_ = -1;
-	if(!strcmp(format, "411")) coder_format_ = f_411;
-	if(!strcmp(format, "422")) coder_format_ = f_422;
-	if(!strcmp(format, "cif")) coder_format_ = f_cif;
-	if(coder_format_ == -1) {
-		fprintf(stderr,
-			"vic: MeteorGrabber: unsupported format: %s\n",
-			format);
-		abort();
-	}
-
+	int devnum;
+	if (sscanf(name, "/dev/bktr%d", &devnum) == 1) {
+		char *tunerdev  = new char[strlen(name) + 3];
+		sprintf(tunerdev, "/dev/tuner%d", devnum);
+		tuner_ = open(tunerdev, O_RDONLY);
+	} else
+		tuner_ = -1;
 	dev_ = open(name, O_RDONLY);
 	if (dev_ == -1) {
 		status_ = -1;
@@ -203,52 +219,33 @@
 	if (dev_ != -1) {
 		close(dev_);
 	}
+	if (tuner_ != -1)
+		close(tuner_);
 }
 
-void MeteorGrabber::setsize()
+void MeteorGrabber::set_size_meteor(int w, int h)
 {
 	struct meteor_geomet geom;
 
-	geom.rows = (baseheight_ / decimate_) &~0xf;	/* 0xf, ugh! */
-	geom.columns = (basewidth_ / decimate_)  &~0xf;
+	geom.rows = h &~0xf;	/* 0xf, ugh! */
+	geom.columns = w  &~0xf;
 	geom.frames = 1;
-	geom.oformat = METEOR_GEO_UNSIGNED;
-	geom.oformat |= METEOR_GEO_YUV_422;
+	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) {	/* do we have a source? */
-						/* No source, assume ntsc*/
+	// ioctl(dev_, METEORSTATUS, &status);
+	if ( video_format_ == METEOR_FMT_NTSC ) {
 		if(geom.rows <= NTSC_HEIGHT && geom.columns <= NTSC_WIDTH)
 			geom.oformat |= METEOR_GEO_EVEN_ONLY;
 	} else {
-		if(status & METEOR_STATUS_FIDT) { /* is it pal or ntsc? */
-						/* 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: ");
-
-	switch(coder_format_) {
-	case f_422:
-		set_size_422(geom.columns, geom.rows);
-		break;
-	case f_cif:
-	case f_411:
-		set_size_411(geom.columns, geom.rows);
-		break;
-	}
-
-	allocref();	/* allocate reference frame */
 }
 
 void MeteorGrabber::format()
@@ -285,11 +282,6 @@
 		baseheight_ = PAL_HEIGHT * 2;
 		basewidth_ = PAL_WIDTH * 2;
 	}
-		
-	if(coder_format_ == f_cif) {
-		baseheight_ = CIF_HEIGHT * 2;
-		basewidth_ = CIF_WIDTH * 2;
-	}
 	setsize();
 }
 
@@ -299,15 +291,6 @@
 	format();
 	int cmd = METEOR_CAP_SINGLE;
 	ioctl(dev_, METEORCAPTUR, (char*)&cmd);
-#ifdef FRAME_CNTS
-	cnts_.fifo_errors = 0;
-	cnts_.dma_errors = 0;
-	cnts_.frames_captured = 0;
-	cnts_.even_fields_captured = 0;
-	cnts_.odd_fields_captured = 0;
-	ioctl(dev_, METEORSCOUNT, &cnts_);
-	start_time_ = gettimeofday();
-#endif
 
 	cmd = METEOR_CAP_CONTINOUS;
 	ioctl(dev_, METEORCAPTUR, (char*)&cmd);
@@ -319,19 +302,6 @@
 
 	int cmd = METEOR_CAP_STOP_CONT;
 	ioctl(dev_, METEORCAPTUR, (char*)&cmd);
-#ifdef FRAME_CNTS
-	double endtime = gettimeofday() ;
-	ioctl(dev_, METEORGCOUNT, &cnts_);
-	int diff = (int)((endtime-start_time_) * 1e-6 + 0.5);
-	printf("frames = %d, even fields = %d, odd fields = %d,\n\
-fifo errors = %d, dma errors = %d, seconds = %d",
-		cnts_.frames_captured, cnts_.even_fields_captured,
-		cnts_.odd_fields_captured, cnts_.fifo_errors, cnts_.dma_errors,
-		diff);
-	if(diff)
-		printf(",fps = %d", cnts_.frames_captured/diff);
-	printf("\n");
-#endif
 	Grabber::stop();
 }
 
@@ -345,15 +315,15 @@
 
 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]);
-			Tcl& tcl = Tcl::instance();
 			if (dec <= 0) {
 				tcl.resultf("%s: divide by zero", argv[0]);
 				return (TCL_ERROR);
 			}
-			if (dec != decimate_) {
+			if ((u_int)dec != decimate_) {
 				decimate_ = dec;
 				if(running_) {
 					stop();
@@ -362,7 +332,8 @@
 				}
 			}
 			return (TCL_OK);	
-		} else if (strcmp(argv[1], "port") == 0) {
+		}
+		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;
@@ -377,7 +348,30 @@
 				ioctl(dev_, METEORSINPUT, &port_);
 			}
 			return (TCL_OK);	
-		} else if (strcmp(argv[1], "format") == 0 ||
+		}
+		if (strcmp(argv[1], "freeze") == 0) {
+			int cmd = METEOR_CAP_CONTINOUS ;
+			if ( atoi(argv[2]) != 0 )
+			    cmd = METEOR_CAP_STOP_CONT;
+			ioctl(dev_, METEORCAPTUR, (char*)&cmd);
+			return (TCL_OK);
+		}
+		if (strcmp(argv[1], "chan") == 0) {
+			int p = port_;
+			int c = atoi(argv[2]);
+			if (c > 0 && c < 199)
+			    p = METEOR_INPUT_DEV1 ;
+			else
+			    p = METEOR_INPUT_DEV0 ;
+			if (p != port_) {
+				port_ = p;
+				ioctl(dev_, METEORSINPUT, &port_);
+			}
+			if (p == METEOR_INPUT_DEV1)
+			    ioctl(tuner_, TVTUNER_SETCHNL, &c);
+			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;
@@ -390,14 +384,35 @@
 			if (running_)
 				format();
 			return (TCL_OK);	
-		} else if (strcmp(argv[1], "contrast") == 0) {
-			contrast(atof(argv[2]));
-			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) {
-			Tcl& tcl = Tcl::instance();
 			switch (video_format_) {
 
 			case METEOR_FMT_AUTOMODE:
@@ -423,54 +438,316 @@
 			return (TCL_OK);
 			
 		}
+		if (strcmp(argv[1], "brightness") == 0) {
+			u_char val;
+			ioctl(dev_, METEORGBRIG, &val);
+			tcl.resultf("%d", (unsigned 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));
 }
 
-int MeteorGrabber::capture()
-{
-	if(pyuv_ == 0) return 0;
-
-	volatile u_int* py   = pyuv_;
-	volatile u_int* pu   = (u_int *)((u_int)py + (u_int)framesize_);
-	volatile u_int* pv   = (u_int *)((u_int)pu + (framesize_ >> 1));
-	u_int* 		lum  = (u_int *)frame_;
-	u_int*		uoff = (u_int *)((u_int)lum + (u_int)framesize_);
-	int		f422 = coder_format_ == f_422;
-	u_int*	 	voff = (u_int *)((u_int)uoff + 
-					 (u_int)(framesize_>>(f422?1:2)));
-	int 		numc = ((basewidth_/decimate_) &~0xf) >> 3;
-
-	for (int row = 0; row < (((baseheight_/decimate_)&~0xf) >> 1); row++) {
-		for(int col = 0; col < numc; col++) {
-			*lum++ = *py++;
-			*lum++ = *py++;
-			*uoff++ = *pu++;
-			*voff++ = *pv++;
-		}
-		for(col = 0; col < numc; col++) {   
-                        *lum++ = *py++;
-                        *lum++ = *py++;
-                        if(f422) {	/* only copy odd in 4:2:2 format */
-                                *uoff++ = *pu++; 
-                               	*voff++ = *pv++;
-			
-                        }
-                }
-                if(!f422) {	/* skip odd if 4:1:1 or cif format */
-			pu += numc;
-			pv += numc;
-		}
-	}
-	return 1;
+#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 (capture() == 0)
-		return (0);
-	suppress(frame_);
-	saveblks(frame_);
-	YuvFrame f(media_ts(), frame_, crvec_, outw_, outh_);
+	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;
+	}
 }
