git » pipewire.git » commit fc2c094

1:1.0.6-1

author Jan Alexander Steffens (heftig)
2024-05-09 15:15:54 UTC
committer Jan Alexander Steffens (heftig)
2024-05-09 15:15:54 UTC
parent fb85208e68445bd2db36d64bf4c3caea310fef05

1:1.0.6-1

.SRCINFO +12 -4
0001-gst-Add-support-for-DMA_DRM-explicit-modifiers.patch +939 -0
0002-gst-Sanitize-caps-before-translating.patch +96 -0
0003-gst-Fix-sanitization-of-non-writable-caps.patch +67 -0
0004-gst-Re-enable-handling-of-single-long-modifiers.patch +70 -0
PKGBUILD +14 -7

diff --git a/.SRCINFO b/.SRCINFO
index 2b41cd4..86609f8 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,6 +1,6 @@
 pkgbase = pipewire
 	pkgdesc = Low-latency audio/video router and processor
-	pkgver = 1.0.5
+	pkgver = 1.0.6
 	pkgrel = 1
 	epoch = 1
 	url = https://pipewire.org
@@ -45,8 +45,16 @@ pkgbase = pipewire
 	makedepends = systemd
 	makedepends = valgrind
 	makedepends = webrtc-audio-processing-1
-	source = git+https://gitlab.freedesktop.org/pipewire/pipewire.git#tag=1.0.5
-	b2sums = 46f2e8e0206077590af8e3accd338c84ed66c954955b01bb316f1dd723f4c75d111078b845a0e682c5ca7a8ff398023a9c2d0074530ff85f87ac0c2dee1a6c34
+	source = git+https://gitlab.freedesktop.org/pipewire/pipewire.git#tag=1.0.6
+	source = 0001-gst-Add-support-for-DMA_DRM-explicit-modifiers.patch
+	source = 0002-gst-Sanitize-caps-before-translating.patch
+	source = 0003-gst-Fix-sanitization-of-non-writable-caps.patch
+	source = 0004-gst-Re-enable-handling-of-single-long-modifiers.patch
+	b2sums = 77e01e262df0b0159cc4bbc79387268798d01c6fe035e779e85937e53f486412b210f94454fb6ed78c8f073e9cb1ea4cda551f57e1129cdd30020254e4be778b
+	b2sums = a32e85e5535664d960ad2452638703885e488ad8cf02e6df8378fd4bb9ff8b3c851645fa47ba2037cf597bbfe4b048c33a82977d551df9c3746e175edbd208b3
+	b2sums = 5aca6a491907cabeee40765ef6591448bfd5a684327db5f0ffe0b59c99e23bd7cc13994f8aa42b8f5ae9c1bbd8cd69c487c4b04c6fa1dd98e9934bc4b80a17cb
+	b2sums = 902effec51d1c40191a0a5a8e5dcf54e24062f7228c8de1e25dae5ab622a3adcbbc8156d398fa14ea74a0c8e8fc489144771fbead86f91a79f4435c08f419767
+	b2sums = 87dc2c9e67121311cd960aae0751ac77652cacd6e27b70be71d0738d356d0675e731f0dad3a82f6e71b9ada2a458a13ebb572fccba3d33f88be4dc350cd5e8b3
 
 pkgname = pipewire
 	install = pipewire.install
@@ -54,7 +62,7 @@ pkgname = pipewire
 	license = LGPL-2.1-or-later
 	depends = gcc-libs
 	depends = glibc
-	depends = libpipewire=1:1.0.5-1
+	depends = libpipewire=1:1.0.6-1
 	depends = libcamera-base.so
 	depends = libcamera.so
 	depends = libdbus-1.so
diff --git a/0001-gst-Add-support-for-DMA_DRM-explicit-modifiers.patch b/0001-gst-Add-support-for-DMA_DRM-explicit-modifiers.patch
new file mode 100644
index 0000000..2135f38
--- /dev/null
+++ b/0001-gst-Add-support-for-DMA_DRM-explicit-modifiers.patch
@@ -0,0 +1,939 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robert Mader <robert.mader@collabora.com>
+Date: Fri, 2 Feb 2024 02:20:29 +0100
+Subject: [PATCH] gst: Add support for DMA_DRM / explicit modifiers
+
+Gstreamer 1.24 added and largely switched to a new, modifier aware
+DMABuf API. Unfortunately that breaks the existing DMABuf support in the
+PW Gst element.
+
+Add support for the new API.
+---
+ meson.build                 |   8 +
+ src/gst/gstpipewireformat.c | 521 +++++++++++++++++++++++++-----------
+ src/gst/gstpipewireformat.h |   4 +-
+ src/gst/gstpipewiresink.c   |   2 +-
+ src/gst/gstpipewiresrc.c    |  46 +++-
+ src/gst/gstpipewiresrc.h    |   5 +
+ 6 files changed, 417 insertions(+), 169 deletions(-)
+
+diff --git a/meson.build b/meson.build
+index ab8bf5ca3450..313dec6c2d28 100644
+--- a/meson.build
++++ b/meson.build
+@@ -361,26 +361,34 @@ gst_deps_def = {
+ }
+ 
+ gst_dep = []
++gst_dma_drm_found = false
+ foreach depname, kwargs: gst_deps_def
+   dep = dependency(depname, required: gst_option, kwargs: kwargs)
+   summary({depname: dep.found()}, bool_yn: true, section: 'GStreamer modules')
+   if not dep.found()
+     # Beware, there's logic below depending on the array clear here!
+     gst_dep = []
+     if get_option('gstreamer-device-provider').enabled()
+       error('`gstreamer-device-provider` is enabled but `@0@` was not found.'.format(depname))
+     endif
+     break
+   endif
+   gst_dep += [dep]
++
++  if depname == 'gstreamer-allocators-1.0' and dep.version().version_compare('>= 1.23.1')
++    gst_dma_drm_found = true
++  endif
+ endforeach
+ 
+ # This code relies on the array being empty if any dependency was not found
+ gst_dp_found = gst_dep.length() > 0
+ summary({'gstreamer-device-provider': gst_dp_found}, bool_yn: true, section: 'Backend')
+ 
+ cdata.set('HAVE_GSTREAMER_DEVICE_PROVIDER', get_option('gstreamer-device-provider').allowed())
+ 
++summary({'gstreamer DMA_DRM support': gst_dma_drm_found}, bool_yn: true, section: 'Backend')
++cdata.set('HAVE_GSTREAMER_DMA_DRM', gst_dma_drm_found)
++
+ webrtc_dep = dependency('webrtc-audio-processing-1',
+   version : ['>= 1.2' ],
+   required : false)
+diff --git a/src/gst/gstpipewireformat.c b/src/gst/gstpipewireformat.c
+index b16f7b1cf002..ff1752a06565 100644
+--- a/src/gst/gstpipewireformat.c
++++ b/src/gst/gstpipewireformat.c
+@@ -2,21 +2,27 @@
+ /* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
+ /* SPDX-License-Identifier: MIT */
+ 
++#include "config.h"
++
+ #include <stdio.h>
+ 
+ #include <gst/gst.h>
+ #include <gst/allocators/gstdmabuf.h>
+ #include <gst/video/video.h>
+ #include <gst/audio/audio.h>
+ 
+ #include <spa/utils/string.h>
+ #include <spa/utils/type.h>
+ #include <spa/param/video/format-utils.h>
+ #include <spa/param/audio/format-utils.h>
+-#include <spa/pod/builder.h>
++#include <spa/pod/dynamic.h>
+ 
+ #include "gstpipewireformat.h"
+ 
++#ifndef DRM_FORMAT_INVALID
++#define DRM_FORMAT_INVALID 0
++#endif
++
+ #ifndef DRM_FORMAT_MOD_INVALID
+ #define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
+ #endif
+@@ -169,9 +175,7 @@ static const uint32_t audio_format_map[] = {
+ };
+ 
+ typedef struct {
+-  struct spa_pod_builder b;
+   const struct media_type *type;
+-  uint32_t id;
+   const GstCapsFeatures *cf;
+   const GstStructure *cs;
+   GPtrArray *array;
+@@ -358,89 +362,221 @@ get_range_type2 (const GValue *v1, const GValue *v2)
+   return SPA_CHOICE_Range;
+ }
+ 
+-static gboolean
+-handle_video_fields (ConvertData *d)
++static void
++add_limits (struct spa_pod_dynamic_builder *b, ConvertData *d)
+ {
+-  const GValue *value, *value2;
+-  int i;
+   struct spa_pod_choice *choice;
+   struct spa_pod_frame f;
++  const GValue *value, *value2;
++  int i;
+ 
+-  value = gst_structure_get_value (d->cs, "format");
+-  if (value) {
+-    const char *v;
+-    int idx;
+-    for (i = 0; (v = get_nth_string (value, i)); i++) {
+-      if (i == 0) {
+-        spa_pod_builder_prop (&d->b, SPA_FORMAT_VIDEO_format, 0);
+-        spa_pod_builder_push_choice(&d->b, &f, get_range_type (value), 0);
+-      }
+-
+-      idx = gst_video_format_from_string (v);
+-      if (idx != GST_VIDEO_FORMAT_UNKNOWN && idx < (int)SPA_N_ELEMENTS (video_format_map))
+-        spa_pod_builder_id (&d->b, video_format_map[idx]);
+-    }
+-    if (i > 0) {
+-      choice = spa_pod_builder_pop(&d->b, &f);
+-      if (i == 1)
+-        choice->body.type = SPA_CHOICE_None;
+-    }
+-  }
+   value = gst_structure_get_value (d->cs, "width");
+   value2 = gst_structure_get_value (d->cs, "height");
+   if (value && value2) {
+     struct spa_rectangle v;
+     for (i = 0; get_nth_rectangle (value, value2, i, &v); i++) {
+       if (i == 0) {
+-        spa_pod_builder_prop (&d->b, SPA_FORMAT_VIDEO_size, 0);
+-        spa_pod_builder_push_choice(&d->b, &f, get_range_type2 (value, value2), 0);
++        spa_pod_builder_prop (&b->b, SPA_FORMAT_VIDEO_size, 0);
++        spa_pod_builder_push_choice(&b->b, &f, get_range_type2 (value, value2), 0);
+       }
+ 
+-      spa_pod_builder_rectangle (&d->b, v.width, v.height);
++      spa_pod_builder_rectangle (&b->b, v.width, v.height);
+     }
+     if (i > 0) {
+-      choice = spa_pod_builder_pop(&d->b, &f);
++      choice = spa_pod_builder_pop(&b->b, &f);
+       if (i == 1)
+         choice->body.type = SPA_CHOICE_None;
+     }
+   }
+ 
+   value = gst_structure_get_value (d->cs, "framerate");
+   if (value) {
+     struct spa_fraction v;
+     for (i = 0; get_nth_fraction (value, i, &v); i++) {
+       if (i == 0) {
+-        spa_pod_builder_prop (&d->b, SPA_FORMAT_VIDEO_framerate, 0);
+-        spa_pod_builder_push_choice(&d->b, &f, get_range_type (value), 0);
++        spa_pod_builder_prop (&b->b, SPA_FORMAT_VIDEO_framerate, 0);
++        spa_pod_builder_push_choice(&b->b, &f, get_range_type (value), 0);
+       }
+ 
+-      spa_pod_builder_fraction (&d->b, v.num, v.denom);
++      spa_pod_builder_fraction (&b->b, v.num, v.denom);
+     }
+     if (i > 0) {
+-      choice = spa_pod_builder_pop(&d->b, &f);
++      choice = spa_pod_builder_pop(&b->b, &f);
+       if (i == 1)
+         choice->body.type = SPA_CHOICE_None;
+     }
+   }
+ 
+   value = gst_structure_get_value (d->cs, "max-framerate");
+   if (value) {
+     struct spa_fraction v;
+     for (i = 0; get_nth_fraction (value, i, &v); i++) {
+       if (i == 0) {
+-        spa_pod_builder_prop (&d->b, SPA_FORMAT_VIDEO_maxFramerate, 0);
+-        spa_pod_builder_push_choice(&d->b, &f, get_range_type (value), 0);
++        spa_pod_builder_prop (&b->b, SPA_FORMAT_VIDEO_maxFramerate, 0);
++        spa_pod_builder_push_choice(&b->b, &f, get_range_type (value), 0);
+       }
+ 
+-      spa_pod_builder_fraction (&d->b, v.num, v.denom);
++      spa_pod_builder_fraction (&b->b, v.num, v.denom);
+     }
+     if (i > 0) {
+-      choice = spa_pod_builder_pop(&d->b, &f);
++      choice = spa_pod_builder_pop(&b->b, &f);
+       if (i == 1)
+         choice->body.type = SPA_CHOICE_None;
+     }
+   }
+-  return TRUE;
++}
++
++static void
++add_video_format (gpointer format_ptr,
++                  gpointer modifiers_ptr,
++                  gpointer user_data)
++{
++  uint32_t format = GPOINTER_TO_UINT (format_ptr);
++  GHashTable *modifiers = modifiers_ptr;
++  ConvertData *d = user_data;
++  struct spa_pod_dynamic_builder b;
++  struct spa_pod_frame f;
++
++  spa_pod_dynamic_builder_init (&b, NULL, 0, 1024);
++
++  spa_pod_builder_push_object (&b.b, &f, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
++
++  spa_pod_builder_prop (&b.b, SPA_FORMAT_mediaType, 0);
++  spa_pod_builder_id(&b.b, d->type->media_type);
++
++  spa_pod_builder_prop (&b.b, SPA_FORMAT_mediaSubtype, 0);
++  spa_pod_builder_id(&b.b, d->type->media_subtype);
++
++  spa_pod_builder_prop (&b.b, SPA_FORMAT_VIDEO_format, 0);
++  spa_pod_builder_id (&b.b, format);
++
++  if (g_hash_table_size (modifiers) > 0) {
++    GHashTableIter iter;
++    gpointer key, value;
++
++    g_hash_table_iter_init (&iter, modifiers);
++    if (g_hash_table_size (modifiers) > 1) {
++      struct spa_pod_frame f2;
++
++      spa_pod_builder_prop (&b.b, SPA_FORMAT_VIDEO_modifier,
++                            (SPA_POD_PROP_FLAG_MANDATORY | SPA_POD_PROP_FLAG_DONT_FIXATE));
++      spa_pod_builder_push_choice (&b.b, &f2, SPA_CHOICE_Enum, 0);
++      g_hash_table_iter_next (&iter, &key, &value);
++      spa_pod_builder_long (&b.b, (uint64_t) key);
++      do {
++        spa_pod_builder_long (&b.b, (uint64_t) key);
++      } while (g_hash_table_iter_next (&iter, &key, &value));
++      spa_pod_builder_pop (&b.b, &f2);
++    } else {
++      g_hash_table_iter_next (&iter, &key, &value);
++      spa_pod_builder_prop (&b.b, SPA_FORMAT_VIDEO_modifier,
++                            SPA_POD_PROP_FLAG_MANDATORY);
++      spa_pod_builder_long (&b.b, (uint64_t) key);
++    }
++  }
++
++  add_limits (&b, d);
++
++  g_ptr_array_add (d->array, spa_pod_builder_pop (&b.b, &f));
++}
++
++static void
++handle_video_fields (ConvertData *d)
++{
++  g_autoptr (GHashTable) formats = NULL;
++  const GValue *value;
++  gboolean dmabuf_caps;
++  int i;
++
++  formats = g_hash_table_new_full (NULL, NULL, NULL,
++                                   (GDestroyNotify) g_hash_table_unref);
++  dmabuf_caps = (d->cf &&
++                 gst_caps_features_contains (d->cf,
++                                             GST_CAPS_FEATURE_MEMORY_DMABUF));
++
++  value = gst_structure_get_value (d->cs, "format");
++  if (value) {
++    const char *v;
++
++    for (i = 0; (v = get_nth_string (value, i)); i++) {
++      int idx;
++
++      idx = gst_video_format_from_string (v);
++#ifdef HAVE_GSTREAMER_DMA_DRM
++      if (dmabuf_caps && idx == GST_VIDEO_FORMAT_DMA_DRM) {
++        const GValue *value2;
++
++        value2 = gst_structure_get_value (d->cs, "drm-format");
++        if (value2) {
++          const char *v2;
++          int j;
++
++          for (j = 0; (v2 = get_nth_string (value2, j)); j++) {
++            uint32_t fourcc;
++            uint64_t mod;
++            int idx2;
++
++            fourcc = gst_video_dma_drm_fourcc_from_string (v2, &mod);
++            idx2 = gst_video_dma_drm_fourcc_to_format (fourcc);
++
++            if (idx2 != GST_VIDEO_FORMAT_UNKNOWN &&
++                idx2 < (int)SPA_N_ELEMENTS (video_format_map)) {
++              GHashTable *modifiers =
++                  g_hash_table_lookup (formats,
++                                       GINT_TO_POINTER (video_format_map[idx2]));
++              if (!modifiers) {
++                modifiers = g_hash_table_new (NULL, NULL);
++                g_hash_table_insert (formats,
++                                     GINT_TO_POINTER (video_format_map[idx2]),
++                                     modifiers);
++              }
++
++              g_hash_table_add (modifiers, GINT_TO_POINTER (mod));
++            }
++          }
++        }
++      } else
++#endif
++      if (idx != GST_VIDEO_FORMAT_UNKNOWN &&
++          idx < (int)SPA_N_ELEMENTS (video_format_map)) {
++          GHashTable *modifiers =
++              g_hash_table_lookup (formats,
++                                   GINT_TO_POINTER (video_format_map[idx]));
++          if (!modifiers) {
++            modifiers = g_hash_table_new (NULL, NULL);
++            g_hash_table_insert (formats,
++                                 GINT_TO_POINTER (video_format_map[idx]),
++                                 modifiers);
++          }
++
++          if (dmabuf_caps) {
++            g_hash_table_add (modifiers, GINT_TO_POINTER (DRM_FORMAT_MOD_LINEAR));
++            g_hash_table_add (modifiers, GINT_TO_POINTER (DRM_FORMAT_MOD_INVALID));
++          }
++      }
++    }
++  }
++
++  if (g_hash_table_size (formats) > 0) {
++    g_hash_table_foreach (formats, add_video_format, d);
++  } else if (!dmabuf_caps) {
++    struct spa_pod_dynamic_builder b;
++    struct spa_pod_frame f;
++
++    spa_pod_dynamic_builder_init (&b, NULL, 0, 1024);
++
++    spa_pod_builder_push_object (&b.b, &f, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
++
++    spa_pod_builder_prop (&b.b, SPA_FORMAT_mediaType, 0);
++    spa_pod_builder_id(&b.b, d->type->media_type);
++
++    spa_pod_builder_prop (&b.b, SPA_FORMAT_mediaSubtype, 0);
++    spa_pod_builder_id(&b.b, d->type->media_subtype);
++
++    add_limits (&b, d);
++
++    g_ptr_array_add (d->array, spa_pod_builder_pop (&b.b, &f));
++  }
+ }
+ 
+ static void
+@@ -481,237 +617,207 @@ set_default_channels (struct spa_pod_builder *b, uint32_t channels)
+         SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id, channels, position), 0);
+ }
+ 
+-static gboolean
++static void
+ handle_audio_fields (ConvertData *d)
+ {
+   const GValue *value;
++  struct spa_pod_dynamic_builder b;
+   struct spa_pod_choice *choice;
+-  struct spa_pod_frame f;
++  struct spa_pod_frame f, f0;
+   int i = 0;
+ 
++  spa_pod_dynamic_builder_init (&b, NULL, 0, 1024);
++
++  spa_pod_builder_push_object (&b.b, &f0, SPA_TYPE_OBJECT_Format,
++                               SPA_PARAM_EnumFormat);
++
++  spa_pod_builder_prop (&b.b, SPA_FORMAT_mediaType, 0);
++  spa_pod_builder_id(&b.b, d->type->media_type);
++
++  spa_pod_builder_prop (&b.b, SPA_FORMAT_mediaSubtype, 0);
++  spa_pod_builder_id(&b.b, d->type->media_subtype);
++
+   value = gst_structure_get_value (d->cs, "format");
+   if (value) {
+     const char *v;
+     int idx;
+     for (i = 0; (v = get_nth_string (value, i)); i++) {
+       if (i == 0) {
+-        spa_pod_builder_prop (&d->b, SPA_FORMAT_AUDIO_format, 0);
+-        spa_pod_builder_push_choice(&d->b, &f, get_range_type (value), 0);
++        spa_pod_builder_prop (&b.b, SPA_FORMAT_AUDIO_format, 0);
++        spa_pod_builder_push_choice(&b.b, &f, get_range_type (value), 0);
+       }
+ 
+       idx = gst_audio_format_from_string (v);
+       if (idx < (int)SPA_N_ELEMENTS (audio_format_map))
+-        spa_pod_builder_id (&d->b, audio_format_map[idx]);
++        spa_pod_builder_id (&b.b, audio_format_map[idx]);
+     }
+     if (i > 0) {
+-      choice = spa_pod_builder_pop(&d->b, &f);
++      choice = spa_pod_builder_pop(&b.b, &f);
+       if (i == 1)
+         choice->body.type = SPA_CHOICE_None;
+     }
+   } else if (strcmp(d->type->name, "audio/x-mulaw") == 0) {
+-        spa_pod_builder_prop (&d->b, SPA_FORMAT_AUDIO_format, 0);
+-        spa_pod_builder_id (&d->b, SPA_AUDIO_FORMAT_ULAW);
++        spa_pod_builder_prop (&b.b, SPA_FORMAT_AUDIO_format, 0);
++        spa_pod_builder_id (&b.b, SPA_AUDIO_FORMAT_ULAW);
+   } else if (strcmp(d->type->name, "audio/x-alaw") == 0) {
+-        spa_pod_builder_prop (&d->b, SPA_FORMAT_AUDIO_format, 0);
+-        spa_pod_builder_id (&d->b, SPA_AUDIO_FORMAT_ALAW);
++        spa_pod_builder_prop (&b.b, SPA_FORMAT_AUDIO_format, 0);
++        spa_pod_builder_id (&b.b, SPA_AUDIO_FORMAT_ALAW);
+   } else if (strcmp(d->type->name, "audio/mpeg") == 0) {
+-        spa_pod_builder_prop (&d->b, SPA_FORMAT_AUDIO_format, 0);
+-        spa_pod_builder_id (&d->b, SPA_AUDIO_FORMAT_ENCODED);
++        spa_pod_builder_prop (&b.b, SPA_FORMAT_AUDIO_format, 0);
++        spa_pod_builder_id (&b.b, SPA_AUDIO_FORMAT_ENCODED);
+   } else if (strcmp(d->type->name, "audio/x-flac") == 0) {
+-        spa_pod_builder_prop (&d->b, SPA_FORMAT_AUDIO_format, 0);
+-        spa_pod_builder_id (&d->b, SPA_AUDIO_FORMAT_ENCODED);
++        spa_pod_builder_prop (&b.b, SPA_FORMAT_AUDIO_format, 0);
++        spa_pod_builder_id (&b.b, SPA_AUDIO_FORMAT_ENCODED);
+   }
+ 
+ #if 0
+   value = gst_structure_get_value (d->cs, "layout");
+   if (value) {
+     const char *v;
+     for (i = 0; (v = get_nth_string (value, i)); i++) {
+       enum spa_audio_layout layout;
+ 
+       if (spa_streq(v, "interleaved"))
+         layout = SPA_AUDIO_LAYOUT_INTERLEAVED;
+       else if (spa_streq(v, "non-interleaved"))
+         layout = SPA_AUDIO_LAYOUT_NON_INTERLEAVED;
+       else
+         break;
+ 
+       if (i == 0) {
+-        spa_pod_builder_prop (&d->b, SPA_FORMAT_AUDIO_layout, 0);
+-        spa_pod_builder_push_choice(&d->b, &f, get_range_type (value), 0);
++        spa_pod_builder_prop (&b.b, SPA_FORMAT_AUDIO_layout, 0);
++        spa_pod_builder_push_choice(&b.b, &f, get_range_type (value), 0);
+       }
+ 
+-      spa_pod_builder_id (&d->b, layout);
++      spa_pod_builder_id (&b.b, layout);
+     }
+     if (i > 0) {
+-      choice = spa_pod_builder_pop(&d->b, &f);
++      choice = spa_pod_builder_pop(&b.b, &f);
+       if (i == 1)
+         choice->body.type = SPA_CHOICE_None;
+     }
+   }
+ #endif
+   value = gst_structure_get_value (d->cs, "rate");
+   if (value) {
+     int v;
+     for (i = 0; get_nth_int (value, i, &v); i++) {
+       if (i == 0) {
+-        spa_pod_builder_prop (&d->b, SPA_FORMAT_AUDIO_rate, 0);
+-        spa_pod_builder_push_choice(&d->b, &f, get_range_type (value), 0);
++        spa_pod_builder_prop (&b.b, SPA_FORMAT_AUDIO_rate, 0);
++        spa_pod_builder_push_choice(&b.b, &f, get_range_type (value), 0);
+       }
+ 
+-      spa_pod_builder_int (&d->b, v);
++      spa_pod_builder_int (&b.b, v);
+     }
+     if (i > 0) {
+-      choice = spa_pod_builder_pop(&d->b, &f);
++      choice = spa_pod_builder_pop(&b.b, &f);
+       if (i == 1)
+         choice->body.type = SPA_CHOICE_None;
+     }
+   }
+   value = gst_structure_get_value (d->cs, "channels");
+   if (value) {
+     int v;
+     for (i = 0; get_nth_int (value, i, &v); i++) {
+       if (i == 0) {
+-        spa_pod_builder_prop (&d->b, SPA_FORMAT_AUDIO_channels, 0);
+-        spa_pod_builder_push_choice(&d->b, &f, get_range_type (value), 0);
++        spa_pod_builder_prop (&b.b, SPA_FORMAT_AUDIO_channels, 0);
++        spa_pod_builder_push_choice(&b.b, &f, get_range_type (value), 0);
+       }
+ 
+-      spa_pod_builder_int (&d->b, v);
++      spa_pod_builder_int (&b.b, v);
+     }
+     if (i > 0) {
+-      choice = spa_pod_builder_pop(&d->b, &f);
++      choice = spa_pod_builder_pop(&b.b, &f);
+       if (i == 1) {
+         choice->body.type = SPA_CHOICE_None;
+-        set_default_channels (&d->b, v);
++        set_default_channels (&b.b, v);
+       }
+     }
+   }
+-  return TRUE;
++
++  g_ptr_array_add (d->array, spa_pod_builder_pop (&b.b, &f0));
+ }
+ 
+-static int
+-builder_overflow (void *event_data, uint32_t size)
++static void
++handle_fields (ConvertData *d)
+ {
+-  struct spa_pod_builder *b = event_data;
+-  b->size = SPA_ROUND_UP_N (size, 512);
+-  b->data = realloc (b->data, b->size);
+-  if (b->data == NULL)
+-    return -errno;
+-  return 0;
+-}
+-
+-static const struct spa_pod_builder_callbacks builder_callbacks = {
+-        SPA_VERSION_POD_BUILDER_CALLBACKS,
+-        .overflow = builder_overflow
+-};
+-
+-static struct spa_pod *
+-convert_1 (ConvertData *d)
+-{
+-  struct spa_pod_frame f;
+-
+   if (!(d->type = find_media_types (gst_structure_get_name (d->cs))))
+-    return NULL;
+-
+-  spa_pod_builder_set_callbacks(&d->b, &builder_callbacks, &d->b);
+-
+-  spa_pod_builder_push_object (&d->b, &f, SPA_TYPE_OBJECT_Format, d->id);
+-
+-  spa_pod_builder_prop (&d->b, SPA_FORMAT_mediaType, 0);
+-  spa_pod_builder_id(&d->b, d->type->media_type);
+-
+-  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);
+-  }
++    return;
+ 
+   if (d->type->media_type == SPA_MEDIA_TYPE_video)
+     handle_video_fields (d);
+   else if (d->type->media_type == SPA_MEDIA_TYPE_audio)
+     handle_audio_fields (d);
+-
+-  spa_pod_builder_pop (&d->b, &f);
+-
+-  return SPA_PTROFF (d->b.data, 0, struct spa_pod);
+-}
+-
+-struct spa_pod *
+-gst_caps_to_format (GstCaps *caps, guint index, uint32_t id)
+-{
+-  ConvertData d;
+-  struct spa_pod *res;
+-
+-  g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
+-  g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
+-
+-  spa_zero (d);
+-  d.cf = gst_caps_get_features (caps, index);
+-  d.cs = gst_caps_get_structure (caps, index);
+-  d.id = id;
+-
+-  res = convert_1 (&d);
+-
+-  return res;
+ }
+ 
+ static gboolean
+-foreach_func (GstCapsFeatures *features,
+-              GstStructure    *structure,
+-              ConvertData     *d)
++foreach_func_dmabuf (GstCapsFeatures *features,
++                     GstStructure    *structure,
++                     ConvertData     *d)
+ {
+-  struct spa_pod *fmt;
+-  int idx;
++  if (!features || !gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_DMABUF))
++    return TRUE;
+ 
+-  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;
++  handle_fields (d);
+ 
+-  if ((fmt = convert_1 (d)))
+-    g_ptr_array_insert (d->array, idx, fmt);
++  return TRUE;
++}
++
++static gboolean
++foreach_func_no_dmabuf (GstCapsFeatures *features,
++                        GstStructure    *structure,
++                        ConvertData     *d)
++{
++  if (features && gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_DMABUF))
++    return TRUE;
++
++  d->cf = features;
++  d->cs = structure;
++
++  handle_fields (d);
+ 
+   return TRUE;
+ }
+ 
+ 
+ GPtrArray *
+-gst_caps_to_format_all (GstCaps *caps, uint32_t id)
++gst_caps_to_format_all (GstCaps *caps)
+ {
+   ConvertData d;
+ 
+-  spa_zero (d);
+-  d.id = id;
+   d.array = g_ptr_array_new_full (gst_caps_get_size (caps), (GDestroyNotify)g_free);
+ 
+-  gst_caps_foreach (caps, (GstCapsForeachFunc) foreach_func, &d);
++  gst_caps_foreach (caps, (GstCapsForeachFunc) foreach_func_dmabuf, &d);
++  gst_caps_foreach (caps, (GstCapsForeachFunc) foreach_func_no_dmabuf, &d);
+ 
+   return d.array;
+ }
+ 
+ typedef const char *(*id_to_string_func)(uint32_t id);
+ 
+ static const char *video_id_to_string(uint32_t id)
+ {
+   int idx;
+   if ((idx = find_index(video_format_map, SPA_N_ELEMENTS(video_format_map), id)) == -1)
+     return NULL;
+   return gst_video_format_to_string(idx);
+ }
+ 
++#ifdef HAVE_GSTREAMER_DMA_DRM
++static char *video_id_to_dma_drm_fourcc(uint32_t id, uint64_t mod)
++{
++  int idx;
++  guint32 fourcc;
++  if ((idx = find_index(video_format_map, SPA_N_ELEMENTS(video_format_map), id)) == -1)
++    return NULL;
++  fourcc = gst_video_dma_drm_fourcc_from_format(idx);
++  return gst_video_dma_drm_fourcc_to_string(fourcc, mod);
++}
++#endif
++
+ static const char *audio_id_to_string(uint32_t id)
+ {
+   int idx;
+@@ -762,6 +868,109 @@ handle_id_prop (const struct spa_pod_prop *prop, const char *key, id_to_string_f
+   }
+ }
+ 
++static void
++handle_dmabuf_prop (const struct spa_pod_prop *prop,
++    const struct spa_pod_prop *prop_modifier, GstCaps *res)
++{
++  g_autoptr (GPtrArray) fmt_array = NULL;
++  g_autoptr (GPtrArray) drm_fmt_array = NULL;
++  const struct spa_pod *pod_modifier;
++  struct spa_pod *val;
++  uint32_t *id, n_fmts, n_mods, choice, i, j;
++  uint64_t *mods;
++
++
++  val = spa_pod_get_values (&prop->value, &n_fmts, &choice);
++  if (val->type != SPA_TYPE_Id)
++    return;
++
++  id = SPA_POD_BODY (val);
++  if (n_fmts > 1) {
++    n_fmts--;
++    id++;
++  }
++
++  pod_modifier = &prop_modifier->value;
++  mods = SPA_POD_CHOICE_VALUES (pod_modifier);
++  n_mods = SPA_POD_CHOICE_N_VALUES (pod_modifier);
++  if (n_mods > 1) {
++    n_mods--;
++    mods++;
++  }
++
++  fmt_array = g_ptr_array_new_with_free_func (g_free);
++  drm_fmt_array = g_ptr_array_new_with_free_func (g_free);
++
++  for (i = 0; i < n_fmts; i++) {
++    for (j = 0; j < n_mods; j++) {
++      const char *fmt_str;
++
++      if ((mods[j] == DRM_FORMAT_MOD_LINEAR ||
++           mods[j] == DRM_FORMAT_MOD_INVALID) &&
++          (fmt_str = video_id_to_string(id[i])))
++        g_ptr_array_add(fmt_array, g_strdup_printf ("%s", fmt_str));
++
++#ifdef HAVE_GSTREAMER_DMA_DRM
++      {
++        char *drm_str;
++
++        if ((drm_str = video_id_to_dma_drm_fourcc(id[i], mods[j])))
++          g_ptr_array_add(drm_fmt_array, drm_str);
++      }
++#endif
++    }
++  }
++
++#ifdef HAVE_GSTREAMER_DMA_DRM
++  if (drm_fmt_array->len > 0) {
++    g_ptr_array_add (fmt_array, g_strdup_printf ("DMA_DRM"));
++
++    if (drm_fmt_array->len == 1) {
++      gst_caps_set_simple (res, "drm-format", G_TYPE_STRING,
++          g_ptr_array_index (drm_fmt_array, 0), NULL);
++    } else {
++      GValue list = { 0 };
++
++      g_value_init (&list, GST_TYPE_LIST);
++      for (i = 0; i < drm_fmt_array->len; i++) {
++        GValue v = { 0 };
++
++        g_value_init (&v, G_TYPE_STRING);
++        g_value_set_string (&v, g_ptr_array_index (drm_fmt_array, i));
++        gst_value_list_append_and_take_value (&list, &v);
++      }
++
++      gst_caps_set_value (res, "drm-format", &list);
++      g_value_unset (&list);
++    }
++  }
++#endif
++
++  if (fmt_array->len > 0) {
++    gst_caps_set_features_simple (res,
++        gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_DMABUF));
++
++    if (fmt_array->len == 1) {
++      gst_caps_set_simple (res, "format", G_TYPE_STRING,
++          g_ptr_array_index (fmt_array, 0), NULL);
++    } else {
++      GValue list = { 0 };
++
++      g_value_init (&list, GST_TYPE_LIST);
++      for (i = 0; i < fmt_array->len; i++) {
++        GValue v = { 0 };
++
++        g_value_init (&v, G_TYPE_STRING);
++        g_value_set_string (&v, g_ptr_array_index (fmt_array, i));
++        gst_value_list_append_and_take_value (&list, &v);
++      }
++
++      gst_caps_set_value (res, "format", &list);
++      g_value_unset (&list);
++    }
++  }
++}
++
+ static void
+ handle_int_prop (const struct spa_pod_prop *prop, const char *key, GstCaps *res)
+ {
+@@ -916,9 +1125,17 @@ gst_caps_from_format (const struct spa_pod *format)
+ 
+   if (media_type == SPA_MEDIA_TYPE_video) {
+     if (media_subtype == SPA_MEDIA_SUBTYPE_raw) {
++      const struct spa_pod_prop *prop_modifier;
++
+       res = gst_caps_new_empty_simple ("video/x-raw");
+-      if ((prop = spa_pod_object_find_prop (obj, prop, SPA_FORMAT_VIDEO_format))) {
+-        handle_id_prop (prop, "format", video_id_to_string, res);
++
++      if ((prop = spa_pod_object_find_prop (obj, prop, SPA_FORMAT_VIDEO_format)) &&
++          (prop_modifier = spa_pod_object_find_prop (obj, NULL, SPA_FORMAT_VIDEO_modifier))) {
++        handle_dmabuf_prop (prop, prop_modifier, res);
++      } else {
++        if ((prop = spa_pod_object_find_prop (obj, prop, SPA_FORMAT_VIDEO_format))) {
++          handle_id_prop (prop, "format", video_id_to_string, res);
++        }
+       }
+     }
+     else if (media_subtype == SPA_MEDIA_SUBTYPE_mjpg) {
+diff --git a/src/gst/gstpipewireformat.h b/src/gst/gstpipewireformat.h
+index d82dbee20cef..abd45c4e9bbb 100644
+--- a/src/gst/gstpipewireformat.h
++++ b/src/gst/gstpipewireformat.h
+@@ -11,9 +11,7 @@
+ 
+ G_BEGIN_DECLS
+ 
+-struct spa_pod * gst_caps_to_format      (GstCaps *caps,
+-                                          guint index, uint32_t id);
+-GPtrArray *      gst_caps_to_format_all  (GstCaps *caps, uint32_t id);
++GPtrArray *      gst_caps_to_format_all  (GstCaps *caps);
+ 
+ GstCaps *        gst_caps_from_format    (const struct spa_pod *format);
+ 
+diff --git a/src/gst/gstpipewiresink.c b/src/gst/gstpipewiresink.c
+index 8a6541615ccb..2f3ec9b8bd93 100644
+--- a/src/gst/gstpipewiresink.c
++++ b/src/gst/gstpipewiresink.c
+@@ -575,7 +575,7 @@ gst_pipewire_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
+ 
+   pwsink = GST_PIPEWIRE_SINK (bsink);
+ 
+-  possible = gst_caps_to_format_all (caps, SPA_PARAM_EnumFormat);
++  possible = gst_caps_to_format_all (caps);
+ 
+   pw_thread_loop_lock (pwsink->core->loop);
+   state = pw_stream_get_state (pwsink->stream, &error);
+diff --git a/src/gst/gstpipewiresrc.c b/src/gst/gstpipewiresrc.c
+index a66ef964b9cc..f96da74ba3d0 100644
+--- a/src/gst/gstpipewiresrc.c
++++ b/src/gst/gstpipewiresrc.c
+@@ -15,7 +15,6 @@
+ 
+ #define PW_ENABLE_DEPRECATED
+ 
+-#include "config.h"
+ #include "gstpipewiresrc.h"
+ #include "gstpipewireformat.h"
+ 
+@@ -869,7 +868,7 @@ gst_pipewire_src_negotiate (GstBaseSrc * basesrc)
+   }
+ 
+   /* open a connection with these caps */
+-  possible = gst_caps_to_format_all (possible_caps, SPA_PARAM_EnumFormat);
++  possible = gst_caps_to_format_all (possible_caps);
+ 
+   /* first disconnect */
+   pw_thread_loop_lock (pwsrc->core->loop);
+@@ -1013,26 +1012,47 @@ on_param_changed (void *data, uint32_t id,
+           gst_caps_unref(pwsrc->caps);
+   pwsrc->caps = gst_caps_from_format (param);
+ 
+-  pwsrc->is_video = pwsrc->caps != NULL
+-                      ? gst_video_info_from_caps (&pwsrc->video_info, pwsrc->caps)
+-                      : FALSE;
++  if (pwsrc->caps && gst_caps_is_fixed (pwsrc->caps)) {
++    pwsrc->negotiated = TRUE;
+ 
+-  pwsrc->negotiated = pwsrc->caps != NULL;
++#ifdef HAVE_GSTREAMER_DMA_DRM
++    if (gst_video_is_dma_drm_caps (pwsrc->caps)) {
++      if (!gst_video_info_dma_drm_from_caps (&pwsrc->drm_info, pwsrc->caps)) {
++        GST_WARNING_OBJECT (pwsrc, "Can't create drm video info from caps");
++        pw_stream_set_error (pwsrc->stream, -EINVAL, "internal error");
++        return;
++      }
+ 
+-  if (pwsrc->negotiated) {
++      if (!gst_video_info_dma_drm_to_video_info (&pwsrc->drm_info,
++                                                 &pwsrc->video_info)) {
++        GST_WARNING_OBJECT (pwsrc, "Can't create video info from drm video info");
++        pw_stream_set_error (pwsrc->stream, -EINVAL, "internal error");
++        return;
++      }
++
++      pwsrc->is_video = TRUE;
++    } else {
++      gst_video_info_dma_drm_init (&pwsrc->drm_info);
++#endif
++      pwsrc->is_video = gst_video_info_from_caps (&pwsrc->video_info,
++                                                  pwsrc->caps);
++#ifdef HAVE_GSTREAMER_DMA_DRM
++    }
++#endif
++  } else {
++    pwsrc->negotiated = FALSE;
++    pwsrc->is_video = FALSE;
++  }
++
++  if (pwsrc->caps) {
+     const struct spa_pod *params[4];
+     struct spa_pod_builder b = { NULL };
+     uint8_t buffer[512];
+     uint32_t buffers = CLAMP (16, pwsrc->min_buffers, pwsrc->max_buffers);
+     int buffertypes;
+ 
+     buffertypes = (1<<SPA_DATA_DmaBuf);
+-    if (spa_pod_find_prop (param, NULL, SPA_FORMAT_VIDEO_modifier)) {
+-      gst_caps_features_remove (gst_caps_get_features (pwsrc->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 {
++    if (!spa_pod_find_prop (param, NULL, SPA_FORMAT_VIDEO_modifier)) {
+       buffertypes |= ((1<<SPA_DATA_MemFd) | (1<<SPA_DATA_MemPtr));
+     }
+ 
+diff --git a/src/gst/gstpipewiresrc.h b/src/gst/gstpipewiresrc.h
+index 97f636fb301f..0a61853f50ec 100644
+--- a/src/gst/gstpipewiresrc.h
++++ b/src/gst/gstpipewiresrc.h
+@@ -5,6 +5,8 @@
+ #ifndef __GST_PIPEWIRE_SRC_H__
+ #define __GST_PIPEWIRE_SRC_H__
+ 
++#include "config.h"
++
+ #include <gst/gst.h>
+ #include <gst/base/gstpushsrc.h>
+ 
+@@ -56,6 +58,9 @@ struct _GstPipeWireSrc {
+ 
+   gboolean is_video;
+   GstVideoInfo video_info;
++#ifdef HAVE_GSTREAMER_DMA_DRM
++  GstVideoInfoDmaDrm drm_info;
++#endif
+ 
+   gboolean negotiated;
+   gboolean flushing;
diff --git a/0002-gst-Sanitize-caps-before-translating.patch b/0002-gst-Sanitize-caps-before-translating.patch
new file mode 100644
index 0000000..a435eb9
--- /dev/null
+++ b/0002-gst-Sanitize-caps-before-translating.patch
@@ -0,0 +1,96 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robert Mader <robert.mader@collabora.com>
+Date: Sun, 25 Feb 2024 17:36:08 +0100
+Subject: [PATCH] gst: Sanitize caps before translating
+
+DMABuf caps without concrete formats and modifiers don't map well to the
+Pipewire negotiation process.
+Introduce a new gst_caps_sanitize() helper function, where such cases
+can be handled.
+---
+ src/gst/gstpipewireformat.c | 40 +++++++++++++++++++++++++++++++++++++
+ src/gst/gstpipewireformat.h |  2 ++
+ src/gst/gstpipewiresrc.c    |  6 +++++-
+ 3 files changed, 47 insertions(+), 1 deletion(-)
+
+diff --git a/src/gst/gstpipewireformat.c b/src/gst/gstpipewireformat.c
+index ff1752a06565..6830de234a8d 100644
+--- a/src/gst/gstpipewireformat.c
++++ b/src/gst/gstpipewireformat.c
+@@ -1176,3 +1176,43 @@ gst_caps_from_format (const struct spa_pod *format)
+   }
+   return res;
+ }
++
++static gboolean
++filter_dmabuf_caps (GstCapsFeatures *features,
++                    GstStructure    *structure,
++                    gpointer         user_data)
++{
++  const GValue *value;
++  const char *v;
++
++  if (!gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_DMABUF))
++    return TRUE;
++
++  if (!(value = gst_structure_get_value (structure, "format")) ||
++      !(v = get_nth_string (value, 0)))
++    return FALSE;
++
++#ifdef HAVE_GSTREAMER_DMA_DRM
++  {
++    int idx;
++
++    idx = gst_video_format_from_string (v);
++    if (idx == GST_VIDEO_FORMAT_UNKNOWN)
++      return FALSE;
++
++    if (idx == GST_VIDEO_FORMAT_DMA_DRM &&
++        !gst_structure_get_value (structure, "drm-format"))
++      return FALSE;
++  }
++#endif
++
++  return TRUE;
++}
++
++GstCaps *
++gst_caps_sanitize (GstCaps *caps)
++{
++  caps = gst_caps_make_writable (caps);
++  gst_caps_filter_and_map_in_place (caps, filter_dmabuf_caps, NULL);
++  return caps;
++}
+diff --git a/src/gst/gstpipewireformat.h b/src/gst/gstpipewireformat.h
+index abd45c4e9bbb..ca76b70c2f06 100644
+--- a/src/gst/gstpipewireformat.h
++++ b/src/gst/gstpipewireformat.h
+@@ -15,6 +15,8 @@ GPtrArray *      gst_caps_to_format_all  (GstCaps *caps);
+ 
+ GstCaps *        gst_caps_from_format    (const struct spa_pod *format);
+ 
++GstCaps *        gst_caps_sanitize       (GstCaps *caps);
++
+ G_END_DECLS
+ 
+ #endif
+diff --git a/src/gst/gstpipewiresrc.c b/src/gst/gstpipewiresrc.c
+index f96da74ba3d0..a9ef7d1b2430 100644
+--- a/src/gst/gstpipewiresrc.c
++++ b/src/gst/gstpipewiresrc.c
+@@ -847,10 +847,14 @@ gst_pipewire_src_negotiate (GstBaseSrc * basesrc)
+     /* no peer, work with our own caps then */
+     possible_caps = g_steal_pointer (&thiscaps);
+   }
++
++  GST_DEBUG_OBJECT (basesrc, "have common caps: %" GST_PTR_FORMAT, possible_caps);
++  gst_caps_sanitize (possible_caps);
++
+   if (gst_caps_is_empty (possible_caps))
+     goto no_common_caps;
+ 
+-  GST_DEBUG_OBJECT (basesrc, "have common caps: %" GST_PTR_FORMAT, possible_caps);
++  GST_DEBUG_OBJECT (basesrc, "have common caps (sanitized): %" GST_PTR_FORMAT, possible_caps);
+ 
+   if (pw_stream_get_state(pwsrc->stream, NULL) == PW_STREAM_STATE_STREAMING) {
+     g_autoptr (GstCaps) current_caps = NULL;
diff --git a/0003-gst-Fix-sanitization-of-non-writable-caps.patch b/0003-gst-Fix-sanitization-of-non-writable-caps.patch
new file mode 100644
index 0000000..2a56e93
--- /dev/null
+++ b/0003-gst-Fix-sanitization-of-non-writable-caps.patch
@@ -0,0 +1,67 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robert Mader <robert.mader@collabora.com>
+Date: Thu, 7 Mar 2024 06:55:09 +0100
+Subject: [PATCH] gst: Fix sanitization of non-writable caps
+
+`gst_caps_make_writable()` may create a copy which we have to keep
+using afterwards. The return value was meant to be used for that,
+but was promptly forgotten for the initial user.
+Avoid such errors in the future by using an in-out parameter instead.
+
+While on it, add a type check and remove a check for an impossible
+condition.
+
+Fixes: 8a271a87b ("gst: Sanitize caps before translating")
+---
+ src/gst/gstpipewireformat.c | 11 ++++++-----
+ src/gst/gstpipewireformat.h |  2 +-
+ src/gst/gstpipewiresrc.c    |  2 +-
+ 3 files changed, 8 insertions(+), 7 deletions(-)
+
+diff --git a/src/gst/gstpipewireformat.c b/src/gst/gstpipewireformat.c
+index 6830de234a8d..a0f64747697c 100644
+--- a/src/gst/gstpipewireformat.c
++++ b/src/gst/gstpipewireformat.c
+@@ -1209,10 +1209,11 @@ filter_dmabuf_caps (GstCapsFeatures *features,
+   return TRUE;
+ }
+ 
+-GstCaps *
+-gst_caps_sanitize (GstCaps *caps)
++void
++gst_caps_sanitize (GstCaps **caps)
+ {
+-  caps = gst_caps_make_writable (caps);
+-  gst_caps_filter_and_map_in_place (caps, filter_dmabuf_caps, NULL);
+-  return caps;
++  g_return_if_fail (GST_IS_CAPS (*caps));
++
++  *caps = gst_caps_make_writable (*caps);
++  gst_caps_filter_and_map_in_place (*caps, filter_dmabuf_caps, NULL);
+ }
+diff --git a/src/gst/gstpipewireformat.h b/src/gst/gstpipewireformat.h
+index ca76b70c2f06..1c3a239baeaf 100644
+--- a/src/gst/gstpipewireformat.h
++++ b/src/gst/gstpipewireformat.h
+@@ -15,7 +15,7 @@ GPtrArray *      gst_caps_to_format_all  (GstCaps *caps);
+ 
+ GstCaps *        gst_caps_from_format    (const struct spa_pod *format);
+ 
+-GstCaps *        gst_caps_sanitize       (GstCaps *caps);
++void             gst_caps_sanitize       (GstCaps **caps);
+ 
+ G_END_DECLS
+ 
+diff --git a/src/gst/gstpipewiresrc.c b/src/gst/gstpipewiresrc.c
+index a9ef7d1b2430..5e518884f2f8 100644
+--- a/src/gst/gstpipewiresrc.c
++++ b/src/gst/gstpipewiresrc.c
+@@ -849,7 +849,7 @@ gst_pipewire_src_negotiate (GstBaseSrc * basesrc)
+   }
+ 
+   GST_DEBUG_OBJECT (basesrc, "have common caps: %" GST_PTR_FORMAT, possible_caps);
+-  gst_caps_sanitize (possible_caps);
++  gst_caps_sanitize (&possible_caps);
+ 
+   if (gst_caps_is_empty (possible_caps))
+     goto no_common_caps;
diff --git a/0004-gst-Re-enable-handling-of-single-long-modifiers.patch b/0004-gst-Re-enable-handling-of-single-long-modifiers.patch
new file mode 100644
index 0000000..70a0cb9
--- /dev/null
+++ b/0004-gst-Re-enable-handling-of-single-long-modifiers.patch
@@ -0,0 +1,70 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robert Mader <robert.mader@collabora.com>
+Date: Thu, 28 Mar 2024 14:01:20 +0100
+Subject: [PATCH] gst: Re-enable handling of single long modifiers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+A peer may announce support for a single modifier, in which case it may
+not use a choice-pod. And while the documentation in `dma-buf.dox`
+requires modifiers to always be announced as `SPA_CHOICE_Enum`, this has
+been supported in the past - as well as matching Pipewire conventions.
+
+Thus, in order to not break existing clients not crash, reintroduce
+handling of modifiers as a single long.
+
+Fixes: f1b75fc6f (gst: Add support for DMA_DRM / explicit modifiers)
+
+Solution suggested by Barnabás Pőcze <pobrn@protonmail.com>
+---
+ src/gst/gstpipewireformat.c | 24 +++++++++++++++++-------
+ 1 file changed, 17 insertions(+), 7 deletions(-)
+
+diff --git a/src/gst/gstpipewireformat.c b/src/gst/gstpipewireformat.c
+index a0f64747697c..e4159835da76 100644
+--- a/src/gst/gstpipewireformat.c
++++ b/src/gst/gstpipewireformat.c
+@@ -877,25 +877,35 @@ handle_dmabuf_prop (const struct spa_pod_prop *prop,
+   const struct spa_pod *pod_modifier;
+   struct spa_pod *val;
+   uint32_t *id, n_fmts, n_mods, choice, i, j;
+-  uint64_t *mods;
+-
++  uint64_t *mods, single_modifier;
+ 
+   val = spa_pod_get_values (&prop->value, &n_fmts, &choice);
+   if (val->type != SPA_TYPE_Id)
+     return;
+ 
+   id = SPA_POD_BODY (val);
+   if (n_fmts > 1) {
+     n_fmts--;
+     id++;
+   }
+ 
+   pod_modifier = &prop_modifier->value;
+-  mods = SPA_POD_CHOICE_VALUES (pod_modifier);
+-  n_mods = SPA_POD_CHOICE_N_VALUES (pod_modifier);
+-  if (n_mods > 1) {
+-    n_mods--;
+-    mods++;
++  if (spa_pod_is_long (pod_modifier) &&
++      spa_pod_get_long (pod_modifier, (int64_t *) &single_modifier)) {
++    mods = &single_modifier;
++    n_mods = 1;
++  } else if (spa_pod_is_choice (pod_modifier) &&
++             SPA_POD_CHOICE_TYPE (pod_modifier) == SPA_CHOICE_Enum &&
++             SPA_POD_CHOICE_VALUE_TYPE (pod_modifier) == SPA_TYPE_Long) {
++    mods = SPA_POD_CHOICE_VALUES (pod_modifier);
++    n_mods = SPA_POD_CHOICE_N_VALUES (pod_modifier);
++
++    if (n_mods > 1) {
++      n_mods--;
++      mods++;
++    }
++  } else {
++    return;
+   }
+ 
+   fmt_array = g_ptr_array_new_with_free_func (g_free);
diff --git a/PKGBUILD b/PKGBUILD
index 31fd141..989a958 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -22,7 +22,7 @@ pkgname=(
   pipewire-session-manager
   pulse-native-provider
 )
-pkgver=1.0.5
+pkgver=1.0.6
 _so_ver=0.3
 pkgrel=1
 epoch=1
@@ -75,8 +75,16 @@ checkdepends=(
 )
 source=(
   "git+https://gitlab.freedesktop.org/pipewire/pipewire.git#tag=$pkgver"
+  0001-gst-Add-support-for-DMA_DRM-explicit-modifiers.patch
+  0002-gst-Sanitize-caps-before-translating.patch
+  0003-gst-Fix-sanitization-of-non-writable-caps.patch
+  0004-gst-Re-enable-handling-of-single-long-modifiers.patch
 )
-b2sums=('46f2e8e0206077590af8e3accd338c84ed66c954955b01bb316f1dd723f4c75d111078b845a0e682c5ca7a8ff398023a9c2d0074530ff85f87ac0c2dee1a6c34')
+b2sums=('77e01e262df0b0159cc4bbc79387268798d01c6fe035e779e85937e53f486412b210f94454fb6ed78c8f073e9cb1ea4cda551f57e1129cdd30020254e4be778b'
+        'a32e85e5535664d960ad2452638703885e488ad8cf02e6df8378fd4bb9ff8b3c851645fa47ba2037cf597bbfe4b048c33a82977d551df9c3746e175edbd208b3'
+        '5aca6a491907cabeee40765ef6591448bfd5a684327db5f0ffe0b59c99e23bd7cc13994f8aa42b8f5ae9c1bbd8cd69c487c4b04c6fa1dd98e9934bc4b80a17cb'
+        '902effec51d1c40191a0a5a8e5dcf54e24062f7228c8de1e25dae5ab622a3adcbbc8156d398fa14ea74a0c8e8fc489144771fbead86f91a79f4435c08f419767'
+        '87dc2c9e67121311cd960aae0751ac77652cacd6e27b70be71d0738d356d0675e731f0dad3a82f6e71b9ada2a458a13ebb572fccba3d33f88be4dc350cd5e8b3')
 
 pkgver() {
   cd pipewire
@@ -87,11 +95,10 @@ prepare() {
   cd pipewire
 
   # Gst plugin fixes
-  git cherry-pick -n \
-    f1b75fc6f803f866d2ed0f7d1366f56ef96f0610 \
-    8a271a87b77e4508bb698f9b9e9fe3624884bfa6 \
-    1a6bb994a502d95434e326a35a83a1fb5f4ebad8 \
-    8848c7e7920618b97016243912bcb20c69a71960
+  git apply -3 ../0001-gst-Add-support-for-DMA_DRM-explicit-modifiers.patch
+  git apply -3 ../0002-gst-Sanitize-caps-before-translating.patch
+  git apply -3 ../0003-gst-Fix-sanitization-of-non-writable-caps.patch
+  git apply -3 ../0004-gst-Re-enable-handling-of-single-long-modifiers.patch
 }
 
 build() {