--- /dev/null
+From 19202b54698b343a0207d7e213448e32b8e58fc3 Mon Sep 17 00:00:00 2001
+From: Olliver Schinagl <o.schinagl@ultimaker.com>
+Date: Wed, 29 Oct 2014 09:34:41 +0100
+Subject: [PATCH 1/7] Buffer the bytesused variable from struct v4l2_buffer
+
+Starting with kernel versions 3.16, (DE)Queing of buffers has been fixed
+after it was leaking data for ages. in the struct v4l2_buffer is the
+bytesused element which indicates the size of the buffer. This however
+gets cleared whenever the buffer gets requeued and is thus no longer
+valid.
+
+This patch copies the bytesused variable so it is available until the
+next frame captured again.
+
+Signed-off-by: Olliver Schinagl <o.schinagl@ultimaker.com>
+---
+ plugins/input_uvc/input_uvc.c | 6 +++---
+ plugins/input_uvc/v4l2uvc.c | 2 ++
+ plugins/input_uvc/v4l2uvc.h | 1 +
+ 3 files changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/plugins/input_uvc/input_uvc.c b/plugins/input_uvc/input_uvc.c
+index e6c74fd..64f66cb 100644
+--- a/plugins/input_uvc/input_uvc.c
++++ b/plugins/input_uvc/input_uvc.c
+@@ -482,7 +482,7 @@ void *cam_thread(void *arg)
+ exit(EXIT_FAILURE);
+ }
+
+- //DBG("received frame of size: %d from plugin: %d\n", pcontext->videoIn->buf.bytesused, pcontext->id);
++ //DBG("received frame of size: %d from plugin: %d\n", pcontext->videoIn->tmpbytesused, pcontext->id);
+
+ /*
+ * Workaround for broken, corrupted frames:
+@@ -491,7 +491,7 @@ void *cam_thread(void *arg)
+ * For example a VGA (640x480) webcam picture is normally >= 8kByte large,
+ * corrupted frames are smaller.
+ */
+- if(pcontext->videoIn->buf.bytesused < minimum_size) {
++ if(pcontext->videoIn->tmpbytesused < minimum_size) {
+ DBG("dropping too small frame, assuming it as broken\n");
+ continue;
+ }
+@@ -529,7 +529,7 @@ void *cam_thread(void *arg)
+ } else {
+ #endif
+ //DBG("copying frame from input: %d\n", (int)pcontext->id);
+- pglobal->in[pcontext->id].size = memcpy_picture(pglobal->in[pcontext->id].buf, pcontext->videoIn->tmpbuffer, pcontext->videoIn->buf.bytesused);
++ pglobal->in[pcontext->id].size = memcpy_picture(pglobal->in[pcontext->id].buf, pcontext->videoIn->tmpbuffer, pcontext->videoIn->tmpbytesused);
+ #ifndef NO_LIBJPEG
+ }
+ #endif
+diff --git a/plugins/input_uvc/v4l2uvc.c b/plugins/input_uvc/v4l2uvc.c
+index c5a5aa4..d11510c 100644
+--- a/plugins/input_uvc/v4l2uvc.c
++++ b/plugins/input_uvc/v4l2uvc.c
+@@ -532,6 +532,7 @@ int uvcGrab(struct vdIn *vd)
+ */
+
+ memcpy(vd->tmpbuffer, vd->mem[vd->buf.index], vd->buf.bytesused);
++ vd->tmpbytesused = vd->buf.bytesused;
+
+ if(debug)
+ fprintf(stderr, "bytes in used %d \n", vd->buf.bytesused);
+@@ -570,6 +571,7 @@ int close_v4l2(struct vdIn *vd)
+ if(vd->tmpbuffer)
+ free(vd->tmpbuffer);
+ vd->tmpbuffer = NULL;
++ vd->tmpbytesused = 0;
+ free(vd->framebuffer);
+ vd->framebuffer = NULL;
+ free(vd->videodevice);
+diff --git a/plugins/input_uvc/v4l2uvc.h b/plugins/input_uvc/v4l2uvc.h
+index 022c57e..2c7c8ba 100644
+--- a/plugins/input_uvc/v4l2uvc.h
++++ b/plugins/input_uvc/v4l2uvc.h
+@@ -83,6 +83,7 @@ struct vdIn {
+ struct v4l2_requestbuffers rb;
+ void *mem[NB_BUFFER];
+ unsigned char *tmpbuffer;
++ int tmpbytesused;
+ unsigned char *framebuffer;
+ streaming_state streamingState;
+ int grabmethod;
+--
+1.9.1
+
--- /dev/null
+From 11b28b36a8711b53658e8bbc50435595522f91ba Mon Sep 17 00:00:00 2001
+From: Olliver Schinagl <o.schinagl@ultimaker.com>
+Date: Wed, 29 Oct 2014 11:21:16 +0100
+Subject: [PATCH 2/7] Stop leaking data via struct v4l2_buffer
+
+Before the 3.16 kernel, the v4l2_buffer was leaking data and violating
+its own spec. Since 3.16 this has been corrected and after calling the
+QBUF ioctl, the struct gets cleaned up.
+
+Right now, input_uvc assumes the buffer is valid at all times. This no
+longer being true, this patch removes the v4l2_buffer from the vdIn
+struct. Certain values are still needed outside of this buffer however,
+the length buffer in the buffer array 'mem' and the timestamp. These are
+now stored in the vdIn struct.
+
+All of this is still somewhat hackish, as a) the processing of the image
+should really be done inside the uvcGrab function between the queuing
+and dequeing of the buffers (or separate that into 3 functions, deq, q
+and process and call them from input_uvc). b) we are still copying the
+image using memcpy, which is something we don't really want and defeats
+the purpose of using a mmap in the first place. Changing this however
+requires some heavier re-architecting and in the end, may still not be avoided.
+
+More information about this bug and change can be found on the
+linux-media mailing list[0] with the title uvcvideo fails on 3.16 and
+3.17 kernels.
+
+[0] http://www.spinics.net/lists/linux-media/msg81515.html
+
+Signed-off-by: Olliver Schinagl <o.schinagl@ultimaker.com>
+---
+ plugins/input_uvc/input_uvc.c | 6 ++--
+ plugins/input_uvc/v4l2uvc.c | 64 +++++++++++++++++++++++--------------------
+ plugins/input_uvc/v4l2uvc.h | 4 ++-
+ 3 files changed, 41 insertions(+), 33 deletions(-)
+
+diff --git a/plugins/input_uvc/input_uvc.c b/plugins/input_uvc/input_uvc.c
+index 64f66cb..64ef56c 100644
+--- a/plugins/input_uvc/input_uvc.c
++++ b/plugins/input_uvc/input_uvc.c
+@@ -500,8 +500,8 @@ void *cam_thread(void *arg)
+ if (pcontext->videoIn->soft_framedrop == 1) {
+ unsigned long last = pglobal->in[pcontext->id].timestamp.tv_sec * 1000 +
+ (pglobal->in[pcontext->id].timestamp.tv_usec/1000); // convert to ms
+- unsigned long current = pcontext->videoIn->buf.timestamp.tv_sec * 1000 +
+- pcontext->videoIn->buf.timestamp.tv_usec/1000; // convert to ms
++ unsigned long current = pcontext->videoIn->tmptimestamp.tv_sec * 1000 +
++ pcontext->videoIn->tmptimestamp.tv_usec/1000; // convert to ms
+
+ // if the requested time did not esplashed skip the frame
+ if ((current - last) < pcontext->videoIn->frame_period_time) {
+@@ -543,7 +543,7 @@ void *cam_thread(void *arg)
+ #endif
+
+ /* copy this frame's timestamp to user space */
+- pglobal->in[pcontext->id].timestamp = pcontext->videoIn->buf.timestamp;
++ pglobal->in[pcontext->id].timestamp = pcontext->videoIn->tmptimestamp;
+
+ /* signal fresh_frame */
+ pthread_cond_broadcast(&pglobal->in[pcontext->id].db_update);
+diff --git a/plugins/input_uvc/v4l2uvc.c b/plugins/input_uvc/v4l2uvc.c
+index d11510c..7ec5eec 100644
+--- a/plugins/input_uvc/v4l2uvc.c
++++ b/plugins/input_uvc/v4l2uvc.c
+@@ -217,6 +217,9 @@ static int init_v4l2(struct vdIn *vd)
+ {
+ int i;
+ int ret = 0;
++ struct v4l2_buffer buf;
++
++
+ if((vd->fd = OPEN_VIDEO(vd->videodevice, O_RDWR)) == -1) {
+ perror("ERROR opening V4L interface");
+ DBG("errno: %d", errno);
+@@ -375,26 +378,27 @@ static int init_v4l2(struct vdIn *vd)
+ * map the buffers
+ */
+ for(i = 0; i < NB_BUFFER; i++) {
+- memset(&vd->buf, 0, sizeof(struct v4l2_buffer));
+- vd->buf.index = i;
+- vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+- vd->buf.memory = V4L2_MEMORY_MMAP;
+- ret = xioctl(vd->fd, VIDIOC_QUERYBUF, &vd->buf);
++ memset(&buf, 0, sizeof(struct v4l2_buffer));
++ buf.index = i;
++ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ buf.memory = V4L2_MEMORY_MMAP;
++ ret = xioctl(vd->fd, VIDIOC_QUERYBUF, &buf);
+ if(ret < 0) {
+ perror("Unable to query buffer");
+ goto fatal;
+ }
+
+ if(debug)
+- fprintf(stderr, "length: %u offset: %u\n", vd->buf.length, vd->buf.m.offset);
++ fprintf(stderr, "length: %u offset: %u\n", buf.length, buf.m.offset);
+
+ vd->mem[i] = mmap(0 /* start anywhere */ ,
+- vd->buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, vd->fd,
+- vd->buf.m.offset);
++ buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, vd->fd,
++ buf.m.offset);
+ if(vd->mem[i] == MAP_FAILED) {
+ perror("Unable to map buffer");
+ goto fatal;
+ }
++ vd->memlength[i] = buf.length;
+ if(debug)
+ fprintf(stderr, "Buffer mapped at address %p.\n", vd->mem[i]);
+ }
+@@ -403,11 +407,11 @@ static int init_v4l2(struct vdIn *vd)
+ * Queue the buffers.
+ */
+ for(i = 0; i < NB_BUFFER; ++i) {
+- memset(&vd->buf, 0, sizeof(struct v4l2_buffer));
+- vd->buf.index = i;
+- vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+- vd->buf.memory = V4L2_MEMORY_MMAP;
+- ret = xioctl(vd->fd, VIDIOC_QBUF, &vd->buf);
++ memset(&buf, 0, sizeof(struct v4l2_buffer));
++ buf.index = i;
++ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ buf.memory = V4L2_MEMORY_MMAP;
++ ret = xioctl(vd->fd, VIDIOC_QBUF, &buf);
+ if(ret < 0) {
+ perror("Unable to queue buffer");
+ goto fatal;;
+@@ -499,17 +503,18 @@ int memcpy_picture(unsigned char *out, unsigned char *buf, int size)
+ int uvcGrab(struct vdIn *vd)
+ {
+ #define HEADERFRAME1 0xaf
++ struct v4l2_buffer buf;
+ int ret;
+
+ if(vd->streamingState == STREAMING_OFF) {
+ if(video_enable(vd))
+ goto err;
+ }
+- memset(&vd->buf, 0, sizeof(struct v4l2_buffer));
+- vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+- vd->buf.memory = V4L2_MEMORY_MMAP;
++ memset(&buf, 0, sizeof(struct v4l2_buffer));
++ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ buf.memory = V4L2_MEMORY_MMAP;
+
+- ret = xioctl(vd->fd, VIDIOC_DQBUF, &vd->buf);
++ ret = xioctl(vd->fd, VIDIOC_DQBUF, &buf);
+ if(ret < 0) {
+ perror("Unable to dequeue buffer");
+ goto err;
+@@ -517,33 +522,34 @@ int uvcGrab(struct vdIn *vd)
+
+ switch(vd->formatIn) {
+ case V4L2_PIX_FMT_MJPEG:
+- if(vd->buf.bytesused <= HEADERFRAME1) {
++ if(buf.bytesused <= HEADERFRAME1) {
+ /* Prevent crash
+ * on empty image */
+ fprintf(stderr, "Ignoring empty buffer ...\n");
+ return 0;
+ }
+
+- /* memcpy(vd->tmpbuffer, vd->mem[vd->buf.index], vd->buf.bytesused);
++ /* memcpy(vd->tmpbuffer, vd->mem[buf.index], buf.bytesused);
+
+- memcpy (vd->tmpbuffer, vd->mem[vd->buf.index], HEADERFRAME1);
++ memcpy (vd->tmpbuffer, vd->mem[buf.index], HEADERFRAME1);
+ memcpy (vd->tmpbuffer + HEADERFRAME1, dht_data, sizeof(dht_data));
+- memcpy (vd->tmpbuffer + HEADERFRAME1 + sizeof(dht_data), vd->mem[vd->buf.index] + HEADERFRAME1, (vd->buf.bytesused - HEADERFRAME1));
++ memcpy (vd->tmpbuffer + HEADERFRAME1 + sizeof(dht_data), vd->mem[buf.index] + HEADERFRAME1, (buf.bytesused - HEADERFRAME1));
+ */
+
+- memcpy(vd->tmpbuffer, vd->mem[vd->buf.index], vd->buf.bytesused);
+- vd->tmpbytesused = vd->buf.bytesused;
++ memcpy(vd->tmpbuffer, vd->mem[buf.index], buf.bytesused);
++ vd->tmpbytesused = buf.bytesused;
++ vd->tmptimestamp = buf.timestamp;
+
+ if(debug)
+- fprintf(stderr, "bytes in used %d \n", vd->buf.bytesused);
++ fprintf(stderr, "bytes in used %d \n", buf.bytesused);
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_RGB24:
+- if(vd->buf.bytesused > vd->framesizeIn)
+- memcpy(vd->framebuffer, vd->mem[vd->buf.index], (size_t) vd->framesizeIn);
++ if(buf.bytesused > vd->framesizeIn)
++ memcpy(vd->framebuffer, vd->mem[buf.index], (size_t) vd->framesizeIn);
+ else
+- memcpy(vd->framebuffer, vd->mem[vd->buf.index], (size_t) vd->buf.bytesused);
++ memcpy(vd->framebuffer, vd->mem[buf.index], (size_t) buf.bytesused);
+ break;
+
+ default:
+@@ -551,7 +557,7 @@ int uvcGrab(struct vdIn *vd)
+ break;
+ }
+
+- ret = xioctl(vd->fd, VIDIOC_QBUF, &vd->buf);
++ ret = xioctl(vd->fd, VIDIOC_QBUF, &buf);
+ if(ret < 0) {
+ perror("Unable to requeue buffer");
+ goto err;
+@@ -947,7 +953,7 @@ int setResolution(struct vdIn *vd, int width, int height)
+ DBG("Unmap buffers\n");
+ int i;
+ for(i = 0; i < NB_BUFFER; i++)
+- munmap(vd->mem[i], vd->buf.length);
++ munmap(vd->mem[i], vd->memlength[i]);
+
+ if(CLOSE_VIDEO(vd->fd) == 0) {
+ DBG("Device closed successfully\n");
+diff --git a/plugins/input_uvc/v4l2uvc.h b/plugins/input_uvc/v4l2uvc.h
+index 2c7c8ba..e625957 100644
+--- a/plugins/input_uvc/v4l2uvc.h
++++ b/plugins/input_uvc/v4l2uvc.h
+@@ -35,6 +35,7 @@
+ #include <sys/ioctl.h>
+ #include <sys/mman.h>
+ #include <sys/select.h>
++#include <sys/time.h>
+
+ #include <linux/types.h> /* for videodev2.h */
+ #include <linux/videodev2.h>
+@@ -79,11 +80,12 @@ struct vdIn {
+ char *pictName;
+ struct v4l2_capability cap;
+ struct v4l2_format fmt;
+- struct v4l2_buffer buf;
+ struct v4l2_requestbuffers rb;
+ void *mem[NB_BUFFER];
++ int memlength[NB_BUFFER];
+ unsigned char *tmpbuffer;
+ int tmpbytesused;
++ struct timeval tmptimestamp;
+ unsigned char *framebuffer;
+ streaming_state streamingState;
+ int grabmethod;
+--
+1.9.1
+