123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- 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
|