aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2010-06-17 05:52:37 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-08-08 22:43:01 -0400
commit9bde9f263e958b0d588aada03854fcc0f0c88b86 (patch)
treec27ae43a84136e18908a9a4d3bd9b541be6db9d8
parentdf49d113d16b18070b3d51832f3a02145eeb354b (diff)
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 <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/uvc/uvc_queue.c13
-rw-r--r--drivers/media/video/uvc/uvc_video.c19
-rw-r--r--drivers/media/video/uvc/uvcvideo.h5
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 @@
78 * 78 *
79 */ 79 */
80 80
81void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) 81void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
82 int drop_corrupted)
82{ 83{
83 mutex_init(&queue->mutex); 84 mutex_init(&queue->mutex);
84 spin_lock_init(&queue->irqlock); 85 spin_lock_init(&queue->irqlock);
85 INIT_LIST_HEAD(&queue->mainqueue); 86 INIT_LIST_HEAD(&queue->mainqueue);
86 INIT_LIST_HEAD(&queue->irqqueue); 87 INIT_LIST_HEAD(&queue->irqqueue);
88 queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0;
87 queue->type = type; 89 queue->type = type;
88} 90}
89 91
@@ -435,8 +437,10 @@ int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
435 uvc_queue_cancel(queue, 0); 437 uvc_queue_cancel(queue, 0);
436 INIT_LIST_HEAD(&queue->mainqueue); 438 INIT_LIST_HEAD(&queue->mainqueue);
437 439
438 for (i = 0; i < queue->count; ++i) 440 for (i = 0; i < queue->count; ++i) {
441 queue->buffer[i].error = 0;
439 queue->buffer[i].state = UVC_BUF_STATE_IDLE; 442 queue->buffer[i].state = UVC_BUF_STATE_IDLE;
443 }
440 444
441 queue->flags &= ~UVC_QUEUE_STREAMING; 445 queue->flags &= ~UVC_QUEUE_STREAMING;
442 } 446 }
@@ -488,8 +492,8 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
488 struct uvc_buffer *nextbuf; 492 struct uvc_buffer *nextbuf;
489 unsigned long flags; 493 unsigned long flags;
490 494
491 if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) && 495 if ((queue->flags & UVC_QUEUE_DROP_CORRUPTED) && buf->error) {
492 buf->buf.length != buf->buf.bytesused) { 496 buf->error = 0;
493 buf->state = UVC_BUF_STATE_QUEUED; 497 buf->state = UVC_BUF_STATE_QUEUED;
494 buf->buf.bytesused = 0; 498 buf->buf.bytesused = 0;
495 return buf; 499 return buf;
@@ -497,6 +501,7 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
497 501
498 spin_lock_irqsave(&queue->irqlock, flags); 502 spin_lock_irqsave(&queue->irqlock, flags);
499 list_del(&buf->queue); 503 list_del(&buf->queue);
504 buf->error = 0;
500 buf->state = UVC_BUF_STATE_DONE; 505 buf->state = UVC_BUF_STATE_DONE;
501 if (!list_empty(&queue->irqqueue)) 506 if (!list_empty(&queue->irqqueue))
502 nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer, 507 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,
555 if (urb->iso_frame_desc[i].status < 0) { 555 if (urb->iso_frame_desc[i].status < 0) {
556 uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame " 556 uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame "
557 "lost (%d).\n", urb->iso_frame_desc[i].status); 557 "lost (%d).\n", urb->iso_frame_desc[i].status);
558 /* Mark the buffer as faulty. */
559 if (buf != NULL)
560 buf->error = 1;
558 continue; 561 continue;
559 } 562 }
560 563
@@ -579,8 +582,14 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
579 uvc_video_decode_end(stream, buf, mem, 582 uvc_video_decode_end(stream, buf, mem,
580 urb->iso_frame_desc[i].actual_length); 583 urb->iso_frame_desc[i].actual_length);
581 584
582 if (buf->state == UVC_BUF_STATE_READY) 585 if (buf->state == UVC_BUF_STATE_READY) {
586 if (buf->buf.length != buf->buf.bytesused &&
587 !(stream->cur_format->flags &
588 UVC_FMT_FLAG_COMPRESSED))
589 buf->error = 1;
590
583 buf = uvc_queue_next_buffer(&stream->queue, buf); 591 buf = uvc_queue_next_buffer(&stream->queue, buf);
592 }
584 } 593 }
585} 594}
586 595
@@ -1104,7 +1113,7 @@ int uvc_video_init(struct uvc_streaming *stream)
1104 atomic_set(&stream->active, 0); 1113 atomic_set(&stream->active, 0);
1105 1114
1106 /* Initialize the video buffers queue. */ 1115 /* Initialize the video buffers queue. */
1107 uvc_queue_init(&stream->queue, stream->type); 1116 uvc_queue_init(&stream->queue, stream->type, !uvc_no_drop_param);
1108 1117
1109 /* Alternate setting 0 should be the default, yet the XBox Live Vision 1118 /* Alternate setting 0 should be the default, yet the XBox Live Vision
1110 * Cam (and possibly other devices) crash or otherwise misbehave if 1119 * Cam (and possibly other devices) crash or otherwise misbehave if
@@ -1197,12 +1206,6 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable)
1197 return 0; 1206 return 0;
1198 } 1207 }
1199 1208
1200 if ((stream->cur_format->flags & UVC_FMT_FLAG_COMPRESSED) ||
1201 uvc_no_drop_param)
1202 stream->queue.flags &= ~UVC_QUEUE_DROP_INCOMPLETE;
1203 else
1204 stream->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE;
1205
1206 ret = uvc_queue_enable(&stream->queue, 1); 1209 ret = uvc_queue_enable(&stream->queue, 1);
1207 if (ret < 0) 1210 if (ret < 0)
1208 return ret; 1211 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 {
379 struct list_head queue; 379 struct list_head queue;
380 wait_queue_head_t wait; 380 wait_queue_head_t wait;
381 enum uvc_buffer_state state; 381 enum uvc_buffer_state state;
382 unsigned int error;
382}; 383};
383 384
384#define UVC_QUEUE_STREAMING (1 << 0) 385#define UVC_QUEUE_STREAMING (1 << 0)
385#define UVC_QUEUE_DISCONNECTED (1 << 1) 386#define UVC_QUEUE_DISCONNECTED (1 << 1)
386#define UVC_QUEUE_DROP_INCOMPLETE (1 << 2) 387#define UVC_QUEUE_DROP_CORRUPTED (1 << 2)
387 388
388struct uvc_video_queue { 389struct uvc_video_queue {
389 enum v4l2_buf_type type; 390 enum v4l2_buf_type type;
@@ -562,7 +563,7 @@ extern struct uvc_driver uvc_driver;
562 563
563/* Video buffers queue management. */ 564/* Video buffers queue management. */
564extern void uvc_queue_init(struct uvc_video_queue *queue, 565extern void uvc_queue_init(struct uvc_video_queue *queue,
565 enum v4l2_buf_type type); 566 enum v4l2_buf_type type, int drop_corrupted);
566extern int uvc_alloc_buffers(struct uvc_video_queue *queue, 567extern int uvc_alloc_buffers(struct uvc_video_queue *queue,
567 unsigned int nbuffers, unsigned int buflength); 568 unsigned int nbuffers, unsigned int buflength);
568extern int uvc_free_buffers(struct uvc_video_queue *queue); 569extern int uvc_free_buffers(struct uvc_video_queue *queue);