📄 ov511 v1.28.c
字号:
/* Calculate and set the clock divisor */ clock = ((sub_flag ? ov511->subw * ov511->subh : width * height) * (mlist[i].color ? 3 : 2) / 2) / 66000;#if 0 clock *= cams;#endif ov511_i2c_write(dev, 0x11, clock); /* We only have code to convert GBR -> RGB24 */ if ((mode == VIDEO_PALETTE_RGB24) && sensor_gbr) ov511_i2c_write(dev, 0x12, mlist[i].common_A | (testpat?0x0a:0x08)); else ov511_i2c_write(dev, 0x12, mlist[i].common_A | (testpat?0x02:0x00)); /* 7620/6620 don't have register 0x35, so play it safe */ if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV7620AE) ov511_i2c_write(dev, 0x35, mlist[i].common_L); break; } if (compress) { ov511_reg_write(dev, 0x78, 0x03); // Turn on Y compression ov511_reg_write(dev, 0x79, 0x00); // Disable LUTs } if (ov511_restart(ov511->dev) < 0) return -EIO; if (mlist[i].width == 0) { err("Unknown mode (%d, %d): %d", width, height, mode); return -EINVAL; }#ifdef OV511_DEBUG if (debug >= 5) ov511_dump_i2c_regs(dev);#endif return 0;}/********************************************************************** * * Color correction functions * **********************************************************************//* * Turn a YUV4:2:0 block into an RGB block * * Video4Linux seems to use the blue, green, red channel * order convention-- rgb[0] is blue, rgb[1] is green, rgb[2] is red. * * Color space conversion coefficients taken from the excellent * http://www.inforamp.net/~poynton/ColorFAQ.html * In his terminology, this is a CCIR 601.1 YCbCr -> RGB. * Y values are given for all 4 pixels, but the U (Pb) * and V (Pr) are assumed constant over the 2x2 block. * * To avoid floating point arithmetic, the color conversion * coefficients are scaled into 16.16 fixed-point integers. * They were determined as follows: * * double brightness = 1.0; (0->black; 1->full scale) * double saturation = 1.0; (0->greyscale; 1->full color) * double fixScale = brightness * 256 * 256; * int rvScale = (int)(1.402 * saturation * fixScale); * int guScale = (int)(-0.344136 * saturation * fixScale); * int gvScale = (int)(-0.714136 * saturation * fixScale); * int buScale = (int)(1.772 * saturation * fixScale); * int yScale = (int)(fixScale); *//* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */#define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))static inline voidov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, int rowPixels, unsigned char * rgb, int bits){ const int rvScale = 91881; const int guScale = -22553; const int gvScale = -46801; const int buScale = 116129; const int yScale = 65536; int r, g, b; g = guScale * u + gvScale * v; if (force_rgb) { r = buScale * u; b = rvScale * v; } else { r = rvScale * v; b = buScale * u; } yTL *= yScale; yTR *= yScale; yBL *= yScale; yBR *= yScale; if (bits == 24) { /* Write out top two pixels */ rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL); rgb[2] = LIMIT(r+yTL); rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR); rgb[5] = LIMIT(r+yTR); /* Skip down to next line to write out bottom two pixels */ rgb += 3 * rowPixels; rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL); rgb[2] = LIMIT(r+yBL); rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR); rgb[5] = LIMIT(r+yBR); } else if (bits == 16) { /* Write out top two pixels */ rgb[0] = ((LIMIT(b+yTL) >> 3) & 0x1F) | ((LIMIT(g+yTL) << 3) & 0xE0); rgb[1] = ((LIMIT(g+yTL) >> 5) & 0x07) | (LIMIT(r+yTL) & 0xF8); rgb[2] = ((LIMIT(b+yTR) >> 3) & 0x1F) | ((LIMIT(g+yTR) << 3) & 0xE0); rgb[3] = ((LIMIT(g+yTR) >> 5) & 0x07) | (LIMIT(r+yTR) & 0xF8); /* Skip down to next line to write out bottom two pixels */ rgb += 2 * rowPixels; rgb[0] = ((LIMIT(b+yBL) >> 3) & 0x1F) | ((LIMIT(g+yBL) << 3) & 0xE0); rgb[1] = ((LIMIT(g+yBL) >> 5) & 0x07) | (LIMIT(r+yBL) & 0xF8); rgb[2] = ((LIMIT(b+yBR) >> 3) & 0x1F) | ((LIMIT(g+yBR) << 3) & 0xE0); rgb[3] = ((LIMIT(g+yBR) >> 5) & 0x07) | (LIMIT(r+yBR) & 0xF8); }}/* * For a 640x480 YUV4:2:0 images, data shows up in 1200 384 byte segments. * The first 64 bytes of each segment are U, the next 64 are V. The U and * V are arranged as follows: * * 0 1 ... 7 * 8 9 ... 15 * ... * 56 57 ... 63 * * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block). * * The next 256 bytes are full resolution Y data and 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 * * Note that the U and V data in one segment represents a 16 x 16 pixel * area, but the Y data represents a 32 x 8 pixel area. * * If dumppix module param is set, _parse_data just dumps the incoming segments, * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480 * this puts the data on the standard output and can be analyzed with the * parseppm.c utility I wrote. That's a much faster way for figuring out how * this data is scrambled. */#define HDIV 8#define WDIV (256/HDIV)static voidov511_parse_gbr422_to_rgb24(unsigned char *pIn0, unsigned char *pOut0, int iOutY, int iOutUV, int iHalf, int iWidth){ int k, l, m; unsigned char *pIn; unsigned char *pOut, *pOut1; pIn = pIn0; pOut = pOut0 + iOutUV + (force_rgb ? 2 : 0); for (k = 0; k < 8; k++) { pOut1 = pOut; for (l = 0; l < 8; l++) { *pOut1 = *(pOut1 + 3) = *(pOut1 + iWidth*3) = *(pOut1 + iWidth*3 + 3) = *pIn++; pOut1 += 6; } pOut += iWidth*3*2; } pIn = pIn0 + 64; pOut = pOut0 + iOutUV + (force_rgb ? 0 : 2); for (k = 0; k < 8; k++) { pOut1 = pOut; for (l = 0; l < 8; l++) { *pOut1 = *(pOut1 + 3) = *(pOut1 + iWidth*3) = *(pOut1 + iWidth*3 + 3) = *pIn++; pOut1 += 6; } pOut += iWidth*3*2; } pIn = pIn0 + 128; pOut = pOut0 + iOutY + 1; 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; }}static voidov511_parse_yuv420_to_rgb(unsigned char *pIn0, unsigned char *pOut0, int iOutY, int iOutUV, int iHalf, int iWidth, int bits){ int k, l, m; int bytes = bits >> 3; unsigned char *pIn; unsigned char *pOut, *pOut1; /* 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 += bytes; } pOut1 += (iWidth - 8) * bytes; } pOut += 8 * bytes; } } /* 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+bytes); int y10 = *(pOut+iWidth*bytes); int y11 = *(pOut+iWidth*bytes+bytes); int v = *(pIn+64) - 128; int u = *pIn++ - 128; ov511_move_420_block(y00, y01, y10, y11, u, v, iWidth, pOut, bits); pOut += 2 * bytes; } pOut += (iWidth*2 - 16) * bytes; } /* Just copy the other UV rows */ for (l = 0; l < 4; l++) { for (m = 0; m < 8; m++) { *pOut++ = *(pIn + 64); *pOut = *pIn++; pOut += 2 * bytes - 1; } pOut += (iWidth*2 - 16) * bytes; } /* 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 v = *pOut1 - 128; int u = *(pOut1+1) - 128; ov511_move_420_block(y00, y01, y10, y11, u, v, iWidth, pOut1, bits); pOut1 += 2 * bytes; } pOut1 += (iWidth*2 - 8) * bytes; pIn += 8; } pOut += 8 * bytes; } }}static voidov511_dumppix(unsigned char *pIn0, unsigned char *pOut0, int iOutY, int iOutUV, int iHalf, int iWidth){ int i, j, k; unsigned char *pIn, *pOut, *pOut1; switch (dumppix) { case 1: /* Just dump YUV data straight out for debug */ pOut0 += iOutY; for (i = 0; i < HDIV; i++) { for (j = 0; j < WDIV; j++) { *pOut0++ = *pIn0++; *pOut0++ = *pIn0++; *pOut0++ = *pIn0++; } pOut0 += (iWidth - WDIV) * 3; } break; case 2: /* This converts the Y data to "black-and-white" RGB data */ /* Useful for experimenting with compression */ pIn = pIn0 + 128; pOut = pOut0 + iOutY; for (i = 0; i < 4; i++) { pOut1 = pOut; for (j = 0; j < 8; j++) { for (k = 0; k < 8; k++) { *pOut1++ = *pIn; *pOut1++ = *pIn; *pOut1++ = *pIn++; } pOut1 += (iWidth - 8) * 3; } pOut += 8 * 3; } break; case 3: /* This will dump only the Y channel data stream as-is */ pIn = pIn0 + 128; pOut = pOut0 + output_offset; for (i = 0; i < 256; i++) { *pOut++ = *pIn; *pOut++ = *pIn; *pOut++ = *pIn++; output_offset += 3; } break; } /* End switch (dumppix) */}/* This converts YUV420 segments to YUYV */static voidov511_parse_data_yuv422(unsigned char *pIn0, unsigned char *pOut0, int iOutY, int iOutUV, int iWidth){ int k, l, m; unsigned char *pIn, *pOut, *pOut1; 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 += 2; } pOut1 += (iWidth - 8) * 2; } pOut += 8 * 2; } pIn = pIn0; pOut = pOut0 + iOutUV + 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -