Skip to content

Commit

Permalink
V4L/DVB (12406): em28xx: fix: don't do image interlacing on webcams
Browse files Browse the repository at this point in the history
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: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Mauro Carvalho Chehab committed Aug 13, 2009
1 parent d594317 commit c2a6b54
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 10 deletions.
4 changes: 4 additions & 0 deletions drivers/media/video/em28xx/em28xx-cards.c
Original file line number Diff line number Diff line change
Expand Up @@ -2502,6 +2502,10 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
if (em28xx_hint_sensor(dev) < 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 */
em28xx_card_setup(dev);

Expand Down
5 changes: 4 additions & 1 deletion drivers/media/video/em28xx/em28xx-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,10 @@ int em28xx_resolution_set(struct em28xx *dev)
{
int width, height;
width = norm_maxw(dev);
height = norm_maxh(dev) >> 1;
height = norm_maxh(dev);

if (!dev->progressive)
height >>= norm_maxh(dev);

em28xx_set_outfmt(dev);

Expand Down
40 changes: 31 additions & 9 deletions drivers/media/video/em28xx/em28xx-video.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,15 +194,24 @@ static void em28xx_copy_video(struct em28xx *dev,
startread = p;
remain = len;

/* Interlaces frame */
if (buf->top_field)
if (dev->progressive)
fieldstart = outp;
else
fieldstart = outp + bytesperline;
else {
/* Interlaces two half frames */
if (buf->top_field)
fieldstart = outp;
else
fieldstart = outp + bytesperline;
}

linesdone = dma_q->pos / bytesperline;
currlinedone = dma_q->pos % bytesperline;
offset = linesdone * bytesperline * 2 + currlinedone;

if (dev->progressive)
offset = linesdone * bytesperline + currlinedone;
else
offset = linesdone * bytesperline * 2 + currlinedone;

startwrite = fieldstart + offset;
lencopy = bytesperline - currlinedone;
lencopy = lencopy > remain ? remain : lencopy;
Expand Down Expand Up @@ -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],
len, (p[2] & 1) ? "odd" : "even");

if (!(p[2] & 1)) {
if (dev->progressive || !(p[2] & 1)) {
if (buf != NULL)
buffer_filled(dev, dma_q, buf);
get_next_buf(dma_q, &buf);
Expand Down Expand Up @@ -689,7 +698,10 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;

/* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
f->fmt.pix.field = dev->interlaced ?
if (dev->progressive)
f->fmt.pix.field = V4L2_FIELD_NONE;
else
f->fmt.pix.field = dev->interlaced ?
V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;

mutex_unlock(&dev->lock);
Expand Down Expand Up @@ -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.sizeimage = f->fmt.pix.bytesperline * height;
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;
}
Expand Down Expand Up @@ -1659,6 +1675,7 @@ static int em28xx_v4l2_open(struct file *filp)
struct em28xx *dev;
enum v4l2_buf_type fh_type;
struct em28xx_fh *fh;
enum v4l2_field field;

dev = em28xx_get_device(minor, &fh_type, &radio);

Expand Down Expand Up @@ -1700,8 +1717,13 @@ static int em28xx_v4l2_open(struct file *filp)

dev->users++;

if (dev->progressive)
field = V4L2_FIELD_NONE;
else
field = V4L2_FIELD_INTERLACED;

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);

mutex_unlock(&dev->lock);
Expand Down
3 changes: 3 additions & 0 deletions drivers/media/video/em28xx/em28xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,9 @@ struct em28xx {
int sensor_xres, sensor_yres;
int sensor_xtal;

/* Allows progressive (e. g. non-interlaced) mode */
int progressive;

/* Vinmode/Vinctl used at the driver */
int vinmode, vinctl;

Expand Down

0 comments on commit c2a6b54

Please sign in to comment.