v4l2allocator: support orphaning
authorPhilipp Zabel <p.zabel@pengutronix.de>
Thu, 24 Jan 2019 15:12:13 +0000 (16:12 +0100)
committerNicolas Dufresne <nicolas@ndufresne.ca>
Fri, 5 Apr 2019 16:01:55 +0000 (16:01 +0000)
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
sys/v4l2/gstv4l2allocator.h

index 0281fc5..05bde3d 100644 (file)
@@ -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)
 {
index 2533713..eb51524 100644 (file)
@@ -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,