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:
David Svensson Fors 2016-06-23 19:22:13 +02:00 committed by Wim Taymans
parent c70e24c51c
commit 649882f42a

View file

@ -371,6 +371,7 @@ on_output_port_created (GObject *source_object,
PinosNode *node = PINOS_NODE (source_object);
PinosGstSource *source = PINOS_GST_SOURCE (node);
PinosGstSourcePrivate *priv = source->priv;
GTask *task = user_data;
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);
setup_pipeline (source, NULL);
if (task) {
g_task_return_pointer (task,
priv->output,
(GDestroyNotify) g_object_unref);
}
}
static void
@ -391,18 +398,20 @@ source_constructed (GObject * object)
G_OBJECT_CLASS (pinos_gst_source_parent_class)->constructed (object);
str = gst_caps_to_string (priv->possible_formats);
possible_formats = g_bytes_new_take (str, strlen (str) + 1);
if (priv->element) {
str = gst_caps_to_string (priv->possible_formats);
possible_formats = g_bytes_new_take (str, strlen (str) + 1);
pinos_node_create_port (PINOS_NODE (node),
PINOS_DIRECTION_OUTPUT,
"output",
possible_formats,
NULL,
NULL,
on_output_port_created,
node);
g_bytes_unref (possible_formats);
pinos_node_create_port (PINOS_NODE (node),
PINOS_DIRECTION_OUTPUT,
"output",
possible_formats,
NULL,
NULL,
NULL,
NULL);
g_bytes_unref (possible_formats);
}
}
static void
@ -420,6 +429,113 @@ source_finalize (GObject * 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
pinos_gst_source_class_init (PinosGstSourceClass * klass)
{
@ -453,6 +569,7 @@ pinos_gst_source_class_init (PinosGstSourceClass * klass)
G_PARAM_STATIC_STRINGS));
node_class->set_state = set_state;
node_class->create_port = source_create_port;
}
static void