mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	gst-source: on-demand element creation
Add to GstSource the possibility to create the GStreamer element when an output port is created, and not directly when the node is created. The element is chosen based on the requested format, using GStreamer typefind as in the GstAutoDetect class.
This commit is contained in:
		
							parent
							
								
									c70e24c51c
								
							
						
					
					
						commit
						649882f42a
					
				
					 1 changed files with 128 additions and 11 deletions
				
			
		| 
						 | 
					@ -371,6 +371,7 @@ on_output_port_created (GObject      *source_object,
 | 
				
			||||||
  PinosNode *node = PINOS_NODE (source_object);
 | 
					  PinosNode *node = PINOS_NODE (source_object);
 | 
				
			||||||
  PinosGstSource *source = PINOS_GST_SOURCE (node);
 | 
					  PinosGstSource *source = PINOS_GST_SOURCE (node);
 | 
				
			||||||
  PinosGstSourcePrivate *priv = source->priv;
 | 
					  PinosGstSourcePrivate *priv = source->priv;
 | 
				
			||||||
 | 
					  GTask *task = user_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  priv->output = pinos_node_create_port_finish (node, res, NULL);
 | 
					  priv->output = pinos_node_create_port_finish (node, res, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -378,6 +379,12 @@ on_output_port_created (GObject      *source_object,
 | 
				
			||||||
  g_signal_connect (priv->output, "unlinked", (GCallback) on_unlinked, node);
 | 
					  g_signal_connect (priv->output, "unlinked", (GCallback) on_unlinked, node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  setup_pipeline (source, NULL);
 | 
					  setup_pipeline (source, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (task) {
 | 
				
			||||||
 | 
					    g_task_return_pointer (task,
 | 
				
			||||||
 | 
					                           priv->output,
 | 
				
			||||||
 | 
					                           (GDestroyNotify) g_object_unref);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
| 
						 | 
					@ -391,6 +398,7 @@ source_constructed (GObject * object)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  G_OBJECT_CLASS (pinos_gst_source_parent_class)->constructed (object);
 | 
					  G_OBJECT_CLASS (pinos_gst_source_parent_class)->constructed (object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (priv->element) {
 | 
				
			||||||
    str = gst_caps_to_string (priv->possible_formats);
 | 
					    str = gst_caps_to_string (priv->possible_formats);
 | 
				
			||||||
    possible_formats = g_bytes_new_take (str, strlen (str) + 1);
 | 
					    possible_formats = g_bytes_new_take (str, strlen (str) + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -400,10 +408,11 @@ source_constructed (GObject * object)
 | 
				
			||||||
                            possible_formats,
 | 
					                            possible_formats,
 | 
				
			||||||
                            NULL,
 | 
					                            NULL,
 | 
				
			||||||
                            NULL,
 | 
					                            NULL,
 | 
				
			||||||
                          on_output_port_created,
 | 
					                            NULL,
 | 
				
			||||||
                          node);
 | 
					                            NULL);
 | 
				
			||||||
    g_bytes_unref (possible_formats);
 | 
					    g_bytes_unref (possible_formats);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
source_finalize (GObject * object)
 | 
					source_finalize (GObject * object)
 | 
				
			||||||
| 
						 | 
					@ -420,6 +429,113 @@ source_finalize (GObject * object)
 | 
				
			||||||
  G_OBJECT_CLASS (pinos_gst_source_parent_class)->finalize (object);
 | 
					  G_OBJECT_CLASS (pinos_gst_source_parent_class)->finalize (object);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static gboolean
 | 
				
			||||||
 | 
					factory_filter (GstPluginFeature * feature, gpointer data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  guint rank;
 | 
				
			||||||
 | 
					  const gchar *klass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!GST_IS_ELEMENT_FACTORY (feature))
 | 
				
			||||||
 | 
					    return FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  rank = gst_plugin_feature_get_rank (feature);
 | 
				
			||||||
 | 
					  if (rank < 1)
 | 
				
			||||||
 | 
					    return FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  klass = gst_element_factory_get_metadata (GST_ELEMENT_FACTORY (feature),
 | 
				
			||||||
 | 
					      GST_ELEMENT_METADATA_KLASS);
 | 
				
			||||||
 | 
					  if (g_strcmp0 (klass, "Source/Video") && g_strcmp0 (klass, "Source/Audio"))
 | 
				
			||||||
 | 
					    return FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return TRUE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static GstElement *
 | 
				
			||||||
 | 
					create_best_element (GstCaps *caps)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  GstElement *element = NULL;
 | 
				
			||||||
 | 
					  GList *list, *item;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* get factories from registry */
 | 
				
			||||||
 | 
					  list = gst_registry_feature_filter (gst_registry_get (),
 | 
				
			||||||
 | 
					                                      (GstPluginFeatureFilter) factory_filter,
 | 
				
			||||||
 | 
					                                      FALSE, NULL);
 | 
				
			||||||
 | 
					  list = g_list_sort (list,
 | 
				
			||||||
 | 
					                      (GCompareFunc) gst_plugin_feature_rank_compare_func);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* loop through list and try to find factory that best matches caps,
 | 
				
			||||||
 | 
					   * following the pattern from GstAutoDetect */
 | 
				
			||||||
 | 
					  for (item = list; item != NULL; item = item->next) {
 | 
				
			||||||
 | 
					    GstElementFactory *f = GST_ELEMENT_FACTORY (item->data);
 | 
				
			||||||
 | 
					    GstElement *el;
 | 
				
			||||||
 | 
					    GstPad *el_pad;
 | 
				
			||||||
 | 
					    GstCaps *el_caps = NULL;
 | 
				
			||||||
 | 
					    gboolean match = FALSE;
 | 
				
			||||||
 | 
					    GstStateChangeReturn ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((el = gst_element_factory_create (f, NULL))) {
 | 
				
			||||||
 | 
					      el_pad = gst_element_get_static_pad (el, "src");
 | 
				
			||||||
 | 
					      el_caps = gst_pad_query_caps (el_pad, NULL);
 | 
				
			||||||
 | 
					      gst_object_unref (el_pad);
 | 
				
			||||||
 | 
					      match = gst_caps_can_intersect (caps, el_caps);
 | 
				
			||||||
 | 
					      gst_caps_unref (el_caps);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!match) {
 | 
				
			||||||
 | 
					        gst_object_unref (el);
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = gst_element_set_state (el, GST_STATE_READY);
 | 
				
			||||||
 | 
					    if (ret == GST_STATE_CHANGE_SUCCESS) {
 | 
				
			||||||
 | 
					      element = el;
 | 
				
			||||||
 | 
					      g_debug ("element %p selected", element);
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gst_element_set_state (el, GST_STATE_NULL);
 | 
				
			||||||
 | 
					    gst_object_unref (el);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return element;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					source_create_port (PinosNode       *node,
 | 
				
			||||||
 | 
					                    PinosDirection   direction,
 | 
				
			||||||
 | 
					                    const gchar     *name,
 | 
				
			||||||
 | 
					                    GBytes          *possible_formats,
 | 
				
			||||||
 | 
					                    PinosProperties *props,
 | 
				
			||||||
 | 
					                    GTask           *task)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  PinosGstSourcePrivate *priv = PINOS_GST_SOURCE (node)->priv;
 | 
				
			||||||
 | 
					  GTask *source_task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (props == NULL)
 | 
				
			||||||
 | 
					    props = pinos_properties_new (NULL, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (priv->element == NULL) {
 | 
				
			||||||
 | 
					    GstCaps *caps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    caps = gst_caps_from_string (g_bytes_get_data (possible_formats, NULL));
 | 
				
			||||||
 | 
					    priv->element = create_best_element (caps);
 | 
				
			||||||
 | 
					    gst_caps_unref (caps);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (priv->element) {
 | 
				
			||||||
 | 
					      pinos_properties_set (props, "autoconnect", "0");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* chain up */
 | 
				
			||||||
 | 
					  source_task = g_task_new (node, NULL, on_output_port_created, task);
 | 
				
			||||||
 | 
					  PINOS_NODE_CLASS (pinos_gst_source_parent_class)->create_port (node,
 | 
				
			||||||
 | 
					                                                                 direction,
 | 
				
			||||||
 | 
					                                                                 name,
 | 
				
			||||||
 | 
					                                                                 possible_formats,
 | 
				
			||||||
 | 
					                                                                 props,
 | 
				
			||||||
 | 
					                                                                 source_task);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
pinos_gst_source_class_init (PinosGstSourceClass * klass)
 | 
					pinos_gst_source_class_init (PinosGstSourceClass * klass)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -453,6 +569,7 @@ pinos_gst_source_class_init (PinosGstSourceClass * klass)
 | 
				
			||||||
                                                       G_PARAM_STATIC_STRINGS));
 | 
					                                                       G_PARAM_STATIC_STRINGS));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  node_class->set_state = set_state;
 | 
					  node_class->set_state = set_state;
 | 
				
			||||||
 | 
					  node_class->create_port = source_create_port;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue