Browse Source

mjpg-streamer: fix compatibility with new kernels (>=3.16)

input_uvc was broken with new kernel update

patch source: https://github.com/oliv3r/mjpg-streamer

Tested on ar71xx with Logitech C170

Signed-off-by: Mantas Pucka <mantas@8devices.com>
Mantas Pucka 10 years ago
parent
commit
b17a973f14

+ 1
- 1
multimedia/mjpg-streamer/Makefile View File

@@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk
10 10
 PKG_NAME:=mjpg-streamer
11 11
 PKG_REV:=182
12 12
 PKG_VERSION:=r$(PKG_REV)
13
-PKG_RELEASE:=5
13
+PKG_RELEASE:=6
14 14
 PKG_MAINTAINER:=Roger D <rogerdammit@gmail.com>
15 15
 
16 16
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).1.tar.bz2

+ 87
- 0
multimedia/mjpg-streamer/patches/040-Buffer-the-bytesused-variable-from-struct-v4l2_buffe.patch View File

@@ -0,0 +1,87 @@
1
+From 19202b54698b343a0207d7e213448e32b8e58fc3 Mon Sep 17 00:00:00 2001
2
+From: Olliver Schinagl <o.schinagl@ultimaker.com>
3
+Date: Wed, 29 Oct 2014 09:34:41 +0100
4
+Subject: [PATCH 1/7] Buffer the bytesused variable from struct v4l2_buffer
5
+
6
+Starting with kernel versions 3.16, (DE)Queing of buffers has been fixed
7
+after it was leaking data for ages. in the struct v4l2_buffer is the
8
+bytesused element which indicates the size of the buffer. This however
9
+gets cleared whenever the buffer gets requeued and is thus no longer
10
+valid.
11
+
12
+This patch copies the bytesused variable so it is available until the
13
+next frame captured again.
14
+
15
+Signed-off-by: Olliver Schinagl <o.schinagl@ultimaker.com>
16
+---
17
+ plugins/input_uvc/input_uvc.c | 6 +++---
18
+ plugins/input_uvc/v4l2uvc.c   | 2 ++
19
+ plugins/input_uvc/v4l2uvc.h   | 1 +
20
+ 3 files changed, 6 insertions(+), 3 deletions(-)
21
+
22
+diff --git a/plugins/input_uvc/input_uvc.c b/plugins/input_uvc/input_uvc.c
23
+index e6c74fd..64f66cb 100644
24
+--- a/plugins/input_uvc/input_uvc.c
25
++++ b/plugins/input_uvc/input_uvc.c
26
+@@ -482,7 +482,7 @@ void *cam_thread(void *arg)
27
+             exit(EXIT_FAILURE);
28
+         }
29
+ 
30
+-        //DBG("received frame of size: %d from plugin: %d\n", pcontext->videoIn->buf.bytesused, pcontext->id);
31
++        //DBG("received frame of size: %d from plugin: %d\n", pcontext->videoIn->tmpbytesused, pcontext->id);
32
+ 
33
+         /*
34
+          * Workaround for broken, corrupted frames:
35
+@@ -491,7 +491,7 @@ void *cam_thread(void *arg)
36
+          * For example a VGA (640x480) webcam picture is normally >= 8kByte large,
37
+          * corrupted frames are smaller.
38
+          */
39
+-        if(pcontext->videoIn->buf.bytesused < minimum_size) {
40
++        if(pcontext->videoIn->tmpbytesused < minimum_size) {
41
+             DBG("dropping too small frame, assuming it as broken\n");
42
+             continue;
43
+         }
44
+@@ -529,7 +529,7 @@ void *cam_thread(void *arg)
45
+         } else {
46
+         #endif
47
+             //DBG("copying frame from input: %d\n", (int)pcontext->id);
48
+-            pglobal->in[pcontext->id].size = memcpy_picture(pglobal->in[pcontext->id].buf, pcontext->videoIn->tmpbuffer, pcontext->videoIn->buf.bytesused);
49
++            pglobal->in[pcontext->id].size = memcpy_picture(pglobal->in[pcontext->id].buf, pcontext->videoIn->tmpbuffer, pcontext->videoIn->tmpbytesused);
50
+         #ifndef NO_LIBJPEG
51
+         }
52
+         #endif
53
+diff --git a/plugins/input_uvc/v4l2uvc.c b/plugins/input_uvc/v4l2uvc.c
54
+index c5a5aa4..d11510c 100644
55
+--- a/plugins/input_uvc/v4l2uvc.c
56
++++ b/plugins/input_uvc/v4l2uvc.c
57
+@@ -532,6 +532,7 @@ int uvcGrab(struct vdIn *vd)
58
+         */
59
+ 
60
+         memcpy(vd->tmpbuffer, vd->mem[vd->buf.index], vd->buf.bytesused);
61
++	vd->tmpbytesused = vd->buf.bytesused;
62
+ 
63
+         if(debug)
64
+             fprintf(stderr, "bytes in used %d \n", vd->buf.bytesused);
65
+@@ -570,6 +571,7 @@ int close_v4l2(struct vdIn *vd)
66
+     if(vd->tmpbuffer)
67
+         free(vd->tmpbuffer);
68
+     vd->tmpbuffer = NULL;
69
++    vd->tmpbytesused = 0;
70
+     free(vd->framebuffer);
71
+     vd->framebuffer = NULL;
72
+     free(vd->videodevice);
73
+diff --git a/plugins/input_uvc/v4l2uvc.h b/plugins/input_uvc/v4l2uvc.h
74
+index 022c57e..2c7c8ba 100644
75
+--- a/plugins/input_uvc/v4l2uvc.h
76
++++ b/plugins/input_uvc/v4l2uvc.h
77
+@@ -83,6 +83,7 @@ struct vdIn {
78
+     struct v4l2_requestbuffers rb;
79
+     void *mem[NB_BUFFER];
80
+     unsigned char *tmpbuffer;
81
++    int tmpbytesused;
82
+     unsigned char *framebuffer;
83
+     streaming_state streamingState;
84
+     int grabmethod;
85
+-- 
86
+1.9.1
87
+

+ 242
- 0
multimedia/mjpg-streamer/patches/041-Stop-leaking-data-via-struct-v4l2_buffer.patch View File

@@ -0,0 +1,242 @@
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
+