[initial import
timo.lindfors@iki.fi**20081231182046] {
addfile ./Makefile
hunk ./Makefile 1
-
+# performance on dandelion
+# read 2.6%
+# decode 30%, 2598800 bytes takes 1.78 seconds
+# show 13%
+all: stv680-read stv680-decode stv680-show
+stv680-read: stv680-read.c
+	gcc stv680-read.c -o stv680-read -O2 -lusb -Wall
+stv680-decode: stv680-decode.c Makefile
+	gcc stv680-decode.c -o stv680-decode -O3 -Wall -g -march=pentium-mmx -fomit-frame-pointer
+	gcc stv680-decode.c -S -o stv680-decode.S -O3 -Wall -g -march=pentium-mmx -fomit-frame-pointer
+stv680-show: stv680-show.c
+	gcc stv680-show.c -o stv680-show -O2 -lSDL -Wall
+test:
+#	sh -c "echo 64f5393af55ba3ae3891c9bc179810cc  -; ./stv680-decode < stv.raw |md5sum; time ./stv680-decode-reference < stv.raw > /dev/null ; time ./stv680-decode < stv.raw > /dev/null"
+	sh -c "echo a96505a40324492e873417ffb5ae3c2a; ./stv680-decode < stv4.raw |md5sum; time ./stv680-decode-reference < stv4.raw > /dev/null ; time ./stv680-decode < stv4.raw > /dev/null"
addfile ./detect-gate.c
hunk ./detect-gate.c 1
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <sys/time.h>
+#include <assert.h>
+
+#define WIDTH 356
+#define HEIGHT 292
+#define BUFLEN 256
+#define PTX 220
+#define PTY 206
+#define RFX 280
+#define RFY 183
+
+int main(int argc, char *argv[]) {
+	unsigned char buf[WIDTH*HEIGHT*3];
+	int ret;
+	unsigned long cnt = 0;
+
+	for(;;) {
+	    int sample, sample2;
+
+	    fgets(buf, BUFLEN, stdin);
+	    assert(buf[0] == 'P' && buf[1] == '6');
+	    fgets(buf, BUFLEN, stdin);
+	    fgets(buf, BUFLEN, stdin);
+	    ret = fread(buf, WIDTH*HEIGHT*3, 1, stdin);
+	    assert(ret == 1);
+
+	    sample = buf[PTX*3+PTY*WIDTH*3+1/*green*/];
+	    sample2 = buf[RFX*3+RFY*WIDTH*3+1/*green*/];
+	    printf("%ld %d %d\n", cnt, sample, sample2);
+	    
+	    cnt++;
+	}
+	return 0;
+}
+	
addfile ./run
hunk ./run 1
+sudo ./stv680-read 0x0553 0x0202 | ./stv680-decode | ./stv680-show
+
addfile ./stv680-decode-optimized.c
hunk ./stv680-decode-optimized.c 1
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#define WIDTH 356
+#define HEIGHT 292
+
+unsigned char input[WIDTH*HEIGHT];
+unsigned char output[WIDTH*HEIGHT*3];
+
+/* Conversion tables ripped from linux-2.4.31/drivers/usb/stv680.h */
+/* also quickcam seems to parse bayer data,
+   http://cvs.sourceforge.net/viewcvs.py/qce-ga/quickcam/hdcs.c?rev=1.18&view=markup */
+const unsigned char const red[256] = { 
+	0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
+	18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42, 
+	44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69, 
+	71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87, 
+	88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101, 
+	102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 
+	114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124, 
+	125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 
+	134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, 
+	143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, 
+	152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159, 
+	159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166, 
+	167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173, 
+	173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179, 
+	180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, 
+	187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192, 
+	192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197, 
+	198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204, 
+	204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209, 
+	209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, 
+	215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219, 
+	220, 220, 221, 221 
+}; 
+
+const unsigned char const green[256] = {
+	0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 
+	21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, 
+	50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, 
+	79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, 
+	98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, 
+	114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, 
+	127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 
+	139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 
+	150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, 
+	160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, 
+	169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 
+	177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, 
+	186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 
+	193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 
+	201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, 
+	208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 
+	214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, 
+	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+	227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 
+	233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 
+	239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, 
+	245, 245, 246, 246 
+}; 
+
+const unsigned char const blue[256] = {
+	0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 
+	23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51, 
+	55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84, 
+	86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106, 
+	107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, 
+	125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, 
+	139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, 
+	152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, 
+	165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 
+	176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, 
+	185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, 
+	194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203, 
+	204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212, 
+	212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220, 
+	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+	228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235, 
+	235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242, 
+	243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, 
+	249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255, 
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+	255, 255, 255, 255 
+}; 
+
+
+/*******  routines from the pencam program; hey, they work!  ********/
+
+/*
+ * STV0680 Vision Camera Chipset Driver
+ * Copyright (C) 2000 Adam Harrison <adam@antispin.org> 
+*/
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+
+/*
+GRGRGRGRGRGRGRGRGRGRGRGRGRGRGR ... ..RGRGR
+BGbGBGBGBGBGBGBGBGBGBGBGBGBGBG ... ..GBGBG
+GRGRGRGRGRGRGRGRGRGRGRGRGRGRGR
+BGBGBGBGBGBGBGBGBGBGBGBGBGBGBG
+GRGRGRGRGRGRGRGRGRGRGRGRGRGRGR
+BGBGBGBGBGBGBGBGBGBGBGBGBGBGBG
+GRGRGRGRGRGRGRGRGRGRGRGRGRGRGR
+BGBGBGBGBGBGBGBGBGBGBGBGBGBGBG
+GRGRGRGRGRGRGRGRGRGRGRGRGRGRGR
+...
+GRGRGRGRGRGRGRGRGR
+BGBGBGBGBGBGBGBGBG       ...  BGBGBGBGBGBG*/
+void bayer2rgb() {
+	int x, y, i, bayer = 0;
+        unsigned char p = 0;
+	for (y = 0; y < HEIGHT; y++) {
+                i = (y * WIDTH + /*x=*/0) * 3;
+		for (x = 0; x < WIDTH; x++) {
+			if (y & 1)
+				bayer = 2; // y odd
+			else
+				bayer = 0; // y even
+			if (x & 1)
+				p = input[y * WIDTH + x/2];
+			else {
+				p = input[y * WIDTH + x/2 + WIDTH/2];
+                                bayer++;
+                        }
+			switch (bayer) {
+			case 1: // color = 1
+			case 2: // color = 1
+                                output[i+1] = green[p];
+                                if (1 <= x && x < WIDTH-1 && 2 <= y && y < HEIGHT)
+                                        output[i+1-3*WIDTH] = (output[i+1] + output[i+1-3-3*WIDTH] + output[i+1+3-3*WIDTH]+output[i+1-6*WIDTH])/4;
+				break;
+			case 0:// colour = 0;
+                                output[i] = red[p];
+                                if (1 <= x && y<HEIGHT-1)
+                                        output[i-3] = (output[i-6] + output[i])/2;
+                                if (x<WIDTH-1 && 2 <= y)
+                                        output[i-3*WIDTH]=(output[i-6*WIDTH]+output[i])/2;
+                                if (1 <= x && x < WIDTH && 2 <= y && y < HEIGHT)
+                                        output[i-3-3*WIDTH] = (output[i] + output[i-6] + output[i-6*WIDTH]+output[i-6-6*WIDTH])/4;
+				break;
+			case 3: //colour = 2;
+                                output[i+2] = blue[p];
+                                if (1 <= x && y<HEIGHT-1)
+                                        output[i+2-3] = (output[i+2-6] + output[i+2])/2;
+                                if (x<WIDTH-1 && 2 <= y)
+                                        output[i+2-3*WIDTH] = (output[i+2]+output[i+2-6*WIDTH])/2;
+                                if (1 <= x && x < WIDTH && 2 <= y && y < HEIGHT)
+                                        output[i+2-3-3*WIDTH] = (output[i+2] + output[i+2-6] + output[i+2-6*WIDTH]+output[i+2-6-6*WIDTH])/4;
+				break;
+			}
+                        i += 3;
+		}
+	}
+}
+void bayer2rgb2() {
+	int x, y, i, o;
+        unsigned char p = 0;
+	for (y = 0; y < HEIGHT; y++) {
+                i = (y * WIDTH + /*x=*/0) * 3;
+                o = y * WIDTH + /*x=*/0/2 + WIDTH/2;
+		for (x = 0; x < WIDTH; x+=2) {
+                        p = input[o];
+                        output[i+1] = green[p];
+                        if (1 <= x && x < WIDTH-1 && 2 <= y)
+                                output[i+1-3*WIDTH] = (output[i+1] + output[i+1-3-3*WIDTH] + output[i+1+3-3*WIDTH]+output[i+1-6*WIDTH])/4;
+                        i+=6;
+                        o+=1;
+		}
+                i = (y * WIDTH + /*x=*/1) * 3;
+                o = y * WIDTH + /*x=*/1/2;
+                for (x = 1; x < WIDTH; x+=2) {
+                        p = input[o];
+                        output[i] = red[p];
+                        if (1 <= x && y<HEIGHT-1)
+                                output[i-3] = (output[i-6] + output[i])/2;
+                        if (x<WIDTH-1 && 2 <= y)
+                                output[i-3*WIDTH]=(output[i-6*WIDTH]+output[i])/2;
+                        if (1 <= x && x < WIDTH && 2 <= y && y < HEIGHT)
+                                output[i-3-3*WIDTH] = (output[i] + output[i-6] + output[i-6*WIDTH]+output[i-6-6*WIDTH])/4;
+                        i+=6;
+                        o+=1;
+                }
+                y++;
+                i = (y * WIDTH + /*x=*/0) * 3;
+                o = y * WIDTH + /*x=*/0/2 + WIDTH/2;
+		for (x = 0; x < WIDTH; x+=2) {
+                        p = input[o];
+                        output[i+2] = blue[p];
+                        if (1 <= x && y<HEIGHT-1)
+                                output[i+2-3] = (output[i+2-6] + output[i+2])/2;
+                        if (x<WIDTH-1 && 2 <= y)
+                                output[i+2-3*WIDTH] = (output[i+2]+output[i+2-6*WIDTH])/2;
+                        if (1 <= x && x < WIDTH && 2 <= y && y < HEIGHT)
+                                output[i+2-3-3*WIDTH] = (output[i+2] + output[i+2-6] + output[i+2-6*WIDTH]+output[i+2-6-6*WIDTH])/4;
+                        i+=6;
+                        o++;
+		}
+                i = (y * WIDTH + /*x=*/1) * 3;
+                o = y * WIDTH + /*x=*/1/2;
+                for (x = 1; x < WIDTH; x+=2) {
+                        p = input[o];
+                        output[i+1] = green[p];
+                        if (1 <= x && x < WIDTH-1 && 2 <= y && y < HEIGHT)
+                                output[i+1-3*WIDTH] = (output[i+1] + output[i+1-3-3*WIDTH] + output[i+1+3-3*WIDTH]+output[i+1-6*WIDTH])/4;
+                        i+=6;
+                        o++;
+                }
+	}
+}
+void bayer2rgb3_1() {
+        int x, y, i, o;
+        unsigned char p = 0;
+	for (y = 0; y < 2; y++) {
+                i = (y * WIDTH + /*x=*/0) * 3;
+                o = y * WIDTH + /*x=*/0/2 + WIDTH/2;
+		for (x = 0; x < WIDTH-1; x+=2) {
+                        p = input[o];
+                        output[i+1] = green[p];
+                        i+=6;
+                        o+=1;
+		}
+                p = input[o];
+                output[i+1] = green[p];
+                
+                i = (y * WIDTH + /*x=*/1) * 3;
+                o = y * WIDTH + /*x=*/1/2;
+                for (x = 1; x < WIDTH; x+=2) {
+                        p = input[o];
+                        output[i] = red[p];
+                        output[i-3] = (output[i-6] + output[i])/2;
+                        i+=6;
+                        o+=1;
+                }
+                y++;
+                i = (y * WIDTH + /*x=*/0) * 3;
+                o = y * WIDTH + /*x=*/0/2 + WIDTH/2;
+                p = input[o];
+                output[i+2] = blue[p];
+                i+=6;
+                o++;
+		for (x = 2; x < WIDTH; x+=2) {
+                        p = input[o];
+                        output[i+2] = blue[p];
+                        output[i+2-3] = (output[i+2-6] + output[i+2])/2;
+                        i+=6;
+                        o++;
+		}
+                i = (y * WIDTH + /*x=*/1) * 3;
+                o = y * WIDTH + /*x=*/1/2;
+                for (x = 1; x < WIDTH; x+=2) {
+                        p = input[o];
+                        output[i+1] = green[p];
+                        i+=6;
+                        o++;
+                }
+	}
+}
+void bayer2rgb3_2() {
+	int x, y, i, o;
+        unsigned char p = 0;
+	for (y = 2; y < HEIGHT-2; y++) {
+                i = (y * WIDTH + /*x=*/0) * 3;
+                o = y * WIDTH + /*x=*/0/2 + WIDTH/2;
+		for (x = 0; x < WIDTH-1; x+=2) {
+                        output[i+1] = green[input[o]];
+                        output[i+1-3*WIDTH] = (output[i+1] + output[i+1-3-3*WIDTH] + output[i+1+3-3*WIDTH]+output[i+1-6*WIDTH])/4;
+                        i+=6;
+                        o+=1;
+		}
+                p = input[o];
+                output[i+1] = green[p];
+                
+                i = (y * WIDTH + /*x=*/1) * 3;
+                o = y * WIDTH + /*x=*/1/2;
+                for (x = 1; x < WIDTH-1; x+=2) {
+                        p = input[o];
+                        output[i] = red[p];
+                        output[i-3] = (output[i-6] + output[i])/2;
+                        output[i-3*WIDTH]=(output[i-6*WIDTH]+output[i])/2;
+                        output[i-3-3*WIDTH] = (output[i] + output[i-6] + output[i-6*WIDTH]+output[i-6-6*WIDTH])/4;
+                        i+=6;
+                        o+=1;
+                }
+                p = input[o];
+                output[i] = red[p];
+                output[i-3] = (output[i-6] + output[i])/2;
+                output[i-3-3*WIDTH] = (output[i] + output[i-6] + output[i-6*WIDTH]+output[i-6-6*WIDTH])/4;
+                
+                y++;
+                i = (y * WIDTH + /*x=*/0) * 3;
+                o = y * WIDTH + /*x=*/0/2 + WIDTH/2;
+                p = input[o];
+                output[i+2] = blue[p];
+                output[i+2-3*WIDTH] = (output[i+2]+output[i+2-6*WIDTH])/2;
+                i+=6;
+                o++;
+		for (x = 2; x < WIDTH; x+=2) {
+                        p = input[o];
+                        output[i+2] = blue[p];
+                        output[i+2-3] = (output[i+2-6] + output[i+2])/2;
+                        output[i+2-3*WIDTH] = (output[i+2]+output[i+2-6*WIDTH])/2;
+                        output[i+2-3-3*WIDTH] = (output[i+2] + output[i+2-6] + output[i+2-6*WIDTH]+output[i+2-6-6*WIDTH])/4;
+                        i+=6;
+                        o++;
+		}
+                i = (y * WIDTH + /*x=*/1) * 3;
+                o = y * WIDTH + /*x=*/1/2;
+                for (x = 1; x < WIDTH-1; x+=2) {
+                        p = input[o];
+                        output[i+1] = green[p];
+                        output[i+1-3*WIDTH] = (output[i+1] + output[i+1-3-3*WIDTH] + output[i+1+3-3*WIDTH]+output[i+1-6*WIDTH])/4;
+                        i+=6;
+                        o++;
+                }
+                p = input[o];
+                output[i+1] = green[p];
+	}
+}
+void bayer2rgb3_3() {
+	int x, y, i, o;
+        unsigned char p = 0;
+	for (y = HEIGHT-2; y < HEIGHT; y++) {
+                i = (y * WIDTH + /*x=*/0) * 3;
+                o = y * WIDTH + /*x=*/0/2 + WIDTH/2;
+		for (x = 0; x < WIDTH-1; x+=2) {
+                        output[i+1] = green[input[o]];
+                        output[i+1-3*WIDTH] = (output[i+1] + output[i+1-3-3*WIDTH] + output[i+1+3-3*WIDTH]+output[i+1-6*WIDTH])/4;
+                        i+=6;
+                        o+=1;
+		}
+                p = input[o];
+                output[i+1] = green[p];
+                
+                i = (y * WIDTH + /*x=*/1) * 3;
+                o = y * WIDTH + /*x=*/1/2;
+                for (x = 1; x < WIDTH-1; x+=2) {
+                        p = input[o];
+                        output[i] = red[p];
+                        output[i-3] = (output[i-6] + output[i])/2;
+                        output[i-3*WIDTH]=(output[i-6*WIDTH]+output[i])/2;
+                        output[i-3-3*WIDTH] = (output[i] + output[i-6] + output[i-6*WIDTH]+output[i-6-6*WIDTH])/4;
+                        i+=6;
+                        o+=1;
+                }
+                p = input[o];
+                output[i] = red[p];
+                output[i-3] = (output[i-6] + output[i])/2;
+                output[i-3-3*WIDTH] = (output[i] + output[i-6] + output[i-6*WIDTH]+output[i-6-6*WIDTH])/4;
+                
+                y++;
+                i = (y * WIDTH + /*x=*/0) * 3;
+                o = y * WIDTH + /*x=*/0/2 + WIDTH/2;
+                p = input[o];
+                output[i+2] = blue[p];
+                output[i+2-3*WIDTH] = (output[i+2]+output[i+2-6*WIDTH])/2;
+                i+=6;
+                o++;
+		for (x = 2; x < WIDTH-1; x+=2) {
+                        p = input[o];
+                        output[i+2] = blue[p];
+                        output[i+2-3*WIDTH] = (output[i+2]+output[i+2-6*WIDTH])/2;
+                        output[i+2-3-3*WIDTH] = (output[i+2] + output[i+2-6] + output[i+2-6*WIDTH]+output[i+2-6-6*WIDTH])/4;
+                        i+=6;
+                        o++;
+		}
+                        
+                i = (y * WIDTH + /*x=*/1) * 3;
+                o = y * WIDTH + /*x=*/1/2;
+                for (x = 1; x < WIDTH-1; x+=2) {
+                        p = input[o];
+                        output[i+1] = green[p];
+                        output[i+1-3*WIDTH] = (output[i+1] + output[i+1-3-3*WIDTH] + output[i+1+3-3*WIDTH]+output[i+1-6*WIDTH])/4;
+                        i+=6;
+                        o++;
+                }
+                p = input[o];
+                output[i+1] = green[p];
+        }
+}        
+
+void fix_edges() {
+        int y, i;
+        /* fix top and bottom row, left and right side */
+	i = WIDTH * 3;
+	memcpy (output, (output + i), i);
+	memcpy ((output + (HEIGHT * i)), (output + ((HEIGHT - 1) * i)), i);
+	for (y = 0; y < HEIGHT; y++) {
+		i = y * WIDTH * 3;
+                output[i] = output[i+3];
+                output[i+1] = output[i+3+1];
+                output[i+2] = output[i+3+2];
+                output[i+(WIDTH*3)] = output[i+(WIDTH-1)*3];
+                output[i+(WIDTH*3)+1] = output[i+(WIDTH-1)*3+1];
+                output[i+(WIDTH*3)+2] = output[i+(WIDTH-1)*3+2];
+	}
+}
+void bayer_unshuffle() {
+        bayer2rgb3_1();
+        bayer2rgb3_2();
+        bayer2rgb3_3();
+        fix_edges();
+}				/* bayer_unshuffle */
+
+/*******  end routines from the pencam program  *********/
+
+int main(int argc, char **argv) {
+	for(;;) {
+		if (fread(input, WIDTH*HEIGHT, 1, stdin) != 1)
+			break;
+		bayer_unshuffle();
+		printf("P6\n%d %d\n255\n", WIDTH, HEIGHT);
+		fwrite(output, WIDTH*HEIGHT*3, 1, stdout);
+	}
+	return 0;
+}
addfile ./stv680-decode-reference.c
hunk ./stv680-decode-reference.c 1
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#define BUFLEN 512
+#define WIDTH 356
+#define HEIGHT 292
+
+
+/* also quickcam seems to parse bayer data,
+   http://cvs.sourceforge.net/viewcvs.py/qce-ga/quickcam/hdcs.c?rev=1.18&view=markup */
+
+/* Conversion tables ripped from linux-2.4.31/drivers/usb/stv680.h */
+
+unsigned char red[256] = { 
+	0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
+	18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42, 
+	44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69, 
+	71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87, 
+	88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101, 
+	102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 
+	114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124, 
+	125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 
+	134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, 
+	143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, 
+	152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159, 
+	159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166, 
+	167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173, 
+	173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179, 
+	180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, 
+	187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192, 
+	192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197, 
+	198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204, 
+	204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209, 
+	209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, 
+	215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219, 
+	220, 220, 221, 221 
+}; 
+
+unsigned char green[256] = {
+	0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 
+	21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, 
+	50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, 
+	79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, 
+	98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, 
+	114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, 
+	127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 
+	139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 
+	150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, 
+	160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, 
+	169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 
+	177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, 
+	186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 
+	193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 
+	201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, 
+	208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 
+	214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, 
+	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+	227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 
+	233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 
+	239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, 
+	245, 245, 246, 246 
+}; 
+
+unsigned char blue[256] = {
+	0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 
+	23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51, 
+	55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84, 
+	86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106, 
+	107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, 
+	125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, 
+	139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, 
+	152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, 
+	165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 
+	176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, 
+	185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, 
+	194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203, 
+	204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212, 
+	212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220, 
+	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+	228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235, 
+	235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242, 
+	243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, 
+	249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255, 
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+	255, 255, 255, 255 
+}; 
+
+
+/*******  routines from the pencam program; hey, they work!  ********/
+
+/*
+ * STV0680 Vision Camera Chipset Driver
+ * Copyright (C) 2000 Adam Harrison <adam@antispin.org> 
+*/
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+#define AD(x, y, w) (((y)*(w)+(x))*3)
+
+void bayer_unshuffle (unsigned char *input2, unsigned char *output2)
+{
+	int x, y, i;
+	int w = WIDTH;
+	int vw = WIDTH, vh = HEIGHT;
+	unsigned int p = 0;
+	int colour = 0, bayer = 0;
+	unsigned char *raw = input2;
+	unsigned char *output = output2;
+
+	memset (output, 0, 3 * vw * vh);	/* clear output matrix. */
+
+	for (y = 0; y < vh; y++) {
+		for (x = 0; x < vw; x++) {
+			if (x & 1)
+				p = *(raw + y * w + (x >> 1));
+			else
+				p = *(raw + y * w + (x >> 1) + (w >> 1));
+
+			if (y & 1)
+				bayer = 2;
+			else
+				bayer = 0;
+			if (x & 1)
+				bayer++;
+
+			switch (bayer) {
+			case 0:
+			case 3:
+				colour = 1;
+				break;
+			case 1:
+				colour = 0;
+				break;
+			case 2:
+				colour = 2;
+				break;
+			}
+			i = (y * vw + x) * 3;
+			*(output + i + colour) = (unsigned char) p;
+		}		/* for x */
+
+	}			/* for y */
+
+#if 0	/* average data from two different types of green sensors */
+	for (y = 0; y < vh-1; y+=2) {
+		for (x = 0; x < vw-1; x+=2) {
+			unsigned char *g1, *g2, average;
+			g1 = output + (y * vw + x) * 3 + 1;
+			g2 = output + ((y+1) * vw + (x+1)) * 3 + 1;
+			average = (*g1 + *g2) / 2;
+			*g1 = average;
+			*g2 = average;
+		}
+	}
+#endif
+	
+
+#if 0 	/* DEBUG color green color sensors */
+	for (y=0; y<260; y+=16) {
+		for (x=124; x<vw-2; x+= 2) {
+			fprintf(stderr, "%d %d\n",
+				*(output + (y * vw + x) * 3 + 1),
+				*(output + ((y+1) * vw + (x+1)) * 3 + 1));
+		}
+	}
+#endif
+
+#if 1
+	/****** gamma correction plus hardcoded white balance */
+	/* Thanks to Alexander Schwartx <alexander.schwartx@gmx.net> for this code.
+	   Correction values red[], green[], blue[], are generated by 
+	   (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255. 
+	   White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and 
+	   converted to unsigned char. Values are in stv680.h  */
+
+	for (y = 0; y < vh; y++) {
+		for (x = 0; x < vw; x++) {
+			i = (y * vw + x) * 3;
+			*(output + i) = red[*(output + i)];
+			*(output + i + 1) = green[*(output + i + 1)];
+			*(output + i + 2) = blue[*(output + i + 2)];
+		}
+	}
+
+	/******  bayer demosaic  ******/
+	for (y = 1; y < (vh - 1); y++) {
+		for (x = 1; x < (vw - 1); x++) {	/* work out pixel type */
+			if (y & 1)
+				bayer = 0;
+			else
+				bayer = 2;
+			if (!(x & 1))
+				bayer++;
+
+			switch (bayer) {
+			case 0:	/* green. blue lr, red tb */
+				*(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y, vw) + BLUE) + (int) *(output + AD (x + 1, y, vw) + BLUE)) >> 1;
+				*(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x, y - 1, vw) + RED) + (int) *(output + AD (x, y + 1, vw) + RED)) >> 1;
+				break;
+
+			case 1:	/* blue. green lrtb, red diagonals */
+				*(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
+				*(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y - 1, vw) + RED) + (int) *(output + AD (x - 1, y + 1, vw) + RED) + (int) *(output + AD (x + 1, y - 1, vw) + RED) + (int) *(output + AD (x + 1, y + 1, vw) + RED)) >> 2;
+				break;
+
+			case 2:	/* red. green lrtb, blue diagonals */
+				*(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
+				*(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y - 1, vw) + BLUE) + (int) *(output + AD (x + 1, y - 1, vw) + BLUE) + (int) *(output + AD (x - 1, y + 1, vw) + BLUE) + (int) *(output + AD (x + 1, y + 1, vw) + BLUE)) >> 2;
+				break;
+
+			case 3:	/* green. red lr, blue tb */
+				*(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y, vw) + RED) + (int) *(output + AD (x + 1, y, vw) + RED)) >> 1;
+				*(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x, y - 1, vw) + BLUE) + (int) *(output + AD (x, y + 1, vw) + BLUE)) >> 1;
+				break;
+			}	/* switch */
+		}		/* for x */
+	}			/* for y  - end demosaic  */
+
+	/* fix top and bottom row, left and right side */
+	i = vw * 3;
+	memcpy (output, (output + i), i);
+	memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i);
+	for (y = 0; y < vh; y++) {
+		i = y * vw * 3;
+		memcpy ((output + i), (output + i + 3), 3);
+		memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3);
+	}
+#endif
+}				/* bayer_unshuffle */
+
+/*******  end routines from the pencam program  *********/
+
+int main(int argc, char **argv) {
+	unsigned char input[WIDTH*HEIGHT];
+	unsigned char output[WIDTH*HEIGHT*3];
+
+	for(;;) {
+		if (fread(input, WIDTH*HEIGHT, 1, stdin) != 1)
+			break;
+		bayer_unshuffle(input, output);
+		printf("P6\n%d %d\n255\n", WIDTH, HEIGHT);
+		fwrite(output, WIDTH*HEIGHT*3, 1, stdout);
+	}
+	return 0;
+}
addfile ./stv680-decode.c
hunk ./stv680-decode.c 1
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#define WIDTH 356
+#define HEIGHT 292
+
+unsigned char input[WIDTH*HEIGHT];
+unsigned char output[WIDTH*HEIGHT*3];
+
+/* Conversion tables ripped from linux-2.4.31/drivers/usb/stv680.h */
+/* also quickcam seems to parse bayer data,
+   http://cvs.sourceforge.net/viewcvs.py/qce-ga/quickcam/hdcs.c?rev=1.18&view=markup */
+const unsigned char const red[256] = { 
+	0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
+	18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42, 
+	44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69, 
+	71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87, 
+	88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101, 
+	102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 
+	114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124, 
+	125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 
+	134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, 
+	143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, 
+	152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159, 
+	159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166, 
+	167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173, 
+	173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179, 
+	180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, 
+	187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192, 
+	192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197, 
+	198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204, 
+	204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209, 
+	209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, 
+	215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219, 
+	220, 220, 221, 221 
+}; 
+
+const unsigned char const green[256] = {
+	0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 
+	21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, 
+	50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, 
+	79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, 
+	98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, 
+	114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, 
+	127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 
+	139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 
+	150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, 
+	160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, 
+	169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 
+	177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, 
+	186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 
+	193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 
+	201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, 
+	208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 
+	214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, 
+	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+	227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 
+	233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 
+	239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, 
+	245, 245, 246, 246 
+}; 
+
+const unsigned char const blue[256] = {
+	0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 
+	23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51, 
+	55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84, 
+	86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106, 
+	107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, 
+	125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, 
+	139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, 
+	152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, 
+	165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 
+	176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, 
+	185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, 
+	194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203, 
+	204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212, 
+	212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220, 
+	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+	228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235, 
+	235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242, 
+	243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, 
+	249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255, 
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+	255, 255, 255, 255 
+}; 
+
+
+/*******  routines from the pencam program; hey, they work!  ********/
+
+/*
+ * STV0680 Vision Camera Chipset Driver
+ * Copyright (C) 2000 Adam Harrison <adam@antispin.org> 
+*/
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+
+/*
+GRGRGRGRGRGRGRGRGRGRGRGRGRGRGR ... ..RGRGR
+BGbGBGBGBGBGBGBGBGBGBGBGBGBGBG ... ..GBGBG
+GRGRGRGRGRGRGRGRGRGRGRGRGRGRGR
+BGBGBGBGBGBGBGBGBGBGBGBGBGBGBG
+GRGRGRGRGRGRGRGRGRGRGRGRGRGRGR
+BGBGBGBGBGBGBGBGBGBGBGBGBGBGBG
+GRGRGRGRGRGRGRGRGRGRGRGRGRGRGR
+BGBGBGBGBGBGBGBGBGBGBGBGBGBGBG
+GRGRGRGRGRGRGRGRGRGRGRGRGRGRGR
+...
+GRGRGRGRGRGRGRGRGR
+BGBGBGBGBGBGBGBGBG       ...  BGBGBGBGBGBG*/
+void bayer2rgb() {
+	int x, y, i, bayer = 0;
+        unsigned char p = 0;
+	for (y = 0; y < HEIGHT; y++) {
+                i = (y * WIDTH + /*x=*/0) * 3;
+		for (x = 0; x < WIDTH; x++) {
+			if (y & 1)
+				bayer = 2; // y odd
+			else
+				bayer = 0; // y even
+			if (x & 1)
+				p = input[y * WIDTH + x/2];
+			else {
+				p = input[y * WIDTH + x/2 + WIDTH/2];
+                                bayer++;
+                        }
+			switch (bayer) {
+			case 1: // color = 1
+			case 2: // color = 1
+                                output[i+1] = green[p];
+                                if (1 <= x && x < WIDTH-1 && 2 <= y && y < HEIGHT)
+                                        output[i+1-3*WIDTH] = (output[i+1] + output[i+1-3-3*WIDTH] + output[i+1+3-3*WIDTH]+output[i+1-6*WIDTH])/4;
+				break;
+			case 0:// colour = 0;
+                                output[i] = red[p];
+                                if (1 <= x && y<HEIGHT-1)
+                                        output[i-3] = (output[i-6] + output[i])/2;
+                                if (x<WIDTH-1 && 2 <= y)
+                                        output[i-3*WIDTH]=(output[i-6*WIDTH]+output[i])/2;
+                                if (1 <= x && x < WIDTH && 2 <= y && y < HEIGHT)
+                                        output[i-3-3*WIDTH] = (output[i] + output[i-6] + output[i-6*WIDTH]+output[i-6-6*WIDTH])/4;
+				break;
+			case 3: //colour = 2;
+                                output[i+2] = blue[p];
+                                if (1 <= x && y<HEIGHT-1)
+                                        output[i+2-3] = (output[i+2-6] + output[i+2])/2;
+                                if (x<WIDTH-1 && 2 <= y)
+                                        output[i+2-3*WIDTH] = (output[i+2]+output[i+2-6*WIDTH])/2;
+                                if (1 <= x && x < WIDTH && 2 <= y && y < HEIGHT)
+                                        output[i+2-3-3*WIDTH] = (output[i+2] + output[i+2-6] + output[i+2-6*WIDTH]+output[i+2-6-6*WIDTH])/4;
+				break;
+			}
+                        i += 3;
+		}
+	}
+}
+void bayer2rgb2() {
+	int x, y, i, o;
+        unsigned char p = 0;
+	for (y = 0; y < HEIGHT; y++) {
+                i = (y * WIDTH + /*x=*/0) * 3;
+                o = y * WIDTH + /*x=*/0/2 + WIDTH/2;
+		for (x = 0; x < WIDTH; x+=2) {
+                        p = input[o];
+                        output[i+1] = green[p];
+                        if (1 <= x && x < WIDTH-1 && 2 <= y)
+                                output[i+1-3*WIDTH] = (output[i+1] + output[i+1-3-3*WIDTH] + output[i+1+3-3*WIDTH]+output[i+1-6*WIDTH])/4;
+                        i+=6;
+                        o+=1;
+		}
+                i = (y * WIDTH + /*x=*/1) * 3;
+                o = y * WIDTH + /*x=*/1/2;
+                for (x = 1; x < WIDTH; x+=2) {
+                        p = input[o];
+                        output[i] = red[p];
+                        if (1 <= x && y<HEIGHT-1)
+                                output[i-3] = (output[i-6] + output[i])/2;
+                        if (x<WIDTH-1 && 2 <= y)
+                                output[i-3*WIDTH]=(output[i-6*WIDTH]+output[i])/2;
+                        if (1 <= x && x < WIDTH && 2 <= y && y < HEIGHT)
+                                output[i-3-3*WIDTH] = (output[i] + output[i-6] + output[i-6*WIDTH]+output[i-6-6*WIDTH])/4;
+                        i+=6;
+                        o+=1;
+                }
+                y++;
+                i = (y * WIDTH + /*x=*/0) * 3;
+                o = y * WIDTH + /*x=*/0/2 + WIDTH/2;
+		for (x = 0; x < WIDTH; x+=2) {
+                        p = input[o];
+                        output[i+2] = blue[p];
+                        if (1 <= x && y<HEIGHT-1)
+                                output[i+2-3] = (output[i+2-6] + output[i+2])/2;
+                        if (x<WIDTH-1 && 2 <= y)
+                                output[i+2-3*WIDTH] = (output[i+2]+output[i+2-6*WIDTH])/2;
+                        if (1 <= x && x < WIDTH && 2 <= y && y < HEIGHT)
+                                output[i+2-3-3*WIDTH] = (output[i+2] + output[i+2-6] + output[i+2-6*WIDTH]+output[i+2-6-6*WIDTH])/4;
+                        i+=6;
+                        o++;
+		}
+                i = (y * WIDTH + /*x=*/1) * 3;
+                o = y * WIDTH + /*x=*/1/2;
+                for (x = 1; x < WIDTH; x+=2) {
+                        p = input[o];
+                        output[i+1] = green[p];
+                        if (1 <= x && x < WIDTH-1 && 2 <= y && y < HEIGHT)
+                                output[i+1-3*WIDTH] = (output[i+1] + output[i+1-3-3*WIDTH] + output[i+1+3-3*WIDTH]+output[i+1-6*WIDTH])/4;
+                        i+=6;
+                        o++;
+                }
+	}
+}
+void bayer2rgb3_1() {
+        int x, y, i, o;
+        unsigned char p = 0;
+	for (y = 0; y < 2; y++) {
+                i = (y * WIDTH + /*x=*/0) * 3;
+                o = y * WIDTH + /*x=*/0/2 + WIDTH/2;
+		for (x = 0; x < WIDTH-1; x+=2) {
+                        p = input[o];
+                        output[i+1] = green[p];
+                        i+=6;
+                        o+=1;
+		}
+                p = input[o];
+                output[i+1] = green[p];
+                
+                i = (y * WIDTH + /*x=*/1) * 3;
+                o = y * WIDTH + /*x=*/1/2;
+                for (x = 1; x < WIDTH; x+=2) {
+                        p = input[o];
+                        output[i] = red[p];
+                        output[i-3] = (output[i-6] + output[i])/2;
+                        i+=6;
+                        o+=1;
+                }
+                y++;
+                i = (y * WIDTH + /*x=*/0) * 3;
+                o = y * WIDTH + /*x=*/0/2 + WIDTH/2;
+                p = input[o];
+                output[i+2] = blue[p];
+                i+=6;
+                o++;
+		for (x = 2; x < WIDTH; x+=2) {
+                        p = input[o];
+                        output[i+2] = blue[p];
+                        output[i+2-3] = (output[i+2-6] + output[i+2])/2;
+                        i+=6;
+                        o++;
+		}
+                i = (y * WIDTH + /*x=*/1) * 3;
+                o = y * WIDTH + /*x=*/1/2;
+                for (x = 1; x < WIDTH; x+=2) {
+                        p = input[o];
+                        output[i+1] = green[p];
+                        i+=6;
+                        o++;
+                }
+	}
+}
+void bayer2rgb3_2() {
+	int x, y, i, o;
+        unsigned char p = 0;
+	for (y = 2; y < HEIGHT-2; y++) {
+                i = (y * WIDTH + /*x=*/0) * 3;
+                o = y * WIDTH + /*x=*/0/2 + WIDTH/2;
+		for (x = 0; x < WIDTH-1; x+=2) {
+                        output[i+1] = green[input[o]];
+                        output[i+1-3*WIDTH] = (output[i+1] + output[i+1-3-3*WIDTH] + output[i+1+3-3*WIDTH]+output[i+1-6*WIDTH])/4;
+                        i+=6;
+                        o+=1;
+		}
+                p = input[o];
+                output[i+1] = green[p];
+                
+                i = (y * WIDTH + /*x=*/1) * 3;
+                o = y * WIDTH + /*x=*/1/2;
+                for (x = 1; x < WIDTH-1; x+=2) {
+                        p = input[o];
+                        output[i] = red[p];
+                        output[i-3] = (output[i-6] + output[i])/2;
+                        output[i-3*WIDTH]=(output[i-6*WIDTH]+output[i])/2;
+                        output[i-3-3*WIDTH] = (output[i] + output[i-6] + output[i-6*WIDTH]+output[i-6-6*WIDTH])/4;
+                        i+=6;
+                        o+=1;
+                }
+                p = input[o];
+                output[i] = red[p];
+                output[i-3] = (output[i-6] + output[i])/2;
+                output[i-3-3*WIDTH] = (output[i] + output[i-6] + output[i-6*WIDTH]+output[i-6-6*WIDTH])/4;
+                
+                y++;
+                i = (y * WIDTH + /*x=*/0) * 3;
+                o = y * WIDTH + /*x=*/0/2 + WIDTH/2;
+                p = input[o];
+                output[i+2] = blue[p];
+                output[i+2-3*WIDTH] = (output[i+2]+output[i+2-6*WIDTH])/2;
+                i+=6;
+                o++;
+		for (x = 2; x < WIDTH; x+=2) {
+                        p = input[o];
+                        output[i+2] = blue[p];
+                        output[i+2-3] = (output[i+2-6] + output[i+2])/2;
+                        output[i+2-3*WIDTH] = (output[i+2]+output[i+2-6*WIDTH])/2;
+                        output[i+2-3-3*WIDTH] = (output[i+2] + output[i+2-6] + output[i+2-6*WIDTH]+output[i+2-6-6*WIDTH])/4;
+                        i+=6;
+                        o++;
+		}
+                i = (y * WIDTH + /*x=*/1) * 3;
+                o = y * WIDTH + /*x=*/1/2;
+                for (x = 1; x < WIDTH-1; x+=2) {
+                        p = input[o];
+                        output[i+1] = green[p];
+                        output[i+1-3*WIDTH] = (output[i+1] + output[i+1-3-3*WIDTH] + output[i+1+3-3*WIDTH]+output[i+1-6*WIDTH])/4;
+                        i+=6;
+                        o++;
+                }
+                p = input[o];
+                output[i+1] = green[p];
+	}
+}
+void bayer2rgb3_3() {
+	int x, y, i, o;
+        unsigned char p = 0;
+	for (y = HEIGHT-2; y < HEIGHT; y++) {
+                i = (y * WIDTH + /*x=*/0) * 3;
+                o = y * WIDTH + /*x=*/0/2 + WIDTH/2;
+		for (x = 0; x < WIDTH-1; x+=2) {
+                        output[i+1] = green[input[o]];
+                        output[i+1-3*WIDTH] = (output[i+1] + output[i+1-3-3*WIDTH] + output[i+1+3-3*WIDTH]+output[i+1-6*WIDTH])/4;
+                        i+=6;
+                        o+=1;
+		}
+                p = input[o];
+                output[i+1] = green[p];
+                
+                i = (y * WIDTH + /*x=*/1) * 3;
+                o = y * WIDTH + /*x=*/1/2;
+                for (x = 1; x < WIDTH-1; x+=2) {
+                        p = input[o];
+                        output[i] = red[p];
+                        output[i-3] = (output[i-6] + output[i])/2;
+                        output[i-3*WIDTH]=(output[i-6*WIDTH]+output[i])/2;
+                        output[i-3-3*WIDTH] = (output[i] + output[i-6] + output[i-6*WIDTH]+output[i-6-6*WIDTH])/4;
+                        i+=6;
+                        o+=1;
+                }
+                p = input[o];
+                output[i] = red[p];
+                output[i-3] = (output[i-6] + output[i])/2;
+                output[i-3-3*WIDTH] = (output[i] + output[i-6] + output[i-6*WIDTH]+output[i-6-6*WIDTH])/4;
+                
+                y++;
+                i = (y * WIDTH + /*x=*/0) * 3;
+                o = y * WIDTH + /*x=*/0/2 + WIDTH/2;
+                p = input[o];
+                output[i+2] = blue[p];
+                output[i+2-3*WIDTH] = (output[i+2]+output[i+2-6*WIDTH])/2;
+                i+=6;
+                o++;
+		for (x = 2; x < WIDTH-1; x+=2) {
+                        p = input[o];
+                        output[i+2] = blue[p];
+                        output[i+2-3*WIDTH] = (output[i+2]+output[i+2-6*WIDTH])/2;
+                        output[i+2-3-3*WIDTH] = (output[i+2] + output[i+2-6] + output[i+2-6*WIDTH]+output[i+2-6-6*WIDTH])/4;
+                        i+=6;
+                        o++;
+		}
+                        
+                i = (y * WIDTH + /*x=*/1) * 3;
+                o = y * WIDTH + /*x=*/1/2;
+                for (x = 1; x < WIDTH-1; x+=2) {
+                        p = input[o];
+                        output[i+1] = green[p];
+                        output[i+1-3*WIDTH] = (output[i+1] + output[i+1-3-3*WIDTH] + output[i+1+3-3*WIDTH]+output[i+1-6*WIDTH])/4;
+                        i+=6;
+                        o++;
+                }
+                p = input[o];
+                output[i+1] = green[p];
+        }
+}        
+
+void fix_edges() {
+        int y, i;
+        /* fix top and bottom row, left and right side */
+	i = WIDTH * 3;
+	memcpy (output, (output + i), i);
+	memcpy ((output + (HEIGHT * i)), (output + ((HEIGHT - 1) * i)), i);
+	for (y = 0; y < HEIGHT; y++) {
+		i = y * WIDTH * 3;
+                output[i] = output[i+3];
+                output[i+1] = output[i+3+1];
+                output[i+2] = output[i+3+2];
+                output[i+(WIDTH*3)] = output[i+(WIDTH-1)*3];
+                output[i+(WIDTH*3)+1] = output[i+(WIDTH-1)*3+1];
+                output[i+(WIDTH*3)+2] = output[i+(WIDTH-1)*3+2];
+	}
+}
+void bayer_unshuffle() {
+        bayer2rgb3_1();
+        bayer2rgb3_2();
+        bayer2rgb3_3();
+        fix_edges();
+}				/* bayer_unshuffle */
+
+/*******  end routines from the pencam program  *********/
+
+int main(int argc, char **argv) {
+	for(;;) {
+		if (fread(input, WIDTH*HEIGHT, 1, stdin) != 1)
+			break;
+		bayer_unshuffle();
+		printf("P6\n%d %d\n255\n", WIDTH, HEIGHT);
+		fwrite(output, WIDTH*HEIGHT*3, 1, stdout);
+	}
+	return 0;
+}
addfile ./stv680-read.c
hunk ./stv680-read.c 1
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <signal.h>
+#include <ctype.h>
+#include <usb.h>
+#include <unistd.h>
+
+struct usb_dev_handle *devh;
+
+void release_usb_device(int dummy) {
+    int ret;
+    ret = usb_release_interface(devh, 0);
+    if (!ret)
+	printf("failed to release interface: %d\n", ret);
+    usb_close(devh);
+    if (!ret)
+	printf("failed to close interface: %d\n", ret);
+    exit(1);
+}
+
+void list_devices() {
+    struct usb_bus *bus;
+    for (bus = usb_get_busses(); bus; bus = bus->next) {
+	struct usb_device *dev;
+	
+	for (dev = bus->devices; dev; dev = dev->next)
+	    printf("0x%04x 0x%04x\n",
+		   dev->descriptor.idVendor,
+		   dev->descriptor.idProduct);
+    }
+}    
+
+struct usb_device *find_device(int vendor, int product) {
+    struct usb_bus *bus;
+    
+    for (bus = usb_get_busses(); bus; bus = bus->next) {
+	struct usb_device *dev;
+	
+	for (dev = bus->devices; dev; dev = dev->next) {
+	    if (dev->descriptor.idVendor == vendor
+		&& dev->descriptor.idProduct == product)
+		return dev;
+	}
+    }
+    return NULL;
+}
+
+void print_bytes(char *bytes, int len) {
+    int i;
+    if (len > 0) {
+	for (i=0; i<len; i++) {
+	    fprintf(stderr, "%02x ", (int)((unsigned char)bytes[i]));
+	}
+	fprintf(stderr, "\"");
+        for (i=0; i<len; i++) {
+		fprintf(stderr, "%c", isprint(bytes[i]) ? bytes[i] : '.');
+        }
+        fprintf(stderr, "\"");
+    }
+}
+
+
+int main(int argc, char **argv) {
+    int ret, vendor, product;
+    struct usb_device *dev;
+    char buf[65535];
+    int verbose;
+    usb_init();
+//    usb_set_debug(255);
+    usb_find_busses();
+    usb_find_devices();
+
+    if (argc<3) {
+	    printf("usage: %s vendorID productID\n", argv[0]);
+	    printf("ID numbers of currently attached devices:\n");
+	    list_devices();
+	    exit(1);
+    }
+    if (argc==4 && argv[3][0] == '-' && argv[3][1] == 'v' && argv[3][2] == 0)
+	    verbose = 1;
+    else
+	    verbose = 0;
+    vendor = strtol(argv[1], NULL, 16);
+    product = strtol(argv[2], NULL, 16);
+    if (vendor <= 1 || product <= 1) {
+	printf("invalid vendor or product id\n");
+	exit(1);
+    }
+    dev = find_device(vendor, product);
+    assert(dev);
+
+    devh = usb_open(dev);
+    assert(devh);
+    
+    signal(SIGTERM, release_usb_device);
+
+    ret = usb_claim_interface(devh, 0);
+    if (ret != 0) {
+	    printf("claim failed with error %d\n", ret);
+	    exit(1);
+    }
+    
+    ret = usb_set_altinterface(devh, 0);
+    assert(ret >= 0);
+
+ret = usb_get_descriptor(devh, 0x0000002, 0x0000000, buf, 0x0000009);
+if (verbose) fprintf(stderr, "1 get descriptor returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(3*1000);
+ret = usb_get_descriptor(devh, 0x0000002, 0x0000000, buf, 0x0000022);
+if (verbose) fprintf(stderr, "2 get descriptor returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(7*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000085, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "3 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(9*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000085, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "4 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(156*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008a, 0x0000000, 0x0000000, buf, 0x0000002, 1000);
+if (verbose) fprintf(stderr, "5 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(3*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008b, 0x0000000, 0x0000000, buf, 0x0000024, 1000);
+if (verbose) fprintf(stderr, "6 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(10*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000085, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "7 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(5*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000085, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "8 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(5*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000085, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "9 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(5*1000);
+ret = usb_get_descriptor(devh, 0x0000001, 0x0000000, buf, 0x0000012);
+if (verbose) fprintf(stderr, "10 get descriptor returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(14*1000);
+ret = usb_set_configuration(devh, 0x0000001);
+if (verbose) fprintf(stderr, "11 set configuration returned %d\n", ret);
+ret = usb_set_altinterface(devh, 1);
+if (verbose) fprintf(stderr, "11 set alternate setting returned %d\n", ret);
+usleep(21*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000085, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "12 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(6*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000088, 0x0007856, 0x0000000, buf, 0x0000002, 1000);
+if (verbose) fprintf(stderr, "13 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(3*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008d, 0x0000000, 0x0000000, buf, 0x0000008, 1000);
+if (verbose) fprintf(stderr, "14 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(116*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008d, 0x0000000, 0x0000000, buf, 0x0000008, 1000);
+if (verbose) fprintf(stderr, "15 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(109*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008d, 0x0000000, 0x0000000, buf, 0x0000008, 1000);
+if (verbose) fprintf(stderr, "16 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(110*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008d, 0x0000000, 0x0000000, buf, 0x0000008, 1000);
+if (verbose) fprintf(stderr, "17 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(109*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008d, 0x0000000, 0x0000000, buf, 0x0000008, 1000);
+if (verbose) fprintf(stderr, "18 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(110*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008d, 0x0000000, 0x0000000, buf, 0x0000008, 1000);
+if (verbose) fprintf(stderr, "19 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(109*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008d, 0x0000000, 0x0000000, buf, 0x0000008, 1000);
+if (verbose) fprintf(stderr, "20 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(110*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008d, 0x0000000, 0x0000000, buf, 0x0000008, 1000);
+if (verbose) fprintf(stderr, "21 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(6*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008a, 0x0000000, 0x0000000, buf, 0x0000002, 1000);
+if (verbose) fprintf(stderr, "22 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(2*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008b, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "23 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(6*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008b, 0x0001000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "24 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(6*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008b, 0x0002000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "25 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(9*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000086, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "26 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(5*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000085, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "27 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(5*1000);
+ret = usb_set_configuration(devh, 0x0000001);
+if (verbose) fprintf(stderr, "28 set configuration returned %d\n", ret);
+ret = usb_set_altinterface(devh, 0);
+if (verbose) fprintf(stderr, "28 set alternate setting returned %d\n", ret);
+usleep(280*1000);
+ret = usb_set_configuration(devh, 0x0000001);
+if (verbose) fprintf(stderr, "29 set configuration returned %d\n", ret);
+ret = usb_set_altinterface(devh, 1);
+if (verbose) fprintf(stderr, "29 set alternate setting returned %d\n", ret);
+usleep(25*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000085, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "30 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(5*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000088, 0x0007856, 0x0000000, buf, 0x0000002, 1000);
+if (verbose) fprintf(stderr, "31 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(3*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008d, 0x0000000, 0x0000000, buf, 0x0000008, 1000);
+if (verbose) fprintf(stderr, "32 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(5*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008a, 0x0000000, 0x0000000, buf, 0x0000002, 1000);
+if (verbose) fprintf(stderr, "33 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(3*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008b, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "34 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(6*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008b, 0x0001000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "35 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(6*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008b, 0x0002000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "36 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(9*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000086, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "37 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(5*1000);
+ret = usb_set_configuration(devh, 0x0000001);
+if (verbose) fprintf(stderr, "38 set configuration returned %d\n", ret);
+ret = usb_set_altinterface(devh, 0);
+if (verbose) fprintf(stderr, "38 set alternate setting returned %d\n", ret);
+usleep(1633*1000);
+ret = usb_set_configuration(devh, 0x0000001);
+if (verbose) fprintf(stderr, "39 set configuration returned %d\n", ret);
+ret = usb_set_altinterface(devh, 1);
+if (verbose) fprintf(stderr, "39 set alternate setting returned %d\n", ret);
+usleep(28*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000085, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "40 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(5*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000088, 0x0007856, 0x0000000, buf, 0x0000002, 1000);
+if (verbose) fprintf(stderr, "41 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(6*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008a, 0x0000000, 0x0000000, buf, 0x0000002, 1000);
+if (verbose) fprintf(stderr, "42 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(3*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008b, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "43 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(6*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008b, 0x0001000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "44 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(6*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008b, 0x0002000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "45 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(6*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000085, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "46 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(5*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008f, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "47 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(6*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008d, 0x0000000, 0x0000000, buf, 0x0000008, 1000);
+if (verbose) fprintf(stderr, "48 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(4*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000085, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "49 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(11*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000085, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "50 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(6*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000088, 0x0003412, 0x0000000, buf, 0x0000002, 1000);
+if (verbose) fprintf(stderr, "51 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(2*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000088, 0x0007856, 0x0000000, buf, 0x0000002, 1000);
+if (verbose) fprintf(stderr, "52 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(3*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008f, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "53 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(6*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008d, 0x0000000, 0x0000000, buf, 0x0000008, 1000);
+if (verbose) fprintf(stderr, "54 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(3*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000085, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "55 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(6*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000085, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "56 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(6*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000085, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "57 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(2500*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008d, 0x0000000, 0x0000000, buf, 0x0000008, 1000);
+if (verbose) fprintf(stderr, "58 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(7*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000088, 0x0003412, 0x0000000, buf, 0x0000002, 1000);
+if (verbose) fprintf(stderr, "59 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(3*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000088, 0x0007856, 0x0000000, buf, 0x0000002, 1000);
+if (verbose) fprintf(stderr, "60 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(3*1000);
+ret = usb_set_configuration(devh, 0x0000001);
+if (verbose) fprintf(stderr, "61 set configuration returned %d\n", ret);
+ret = usb_set_altinterface(devh, 0);
+if (verbose) fprintf(stderr, "61 set alternate setting returned %d\n", ret);
+usleep(14*1000);
+ret = usb_get_descriptor(devh, 0x0000001, 0x0000000, buf, 0x0000012);
+if (verbose) fprintf(stderr, "62 get descriptor returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(5*1000);
+ret = usb_get_descriptor(devh, 0x0000001, 0x0000000, buf, 0x0000012);
+if (verbose) fprintf(stderr, "63 get descriptor returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(8*1000);
+ret = usb_get_descriptor(devh, 0x0000001, 0x0000000, buf, 0x0000012);
+if (verbose) fprintf(stderr, "64 get descriptor returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(9*1000);
+ret = usb_get_descriptor(devh, 0x0000001, 0x0000000, buf, 0x0000012);
+if (verbose) fprintf(stderr, "65 get descriptor returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(4*1000);
+ret = usb_set_configuration(devh, 0x0000001);
+if (verbose) fprintf(stderr, "66 set configuration returned %d\n", ret);
+ret = usb_set_altinterface(devh, 1);
+if (verbose) fprintf(stderr, "66 set alternate setting returned %d\n", ret);
+usleep(23*1000);
+usleep(1*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000085, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "75 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(5*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE, 0x0000009, 0x0000000, 0x0000000, buf, 0x0000000, 1000);
+if (verbose) fprintf(stderr, "76 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(67*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008c, 0x0000000, 0x0000000, buf, 0x0000001, 1000);
+if (verbose) fprintf(stderr, "77 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(3*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000085, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "78 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(5*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008a, 0x0000000, 0x0000000, buf, 0x0000002, 1000);
+if (verbose) fprintf(stderr, "79 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(3*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008b, 0x0000000, 0x0000000, buf, 0x0000024, 1000);
+if (verbose) fprintf(stderr, "80 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(10*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000093, 0x0000000, 0x0000000, buf, 0x0000002, 1000);
+if (verbose) fprintf(stderr, "81 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(1*1000);
+ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x0000085, 0x0000000, 0x0000000, buf, 0x0000010, 1000);
+if (verbose) fprintf(stderr, "82 control msg returned %d, bytes: ", ret);
+if (verbose) print_bytes(buf, ret);
+if (verbose) fprintf(stderr, "\n");
+usleep(15*1000);
+{
+	int j;
+	/* kernel driver says
+	   stv680.c: [stv_init:381] STV(i): CIF is supported
+	   stv680.c: [stv_init:386] STV(i): Firmware rev is 1.0
+	   stv680.c: [stv_init:387] STV(i): ASIC rev is 7.6
+	   stv680.c: [stv_init:388] STV(i): Sensor ID is 410
+	   stv680.c: [stv_init:399] STV(i): Camera has 0 pictures.
+	   stv680.c: [stv_init:426] STV(i): Video Mode set to CIF
+	   stv680.c: [stv_init:468] STV(i): width = 352, height = 288, rawbufsize = 103952
+	   stv680.c: [stv_init:488] STV(i): swapRGB is (auto) OFF
+	   stv680.c: [stv_set_video_mode:302] STV(i): Setting video mode.
+	   stv680.c: [stv_stop_video:244] STV(i): Camera reset to idle mode.
+	*/
+
+	     
+		ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008c, 0x0000000, 0x0000000, buf, 0x0000001, 1000);
+		do {
+			ret = usb_bulk_read(devh, 0x00000082, buf, 0x0001000, 1000);
+//			fprintf(stderr, "waiting for sync, ret %d\n", ret);
+		} while (ret != 1552);
+	for(;;) {
+//		ret = usb_control_msg(devh, USB_TYPE_VENDOR + USB_RECIP_INTERFACE + USB_ENDPOINT_IN, 0x000008c, 0x0000000, 0x0000000, buf, 0x0000001, 1000);
+		for (j=0; j<33; j++) {
+			ret = usb_bulk_read(devh, 0x00000082, buf, 32768, 1000);
+//			fprintf(stderr,  "%04d ", ret);
+			if (ret>0) write(1, buf, ret);
+		}
+	}
+}
+ return 0;
+}
addfile ./stv680-show.c
hunk ./stv680-show.c 1
+#include <SDL/SDL.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <sys/time.h>
+#include <assert.h>
+
+#define WIDTH 356
+#define HEIGHT 292
+#define BUFLEN 256
+
+double timediff(struct timeval *tv1, struct timeval *tv2) {
+	long dsec, dusec;
+	dsec = tv2->tv_sec - tv1->tv_sec;
+	dusec = tv2->tv_usec - tv1->tv_usec;
+	return (double)dsec + (double)dusec/(1000*1000);
+}
+int main(int argc, char **argv) {
+	SDL_Surface *screen;
+	SDL_Event event;
+	unsigned char buf[WIDTH*HEIGHT*3];
+
+        Uint32 *bufp;
+	Uint32 x,y;
+	int frames, last_frames;
+	struct timeval tv1, tv2;
+	int verbose;
+	if (argc==2 && argv[1][0] == '-' && argv[1][1] == 'v' && argv[1][2] == 0)
+		verbose = 1;
+	else
+		verbose = 0;
+
+	if(SDL_Init(SDL_INIT_VIDEO)) {
+		puts("failed to initialize SDL");
+		exit(EXIT_FAILURE);
+	}
+	atexit(SDL_Quit);
+	
+	screen=SDL_SetVideoMode(WIDTH, HEIGHT,
+                                32, SDL_HWSURFACE|SDL_DOUBLEBUF);
+	
+	if(screen==NULL) {
+		puts("failed to set video mode");
+		exit(EXIT_FAILURE);
+	}
+	
+	bufp = (Uint32 *)screen->pixels;
+	frames = last_frames = 0;
+	gettimeofday(&tv1, NULL);
+	for(;;) {
+		double tdiff;
+		// skip header
+		fgets((char*)buf, BUFLEN, stdin);
+		assert(buf[0] == 'P' && buf[1] == '6');
+		fgets((char*)buf, BUFLEN, stdin);
+		fgets((char*)buf, BUFLEN, stdin);
+		if (fread(buf, WIDTH*HEIGHT*3, 1, stdin) != 1) {
+			SDL_Quit();
+			exit(0);
+		}
+		for(y=0; y<HEIGHT; y++) {
+			for(x=0; x<WIDTH; x++) {
+				bufp[x+WIDTH*y]=(buf[x*3+y*WIDTH*3+0]<<16)+(buf[x*3+y*WIDTH*3+1]<<8)+(buf[x*3+y*WIDTH*3+2]);
+			}
+		}
+		SDL_Flip(screen);
+		if (verbose) {
+			frames++;
+			gettimeofday(&tv2, NULL);
+
+			tdiff = timediff(&tv1, &tv2);
+			if (tdiff >= 5) {
+				printf("%.3f fps\n",
+				       frames / tdiff);
+				frames = 0;
+				memcpy(&tv1, &tv2, sizeof(tv2));
+			}
+		}
+
+		SDL_PollEvent(&event);
+		if((event.type==SDL_KEYDOWN && event.key.keysym.sym=='q') || event.type==SDL_QUIT) {
+			SDL_Quit();
+			exit(0);
+		}
+
+	}
+	return 0;
+}
+	
}
