📄 ov511.c
字号:
for (l = 0; l < 8; l++) { *pOut1 = *(pOut1 + w) = *pIn++; pOut1++; } pOut += iWidth; } pIn = pIn0 + 64; pOut = pOut0 + iOutUV + a + a/2; for (k = 0; k < 8; k++) { pOut1 = pOut; for (l = 0; l < 8; l++) { *pOut1 = *(pOut1 + w) = *pIn++; pOut1++; } pOut += iWidth; } 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 += iWidth - 8; } pOut += 8; }}/* * For 640x480 RAW BW images, data shows up in 1200 256 byte segments. * The segments represent 4 squares of 8x8 pixels as follows: * * 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 ... 255 * */ static voidov511_parse_data_grey(unsigned char *pIn0, unsigned char *pOut0, int iOutY, int iWidth) { int k, l, m; unsigned char *pIn; unsigned char *pOut, *pOut1; pIn = pIn0; 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 += iWidth - 8; } pOut += 8; }}/* * fixFrameRGBoffset-- * My camera seems to return the red channel about 1 pixel * low, and the blue channel about 1 pixel high. After YUV->RGB * conversion, we can correct this easily. OSL 2/24/2000. */static void fixFrameRGBoffset(struct ov511_frame *frame){ int x, y; int rowBytes = frame->width*3, w = frame->width; unsigned char *rgb = frame->data; const int shift = 1; /* Distance to shift pixels by, vertically */ /* Don't bother with little images */ if (frame->width < 400) return; /* Shift red channel up */ for (y = shift; y < frame->height; y++) { int lp = (y-shift)*rowBytes; /* Previous line offset */ int lc = y*rowBytes; /* Current line offset */ for (x = 0; x < w; x++) rgb[lp+x*3+2] = rgb[lc+x*3+2]; /* Shift red up */ } /* Shift blue channel down */ for (y = frame->height-shift-1; y >= 0; y--) { int ln = (y + shift) * rowBytes; /* Next line offset */ int lc = y * rowBytes; /* Current line offset */ for (x = 0; x < w; x++) rgb[ln+x*3+0] = rgb[lc+x*3+0]; /* Shift blue down */ }}/********************************************************************** * * OV511 data transfer, IRQ handler * **********************************************************************/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; unsigned char *pData; int iPix; PDEBUG (4, "Moving %d packets", urb->number_of_packets); 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; urb->iso_frame_desc[i].actual_length = 0; urb->iso_frame_desc[i].status = 0; cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; aPackNum[i] = n ? cdata[ov511->packet_size - 1] : -1; if (!n || ov511->curframe == -1) continue; if (st) PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st); frame = &ov511->frame[ov511->curframe]; /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th * byte non-zero. The EOF packet has image width/height in the * 10th and 11th packets. The 9th bit is given as follows: * * bit 7: EOF * 6: compression enabled * 5: 422/420/400 modes * 4: 422/420/400 modes * 3: 1 * 2: snapshot bottom on * 1: snapshot frame * 0: even/odd field */ /* Check for SOF/EOF packet */ if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] | cdata[4] | cdata[5] | cdata[6] | cdata[7]) || (~cdata[8] & 0x08)) goto check_middle; /* Frame end */ if (cdata[8] & 0x80) { struct timeval *ts; ts = (struct timeval *)(frame->data + MAX_FRAME_SIZE); do_gettimeofday (ts); PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d", ov511->curframe, (int)(cdata[ov511->packet_size - 1]), (int)(cdata[9]), (int)(cdata[10])); if (frame->scanstate == STATE_LINES) { int iFrameNext; if (fix_rgb_offset) fixFrameRGBoffset(frame); frame->grabstate = FRAME_DONE; if (waitqueue_active(&frame->wq)) { frame->grabstate = FRAME_DONE; wake_up_interruptible(&frame->wq); } /* If next frame is ready or grabbing, * point to it */ iFrameNext = (ov511->curframe + 1) % OV511_NUMFRAMES; if (ov511->frame[iFrameNext].grabstate == FRAME_READY || ov511->frame[iFrameNext].grabstate == FRAME_GRABBING) { ov511->curframe = iFrameNext; ov511->frame[iFrameNext].scanstate = STATE_SCANNING; } else { if (frame->grabstate == FRAME_DONE) { PDEBUG(4, "Frame done! congratulations"); } else { PDEBUG(4, "Frame not ready? state = %d", ov511->frame[iFrameNext].grabstate); } ov511->curframe = -1; } } /* Image corruption caused by misplaced frame->segment = 0 * fixed by carlosf@conectiva.com.br */ } else { /* Frame start */ PDEBUG(4, "Frame start, framenum = %d", ov511->curframe);#if 0 /* Make sure no previous data carries over; necessary * for compression experimentation */ memset(frame->data, 0, MAX_DATA_SIZE);#endif output_offset = 0; /* Check to see if it's a snapshot frame */ /* FIXME?? Should the snapshot reset go here? Performance? */ if (cdata[8] & 0x02) { frame->snapshot = 1; PDEBUG(3, "snapshot detected"); } frame->scanstate = STATE_LINES; frame->segment = 0; }check_middle: /* Are we in a frame? */ if (frame->scanstate != STATE_LINES) continue; /* Deal with leftover from last segment, if any */ if (frame->segment) { pData = ov511->scratch; iPix = -ov511->scratchlen; memmove(pData + ov511->scratchlen, cdata, iPix+frame->segsize); } else { pData = &cdata[iPix = 9]; } /* Parse the segments */ while (iPix <= (ov511->packet_size - 1) - frame->segsize && frame->segment < frame->width * frame->height / 256) { int iSegY, iSegUV; int iY, jY, iUV, jUV; int iOutY, iOutYP, iOutUV, iOutUVP; unsigned char *pOut; iSegY = iSegUV = frame->segment; pOut = frame->data; frame->segment++; iPix += frame->segsize; /* Handle subwindow */ if (frame->sub_flag) { int iSeg1; iSeg1 = iSegY / (ov511->subw / 32); iSeg1 *= frame->width / 32; iSegY = iSeg1 + (iSegY % (ov511->subw / 32)); if (iSegY >= frame->width * ov511->subh / 256) break; iSeg1 = iSegUV / (ov511->subw / 16); iSeg1 *= frame->width / 16; iSegUV = iSeg1 + (iSegUV % (ov511->subw / 16)); pOut += (ov511->subx + ov511->suby * frame->width) * (frame->depth >> 3); } /* * i counts segment lines * j counts segment columns * iOut is the offset (in bytes) of the upper left corner */ iY = iSegY / (frame->width / WDIV); jY = iSegY - iY * (frame->width / WDIV); iOutYP = iY*HDIV*frame->width + jY*WDIV; iOutY = iOutYP * (frame->depth >> 3); iUV = iSegUV / (frame->width / WDIV * 2); jUV = iSegUV - iUV * (frame->width / WDIV * 2); iOutUVP = iUV*HDIV*2*frame->width + jUV*WDIV/2; iOutUV = iOutUVP * (frame->depth >> 3); switch (frame->format) { case VIDEO_PALETTE_GREY: ov511_parse_data_grey (pData, pOut, iOutY, frame->width); break; case VIDEO_PALETTE_RGB24: if (dumppix) ov511_dumppix(pData, pOut, iOutY, iOutUV, iY & 1, frame->width); else if (sensor_gbr) ov511_parse_gbr422_to_rgb24(pData, pOut, iOutY, iOutUV, iY & 1, frame->width); else ov511_parse_yuv420_to_rgb(pData, pOut, iOutY, iOutUV, iY & 1, frame->width, 24); break; case VIDEO_PALETTE_RGB565: ov511_parse_yuv420_to_rgb(pData, pOut, iOutY, iOutUV, iY & 1, frame->width, 16); break; case VIDEO_PALETTE_YUV422: case VIDEO_PALETTE_YUYV: ov511_parse_data_yuv422(pData, pOut, iOutY, iOutUV, frame->width); break; case VIDEO_PALETTE_YUV420: ov511_parse_data_yuv420 (pData, pOut, iOutYP, iUV*HDIV*frame->width/2 + jUV*WDIV/4, frame->width, frame->height); break; case VIDEO_PALETTE_YUV422P: ov511_parse_data_yuv422p (pData, pOut, iOutYP, iOutUVP/2, frame->width, frame->height); break; default: err("Unsupported format: %d", frame->format); } pData = &cdata[iPix]; } /* Save extra data for next time */ if (frame->segment < frame->width * frame->height / 256) { ov511->scratchlen = (ov511->packet_size - 1) - iPix; if (ov511->scratchlen < frame->segsize) memmove(ov511->scratch, pData, ov511->scratchlen); else ov511->scratchlen = 0; } } PDEBUG(5, "pn: %d %d %d %d %d %d %d %d %d %d", aPackNum[0], aPackNum[1], aPackNum[2], aPackNum[3], aPackNum[4], aPackNum[5],aPackNum[6], aPackNum[7], aPackNum[8], aPackNum[9]); return totlen;}static void ov511_isoc_irq(struct urb *urb){ int len; struct usb_ov511 *ov511; struct ov511_sbuf *sbuf; if (!urb->context) { PDEBUG(4, "no context"); return; } ov511 = (struct usb_ov511 *) urb->context; if (!ov511->dev || !ov511->user) { PDEBUG(4, "no device, or not open"); return; } if (!ov511->streaming) { PDEBUG(4, "hmmm... not streaming, but got interrupt"); return; } sbuf = &ov511->sbuf[ov511->cursbuf]; /* Copy the data received into our scratch buffer */ if (ov511->curframe >= 0) { len = ov511_move_data(ov511, urb); } else if (waitqueue_active(&ov511->wq)) { wake_up_interruptible(&ov511->wq); } /* Move to the next sbuf */ ov511->cursbuf = (ov511->cursbuf + 1) % OV511_NUMSBUF; urb->dev = ov511->dev; return;}static int ov511_init_isoc(struct usb_ov511 *ov511){ urb_t *urb; int fx, err, n, size; PDEBUG(3, "*** Initializing capture ***"); ov511->compress = 0; ov511->curframe = -1; ov511->cursbuf = 0; ov511->scratchlen = 0; if (ov511->bridge == BRG_OV511) if (cams == 1) size = 993; else if (cams == 2) size = 513; else if (cams == 3 || cams == 4) size = 257; else { err("\"cams\" parameter too high!"); return -1; } else if (ov511->bridge == BRG_OV511PLUS) if (cams == 1) size = 961; else if (cams == 2) size = 513; else if (cams == 3 || cams == 4) size = 257; else if (cams >= 5 && cams <= 8) size = 129; else if (cams >= 9 && cams <= 31) size = 33; else { err("\"cams\" parameter too high!"); return -1; } else { err("invalid bridge type"); return -1; } ov511_set_packet_size(ov511, size); for (n = 0; n < OV511_NUMSBUF; n++) { urb = usb_alloc_urb(FRAMES_PER_DESC); if (!urb) { err("init isoc: usb_alloc_urb ret. NULL"); return -ENOMEM; } ov511->sbuf[n].urb = urb; urb->dev = ov511->dev; urb->context = ov511; urb->pipe = usb_rcvisocpipe(ov511->dev, OV511_ENDPOINT_ADDRESS); urb->transfer_flags = USB_ISO_ASAP; urb->transfer_buffer = ov511->sbuf[n].data; urb->complete = ov511_isoc_irq; urb->number_of_packets = FRAMES_PER_DESC; urb->transfer_buffer_length = ov511->packet_size * FRAMES_PER_DESC; for (fx = 0; fx < FRAMES_PER_DESC; fx++) { urb->iso_frame_desc[fx].offset = ov511->packet_size * fx; urb->iso_frame_desc[fx].length = ov511->packet_size; } } ov511->sbuf[OV511_NUMSBUF - 1].urb->next = ov511->sbuf[0].urb; for (n = 0; n < OV511_NUMSBUF - 1; n++) ov511->sbuf[n].urb->next = ov511->sbuf[n+1].urb; for (n = 0; n < OV511_NUMSBUF; n++) { ov511->sbuf[n].urb->dev = ov511->dev; err = usb_submit_urb(ov511->sbuf[n].urb); if (err) err("init isoc: usb_submit_urb(%d) ret %d", n, err); } ov511->streaming = 1; return 0;}static void ov511_stop_isoc(struct usb_ov511 *ov511){ int n; if (!ov511->streaming || !ov511->dev) return; PDEBUG (3, "*** Stopping capture ***"); ov511_set_packet_size(ov511, 0); ov511->streaming = 0; /* Unschedule all of the iso td's */ for (n = OV511_NUMSBUF - 1; n >= 0; n--) { if (ov511->sbuf[n].urb) { ov511->sbuf[n].urb->next = NULL; usb_unlink_urb(ov511->sbuf[n].urb); usb_free_urb(ov511->sbuf[n].urb); ov511->sbuf[n].urb = NULL; } }}static int ov511_new_frame(struct usb_ov511 *ov511, int framenum){ struct ov511_frame *frame; PDEBUG(4, "ov511->curframe = %d, framenum = %d", ov511->curframe, framenum); if (!ov511->dev) return -1; /* 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]; PDEBUG (4, "framenum = %d, width = %d, height = %d", framenum, frame->width, frame->height); frame->grabstate = FRAME_GRABBING; frame->scanstate = STATE_SCANNING; frame->scanlength = 0; /* accumulated in ov511_parse_data() */ frame->snapshot = 0; ov511->curframe = framenum; /* Make sure it's not too big */ if (frame->width > ov511->maxwidth) frame->width = ov511->maxwidth;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -