📄 ibmcam.c
字号:
/* * The purpose of creating the pixel here, in one, * dedicated place is that we may need to make the * pixel wider and taller than it actually is. This * may be used if camera generates small frames for * sake of frame rate (or any other reason.) * * The output data consists of B, G, R bytes * (in this order). */#if USES_IBMCAM_PUTPIXEL IBMCAM_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);#else *f++ = bv; *f++ = gv; *f++ = rv;#endif /* * Typically we do not decide within a legitimate frame * that we want to end the frame. However debugging code * may detect marker of new frame within the data. Then * this condition activates. The 'data' pointer is already * pointing at the new marker, so we'd better leave it as is. */ if (frame_done) break; /* End scanning of lines */ } /* * Account for number of bytes that we wrote into output V4L frame. * We do it here, after we are done with the scanline, because we * may fill more than one output scanline if we do vertical * enlargement. */ frame->curline++; *pcopylen += v4l_linesize; usb_ibmcam_align_scratch(ibmcam, data); if (frame_done || (frame->curline >= frame->frmheight)) return scan_NextFrame; else return scan_Continue;}/* * usb_ibmcam_model2_parse_lines() * * This procedure deals with a weird RGB format that is produced by IBM * camera model 2 in modes 320x240 and above; 'x' below is 159 or 175, * depending on horizontal size of the picture: * * <--- 160 or 176 pairs of RA,RB bytes -----> * *-----------------------------------------* \ * | RA0 | RB0 | RA1 | RB1 | ... | RAx | RBx | \ * |-----+-----+-----+-----+ ... +-----+-----| *- This is pair of horizontal lines, * | B0 | G0 | B1 | G1 | ... | Bx | Gx | / total 240 or 288 lines (120 or 144 * |=====+=====+=====+=====+ ... +=====+=====| / such pairs). * * Each group of FOUR bytes (RAi, RBi, Bi, Gi) where i=0..frame_width/2-1 * defines ONE pixel. Therefore this format yields 176x144 "decoded" * resolution at best. I do not know why camera sends such format - the * previous model just used I420 and everyone was happy. * * I do not know what is the difference between RAi and RBi bytes. Both * seemingly represent R component, but slightly vary in value (so that * the picture looks a bit colored if one or another is used). I use * them both as R component in attempt to at least partially recover the * lost resolution. */static scan_state_t usb_ibmcam_model2_parse_lines(struct usb_ibmcam *ibmcam, long *pcopylen){ struct ibmcam_frame *frame; unsigned char *data, *f, *la, *lb; unsigned int len; const int v4l_linesize = imgwidth * V4L_BYTES_PER_PIXEL; /* V4L line offset */ int i, j, frame_done=0, color_corr; color_corr = (ibmcam->vpic.colour) >> 8; /* 0..+255 */ data = ibmcam->scratch; frame = &ibmcam->frame[ibmcam->curframe]; /* Here we deal with pairs of horizontal lines */ len = frame->frmwidth * 2; /* 2 lines */ /*printk(KERN_DEBUG "len=%d. left=%d.\n",len,scratch_left(data));*/ /* Make sure there's enough data for the entire line */ if (scratch_left(data) < (len+32)) { /*printk(KERN_DEBUG "out of data, need %u.\n", len);*/ return scan_Out; } /* * Make sure that our writing into output buffer * will not exceed the buffer. Mind that we may write * not into current output scanline but in several after * it as well (if we enlarge image vertically.) */ if ((frame->curline + 1) >= V4L_FRAME_HEIGHT) return scan_NextFrame; if ((frame->curline & 1) == 0) { la = data; lb = data + frame->frmwidth; } else { la = data + frame->frmwidth; lb = data; } /* * Now we are sure that entire line (representing all 'frame->frmwidth' * pixels from the camera) is available in the scratch buffer. We * start copying the line left-aligned to the V4L buffer (which * might be larger - not smaller, hopefully). If the camera * line is shorter then we should pad the V4L buffer with something * (black in this case) to complete the line. */ f = frame->data + (v4l_linesize * frame->curline); /* Fill the 2-line strip */ for (i = 0; i < frame->frmwidth; i++) { int y, rv, gv, bv; /* RGB components */ j = i & (~1); /* Check for various visual debugging hints (colorized pixels) */ if ((flags & FLAGS_DISPLAY_HINTS) && (ibmcam->has_hdr)) { if (ibmcam->has_hdr == 1) { bv = 0; /* Yellow marker */ gv = 0xFF; rv = 0xFF; } else { bv = 0xFF; /* Cyan marker */ gv = 0xFF; rv = 0; } ibmcam->has_hdr = 0; goto make_pixel; } /* * Here I use RA and RB components, one per physical pixel. * This causes fine vertical grid on the picture but may improve * horizontal resolution. If you prefer replicating, use this: * rv = la[j + 0]; ... or ... rv = la[j + 1]; * then the pixel will be replicated. */ rv = la[i]; gv = lb[j + 1]; bv = lb[j + 0]; y = (rv + gv + bv) / 3; /* Brightness (badly calculated) */ if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */ rv = gv = bv = y; else if (color_corr != 128) { /* Calculate difference between color and brightness */ rv -= y; gv -= y; bv -= y; /* Scale differences */ rv = (rv * color_corr) / 128; gv = (gv * color_corr) / 128; bv = (bv * color_corr) / 128; /* Reapply brightness */ rv += y; gv += y; bv += y; /* Watch for overflows */ RESTRICT_TO_RANGE(rv, 0, 255); RESTRICT_TO_RANGE(gv, 0, 255); RESTRICT_TO_RANGE(bv, 0, 255); } make_pixel: IBMCAM_PUTPIXEL(frame, i, frame->curline, rv, gv, bv); IBMCAM_PUTPIXEL(frame, i, frame->curline+1, rv, gv, bv); } /* * Account for number of bytes that we wrote into output V4L frame. * We do it here, after we are done with the scanline, because we * may fill more than one output scanline if we do vertical * enlargement. */ frame->curline += 2; *pcopylen += v4l_linesize * 2; data += frame->frmwidth * 2; usb_ibmcam_align_scratch(ibmcam, data); if (frame_done || (frame->curline >= frame->frmheight)) return scan_NextFrame; else return scan_Continue;}/* * ibmcam_parse_data() * * Generic routine to parse the scratch buffer. It employs either * usb_ibmcam_find_header() or usb_ibmcam_parse_lines() to do most * of work. * * History: * 1/21/00 Created. */static void ibmcam_parse_data(struct usb_ibmcam *ibmcam){ struct ibmcam_frame *frame; unsigned char *data = ibmcam->scratch; scan_state_t newstate; long copylen = 0; /* Grab the current frame and the previous frame */ frame = &ibmcam->frame[ibmcam->curframe]; /* printk(KERN_DEBUG "parsing %u.\n", ibmcam->scratchlen); */ while (1) { newstate = scan_Out; if (scratch_left(data)) { if (frame->scanstate == STATE_SCANNING) newstate = usb_ibmcam_find_header(ibmcam); else if (frame->scanstate == STATE_LINES) { if ((ibmcam->camera_model == IBMCAM_MODEL_2) && (videosize >= VIDEOSIZE_352x288)) { newstate = usb_ibmcam_model2_parse_lines(ibmcam, ©len); } else { newstate = usb_ibmcam_parse_lines(ibmcam, ©len); } } } if (newstate == scan_Continue) continue; else if ((newstate == scan_NextFrame) || (newstate == scan_Out)) break; else return; /* scan_EndParse */ } if (newstate == scan_NextFrame) { frame->grabstate = FRAME_DONE; ibmcam->curframe = -1; ibmcam->frame_num++; /* Optionally display statistics on the screen */ if (flags & FLAGS_OVERLAY_STATS) usb_ibmcam_overlaystats(ibmcam, frame); /* This will cause the process to request another frame. */ if (waitqueue_active(&frame->wq)) wake_up_interruptible(&frame->wq); } /* Update the frame's uncompressed length. */ frame->scanlength += copylen;}/* * Make all of the blocks of data contiguous */static int ibmcam_compress_isochronous(struct usb_ibmcam *ibmcam, urb_t *urb){ unsigned char *cdata, *data, *data0; int i, totlen = 0; data = data0 = ibmcam->scratch + ibmcam->scratchlen; 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; /* Detect and ignore errored packets */ if (st < 0) { if (debug >= 1) { printk(KERN_ERR "ibmcam data error: [%d] len=%d, status=%X\n", i, n, st); } ibmcam->iso_err_count++; continue; } /* Detect and ignore empty packets */ if (n <= 0) { ibmcam->iso_skip_count++; continue; } /* * If camera continues to feed us with data but there is no * consumption (if, for example, V4L client fell asleep) we * may overflow the buffer. We have to move old data over to * free room for new data. This is bad for old data. If we * just drop new data then it's bad for new data... choose * your favorite evil here. */ if ((ibmcam->scratchlen + n) > scratchbufsize) {#if 0 ibmcam->scratch_ovf_count++; if (debug >= 3) printk(KERN_ERR "ibmcam: scratch buf overflow! " "scr_len: %d, n: %d\n", ibmcam->scratchlen, n ); return totlen;#else int mv; ibmcam->scratch_ovf_count++; if (debug >= 3) { printk(KERN_ERR "ibmcam: scratch buf overflow! " "scr_len: %d, n: %d\n", ibmcam->scratchlen, n ); } mv = (ibmcam->scratchlen + n) - scratchbufsize; if (ibmcam->scratchlen >= mv) { int newslen = ibmcam->scratchlen - mv; memmove(ibmcam->scratch, ibmcam->scratch + mv, newslen); ibmcam->scratchlen = newslen; data = data0 = ibmcam->scratch + ibmcam->scratchlen; } else { printk(KERN_ERR "ibmcam: scratch buf too small\n"); return totlen; }#endif } /* Now we know that there is enough room in scratch buffer */ memmove(data, cdata, n); data += n; totlen += n; ibmcam->scratchlen += n; }#if 0 if (totlen > 0) { static int foo=0; if (foo < 1) { printk(KERN_DEBUG "+%d.\n", totlen); ibmcam_hexdump(data0, (totlen > 64) ? 64:totlen); ++foo; } }#endif return totlen;}static void ibmcam_isoc_irq(struct urb *urb){ int len; struct usb_ibmcam *ibmcam = urb->context; struct ibmcam_sbuf *sbuf; int i; /* We don't want to do anything if we are about to be removed! */ if (!IBMCAM_IS_OPERATIONAL(ibmcam)) return;#if 0 if (urb->actual_length > 0) { printk(KERN_DEBUG "ibmcam_isoc_irq: %p status %d, " " errcount = %d, length = %d\n", urb, urb->status, urb->error_count, urb->actual_length); } else { static int c = 0; if (c++ % 100 == 0) printk(KERN_DEBUG "ibmcam_isoc_irq: no data\n"); }#endif if (!ibmcam->streaming) { if (debug >= 1) printk(KERN_DEBUG "ibmcam: oops, not streaming, but interrupt\n"); return; } sbuf = &ibmcam->sbuf[ibmcam->cursbuf]; /* Copy the data received into our scratch buffer */ len = ibmcam_compress_isochronous(ibmcam, urb); ibmcam->urb_count++; ibmcam->urb_length = len; ibmcam->data_count += len;#if 0 /* This code prints few initial bytes of ISO data: used to decode markers */ if (ibmcam->urb_count % 64 == 1) { if (ibmcam->urb_count == 1) { ibmcam_hexdump(ibmcam->scratch, (ibmcam->scratchlen > 32) ? 32 : ibmcam->scratchlen); } }#endif /* If we collected enough data let's parse! */ if (ibmcam->scratchlen) { /* If we don't have a frame we're current working on, complain */ if (ibmcam->curframe >= 0) ibmcam_parse_data(ibmcam); else { if (debug >= 1) printk(KERN_DEBUG "ibmcam: received data, but no frame available\n"); } } 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 */ ibmcam->cursbuf = (ibmcam->cursbuf + 1) % IBMCAM_NUMSBUF; return;}/* * usb_ibmcam_veio() * * History: * 1/27/00 Added check for dev == NULL; this happens if camera is unplugged. */static int usb_ibmcam_veio( struct usb_ibmcam *ibmcam, unsigned char req, unsigned short value, unsigned short index){ static const char proc[] = "usb_ibmcam_veio";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -