usbvision-core.c

来自「linux 内核源代码」· C语言 代码 · 共 2,307 行 · 第 1/5 页

C
2,307
字号
			*f++ = cb;			*f++ = cg;			*f++ = cr;			scan_length += 3;		}	}	frame->grabstate = FrameState_Done;	frame->scanlength += scan_length;	++num_pass;}/* * usbvision_decompress_alloc() * * allocates intermediate buffer for decompression */int usbvision_decompress_alloc(struct usb_usbvision *usbvision){	int IFB_size = MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * 3 / 2;	usbvision->IntraFrameBuffer = vmalloc_32(IFB_size);	if (usbvision->IntraFrameBuffer == NULL) {		err("%s: unable to allocate %d for compr. frame buffer", __FUNCTION__, IFB_size);		return -ENOMEM;	}	return 0;}/* * usbvision_decompress_free() * * frees intermediate buffer for decompression */void usbvision_decompress_free(struct usb_usbvision *usbvision){	if (usbvision->IntraFrameBuffer != NULL) {		vfree(usbvision->IntraFrameBuffer);		usbvision->IntraFrameBuffer = NULL;	}}/************************************************************ * Here comes the data parsing stuff that is run as interrupt ************************************************************//* * usbvision_find_header() * * Locate one of supported header markers in the scratch buffer. */static enum ParseState usbvision_find_header(struct usb_usbvision *usbvision){	struct usbvision_frame *frame;	int foundHeader = 0;	frame = usbvision->curFrame;	while (scratch_get_header(usbvision, &frame->isocHeader) == USBVISION_HEADER_LENGTH) {		// found header in scratch		PDEBUG(DBG_HEADER, "found header: 0x%02x%02x %d %d %d %d %#x 0x%02x %u %u",				frame->isocHeader.magic_2,				frame->isocHeader.magic_1,				frame->isocHeader.headerLength,				frame->isocHeader.frameNum,				frame->isocHeader.framePhase,				frame->isocHeader.frameLatency,				frame->isocHeader.dataFormat,				frame->isocHeader.formatParam,				frame->isocHeader.frameWidth,				frame->isocHeader.frameHeight);		if (usbvision->requestIntra) {			if (frame->isocHeader.formatParam & 0x80) {				foundHeader = 1;				usbvision->lastIsocFrameNum = -1; // do not check for lost frames this time				usbvision_unrequest_intra(usbvision);				break;			}		}		else {			foundHeader = 1;			break;		}	}	if (foundHeader) {		frame->frmwidth = frame->isocHeader.frameWidth * usbvision->stretch_width;		frame->frmheight = frame->isocHeader.frameHeight * usbvision->stretch_height;		frame->v4l2_linesize = (frame->frmwidth * frame->v4l2_format.depth)>> 3;	}	else { // no header found		PDEBUG(DBG_HEADER, "skipping scratch data, no header");		scratch_reset(usbvision);		return ParseState_EndParse;	}	// found header	if (frame->isocHeader.dataFormat==ISOC_MODE_COMPRESS) {		//check isocHeader.frameNum for lost frames		if (usbvision->lastIsocFrameNum >= 0) {			if (((usbvision->lastIsocFrameNum + 1) % 32) != frame->isocHeader.frameNum) {				// unexpected frame drop: need to request new intra frame				PDEBUG(DBG_HEADER, "Lost frame before %d on USB", frame->isocHeader.frameNum);				usbvision_request_intra(usbvision);				return ParseState_NextFrame;			}		}		usbvision->lastIsocFrameNum = frame->isocHeader.frameNum;	}	usbvision->header_count++;	frame->scanstate = ScanState_Lines;	frame->curline = 0;	if (force_testpattern) {		usbvision_testpattern(usbvision, 1, 1);		return ParseState_NextFrame;	}	return ParseState_Continue;}static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision,					   long *pcopylen){	volatile struct usbvision_frame *frame;	unsigned char *f;	int len;	int i;	unsigned char yuyv[4]={180, 128, 10, 128}; // YUV components	unsigned char rv, gv, bv;	// RGB components	int clipmask_index, bytes_per_pixel;	int stretch_bytes, clipmask_add;	frame  = usbvision->curFrame;	f = frame->data + (frame->v4l2_linesize * frame->curline);	/* Make sure there's enough data for the entire line */	len = (frame->isocHeader.frameWidth * 2)+5;	if (scratch_len(usbvision) < len) {		PDEBUG(DBG_PARSE, "out of data in line %d, need %u.\n", frame->curline, len);		return ParseState_Out;	}	if ((frame->curline + 1) >= frame->frmheight) {		return ParseState_NextFrame;	}	bytes_per_pixel = frame->v4l2_format.bytes_per_pixel;	stretch_bytes = (usbvision->stretch_width - 1) * bytes_per_pixel;	clipmask_index = frame->curline * MAX_FRAME_WIDTH;	clipmask_add = usbvision->stretch_width;	for (i = 0; i < frame->frmwidth; i+=(2 * usbvision->stretch_width)) {		scratch_get(usbvision, &yuyv[0], 4);		if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {			*f++ = yuyv[0]; // Y			*f++ = yuyv[3]; // U		}		else {			YUV_TO_RGB_BY_THE_BOOK(yuyv[0], yuyv[1], yuyv[3], rv, gv, bv);			switch (frame->v4l2_format.format) {				case V4L2_PIX_FMT_RGB565:					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3));					*f++ = (0x07 & (gv >> 5)) | (0xF8 &  rv);					break;				case V4L2_PIX_FMT_RGB24:					*f++ = bv;					*f++ = gv;					*f++ = rv;					break;				case V4L2_PIX_FMT_RGB32:					*f++ = bv;					*f++ = gv;					*f++ = rv;					f++;					break;				case V4L2_PIX_FMT_RGB555:					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2));					*f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1));					break;			}		}		clipmask_index += clipmask_add;		f += stretch_bytes;		if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {			*f++ = yuyv[2]; // Y			*f++ = yuyv[1]; // V		}		else {			YUV_TO_RGB_BY_THE_BOOK(yuyv[2], yuyv[1], yuyv[3], rv, gv, bv);			switch (frame->v4l2_format.format) {				case V4L2_PIX_FMT_RGB565:					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3));					*f++ = (0x07 & (gv >> 5)) | (0xF8 &  rv);					break;				case V4L2_PIX_FMT_RGB24:					*f++ = bv;					*f++ = gv;					*f++ = rv;					break;				case V4L2_PIX_FMT_RGB32:					*f++ = bv;					*f++ = gv;					*f++ = rv;					f++;					break;				case V4L2_PIX_FMT_RGB555:					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2));					*f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1));					break;			}		}		clipmask_index += clipmask_add;		f += stretch_bytes;	}	frame->curline += usbvision->stretch_height;	*pcopylen += frame->v4l2_linesize * usbvision->stretch_height;	if (frame->curline >= frame->frmheight) {		return ParseState_NextFrame;	}	else {		return ParseState_Continue;	}}/* The decompression routine  */static int usbvision_decompress(struct usb_usbvision *usbvision,unsigned char *Compressed,								unsigned char *Decompressed, int *StartPos,								int *BlockTypeStartPos, int Len){	int RestPixel, Idx, MaxPos, Pos, ExtraPos, BlockLen, BlockTypePos, BlockTypeLen;	unsigned char BlockByte, BlockCode, BlockType, BlockTypeByte, Integrator;	Integrator = 0;	Pos = *StartPos;	BlockTypePos = *BlockTypeStartPos;	MaxPos = 396; //Pos + Len;	ExtraPos = Pos;	BlockLen = 0;	BlockByte = 0;	BlockCode = 0;	BlockType = 0;	BlockTypeByte = 0;	BlockTypeLen = 0;	RestPixel = Len;	for (Idx = 0; Idx < Len; Idx++) {		if (BlockLen == 0) {			if (BlockTypeLen==0) {				BlockTypeByte = Compressed[BlockTypePos];				BlockTypePos++;				BlockTypeLen = 4;			}			BlockType = (BlockTypeByte & 0xC0) >> 6;			//statistic:			usbvision->ComprBlockTypes[BlockType]++;			Pos = ExtraPos;			if (BlockType == 0) {				if(RestPixel >= 24) {					Idx += 23;					RestPixel -= 24;					Integrator = Decompressed[Idx];				} else {					Idx += RestPixel - 1;					RestPixel = 0;				}			} else {				BlockCode = Compressed[Pos];				Pos++;				if (RestPixel >= 24) {					BlockLen  = 24;				} else {					BlockLen = RestPixel;				}				RestPixel -= BlockLen;				ExtraPos = Pos + (BlockLen / 4);			}			BlockTypeByte <<= 2;			BlockTypeLen -= 1;		}		if (BlockLen > 0) {			if ((BlockLen%4) == 0) {				BlockByte = Compressed[Pos];				Pos++;			}			if (BlockType == 1) { //inter Block				Integrator = Decompressed[Idx];			}			switch (BlockByte & 0xC0) {				case 0x03<<6:					Integrator += Compressed[ExtraPos];					ExtraPos++;					break;				case 0x02<<6:					Integrator += BlockCode;					break;				case 0x00:					Integrator -= BlockCode;					break;			}			Decompressed[Idx] = Integrator;			BlockByte <<= 2;			BlockLen -= 1;		}	}	*StartPos = ExtraPos;	*BlockTypeStartPos = BlockTypePos;	return Idx;}/* * usbvision_parse_compress() * * Parse compressed frame from the scratch buffer, put * decoded RGB value into the current frame buffer and add the written * number of bytes (RGB) to the *pcopylen. * */static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision,					   long *pcopylen){#define USBVISION_STRIP_MAGIC		0x5A#define USBVISION_STRIP_LEN_MAX		400#define USBVISION_STRIP_HEADER_LEN	3	struct usbvision_frame *frame;	unsigned char *f,*u = NULL ,*v = NULL;	unsigned char StripData[USBVISION_STRIP_LEN_MAX];	unsigned char StripHeader[USBVISION_STRIP_HEADER_LEN];	int Idx, IdxEnd, StripLen, StripPtr, StartBlockPos, BlockPos, BlockTypePos;	int clipmask_index, bytes_per_pixel, rc;	int imageSize;	unsigned char rv, gv, bv;	static unsigned char *Y, *U, *V;	frame  = usbvision->curFrame;	imageSize = frame->frmwidth * frame->frmheight;	if ( (frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) ||	     (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) ) {       // this is a planar format		//... v4l2_linesize not used here.		f = frame->data + (frame->width * frame->curline);	} else		f = frame->data + (frame->v4l2_linesize * frame->curline);	if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV){ //initialise u and v pointers		// get base of u and b planes add halfoffset		u = frame->data			+ imageSize			+ (frame->frmwidth >>1) * frame->curline ;		v = u + (imageSize >>1 );	} else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420){		v = frame->data + imageSize + ((frame->curline* (frame->width))>>2) ;		u = v + (imageSize >>2) ;	}	if (frame->curline == 0) {		usbvision_adjust_compression(usbvision);	}	if (scratch_len(usbvision) < USBVISION_STRIP_HEADER_LEN) {		return ParseState_Out;	}	//get strip header without changing the scratch_read_ptr	scratch_set_extra_ptr(usbvision, &StripPtr, 0);	scratch_get_extra(usbvision, &StripHeader[0], &StripPtr,				USBVISION_STRIP_HEADER_LEN);	if (StripHeader[0] != USBVISION_STRIP_MAGIC) {		// wrong strip magic		usbvision->stripMagicErrors++;		return ParseState_NextFrame;	}	if (frame->curline != (int)StripHeader[2]) {		//line number missmatch error		usbvision->stripLineNumberErrors++;	}	StripLen = 2 * (unsigned int)StripHeader[1];	if (StripLen > USBVISION_STRIP_LEN_MAX) {		// strip overrun		// I think this never happens		usbvision_request_intra(usbvision);	}	if (scratch_len(usbvision) < StripLen) {		//there is not enough data for the strip		return ParseState_Out;	}	if (usbvision->IntraFrameBuffer) {		Y = usbvision->IntraFrameBuffer + frame->frmwidth * frame->curline;		U = usbvision->IntraFrameBuffer + imageSize + (frame->frmwidth / 2) * (frame->curline / 2);		V = usbvision->IntraFrameBuffer + imageSize / 4 * 5 + (frame->frmwidth / 2) * (frame->curline / 2);	}	else {		return ParseState_NextFrame;	}	bytes_per_pixel = frame->v4l2_format.bytes_per_pixel;	clipmask_index = frame->curline * MAX_FRAME_WIDTH;	scratch_get(usbvision, StripData, StripLen);	IdxEnd = frame->frmwidth;	BlockTypePos = USBVISION_STRIP_HEADER_LEN;	StartBlockPos = BlockTypePos + (IdxEnd - 1) / 96 + (IdxEnd / 2 - 1) / 96 + 2;	BlockPos = StartBlockPos;	usbvision->BlockPos = BlockPos;	if ((rc = usbvision_decompress(usbvision, StripData, Y, &BlockPos, &BlockTypePos, IdxEnd)) != IdxEnd) {		//return ParseState_Continue;	}	if (StripLen > usbvision->maxStripLen) {		usbvision->maxStripLen = StripLen;	}	if (frame->curline%2) {		if ((rc = usbvision_decompress(usbvision, StripData, V, &BlockPos, &BlockTypePos, IdxEnd/2)) != IdxEnd/2) {		//return ParseState_Continue;		}	}	else {		if ((rc = usbvision_decompress(usbvision, StripData, U, &BlockPos, &BlockTypePos, IdxEnd/2)) != IdxEnd/2) {			//return ParseState_Continue;		}	}	if (BlockPos > usbvision->comprBlockPos) {		usbvision->comprBlockPos = BlockPos;	}	if (BlockPos > StripLen) {		usbvision->stripLenErrors++;	}	for (Idx = 0; Idx < IdxEnd; Idx++) {		if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {			*f++ = Y[Idx];			*f++ = Idx & 0x01 ? U[Idx/2] : V[Idx/2];		}		else if(frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) {			*f++ = Y[Idx];			if ( Idx & 0x01)				*u++ = U[Idx>>1] ;			else				*v++ = V[Idx>>1];

⌨️ 快捷键说明

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