/* * USB Quickcam Video Camera Sequential Image Capture Program for NetBSD/FreeBSD, version 0.04 * qcamview - Sequential image capture program. * Copyright (C) 2003-2004 Takafumi Mizuno * * This program is very referenced one book. see "gui.c" more detail. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "gui.h" #include "linux_usbif.h" #include "quickcam.h" /* Control register of the STV0600 ASIC */ #include "helper.h" #include "pb0100.h" #include "hdcs.h" #include "vv6410.h" #define _QCAMVIEW_ #include "qcamshot.h" struct usb_device usbdev; struct usb_quickcam *quickcam; char dev[FILENAME_MAX]; #define REQ_FRAMES 10 #define RAW_DAT_BUFSIZE (REQ_FRAMES*FRAMES_PER_DESC*FRAME_SIZE_PER_DESC) static unsigned char storebuf[RAW_DAT_BUFSIZE*3]; static unsigned char grabbuf[RAW_DAT_BUFSIZE]; static unsigned char rgb[BAYER_FRAME_SIZE*4]; /* 4= 0RGB */ GdkImlibImage *get_new_frame(GdkImlibImage *); int main(int argc, char *argv[]) { int i = 0; gtk_init(&argc, &argv); gdk_imlib_init(); /* * check option */ if (argc == 1) { /* search Quickcam */ for ( i = 0; i < 15; ++i ) { #ifdef __FreeBSD__ sprintf(dev, "/dev/ugen%d", i); #else sprintf(dev, "/dev/ugen%d.00", i); #endif if ( (usbdev.fd = open(dev, O_RDWR)) < 0 ) { continue; } if ( (quickcam = (struct usb_quickcam *)quickcam_probe(&usbdev)) == NULL ) { close(usbdev.fd); usbdev.fd = -1; continue; } else { break; } } } else { if ( argv[1][0] != '/' ) { fprintf(stderr, "usage: %s [device-name]\n", argv[0]); fprintf(stderr, " [device-name] must be started slash \'/\' character.\n"); exit(1); } strncpy(dev, argv[1], FILENAME_MAX-1); if ( (usbdev.fd = open(dev, O_RDWR)) < 0 ) { err(1, "%s", dev); } else { if ( (quickcam = (struct usb_quickcam *)quickcam_probe(&usbdev)) == NULL ) { close(usbdev.fd); usbdev.fd = -1; } } } if ( usbdev.fd < 0 ) { fprintf(stderr, "Not found Quickcam, or Permission denied\n"); exit(1); } quickcam_open(quickcam); /* open endpoint (endpoint 1) */ #ifdef __FreeBSD__ sprintf(usbdev.epdevname, "%s.1", dev); #else sprintf(usbdev.epdevname, "%s.01", strtok(dev,".")); #endif if ((usbdev.efd = open(usbdev.epdevname, O_RDONLY)) < 0) { perror(usbdev.epdevname); quickcam_close(quickcam); close(usbdev.fd); exit(1); } memset(storebuf, 0, RAW_DAT_BUFSIZE*3); memset(grabbuf, 0, RAW_DAT_BUFSIZE); memset(rgb, 0, BAYER_FRAME_SIZE*4); if ( usb_quickcam_start(quickcam) < 0) { fprintf(stderr, "can\'t quickcam start\n"); } else { gui_config(); gtk_main(); } fprintf(stderr, "Closing Qcam Express....."); close(usbdev.efd); quickcam_close(quickcam); /* do free(quickcam) */ close(usbdev.fd); fprintf(stderr, "Done.\n"); return 0; } /* Read raw-data from Quickcam and convert to RGB24 * reference qce-linux-driver * quickcam_parse_store() quickcam_parse_data() */ GdkImlibImage *get_new_frame(GdkImlibImage *current) { int i, cur_len; unsigned char *isodat, *rawdat; ssize_t readlen; int totalsize; /* total iso-packet data */ int tot_len; /* total grabbing data */ unsigned char type1, type2; int frag_len; enum { SEARCH_HEAD, GRABBING_DAT, FOUND_TAIL} state; int framesize; long ii; unsigned long mid_value=0; unsigned long mid_value_line=0; int xx=0; int yy=0; int xd=0; int copylen=0; unsigned char *o; unsigned char *data; int skiph; int startw, endw; /* Use sensor information to get the framesize */ if (quickcam->sensor_ctrl.mode==1) framesize = qcmin(BAYER_FRAME_SIZE, (quickcam->sensor_ctrl.width* quickcam->sensor_ctrl.height)*2); else framesize = qcmin(BAYER_FRAME_SIZE, quickcam->sensor_ctrl.width* quickcam->sensor_ctrl.height); /* get iso packet (with margin) */ totalsize = 0; isodat = storebuf; totalsize = 0; for ( i = 0; i < (REQ_FRAMES*FRAMES_PER_DESC*3); i++ ) { if ( (readlen = read(usbdev.efd, (void *)isodat, FRAME_SIZE_PER_DESC))<0 ) { perror("Read"); return NULL; } isodat += readlen; totalsize += readlen; } /* fail safe */ if ( totalsize > RAW_DAT_BUFSIZE*3) { fprintf(stderr,"!"); return NULL; } /* grab raw RGB data from isopacket */ tot_len = 0; isodat = storebuf; rawdat = grabbuf; state = SEARCH_HEAD; /* enum { SEARCH_HEAD, GRABBING_DAT, FOUND_TAIL} */ for ( cur_len = 0; cur_len < totalsize; cur_len++ ) { type1 = isodat[cur_len]; type2 = isodat[cur_len+1]; frag_len=isodat[cur_len+2]<<8 | isodat[cur_len+3]; if(type1==0x80 || type1==0xC0) { if(type2==1 || type2==5) { /* a frame begins - see if we can capture it. */ if ( state == SEARCH_HEAD ) { state = GRABBING_DAT; cur_len += 3; continue; } else if ( state == GRABBING_DAT ) { /* restart */ state = GRABBING_DAT; tot_len = 0; rawdat = grabbuf; cur_len += 3; continue; } else { /* cant find FOUND_TAIL, grabbing abort */ state = FOUND_TAIL; break; } } else if(type2==2 || type2==6) { /* a frame end */ if ( state == GRABBING_DAT ) { state = FOUND_TAIL; break; } else { /* ignore */ cur_len += 3; continue; } } } else if(type1==0x02 || type1==0x42) { /* data chunk */ if ( state != GRABBING_DAT ) { cur_len += 3; continue; } if ( tot_len + frag_len > BAYER_FRAME_SIZE) { state = FOUND_TAIL; break; } memcpy((void *)rawdat, (void *)&isodat[cur_len+4], frag_len); rawdat += frag_len; tot_len += frag_len; cur_len += (frag_len + 3); } /* other ignore */ } if ( state != FOUND_TAIL ) { fprintf(stderr,"/"); return NULL; } /* grabbing sucess ?: total size %d\n", tot_len); */ if ( tot_len != framesize ) { tot_len = framesize; } #define addblue 0 #define addgreen 1 #define addred 2 /* need cleaning ... */ #define XH QUICKCAM_HEIGHT #define XW QUICKCAM_WIDTH #define SW quickcam->sensor_ctrl.width /* calculate data to skip for the VV6410 sensor */ if (mode) { skiph = (quickcam->sensor_ctrl.height-(XH/2))/2; startw = (quickcam->sensor_ctrl.width-(XW/2))/2; } else { skiph = (quickcam->sensor_ctrl.height-XH)/2; startw = (quickcam->sensor_ctrl.width-XW)/2; } if (skiph<0) skiph=0; if (startw<0) startw=0; endw = quickcam->sensor_ctrl.width-startw; /* difference original linux driver as follow; */ /* frame->storedata ==> grabbuf */ /* frame->storelength ==> tot_len */ /* frame->data ==> rgb */ /* frame->scanlength ==> N/A */ /* skip fisrt and last lines if needed */ data = grabbuf+(skiph*quickcam->sensor_ctrl.width); for (ii=skiph*quickcam->sensor_ctrl.width; iisensor_ctrl.width); ii++) { /* * Skip line data when needed. */ if ((ii%quickcam->sensor_ctrl.widthsensor_ctrl.width>=endw && startw)) { data++; continue; } /* * For HDCS Sensors: * Camera is G1R1 G2R2 G3R3... * B4G4 B5G5 B6G6... * Video is B4G1R1 B4G1R1 * B4G4R1 B4G4R1 * For Photobit... */ if (yy>XH) yy=XH; if (mode) { o=((unsigned char*)rgb)+3*xd+(XW*3*yy); xd++; xd++; } else { o=((unsigned char*)rgb)+3*xx+(XW*3*yy); } mid_value_line+=*data; if (interpolation == 1) { /* bilinear interpolation */ if (!(yy&1)) { // even row if (xx&1) { // odd column, red *(o+addred)=*data; if (yy == 0) { if (xx == XW-1) { *(o+addblue)=*(data+SW-1); *(o+addgreen)=(*(data-1) + *(data+SW))/2; } else { *(o+addblue)=(*(data+SW-1) + *(data+SW+1))/2; *(o+addgreen)=(*(data-1) + *(data+1) + *(data+SW))/3; } } else { if (xx == XW-1) { *(o+addblue)=(*(data-SW-1) + *(data+SW-1))/2; *(o+addgreen)=(*(data-SW) + *(data-1) + *(data+SW))/3; } else { *(o+addblue)=(*(data-SW-1) + *(data-SW+1) + *(data+SW-1) + *(data+SW+1))/4; *(o+addgreen)=(*(data-SW) + *(data-1) + *(data+1) + *(data+SW))/4; } } if (mode) { } } else { // green if (yy == 0) { if (xx == 0) { *(o+addred)=*(data+1); *(o+addblue)=*(data+SW); } else { *(o+addred)=(*(data-1) + *(data+1))/2; *(o+addblue)=*(data+SW); } } else { if (xx == 0) { *(o+addred)=*(data+1); *(o+addblue)=(*(data-SW) + *(data+SW))/2; } else { *(o+addred)=(*(data-1) + *(data+1))/2; *(o+addblue)=(*(data-SW) + *(data+SW))/2; } } *(o+addgreen)=*data; if (mode) { } } } else { if (xx&1) { // odd column green if (yy == XH-1) { if (xx == XW-1) { *(o+addred)=*(data-SW); *(o+addblue)=*(data-1); } else { *(o+addred)=*(data-SW); *(o+addblue)=(*(data-1) + *(data+1))/2; } } else { if (xx == XW-1) { *(o+addred)=(*(data-SW) + *(data+SW))/2; *(o+addblue)=*(data-1); } else { *(o+addred)=(*(data-SW) + *(data+SW))/2; *(o+addblue)=(*(data-1) + *(data+1))/2; } } *(o+addgreen)=*data; if (mode) { } } else { //blue *(o+addblue)=*data; if (yy == XH-1) { if (xx == 0) { *(o+addred)=*(data-SW+1); *(o+addgreen)=(*(data-SW) + *(data+1))/2; } else { *(o+addred)=(*(data-SW-1) + *(data-SW+1))/2; *(o+addgreen)=(*(data-SW) + *(data-1) + *(data+1))/3; } } else { if (xx == 0) { *(o+addred)=(*(data-SW+1) + *(data+SW+1))/2; *(o+addgreen)=(*(data-SW) + *(data+1) + *(data+SW))/3; } else { *(o+addred)=(*(data-SW-1) + *(data-SW+1) + *(data+SW-1) + *(data+SW+1))/4; *(o+addgreen)=(*(data-SW) + *(data-1) + *(data+1) + *(data+SW))/4; } } if (mode) { } } } } else { /* not bilinear interpolation */ if (!(yy&1)) { // even row if (xx&1) { // odd column, red *(o+addred)=*data; *(o+addred-3)=*data; *(o+addred+3*(XW))=*data; *(o+addred+3*(XW-1))=*data; if (mode) { *(o+addred+3)=*data; *(o+addred-6)=*data; *(o+addred+3*(XW+1))=*data; *(o+addred+3*(XW-2))=*data; } } else { // green *(o+1)=*data; *(o+1+3)=*data; if (mode) { *(o+1+6)=*data; if (xd>2) *(o+1-3)=*data; } } } else { if (xx&1) { // odd column green *(o+1)=*data; *(o+1-3)=*data; if (mode) { *(o+1+3)=*data; *(o+1-6)=*data; *(o+1+6)=*data; // last would be missing. } } else { //blue *(o+addblue)=*data; *(o+addblue+3)=*data; *(o+addblue+3*(XW))=*data; *(o+addblue+3*(XW-1))=*data; if (mode) { *(o+addblue+6)=*data; *(o+addblue+3*(XW+1))=*data; *(o+addblue-6)=*data; *(o+addblue+3*(XW-2))=*data; } } } } xx++; copylen ++; if (xx==XW || (xx==XW/2 && mode)) { if (mode) mid_value += (mid_value_line/(XW/2)); else mid_value += (mid_value_line/XW); mid_value_line = 0; xx=0; xd = 0; yy++; if (yy>=XH) { break; } } data++; } /* * the frame is done, the exposure should * be set here (We are the waked-up process) */ if (yy>=XH || (yy>=XH/2 && mode)) { if (quickcam->sensor_ctrl.mode==2) { mid_value = mid_value/(yy/2); } else { mid_value = mid_value/yy; } usb_quickcam_set_exposure(quickcam,mid_value); } /* if mode=2 we have only 1/2 of the enlargement */ if (quickcam->sensor_ctrl.mode==2) { data = rgb; for (i=XH/2;i>1;i--) { memcpy(&data[i*6*XW],&data[i*3*XW],XW*3); memcpy(&data[i*6*XW-3*XW],&data[i*3*XW],XW*3); } copylen = copylen *2; } if (mode) { copylen = copylen *2; } /* frame->scanlength = (copylen*6)/2; */// yes but how to compute partial pixels!. /* RGB -> BGR */ if(tobgr) { char c; char *p = rgb; int i = QUICKCAM_WIDTH * QUICKCAM_HEIGHT; while(--i) { c = p[0]; p[0] = p[2]; p[2] = c; p += 3; } } if (current) gdk_imlib_kill_image(current); return gdk_imlib_create_image_from_data(rgb, NULL, QUICKCAM_WIDTH,QUICKCAM_HEIGHT); }