Commit c2a6b54a authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab

V4L/DVB (12406): em28xx: fix: don't do image interlacing on webcams

Due to historical reasons, em28xx driver gets two consecutive frames and
fold them into an unique framing, doing interlacing. While this works
fine for TV images, this produces two bad effects with webcams:

1) webcam images are progressive. Merging two consecutive images produce
interlacing artifacts on the image;

2) since the driver needs to get two frames, it reduces the maximum
frame rate by two.
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent d594317b
...@@ -2502,6 +2502,10 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, ...@@ -2502,6 +2502,10 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
if (em28xx_hint_sensor(dev) < 0) if (em28xx_hint_sensor(dev) < 0)
dev->board.is_webcam = 0; dev->board.is_webcam = 0;
/* It makes no sense to use de-interlacing mode on webcams */
if (dev->board.is_webcam)
dev->progressive = 1;
/* Do board specific init and eeprom reading */ /* Do board specific init and eeprom reading */
em28xx_card_setup(dev); em28xx_card_setup(dev);
......
...@@ -720,7 +720,10 @@ int em28xx_resolution_set(struct em28xx *dev) ...@@ -720,7 +720,10 @@ int em28xx_resolution_set(struct em28xx *dev)
{ {
int width, height; int width, height;
width = norm_maxw(dev); width = norm_maxw(dev);
height = norm_maxh(dev) >> 1; height = norm_maxh(dev);
if (!dev->progressive)
height >>= norm_maxh(dev);
em28xx_set_outfmt(dev); em28xx_set_outfmt(dev);
......
...@@ -194,15 +194,24 @@ static void em28xx_copy_video(struct em28xx *dev, ...@@ -194,15 +194,24 @@ static void em28xx_copy_video(struct em28xx *dev,
startread = p; startread = p;
remain = len; remain = len;
/* Interlaces frame */ if (dev->progressive)
fieldstart = outp;
else {
/* Interlaces two half frames */
if (buf->top_field) if (buf->top_field)
fieldstart = outp; fieldstart = outp;
else else
fieldstart = outp + bytesperline; fieldstart = outp + bytesperline;
}
linesdone = dma_q->pos / bytesperline; linesdone = dma_q->pos / bytesperline;
currlinedone = dma_q->pos % bytesperline; currlinedone = dma_q->pos % bytesperline;
if (dev->progressive)
offset = linesdone * bytesperline + currlinedone;
else
offset = linesdone * bytesperline * 2 + currlinedone; offset = linesdone * bytesperline * 2 + currlinedone;
startwrite = fieldstart + offset; startwrite = fieldstart + offset;
lencopy = bytesperline - currlinedone; lencopy = bytesperline - currlinedone;
lencopy = lencopy > remain ? remain : lencopy; lencopy = lencopy > remain ? remain : lencopy;
...@@ -376,7 +385,7 @@ static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb) ...@@ -376,7 +385,7 @@ static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2], em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
len, (p[2] & 1) ? "odd" : "even"); len, (p[2] & 1) ? "odd" : "even");
if (!(p[2] & 1)) { if (dev->progressive || !(p[2] & 1)) {
if (buf != NULL) if (buf != NULL)
buffer_filled(dev, dma_q, buf); buffer_filled(dev, dma_q, buf);
get_next_buf(dma_q, &buf); get_next_buf(dma_q, &buf);
...@@ -689,6 +698,9 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, ...@@ -689,6 +698,9 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
/* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
if (dev->progressive)
f->fmt.pix.field = V4L2_FIELD_NONE;
else
f->fmt.pix.field = dev->interlaced ? f->fmt.pix.field = dev->interlaced ?
V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
...@@ -753,7 +765,11 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, ...@@ -753,7 +765,11 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3; f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3;
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height; f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
f->fmt.pix.field = V4L2_FIELD_INTERLACED; if (dev->progressive)
f->fmt.pix.field = V4L2_FIELD_NONE;
else
f->fmt.pix.field = dev->interlaced ?
V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
return 0; return 0;
} }
...@@ -1659,6 +1675,7 @@ static int em28xx_v4l2_open(struct file *filp) ...@@ -1659,6 +1675,7 @@ static int em28xx_v4l2_open(struct file *filp)
struct em28xx *dev; struct em28xx *dev;
enum v4l2_buf_type fh_type; enum v4l2_buf_type fh_type;
struct em28xx_fh *fh; struct em28xx_fh *fh;
enum v4l2_field field;
dev = em28xx_get_device(minor, &fh_type, &radio); dev = em28xx_get_device(minor, &fh_type, &radio);
...@@ -1700,8 +1717,13 @@ static int em28xx_v4l2_open(struct file *filp) ...@@ -1700,8 +1717,13 @@ static int em28xx_v4l2_open(struct file *filp)
dev->users++; dev->users++;
if (dev->progressive)
field = V4L2_FIELD_NONE;
else
field = V4L2_FIELD_INTERLACED;
videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops, videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED, NULL, &dev->slock, fh->type, field,
sizeof(struct em28xx_buffer), fh); sizeof(struct em28xx_buffer), fh);
mutex_unlock(&dev->lock); mutex_unlock(&dev->lock);
......
...@@ -484,6 +484,9 @@ struct em28xx { ...@@ -484,6 +484,9 @@ struct em28xx {
int sensor_xres, sensor_yres; int sensor_xres, sensor_yres;
int sensor_xtal; int sensor_xtal;
/* Allows progressive (e. g. non-interlaced) mode */
int progressive;
/* Vinmode/Vinctl used at the driver */ /* Vinmode/Vinctl used at the driver */
int vinmode, vinctl; int vinmode, vinctl;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment