041-Stop-leaking-data-via-struct-v4l2_buffer.patch (9912B)
1 From 11b28b36a8711b53658e8bbc50435595522f91ba Mon Sep 17 00:00:00 2001 2 From: Olliver Schinagl <o.schinagl@ultimaker.com> 3 Date: Wed, 29 Oct 2014 11:21:16 +0100 4 Subject: [PATCH 2/7] Stop leaking data via struct v4l2_buffer 5 6 Before the 3.16 kernel, the v4l2_buffer was leaking data and violating 7 its own spec. Since 3.16 this has been corrected and after calling the 8 QBUF ioctl, the struct gets cleaned up. 9 10 Right now, input_uvc assumes the buffer is valid at all times. This no 11 longer being true, this patch removes the v4l2_buffer from the vdIn 12 struct. Certain values are still needed outside of this buffer however, 13 the length buffer in the buffer array 'mem' and the timestamp. These are 14 now stored in the vdIn struct. 15 16 All of this is still somewhat hackish, as a) the processing of the image 17 should really be done inside the uvcGrab function between the queuing 18 and dequeing of the buffers (or separate that into 3 functions, deq, q 19 and process and call them from input_uvc). b) we are still copying the 20 image using memcpy, which is something we don't really want and defeats 21 the purpose of using a mmap in the first place. Changing this however 22 requires some heavier re-architecting and in the end, may still not be avoided. 23 24 More information about this bug and change can be found on the 25 linux-media mailing list[0] with the title uvcvideo fails on 3.16 and 26 3.17 kernels. 27 28 [0] http://www.spinics.net/lists/linux-media/msg81515.html 29 30 Signed-off-by: Olliver Schinagl <o.schinagl@ultimaker.com> 31 --- 32 plugins/input_uvc/input_uvc.c | 6 ++-- 33 plugins/input_uvc/v4l2uvc.c | 64 +++++++++++++++++++++++-------------------- 34 plugins/input_uvc/v4l2uvc.h | 4 ++- 35 3 files changed, 41 insertions(+), 33 deletions(-) 36 37 diff --git a/plugins/input_uvc/input_uvc.c b/plugins/input_uvc/input_uvc.c 38 index 64f66cb..64ef56c 100644 39 --- a/plugins/input_uvc/input_uvc.c 40 +++ b/plugins/input_uvc/input_uvc.c 41 @@ -500,8 +500,8 @@ void *cam_thread(void *arg) 42 if (pcontext->videoIn->soft_framedrop == 1) { 43 unsigned long last = pglobal->in[pcontext->id].timestamp.tv_sec * 1000 + 44 (pglobal->in[pcontext->id].timestamp.tv_usec/1000); // convert to ms 45 - unsigned long current = pcontext->videoIn->buf.timestamp.tv_sec * 1000 + 46 - pcontext->videoIn->buf.timestamp.tv_usec/1000; // convert to ms 47 + unsigned long current = pcontext->videoIn->tmptimestamp.tv_sec * 1000 + 48 + pcontext->videoIn->tmptimestamp.tv_usec/1000; // convert to ms 49 50 // if the requested time did not esplashed skip the frame 51 if ((current - last) < pcontext->videoIn->frame_period_time) { 52 @@ -543,7 +543,7 @@ void *cam_thread(void *arg) 53 #endif 54 55 /* copy this frame's timestamp to user space */ 56 - pglobal->in[pcontext->id].timestamp = pcontext->videoIn->buf.timestamp; 57 + pglobal->in[pcontext->id].timestamp = pcontext->videoIn->tmptimestamp; 58 59 /* signal fresh_frame */ 60 pthread_cond_broadcast(&pglobal->in[pcontext->id].db_update); 61 diff --git a/plugins/input_uvc/v4l2uvc.c b/plugins/input_uvc/v4l2uvc.c 62 index d11510c..7ec5eec 100644 63 --- a/plugins/input_uvc/v4l2uvc.c 64 +++ b/plugins/input_uvc/v4l2uvc.c 65 @@ -217,6 +217,9 @@ static int init_v4l2(struct vdIn *vd) 66 { 67 int i; 68 int ret = 0; 69 + struct v4l2_buffer buf; 70 + 71 + 72 if((vd->fd = OPEN_VIDEO(vd->videodevice, O_RDWR)) == -1) { 73 perror("ERROR opening V4L interface"); 74 DBG("errno: %d", errno); 75 @@ -375,26 +378,27 @@ static int init_v4l2(struct vdIn *vd) 76 * map the buffers 77 */ 78 for(i = 0; i < NB_BUFFER; i++) { 79 - memset(&vd->buf, 0, sizeof(struct v4l2_buffer)); 80 - vd->buf.index = i; 81 - vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 82 - vd->buf.memory = V4L2_MEMORY_MMAP; 83 - ret = xioctl(vd->fd, VIDIOC_QUERYBUF, &vd->buf); 84 + memset(&buf, 0, sizeof(struct v4l2_buffer)); 85 + buf.index = i; 86 + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 87 + buf.memory = V4L2_MEMORY_MMAP; 88 + ret = xioctl(vd->fd, VIDIOC_QUERYBUF, &buf); 89 if(ret < 0) { 90 perror("Unable to query buffer"); 91 goto fatal; 92 } 93 94 if(debug) 95 - fprintf(stderr, "length: %u offset: %u\n", vd->buf.length, vd->buf.m.offset); 96 + fprintf(stderr, "length: %u offset: %u\n", buf.length, buf.m.offset); 97 98 vd->mem[i] = mmap(0 /* start anywhere */ , 99 - vd->buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, vd->fd, 100 - vd->buf.m.offset); 101 + buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, vd->fd, 102 + buf.m.offset); 103 if(vd->mem[i] == MAP_FAILED) { 104 perror("Unable to map buffer"); 105 goto fatal; 106 } 107 + vd->memlength[i] = buf.length; 108 if(debug) 109 fprintf(stderr, "Buffer mapped at address %p.\n", vd->mem[i]); 110 } 111 @@ -403,11 +407,11 @@ static int init_v4l2(struct vdIn *vd) 112 * Queue the buffers. 113 */ 114 for(i = 0; i < NB_BUFFER; ++i) { 115 - memset(&vd->buf, 0, sizeof(struct v4l2_buffer)); 116 - vd->buf.index = i; 117 - vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 118 - vd->buf.memory = V4L2_MEMORY_MMAP; 119 - ret = xioctl(vd->fd, VIDIOC_QBUF, &vd->buf); 120 + memset(&buf, 0, sizeof(struct v4l2_buffer)); 121 + buf.index = i; 122 + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 123 + buf.memory = V4L2_MEMORY_MMAP; 124 + ret = xioctl(vd->fd, VIDIOC_QBUF, &buf); 125 if(ret < 0) { 126 perror("Unable to queue buffer"); 127 goto fatal;; 128 @@ -499,17 +503,18 @@ int memcpy_picture(unsigned char *out, unsigned char *buf, int size) 129 int uvcGrab(struct vdIn *vd) 130 { 131 #define HEADERFRAME1 0xaf 132 + struct v4l2_buffer buf; 133 int ret; 134 135 if(vd->streamingState == STREAMING_OFF) { 136 if(video_enable(vd)) 137 goto err; 138 } 139 - memset(&vd->buf, 0, sizeof(struct v4l2_buffer)); 140 - vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 141 - vd->buf.memory = V4L2_MEMORY_MMAP; 142 + memset(&buf, 0, sizeof(struct v4l2_buffer)); 143 + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 144 + buf.memory = V4L2_MEMORY_MMAP; 145 146 - ret = xioctl(vd->fd, VIDIOC_DQBUF, &vd->buf); 147 + ret = xioctl(vd->fd, VIDIOC_DQBUF, &buf); 148 if(ret < 0) { 149 perror("Unable to dequeue buffer"); 150 goto err; 151 @@ -517,33 +522,34 @@ int uvcGrab(struct vdIn *vd) 152 153 switch(vd->formatIn) { 154 case V4L2_PIX_FMT_MJPEG: 155 - if(vd->buf.bytesused <= HEADERFRAME1) { 156 + if(buf.bytesused <= HEADERFRAME1) { 157 /* Prevent crash 158 * on empty image */ 159 fprintf(stderr, "Ignoring empty buffer ...\n"); 160 return 0; 161 } 162 163 - /* memcpy(vd->tmpbuffer, vd->mem[vd->buf.index], vd->buf.bytesused); 164 + /* memcpy(vd->tmpbuffer, vd->mem[buf.index], buf.bytesused); 165 166 - memcpy (vd->tmpbuffer, vd->mem[vd->buf.index], HEADERFRAME1); 167 + memcpy (vd->tmpbuffer, vd->mem[buf.index], HEADERFRAME1); 168 memcpy (vd->tmpbuffer + HEADERFRAME1, dht_data, sizeof(dht_data)); 169 - memcpy (vd->tmpbuffer + HEADERFRAME1 + sizeof(dht_data), vd->mem[vd->buf.index] + HEADERFRAME1, (vd->buf.bytesused - HEADERFRAME1)); 170 + memcpy (vd->tmpbuffer + HEADERFRAME1 + sizeof(dht_data), vd->mem[buf.index] + HEADERFRAME1, (buf.bytesused - HEADERFRAME1)); 171 */ 172 173 - memcpy(vd->tmpbuffer, vd->mem[vd->buf.index], vd->buf.bytesused); 174 - vd->tmpbytesused = vd->buf.bytesused; 175 + memcpy(vd->tmpbuffer, vd->mem[buf.index], buf.bytesused); 176 + vd->tmpbytesused = buf.bytesused; 177 + vd->tmptimestamp = buf.timestamp; 178 179 if(debug) 180 - fprintf(stderr, "bytes in used %d \n", vd->buf.bytesused); 181 + fprintf(stderr, "bytes in used %d \n", buf.bytesused); 182 break; 183 case V4L2_PIX_FMT_RGB565: 184 case V4L2_PIX_FMT_YUYV: 185 case V4L2_PIX_FMT_RGB24: 186 - if(vd->buf.bytesused > vd->framesizeIn) 187 - memcpy(vd->framebuffer, vd->mem[vd->buf.index], (size_t) vd->framesizeIn); 188 + if(buf.bytesused > vd->framesizeIn) 189 + memcpy(vd->framebuffer, vd->mem[buf.index], (size_t) vd->framesizeIn); 190 else 191 - memcpy(vd->framebuffer, vd->mem[vd->buf.index], (size_t) vd->buf.bytesused); 192 + memcpy(vd->framebuffer, vd->mem[buf.index], (size_t) buf.bytesused); 193 break; 194 195 default: 196 @@ -551,7 +557,7 @@ int uvcGrab(struct vdIn *vd) 197 break; 198 } 199 200 - ret = xioctl(vd->fd, VIDIOC_QBUF, &vd->buf); 201 + ret = xioctl(vd->fd, VIDIOC_QBUF, &buf); 202 if(ret < 0) { 203 perror("Unable to requeue buffer"); 204 goto err; 205 @@ -947,7 +953,7 @@ int setResolution(struct vdIn *vd, int width, int height) 206 DBG("Unmap buffers\n"); 207 int i; 208 for(i = 0; i < NB_BUFFER; i++) 209 - munmap(vd->mem[i], vd->buf.length); 210 + munmap(vd->mem[i], vd->memlength[i]); 211 212 if(CLOSE_VIDEO(vd->fd) == 0) { 213 DBG("Device closed successfully\n"); 214 diff --git a/plugins/input_uvc/v4l2uvc.h b/plugins/input_uvc/v4l2uvc.h 215 index 2c7c8ba..e625957 100644 216 --- a/plugins/input_uvc/v4l2uvc.h 217 +++ b/plugins/input_uvc/v4l2uvc.h 218 @@ -35,6 +35,7 @@ 219 #include <sys/ioctl.h> 220 #include <sys/mman.h> 221 #include <sys/select.h> 222 +#include <sys/time.h> 223 224 #include <linux/types.h> /* for videodev2.h */ 225 #include <linux/videodev2.h> 226 @@ -79,11 +80,12 @@ struct vdIn { 227 char *pictName; 228 struct v4l2_capability cap; 229 struct v4l2_format fmt; 230 - struct v4l2_buffer buf; 231 struct v4l2_requestbuffers rb; 232 void *mem[NB_BUFFER]; 233 + int memlength[NB_BUFFER]; 234 unsigned char *tmpbuffer; 235 int tmpbytesused; 236 + struct timeval tmptimestamp; 237 unsigned char *framebuffer; 238 streaming_state streamingState; 239 int grabmethod; 240 -- 241 1.9.1 242