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@xxxxxxxxxx> Cc: Marc-André Lureau <marcandre.lureau@xxxxxxxxxx> Cc: Dongwon Kim <dongwon.kim@xxxxxxxxx> Signed-off-by: Vivek Kasireddy <vivek.kasireddy@xxxxxxxxx> --- 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@-@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