⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qcamvc.c

📁 VC编写的USB QuickCam驱动程序,实现四种视频格式在linux下的编码,信号来自摄像源
💻 C
📖 第 1 页 / 共 4 页
字号:
	calc_CCD_area(qcamvc->width, qcamvc->height, &qcamvc->ccd_area);	qcamvc->width = qcamvc->ccd_area.width;	qcamvc->height = qcamvc->ccd_area.height;	/* new packet lengths for new image size & bpc */	qcamvc->packet_len = calc_packetlength(qcamvc, qcamvc->bpc);	qcamvc->packet_len_bpc8 = calc_packetlength(qcamvc, 8);	/* write out 1st 4 bytes of ccd_area */	if (set_registers(qcamvc, QCAM_VC_SET_CCD_AREA, (unsigned char*)&qcamvc->ccd_area, 4))		return -1;		return 0;}static int qcamvc_set_res(struct qcamvc_data *qcamvc, int width, int height){	/* make sure the width and height are valid, or bad things will happen */	make_valid_res(&width, &height);		if (down_interruptible(&qcamvc->busy_lock))		return -1;	qcamvc->width = width;	qcamvc->height = height;		/* set CCD columns & rows */	qcamvc_set_ccd_area(qcamvc);	/* set multiplier bit after res change */	qcamvc->misc_reg.multiplier = (qcamvc->ccd_area.multiplier ? 0 : 1);	set_registers(qcamvc, QCAM_VC_SET_MISC, (unsigned char*)&qcamvc->misc_reg, 1);	/* clear the current frame by asking for a new one */	send_grab_image(qcamvc, 1);	up(&qcamvc->busy_lock);		return 0;}static void qcamvc_set_exposure(struct qcamvc_data *qcamvc,  unsigned char val){	unsigned char buffer[2];	int ival;	/* No idea why exposure range is 294 -> 1, 295 -> 16383, but that's what it is. */	/* Exposure zero and one, appear to be the same thing. */	ival = val + 1;	ival = (ival < 4) ? ival : ((ival * ival) >> 2); /* linear below 4 */		if(ival < 295)	{		ival = 295 - ival;	}	else if(ival > 16383)	{		ival = 16383;	}	buffer[0] = ival;	buffer[1] = ival >> 8;	set_registers(qcamvc, QCAM_VC_SET_EXPOSURE, buffer, 2);}static void qcamvc_set_brightness(struct qcamvc_data *qcamvc,  unsigned char val){	short i,j;	unsigned char buffer[21]=		{		0x58, 0xd8, 0x58, 0xd8, 0x58,		0xd8, 0x58, 0xd8, 0x58, 0xd8,		0x58, 0xd8, 0x58, 0xd8, 0x58,		0xd8, 0x58, 0xd8, 0x58, 0xd8, 0x5c		};		for(i=1, j=18 ; i<=0x80 ; i*=2 , j-=2)	{		if( val & i)		{			buffer[j] = buffer[j] | 1;			buffer[j+1] = buffer[j+1] | 1;		}	}	set_registers(qcamvc, QCAM_VC_SET_BRIGHTNESS, buffer, sizeof(buffer));}static void qcamvc_set_light_sensitivity(struct qcamvc_data *qcamvc,  unsigned char val){	unsigned char buffer[2];		buffer[0] = 255-val;	/* attenuation */	buffer[1] = val;		/* gain */		set_registers(qcamvc, QCAM_VC_SET_LIGHTSENS_LO, buffer, 2);}/*	have to get this checked on a USB & quickcam Pro to make sure 	address 0x00 & 0x01 are in fact, camera model/type.*/static int get_camera_model(struct qcamvc_data *qcamvc){	unsigned char model, type;	if (get_register(qcamvc, 0x00, &model))		return -1;	if (get_register(qcamvc, 0x01, &type))		return -1;		/* 	for quickcam vc...	address 0x00 always 0x02 (2)	address 0x01 always 0x0A (16)	*/		qcamvc->camera_model = model;	qcamvc->camera_type = type;		//printk("Camera: %d / %d\n", model, type);		return 0;}/* Table of ln(x/256) * 256 for x going from 0 -> 255 */static const int gamma_helper[256] ={	0, -1420, -1242, -1138, -1065, -1007, -961, -921, -887, -857, -830, -806, -783, -762, -744, -726,	-710, -694, -679, -666, -652, -640, -628, -617, -606, -596, -586, -576, -567, -577, -549, -541,	-532, -525, -517, -509, -502, -495, -488, -482, -475, -469, -463, -457, -451, -455, -439, -434,	-429, -423, -418, -413, -408, -403, -398, -394, -389, -385, -380, -376, -371, -367, -363, -359,	-355, -351, -347, -343, -339, -336, -332, -328, -325, -321, -318, -314, -311, -308, -304, -301,	-298, -295, -291, -288, -285, -282, -279, -276, -273, -271, -268, -265, -262, -259, -257, -254,	-251, -248, -246, -243, -241, -238, -236, -233, -231, -228, -226, -223, -221, -219, -216, -214,	-212, -209, -207, -205, -203, -200, -198, -196, -194, -192, -190, -188, -186, -184, -182, -180,	-178, -176, -174, -172, -170, -168, -166, -164, -162, -160, -158, -156, -155, -153, -151, -149,	-147, -146, -144, -142, -140, -139, -137, -135, -134, -132, -130, -128, -127, -125, -124, -122,	-120, -119, -117, -116, -114, -112, -111, -109, -108, -106, -105, -103, -102, -100, -99, -97,	-96, -95, -93, -92, -90, -89, -87, -86, -85, -83, -82, -80, -79, -78, -76, -75,	-74, -72, -71, -70, -68, -67, -66, -65, -63, -62, -61, -59, -58, -57, -56, -54,	-53, -52, -51, -50, -48, -47, -46, -45, -44, -42, -41, -40, -39, -38, -37, -35,	-34, -33, -32, -31, -30, -29, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18,	-17, -16, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1};/* * Copyright (c) 2002 S. Fuerst * * This software may be copied and distributed for educational, research, and * not for profit purposes provided that this copyright and statement are * included in all such copies. * Build the gamma table so that floating point isn't needed. * *  ANGBAND_X11_GAMMA is * 256 * (1 / gamma), rounded to integer. A recommended value * is 183, which is an approximation of the Macintosh hardware * gamma of 1.4. * *   gamma      ANGBAND_X11_GAMMA *   -----      ----------------- *   1.2        213 *   1.25       205 *   1.3        197 *   1.35       190 *   1.4        183 *   1.45       177 *   1.5        171 *   1.6        160 *   1.7        151 *   ... * * XXX XXX The environment variable, or better, * the interact with colours command should allow users * to specify gamma values (or gamma value * 100). */void build_gamma_table(struct qcamvc_data *qcamvc){	if (!qcamvc || qcamvc->gamma_done) return;	qcamvc->gamma_done = 1;	int gamma = 170;//qcamvc->contrast;		int i, n;	/*	* value is the current sum.	* diff is the new term to add to the series.	*/	long value, diff;	/* Paranoia */	if (gamma < 0) gamma = 0;	else if (gamma > 255) gamma = 255;	/* Hack - convergence is bad in these cases. */	qcamvc->gamma_table[0] = 0;	qcamvc->gamma_table[255] = 255;	for (i = 1; i < 255; i++)	{		/*		* Initialise the Taylor series		*		* value and diff have been scaled by 256		*/		n = 1;		value = 256 * 256;		diff = ((long)gamma_helper[i]) * (gamma - 256);		while (diff)		{			value += diff;			n++;			/*			* Use the following identiy to calculate the gamma table.			* exp(x) = 1 + x + x^2/2 + x^3/(2*3) + x^4/(2*3*4) +...			*			* n is the current term number.			*			* The gamma_helper array contains a table of			* ln(x/256) * 256			* This is used because a^b = exp(b*ln(a))			*			* In this case:			* a is i / 256			* b is gamma.			*			* Note that everything is scaled by 256 for accuracy,			* plus another factor of 256 for the final result to			* be from 0-255.  Thus gamma_helper[] * gamma must be			* divided by 256*256 each itteration, to get back to			* the original power series.			*/			diff = (((diff / 256) * gamma_helper[i]) * (gamma - 256)) / (256 * n);		}		/*		* Store the value in the table so that the		* floating point pow function isn't needed.		*/		qcamvc->gamma_table[i] = ((long)(value / 256) * i) / 256;	}}#define LIMIT(x) ((x)>255?255 : ((x)<0?0:x))static int ybr_convert(struct qcamvc_data *qcamvc,  unsigned char *pout, int Y, int Cb, int Cr, int odd){	unsigned char red=0, green=0, blue=0;	unsigned bytes = 0;	Y = qcamvc->gamma_table[ Y ];	//Y = LIMIT(Y);		Y = Y * qcamvc->contrast * qcamvc->contrast / 16384;	Cr = Cr * qcamvc->saturation * qcamvc->saturation / 16384;	Cb = Cb * qcamvc->saturation * qcamvc->saturation / 16384;		switch (qcamvc->pixelformat)	{	case V4L2_PIX_FMT_RGB24:	case V4L2_PIX_FMT_RGB32:	case V4L2_PIX_FMT_BGR24:	case V4L2_PIX_FMT_BGR32:	case V4L2_PIX_FMT_RGB555:	case V4L2_PIX_FMT_RGB565:		red =   LIMIT( (Y) + (Cr * 1402 / 1000) );		green = LIMIT( (Y) - (Cb * 3441 / 10000)  - (Cr * 7141 / 10000) );		blue =  LIMIT( (Y) + (Cb * 1772 / 1000) );		break;	}	if (qcamvc->flip_bgr)	{		/* There has been some confusion regarding why this is necessary.		 * It is not because of a problem in the driver, but because of		 * a problem in the V4L2 standard. In V4L1, the V4L_PALETTE_RGB*		 * entries referred to a B,G,R order. In the first versions of the		 * V4L2 spec this was also the order, but it was changed fairly		 * early on. To complicate matters, some specs were published which		 * showed V4L2_PIX_FMT_RGB* and V4L2_PIX_FMT_BGR* having the		 * opposite meanings to those they have now. Since some apps will		 * be using the wrong meanings, we have no choice but to have a		 * switch, but at least we can switch via settings to		 * /proc/qcamvc/video0 rather than at module initialisation time.		 */		unsigned tmp;		switch (qcamvc->pixelformat)		{		case V4L2_PIX_FMT_RGB24:		case V4L2_PIX_FMT_RGB32:		case V4L2_PIX_FMT_BGR24:		case V4L2_PIX_FMT_BGR32:			tmp = red;			red = blue;			blue = tmp;			break;		}	}	switch (qcamvc->pixelformat)	{	case V4L2_PIX_FMT_BGR32:		*pout-- = 0;		++bytes;	case V4L2_PIX_FMT_BGR24:		*pout-- = red;		*pout-- = green;		*pout-- = blue;		bytes += 3;		break;	case V4L2_PIX_FMT_RGB32:		*pout-- = 0;		++bytes;	case V4L2_PIX_FMT_RGB24:		*pout-- = blue;		*pout-- = green;		*pout-- = red;		bytes += 3;		break;	case V4L2_PIX_FMT_GREY:		*pout-- = LIMIT(Y);		++bytes;		break;	case V4L2_PIX_FMT_RGB555:		*pout-- = (green >> 6) | ((blue >> 1) &0x7c);		*pout-- = (red >> 3) | ((green << 2) & 0xe0);		bytes += 2;		break;	case V4L2_PIX_FMT_RGB565:		*pout-- = (green >> 5) | (blue & 0xf8);		*pout-- = (red >> 3) | ((green << 3) & 0xe0);		bytes += 2;		break;	case V4L2_PIX_FMT_YUYV:		if (odd)			*pout-- = LIMIT(Cb + 128);		else			*pout-- = LIMIT(Cr + 128);		*pout-- = (Y > 203) ? 219 : (Y + 16);		bytes += 2;		break;	case V4L2_PIX_FMT_UYVY:		*pout-- = (Y > 203) ? 219 : (Y + 16);		if (odd)			*pout-- = LIMIT(Cb + 128);		else			*pout-- = LIMIT(Cr + 128);		bytes += 2;		break;	}		return bytes;}static void codec(struct qcamvc_data *qcamvc, unsigned char *inbuf, unsigned char *outbuf){	if (!qcamvc) return;		int row,col;	int start_row, start_col, end_col, end_row, width;	unsigned char *pin, *pout;	int rgb_offset;	char Y, Cb, Cr;	rgb_offset = qcamvc->colordepth / 8;	pin			= inbuf;	pout		= outbuf + (qcamvc->width * qcamvc->height * rgb_offset) - 1;	start_col	= 0;//qcamvc->ccd_area.first_col;	start_row	= 1;//(qcamvc->ccd_area.first_row >> qcamvc->ccd_area.multiplier);	end_col		= start_col + qcamvc->width;	end_row		= start_row + qcamvc->height;	width		= qcamvc->width;	/* do gamma table */	if (!qcamvc->gamma_done)		build_gamma_table(qcamvc);#define ADD(a,b) (((int)*(pin+a) + (int)*(pin+b)))#define SUB(a,b) (((int)*(pin+a) - (int)*(pin+b)))	/*	Demosaic the CCD cells and convert to some usable colourspace...	Connectix uses just the odd or even fields. Not both.		So that the max vertical resolution of the 362x582 CCD is 582/2= 291.		Effectively 290 max, using the one field.	Each field is given to us as		odd row: (Mg+Ye), (Gr+Cy)		even row: (Gr+Ye), (Mg+Cy)		So 576 CCD cell rows are used for 352x288 resolution.		For this codec to work, the width and height must be even.	*///printk("start row=%d, start col=%d\n", start_row, start_row);		for(row = start_row ; row < end_row ; row++)	{		//reverse = (row % 4) >> 1;				for (col = start_col ; col < end_col ; col++)		{			#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))			if (current->need_resched)				schedule ();			#else			cond_resched();			#endif						if (col % 2 == qcamvc->ccd_area.multiplier)			{ //even column								Y = ADD(0, -1);								if (row % 2 == qcamvc->ccd_area.multiplier)				{ //odd row					Cb = -SUB(width, width-1);					Cr = SUB(0, -1);				}				else				{ //even row					Cb = -SUB(0, -1);					Cr = SUB(-width, -width-1);				}			}			else			{ //odd column								Y = ADD(0, 1);								if (row % 2 == qcamvc->ccd_area.multiplier)				{ //odd row					Cb = -SUB(width+1, width);					Cr = SUB(1, 0);				}				else				{ //even row					Cb = -SUB(1, 0);					Cr = SUB(-width+1, -width);				}			}			/* YCbCr -> output format */			pout -= ybr_convert(qcamvc, pout, Y, Cb, Cr, col & 1);						pin++;		}	} #undef ADD#undef SUB}static void qcamvc_parse(struct qcamvc_data *qcamvc, unsigned char *outbuf){	unsigned char *inbuf;		if (qcamvc->bpc == 6)	{		/* convert 6bit packed data to 8bit data. */				unsigned char *pTo, *pFrom;		int eop = ((qcamvc->width * qcamvc->height * 3) / 4) + 2;		int eop8 = qcamvc->width * qcamvc->height + 2;				/* starting at the end of the buffer */		pFrom = qcamvc->raw_frame + eop - 1;				/* +4 bytes to avoid overlap by the end of this conversion. */		pTo = qcamvc->raw_frame + eop8 + 4 - 1;		while(pFrom > qcamvc->raw_frame + 2)		{			*(pTo--) = *(pFrom) >> 2;			*(pTo--) = ((*(pFrom - 1) >> 4) & 0x0f) | ((*(pFrom) << 4) & 0x30);			*(pTo--) = ((*(pFrom - 2) >> 6) & 0x03) | ((*(pFrom - 1) & 0x0f) << 2);			*(pTo--) = *(pFrom - 2) & 0x3f;						pFrom -= 3;		}				/* the start of data is now +4 bytes away +2 bytes			to skip header data */		inbuf = qcamvc->raw_frame + 4 + 2;	}	else	{		inbuf = qcamvc->raw_frame + 2; /* skip first 2 bytes */	}#if 1	codec(qcamvc, inbuf, outbuf);#else	/* test - view the raw image */	size_t i;	for( i=0; i < qcamvc->width*qcamvc->height*3; i++ ){		*(outbuf+i) = *(inbuf + (i/3));	}#endif}static void put_cam(struct qcamvc_camera_ops* ops){	if (ops->owner)		module_put(ops->owner);}/**************************************************************************** * * /proc interface * ***************************************************************************/#ifdef CONFIG_PROC_FSstatic struct proc_dir_entry *qcamvc_proc_root = NULL;#define YES_NO(x) ((x) ? "yes" : "no")static int qcamvc_read_proc(char *page, char **start, off_t off, int count,			   int *eof, void *data){	char *out = page;	int len;	struct qcamvc_data *qcamvc = data;		if (!qcamvc) return 0;		/* ok. no floating point */	unsigned int fps = qcamvc->packet_len ? ((qcamvc->transfer_rate * 102400) / qcamvc->packet_len) : 0;		// Stay under PAGE_SIZE or bad things will happen :(	out+=sprintf(out, "driver_version   : %s\n", QCAMVCVERSION);	out+=sprintf(out, "model            : %s\n", qcamvc->camtypedesc);	out+=sprintf(out, "max resolution   : %dx%d\n", MAX_WIDTH, MAX_HEIGHT);	out+=sprintf(out, "min resolution   : %dx%d\n\n", MIN_WIDTH, MIN_HEIGHT);	out+=sprintf(out, "Settings\n");	out+=sprintf(out, "resolution       : %dx%d\n", qcamvc->width, qcamvc->height);	out+=sprintf(out, "bit per component: %d\n", qcamvc->bpc);	out+=sprintf(out, "contrast         : %d\n", (int)qcamvc->contrast);	out+=sprintf(out, "brightness       : %d\n", qcamvc->brightness);	out+=sprintf(out, "exposure         : %d\n", (int)qcamvc->exposure);	out+=sprintf(out, "hue              : %d\n", (int)qcamvc->hue);	out+=sprintf(out, "saturation       : %d\n", (int)qcamvc->saturation);	out+=sprintf(out, "transfer rate    : %dkB/s (%d.%dfps)\n", 		qcamvc->transfer_rate, fps/100, fps ? (fps-((fps/100)*100)) : 0);	out+=sprintf(out, "rgb to bgr hack  : %s\n", qcamvc->flip_bgr ? "on" : "off");		out+=sprintf(out, "\n");		len = out - page;	len -= off;	if (len < count)	{		*eof = 1;		if (len <= 0) return 0;	}	else	{		len = count;	}		*start = page + off;		return len;	}static void setparam (struct qcamvc_data *qcamvc, char *name, char *sval){	if (down_interruptible(&qcamvc->busy_lock))		return;		unsigned int val, err;		if (!qcamvc || !sval) return;	if (!isdigit(sval[0])) return;	err = 1;	val = simple_strtoul(sval, NULL, 0);#define MATCH(x) (strcmp(name, x)==0)		if (MATCH("brightness") && (val <= 255))	{		qcamvc->brightness = val;		qcamvc_set_brightness(qcamvc,qcamvc->brightness);		err=0;	}	else if (MATCH("exposure") && (val <= 255))	{				qcamvc->exposure = val;		qcamvc_set_exposure(qcamvc,qcamvc->exposure);		err=0;	}	else if (MATCH("contrast") && (val <= 255))	{		//qcamvc->blue_hue = val;		qcamvc->contrast = val;		qcamvc->gamma_done=0;		err=0;	}	else if (MATCH("hue") && (val <= 255))	{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -