📄 ov511.c
字号:
*pOut++ = LIMIT(g + y00); *(pOut+w*3) = LIMIT(b + y10); *pOut++ = LIMIT(b + y00); *(pOut+w*3) = LIMIT(r + y11); *pOut++ = LIMIT(r + y01); *(pOut+w*3) = LIMIT(g + y11); *pOut++ = LIMIT(g + y01); *(pOut+w*3) = LIMIT(b + y11); *pOut++ = LIMIT(b + y01);}/***************************************************************For a 640x480 YUV4:2:0 images, data shows up in 1200 384 byte segments. Thefirst 64 bytes of each segment are V, the next 64 are U. The V andU are arranged as follows: 0 1 ... 7 8 9 ... 15 ... 56 57 ... 63The next 256 bytes are Y data and represent 4 squares of 8x8 pixels asfollows: 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 8 9 ... 15 72 73 ... 79 200 201 ... 207 ... ... ... 56 57 ... 63 120 121 127 248 249 ... 255If OV511_DUMPPIX is defined, _parse_data just dumps theincoming segments, verbatim, in order, into the frame.When used with vidcat -f ppm -s 640x480 this puts the dataon the standard output and can be analyzed with the parseppm.cutility I wrote. That's a much faster way for figuring out howthis data is scrambled.****************************************************************/ #define HDIV 8#define WDIV (256/HDIV)static void ov511_parse_data(unsigned char * pIn0, unsigned char * pOut0, int iWidth, int iSegment) {#ifndef OV511_DUMPPIX int k, l, m; unsigned char * pIn; unsigned char * pOut, * pOut1; int iHalf = (iSegment / (iWidth / 32)) & 1; int iY = iSegment / (iWidth / WDIV); int jY = iSegment - iY * (iWidth / WDIV); int iOutY = (iY*HDIV*iWidth + jY*WDIV) * 3; int iUV = iSegment / (iWidth / WDIV * 2); int jUV = iSegment - iUV * (iWidth / WDIV * 2); int iOutUV = (iUV*HDIV*2*iWidth + jUV*WDIV/2) * 3; /* Just copy the Y's if in the first stripe */ if (!iHalf) { pIn = pIn0 + 128; pOut = pOut0 + iOutY; for(k=0; k<4; k++) { pOut1 = pOut; for(l=0; l<8; l++) { for(m=0; m<8; m++) { *pOut1 = *pIn++; pOut1 += 3; } pOut1 += (iWidth - 8) * 3; } pOut += 8 * 3; } } /* Use the first half of VUs to calculate value */ pIn = pIn0; pOut = pOut0 + iOutUV; for(l=0; l<4; l++) { for(m=0; m<8; m++) { int y00 = *(pOut); int y01 = *(pOut+3); int y10 = *(pOut+iWidth*3); int y11 = *(pOut+iWidth*3+3); int u = *(pIn+64) - 128; int v = *pIn++ - 128; ov511_move_420_block(y00, y01, y10, y11, u, v, iWidth, pOut); pOut += 6; } pOut += (iWidth*2 - 16) * 3; } /* Just copy the other UV rows */ for(l=0; l<4; l++) { for(m=0; m<8; m++) { *pOut++ = *(pIn + 64); *pOut = *pIn++; pOut += 5; } pOut += (iWidth*2 - 16) * 3; } /* Calculate values if it's the second half */ if (iHalf) { pIn = pIn0 + 128; pOut = pOut0 + iOutY; for(k=0; k<4; k++) { pOut1 = pOut; for(l=0; l<4; l++) { for(m=0; m<4; m++) { int y10 = *(pIn+8); int y00 = *pIn++; int y11 = *(pIn+8); int y01 = *pIn++; int u = *pOut1 - 128; int v = *(pOut1+1) - 128; ov511_move_420_block(y00, y01, y10, y11, u, v, iWidth, pOut1); pOut1 += 6; } pOut1 += (iWidth*2 - 8) * 3; pIn += 8; } pOut += 8 * 3; } }#else /* Just dump pix data straight out for debug */ int i; pOut0 += iSegment * 384; for(i=0; i<384; i++) { *pOut0++ = *pIn0++; }#endif}static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb){ unsigned char *cdata; int i, totlen = 0; int aPackNum[10]; struct ov511_frame *frame; if (ov511->curframe == -1) { return 0; } for (i = 0; i < urb->number_of_packets; i++) { int n = urb->iso_frame_desc[i].actual_length; int st = urb->iso_frame_desc[i].status; cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; if (!n) continue; aPackNum[i] = n ? cdata[992] : -1; if (st){ // Macro - must be in braces! PDEBUG("data error: [%d] len=%d, status=%d\n", i, n, st); } frame = &ov511->frame[ov511->curframe]; /* Can we find a frame end */ if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] | cdata[4] | cdata[5] | cdata[6] | cdata[7]) == 0 && (cdata[8] & 8) && (cdata[8] & 0x80)) {#if 0 PDEBUG("Found Frame End!, packnum = %d\n", (int)(cdata[992])); PDEBUG("Current frame = %d\n", ov511->curframe);#endif if (frame->scanstate == STATE_LINES) { if (waitqueue_active(&frame->wq)) {#if 0 PDEBUG("About to wake up waiting processes\n");#endif frame->grabstate = FRAME_DONE; ov511->curframe = -1; wake_up_interruptible(&frame->wq); } } } /* Can we find a frame start */ else if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] | cdata[4] | cdata[5] | cdata[6] | cdata[7]) == 0 && (cdata[8] & 8)) {#if 0 PDEBUG("ov511: Found Frame Start!, packnum = %d\n", (int)(cdata[992])); PDEBUG("ov511: Frame Header Byte = 0x%x\n", (int)(cdata[8]));#endif frame->scanstate = STATE_LINES; frame->segment = 0; } /* Are we in a frame? */ if (frame->scanstate == STATE_LINES) { unsigned char * pData; int iPix; /* Deal with leftover from last segment, if any */ if (frame->segment) { pData = ov511->scratch; iPix = - ov511->scratchlen; memmove(pData + ov511->scratchlen, cdata, iPix+384); } else { pData = &cdata[iPix = 9]; } /* Parse the segments */ while(iPix <= 992 - 384 && frame->segment < frame->width * frame->height / 256) { ov511_parse_data(pData, frame->data, frame->width, frame->segment); frame->segment++; iPix += 384; pData = &cdata[iPix]; } /* Save extra data for next time */ if (frame->segment < frame->width * frame->height / 256) { memmove(ov511->scratch, pData, 992 - iPix); ov511->scratchlen = 992 - iPix; } } }#if 0 PDEBUG("pn: %d %d %d %d %d %d %d %d %d %d\n", aPackNum[0], aPackNum[1], aPackNum[2], aPackNum[3], aPackNum[4], aPackNum[5],aPackNum[6], aPackNum[7], aPackNum[8], aPackNum[9]);#endif return totlen;}static void ov511_isoc_irq(struct urb *urb){ int len; struct usb_ov511 *ov511 = urb->context; struct ov511_sbuf *sbuf; int i; if (!ov511->streaming) { PDEBUG("hmmm... not streaming, but got interrupt\n"); return; } sbuf = &ov511->sbuf[ov511->cursbuf]; /* Copy the data received into our scratch buffer */ if (ov511->curframe >= 0) { len = ov511_move_data(ov511, urb); } for (i = 0; i < FRAMES_PER_DESC; i++) { sbuf->urb->iso_frame_desc[i].status = 0; sbuf->urb->iso_frame_desc[i].actual_length = 0; } /* Move to the next sbuf */ ov511->cursbuf = (ov511->cursbuf + 1) % OV511_NUMSBUF; return;}static int ov511_init_isoc(struct usb_ov511 *ov511){ struct usb_device *dev = ov511->dev; urb_t *urb; int fx, err; ov511->compress = 0; ov511->curframe = -1; ov511->cursbuf = 0; ov511->scratchlen = 0; ov511_set_packet_size(ov511, 993); /* We double buffer the Iso lists */ urb = usb_alloc_urb(FRAMES_PER_DESC); if (!urb) { printk(KERN_ERR "ov511_init_isoc: usb_alloc_urb ret. NULL\n"); return -ENOMEM; } ov511->sbuf[0].urb = urb; urb->dev = dev; urb->context = ov511; urb->pipe = usb_rcvisocpipe(dev, OV511_ENDPOINT_ADDRESS); urb->transfer_flags = USB_ISO_ASAP; urb->transfer_buffer = ov511->sbuf[0].data; urb->complete = ov511_isoc_irq; urb->number_of_packets = FRAMES_PER_DESC; urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; for (fx = 0; fx < FRAMES_PER_DESC; fx++) { urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx; urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; } urb = usb_alloc_urb(FRAMES_PER_DESC); if (!urb) { printk(KERN_ERR "ov511_init_isoc: usb_alloc_urb ret. NULL\n"); return -ENOMEM; } ov511->sbuf[1].urb = urb; urb->dev = dev; urb->context = ov511; urb->pipe = usb_rcvisocpipe(dev, OV511_ENDPOINT_ADDRESS); urb->transfer_flags = USB_ISO_ASAP; urb->transfer_buffer = ov511->sbuf[1].data; urb->complete = ov511_isoc_irq; urb->number_of_packets = FRAMES_PER_DESC; urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; for (fx = 0; fx < FRAMES_PER_DESC; fx++) { urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx; urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; } ov511->sbuf[1].urb->next = ov511->sbuf[0].urb; ov511->sbuf[0].urb->next = ov511->sbuf[1].urb; err = usb_submit_urb(ov511->sbuf[0].urb); if (err) printk(KERN_ERR "ov511_init_isoc: usb_run_isoc(0) ret %d\n", err); err = usb_submit_urb(ov511->sbuf[1].urb); if (err) printk(KERN_ERR "ov511_init_isoc: usb_run_isoc(1) ret %d\n", err); ov511->streaming = 1; return 0;}static void ov511_stop_isoc(struct usb_ov511 *ov511){ if (!ov511->streaming) return; ov511_set_packet_size(ov511, 0); /* Unschedule all of the iso td's */ usb_unlink_urb(ov511->sbuf[1].urb); usb_unlink_urb(ov511->sbuf[0].urb); ov511->streaming = 0; /* Delete them all */ usb_free_urb(ov511->sbuf[1].urb); usb_free_urb(ov511->sbuf[0].urb);}static int ov511_new_frame(struct usb_ov511 *ov511, int framenum){ struct ov511_frame *frame; int width, height; /* If we're not grabbing a frame right now and the other frame is */ /* ready to be grabbed into, then use it instead */ if (ov511->curframe == -1) { if (ov511->frame[(framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES].grabstate == FRAME_READY) framenum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES; } else return 0; frame = &ov511->frame[framenum]; width = frame->width; height = frame->height; frame->grabstate = FRAME_GRABBING; frame->scanstate = STATE_SCANNING; frame->scanlength = 0; /* accumulated in ov511_parse_data() */ ov511->curframe = framenum; /* Make sure it's not too big */ if (width > DEFAULT_WIDTH) width = DEFAULT_WIDTH; width = (width / 8) * 8; /* Multiple of 8 */ if (height > DEFAULT_HEIGHT) height = DEFAULT_HEIGHT; height = (height / 4) * 4; /* Multiple of 4 */ // /* We want a fresh frame every 30 we get */// ov511->compress = (ov511->compress + 1) % 30; return 0;}/* Video 4 Linux API */static int ov511_open(struct video_device *dev, int flags){ int err = -EBUSY; struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; PDEBUG("ov511_open\n"); down(&ov511->lock); if (ov511->user) goto out_unlock; ov511->frame[0].grabstate = FRAME_UNUSED; ov511->frame[1].grabstate = FRAME_UNUSED; err = -ENOMEM; /* Allocate memory for the frame buffers */ ov511->fbuf = rvmalloc(2 * MAX_FRAME_SIZE); if (!ov511->fbuf) goto open_err_ret; ov511->frame[0].data = ov511->fbuf; ov511->frame[1].data = ov511->fbuf + MAX_FRAME_SIZE; PDEBUG("frame [0] @ %p\n", ov511->frame[0].data); PDEBUG("frame [1] @ %p\n", ov511->frame[1].data); ov511->sbuf[0].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); if (!ov511->sbuf[0].data) goto open_err_on0; ov511->sbuf[1].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); if (!ov511->sbuf[1].data) goto open_err_on1; PDEBUG("sbuf[0] @ %p\n", ov511->sbuf[0].data); PDEBUG("sbuf[1] @ %p\n", ov511->sbuf[1].data); err = ov511_init_isoc(ov511); if (err) goto open_err_on2; ov511->user++; up(&ov511->lock); MOD_INC_USE_COUNT; return 0;open_err_on2: kfree (ov511->sbuf[1].data);open_err_on1: kfree (ov511->sbuf[0].data);open_err_on0: rvfree(ov511->fbuf, 2 * MAX_FRAME_SIZE);open_err_ret: return err;out_unlock: up(&ov511->lock); return err;}static void ov511_close(struct video_device *dev){ struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; PDEBUG("ov511_close\n"); down(&ov511->lock); ov511->user--; MOD_DEC_USE_COUNT; ov511_stop_isoc(ov511); rvfree(ov511->fbuf, 2 * MAX_FRAME_SIZE); kfree(ov511->sbuf[1].data); kfree(ov511->sbuf[0].data); up(&ov511->lock);}static int ov511_init_done(struct video_device *dev){ return 0;}static long ov511_write(struct video_device *dev, const char *buf, unsigned long count, int noblock){ return -EINVAL;}// FIXME - Needs much work!!!static int ov511_ioctl(struct video_device *dev, unsigned int cmd, void *arg){ struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;#if 0 PDEBUG("IOCtl: 0x%X\n", cmd);#endif switch (cmd) { case VIDIOCGCAP: { struct video_capability b; strcpy(b.name, "OV511 USB Camera"); b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE; b.channels = 1; b.audios = 0; b.maxwidth = DEFAULT_WIDTH; b.maxheight = DEFAULT_HEIGHT; b.minwidth = 8; b.minheight = 4; if (copy_to_user(arg, &b, sizeof(b))) return -EFAULT; return 0; } case VIDIOCGCHAN: { struct video_channel v; if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; if (v.channel != 0) return -EINVAL; v.flags = 0; v.tuners = 0; v.type = VIDEO_TYPE_CAMERA; strcpy(v.name, "Camera"); if (copy_to_user(arg, &v, sizeof(v))) return -EFAULT; return 0; } case VIDIOCSCHAN: { int v; if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; if (v != 0) return -EINVAL; return 0; } case VIDIOCGPICT: { struct video_picture p;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -