From 9bde9f263e958b0d588aada03854fcc0f0c88b86 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 17 Jun 2010 06:52:37 -0300 Subject: [PATCH] V4L/DVB: uvcvideo: Drop corrupted compressed frames Corrupted video frames are dropped by default by the driver for uncompressed formats. Data corruption is not less problematic for compressed formats, so frame drop should be enabled by default for those formats as well. Mark buffers as faulty when an isochronous packet loss is detected for any format, or when the buffer length doesn't match the image size for uncompressed formats. Drop erroneous buffers regardless of whether the format is compressed or uncompressed. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/uvc/uvc_queue.c | 13 +++++++++---- drivers/media/video/uvc/uvc_video.c | 19 +++++++++++-------- drivers/media/video/uvc/uvcvideo.h | 5 +++-- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c index 133c78d113ac..e9928a415086 100644 --- a/drivers/media/video/uvc/uvc_queue.c +++ b/drivers/media/video/uvc/uvc_queue.c @@ -78,12 +78,14 @@ * */ -void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) +void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, + int drop_corrupted) { mutex_init(&queue->mutex); spin_lock_init(&queue->irqlock); INIT_LIST_HEAD(&queue->mainqueue); INIT_LIST_HEAD(&queue->irqqueue); + queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0; queue->type = type; } @@ -435,8 +437,10 @@ int uvc_queue_enable(struct uvc_video_queue *queue, int enable) uvc_queue_cancel(queue, 0); INIT_LIST_HEAD(&queue->mainqueue); - for (i = 0; i < queue->count; ++i) + for (i = 0; i < queue->count; ++i) { + queue->buffer[i].error = 0; queue->buffer[i].state = UVC_BUF_STATE_IDLE; + } queue->flags &= ~UVC_QUEUE_STREAMING; } @@ -488,8 +492,8 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *nextbuf; unsigned long flags; - if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) && - buf->buf.length != buf->buf.bytesused) { + if ((queue->flags & UVC_QUEUE_DROP_CORRUPTED) && buf->error) { + buf->error = 0; buf->state = UVC_BUF_STATE_QUEUED; buf->buf.bytesused = 0; return buf; @@ -497,6 +501,7 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, spin_lock_irqsave(&queue->irqlock, flags); list_del(&buf->queue); + buf->error = 0; buf->state = UVC_BUF_STATE_DONE; if (!list_empty(&queue->irqqueue)) nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer, diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 53f3ef4635eb..e27cf0d3b6d9 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -555,6 +555,9 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream, if (urb->iso_frame_desc[i].status < 0) { uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame " "lost (%d).\n", urb->iso_frame_desc[i].status); + /* Mark the buffer as faulty. */ + if (buf != NULL) + buf->error = 1; continue; } @@ -579,8 +582,14 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream, uvc_video_decode_end(stream, buf, mem, urb->iso_frame_desc[i].actual_length); - if (buf->state == UVC_BUF_STATE_READY) + if (buf->state == UVC_BUF_STATE_READY) { + if (buf->buf.length != buf->buf.bytesused && + !(stream->cur_format->flags & + UVC_FMT_FLAG_COMPRESSED)) + buf->error = 1; + buf = uvc_queue_next_buffer(&stream->queue, buf); + } } } @@ -1104,7 +1113,7 @@ int uvc_video_init(struct uvc_streaming *stream) atomic_set(&stream->active, 0); /* Initialize the video buffers queue. */ - uvc_queue_init(&stream->queue, stream->type); + uvc_queue_init(&stream->queue, stream->type, !uvc_no_drop_param); /* Alternate setting 0 should be the default, yet the XBox Live Vision * Cam (and possibly other devices) crash or otherwise misbehave if @@ -1197,12 +1206,6 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable) return 0; } - if ((stream->cur_format->flags & UVC_FMT_FLAG_COMPRESSED) || - uvc_no_drop_param) - stream->queue.flags &= ~UVC_QUEUE_DROP_INCOMPLETE; - else - stream->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE; - ret = uvc_queue_enable(&stream->queue, 1); if (ret < 0) return ret; diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index ac272456fbfd..bdacf3beabf5 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h @@ -379,11 +379,12 @@ struct uvc_buffer { struct list_head queue; wait_queue_head_t wait; enum uvc_buffer_state state; + unsigned int error; }; #define UVC_QUEUE_STREAMING (1 << 0) #define UVC_QUEUE_DISCONNECTED (1 << 1) -#define UVC_QUEUE_DROP_INCOMPLETE (1 << 2) +#define UVC_QUEUE_DROP_CORRUPTED (1 << 2) struct uvc_video_queue { enum v4l2_buf_type type; @@ -562,7 +563,7 @@ extern struct uvc_driver uvc_driver; /* Video buffers queue management. */ extern void uvc_queue_init(struct uvc_video_queue *queue, - enum v4l2_buf_type type); + enum v4l2_buf_type type, int drop_corrupted); extern int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers, unsigned int buflength); extern int uvc_free_buffers(struct uvc_video_queue *queue); -- 2.39.5