Commit 7dc94047 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

v4l2: fix and cleanup of mmap buffers allocation

Especially fix memory leaks on error.
parent 7e028434
...@@ -96,7 +96,6 @@ error: ...@@ -96,7 +96,6 @@ error:
int InitVideo (access_t *access, int fd) int InitVideo (access_t *access, int fd)
{ {
demux_sys_t *sys = (demux_sys_t *)access->p_sys; demux_sys_t *sys = (demux_sys_t *)access->p_sys;
enum v4l2_buf_type buf_type;
/* Get device capabilites */ /* Get device capabilites */
struct v4l2_capability cap; struct v4l2_capability cap;
...@@ -168,9 +167,10 @@ int InitVideo (access_t *access, int fd) ...@@ -168,9 +167,10 @@ int InitVideo (access_t *access, int fd)
/* Init I/O method */ /* Init I/O method */
if (cap.capabilities & V4L2_CAP_STREAMING) 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; 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 = { struct v4l2_buffer buf = {
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
...@@ -185,7 +185,7 @@ int InitVideo (access_t *access, int fd) ...@@ -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) if (v4l2_ioctl (fd, VIDIOC_STREAMON, &buf_type) < 0)
{ {
msg_Err (access, "cannot start streaming: %m" ); msg_Err (access, "cannot start streaming: %m" );
......
...@@ -430,9 +430,10 @@ static int InitVideo (demux_t *demux, int fd) ...@@ -430,9 +430,10 @@ static int InitVideo (demux_t *demux, int fd)
void *(*entry) (void *); void *(*entry) (void *);
if (caps & V4L2_CAP_STREAMING) 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; 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 = { struct v4l2_buffer buf = {
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
...@@ -494,37 +495,22 @@ void DemuxClose( vlc_object_t *obj ) ...@@ -494,37 +495,22 @@ void DemuxClose( vlc_object_t *obj )
{ {
/* NOTE: Some buggy drivers hang if buffers are not unmapped before /* NOTE: Some buggy drivers hang if buffers are not unmapped before
* streamoff */ * streamoff */
for( unsigned i = 0; i < sys->i_nbuffers; i++ ) for (uint32_t i = 0; i < sys->bufc; i++)
{ {
struct v4l2_buffer buf = { struct v4l2_buffer buf = {
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
.memory = V4L2_MEMORY_MMAP, .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; enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_ioctl( sys->i_fd, VIDIOC_STREAMOFF, &buf_type ); v4l2_ioctl( sys->i_fd, VIDIOC_STREAMOFF, &buf_type );
free (sys->bufv);
break; 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 ); ControlsDeinit( obj, sys->controls );
v4l2_close( fd ); v4l2_close( fd );
free( sys ); free( sys );
......
...@@ -86,9 +86,9 @@ struct demux_sys_t ...@@ -86,9 +86,9 @@ struct demux_sys_t
/* Video */ /* Video */
io_method io; io_method io;
struct buffer_t *p_buffers; struct buffer_t *bufv;
unsigned int i_nbuffers; uint32_t bufc;
#define blocksize i_nbuffers /* HACK HACK */ #define blocksize bufc /* HACK HACK */
uint32_t i_block_flags; uint32_t i_block_flags;
...@@ -110,8 +110,7 @@ int SetupFormat (vlc_object_t *, int, uint32_t, ...@@ -110,8 +110,7 @@ int SetupFormat (vlc_object_t *, int, uint32_t,
struct v4l2_format *, struct v4l2_streamparm *); struct v4l2_format *, struct v4l2_streamparm *);
#define SetupFormat(o,fd,fcc,fmt,p) \ #define SetupFormat(o,fd,fcc,fmt,p) \
SetupFormat(VLC_OBJECT(o),fd,fcc,fmt,p) SetupFormat(VLC_OBJECT(o),fd,fcc,fmt,p)
struct buffer_t *InitMmap (vlc_object_t *, int, uint32_t *);
int InitMmap (vlc_object_t *, demux_sys_t *, int);
block_t* GrabVideo(vlc_object_t *, demux_sys_t *); block_t* GrabVideo(vlc_object_t *, demux_sys_t *);
/* demux.c */ /* demux.c */
......
...@@ -1001,7 +1001,7 @@ block_t* GrabVideo (vlc_object_t *demux, demux_sys_t *sys) ...@@ -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"); msg_Err (demux, "Failed capturing new frame as i>=nbuffers");
return NULL; return NULL;
} }
...@@ -1010,7 +1010,7 @@ block_t* GrabVideo (vlc_object_t *demux, demux_sys_t *sys) ...@@ -1010,7 +1010,7 @@ block_t* GrabVideo (vlc_object_t *demux, demux_sys_t *sys)
block_t *block = block_Alloc (buf.bytesused); block_t *block = block_Alloc (buf.bytesused);
if (unlikely(block == NULL)) if (unlikely(block == NULL))
return 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 */ /* Unlock */
if (v4l2_ioctl (sys->i_fd, VIDIOC_QBUF, &buf) < 0) 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) ...@@ -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 * 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; struct v4l2_requestbuffers req = {
.count = 4,
memset( &req, 0, sizeof(req) ); .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
req.count = 4; .memory = V4L2_MEMORY_MMAP,
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; };
req.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" ); msg_Err (obj, "cannot allocate buffers: %m" );
return -1; return NULL;
} }
if( req.count < 2 ) if (req.count < 2)
{ {
msg_Err( p_demux, "insufficient buffers" ); msg_Err (obj, "cannot allocate enough buffers");
return -1; return NULL;
} }
p_sys->p_buffers = calloc( req.count, sizeof( *p_sys->p_buffers ) ); struct buffer_t *bufv = malloc (req.count * sizeof (*bufv));
if( unlikely(!p_sys->p_buffers) ) if (unlikely(bufv == NULL))
return -1; 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; struct v4l2_buffer buf = {
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
memset( &buf, 0, sizeof(buf) ); .memory = V4L2_MEMORY_MMAP,
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; .index = bufc,
buf.memory = V4L2_MEMORY_MMAP; };
buf.index = p_sys->i_nbuffers;
if( v4l2_ioctl( i_fd, VIDIOC_QUERYBUF, &buf ) < 0 ) if (v4l2_ioctl (fd, VIDIOC_QUERYBUF, &buf) < 0)
{ {
msg_Err( p_demux, "VIDIOC_QUERYBUF: %m" ); msg_Err (obj, "cannot query buffer %"PRIu32": %m", bufc);
return -1; goto error;
} }
p_sys->p_buffers[p_sys->i_nbuffers].length = buf.length; bufv[bufc].start = v4l2_mmap (NULL, buf.length, PROT_READ | PROT_WRITE,
p_sys->p_buffers[p_sys->i_nbuffers].start = MAP_SHARED, fd, buf.m.offset);
v4l2_mmap( NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, i_fd, buf.m.offset ); if (bufv[bufc].start == MAP_FAILED)
if( p_sys->p_buffers[p_sys->i_nbuffers].start == MAP_FAILED )
{ {
msg_Err( p_demux, "mmap failed: %m" ); msg_Err (obj, "cannot map buffer %"PRIu32": %m", bufc);
return -1; 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;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment