mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-10-29 05:40:27 -04:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									f2f60ee0ec
								
							
						
					
					
						commit
						f1b75fc6f8
					
				
					 6 changed files with 417 additions and 169 deletions
				
			
		|  | @ -364,6 +364,7 @@ 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') | ||||
|  | @ -376,6 +377,10 @@ foreach depname, kwargs: gst_deps_def | |||
|     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 | ||||
|  | @ -384,6 +389,9 @@ summary({'gstreamer-device-provider': gst_dp_found}, bool_yn: true, section: 'Ba | |||
| 
 | ||||
| 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) | ||||
|  |  | |||
|  | @ -2,6 +2,8 @@ | |||
| /* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */ | ||||
| /* SPDX-License-Identifier: MIT */ | ||||
| 
 | ||||
| #include "config.h" | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| #include <gst/gst.h> | ||||
|  | @ -13,10 +15,14 @@ | |||
| #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,48 +362,28 @@ 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; | ||||
|     } | ||||
|  | @ -410,14 +394,14 @@ handle_video_fields (ConvertData *d) | |||
|     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; | ||||
|     } | ||||
|  | @ -428,19 +412,171 @@ handle_video_fields (ConvertData *d) | |||
|     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,45 +617,57 @@ 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 | ||||
|  | @ -537,14 +685,14 @@ handle_audio_fields (ConvertData *d) | |||
|         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; | ||||
|     } | ||||
|  | @ -555,14 +703,14 @@ handle_audio_fields (ConvertData *d) | |||
|     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; | ||||
|     } | ||||
|  | @ -572,132 +720,78 @@ handle_audio_fields (ConvertData *d) | |||
|     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; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| builder_overflow (void *event_data, uint32_t size) | ||||
|   g_ptr_array_add (d->array, spa_pod_builder_pop (&b.b, &f0)); | ||||
| } | ||||
| 
 | ||||
| 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, | ||||
| 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; | ||||
| } | ||||
|  | @ -712,6 +806,18 @@ static const char *video_id_to_string(uint32_t id) | |||
|   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,11 +1125,19 @@ 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)) && | ||||
|           (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) { | ||||
|       res = gst_caps_new_empty_simple ("image/jpeg"); | ||||
|     } | ||||
|  |  | |||
|  | @ -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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -570,7 +570,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); | ||||
|  |  | |||
|  | @ -15,7 +15,6 @@ | |||
| 
 | ||||
| #define PW_ENABLE_DEPRECATED | ||||
| 
 | ||||
| #include "config.h" | ||||
| #include "gstpipewiresrc.h" | ||||
| #include "gstpipewireformat.h" | ||||
| 
 | ||||
|  | @ -851,7 +850,7 @@ gst_pipewire_src_negotiate (GstBaseSrc * basesrc) | |||
|   GST_DEBUG_OBJECT (basesrc, "have common caps: %" GST_PTR_FORMAT, caps); | ||||
| 
 | ||||
|   /* open a connection with these caps */ | ||||
|   possible = gst_caps_to_format_all (caps, SPA_PARAM_EnumFormat); | ||||
|   possible = gst_caps_to_format_all (caps); | ||||
|   gst_caps_unref (caps); | ||||
| 
 | ||||
|   /* first disconnect */ | ||||
|  | @ -1008,13 +1007,39 @@ 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]; | ||||
|  | @ -1022,12 +1047,7 @@ on_param_changed (void *data, uint32_t id, | |||
|     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)); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Robert Mader
						Robert Mader