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
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.
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.
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.
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
28 [0] http://www.spinics.net/lists/linux-media/msg81515.html
30 Signed-off-by: Olliver Schinagl <o.schinagl@ultimaker.com>
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(-)
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
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)
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;
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)
69 + struct v4l2_buffer buf;
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)
78 for(i = 0; i < NB_BUFFER; i++) {
79 - memset(&vd->buf, 0, sizeof(struct v4l2_buffer));
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));
86 + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
87 + buf.memory = V4L2_MEMORY_MMAP;
88 + ret = xioctl(vd->fd, VIDIOC_QUERYBUF, &buf);
90 perror("Unable to query buffer");
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);
98 vd->mem[i] = mmap(0 /* start anywhere */ ,
99 - vd->buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, vd->fd,
101 + buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, vd->fd,
103 if(vd->mem[i] == MAP_FAILED) {
104 perror("Unable to map buffer");
107 + vd->memlength[i] = buf.length;
109 fprintf(stderr, "Buffer mapped at address %p.\n", vd->mem[i]);
111 @@ -403,11 +407,11 @@ static int init_v4l2(struct vdIn *vd)
114 for(i = 0; i < NB_BUFFER; ++i) {
115 - memset(&vd->buf, 0, sizeof(struct v4l2_buffer));
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));
122 + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
123 + buf.memory = V4L2_MEMORY_MMAP;
124 + ret = xioctl(vd->fd, VIDIOC_QBUF, &buf);
126 perror("Unable to queue buffer");
128 @@ -499,17 +503,18 @@ int memcpy_picture(unsigned char *out, unsigned char *buf, int size)
129 int uvcGrab(struct vdIn *vd)
131 #define HEADERFRAME1 0xaf
132 + struct v4l2_buffer buf;
135 if(vd->streamingState == STREAMING_OFF) {
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;
146 - ret = xioctl(vd->fd, VIDIOC_DQBUF, &vd->buf);
147 + ret = xioctl(vd->fd, VIDIOC_DQBUF, &buf);
149 perror("Unable to dequeue buffer");
151 @@ -517,33 +522,34 @@ int uvcGrab(struct vdIn *vd)
153 switch(vd->formatIn) {
154 case V4L2_PIX_FMT_MJPEG:
155 - if(vd->buf.bytesused <= HEADERFRAME1) {
156 + if(buf.bytesused <= HEADERFRAME1) {
159 fprintf(stderr, "Ignoring empty buffer ...\n");
163 - /* memcpy(vd->tmpbuffer, vd->mem[vd->buf.index], vd->buf.bytesused);
164 + /* memcpy(vd->tmpbuffer, vd->mem[buf.index], buf.bytesused);
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));
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;
180 - fprintf(stderr, "bytes in used %d \n", vd->buf.bytesused);
181 + fprintf(stderr, "bytes in used %d \n", buf.bytesused);
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);
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);
196 @@ -551,7 +557,7 @@ int uvcGrab(struct vdIn *vd)
200 - ret = xioctl(vd->fd, VIDIOC_QBUF, &vd->buf);
201 + ret = xioctl(vd->fd, VIDIOC_QBUF, &buf);
203 perror("Unable to requeue buffer");
205 @@ -947,7 +953,7 @@ int setResolution(struct vdIn *vd, int width, int height)
206 DBG("Unmap buffers\n");
208 for(i = 0; i < NB_BUFFER; i++)
209 - munmap(vd->mem[i], vd->buf.length);
210 + munmap(vd->mem[i], vd->memlength[i]);
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
219 #include <sys/ioctl.h>
220 #include <sys/mman.h>
221 #include <sys/select.h>
222 +#include <sys/time.h>
224 #include <linux/types.h> /* for videodev2.h */
225 #include <linux/videodev2.h>
226 @@ -79,11 +80,12 @@ struct vdIn {
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;
236 + struct timeval tmptimestamp;
237 unsigned char *framebuffer;
238 streaming_state streamingState;