Commit 8d9f4bb6 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

v4l2: factorize and simplify mmap() initialization

Also fix huge memory leak in v4l2 access (buffers never released).
parent e59a7006
...@@ -180,36 +180,16 @@ int InitVideo (access_t *access, int fd) ...@@ -180,36 +180,16 @@ 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)
{ {
sys->bufv = InitMmap (VLC_OBJECT(access), fd, &sys->bufc); sys->bufc = 4;
sys->bufv = StartMmap (VLC_OBJECT(access), fd, &sys->bufc);
if (sys->bufv == NULL) if (sys->bufv == NULL)
return -1; return -1;
for (uint32_t i = 0; i < sys->bufc; i++)
{
struct v4l2_buffer buf = {
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
.memory = V4L2_MEMORY_MMAP,
.index = i,
};
if (v4l2_ioctl (fd, VIDIOC_QBUF, &buf) < 0)
{
msg_Err (access, "cannot queue buffer: %m");
return -1;
}
}
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" );
return -1;
}
access->pf_block = AccessRead; access->pf_block = AccessRead;
} }
else if (cap.capabilities & V4L2_CAP_READWRITE) else if (cap.capabilities & V4L2_CAP_READWRITE)
{ {
sys->blocksize = fmt.fmt.pix.sizeimage; sys->blocksize = fmt.fmt.pix.sizeimage;
sys->bufv = NULL;
access->pf_read = AccessReadStream; access->pf_read = AccessReadStream;
} }
else else
...@@ -225,6 +205,8 @@ void AccessClose( vlc_object_t *obj ) ...@@ -225,6 +205,8 @@ void AccessClose( vlc_object_t *obj )
access_t *access = (access_t *)obj; access_t *access = (access_t *)obj;
access_sys_t *sys = access->p_sys; access_sys_t *sys = access->p_sys;
if (sys->bufv != NULL)
StopMmap (sys->fd, sys->bufv, sys->bufc);
ControlsDeinit( obj, sys->controls ); ControlsDeinit( obj, sys->controls );
v4l2_close (sys->fd); v4l2_close (sys->fd);
free( sys ); free( sys );
......
...@@ -438,30 +438,10 @@ static int InitVideo (demux_t *demux, int fd) ...@@ -438,30 +438,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)
{ {
sys->bufv = InitMmap (VLC_OBJECT(demux), fd, &sys->bufc); sys->bufc = 4;
sys->bufv = StartMmap (VLC_OBJECT(demux), fd, &sys->bufc);
if (sys->bufv == NULL) if (sys->bufv == NULL)
return -1; return -1;
for (uint32_t i = 0; i < sys->bufc; i++)
{
struct v4l2_buffer buf = {
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
.memory = V4L2_MEMORY_MMAP,
.index = i,
};
if (v4l2_ioctl (fd, VIDIOC_QBUF, &buf) < 0)
{
msg_Err (demux, "cannot queue buffer: %m");
return -1;
}
}
enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (v4l2_ioctl (fd, VIDIOC_STREAMON, &buf_type) < 0)
{
msg_Err (demux, "cannot start streaming: %m");
return -1;
}
entry = StreamThread; entry = StreamThread;
} }
else if (caps & V4L2_CAP_READWRITE) else if (caps & V4L2_CAP_READWRITE)
...@@ -485,32 +465,13 @@ void DemuxClose( vlc_object_t *obj ) ...@@ -485,32 +465,13 @@ void DemuxClose( vlc_object_t *obj )
{ {
demux_t *demux = (demux_t *)obj; demux_t *demux = (demux_t *)obj;
demux_sys_t *sys = demux->p_sys; demux_sys_t *sys = demux->p_sys;
int fd = sys->fd;
vlc_cancel (sys->thread); vlc_cancel (sys->thread);
vlc_join (sys->thread, NULL); vlc_join (sys->thread, NULL);
/* Stop video capture */
if (sys->bufv != NULL) if (sys->bufv != NULL)
{ StopMmap (sys->fd, sys->bufv, sys->bufc);
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_munmap (sys->bufv[i].start, sys->bufv[i].length);
}
enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_ioctl (fd, VIDIOC_STREAMOFF, &buf_type);
free (sys->bufv);
}
ControlsDeinit( obj, sys->controls ); ControlsDeinit( obj, sys->controls );
v4l2_close( fd ); v4l2_close (sys->fd);
free( sys ); free( sys );
} }
......
...@@ -87,7 +87,10 @@ int SetupFormat (vlc_object_t *, int, uint32_t, ...@@ -87,7 +87,10 @@ 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 *);
struct buffer_t *StartMmap (vlc_object_t *, int, uint32_t *);
void StopMmap (int, struct buffer_t *, uint32_t);
block_t* GrabVideo (vlc_object_t *, int, const struct buffer_t *); block_t* GrabVideo (vlc_object_t *, int, const struct buffer_t *);
/* demux.c */ /* demux.c */
......
...@@ -556,13 +556,15 @@ block_t *GrabVideo (vlc_object_t *demux, int fd, ...@@ -556,13 +556,15 @@ block_t *GrabVideo (vlc_object_t *demux, int fd,
return block; return block;
} }
/***************************************************************************** /**
* Helper function to initalise video IO using the mmap method * Allocates memory-mapped buffers, queues them and start streaming.
*****************************************************************************/ * @param n requested buffers count [IN], allocated buffers count [OUT]
struct buffer_t *InitMmap (vlc_object_t *obj, int fd, uint32_t *restrict n) * @return array of allocated buffers (use free()), or NULL on error.
*/
struct buffer_t *StartMmap (vlc_object_t *obj, int fd, uint32_t *restrict n)
{ {
struct v4l2_requestbuffers req = { struct v4l2_requestbuffers req = {
.count = 4, .count = *n,
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
.memory = V4L2_MEMORY_MMAP, .memory = V4L2_MEMORY_MMAP,
}; };
...@@ -597,6 +599,11 @@ struct buffer_t *InitMmap (vlc_object_t *obj, int fd, uint32_t *restrict n) ...@@ -597,6 +599,11 @@ struct buffer_t *InitMmap (vlc_object_t *obj, int fd, uint32_t *restrict n)
msg_Err (obj, "cannot query buffer %"PRIu32": %m", bufc); msg_Err (obj, "cannot query buffer %"PRIu32": %m", bufc);
goto error; goto error;
} }
if (v4l2_ioctl (fd, VIDIOC_QBUF, &buf) < 0)
{
msg_Err (obj, "cannot queue buffer %"PRIu32": %m", bufc);
goto error;
}
bufv[bufc].start = v4l2_mmap (NULL, buf.length, PROT_READ | PROT_WRITE, bufv[bufc].start = v4l2_mmap (NULL, buf.length, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, buf.m.offset); MAP_SHARED, fd, buf.m.offset);
...@@ -608,14 +615,26 @@ struct buffer_t *InitMmap (vlc_object_t *obj, int fd, uint32_t *restrict n) ...@@ -608,14 +615,26 @@ struct buffer_t *InitMmap (vlc_object_t *obj, int fd, uint32_t *restrict n)
bufv[bufc].length = buf.length; bufv[bufc].length = buf.length;
} }
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (v4l2_ioctl (fd, VIDIOC_STREAMON, &type) < 0)
{
msg_Err (obj, "cannot start streaming: %m");
goto error;
}
*n = bufc; *n = bufc;
return bufv; return bufv;
error: error:
while (bufc > 0) StopMmap (fd, bufv, bufc);
{
bufc--;
v4l2_munmap (bufv[bufc].start, bufv[bufc].length);
}
free (bufv);
return NULL; return NULL;
} }
void StopMmap (int fd, struct buffer_t *bufv, uint32_t bufc)
{
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/* STREAMOFF implicitly dequeues all buffers */
v4l2_ioctl (fd, VIDIOC_STREAMOFF, &type);
for (uint32_t i = bufc; i < bufc; i++)
v4l2_munmap (bufv[i].start, bufv[i].length);
free (bufv);
}
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