v4l2: Add run-time environment to enable libv4l2

The library has started preventing a lot of interesting use cases,
like CREATE_BUFS, DMABuf, usage of TRY_FMT. As the libv4l2 is totally
inactive and not maintained, we decided to disable it. As a convenience
we added a run-time environment that let you enable it for testing.

  GST_V4L2_USE_LIBV4L2=1

This of course only works if you have enabled libv4l2 at build time.
This commit is contained in:
Nicolas Dufresne 2017-07-24 14:19:02 -04:00
parent ab3b289bf2
commit 31d8a1d929
12 changed files with 171 additions and 130 deletions

View file

@ -241,9 +241,9 @@ gst_v4l2_memory_group_free (GstV4l2MemoryGroup * group)
static GstV4l2MemoryGroup * static GstV4l2MemoryGroup *
gst_v4l2_memory_group_new (GstV4l2Allocator * allocator, guint32 index) gst_v4l2_memory_group_new (GstV4l2Allocator * allocator, guint32 index)
{ {
gint video_fd = allocator->video_fd; GstV4l2Object *obj = allocator->obj;
guint32 memory = allocator->memory; guint32 memory = allocator->memory;
struct v4l2_format *format = &allocator->format; struct v4l2_format *format = &obj->format;
GstV4l2MemoryGroup *group; GstV4l2MemoryGroup *group;
gsize img_size, buf_size; gsize img_size, buf_size;
@ -260,7 +260,7 @@ gst_v4l2_memory_group_new (GstV4l2Allocator * allocator, guint32 index)
group->n_mem = 1; group->n_mem = 1;
} }
if (v4l2_ioctl (video_fd, VIDIOC_QUERYBUF, &group->buffer) < 0) if (obj->ioctl (obj->video_fd, VIDIOC_QUERYBUF, &group->buffer) < 0)
goto querybuf_failed; goto querybuf_failed;
if (group->buffer.index != index) { if (group->buffer.index != index) {
@ -273,17 +273,17 @@ gst_v4l2_memory_group_new (GstV4l2Allocator * allocator, guint32 index)
/* Check that provided size matches the format we have negotiation. Failing /* Check that provided size matches the format we have negotiation. Failing
* there usually means a driver of libv4l bug. */ * there usually means a driver of libv4l bug. */
if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) { if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
gint i; gint i;
for (i = 0; i < group->n_mem; i++) { for (i = 0; i < group->n_mem; i++) {
img_size = allocator->format.fmt.pix_mp.plane_fmt[i].sizeimage; img_size = obj->format.fmt.pix_mp.plane_fmt[i].sizeimage;
buf_size = group->planes[i].length; buf_size = group->planes[i].length;
if (buf_size < img_size) if (buf_size < img_size)
goto buffer_too_short; goto buffer_too_short;
} }
} else { } else {
img_size = allocator->format.fmt.pix.sizeimage; img_size = obj->format.fmt.pix.sizeimage;
buf_size = group->buffer.length; buf_size = group->buffer.length;
if (buf_size < img_size) if (buf_size < img_size)
goto buffer_too_short; goto buffer_too_short;
@ -378,6 +378,7 @@ static void
gst_v4l2_allocator_free (GstAllocator * gallocator, GstMemory * gmem) gst_v4l2_allocator_free (GstAllocator * gallocator, GstMemory * gmem)
{ {
GstV4l2Allocator *allocator = (GstV4l2Allocator *) gallocator; GstV4l2Allocator *allocator = (GstV4l2Allocator *) gallocator;
GstV4l2Object *obj = allocator->obj;
GstV4l2Memory *mem = (GstV4l2Memory *) gmem; GstV4l2Memory *mem = (GstV4l2Memory *) gmem;
GstV4l2MemoryGroup *group = mem->group; GstV4l2MemoryGroup *group = mem->group;
@ -388,7 +389,7 @@ gst_v4l2_allocator_free (GstAllocator * gallocator, GstMemory * gmem)
if (allocator->memory == V4L2_MEMORY_MMAP) { if (allocator->memory == V4L2_MEMORY_MMAP) {
if (mem->data) if (mem->data)
v4l2_munmap (mem->data, group->planes[mem->plane].length); obj->munmap (mem->data, group->planes[mem->plane].length);
} }
/* This apply for both mmap with expbuf, and dmabuf imported memory */ /* This apply for both mmap with expbuf, and dmabuf imported memory */
@ -424,7 +425,6 @@ gst_v4l2_allocator_finalize (GObject * obj)
GST_LOG_OBJECT (obj, "called"); GST_LOG_OBJECT (obj, "called");
v4l2_close (allocator->video_fd);
gst_atomic_queue_unref (allocator->free_queue); gst_atomic_queue_unref (allocator->free_queue);
G_OBJECT_CLASS (parent_class)->finalize (obj); G_OBJECT_CLASS (parent_class)->finalize (obj);
@ -478,22 +478,23 @@ static guint32
gst_v4l2_allocator_probe (GstV4l2Allocator * allocator, guint32 memory, gst_v4l2_allocator_probe (GstV4l2Allocator * allocator, guint32 memory,
guint32 breq_flag, guint32 bcreate_flag) guint32 breq_flag, guint32 bcreate_flag)
{ {
GstV4l2Object *obj = allocator->obj;
struct v4l2_requestbuffers breq = { 0 }; struct v4l2_requestbuffers breq = { 0 };
guint32 flags = 0; guint32 flags = 0;
breq.type = allocator->type; breq.type = obj->type;
breq.count = 0; breq.count = 0;
breq.memory = memory; breq.memory = memory;
if (v4l2_ioctl (allocator->video_fd, VIDIOC_REQBUFS, &breq) == 0) { if (obj->ioctl (obj->video_fd, VIDIOC_REQBUFS, &breq) == 0) {
struct v4l2_create_buffers bcreate = { 0 }; struct v4l2_create_buffers bcreate = { 0 };
flags |= breq_flag; flags |= breq_flag;
bcreate.memory = memory; bcreate.memory = memory;
bcreate.format = allocator->format; bcreate.format = obj->format;
if ((v4l2_ioctl (allocator->video_fd, VIDIOC_CREATE_BUFS, &bcreate) == 0)) if ((obj->ioctl (obj->video_fd, VIDIOC_CREATE_BUFS, &bcreate) == 0))
flags |= bcreate_flag; flags |= bcreate_flag;
} }
@ -503,6 +504,7 @@ gst_v4l2_allocator_probe (GstV4l2Allocator * allocator, guint32 memory,
static GstV4l2MemoryGroup * static GstV4l2MemoryGroup *
gst_v4l2_allocator_create_buf (GstV4l2Allocator * allocator) gst_v4l2_allocator_create_buf (GstV4l2Allocator * allocator)
{ {
GstV4l2Object *obj = allocator->obj;
struct v4l2_create_buffers bcreate = { 0 }; struct v4l2_create_buffers bcreate = { 0 };
GstV4l2MemoryGroup *group = NULL; GstV4l2MemoryGroup *group = NULL;
@ -512,13 +514,13 @@ gst_v4l2_allocator_create_buf (GstV4l2Allocator * allocator)
goto done; goto done;
bcreate.memory = allocator->memory; bcreate.memory = allocator->memory;
bcreate.format = allocator->format; bcreate.format = obj->format;
bcreate.count = 1; bcreate.count = 1;
if (!allocator->can_allocate) if (!allocator->can_allocate)
goto done; goto done;
if (v4l2_ioctl (allocator->video_fd, VIDIOC_CREATE_BUFS, &bcreate) < 0) if (obj->ioctl (obj->video_fd, VIDIOC_CREATE_BUFS, &bcreate) < 0)
goto create_bufs_failed; goto create_bufs_failed;
if (allocator->groups[bcreate.index] != NULL) if (allocator->groups[bcreate.index] != NULL)
@ -577,6 +579,7 @@ static void
gst_v4l2_allocator_reset_size (GstV4l2Allocator * allocator, gst_v4l2_allocator_reset_size (GstV4l2Allocator * allocator,
GstV4l2MemoryGroup * group) GstV4l2MemoryGroup * group)
{ {
GstV4l2Object *obj = allocator->obj;
gsize size; gsize size;
gboolean imported = FALSE; gboolean imported = FALSE;
@ -587,11 +590,11 @@ gst_v4l2_allocator_reset_size (GstV4l2Allocator * allocator,
break; break;
} }
if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) { if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
gint i; gint i;
for (i = 0; i < group->n_mem; i++) { for (i = 0; i < group->n_mem; i++) {
size = allocator->format.fmt.pix_mp.plane_fmt[i].sizeimage; size = obj->format.fmt.pix_mp.plane_fmt[i].sizeimage;
if (imported) if (imported)
group->mem[i]->maxsize = size; group->mem[i]->maxsize = size;
@ -600,7 +603,7 @@ gst_v4l2_allocator_reset_size (GstV4l2Allocator * allocator,
} }
} else { } else {
size = allocator->format.fmt.pix.sizeimage; size = obj->format.fmt.pix.sizeimage;
if (imported) if (imported)
group->mem[0]->maxsize = size; group->mem[0]->maxsize = size;
@ -628,8 +631,7 @@ _cleanup_failed_alloc (GstV4l2Allocator * allocator, GstV4l2MemoryGroup * group)
GstV4l2Allocator * GstV4l2Allocator *
gst_v4l2_allocator_new (GstObject * parent, gint video_fd, gst_v4l2_allocator_new (GstObject * parent, GstV4l2Object * v4l2object)
struct v4l2_format *format)
{ {
GstV4l2Allocator *allocator; GstV4l2Allocator *allocator;
guint32 flags = 0; guint32 flags = 0;
@ -644,9 +646,7 @@ gst_v4l2_allocator_new (GstObject * parent, gint video_fd,
g_free (name); g_free (name);
/* Save everything */ /* Save everything */
allocator->video_fd = v4l2_dup (video_fd); allocator->obj = v4l2object;
allocator->type = format->type;
allocator->format = *format;
flags |= GST_V4L2_ALLOCATOR_PROBE (allocator, MMAP); flags |= GST_V4L2_ALLOCATOR_PROBE (allocator, MMAP);
flags |= GST_V4L2_ALLOCATOR_PROBE (allocator, USERPTR); flags |= GST_V4L2_ALLOCATOR_PROBE (allocator, USERPTR);
@ -672,7 +672,8 @@ guint
gst_v4l2_allocator_start (GstV4l2Allocator * allocator, guint32 count, gst_v4l2_allocator_start (GstV4l2Allocator * allocator, guint32 count,
guint32 memory) guint32 memory)
{ {
struct v4l2_requestbuffers breq = { count, allocator->type, memory }; GstV4l2Object *obj = allocator->obj;
struct v4l2_requestbuffers breq = { count, obj->type, memory };
gboolean can_allocate; gboolean can_allocate;
gint i; gint i;
@ -683,7 +684,7 @@ gst_v4l2_allocator_start (GstV4l2Allocator * allocator, guint32 count,
if (g_atomic_int_get (&allocator->active)) if (g_atomic_int_get (&allocator->active))
goto already_active; goto already_active;
if (v4l2_ioctl (allocator->video_fd, VIDIOC_REQBUFS, &breq) < 0) if (obj->ioctl (obj->video_fd, VIDIOC_REQBUFS, &breq) < 0)
goto reqbufs_failed; goto reqbufs_failed;
if (breq.count < 1) if (breq.count < 1)
@ -752,7 +753,8 @@ error:
GstV4l2Return GstV4l2Return
gst_v4l2_allocator_stop (GstV4l2Allocator * allocator) gst_v4l2_allocator_stop (GstV4l2Allocator * allocator)
{ {
struct v4l2_requestbuffers breq = { 0, allocator->type, allocator->memory }; GstV4l2Object *obj = allocator->obj;
struct v4l2_requestbuffers breq = { 0, obj->type, allocator->memory };
gint i = 0; gint i = 0;
GstV4l2Return ret = GST_V4L2_OK; GstV4l2Return ret = GST_V4L2_OK;
@ -781,7 +783,7 @@ gst_v4l2_allocator_stop (GstV4l2Allocator * allocator)
} }
/* Not all drivers support rebufs(0), so warn only */ /* Not all drivers support rebufs(0), so warn only */
if (v4l2_ioctl (allocator->video_fd, VIDIOC_REQBUFS, &breq) < 0) if (obj->ioctl (obj->video_fd, VIDIOC_REQBUFS, &breq) < 0)
GST_WARNING_OBJECT (allocator, GST_WARNING_OBJECT (allocator,
"error releasing buffers buffers: %s", g_strerror (errno)); "error releasing buffers buffers: %s", g_strerror (errno));
@ -797,6 +799,7 @@ done:
GstV4l2MemoryGroup * GstV4l2MemoryGroup *
gst_v4l2_allocator_alloc_mmap (GstV4l2Allocator * allocator) gst_v4l2_allocator_alloc_mmap (GstV4l2Allocator * allocator)
{ {
GstV4l2Object *obj = allocator->obj;
GstV4l2MemoryGroup *group; GstV4l2MemoryGroup *group;
gint i; gint i;
@ -810,8 +813,8 @@ gst_v4l2_allocator_alloc_mmap (GstV4l2Allocator * allocator)
for (i = 0; i < group->n_mem; i++) { for (i = 0; i < group->n_mem; i++) {
if (group->mem[i] == NULL) { if (group->mem[i] == NULL) {
gpointer data; gpointer data;
data = v4l2_mmap (NULL, group->planes[i].length, PROT_READ | PROT_WRITE, data = obj->mmap (NULL, group->planes[i].length, PROT_READ | PROT_WRITE,
MAP_SHARED, allocator->video_fd, group->planes[i].m.mem_offset); MAP_SHARED, obj->video_fd, group->planes[i].m.mem_offset);
if (data == MAP_FAILED) if (data == MAP_FAILED)
goto mmap_failed; goto mmap_failed;
@ -852,6 +855,7 @@ GstV4l2MemoryGroup *
gst_v4l2_allocator_alloc_dmabuf (GstV4l2Allocator * allocator, gst_v4l2_allocator_alloc_dmabuf (GstV4l2Allocator * allocator,
GstAllocator * dmabuf_allocator) GstAllocator * dmabuf_allocator)
{ {
GstV4l2Object *obj = allocator->obj;
GstV4l2MemoryGroup *group; GstV4l2MemoryGroup *group;
gint i; gint i;
@ -870,12 +874,12 @@ gst_v4l2_allocator_alloc_dmabuf (GstV4l2Allocator * allocator,
if (group->mem[i] == NULL) { if (group->mem[i] == NULL) {
struct v4l2_exportbuffer expbuf = { 0 }; struct v4l2_exportbuffer expbuf = { 0 };
expbuf.type = allocator->type; expbuf.type = obj->type;
expbuf.index = group->buffer.index; expbuf.index = group->buffer.index;
expbuf.plane = i; expbuf.plane = i;
expbuf.flags = O_CLOEXEC | O_RDWR; expbuf.flags = O_CLOEXEC | O_RDWR;
if (v4l2_ioctl (allocator->video_fd, VIDIOC_EXPBUF, &expbuf) < 0) if (obj->ioctl (obj->video_fd, VIDIOC_EXPBUF, &expbuf) < 0)
goto expbuf_failed; goto expbuf_failed;
GST_LOG_OBJECT (allocator, "exported DMABUF as fd %i plane %d", GST_LOG_OBJECT (allocator, "exported DMABUF as fd %i plane %d",
@ -933,6 +937,7 @@ static void
gst_v4l2_allocator_clear_dmabufin (GstV4l2Allocator * allocator, gst_v4l2_allocator_clear_dmabufin (GstV4l2Allocator * allocator,
GstV4l2MemoryGroup * group) GstV4l2MemoryGroup * group)
{ {
GstV4l2Object *obj = allocator->obj;
GstV4l2Memory *mem; GstV4l2Memory *mem;
gint i; gint i;
@ -961,7 +966,7 @@ gst_v4l2_allocator_clear_dmabufin (GstV4l2Allocator * allocator,
group->planes[i].data_offset = 0; group->planes[i].data_offset = 0;
} }
if (!V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) { if (!V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
group->buffer.bytesused = 0; group->buffer.bytesused = 0;
group->buffer.length = 0; group->buffer.length = 0;
group->buffer.m.fd = -1; group->buffer.m.fd = -1;
@ -1004,6 +1009,7 @@ static void
gst_v4l2_allocator_clear_userptr (GstV4l2Allocator * allocator, gst_v4l2_allocator_clear_userptr (GstV4l2Allocator * allocator,
GstV4l2MemoryGroup * group) GstV4l2MemoryGroup * group)
{ {
GstV4l2Object *obj = allocator->obj;
GstV4l2Memory *mem; GstV4l2Memory *mem;
gint i; gint i;
@ -1024,7 +1030,7 @@ gst_v4l2_allocator_clear_userptr (GstV4l2Allocator * allocator,
group->planes[i].m.userptr = 0; group->planes[i].m.userptr = 0;
} }
if (!V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) { if (!V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
group->buffer.bytesused = 0; group->buffer.bytesused = 0;
group->buffer.length = 0; group->buffer.length = 0;
group->buffer.m.userptr = 0; group->buffer.m.userptr = 0;
@ -1068,6 +1074,7 @@ gboolean
gst_v4l2_allocator_import_dmabuf (GstV4l2Allocator * allocator, gst_v4l2_allocator_import_dmabuf (GstV4l2Allocator * allocator,
GstV4l2MemoryGroup * group, gint n_mem, GstMemory ** dma_mem) GstV4l2MemoryGroup * group, gint n_mem, GstMemory ** dma_mem)
{ {
GstV4l2Object *obj = allocator->obj;
GstV4l2Memory *mem; GstV4l2Memory *mem;
gint i; gint i;
@ -1106,7 +1113,7 @@ gst_v4l2_allocator_import_dmabuf (GstV4l2Allocator * allocator,
} }
/* Copy into buffer structure if not using planes */ /* Copy into buffer structure if not using planes */
if (!V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) { if (!V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
group->buffer.bytesused = group->planes[0].bytesused; group->buffer.bytesused = group->planes[0].bytesused;
group->buffer.length = group->planes[0].length; group->buffer.length = group->planes[0].length;
group->buffer.m.fd = group->planes[0].m.userptr; group->buffer.m.fd = group->planes[0].m.userptr;
@ -1140,24 +1147,25 @@ gst_v4l2_allocator_import_userptr (GstV4l2Allocator * allocator,
GstV4l2MemoryGroup * group, gsize img_size, int n_planes, GstV4l2MemoryGroup * group, gsize img_size, int n_planes,
gpointer * data, gsize * size) gpointer * data, gsize * size)
{ {
GstV4l2Object *obj = allocator->obj;
GstV4l2Memory *mem; GstV4l2Memory *mem;
gint i; gint i;
g_return_val_if_fail (allocator->memory == V4L2_MEMORY_USERPTR, FALSE); g_return_val_if_fail (allocator->memory == V4L2_MEMORY_USERPTR, FALSE);
/* TODO Support passing N plane from 1 memory to MPLANE v4l2 format */ /* TODO Support passing N plane from 1 memory to MPLANE v4l2 format */
if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type) && n_planes != group->n_mem) if (V4L2_TYPE_IS_MULTIPLANAR (obj->type) && n_planes != group->n_mem)
goto n_mem_missmatch; goto n_mem_missmatch;
for (i = 0; i < group->n_mem; i++) { for (i = 0; i < group->n_mem; i++) {
gsize maxsize, psize; gsize maxsize, psize;
if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) { if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
struct v4l2_pix_format_mplane *pix = &allocator->format.fmt.pix_mp; struct v4l2_pix_format_mplane *pix = &obj->format.fmt.pix_mp;
maxsize = pix->plane_fmt[i].sizeimage; maxsize = pix->plane_fmt[i].sizeimage;
psize = size[i]; psize = size[i];
} else { } else {
maxsize = allocator->format.fmt.pix.sizeimage; maxsize = obj->format.fmt.pix.sizeimage;
psize = img_size; psize = img_size;
} }
@ -1179,7 +1187,7 @@ gst_v4l2_allocator_import_userptr (GstV4l2Allocator * allocator,
} }
/* Copy into buffer structure if not using planes */ /* Copy into buffer structure if not using planes */
if (!V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) { if (!V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
group->buffer.bytesused = group->planes[0].bytesused; group->buffer.bytesused = group->planes[0].bytesused;
group->buffer.length = group->planes[0].length; group->buffer.length = group->planes[0].length;
group->buffer.m.userptr = group->planes[0].m.userptr; group->buffer.m.userptr = group->planes[0].m.userptr;
@ -1229,13 +1237,14 @@ gboolean
gst_v4l2_allocator_qbuf (GstV4l2Allocator * allocator, gst_v4l2_allocator_qbuf (GstV4l2Allocator * allocator,
GstV4l2MemoryGroup * group) GstV4l2MemoryGroup * group)
{ {
GstV4l2Object *obj = allocator->obj;
gboolean ret = TRUE; gboolean ret = TRUE;
gint i; gint i;
g_return_val_if_fail (g_atomic_int_get (&allocator->active), FALSE); g_return_val_if_fail (g_atomic_int_get (&allocator->active), FALSE);
/* update sizes */ /* update sizes */
if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) { if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
for (i = 0; i < group->n_mem; i++) for (i = 0; i < group->n_mem; i++)
group->planes[i].bytesused = group->planes[i].bytesused =
gst_memory_get_sizes (group->mem[i], NULL, NULL); gst_memory_get_sizes (group->mem[i], NULL, NULL);
@ -1247,7 +1256,7 @@ gst_v4l2_allocator_qbuf (GstV4l2Allocator * allocator,
for (i = 0; i < group->n_mem; i++) for (i = 0; i < group->n_mem; i++)
gst_memory_ref (group->mem[i]); gst_memory_ref (group->mem[i]);
if (v4l2_ioctl (allocator->video_fd, VIDIOC_QBUF, &group->buffer) < 0) { if (obj->ioctl (obj->video_fd, VIDIOC_QBUF, &group->buffer) < 0) {
GST_ERROR_OBJECT (allocator, "failed queueing buffer %i: %s", GST_ERROR_OBJECT (allocator, "failed queueing buffer %i: %s",
group->buffer.index, g_strerror (errno)); group->buffer.index, g_strerror (errno));
@ -1281,6 +1290,7 @@ GstFlowReturn
gst_v4l2_allocator_dqbuf (GstV4l2Allocator * allocator, gst_v4l2_allocator_dqbuf (GstV4l2Allocator * allocator,
GstV4l2MemoryGroup ** group_out) GstV4l2MemoryGroup ** group_out)
{ {
GstV4l2Object *obj = allocator->obj;
struct v4l2_buffer buffer = { 0 }; struct v4l2_buffer buffer = { 0 };
struct v4l2_plane planes[VIDEO_MAX_PLANES] = { {0} }; struct v4l2_plane planes[VIDEO_MAX_PLANES] = { {0} };
gint i; gint i;
@ -1289,15 +1299,15 @@ gst_v4l2_allocator_dqbuf (GstV4l2Allocator * allocator,
g_return_val_if_fail (g_atomic_int_get (&allocator->active), GST_FLOW_ERROR); g_return_val_if_fail (g_atomic_int_get (&allocator->active), GST_FLOW_ERROR);
buffer.type = allocator->type; buffer.type = obj->type;
buffer.memory = allocator->memory; buffer.memory = allocator->memory;
if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) { if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
buffer.length = allocator->format.fmt.pix_mp.num_planes; buffer.length = obj->format.fmt.pix_mp.num_planes;
buffer.m.planes = planes; buffer.m.planes = planes;
} }
if (v4l2_ioctl (allocator->video_fd, VIDIOC_DQBUF, &buffer) < 0) if (obj->ioctl (obj->video_fd, VIDIOC_DQBUF, &buffer) < 0)
goto error; goto error;
group = allocator->groups[buffer.index]; group = allocator->groups[buffer.index];
@ -1319,7 +1329,7 @@ gst_v4l2_allocator_dqbuf (GstV4l2Allocator * allocator,
UNSET_QUEUED (group->buffer); UNSET_QUEUED (group->buffer);
} }
if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) { if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
group->buffer.m.planes = group->planes; group->buffer.m.planes = group->planes;
memcpy (group->planes, buffer.m.planes, sizeof (planes)); memcpy (group->planes, buffer.m.planes, sizeof (planes));
} else { } else {
@ -1330,7 +1340,7 @@ gst_v4l2_allocator_dqbuf (GstV4l2Allocator * allocator,
} }
/* And update memory size */ /* And update memory size */
if (V4L2_TYPE_IS_OUTPUT (allocator->type)) { if (V4L2_TYPE_IS_OUTPUT (obj->type)) {
gst_v4l2_allocator_reset_size (allocator, group); gst_v4l2_allocator_reset_size (allocator, group);
} else { } else {
/* for capture, simply read the size */ /* for capture, simply read the size */

View file

@ -50,6 +50,7 @@ typedef struct _GstV4l2MemoryGroup GstV4l2MemoryGroup;
typedef struct _GstV4l2Memory GstV4l2Memory; typedef struct _GstV4l2Memory GstV4l2Memory;
typedef enum _GstV4l2Capabilities GstV4l2Capabilities; typedef enum _GstV4l2Capabilities GstV4l2Capabilities;
typedef enum _GstV4l2Return GstV4l2Return; typedef enum _GstV4l2Return GstV4l2Return;
typedef struct _GstV4l2Object GstV4l2Object;
enum _GstV4l2AllocatorFlags enum _GstV4l2AllocatorFlags
{ {
@ -89,11 +90,9 @@ struct _GstV4l2MemoryGroup
struct _GstV4l2Allocator struct _GstV4l2Allocator
{ {
GstAllocator parent; GstAllocator parent;
gint video_fd; GstV4l2Object *obj;
guint32 count; guint32 count;
guint32 type;
guint32 memory; guint32 memory;
struct v4l2_format format;
gboolean can_allocate; gboolean can_allocate;
gboolean active; gboolean active;
@ -117,8 +116,7 @@ gboolean gst_v4l2_allocator_is_active (GstV4l2Allocator * alloc
guint gst_v4l2_allocator_get_size (GstV4l2Allocator * allocator); guint gst_v4l2_allocator_get_size (GstV4l2Allocator * allocator);
GstV4l2Allocator* gst_v4l2_allocator_new (GstObject *parent, gint video_fd, GstV4l2Allocator* gst_v4l2_allocator_new (GstObject *parent, GstV4l2Object * obj);
struct v4l2_format * format);
guint gst_v4l2_allocator_start (GstV4l2Allocator * allocator, guint gst_v4l2_allocator_start (GstV4l2Allocator * allocator,
guint32 count, guint32 memory); guint32 count, guint32 memory);

View file

@ -621,7 +621,7 @@ gst_v4l2_buffer_pool_streamon (GstV4l2BufferPool * pool)
case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_DMABUF:
case GST_V4L2_IO_DMABUF_IMPORT: case GST_V4L2_IO_DMABUF_IMPORT:
if (!pool->streaming) { if (!pool->streaming) {
if (v4l2_ioctl (pool->video_fd, VIDIOC_STREAMON, &obj->type) < 0) if (obj->ioctl (pool->video_fd, VIDIOC_STREAMON, &obj->type) < 0)
goto streamon_failed; goto streamon_failed;
pool->streaming = TRUE; pool->streaming = TRUE;
@ -654,7 +654,7 @@ gst_v4l2_buffer_pool_streamoff (GstV4l2BufferPool * pool)
case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_DMABUF:
case GST_V4L2_IO_DMABUF_IMPORT: case GST_V4L2_IO_DMABUF_IMPORT:
if (pool->streaming) { if (pool->streaming) {
if (v4l2_ioctl (pool->video_fd, VIDIOC_STREAMOFF, &obj->type) < 0) if (obj->ioctl (pool->video_fd, VIDIOC_STREAMOFF, &obj->type) < 0)
GST_WARNING_OBJECT (pool, "STREAMOFF failed with errno %d (%s)", GST_WARNING_OBJECT (pool, "STREAMOFF failed with errno %d (%s)",
errno, g_strerror (errno)); errno, g_strerror (errno));
@ -728,7 +728,7 @@ gst_v4l2_buffer_pool_start (GstBufferPool * bpool)
* queue to be initialized now. We only do this if we have a streaming * queue to be initialized now. We only do this if we have a streaming
* driver. */ * driver. */
if (obj->device_caps & V4L2_CAP_STREAMING) if (obj->device_caps & V4L2_CAP_STREAMING)
v4l2_read (obj->video_fd, NULL, 0); obj->read (obj->video_fd, NULL, 0);
#endif #endif
break; break;
case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_DMABUF:
@ -1609,8 +1609,7 @@ gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps)
pool->obj = obj; pool->obj = obj;
pool->can_poll_device = TRUE; pool->can_poll_device = TRUE;
pool->vallocator = pool->vallocator = gst_v4l2_allocator_new (GST_OBJECT (pool), obj);
gst_v4l2_allocator_new (GST_OBJECT (pool), obj->video_fd, &obj->format);
if (pool->vallocator == NULL) if (pool->vallocator == NULL)
goto allocator_failed; goto allocator_failed;
@ -1657,7 +1656,7 @@ gst_v4l2_do_read (GstV4l2BufferPool * pool, GstBuffer * buf)
if ((res = gst_v4l2_buffer_pool_poll (pool)) != GST_FLOW_OK) if ((res = gst_v4l2_buffer_pool_poll (pool)) != GST_FLOW_OK)
goto poll_error; goto poll_error;
amount = v4l2_read (obj->video_fd, map.data, toread); amount = obj->read (obj->video_fd, map.data, toread);
if (amount == toread) { if (amount == toread) {
break; break;

View file

@ -329,7 +329,7 @@ negotiate_profile_and_level (GstCapsFeatures * features, GstStructure * s,
if (control.value < 0) if (control.value < 0)
continue; continue;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) {
GST_WARNING_OBJECT (ctx->self, "Failed to set H264 profile: '%s'", GST_WARNING_OBJECT (ctx->self, "Failed to set H264 profile: '%s'",
g_strerror (errno)); g_strerror (errno));
break; break;
@ -371,7 +371,7 @@ negotiate_profile_and_level (GstCapsFeatures * features, GstStructure * s,
if (control.value < 0) if (control.value < 0)
continue; continue;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) {
GST_WARNING_OBJECT (ctx->self, "Failed to set H264 level: '%s'", GST_WARNING_OBJECT (ctx->self, "Failed to set H264 level: '%s'",
g_strerror (errno)); g_strerror (errno));
break; break;
@ -436,7 +436,7 @@ gst_v4l2_h264_enc_negotiate (GstVideoEncoder * encoder)
control.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE; control.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0) if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0)
goto g_ctrl_failed; goto g_ctrl_failed;
ctx.profile = v4l2_profile_to_string (control.value); ctx.profile = v4l2_profile_to_string (control.value);
@ -447,7 +447,7 @@ gst_v4l2_h264_enc_negotiate (GstVideoEncoder * encoder)
control.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL; control.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0) if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0)
goto g_ctrl_failed; goto g_ctrl_failed;
ctx.level = v4l2_level_to_string (control.value); ctx.level = v4l2_level_to_string (control.value);

View file

@ -27,6 +27,9 @@
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#ifdef HAVE_GUDEV #ifdef HAVE_GUDEV
#include <gudev/gudev.h> #include <gudev/gudev.h>
@ -490,6 +493,28 @@ gst_v4l2_object_new (GstElement * element,
v4l2object->no_initial_format = FALSE; v4l2object->no_initial_format = FALSE;
/* We now disable libv4l2 by default, but have an env to enable it. */
#ifdef HAVE_LIBV4L2
if (g_getenv ("GST_V4L2_USE_LIBV4L2")) {
v4l2object->fd_open = v4l2_fd_open;
v4l2object->close = v4l2_close;
v4l2object->dup = v4l2_dup;
v4l2object->ioctl = v4l2_ioctl;
v4l2object->read = v4l2_read;
v4l2object->mmap = v4l2_mmap;
v4l2object->munmap = v4l2_munmap;
} else
#endif
{
v4l2object->fd_open = NULL;
v4l2object->close = close;
v4l2object->dup = dup;
v4l2object->ioctl = ioctl;
v4l2object->read = read;
v4l2object->mmap = mmap;
v4l2object->munmap = munmap;
}
return v4l2object; return v4l2object;
} }
@ -775,7 +800,7 @@ gst_v4l2_get_driver_min_buffers (GstV4l2Object * v4l2object)
else else
control.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE; control.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) == 0) { if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) == 0) {
GST_DEBUG_OBJECT (v4l2object->element, GST_DEBUG_OBJECT (v4l2object->element,
"driver requires a minimum of %d buffers", control.value); "driver requires a minimum of %d buffers", control.value);
v4l2object->min_buffers = control.value; v4l2object->min_buffers = control.value;
@ -1113,7 +1138,7 @@ gst_v4l2_object_fill_format_list (GstV4l2Object * v4l2object,
format->index = n; format->index = n;
format->type = type; format->type = type;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_ENUM_FMT, format) < 0) { if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_ENUM_FMT, format) < 0) {
if (errno == EINVAL) { if (errno == EINVAL) {
g_free (format); g_free (format);
break; /* end of enumeration */ break; /* end of enumeration */
@ -2065,7 +2090,7 @@ gst_v4l2_object_try_fmt (GstV4l2Object * v4l2object,
int r; int r;
memcpy (&fmt, try_fmt, sizeof (fmt)); memcpy (&fmt, try_fmt, sizeof (fmt));
r = v4l2_ioctl (fd, VIDIOC_TRY_FMT, &fmt); r = v4l2object->ioctl (fd, VIDIOC_TRY_FMT, &fmt);
if (r < 0 && errno == ENOTTY) { if (r < 0 && errno == ENOTTY) {
/* The driver might not implement TRY_FMT, in which case we will try /* The driver might not implement TRY_FMT, in which case we will try
@ -2074,7 +2099,7 @@ gst_v4l2_object_try_fmt (GstV4l2Object * v4l2object,
goto error; goto error;
memcpy (&fmt, try_fmt, sizeof (fmt)); memcpy (&fmt, try_fmt, sizeof (fmt));
r = v4l2_ioctl (fd, VIDIOC_S_FMT, &fmt); r = v4l2object->ioctl (fd, VIDIOC_S_FMT, &fmt);
} }
memcpy (try_fmt, &fmt, sizeof (fmt)); memcpy (try_fmt, &fmt, sizeof (fmt));
@ -2269,7 +2294,7 @@ gst_v4l2_object_probe_caps_for_format_and_size (GstV4l2Object * v4l2object,
/* keep in mind that v4l2 gives us frame intervals (durations); we invert the /* keep in mind that v4l2 gives us frame intervals (durations); we invert the
* fraction to get framerate */ * fraction to get framerate */
if (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0) if (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0)
goto enum_frameintervals_failed; goto enum_frameintervals_failed;
if (ival.type == V4L2_FRMIVAL_TYPE_DISCRETE) { if (ival.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
@ -2296,7 +2321,7 @@ gst_v4l2_object_probe_caps_for_format_and_size (GstV4l2Object * v4l2object,
gst_value_list_append_value (&rates, &rate); gst_value_list_append_value (&rates, &rate);
ival.index++; ival.index++;
} while (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) >= 0); } while (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) >= 0);
} else if (ival.type == V4L2_FRMIVAL_TYPE_STEPWISE) { } else if (ival.type == V4L2_FRMIVAL_TYPE_STEPWISE) {
GValue min = { 0, }; GValue min = { 0, };
GValue step = { 0, }; GValue step = { 0, };
@ -2535,7 +2560,7 @@ gst_v4l2_object_probe_caps_for_format (GstV4l2Object * v4l2object,
"Enumerating frame sizes for %" GST_FOURCC_FORMAT, "Enumerating frame sizes for %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (pixelformat)); GST_FOURCC_ARGS (pixelformat));
if (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0) if (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0)
goto enum_framesizes_failed; goto enum_framesizes_failed;
if (size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { if (size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
@ -2556,7 +2581,7 @@ gst_v4l2_object_probe_caps_for_format (GstV4l2Object * v4l2object,
} }
size.index++; size.index++;
} while (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0); } while (v4l2object->ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0);
GST_DEBUG_OBJECT (v4l2object->element, GST_DEBUG_OBJECT (v4l2object->element,
"done iterating discrete frame sizes"); "done iterating discrete frame sizes");
} else if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE) { } else if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
@ -3369,10 +3394,10 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps,
} }
if (try_only) { if (try_only) {
if (v4l2_ioctl (fd, VIDIOC_TRY_FMT, &format) < 0) if (v4l2object->ioctl (fd, VIDIOC_TRY_FMT, &format) < 0)
goto try_fmt_failed; goto try_fmt_failed;
} else { } else {
if (v4l2_ioctl (fd, VIDIOC_S_FMT, &format) < 0) if (v4l2object->ioctl (fd, VIDIOC_S_FMT, &format) < 0)
goto set_fmt_failed; goto set_fmt_failed;
} }
@ -3454,7 +3479,7 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps,
ctl.id = V4L2_CID_ALPHA_COMPONENT; ctl.id = V4L2_CID_ALPHA_COMPONENT;
ctl.value = 0xff; ctl.value = 0xff;
if (v4l2_ioctl (fd, VIDIOC_S_CTRL, &ctl) < 0) if (v4l2object->ioctl (fd, VIDIOC_S_CTRL, &ctl) < 0)
GST_WARNING_OBJECT (v4l2object->element, GST_WARNING_OBJECT (v4l2object->element,
"Failed to set alpha component value"); "Failed to set alpha component value");
} }
@ -3466,7 +3491,7 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps,
memset (&streamparm, 0x00, sizeof (struct v4l2_streamparm)); memset (&streamparm, 0x00, sizeof (struct v4l2_streamparm));
streamparm.type = v4l2object->type; streamparm.type = v4l2object->type;
if (v4l2_ioctl (fd, VIDIOC_G_PARM, &streamparm) < 0) if (v4l2object->ioctl (fd, VIDIOC_G_PARM, &streamparm) < 0)
goto get_parm_failed; goto get_parm_failed;
if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE
@ -3500,7 +3525,7 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps,
streamparm.parm.capture.timeperframe.denominator = fps_n; streamparm.parm.capture.timeperframe.denominator = fps_n;
/* some cheap USB cam's won't accept any change */ /* some cheap USB cam's won't accept any change */
if (v4l2_ioctl (fd, VIDIOC_S_PARM, &streamparm) < 0) if (v4l2object->ioctl (fd, VIDIOC_S_PARM, &streamparm) < 0)
goto set_parm_failed; goto set_parm_failed;
if (streamparm.parm.capture.timeperframe.numerator > 0 && if (streamparm.parm.capture.timeperframe.numerator > 0 &&
@ -3542,7 +3567,7 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps,
streamparm.parm.output.timeperframe.numerator = fps_d; streamparm.parm.output.timeperframe.numerator = fps_d;
streamparm.parm.output.timeperframe.denominator = fps_n; streamparm.parm.output.timeperframe.denominator = fps_n;
if (v4l2_ioctl (fd, VIDIOC_S_PARM, &streamparm) < 0) if (v4l2object->ioctl (fd, VIDIOC_S_PARM, &streamparm) < 0)
goto set_parm_failed; goto set_parm_failed;
if (streamparm.parm.output.timeperframe.numerator > 0 && if (streamparm.parm.output.timeperframe.numerator > 0 &&
@ -3750,7 +3775,7 @@ gst_v4l2_object_acquire_format (GstV4l2Object * v4l2object, GstVideoInfo * info)
memset (&fmt, 0x00, sizeof (struct v4l2_format)); memset (&fmt, 0x00, sizeof (struct v4l2_format));
fmt.type = v4l2object->type; fmt.type = v4l2object->type;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_FMT, &fmt) < 0) if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_FMT, &fmt) < 0)
goto get_fmt_failed; goto get_fmt_failed;
fmtdesc = gst_v4l2_object_get_format_from_fourcc (v4l2object, fmtdesc = gst_v4l2_object_get_format_from_fourcc (v4l2object,
@ -3775,13 +3800,13 @@ gst_v4l2_object_acquire_format (GstV4l2Object * v4l2object, GstVideoInfo * info)
memset (&sel, 0, sizeof (struct v4l2_selection)); memset (&sel, 0, sizeof (struct v4l2_selection));
sel.type = v4l2object->type; sel.type = v4l2object->type;
sel.target = V4L2_SEL_TGT_COMPOSE_DEFAULT; sel.target = V4L2_SEL_TGT_COMPOSE_DEFAULT;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_SELECTION, &sel) >= 0) { if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_SELECTION, &sel) >= 0) {
r = &sel.r; r = &sel.r;
} else { } else {
/* For ancient kernels, fall back to G_CROP */ /* For ancient kernels, fall back to G_CROP */
memset (&crop, 0, sizeof (struct v4l2_crop)); memset (&crop, 0, sizeof (struct v4l2_crop));
crop.type = v4l2object->type; crop.type = v4l2object->type;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_CROP, &crop) >= 0) if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CROP, &crop) >= 0)
r = &crop.c; r = &crop.c;
} }
if (r) { if (r) {
@ -3869,12 +3894,12 @@ gst_v4l2_object_set_crop (GstV4l2Object * obj)
"Desired cropping left %u, top %u, size %ux%u", crop.c.left, crop.c.top, "Desired cropping left %u, top %u, size %ux%u", crop.c.left, crop.c.top,
crop.c.width, crop.c.height); crop.c.width, crop.c.height);
if (v4l2_ioctl (obj->video_fd, VIDIOC_S_CROP, &crop) < 0) { if (obj->ioctl (obj->video_fd, VIDIOC_S_CROP, &crop) < 0) {
GST_WARNING_OBJECT (obj->element, "VIDIOC_S_CROP failed"); GST_WARNING_OBJECT (obj->element, "VIDIOC_S_CROP failed");
return FALSE; return FALSE;
} }
if (v4l2_ioctl (obj->video_fd, VIDIOC_G_CROP, &crop) < 0) { if (obj->ioctl (obj->video_fd, VIDIOC_G_CROP, &crop) < 0) {
GST_WARNING_OBJECT (obj->element, "VIDIOC_G_CROP failed"); GST_WARNING_OBJECT (obj->element, "VIDIOC_G_CROP failed");
return FALSE; return FALSE;
} }
@ -3972,7 +3997,7 @@ gst_v4l2_object_probe_caps (GstV4l2Object * v4l2object, GstCaps * filter)
memset (&cropcap, 0, sizeof (cropcap)); memset (&cropcap, 0, sizeof (cropcap));
cropcap.type = v4l2object->type; cropcap.type = v4l2object->type;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_CROPCAP, &cropcap) < 0) { if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_CROPCAP, &cropcap) < 0) {
if (errno != ENOTTY) if (errno != ENOTTY)
GST_WARNING_OBJECT (v4l2object->element, GST_WARNING_OBJECT (v4l2object->element,
"Failed to probe pixel aspect ratio with VIDIOC_CROPCAP: %s", "Failed to probe pixel aspect ratio with VIDIOC_CROPCAP: %s",

View file

@ -24,23 +24,11 @@
#ifndef __GST_V4L2_OBJECT_H__ #ifndef __GST_V4L2_OBJECT_H__
#define __GST_V4L2_OBJECT_H__ #define __GST_V4L2_OBJECT_H__
#include "ext/videodev2.h"
#ifdef HAVE_LIBV4L2 #ifdef HAVE_LIBV4L2
# include <libv4l2.h> # include <libv4l2.h>
#else
# include "ext/videodev2.h"
# include <sys/ioctl.h>
# include <sys/mman.h>
# include <unistd.h>
# define v4l2_fd_open(fd, flags) (fd)
# define v4l2_close close
# define v4l2_dup dup
# define v4l2_ioctl ioctl
# define v4l2_read read
# define v4l2_mmap mmap
# define v4l2_munmap munmap
#endif #endif
#include "ext/videodev2.h"
#include "v4l2-utils.h" #include "v4l2-utils.h"
#include <gst/gst.h> #include <gst/gst.h>
@ -212,6 +200,16 @@ struct _GstV4l2Object {
GstV4l2SetInOutFunction set_in_out_func; GstV4l2SetInOutFunction set_in_out_func;
GstV4l2UpdateFpsFunction update_fps_func; GstV4l2UpdateFpsFunction update_fps_func;
/* syscalls */
int (*fd_open) (int fd, int v4l2_flags);
int (*close) (int fd);
int (*dup) (int fd);
int (*ioctl) (int fd, unsigned long int request, ...);
ssize_t (*read) (int fd, void *buffer, size_t n);
void * (*mmap) (void *start, size_t length, int prot, int flags,
int fd, int64_t offset);
int (*munmap) (void *_start, size_t length);
/* Quirks */ /* Quirks */
/* Skips interlacing probes */ /* Skips interlacing probes */
gboolean never_interlaced; gboolean never_interlaced;

View file

@ -86,7 +86,7 @@ gst_v4l2radio_fill_channel_list (GstV4l2Radio * radio)
memset (&vc, 0, sizeof (vc)); memset (&vc, 0, sizeof (vc));
res = v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &vc); res = v4l2object->ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &vc);
if (res < 0) if (res < 0)
goto caps_failed; goto caps_failed;
@ -102,7 +102,7 @@ gst_v4l2radio_fill_channel_list (GstV4l2Radio * radio)
memset (&vtun, 0, sizeof (vtun)); memset (&vtun, 0, sizeof (vtun));
vtun.index = 0; vtun.index = 0;
res = v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &vtun); res = v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &vtun);
if (res < 0) if (res < 0)
goto tuner_failed; goto tuner_failed;

View file

@ -246,16 +246,16 @@ gst_v4l2sink_sync_overlay_fields (GstV4l2Sink * v4l2sink)
if (GST_V4L2_IS_OPEN (v4l2sink->v4l2object)) { if (GST_V4L2_IS_OPEN (v4l2sink->v4l2object)) {
gint fd = v4l2sink->v4l2object->video_fd; GstV4l2Object *obj = v4l2sink->v4l2object;
struct v4l2_format format; struct v4l2_format format;
memset (&format, 0x00, sizeof (struct v4l2_format)); memset (&format, 0x00, sizeof (struct v4l2_format));
if (v4l2sink->v4l2object->device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY) if (obj->device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)
format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY; format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY;
else else
format.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; format.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
if (v4l2_ioctl (fd, VIDIOC_G_FMT, &format) < 0) { if (obj->ioctl (obj->video_fd, VIDIOC_G_FMT, &format) < 0) {
GST_WARNING_OBJECT (v4l2sink, "VIDIOC_G_FMT failed"); GST_WARNING_OBJECT (v4l2sink, "VIDIOC_G_FMT failed");
return; return;
} }
@ -275,7 +275,7 @@ gst_v4l2sink_sync_overlay_fields (GstV4l2Sink * v4l2sink)
if (v4l2sink->overlay_fields_set & RECT_HEIGHT_SET) if (v4l2sink->overlay_fields_set & RECT_HEIGHT_SET)
format.fmt.win.w.height = v4l2sink->overlay.height; format.fmt.win.w.height = v4l2sink->overlay.height;
if (v4l2_ioctl (fd, VIDIOC_S_FMT, &format) < 0) { if (obj->ioctl (obj->video_fd, VIDIOC_S_FMT, &format) < 0) {
GST_WARNING_OBJECT (v4l2sink, "VIDIOC_S_FMT failed"); GST_WARNING_OBJECT (v4l2sink, "VIDIOC_S_FMT failed");
return; return;
} }
@ -293,13 +293,13 @@ gst_v4l2sink_sync_crop_fields (GstV4l2Sink * v4l2sink)
if (GST_V4L2_IS_OPEN (v4l2sink->v4l2object)) { if (GST_V4L2_IS_OPEN (v4l2sink->v4l2object)) {
gint fd = v4l2sink->v4l2object->video_fd; GstV4l2Object *obj = v4l2sink->v4l2object;
struct v4l2_crop crop; struct v4l2_crop crop;
memset (&crop, 0x00, sizeof (struct v4l2_crop)); memset (&crop, 0x00, sizeof (struct v4l2_crop));
crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
if (v4l2_ioctl (fd, VIDIOC_G_CROP, &crop) < 0) { if (obj->ioctl (obj->video_fd, VIDIOC_G_CROP, &crop) < 0) {
GST_WARNING_OBJECT (v4l2sink, "VIDIOC_G_CROP failed"); GST_WARNING_OBJECT (v4l2sink, "VIDIOC_G_CROP failed");
return; return;
} }
@ -319,12 +319,12 @@ gst_v4l2sink_sync_crop_fields (GstV4l2Sink * v4l2sink)
if (v4l2sink->crop_fields_set & RECT_HEIGHT_SET) if (v4l2sink->crop_fields_set & RECT_HEIGHT_SET)
crop.c.height = v4l2sink->crop.height; crop.c.height = v4l2sink->crop.height;
if (v4l2_ioctl (fd, VIDIOC_S_CROP, &crop) < 0) { if (obj->ioctl (obj->video_fd, VIDIOC_S_CROP, &crop) < 0) {
GST_WARNING_OBJECT (v4l2sink, "VIDIOC_S_CROP failed"); GST_WARNING_OBJECT (v4l2sink, "VIDIOC_S_CROP failed");
return; return;
} }
if (v4l2_ioctl (fd, VIDIOC_G_CROP, &crop) < 0) { if (obj->ioctl (obj->video_fd, VIDIOC_G_CROP, &crop) < 0) {
GST_WARNING_OBJECT (v4l2sink, "VIDIOC_G_CROP failed"); GST_WARNING_OBJECT (v4l2sink, "VIDIOC_G_CROP failed");
return; return;
} }

View file

@ -38,6 +38,10 @@
* ]| This pipeline shows the video captured from a webcam that delivers jpeg * ]| This pipeline shows the video captured from a webcam that delivers jpeg
* images. * images.
* </refsect2> * </refsect2>
*
* Since 1.14, the use of libv4l2 has been disabled due to major bugs in the
* emulation layer. To enable usage of this library, set the environment
* variable GST_V4L2_USE_LIBV4L2=1.
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H

View file

@ -311,7 +311,7 @@ gst_v4l2_decoder_cmd (GstV4l2Object * v4l2object, guint cmd, guint flags)
dcmd.cmd = cmd; dcmd.cmd = cmd;
dcmd.flags = flags; dcmd.flags = flags;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_DECODER_CMD, &dcmd) < 0) if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_DECODER_CMD, &dcmd) < 0)
goto dcmd_failed; goto dcmd_failed;
return TRUE; return TRUE;

View file

@ -241,7 +241,7 @@ gst_v4l2_encoder_cmd (GstV4l2Object * v4l2object, guint cmd, guint flags)
ecmd.cmd = cmd; ecmd.cmd = cmd;
ecmd.flags = flags; ecmd.flags = flags;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_ENCODER_CMD, &ecmd) < 0) if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_ENCODER_CMD, &ecmd) < 0)
goto ecmd_failed; goto ecmd_failed;
return TRUE; return TRUE;

View file

@ -68,7 +68,8 @@ gst_v4l2_get_capabilities (GstV4l2Object * v4l2object)
if (!GST_V4L2_IS_OPEN (v4l2object)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &v4l2object->vcap) < 0) if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP,
&v4l2object->vcap) < 0)
goto cap_failed; goto cap_failed;
if (v4l2object->vcap.capabilities & V4L2_CAP_DEVICE_CAPS) if (v4l2object->vcap.capabilities & V4L2_CAP_DEVICE_CAPS)
@ -147,7 +148,7 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
memset (&input, 0, sizeof (input)); memset (&input, 0, sizeof (input));
input.index = n; input.index = n;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_ENUMINPUT, &input) < 0) { if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_ENUMINPUT, &input) < 0) {
if (errno == EINVAL || errno == ENOTTY) if (errno == EINVAL || errno == ENOTTY)
break; /* end of enumeration */ break; /* end of enumeration */
else { else {
@ -181,7 +182,7 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
channel->flags |= GST_TUNER_CHANNEL_FREQUENCY; channel->flags |= GST_TUNER_CHANNEL_FREQUENCY;
vtun.index = input.tuner; vtun.index = input.tuner;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &vtun) < 0) { if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &vtun) < 0) {
GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS, GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
(_("Failed to get setting of tuner %d on device '%s'."), (_("Failed to get setting of tuner %d on device '%s'."),
input.tuner, v4l2object->videodev), GST_ERROR_SYSTEM); input.tuner, v4l2object->videodev), GST_ERROR_SYSTEM);
@ -222,7 +223,7 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
standard.frameperiod.denominator = 0; standard.frameperiod.denominator = 0;
standard.index = n; standard.index = n;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_ENUMSTD, &standard) < 0) { if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_ENUMSTD, &standard) < 0) {
if (errno == EINVAL || errno == ENOTTY) if (errno == EINVAL || errno == ENOTTY)
break; /* end of enumeration */ break; /* end of enumeration */
#ifdef ENODATA #ifdef ENODATA
@ -280,7 +281,8 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
GST_DEBUG_OBJECT (e, "checking control %08x", n); GST_DEBUG_OBJECT (e, "checking control %08x", n);
control.id = n | next; control.id = n | next;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYCTRL, &control) < 0) { if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_QUERYCTRL,
&control) < 0) {
if (next) { if (next) {
if (n > 0) { if (n > 0) {
GST_DEBUG_OBJECT (e, "controls finished"); GST_DEBUG_OBJECT (e, "controls finished");
@ -405,7 +407,8 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
menu.id = n; menu.id = n;
for (i = 0;; i++) { for (i = 0;; i++) {
menu.index = i; menu.index = i;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYMENU, &menu) < 0) { if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_QUERYMENU,
&menu) < 0) {
if (errno == EINVAL) if (errno == EINVAL)
break; /* end of enumeration */ break; /* end of enumeration */
else { else {
@ -515,7 +518,7 @@ gboolean
gst_v4l2_open (GstV4l2Object * v4l2object) gst_v4l2_open (GstV4l2Object * v4l2object)
{ {
struct stat st; struct stat st;
int libv4l2_fd; int libv4l2_fd = -1;
GST_DEBUG_OBJECT (v4l2object->element, "Trying to open device %s", GST_DEBUG_OBJECT (v4l2object->element, "Trying to open device %s",
v4l2object->videodev); v4l2object->videodev);
@ -541,8 +544,12 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
if (!GST_V4L2_IS_OPEN (v4l2object)) if (!GST_V4L2_IS_OPEN (v4l2object))
goto not_open; goto not_open;
libv4l2_fd = v4l2_fd_open (v4l2object->video_fd, #ifdef HAVE_LIBV4L2
V4L2_ENABLE_ENUM_FMT_EMULATION); if (v4l2object->fd_open)
libv4l2_fd = v4l2object->fd_open (v4l2object->video_fd,
V4L2_ENABLE_ENUM_FMT_EMULATION);
#endif
/* Note the v4l2_xxx functions are designed so that if they get passed an /* Note the v4l2_xxx functions are designed so that if they get passed an
unknown fd, the will behave exactly as their regular xxx counterparts, so unknown fd, the will behave exactly as their regular xxx counterparts, so
if v4l2_fd_open fails, we continue as normal (missing the libv4l2 custom if v4l2_fd_open fails, we continue as normal (missing the libv4l2 custom
@ -651,7 +658,7 @@ error:
{ {
if (GST_V4L2_IS_OPEN (v4l2object)) { if (GST_V4L2_IS_OPEN (v4l2object)) {
/* close device */ /* close device */
v4l2_close (v4l2object->video_fd); v4l2object->close (v4l2object->video_fd);
v4l2object->video_fd = -1; v4l2object->video_fd = -1;
} }
/* empty lists */ /* empty lists */
@ -676,7 +683,7 @@ gst_v4l2_dup (GstV4l2Object * v4l2object, GstV4l2Object * other)
v4l2object->device_caps = other->device_caps; v4l2object->device_caps = other->device_caps;
gst_v4l2_adjust_buf_type (v4l2object); gst_v4l2_adjust_buf_type (v4l2object);
v4l2object->video_fd = v4l2_dup (other->video_fd); v4l2object->video_fd = v4l2object->dup (other->video_fd);
if (!GST_V4L2_IS_OPEN (v4l2object)) if (!GST_V4L2_IS_OPEN (v4l2object))
goto not_open; goto not_open;
@ -717,7 +724,7 @@ gst_v4l2_close (GstV4l2Object * v4l2object)
GST_V4L2_CHECK_NOT_ACTIVE (v4l2object); GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
/* close device */ /* close device */
v4l2_close (v4l2object->video_fd); v4l2object->close (v4l2object->video_fd);
v4l2object->video_fd = -1; v4l2object->video_fd = -1;
/* empty lists */ /* empty lists */
@ -740,7 +747,7 @@ gst_v4l2_get_norm (GstV4l2Object * v4l2object, v4l2_std_id * norm)
if (!GST_V4L2_IS_OPEN (v4l2object)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_STD, norm) < 0) if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_STD, norm) < 0)
goto std_failed; goto std_failed;
return TRUE; return TRUE;
@ -769,7 +776,7 @@ gst_v4l2_set_norm (GstV4l2Object * v4l2object, v4l2_std_id norm)
if (!GST_V4L2_IS_OPEN (v4l2object)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_STD, &norm) < 0) if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_STD, &norm) < 0)
goto std_failed; goto std_failed;
return TRUE; return TRUE;
@ -805,7 +812,7 @@ gst_v4l2_get_frequency (GstV4l2Object * v4l2object,
channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element)); channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element));
freq.tuner = tunernum; freq.tuner = tunernum;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0) if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0)
goto freq_failed; goto freq_failed;
*frequency = freq.frequency * channel->freq_multiplicator; *frequency = freq.frequency * channel->freq_multiplicator;
@ -846,10 +853,10 @@ gst_v4l2_set_frequency (GstV4l2Object * v4l2object,
freq.tuner = tunernum; freq.tuner = tunernum;
/* fill in type - ignore error */ /* fill in type - ignore error */
(void) v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq); (void) v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq);
freq.frequency = frequency / channel->freq_multiplicator; freq.frequency = frequency / channel->freq_multiplicator;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_FREQUENCY, &freq) < 0) if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_FREQUENCY, &freq) < 0)
goto freq_failed; goto freq_failed;
return TRUE; return TRUE;
@ -881,7 +888,7 @@ gst_v4l2_signal_strength (GstV4l2Object * v4l2object,
return FALSE; return FALSE;
tuner.index = tunernum; tuner.index = tunernum;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &tuner) < 0) if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &tuner) < 0)
goto tuner_failed; goto tuner_failed;
*signal_strength = tuner.signal; *signal_strength = tuner.signal;
@ -917,7 +924,7 @@ gst_v4l2_get_attribute (GstV4l2Object * v4l2object,
control.id = attribute_num; control.id = attribute_num;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0) if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0)
goto ctrl_failed; goto ctrl_failed;
*value = control.value; *value = control.value;
@ -954,7 +961,7 @@ gst_v4l2_set_attribute (GstV4l2Object * v4l2object,
control.id = attribute_num; control.id = attribute_num;
control.value = value; control.value = value;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0)
goto ctrl_failed; goto ctrl_failed;
return TRUE; return TRUE;
@ -1027,7 +1034,7 @@ gst_v4l2_get_input (GstV4l2Object * v4l2object, gint * input)
if (!GST_V4L2_IS_OPEN (v4l2object)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_INPUT, &n) < 0) if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_INPUT, &n) < 0)
goto input_failed; goto input_failed;
*input = n; *input = n;
@ -1056,7 +1063,7 @@ gst_v4l2_set_input (GstV4l2Object * v4l2object, gint input)
if (!GST_V4L2_IS_OPEN (v4l2object)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_INPUT, &input) < 0) if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_INPUT, &input) < 0)
goto input_failed; goto input_failed;
return TRUE; return TRUE;
@ -1084,7 +1091,7 @@ gst_v4l2_get_output (GstV4l2Object * v4l2object, gint * output)
if (!GST_V4L2_IS_OPEN (v4l2object)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_OUTPUT, &n) < 0) if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_OUTPUT, &n) < 0)
goto output_failed; goto output_failed;
*output = n; *output = n;
@ -1113,7 +1120,7 @@ gst_v4l2_set_output (GstV4l2Object * v4l2object, gint output)
if (!GST_V4L2_IS_OPEN (v4l2object)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_OUTPUT, &output) < 0) if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_OUTPUT, &output) < 0)
goto output_failed; goto output_failed;
return TRUE; return TRUE;