View Full Version: Webcam - some success under linux

camerahacks >>Camcorder Discussions >>Webcam - some success under linux


<< Prev | Next >>

linhacker- 12-15-2007
Webcam - some success under linux
I've had some success getting the webcam to work under linux. Maybe this has already been done, but as far as I could tell the button in ops just collects raw output from the camera, and does not turn it into jpeg/mjpeg data I started with the zr364xx.c driver modified with the VID/PID. This did not work, however for two reasons: First the model 3.40 FW is claiming 64 bytes, wheras zr364xx assumes it will get the 4096 it asks for. As a result of this, a remaining size calculation goes negative, which we know is the same as very large positive, and it fails with an error about kernel paging request. So temporarily I used ops to capture a raw file, and used the methods of zr364xx.c to turn it into a jpeg. Second issue is the zr364xx seems to assume 320x240 mode, wheras my camera wanted to put out 640x480. So I had to change some of the jpeg headers it inserts to match. At the moment, I have a program that can take the raw capture from ops for linux and toss a header on it so that the first image is a valid jpeg. Next steps would be to try to seperate multiple images, try to hack linux to ignore the false 64 byte limit the way windows does, and either merge the code into ops or merge the unlock code into a modified zr364xx... Question: has this been done before, am I wasting my time? I really couldn't seem to find an actual solution, just the making of one spread across multiple programs. But maybe it is there somewhere and I just missed it.

BillW- 12-16-2007

Nice work! AFAIK you're treading on virgin ground... congrats on the single-frame success! I suggest you incorporate the code into ops-for-linux, rather than a custom module, so it will more easily run by noobs on different kernel versions.

linhacker- 12-16-2007

That's true... user mode programs are more kernel independent. However, to get my 3.4 going I may have to hack the linux usb drivers, but I suppose others wouldn't need that. I've been out of the scene for a while so my camera is... old. I suppose however that user mode code put into ops isn't even unique to linux, as long as all we are doing is recording to disk without any preview. Off topic for this thread, but I wonder what it takes to write a windows webcam driver once you know the camera side and only need to do the windows back end.

brite_eye- 12-16-2007

I wonder what it takes to write a windows webcam driver once you know the camera side and only need to do the windows back end. Why would anyone bother when Aiptek windows webcam drivers work without any glitches?

linhacker- 12-16-2007

To have a driver smart enough to read and use saturnkeys file? I'm sure the Aiptek driver could be hacked to do that, but the hacked version wouldn't be redistributable. So you'd have to come up with a patch tool that would patch the driver as downloaded from Aiptek...

linhacker- 12-16-2007

so anyway, what is the la-*test*-('") source for ops for linux? It's not real clear from the ops for linux thread

bobbarker- 12-16-2007

0.15 I think...I got that maybe a month ago so there might be a newer version.

linhacker- 12-16-2007

Okay, here's how to make the ops capture file begin with a somewhat valid jpeg frame. Put this in capture_video.c right after the #include and add a call to jpeg_header(file); right before the main while loop. To do: -split frames to make an mjpeg -make it leave camera in a useable state to avoid replugging (examine zr364xx for ideas) -handle other resolutions /*stuff shamelessly ripped off from zr364xx.c */ /*which is GPL v2 just like ops so it should be ok */ /*method inspired by and /*data tables Copyright (C) 2004 Antoine Jacquet */ /* JPEG static data in header (Huffman table, etc) */ static unsigned char header1[] = { 0xFF, 0xD8, // 0xFF, 0xE0, 0x00, 0x10, 'J', 'F', 'I', 'F', //0x00, 0x01, 0x01, 0x00, 0x33, 0x8A, 0x00, 0x00, 0x33, 0x88, 0xFF, 0xDB, 0x00, 0x84 //QUANTATIZATION TABLE 128+4=132 bytes }; static unsigned char header2[] = { 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xC4, 0x00, 0x1F, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xC0,//start of frame markert 0x00, 0x11, 0x08, //8 bit samples // 0x00, 0xF0, //Y = 240 // 0x01, 0x40, //X = 256 + 64 = 320 0x01, 0xe0, //480 0x02, 0x80, //640 0x03, //components 0x01, 0x21, 0x00, //component sampling 0x02, 0x11, 0x01, //component sampling 0x03, 0x11, 0x01, //component sampling 0xFF, 0xDA, 0x00, 0x0C, //scan header, c = 12 bytes 0x03, //components 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3F, 0x00 }; static unsigned char header3; /*end of zr364xx.c copying */ /*function to get exactly this many bytes */ int ReadSize(char *p_buffer, unsigned int length, int timeout) { int this = 0; int total = 0; while(total < length) { this=Read(p_buffer,length-total,timeout); if (this <0) return this; //FIXME, might have read some previusly p_buffer += this; total += this; } return total; } /* call this right before the main capture while loop */ int jpeg_header (FILE *fp) { char *buffer; buffer = malloc(64); /* write the JPEG header */ fwrite (header1, 1, sizeof(header1), fp); /* write color table thingy */ fputc(0, fp); if (ReadSize(buffer,64,TIMEOUT) != 64) return -1; fwrite (buffer, 1, 64, fp); fputc(1, fp); if (ReadSize(buffer,64,TIMEOUT) != 64) return -1; fwrite (buffer, 1, 64, fp); fwrite (header2, 1, sizeof(header2), fp); free(buffer); }

linhacker- 12-16-2007

I think I'm going to temporarily backup from on the fly conversion and instead write a post-processor that takes a raw ops output file and converts it, first to a series of jpegs and eventually to an mjpeg avi. Basic process is this: write a 6 byte static header write 0 write 64 bytes of some table streamed from camera /raw ops file write 1 write 64 bytes of some table from camera write another static header with size info, etc write a lot of data from the camera, ending in ff d9 camera streams some unkown stuff of variable size that we discard camera sends 16 0's **start over - camera is ready to send two 64 byte tables ..and then to incorporate the methods of http://sourceforge.net/projects/jpegtoavi/

linhacker- 12-16-2007

I can sort of convert a raw ops file to images - about 3/4 of them come out okay, but the others have spatial or color corruption. I think I need to try capturing the file under windows without the 64 byte limit and see if my processing tool runs better on that. Here is the code (it needs the same header data tables as above added at the beginning) #define BUFFERSIZE 90000 #define actual_length BUFFERSIZE int main (int argc, char **argv){ FILE *f1, *f2; unsigned char *buffer, *readbuf; char filename[256]; int avail, bufcount, framecount; int bytes, val; int i; f1 = fopen(argv[1], "rb"); buffer = malloc(BUFFERSIZE); avail=0; avail = fread (readbuf=buffer, 1, 1024, f1); for (framecount=0;/*framecount<2*/;framecount++) { printf("framecount %d\n", framecount); bytes=0; sprintf(filename, "%s%03d.jpg", argv[2], framecount); printf("%s:", filename); f2 = fopen(filename, "wb"); if (!f2) return 0; if (avail <= 0) break; printf("read %d bytes\n", avail); /* write the JPEG header */ fwrite(header1, 1, sizeof(header1), f2); fputc(0, f2); fwrite(readbuf, 1, 64, f2); readbuf+=64; avail -= 64; fputc(1, f2); fwrite(readbuf, 1, 64, f2); readbuf+=64; avail -= 64; fwrite(header2, 1, sizeof(header2), f2); fwrite(readbuf, 1, avail, f2); //whatever is left bytes = 128 + avail; avail = fread (readbuf=buffer, 1, BUFFERSIZE-bytes, f1); //now search for ffd9 for (i=avail-1; i; i--) if ((readbuf[i]==0xff) && (readbuf[i+1]==0xd9)) break; if (i) printf("ff d9 found at %d\n", bytes+i); else printf("not found!\n"); i+=2; fwrite(readbuf, 1, i, f2); bytes +=avail; avail -= i; readbuf+=i; fclose(f2); while(avail) { // printf("checking at %d\n", bytes + (readbuf-buffer)); val=0; for(i=0; i<16; ++i) { val += readbuf[i]; if (val) break; } i++; readbuf += i; avail -= i; if (!val) break; } readbuf -= 17; for (i=0; i<16; i++) printf("%02x ", *(readbuf++)); printf("\n"); //if (val)printf("16 zeros not found!\n"); //else printf("16 zeroes found!\n"); printf("%d bytes\n", bytes); //whatever is left belongs to the next frame } fclose(f1); return 0; }

Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.