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

📄 saa7146_video.c

📁 linux环境下的dvb驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
#include <media/saa7146_vv.h>static int memory = 32;MODULE_PARM(memory,"i");MODULE_PARM_DESC(memory, "maximum memory usage for capture buffers (default: 32Mb)");/* 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 		= "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 overlay is running */	if( 0 != vv->ov_data ) {		if( fh != vv->ov_data->fh ) {			DEB_D(("overlay is running in another open.\n"));			return -EAGAIN;		}		DEB_D(("overlay is already active.\n"));		return 0;	}		if( 0 != vv->streaming ) {		DEB_D(("streaming capture is active.\n"));		return -EBUSY;	}			err = try_win(dev,&fh->ov.win);	if (0 != err) {		return err;	}		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))) {		vv->ov_data = NULL;		DEB_D(("enabling overlay failed: %d\n",ret));		return ret;	}	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 overlay is running */	if( 0 == vv->ov_data ) {		DEB_D(("overlay is not active.\n"));		return 0;	}	if( fh != vv->ov_data->fh ) {		DEB_D(("overlay is active, but for another open.\n"));		return 0;	}	vv->ov_data = NULL;	saa7146_disable_overlay(fh);	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;	unsigned long flags;	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( fh == vv->streaming ) {			DEB_EE(("streaming capture is active"));			return -EAGAIN;		}		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;		/* check if we have an active overlay */		if( vv->ov_data != NULL ) {			if( fh == vv->ov_data->fh) {				spin_lock_irqsave(&dev->slock,flags);				saa7146_stop_preview(fh);				saa7146_start_preview(fh);				spin_unlock_irqrestore(&dev->slock,flags);			}		}		up(&dev->lock);		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;}static int set_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;	unsigned long flags;	int restart_overlay = 0;	ctrl = ctrl_by_id(c->id);	if (NULL == ctrl) {		DEB_D(("unknown control %d\n",c->id));		return -EINVAL;	}		switch (ctrl->type) {	case V4L2_CTRL_TYPE_BOOLEAN:	case V4L2_CTRL_TYPE_MENU:	case V4L2_CTRL_TYPE_INTEGER:		if (c->value < ctrl->minimum)			c->value = ctrl->minimum;		if (c->value > ctrl->maximum)			c->value = ctrl->maximum;		break;	default:

⌨️ 快捷键说明

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