[vlc-commits] v4l2: fix and cleanup of mmap buffers allocation

Rémi Denis-Courmont git at videolan.org
Wed Apr 11 18:20:26 CEST 2012


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Wed Apr 11 19:04:56 2012 +0300| [7dc9404731ccf71556c63b1082ea41433715560a] | committer: Rémi Denis-Courmont

v4l2: fix and cleanup of mmap buffers allocation

Especially fix memory leaks on error.

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=7dc9404731ccf71556c63b1082ea41433715560a
---

 modules/access/v4l2/access.c |    8 ++--
 modules/access/v4l2/demux.c  |   28 ++++-----------
 modules/access/v4l2/v4l2.h   |    9 ++---
 modules/access/v4l2/video.c  |   79 +++++++++++++++++++++++-------------------
 4 files changed, 58 insertions(+), 66 deletions(-)

diff --git a/modules/access/v4l2/access.c b/modules/access/v4l2/access.c
index 2f7788d..1ca4e9a 100644
--- a/modules/access/v4l2/access.c
+++ b/modules/access/v4l2/access.c
@@ -96,7 +96,6 @@ error:
 int InitVideo (access_t *access, int fd)
 {
     demux_sys_t *sys = (demux_sys_t *)access->p_sys;
-    enum v4l2_buf_type buf_type;
 
     /* Get device capabilites */
     struct v4l2_capability cap;
@@ -168,9 +167,10 @@ int InitVideo (access_t *access, int fd)
     /* Init I/O method */
     if (cap.capabilities & V4L2_CAP_STREAMING)
     {
-        if (InitMmap (VLC_OBJECT(access), sys, fd))
+        sys->bufv = InitMmap (VLC_OBJECT(access), fd, &sys->bufc);
+        if (sys->bufv == NULL)
             return -1;
-        for (unsigned int i = 0; i < sys->i_nbuffers; i++)
+        for (uint32_t i = 0; i < sys->bufc; i++)
         {
             struct v4l2_buffer buf = {
                 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
@@ -185,7 +185,7 @@ int InitVideo (access_t *access, int fd)
             }
         }
 
-        buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
         if (v4l2_ioctl (fd, VIDIOC_STREAMON, &buf_type) < 0)
         {
             msg_Err (access, "cannot start streaming: %m" );
diff --git a/modules/access/v4l2/demux.c b/modules/access/v4l2/demux.c
index 8c14920..8e28e22 100644
--- a/modules/access/v4l2/demux.c
+++ b/modules/access/v4l2/demux.c
@@ -430,9 +430,10 @@ static int InitVideo (demux_t *demux, int fd)
     void *(*entry) (void *);
     if (caps & V4L2_CAP_STREAMING)
     {
-        if (InitMmap (VLC_OBJECT(demux), sys, fd))
+        sys->bufv = InitMmap (VLC_OBJECT(demux), fd, &sys->bufc);
+        if (sys->bufv == NULL)
             return -1;
-        for (unsigned int i = 0; i < sys->i_nbuffers; i++)
+        for (uint32_t i = 0; i < sys->bufc; i++)
         {
             struct v4l2_buffer buf = {
                 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
@@ -494,37 +495,22 @@ void DemuxClose( vlc_object_t *obj )
         {
             /* NOTE: Some buggy drivers hang if buffers are not unmapped before
              * streamoff */
-            for( unsigned i = 0; i < sys->i_nbuffers; i++ )
+            for (uint32_t i = 0; i < sys->bufc; i++)
             {
                 struct v4l2_buffer buf = {
                     .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
                     .memory = V4L2_MEMORY_MMAP,
                 };
-                v4l2_ioctl( fd, VIDIOC_DQBUF, &buf );
+                v4l2_ioctl (fd, VIDIOC_DQBUF, &buf);
+                v4l2_munmap (sys->bufv[i].start, sys->bufv[i].length);
             }
             enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
             v4l2_ioctl( sys->i_fd, VIDIOC_STREAMOFF, &buf_type );
+            free (sys->bufv);
             break;
         }
     }
 
-    /* Free Video Buffers */
-    if( sys->p_buffers ) {
-        switch( sys->io )
-        {
-        case IO_METHOD_READ:
-            free( sys->p_buffers[0].start );
-            break;
-
-        case IO_METHOD_MMAP:
-            for( unsigned i = 0; i < sys->i_nbuffers; ++i )
-                v4l2_munmap( sys->p_buffers[i].start,
-                             sys->p_buffers[i].length );
-            break;
-        }
-        free( sys->p_buffers );
-    }
-
     ControlsDeinit( obj, sys->controls );
     v4l2_close( fd );
     free( sys );
diff --git a/modules/access/v4l2/v4l2.h b/modules/access/v4l2/v4l2.h
index db9c8ae..3fe47a9 100644
--- a/modules/access/v4l2/v4l2.h
+++ b/modules/access/v4l2/v4l2.h
@@ -86,9 +86,9 @@ struct demux_sys_t
     /* Video */
     io_method io;
 
-    struct buffer_t *p_buffers;
-    unsigned int i_nbuffers;
-#define blocksize i_nbuffers /* HACK HACK */
+    struct buffer_t *bufv;
+    uint32_t bufc;
+#define blocksize bufc /* HACK HACK */
 
     uint32_t i_block_flags;
 
@@ -110,8 +110,7 @@ int SetupFormat (vlc_object_t *, int, uint32_t,
                  struct v4l2_format *, struct v4l2_streamparm *);
 #define SetupFormat(o,fd,fcc,fmt,p) \
         SetupFormat(VLC_OBJECT(o),fd,fcc,fmt,p)
-
-int InitMmap (vlc_object_t *, demux_sys_t *, int);
+struct buffer_t *InitMmap (vlc_object_t *, int, uint32_t *);
 block_t* GrabVideo(vlc_object_t *, demux_sys_t *);
 
 /* demux.c */
diff --git a/modules/access/v4l2/video.c b/modules/access/v4l2/video.c
index 9d8afab..8a5a740 100644
--- a/modules/access/v4l2/video.c
+++ b/modules/access/v4l2/video.c
@@ -1001,7 +1001,7 @@ block_t* GrabVideo (vlc_object_t *demux, demux_sys_t *sys)
         }
     }
 
-    if (buf.index >= sys->i_nbuffers) {
+    if (buf.index >= sys->bufc) {
         msg_Err (demux, "Failed capturing new frame as i>=nbuffers");
         return NULL;
     }
@@ -1010,7 +1010,7 @@ block_t* GrabVideo (vlc_object_t *demux, demux_sys_t *sys)
     block_t *block = block_Alloc (buf.bytesused);
     if (unlikely(block == NULL))
         return NULL;
-    memcpy (block->p_buffer, sys->p_buffers[buf.index].start, buf.bytesused);
+    memcpy (block->p_buffer, sys->bufv[buf.index].start, buf.bytesused);
 
     /* Unlock */
     if (v4l2_ioctl (sys->i_fd, VIDIOC_QBUF, &buf) < 0)
@@ -1025,56 +1025,63 @@ block_t* GrabVideo (vlc_object_t *demux, demux_sys_t *sys)
 /*****************************************************************************
  * Helper function to initalise video IO using the mmap method
  *****************************************************************************/
-int InitMmap( vlc_object_t *p_demux, demux_sys_t *p_sys, int i_fd )
+struct buffer_t *InitMmap (vlc_object_t *obj, int fd, uint32_t *restrict n)
 {
-    struct v4l2_requestbuffers req;
-
-    memset( &req, 0, sizeof(req) );
-    req.count = 4;
-    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-    req.memory = V4L2_MEMORY_MMAP;
+    struct v4l2_requestbuffers req = {
+        .count = 4,
+        .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+        .memory = V4L2_MEMORY_MMAP,
+    };
 
-    if( v4l2_ioctl( i_fd, VIDIOC_REQBUFS, &req ) < 0 )
+    if (v4l2_ioctl (fd, VIDIOC_REQBUFS, &req) < 0)
     {
-        msg_Err( p_demux, "device does not support mmap I/O" );
-        return -1;
+        msg_Err (obj, "cannot allocate buffers: %m" );
+        return NULL;
     }
 
-    if( req.count < 2 )
+    if (req.count < 2)
     {
-        msg_Err( p_demux, "insufficient buffers" );
-        return -1;
+        msg_Err (obj, "cannot allocate enough buffers");
+        return NULL;
     }
 
-    p_sys->p_buffers = calloc( req.count, sizeof( *p_sys->p_buffers ) );
-    if( unlikely(!p_sys->p_buffers) )
-        return -1;
+    struct buffer_t *bufv = malloc (req.count * sizeof (*bufv));
+    if (unlikely(bufv == NULL))
+        return NULL;
 
-    for( p_sys->i_nbuffers = 0; p_sys->i_nbuffers < req.count; ++p_sys->i_nbuffers )
+    uint32_t bufc;
+    for (bufc = 0; bufc < req.count; bufc++)
     {
-        struct v4l2_buffer buf;
-
-        memset( &buf, 0, sizeof(buf) );
-        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-        buf.memory = V4L2_MEMORY_MMAP;
-        buf.index = p_sys->i_nbuffers;
+        struct v4l2_buffer buf = {
+            .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+            .memory = V4L2_MEMORY_MMAP,
+            .index = bufc,
+        };
 
-        if( v4l2_ioctl( i_fd, VIDIOC_QUERYBUF, &buf ) < 0 )
+        if (v4l2_ioctl (fd, VIDIOC_QUERYBUF, &buf) < 0)
         {
-            msg_Err( p_demux, "VIDIOC_QUERYBUF: %m" );
-            return -1;
+            msg_Err (obj, "cannot query buffer %"PRIu32": %m", bufc);
+            goto error;
         }
 
-        p_sys->p_buffers[p_sys->i_nbuffers].length = buf.length;
-        p_sys->p_buffers[p_sys->i_nbuffers].start =
-            v4l2_mmap( NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, i_fd, buf.m.offset );
-
-        if( p_sys->p_buffers[p_sys->i_nbuffers].start == MAP_FAILED )
+        bufv[bufc].start = v4l2_mmap (NULL, buf.length, PROT_READ | PROT_WRITE,
+                                      MAP_SHARED, fd, buf.m.offset);
+        if (bufv[bufc].start == MAP_FAILED)
         {
-            msg_Err( p_demux, "mmap failed: %m" );
-            return -1;
+            msg_Err (obj, "cannot map buffer %"PRIu32": %m", bufc);
+            goto error;
         }
+        bufv[bufc].length = buf.length;
     }
 
-    return 0;
+    *n = bufc;
+    return bufv;
+error:
+    while (bufc > 0)
+    {
+        bufc--;
+        v4l2_munmap (bufv[bufc].start, bufv[bufc].length);
+    }
+    free (bufv);
+    return NULL;
 }



More information about the vlc-commits mailing list