v4l2object: Add a method to try and import buffers
authorNicolas Dufresne <nicolas.dufresne@collabora.com>
Wed, 1 Aug 2018 17:07:52 +0000 (13:07 -0400)
committerNicolas Dufresne <nicolas.dufresne@collabora.com>
Mon, 27 Aug 2018 17:41:30 +0000 (13:41 -0400)
This method will check if a buffer, base on it's video meta,
can be imported. It will also try and adapt the request stride
in case this is the only that miss-match.

https://bugzilla.gnome.org/show_bug.cgi?id=583890

sys/v4l2/gstv4l2object.c
sys/v4l2/gstv4l2object.h

index f24f441..9b50c16 100644 (file)
@@ -42,6 +42,7 @@
 #include "gst/gst-i18n-plugin.h"
 
 #include <gst/video/video.h>
+#include <gst/allocators/gstdmabuf.h>
 
 GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
 #define GST_CAT_DEFAULT v4l2_debug
@@ -4601,3 +4602,154 @@ different_caps:
     return FALSE;
   }
 }
+
+gboolean
+gst_v4l2_object_try_import (GstV4l2Object * obj, GstBuffer * buffer)
+{
+  GstVideoMeta *vmeta;
+  guint n_mem = gst_buffer_n_memory (buffer);
+
+  /* only import if requested */
+  switch (obj->mode) {
+    case GST_V4L2_IO_USERPTR:
+    case GST_V4L2_IO_DMABUF_IMPORT:
+      break;
+    default:
+      GST_DEBUG_OBJECT (obj->dbg_obj,
+          "The io-mode does not enable importation");
+      return FALSE;
+  }
+
+  vmeta = gst_buffer_get_video_meta (buffer);
+  if (!vmeta && obj->need_video_meta) {
+    GST_DEBUG_OBJECT (obj->dbg_obj, "Downstream buffer uses standard "
+        "stride/offset while the driver does not.");
+    return FALSE;
+  }
+
+  /* we need matching strides/offsets and size */
+  if (vmeta) {
+    guint p;
+    gboolean need_fmt_update = FALSE;
+
+    if (vmeta->n_planes != GST_VIDEO_INFO_N_PLANES (&obj->info)) {
+      GST_WARNING_OBJECT (obj->dbg_obj,
+          "Cannot import buffers with different number planes");
+      return FALSE;
+    }
+
+    for (p = 0; p < vmeta->n_planes; p++) {
+      if (vmeta->stride[p] < obj->info.stride[p]) {
+        GST_DEBUG_OBJECT (obj->dbg_obj,
+            "Not importing as remote stride %i is smaller then %i on plane %u",
+            vmeta->stride[p], obj->info.stride[p], p);
+        return FALSE;
+      } else if (vmeta->stride[p] > obj->info.stride[p]) {
+        need_fmt_update = TRUE;
+      }
+
+      if (vmeta->offset[p] < obj->info.offset[p]) {
+        GST_DEBUG_OBJECT (obj->dbg_obj,
+            "Not importing as offset %" G_GSIZE_FORMAT
+            " is smaller then %" G_GSIZE_FORMAT " on plane %u",
+            vmeta->offset[p], obj->info.offset[p], p);
+        return FALSE;
+      } else if (vmeta->offset[p] > obj->info.offset[p]) {
+        need_fmt_update = TRUE;
+      }
+    }
+
+    if (need_fmt_update) {
+      struct v4l2_format format;
+      gint wanted_stride[GST_VIDEO_MAX_PLANES] = { 0, };
+
+      format = obj->format;
+
+      /* update the current format with the stride we want to import from */
+      if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
+        guint i;
+
+        GST_DEBUG_OBJECT (obj->dbg_obj, "Wanted strides:");
+
+        for (i = 0; i < obj->n_v4l2_planes; i++) {
+          gint stride = vmeta->stride[i];
+
+          if (GST_VIDEO_FORMAT_INFO_IS_TILED (obj->info.finfo))
+            stride = GST_VIDEO_TILE_X_TILES (stride) <<
+                GST_VIDEO_FORMAT_INFO_TILE_WS (obj->info.finfo);
+
+          format.fmt.pix_mp.plane_fmt[i].bytesperline = stride;
+          wanted_stride[i] = stride;
+          GST_DEBUG_OBJECT (obj->dbg_obj, "    [%u] %i", i, wanted_stride[i]);
+        }
+      } else {
+        gint stride = vmeta->stride[0];
+
+        GST_DEBUG_OBJECT (obj->dbg_obj, "Wanted stride: %i", stride);
+
+        if (GST_VIDEO_FORMAT_INFO_IS_TILED (obj->info.finfo))
+          stride = GST_VIDEO_TILE_X_TILES (stride) <<
+              GST_VIDEO_FORMAT_INFO_TILE_WS (obj->info.finfo);
+
+        format.fmt.pix.bytesperline = stride;
+        wanted_stride[0] = stride;
+      }
+
+      if (obj->ioctl (obj->video_fd, VIDIOC_S_FMT, &format) < 0) {
+        GST_WARNING_OBJECT (obj->dbg_obj,
+            "Something went wrong trying to update current format: %s",
+            g_strerror (errno));
+        return FALSE;
+      }
+
+      gst_v4l2_object_save_format (obj, obj->fmtdesc, &format, &obj->info,
+          &obj->align);
+
+      if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
+        guint i;
+
+        for (i = 0; i < obj->n_v4l2_planes; i++) {
+          if (format.fmt.pix_mp.plane_fmt[i].bytesperline != wanted_stride[i]) {
+            GST_DEBUG_OBJECT (obj->dbg_obj,
+                "[%i] Driver did not accept the new stride (wants %i, got %i)",
+                i, format.fmt.pix_mp.plane_fmt[i].bytesperline,
+                wanted_stride[i]);
+            return FALSE;
+          }
+        }
+      } else {
+        if (format.fmt.pix.bytesperline != wanted_stride[0]) {
+          GST_DEBUG_OBJECT (obj->dbg_obj,
+              "Driver did not accept the new stride (wants %i, got %i)",
+              format.fmt.pix.bytesperline, wanted_stride[0]);
+          return FALSE;
+        }
+      }
+    }
+  }
+
+  /* we can always import single memory buffer, but otherwise we need the same
+   * amount of memory object. */
+  if (n_mem != 1 && n_mem != obj->n_v4l2_planes) {
+    GST_DEBUG_OBJECT (obj->dbg_obj, "Can only import %i memory, "
+        "buffers contains %u memory", obj->n_v4l2_planes, n_mem);
+    return FALSE;
+  }
+
+  /* For DMABuf importation we need DMABuf of course */
+  if (obj->mode == GST_V4L2_IO_DMABUF_IMPORT) {
+    guint i;
+
+    for (i = 0; i < n_mem; i++) {
+      GstMemory *mem = gst_buffer_peek_memory (buffer, i);
+
+      if (!gst_is_dmabuf_memory (mem)) {
+        GST_DEBUG_OBJECT (obj->dbg_obj, "Cannot import non-DMABuf memory.");
+        return FALSE;
+      }
+    }
+  }
+
+  /* for the remaining, only the kernel driver can tell */
+  return TRUE;
+}
index 7871eaf..f8a9841 100644 (file)
@@ -277,6 +277,7 @@ gint         gst_v4l2_object_extrapolate_stride (const GstVideoFormatInfo * finf
 
 gboolean     gst_v4l2_object_set_format  (GstV4l2Object * v4l2object, GstCaps * caps, GstV4l2Error * error);
 gboolean     gst_v4l2_object_try_format  (GstV4l2Object * v4l2object, GstCaps * caps, GstV4l2Error * error);
+gboolean     gst_v4l2_object_try_import  (GstV4l2Object * v4l2object, GstBuffer * buffer);
 
 gboolean     gst_v4l2_object_caps_equal       (GstV4l2Object * v4l2object, GstCaps * caps);
 gboolean     gst_v4l2_object_caps_is_subset   (GstV4l2Object * v4l2object, GstCaps * caps);