From 0948ce0478040b2cad84c7f135281a1519112221 Mon Sep 17 00:00:00 2001
From: Philipp Zabel
Date: Thu, 24 Jan 2019 16:12:13 +0100
Subject: [PATCH] v4l2allocator: support orphaning
Recent kernels allow REQBUFS(0) on a queue that still has buffers in
use (mmapped or exported via dmabuf), orphaning all buffers on the queue.
Orphaning the allocator causes it to release all buffers with
REQBUFS(0), even if they are still in use. An orphaned allocator can
only be stopped. It can not be restarted or create new buffers.
---
sys/v4l2/gstv4l2allocator.c | 50 ++++++++++++++++++++++++++++++++++---
sys/v4l2/gstv4l2allocator.h | 8 ++++++
2 files changed, 54 insertions(+), 4 deletions(-)
diff --git a/sys/v4l2/gstv4l2allocator.c b/sys/v4l2/gstv4l2allocator.c
index 0281fc560f..05bde3d2a5 100644
--- a/sys/v4l2/gstv4l2allocator.c
+++ b/sys/v4l2/gstv4l2allocator.c
@@ -503,6 +503,9 @@ gst_v4l2_allocator_probe (GstV4l2Allocator * allocator, guint32 memory,
flags |= bcreate_flag;
}
+ if (breq.capabilities & V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS)
+ flags |= GST_V4L2_ALLOCATOR_FLAG_SUPPORTS_ORPHANED_BUFS;
+
return flags;
}
@@ -518,6 +521,9 @@ gst_v4l2_allocator_create_buf (GstV4l2Allocator * allocator)
if (!g_atomic_int_get (&allocator->active))
goto done;
+ if (GST_V4L2_ALLOCATOR_IS_ORPHANED (allocator))
+ goto orphaned_bug;
+
bcreate.memory = allocator->memory;
bcreate.format = obj->format;
bcreate.count = 1;
@@ -542,6 +548,12 @@ done:
GST_OBJECT_UNLOCK (allocator);
return group;
+orphaned_bug:
+ {
+ GST_ERROR_OBJECT (allocator, "allocator was orphaned, "
+ "not creating new buffers");
+ goto done;
+ }
create_bufs_failed:
{
GST_WARNING_OBJECT (allocator, "error creating a new buffer: %s",
@@ -667,6 +679,9 @@ gst_v4l2_allocator_start (GstV4l2Allocator * allocator, guint32 count,
if (g_atomic_int_get (&allocator->active))
goto already_active;
+ if (GST_V4L2_ALLOCATOR_IS_ORPHANED (allocator))
+ goto orphaned;
+
if (obj->ioctl (obj->video_fd, VIDIOC_REQBUFS, &breq) < 0)
goto reqbufs_failed;
@@ -715,6 +730,11 @@ already_active:
GST_ERROR_OBJECT (allocator, "allocator already active");
goto error;
}
+orphaned:
+ {
+ GST_ERROR_OBJECT (allocator, "allocator was orphaned");
+ goto error;
+ }
reqbufs_failed:
{
GST_ERROR_OBJECT (allocator,
@@ -765,10 +785,12 @@ gst_v4l2_allocator_stop (GstV4l2Allocator * allocator)
gst_v4l2_memory_group_free (group);
}
- /* Not all drivers support rebufs(0), so warn only */
- if (obj->ioctl (obj->video_fd, VIDIOC_REQBUFS, &breq) < 0)
- GST_WARNING_OBJECT (allocator,
- "error releasing buffers buffers: %s", g_strerror (errno));
+ if (!GST_V4L2_ALLOCATOR_IS_ORPHANED (allocator)) {
+ /* Not all drivers support rebufs(0), so warn only */
+ if (obj->ioctl (obj->video_fd, VIDIOC_REQBUFS, &breq) < 0)
+ GST_WARNING_OBJECT (allocator,
+ "error releasing buffers buffers: %s", g_strerror (errno));
+ }
allocator->count = 0;
@@ -779,6 +801,26 @@ done:
return ret;
}
+gboolean
+gst_v4l2_allocator_orphan (GstV4l2Allocator * allocator)
+{
+ GstV4l2Object *obj = allocator->obj;
+ struct v4l2_requestbuffers breq = { 0, obj->type, allocator->memory };
+
+ if (!GST_V4L2_ALLOCATOR_CAN_ORPHAN_BUFS (allocator))
+ return FALSE;
+
+ GST_OBJECT_FLAG_SET (allocator, GST_V4L2_ALLOCATOR_FLAG_ORPHANED);
+
+ if (obj->ioctl (obj->video_fd, VIDIOC_REQBUFS, &breq) < 0) {
+ GST_ERROR_OBJECT (allocator,
+ "error orphaning buffers buffers: %s", g_strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
GstV4l2MemoryGroup *
gst_v4l2_allocator_alloc_mmap (GstV4l2Allocator * allocator)
{
diff --git a/sys/v4l2/gstv4l2allocator.h b/sys/v4l2/gstv4l2allocator.h
index 25337138e0..eb515245a1 100644
--- a/sys/v4l2/gstv4l2allocator.h
+++ b/sys/v4l2/gstv4l2allocator.h
@@ -41,6 +41,10 @@ G_BEGIN_DECLS
(GST_OBJECT_FLAG_IS_SET (obj, GST_V4L2_ALLOCATOR_FLAG_ ## type ## _REQBUFS))
#define GST_V4L2_ALLOCATOR_CAN_ALLOCATE(obj,type) \
(GST_OBJECT_FLAG_IS_SET (obj, GST_V4L2_ALLOCATOR_FLAG_ ## type ## _CREATE_BUFS))
+#define GST_V4L2_ALLOCATOR_CAN_ORPHAN_BUFS(obj) \
+ (GST_OBJECT_FLAG_IS_SET (obj, GST_V4L2_ALLOCATOR_FLAG_SUPPORTS_ORPHANED_BUFS))
+#define GST_V4L2_ALLOCATOR_IS_ORPHANED(obj) \
+ (GST_OBJECT_FLAG_IS_SET (obj, GST_V4L2_ALLOCATOR_FLAG_ORPHANED))
#define GST_V4L2_MEMORY_QUARK gst_v4l2_memory_quark ()
@@ -59,6 +63,8 @@ enum _GstV4l2AllocatorFlags
GST_V4L2_ALLOCATOR_FLAG_USERPTR_CREATE_BUFS = (GST_ALLOCATOR_FLAG_LAST << 3),
GST_V4L2_ALLOCATOR_FLAG_DMABUF_REQBUFS = (GST_ALLOCATOR_FLAG_LAST << 4),
GST_V4L2_ALLOCATOR_FLAG_DMABUF_CREATE_BUFS = (GST_ALLOCATOR_FLAG_LAST << 5),
+ GST_V4L2_ALLOCATOR_FLAG_SUPPORTS_ORPHANED_BUFS = (GST_ALLOCATOR_FLAG_LAST << 6),
+ GST_V4L2_ALLOCATOR_FLAG_ORPHANED = (GST_ALLOCATOR_FLAG_LAST << 7),
};
enum _GstV4l2Return
@@ -122,6 +128,8 @@ guint gst_v4l2_allocator_start (GstV4l2Allocator * alloc
GstV4l2Return gst_v4l2_allocator_stop (GstV4l2Allocator * allocator);
+gboolean gst_v4l2_allocator_orphan (GstV4l2Allocator * allocator);
+
GstV4l2MemoryGroup* gst_v4l2_allocator_alloc_mmap (GstV4l2Allocator * allocator);
GstV4l2MemoryGroup* gst_v4l2_allocator_alloc_dmabuf (GstV4l2Allocator * allocator,