author | Jan Alexander Steffens (heftig)
<heftig@archlinux.org> 2024-05-09 15:15:54 UTC |
committer | Jan Alexander Steffens (heftig)
<heftig@archlinux.org> 2024-05-09 15:15:54 UTC |
parent | fb85208e68445bd2db36d64bf4c3caea310fef05 |
.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() {