[mutter/gbsneto/dmabuf-screencast: 6/8] screen-cast-stream-src: Allow exporting DMABufs



commit 2fd1f5bf981b791cab5a504d9ace020acda6d6f7
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Mon Dec 9 10:10:40 2019 -0300

    screen-cast-stream-src: Allow exporting DMABufs
    
    Implement add_buffer and remove_buffer, and fallback to a memfd if
    DMA buffer exporting fails.
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/1086

 src/backends/meta-screen-cast-stream-src.c | 100 ++++++++++++++++++++++++++++-
 1 file changed, 98 insertions(+), 2 deletions(-)
---
diff --git a/src/backends/meta-screen-cast-stream-src.c b/src/backends/meta-screen-cast-stream-src.c
index db68b5be4..f49106e53 100644
--- a/src/backends/meta-screen-cast-stream-src.c
+++ b/src/backends/meta-screen-cast-stream-src.c
@@ -25,6 +25,7 @@
 #include "backends/meta-screen-cast-stream-src.h"
 
 #include <errno.h>
+#include <fcntl.h>
 #include <pipewire/pipewire.h>
 #include <spa/param/props.h>
 #include <spa/param/format-utils.h>
@@ -473,7 +474,8 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src)
       return;
     }
 
-  if (meta_screen_cast_stream_src_record_frame (src, data))
+  if (spa_buffer->datas[0].type != SPA_DATA_DmaBuf &&
+      meta_screen_cast_stream_src_record_frame (src, data))
     {
       struct spa_meta_region *spa_meta_video_crop;
 
@@ -642,10 +644,104 @@ on_stream_param_changed (void                 *data,
   pw_stream_update_params (priv->pipewire_stream, params, G_N_ELEMENTS (params));
 }
 
+static void
+on_stream_add_buffer (void             *data,
+                      struct pw_buffer *buffer)
+{
+  MetaScreenCastStreamSrc *src = data;
+  MetaScreenCastStreamSrcPrivate *priv =
+    meta_screen_cast_stream_src_get_instance_private (src);
+  CoglOnscreenDmabufHandle *dmabuf_handle;
+  struct spa_buffer *buf = buffer->buffer;
+  struct spa_data *d;
+  const int bpp = 4;
+  int stride;
+
+  d = buf->datas;
+  dmabuf_handle = meta_screen_cast_stream_src_capture_dmabuf (src);
+
+  stride = SPA_ROUND_UP_N (priv->video_format.size.width * bpp, 4);
+
+  d[0].mapoffset = 0;
+  d[0].maxsize = stride * priv->video_format.size.height;
+
+  if (dmabuf_handle)
+    {
+      d[0].type = SPA_DATA_DmaBuf;
+      d[0].flags = SPA_DATA_FLAG_READWRITE;
+      d[0].fd = cogl_onscreen_dmabuf_handle_get_fd (dmabuf_handle);
+      d[0].data = NULL;
+
+      g_hash_table_insert (priv->dmabuf_handles,
+                           GINT_TO_POINTER (d[0].fd),
+                           dmabuf_handle);
+    }
+  else
+    {
+      unsigned int seals;
+
+      /* Fallback to a memfd buffer */
+      d[0].type = SPA_DATA_MemFd;
+      d[0].flags = SPA_DATA_FLAG_READWRITE;
+      d[0].fd = memfd_create ("video-src-memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING);
+      if (d[0].fd == -1)
+        {
+          g_critical ("Can't create memfd: %m");
+          return;
+        }
+      d[0].mapoffset = 0;
+      d[0].maxsize = stride * priv->video_format.size.height;
+
+      if (ftruncate (d[0].fd, d[0].maxsize) < 0)
+        {
+          g_critical ("Can't truncate to %d: %m", d[0].maxsize);
+          return;
+        }
+
+      seals = F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL;
+      if (fcntl (d[0].fd, F_ADD_SEALS, seals) == -1)
+        g_warning ("Failed to add seals: %m");
+
+      d[0].data = mmap (NULL, d[0].maxsize, PROT_READ | PROT_WRITE,
+                        MAP_SHARED, d[0].fd, d[0].mapoffset);
+      if (d[0].data == MAP_FAILED)
+        {
+          g_critical ("Failed to mmap memory: %m");
+          return;
+        }
+    }
+}
+
+static void
+on_stream_remove_buffer (void             *data,
+                         struct pw_buffer *buffer)
+{
+  MetaScreenCastStreamSrc *src = data;
+  MetaScreenCastStreamSrcPrivate *priv =
+    meta_screen_cast_stream_src_get_instance_private (src);
+  struct spa_buffer *buf = buffer->buffer;
+  struct spa_data *d;
+
+  d = buf->datas;
+
+  if (d[0].type == SPA_DATA_DmaBuf)
+    {
+      if (!g_hash_table_remove (priv->dmabuf_handles, GINT_TO_POINTER (d[0].fd)))
+        g_critical ("Failed to remove non-exported DMA buffer");
+    }
+  else if (d[0].type == SPA_DATA_MemFd)
+    {
+      munmap (d[0].data, d[0].maxsize);
+      close (d[0].fd);
+    }
+}
+
 static const struct pw_stream_events stream_events = {
   PW_VERSION_STREAM_EVENTS,
   .state_changed = on_stream_state_changed,
   .param_changed = on_stream_param_changed,
+  .add_buffer = on_stream_add_buffer,
+  .remove_buffer = on_stream_remove_buffer,
 };
 
 static struct pw_stream *
@@ -710,7 +806,7 @@ create_pipewire_stream (MetaScreenCastStreamSrc  *src,
                               PW_DIRECTION_OUTPUT,
                               SPA_ID_INVALID,
                               (PW_STREAM_FLAG_DRIVER |
-                               PW_STREAM_FLAG_MAP_BUFFERS),
+                               PW_STREAM_FLAG_ALLOC_BUFFERS),
                               params, G_N_ELEMENTS (params));
   if (result != 0)
     {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]