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

📄 saa7146_video.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
#include <media/saa7146_vv.h>static int max_memory = 32;module_param(max_memory, int, 0644);MODULE_PARM_DESC(max_memory, "maximum memory usage for capture buffers (default: 32Mb)");#define IS_CAPTURE_ACTIVE(fh) \	(((vv->video_status & STATUS_CAPTURE) != 0) && (vv->video_fh == fh))#define IS_OVERLAY_ACTIVE(fh) \	(((vv->video_status & STATUS_OVERLAY) != 0) && (vv->video_fh == fh))/* format descriptions for capture and preview */static struct saa7146_format formats[] = {	{		.name		= "RGB-8 (3-3-2)",		.pixelformat	= V4L2_PIX_FMT_RGB332,		.trans		= RGB08_COMPOSED,		.depth		= 8,		.flags		= 0,	}, {		.name		= "RGB-16 (5/B-6/G-5/R)",		.pixelformat	= V4L2_PIX_FMT_RGB565,		.trans		= RGB16_COMPOSED,		.depth		= 16,		.flags		= 0,	}, {		.name		= "RGB-24 (B-G-R)",		.pixelformat	= V4L2_PIX_FMT_BGR24,		.trans		= RGB24_COMPOSED,		.depth		= 24,		.flags		= 0,	}, {		.name		= "RGB-32 (B-G-R)",		.pixelformat	= V4L2_PIX_FMT_BGR32,		.trans		= RGB32_COMPOSED,		.depth		= 32,		.flags		= 0,	}, {		.name		= "RGB-32 (R-G-B)",		.pixelformat	= V4L2_PIX_FMT_RGB32,		.trans		= RGB32_COMPOSED,		.depth		= 32,		.flags		= 0,		.swap		= 0x2,	}, {		.name		= "Greyscale-8",		.pixelformat	= V4L2_PIX_FMT_GREY,		.trans		= Y8,		.depth		= 8,		.flags		= 0,	}, {		.name		= "YUV 4:2:2 planar (Y-Cb-Cr)",		.pixelformat	= V4L2_PIX_FMT_YUV422P,		.trans		= YUV422_DECOMPOSED,		.depth		= 16,		.flags		= FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR,	}, {		.name		= "YVU 4:2:0 planar (Y-Cb-Cr)",		.pixelformat	= V4L2_PIX_FMT_YVU420,		.trans		= YUV420_DECOMPOSED,		.depth		= 12,		.flags		= FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR,	}, {		.name		= "YUV 4:2:0 planar (Y-Cb-Cr)",		.pixelformat	= V4L2_PIX_FMT_YUV420,		.trans		= YUV420_DECOMPOSED,		.depth		= 12,		.flags		= FORMAT_IS_PLANAR,	}, {		.name		= "YUV 4:2:2 (U-Y-V-Y)",		.pixelformat	= V4L2_PIX_FMT_UYVY,		.trans		= YUV422_COMPOSED,		.depth		= 16,		.flags		= 0,	}};/* unfortunately, the saa7146 contains a bug which prevents it from doing on-the-fly byte swaps.   due to this, it's impossible to provide additional *packed* formats, which are simply byte swapped   (like V4L2_PIX_FMT_YUYV) ... 8-( */static int NUM_FORMATS = sizeof(formats)/sizeof(struct saa7146_format);struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc){	int i, j = NUM_FORMATS;	for (i = 0; i < j; i++) {		if (formats[i].pixelformat == fourcc) {			return formats+i;		}	}	DEB_D(("unknown pixelformat:'%4.4s'\n",(char *)&fourcc));	return NULL;}static int g_fmt(struct saa7146_fh *fh, struct v4l2_format *f){	struct saa7146_dev *dev = fh->dev;	DEB_EE(("dev:%p, fh:%p\n",dev,fh));	switch (f->type) {	case V4L2_BUF_TYPE_VIDEO_CAPTURE:		f->fmt.pix = fh->video_fmt;		return 0;	case V4L2_BUF_TYPE_VIDEO_OVERLAY:		f->fmt.win = fh->ov.win;		return 0;	case V4L2_BUF_TYPE_VBI_CAPTURE:	{		f->fmt.vbi = fh->vbi_fmt;		return 0;	}	default:		DEB_D(("invalid format type '%d'.\n",f->type));		return -EINVAL;	}}static int try_win(struct saa7146_dev *dev, struct v4l2_window *win){	struct saa7146_vv *vv = dev->vv_data;	enum v4l2_field field;	int maxw, maxh;	DEB_EE(("dev:%p\n",dev));	if (NULL == vv->ov_fb.base) {		DEB_D(("no fb base set.\n"));		return -EINVAL;	}	if (NULL == vv->ov_fmt) {		DEB_D(("no fb fmt set.\n"));		return -EINVAL;	}	if (win->w.width < 48 || win->w.height <  32) {		DEB_D(("min width/height. (%d,%d)\n",win->w.width,win->w.height));		return -EINVAL;	}	if (win->clipcount > 16) {		DEB_D(("clipcount too big.\n"));		return -EINVAL;	}	field = win->field;	maxw  = vv->standard->h_max_out;	maxh  = vv->standard->v_max_out;	if (V4L2_FIELD_ANY == field) {		field = (win->w.height > maxh/2)		        ? V4L2_FIELD_INTERLACED		        : V4L2_FIELD_TOP;		}	switch (field) {	case V4L2_FIELD_TOP:	case V4L2_FIELD_BOTTOM:	case V4L2_FIELD_ALTERNATE:		maxh = maxh / 2;		break;	case V4L2_FIELD_INTERLACED:		break;	default: {		DEB_D(("no known field mode '%d'.\n",field));		return -EINVAL;	}	}	win->field = field;	if (win->w.width > maxw)		win->w.width = maxw;	if (win->w.height > maxh)		win->w.height = maxh;	return 0;}static int try_fmt(struct saa7146_fh *fh, struct v4l2_format *f){	struct saa7146_dev *dev = fh->dev;	struct saa7146_vv *vv = dev->vv_data;	int err;	switch (f->type) {	case V4L2_BUF_TYPE_VIDEO_CAPTURE:	{		struct saa7146_format *fmt;		enum v4l2_field field;		int maxw, maxh;		int calc_bpl;		DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n",dev,fh));		fmt = format_by_fourcc(dev,f->fmt.pix.pixelformat);		if (NULL == fmt) {			return -EINVAL;		}		field = f->fmt.pix.field;		maxw  = vv->standard->h_max_out;		maxh  = vv->standard->v_max_out;		if (V4L2_FIELD_ANY == field) {			field = (f->fmt.pix.height > maxh/2)				? V4L2_FIELD_INTERLACED				: V4L2_FIELD_BOTTOM;		}		switch (field) {		case V4L2_FIELD_ALTERNATE: {			vv->last_field = V4L2_FIELD_TOP;			maxh = maxh / 2;			break;		}		case V4L2_FIELD_TOP:		case V4L2_FIELD_BOTTOM:			vv->last_field = V4L2_FIELD_INTERLACED;			maxh = maxh / 2;			break;		case V4L2_FIELD_INTERLACED:			vv->last_field = V4L2_FIELD_INTERLACED;			break;		default: {			DEB_D(("no known field mode '%d'.\n",field));			return -EINVAL;		}		}		f->fmt.pix.field = field;		if (f->fmt.pix.width > maxw)			f->fmt.pix.width = maxw;		if (f->fmt.pix.height > maxh)			f->fmt.pix.height = maxh;		calc_bpl = (f->fmt.pix.width * fmt->depth)/8;		if (f->fmt.pix.bytesperline < calc_bpl)			f->fmt.pix.bytesperline = calc_bpl;		if (f->fmt.pix.bytesperline > (2*PAGE_SIZE * fmt->depth)/8) /* arbitrary constraint */			f->fmt.pix.bytesperline = calc_bpl;		f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;		DEB_D(("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n",f->fmt.pix.width,f->fmt.pix.height,f->fmt.pix.bytesperline,f->fmt.pix.sizeimage));		return 0;	}	case V4L2_BUF_TYPE_VIDEO_OVERLAY:		DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n",dev,fh));		err = try_win(dev,&f->fmt.win);		if (0 != err) {			return err;		}		return 0;	default:		DEB_EE(("unknown format type '%d'\n",f->type));		return -EINVAL;	}}int saa7146_start_preview(struct saa7146_fh *fh){	struct saa7146_dev *dev = fh->dev;	struct saa7146_vv *vv = dev->vv_data;	int ret = 0, err = 0;	DEB_EE(("dev:%p, fh:%p\n",dev,fh));	/* check if we have overlay informations */	if( NULL == fh->ov.fh ) {		DEB_D(("no overlay data available. try S_FMT first.\n"));		return -EAGAIN;	}	/* check if streaming capture is running */	if (IS_CAPTURE_ACTIVE(fh) != 0) {		DEB_D(("streaming capture is active.\n"));		return -EBUSY;	}	/* check if overlay is running */	if (IS_OVERLAY_ACTIVE(fh) != 0) {		if (vv->video_fh == fh) {			DEB_D(("overlay is already active.\n"));			return 0;		}		DEB_D(("overlay is already active in another open.\n"));		return -EBUSY;	}	if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) {		DEB_D(("cannot get necessary overlay resources\n"));		return -EBUSY;	}	err = try_win(dev,&fh->ov.win);	if (0 != err) {		saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);		return -EBUSY;	}	vv->ov_data = &fh->ov;	DEB_D(("%dx%d+%d+%d %s field=%s\n",		fh->ov.win.w.width,fh->ov.win.w.height,		fh->ov.win.w.left,fh->ov.win.w.top,		vv->ov_fmt->name,v4l2_field_names[fh->ov.win.field]));	if (0 != (ret = saa7146_enable_overlay(fh))) {		DEB_D(("enabling overlay failed: %d\n",ret));		saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);		return ret;	}	vv->video_status = STATUS_OVERLAY;	vv->video_fh = fh;	return 0;}int saa7146_stop_preview(struct saa7146_fh *fh){	struct saa7146_dev *dev = fh->dev;	struct saa7146_vv *vv = dev->vv_data;	DEB_EE(("dev:%p, fh:%p\n",dev,fh));	/* check if streaming capture is running */	if (IS_CAPTURE_ACTIVE(fh) != 0) {		DEB_D(("streaming capture is active.\n"));		return -EBUSY;	}	/* check if overlay is running at all */	if ((vv->video_status & STATUS_OVERLAY) == 0) {		DEB_D(("no active overlay.\n"));		return 0;	}	if (vv->video_fh != fh) {		DEB_D(("overlay is active, but in another open.\n"));		return -EBUSY;	}	vv->video_status = 0;	vv->video_fh = NULL;	saa7146_disable_overlay(fh);	saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);	return 0;}static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f){	struct saa7146_dev *dev = fh->dev;	struct saa7146_vv *vv = dev->vv_data;	int err;	switch (f->type) {	case V4L2_BUF_TYPE_VIDEO_CAPTURE:		DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n",dev,fh));		if (IS_CAPTURE_ACTIVE(fh) != 0) {			DEB_EE(("streaming capture is active\n"));			return -EBUSY;		}		err = try_fmt(fh,f);		if (0 != err)			return err;		fh->video_fmt = f->fmt.pix;		DEB_EE(("set to pixelformat '%4.4s'\n",(char *)&fh->video_fmt.pixelformat));		return 0;	case V4L2_BUF_TYPE_VIDEO_OVERLAY:		DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n",dev,fh));		err = try_win(dev,&f->fmt.win);		if (0 != err)			return err;		down(&dev->lock);		fh->ov.win    = f->fmt.win;		fh->ov.nclips = f->fmt.win.clipcount;		if (fh->ov.nclips > 16)			fh->ov.nclips = 16;		if (copy_from_user(fh->ov.clips,f->fmt.win.clips,sizeof(struct v4l2_clip)*fh->ov.nclips)) {			up(&dev->lock);			return -EFAULT;		}		/* fh->ov.fh is used to indicate that we have valid overlay informations, too */		fh->ov.fh = fh;		up(&dev->lock);		/* check if our current overlay is active */		if (IS_OVERLAY_ACTIVE(fh) != 0) {			saa7146_stop_preview(fh);			saa7146_start_preview(fh);		}		return 0;	default:		DEB_D(("unknown format type '%d'\n",f->type));		return -EINVAL;	}}/********************************************************************************//* device controls */static struct v4l2_queryctrl controls[] = {	{		.id		= V4L2_CID_BRIGHTNESS,		.name		= "Brightness",		.minimum	= 0,		.maximum	= 255,		.step		= 1,		.default_value	= 128,		.type		= V4L2_CTRL_TYPE_INTEGER,	},{		.id		= V4L2_CID_CONTRAST,		.name		= "Contrast",		.minimum	= 0,		.maximum	= 127,		.step		= 1,		.default_value	= 64,		.type		= V4L2_CTRL_TYPE_INTEGER,	},{		.id		= V4L2_CID_SATURATION,		.name		= "Saturation",		.minimum	= 0,		.maximum	= 127,		.step		= 1,		.default_value	= 64,		.type		= V4L2_CTRL_TYPE_INTEGER,	},{		.id		= V4L2_CID_VFLIP,		.name		= "Vertical flip",		.minimum	= 0,		.maximum	= 1,		.type		= V4L2_CTRL_TYPE_BOOLEAN,	},{		.id		= V4L2_CID_HFLIP,		.name		= "Horizontal flip",		.minimum	= 0,		.maximum	= 1,		.type		= V4L2_CTRL_TYPE_BOOLEAN,	},};static int NUM_CONTROLS = sizeof(controls)/sizeof(struct v4l2_queryctrl);#define V4L2_CID_PRIVATE_LASTP1      (V4L2_CID_PRIVATE_BASE + 0)static struct v4l2_queryctrl* ctrl_by_id(int id){	int i;	for (i = 0; i < NUM_CONTROLS; i++)		if (controls[i].id == id)			return controls+i;	return NULL;}static int get_control(struct saa7146_fh *fh, struct v4l2_control *c){	struct saa7146_dev *dev = fh->dev;	struct saa7146_vv *vv = dev->vv_data;	const struct v4l2_queryctrl* ctrl;	u32 value = 0;	ctrl = ctrl_by_id(c->id);	if (NULL == ctrl)		return -EINVAL;	switch (c->id) {	case V4L2_CID_BRIGHTNESS:		value = saa7146_read(dev, BCS_CTRL);		c->value = 0xff & (value >> 24);		DEB_D(("V4L2_CID_BRIGHTNESS: %d\n",c->value));		break;	case V4L2_CID_CONTRAST:		value = saa7146_read(dev, BCS_CTRL);		c->value = 0x7f & (value >> 16);		DEB_D(("V4L2_CID_CONTRAST: %d\n",c->value));		break;	case V4L2_CID_SATURATION:		value = saa7146_read(dev, BCS_CTRL);		c->value = 0x7f & (value >> 0);		DEB_D(("V4L2_CID_SATURATION: %d\n",c->value));		break;	case V4L2_CID_VFLIP:		c->value = vv->vflip;		DEB_D(("V4L2_CID_VFLIP: %d\n",c->value));		break;	case V4L2_CID_HFLIP:		c->value = vv->hflip;		DEB_D(("V4L2_CID_HFLIP: %d\n",c->value));		break;	default:		return -EINVAL;	}	return 0;}

⌨️ 快捷键说明

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