[Spice-devel] [RFC v2 1/5] gstreamer-encoder: Use a dmabuf allocator for a valid fd

Vivek Kasireddy vivek.kasireddy at intel.com
Mon Jan 23 08:41:19 UTC 2023


If a valid dmabuf fd is shared with the encoder, then this patch
enables the creation of Gst memory with the fd as the source by
using a dmabuf allocator. This patch also adds code to invoke
any registered callbacks after the Gst memory object is no longer
in use by the pipeline.

Cc: Gerd Hoffmann <kraxel at redhat.com>
Cc: Marc-André Lureau <marcandre.lureau at redhat.com>
Cc: Dongwon Kim <dongwon.kim at intel.com>
Signed-off-by: Vivek Kasireddy <vivek.kasireddy at intel.com>
---
 meson.build                |  2 +-
 server/gstreamer-encoder.c | 48 +++++++++++++++++++++++++++++++++++---
 server/video-encoder.h     |  7 ++++++
 3 files changed, 53 insertions(+), 4 deletions(-)

diff --git a/meson.build b/meson.build
index ef8b41ad..d66fac10 100644
--- a/meson.build
+++ b/meson.build
@@ -131,7 +131,7 @@ endforeach
 spice_server_has_gstreamer = false
 spice_server_gst_version = get_option('gstreamer')
 if spice_server_gst_version != 'no'
-  gst_deps = ['gstreamer', 'gstreamer-base', 'gstreamer-app', 'gstreamer-video']
+  gst_deps = ['gstreamer', 'gstreamer-base', 'gstreamer-app', 'gstreamer-video', 'gstreamer-allocators']
   foreach dep : gst_deps
     dep = '@0 at -@1@'.format(dep, spice_server_gst_version)
     spice_server_deps += dependency(dep)
diff --git a/server/gstreamer-encoder.c b/server/gstreamer-encoder.c
index 5ea11f4b..f590a495 100644
--- a/server/gstreamer-encoder.c
+++ b/server/gstreamer-encoder.c
@@ -22,6 +22,7 @@
 #include <pthread.h>
 
 #include <gst/gst.h>
+#include <gst/allocators/gstdmabuf.h>
 #include <gst/app/gstappsrc.h>
 #include <gst/app/gstappsink.h>
 #include <gst/video/video.h>
@@ -298,6 +299,8 @@ typedef struct SpiceGstEncoder {
 
     /* How many frames were dropped by the server since the last encoded frame. */
     uint32_t server_drops;
+
+    GstAllocator *allocator;
 } SpiceGstEncoder;
 
 
@@ -335,8 +338,12 @@ static inline double get_mbps(uint64_t bit_rate)
  */
 static uint32_t get_source_fps(const SpiceGstEncoder *encoder)
 {
-    return encoder->cbs.get_source_fps ?
-        encoder->cbs.get_source_fps(encoder->cbs.opaque) : SPICE_GST_DEFAULT_FPS;
+    uint32_t source_fps = 0;
+
+    if (encoder->cbs.get_source_fps) {
+        source_fps = encoder->cbs.get_source_fps(encoder->cbs.opaque);
+    }
+    return source_fps ? source_fps : SPICE_GST_DEFAULT_FPS;
 }
 
 static uint32_t get_network_latency(const SpiceGstEncoder *encoder)
@@ -1346,6 +1353,23 @@ static void unmap_and_release_memory(GstMapInfo *map, GstBuffer *buffer)
     gst_buffer_unref(buffer);
 }
 
+static void bitmap_wrapper_weak_unref(BitmapWrapper *wrapper,
+                                      GstMiniObject *obj)
+{
+    VideoEncoder *encoder = &wrapper->encoder->base;
+
+    if (g_atomic_int_dec_and_test(&wrapper->refs)) {
+        g_async_queue_push(wrapper->encoder->unused_bitmap_opaques,
+                           wrapper->opaque);
+        g_free(wrapper);
+    }
+    if (encoder->dmabuf_data) {
+        encoder->dmabuf_data->notify_mem_free(encoder->dmabuf_data->opaque);
+        g_free(encoder->dmabuf_data);
+        encoder->dmabuf_data = NULL;
+    }
+}
+
 /* A helper for spice_gst_encoder_encode_frame() */
 static VideoEncodeResults
 push_raw_frame(SpiceGstEncoder *encoder,
@@ -1367,7 +1391,23 @@ push_raw_frame(SpiceGstEncoder *encoder,
     uint32_t skip_lines = top_down ? src->top : bitmap->y - (src->bottom - 0);
     uint32_t chunk_offset = bitmap->stride * skip_lines;
 
-    if (stream_stride != bitmap->stride) {
+    if (encoder->base.dmabuf_data) {
+        GstMemory *mem = NULL;
+        BitmapWrapper *wrapper = NULL;
+        int fd = encoder->base.dmabuf_data->dmabuf_fd;
+
+        mem = gst_dmabuf_allocator_alloc_with_flags(encoder->allocator,
+                                                    fd, stream_stride * height,
+                                                    GST_FD_MEMORY_FLAG_DONT_CLOSE);
+        if (!mem) {
+            return VIDEO_ENCODER_FRAME_UNSUPPORTED;
+        }
+        gst_buffer_append_memory(buffer, mem);
+        wrapper = bitmap_wrapper_new(encoder, bitmap_opaque);
+        gst_mini_object_weak_ref(GST_MINI_OBJECT(mem),
+                                 (GstMiniObjectNotify)bitmap_wrapper_weak_unref,
+                                 wrapper);
+    } else if (stream_stride != bitmap->stride) {
         /* We have to do a line-by-line copy because for each we have to
          * leave out pixels on the left or right.
          */
@@ -1456,6 +1496,7 @@ static void spice_gst_encoder_destroy(VideoEncoder *video_encoder)
 {
     SpiceGstEncoder *encoder = (SpiceGstEncoder*)video_encoder;
 
+    gst_object_unref(encoder->allocator);
     free_pipeline(encoder);
     pthread_mutex_destroy(&encoder->outbuf_mutex);
     pthread_cond_destroy(&encoder->outbuf_cond);
@@ -1772,6 +1813,7 @@ VideoEncoder *gstreamer_encoder_new(SpiceVideoCodecType codec_type,
     encoder->bitmap_ref = bitmap_ref;
     encoder->bitmap_unref = bitmap_unref;
     encoder->format = GSTREAMER_FORMAT_INVALID;
+    encoder->allocator = gst_dmabuf_allocator_new();
     pthread_mutex_init(&encoder->outbuf_mutex, NULL);
     pthread_cond_init(&encoder->outbuf_cond, NULL);
 
diff --git a/server/video-encoder.h b/server/video-encoder.h
index d5bc0a68..03a6f34d 100644
--- a/server/video-encoder.h
+++ b/server/video-encoder.h
@@ -56,6 +56,12 @@ typedef struct VideoEncoderStats {
     double avg_quality;
 } VideoEncoderStats;
 
+typedef struct VideoEncoderDmabufData {
+    int32_t dmabuf_fd;
+    void *opaque;
+    void (*notify_mem_free)(void *opaque);
+} VideoEncoderDmabufData;
+
 typedef struct VideoEncoder VideoEncoder;
 struct VideoEncoder {
     /* Releases the video encoder's resources */
@@ -142,6 +148,7 @@ struct VideoEncoder {
 
     /* The codec being used by the video encoder */
     SpiceVideoCodecType codec_type;
+    VideoEncoderDmabufData *dmabuf_data;
 };
 
 
-- 
2.37.2



More information about the Spice-devel mailing list