v4l2: try to allocate new buffers with VIDIOC_CREATE_BUFS if needed

If max_buffers is 0 then an arbitrary number of buffers (currently 4) is
allocated. If this is not enough v4l2src starts copying buffers.
With this patch VIDIOC_CREATE_BUFS is used to allocate a new buffer. If
this fails v4l2src falls back to copying buffers.

https://bugzilla.gnome.org/show_bug.cgi?id=699447
This commit is contained in:
Michael Olbrich 2013-05-02 09:41:01 +02:00 committed by Sebastian Dröge
parent bb980775f8
commit 1e777ede92
2 changed files with 53 additions and 0 deletions

View file

@ -157,6 +157,28 @@ gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
case GST_V4L2_IO_MMAP:
case GST_V4L2_IO_DMABUF:
{
#ifdef VIDIOC_CREATE_BUFS
if (pool->num_allocated == pool->num_buffers) {
struct v4l2_create_buffers create_bufs;
memset (&create_bufs, 0, sizeof (struct v4l2_create_buffers));
create_bufs.count = 1;
create_bufs.memory = V4L2_MEMORY_MMAP;
create_bufs.format.type = obj->type;
if (v4l2_ioctl (pool->video_fd, VIDIOC_G_FMT, &create_bufs.format) < 0)
goto g_fmt_failed;
if (v4l2_ioctl (pool->video_fd, VIDIOC_CREATE_BUFS, &create_bufs) < 0)
goto create_bufs_failed;
GST_LOG_OBJECT (pool, "created buffer with index: %u",
create_bufs.index);
pool->num_buffers++;
pool->buffers = g_renew (GstBuffer *, pool->buffers, pool->num_buffers);
pool->buffers[pool->num_buffers - 1] = NULL;
}
#endif
newbuf = gst_buffer_new ();
meta = GST_V4L2_META_ADD (newbuf);
@ -250,6 +272,24 @@ gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
return GST_FLOW_OK;
/* ERRORS */
#ifdef VIDIOC_CREATE_BUFS
g_fmt_failed:
{
gint errnosave = errno;
GST_WARNING ("Failed G_FMT: %s", g_strerror (errnosave));
errno = errnosave;
return GST_FLOW_ERROR;
}
create_bufs_failed:
{
gint errnosave = errno;
GST_WARNING ("Failed CREATE_BUFS: %s", g_strerror (errnosave));
errno = errnosave;
return GST_FLOW_ERROR;
}
#endif
querybuf_failed:
{
gint errnosave = errno;
@ -793,6 +833,17 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
/* start copying buffers when we are running low on buffers */
if (pool->num_queued < pool->copy_threshold) {
GstBuffer *copy;
#ifdef VIDIOC_CREATE_BUFS
if (pool->can_alloc) {
if (GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
&copy, params) == GST_FLOW_OK) {
gst_v4l2_buffer_pool_release_buffer (bpool, copy);
break;
} else {
pool->can_alloc = FALSE;
}
}
#endif
/* copy the memory */
copy = gst_buffer_copy (*buffer);
@ -989,6 +1040,7 @@ gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps)
pool = (GstV4l2BufferPool *) g_object_new (GST_TYPE_V4L2_BUFFER_POOL, NULL);
pool->video_fd = fd;
pool->obj = obj;
pool->can_alloc = TRUE;
s = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
gst_buffer_pool_config_set_params (s, caps, obj->sizeimage, 2, 0);

View file

@ -55,6 +55,7 @@ struct _GstV4l2BufferPool
GstAllocationParams params;
guint size;
gboolean add_videometa;
gboolean can_alloc; /* if extra buffers can be allocated */
guint num_buffers; /* number of buffers we use */
guint num_allocated; /* number of buffers allocated by the driver */