lede-packages-rs

git clone git://archive.git.mtrnord.blog/MTRNord/lede-packages-rs.git
Log | Files | Refs | README | LICENSE

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