You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

242 lines
9.7 KiB

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