diff mbox

s2255drv: support for frame skipping

Message ID tkrat.bdcfbe49c59f68a6@sensoray.com (mailing list archive)
State Accepted
Headers show

Commit Message

Dean Anderson March 8, 2010, 11:04 p.m. UTC
None
diff mbox

Patch

diff -r 08932f075cb1 -r 3ac8a7637cf3 linux/drivers/media/video/s2255drv.c
--- a/linux/drivers/media/video/s2255drv.c	Fri Mar 05 14:55:23 2010 -0800
+++ b/linux/drivers/media/video/s2255drv.c	Mon Mar 08 15:02:14 2010 -0800
@@ -1427,11 +1427,19 @@ 
 	}
 	mode = &fh->mode;
 	if (*i & V4L2_STD_NTSC) {
-		dprintk(4, "vidioc_s_std NTSC\n");
-		mode->format = FORMAT_NTSC;
+		dprintk(4, "%s NTSC\n", __func__);
+		/* if changing format, reset frame decimation/intervals */
+		if (mode->format != FORMAT_NTSC) {
+			mode->format = FORMAT_NTSC;
+			mode->fdec = FDEC_1;
+		}
 	} else if (*i & V4L2_STD_PAL) {
-		dprintk(4, "vidioc_s_std PAL\n");
+		dprintk(4, "%s PAL\n", __func__);
 		mode->format = FORMAT_PAL;
+		if (mode->format != FORMAT_PAL) {
+			mode->format = FORMAT_PAL;
+			mode->fdec = FDEC_1;
+		}
 	} else {
 		ret = -EINVAL;
 	}
@@ -1633,10 +1641,34 @@ 
 {
 	struct s2255_fh *fh = priv;
 	struct s2255_dev *dev = fh->dev;
+	__u32 def_num, def_dem;
 	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
+	memset(sp, 0, sizeof(struct v4l2_streamparm));
+	sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
 	sp->parm.capture.capturemode = dev->cap_parm[fh->channel].capturemode;
-	dprintk(2, "getting parm %d\n", sp->parm.capture.capturemode);
+	def_num = (fh->mode.format == FORMAT_NTSC) ? 1001 : 1000;
+	def_dem = (fh->mode.format == FORMAT_NTSC) ? 30000 : 25000;
+	sp->parm.capture.timeperframe.denominator = def_dem;
+	switch (fh->mode.fdec) {
+	default:
+	case FDEC_1:
+		sp->parm.capture.timeperframe.numerator = def_num;
+		break;
+	case FDEC_2:
+		sp->parm.capture.timeperframe.numerator = def_num * 2;
+		break;
+	case FDEC_3:
+		sp->parm.capture.timeperframe.numerator = def_num * 3;
+		break;
+	case FDEC_5:
+		sp->parm.capture.timeperframe.numerator = def_num * 5;
+		break;
+	}
+	dprintk(4, "%s capture mode, %d timeperframe %d/%d\n", __func__,
+		sp->parm.capture.capturemode,
+		sp->parm.capture.timeperframe.numerator,
+		sp->parm.capture.timeperframe.denominator);
 	return 0;
 }
 
@@ -1645,15 +1677,79 @@ 
 {
 	struct s2255_fh *fh = priv;
 	struct s2255_dev *dev = fh->dev;
-
+	int fdec = FDEC_1;
+	__u32 def_num, def_dem;
 	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
-
-	dev->cap_parm[fh->channel].capturemode = sp->parm.capture.capturemode;
-	dprintk(2, "setting param capture mode %d\n",
-		sp->parm.capture.capturemode);
+	/* high quality capture mode requires a stream restart */
+	if (dev->cap_parm[fh->channel].capturemode
+	    != sp->parm.capture.capturemode && res_locked(fh->dev, fh))
+		return -EBUSY;
+	def_num = (fh->mode.format == FORMAT_NTSC) ? 1001 : 1000;
+	def_dem = (fh->mode.format == FORMAT_NTSC) ? 30000 : 25000;
+	if (def_dem != sp->parm.capture.timeperframe.denominator)
+		sp->parm.capture.timeperframe.numerator = def_num;
+	else if (sp->parm.capture.timeperframe.numerator <= def_num)
+		sp->parm.capture.timeperframe.numerator = def_num;
+	else if (sp->parm.capture.timeperframe.numerator <= (def_num * 2)) {
+		sp->parm.capture.timeperframe.numerator = def_num * 2;
+		fdec = FDEC_2;
+	} else if (sp->parm.capture.timeperframe.numerator <= (def_num * 3)) {
+		sp->parm.capture.timeperframe.numerator = def_num * 3;
+		fdec = FDEC_3;
+	} else {
+		sp->parm.capture.timeperframe.numerator = def_num * 5;
+		fdec = FDEC_5;
+	}
+	fh->mode.fdec = fdec;
+	sp->parm.capture.timeperframe.denominator = def_dem;
+	s2255_set_mode(dev, fh->channel, &fh->mode);
+	dprintk(4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n",
+		__func__,
+		sp->parm.capture.capturemode,
+		sp->parm.capture.timeperframe.numerator,
+		sp->parm.capture.timeperframe.denominator, fdec);
 	return 0;
 }
+
+static int vidioc_enum_frameintervals(struct file *file, void *priv,
+			    struct v4l2_frmivalenum *fe)
+{
+	int is_ntsc = 0;
+#define NUM_FRAME_ENUMS 4
+	int frm_dec[NUM_FRAME_ENUMS] = {1, 2, 3, 5};
+	if (fe->index < 0 || fe->index >= NUM_FRAME_ENUMS)
+		return -EINVAL;
+	switch (fe->width) {
+	case 640:
+		if (fe->height != 240 && fe->height != 480)
+			return -EINVAL;
+		is_ntsc = 1;
+		break;
+	case 320:
+		if (fe->height != 240)
+			return -EINVAL;
+		is_ntsc = 1;
+		break;
+	case 704:
+		if (fe->height != 288 && fe->height != 576)
+			return -EINVAL;
+		break;
+	case 352:
+		if (fe->height != 288)
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+	fe->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+	fe->discrete.denominator = is_ntsc ? 30000 : 25000;
+	fe->discrete.numerator = (is_ntsc ? 1001 : 1000) * frm_dec[fe->index];
+	dprintk(4, "%s discrete %d/%d\n", __func__, fe->discrete.numerator,
+		fe->discrete.denominator);
+	return 0;
+}
+
 static int s2255_open(struct file *file)
 {
 	struct video_device *vdev = video_devdata(file);
@@ -1932,6 +2028,7 @@ 
 	.vidioc_g_jpegcomp = vidioc_g_jpegcomp,
 	.vidioc_s_parm = vidioc_s_parm,
 	.vidioc_g_parm = vidioc_g_parm,
+	.vidioc_enum_frameintervals = vidioc_enum_frameintervals,
 };
 
 static struct video_device template = {