From 602aa7d541e2d3d6b53433aee2042be3bb3c3a9c Mon Sep 17 00:00:00 2001 From: Robert Mader Date: Thu, 5 Jan 2023 15:08:17 +0100 Subject: [PATCH] pipewiresrc: Reenable DMABuf support This was disabled in 15b4c58e as under various circumstances Gstreamer pipelines would mmap the DMABufs, which can be very slow in various cases. One typical example of that is screen casting using a dedicated graphics card. Thus we only want to use DMABufs if the peer element advertises support for `GST_CAPS_FEATURE_MEMORY_DMABUF`, ensuring no mapping will happen if we set the format accordingly. This allows pipewiresrc to be used with DMABufs for fully accelerated pipelines or in combination with a download element such as `gldownload`[1] without regressing the commit above. The `gldownload` approach mirrors what webrtc (Chromium/Firefox) does, but without duplicating the functionality into pipewiresrc. While on it, also implement dmabuf negotiation according to https://docs.pipewire.org/page_dma_buf.html with the modifiers `DRM_FORMAT_MOD_INVALID` and `DRM_FORMAT_MOD_LINEAR` in order to allow dmabuf negotiation with more modern clients, including Gnome-Shell. 1: for now use something like `glupload ! glcolorconvert ! gldownload` - `gldownload` does not support importing DMABufs yet but `glupload` does. --- src/gst/gstpipewireformat.c | 29 ++++++++++++++++++++++++++++- src/gst/gstpipewiresrc.c | 19 +++++++++++++++---- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/gst/gstpipewireformat.c b/src/gst/gstpipewireformat.c index 5e1f86966..110226a05 100644 --- a/src/gst/gstpipewireformat.c +++ b/src/gst/gstpipewireformat.c @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -36,6 +37,14 @@ #include "gstpipewireformat.h" +#ifndef DRM_FORMAT_MOD_INVALID +#define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1) +#endif + +#ifndef DRM_FORMAT_MOD_LINEAR +#define DRM_FORMAT_MOD_LINEAR 0 +#endif + struct media_type { const char *name; uint32_t media_type; @@ -626,6 +635,18 @@ convert_1 (ConvertData *d) spa_pod_builder_prop (&d->b, SPA_FORMAT_mediaSubtype, 0); spa_pod_builder_id(&d->b, d->type->media_subtype); + if (d->cf && gst_caps_features_contains (d->cf, GST_CAPS_FEATURE_MEMORY_DMABUF)) { + struct spa_pod_frame f2; + + spa_pod_builder_prop (&d->b, SPA_FORMAT_VIDEO_modifier, + (SPA_POD_PROP_FLAG_MANDATORY | SPA_POD_PROP_FLAG_DONT_FIXATE)); + spa_pod_builder_push_choice (&d->b, &f2, SPA_CHOICE_Enum, 0); + spa_pod_builder_long (&d->b, DRM_FORMAT_MOD_INVALID); + spa_pod_builder_long (&d->b, DRM_FORMAT_MOD_INVALID); + spa_pod_builder_long (&d->b, DRM_FORMAT_MOD_LINEAR); + spa_pod_builder_pop (&d->b, &f2); + } + if (d->type->media_type == SPA_MEDIA_TYPE_video) handle_video_fields (d); else if (d->type->media_type == SPA_MEDIA_TYPE_audio) @@ -661,13 +682,19 @@ foreach_func (GstCapsFeatures *features, ConvertData *d) { struct spa_pod *fmt; + int idx; spa_zero(d->b); d->cf = features; d->cs = structure; + if (d->cf && gst_caps_features_contains (d->cf, GST_CAPS_FEATURE_MEMORY_DMABUF)) + idx = 0; + else + idx = -1; + if ((fmt = convert_1 (d))) - g_ptr_array_insert (d->array, -1, fmt); + g_ptr_array_insert (d->array, idx, fmt); return TRUE; } diff --git a/src/gst/gstpipewiresrc.c b/src/gst/gstpipewiresrc.c index 0b222aa0e..4e37846fc 100644 --- a/src/gst/gstpipewiresrc.c +++ b/src/gst/gstpipewiresrc.c @@ -43,6 +43,7 @@ #include #include +#include #include #include @@ -949,7 +950,6 @@ on_param_changed (void *data, uint32_t id, if (pwsrc->caps) gst_caps_unref(pwsrc->caps); pwsrc->caps = gst_caps_from_format (param); - GST_DEBUG_OBJECT (pwsrc, "we got format %" GST_PTR_FORMAT, pwsrc->caps); pwsrc->negotiated = pwsrc->caps != NULL; @@ -958,6 +958,19 @@ on_param_changed (void *data, uint32_t id, struct spa_pod_builder b = { NULL }; uint8_t buffer[512]; uint32_t buffers = CLAMP (16, pwsrc->min_buffers, pwsrc->max_buffers); + int buffertypes; + + if (spa_pod_find_prop (param, NULL, SPA_FORMAT_VIDEO_modifier)) { + buffertypes = (1<caps, 0), + GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY); + gst_caps_features_add (gst_caps_get_features (pwsrc->caps, 0), + GST_CAPS_FEATURE_MEMORY_DMABUF); + } else { + buffertypes = ((1<caps); spa_pod_builder_init (&b, buffer, sizeof (buffer)); params[0] = spa_pod_builder_add_object (&b, @@ -968,9 +981,7 @@ on_param_changed (void *data, uint32_t id, SPA_PARAM_BUFFERS_blocks, SPA_POD_CHOICE_RANGE_Int(0, 1, INT32_MAX), SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int(0, 0, INT32_MAX), SPA_PARAM_BUFFERS_stride, SPA_POD_CHOICE_RANGE_Int(0, 0, INT32_MAX), - SPA_PARAM_BUFFERS_dataType, SPA_POD_CHOICE_FLAGS_Int( - (1<