diff options
author | Tim-Philipp Müller <tim.muller@collabora.co.uk> | 2010-01-18 02:08:39 +0000 |
---|---|---|
committer | Tim-Philipp Müller <tim.muller@collabora.co.uk> | 2010-01-18 10:10:27 +0000 |
commit | 7216605ffa14854802c3ae402b48931819a38560 (patch) | |
tree | 2a047d0c6412bcb51221fc4dc83ac44d8af15429 | |
parent | 7335ce5d3e03c126a417a721571cb6f3af136ecf (diff) |
playsink: when looking for sink properties, make sure they have the right type
We don't want to end up setting values on elements where the property is of
a different type than we expect. Can't transform the value either, since we
can't really make assumptions about the scale and transform function.
Fixes crashes when using playbin2 with apexsink (#606949).
-rw-r--r-- | gst/playback/gstplaysink.c | 98 |
1 files changed, 76 insertions, 22 deletions
diff --git a/gst/playback/gstplaysink.c b/gst/playback/gstplaysink.c index aaed6564d..19f4554e7 100644 --- a/gst/playback/gstplaysink.c +++ b/gst/playback/gstplaysink.c @@ -787,26 +787,66 @@ gst_play_sink_find_property (GstPlaySink * playsink, GstElement * obj, return result; } -static gint -find_property_sink (GstElement * element, const gchar * name) +static gboolean +element_is_sink (GstElement * element) { - gint res; gboolean is_sink; GST_OBJECT_LOCK (element); is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SINK); GST_OBJECT_UNLOCK (element); - if (is_sink && - g_object_class_find_property (G_OBJECT_GET_CLASS (element), name)) { - res = 0; - GST_DEBUG_OBJECT (element, "found %s property on sink", name); - } else { - GST_DEBUG_OBJECT (element, "did not find %s property", name); - res = 1; + GST_DEBUG_OBJECT (element, "is a sink: %s", (is_sink) ? "yes" : "no"); + return is_sink; +} + +static gboolean +element_has_property (GstElement * element, const gchar * pname, GType type) +{ + GParamSpec *pspec; + + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (element), pname); + + if (pspec == NULL) { + GST_DEBUG_OBJECT (element, "no %s property", pname); + return FALSE; + } + + if (type == G_TYPE_INVALID || type == pspec->value_type || + g_type_is_a (pspec->value_type, type)) { + GST_DEBUG_OBJECT (element, "has %s property of type %s", pname, + (type == G_TYPE_INVALID) ? "any type" : g_type_name (type)); + return TRUE; + } + + GST_WARNING_OBJECT (element, "has %s property, but property is of type %s " + "and we expected it to be of type %s", pname, + g_type_name (pspec->value_type), g_type_name (type)); + + return FALSE; +} + +typedef struct +{ + const gchar *prop_name; + GType prop_type; +} FindPropertyHelper; + +static gint +find_property_sink (GstElement * element, FindPropertyHelper * helper) +{ + if (!element_is_sink (element)) { gst_object_unref (element); + return 1; } - return res; + + if (!element_has_property (element, helper->prop_name, helper->prop_type)) { + gst_object_unref (element); + return 1; + } + + GST_INFO_OBJECT (element, "found sink with %s property", helper->prop_name); + return 0; /* keep it */ } /* find a sink in the hierarchy with a property named @name. This function does @@ -814,17 +854,19 @@ find_property_sink (GstElement * element, const gchar * name) * long as the bin is valid. */ static GstElement * gst_play_sink_find_property_sinks (GstPlaySink * playsink, GstElement * obj, - const gchar * name) + const gchar * name, GType expected_type) { GstElement *result = NULL; GstIterator *it; - if (g_object_class_find_property (G_OBJECT_GET_CLASS (obj), name)) { + if (element_has_property (obj, name, expected_type)) { result = obj; } else if (GST_IS_BIN (obj)) { + FindPropertyHelper helper = { name, expected_type }; + it = gst_bin_iterate_recurse (GST_BIN_CAST (obj)); result = gst_iterator_find_custom (it, - (GCompareFunc) find_property_sink, (gpointer) name); + (GCompareFunc) find_property_sink, &helper); gst_iterator_free (it); /* we don't need the extra ref */ if (result) @@ -942,7 +984,9 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async, /* if we can disable async behaviour of the sink, we can avoid adding a * queue for the audio chain. */ - elem = gst_play_sink_find_property_sinks (playsink, chain->sink, "async"); + elem = + gst_play_sink_find_property_sinks (playsink, chain->sink, "async", + G_TYPE_BOOLEAN); if (elem) { GST_DEBUG_OBJECT (playsink, "setting async property to %d on element %s", async, GST_ELEMENT_NAME (elem)); @@ -1087,7 +1131,9 @@ setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async, /* if we can disable async behaviour of the sink, we can avoid adding a * queue for the audio chain. */ - elem = gst_play_sink_find_property_sinks (playsink, chain->sink, "async"); + elem = + gst_play_sink_find_property_sinks (playsink, chain->sink, "async", + G_TYPE_BOOLEAN); if (elem) { GST_DEBUG_OBJECT (playsink, "setting async property to %d on element %s", async, GST_ELEMENT_NAME (elem)); @@ -1137,7 +1183,9 @@ gen_text_chain (GstPlaySink * playsink) GST_DEBUG_OBJECT (playsink, "trying configured textsink"); chain->sink = try_element (playsink, playsink->text_sink, FALSE); if (chain->sink) { - elem = gst_play_sink_find_property_sinks (playsink, chain->sink, "async"); + elem = + gst_play_sink_find_property_sinks (playsink, chain->sink, "async", + G_TYPE_BOOLEAN); if (elem) { /* make sure the sparse subtitles don't participate in the preroll */ g_object_set (elem, "async", FALSE, NULL); @@ -1156,7 +1204,7 @@ gen_text_chain (GstPlaySink * playsink) /* try to set sync to true but it's no biggie when we can't */ if ((elem = gst_play_sink_find_property_sinks (playsink, chain->sink, - "sync"))) + "sync", G_TYPE_BOOLEAN))) g_object_set (elem, "sync", TRUE, NULL); } else { GST_WARNING_OBJECT (playsink, @@ -1331,7 +1379,9 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw, gboolean queue) /* check if the sink, or something within the sink, has the volume property. * If it does we don't need to add a volume element. */ - elem = gst_play_sink_find_property_sinks (playsink, chain->sink, "volume"); + elem = + gst_play_sink_find_property_sinks (playsink, chain->sink, "volume", + G_TYPE_DOUBLE); if (elem) { chain->volume = elem; @@ -1345,7 +1395,8 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw, gboolean queue) * use the mute property if there is a volume property. We can simulate the * mute with the volume otherwise. */ chain->mute = - gst_play_sink_find_property_sinks (playsink, chain->sink, "mute"); + gst_play_sink_find_property_sinks (playsink, chain->sink, "mute", + G_TYPE_BOOLEAN); if (chain->mute) { GST_DEBUG_OBJECT (playsink, "the sink has a mute property"); g_signal_connect (chain->mute, "notify::mute", @@ -1527,7 +1578,9 @@ setup_audio_chain (GstPlaySink * playsink, gboolean raw, gboolean queue) /* check if the sink, or something within the sink, has the volume property. * If it does we don't need to add a volume element. */ - elem = gst_play_sink_find_property_sinks (playsink, chain->sink, "volume"); + elem = + gst_play_sink_find_property_sinks (playsink, chain->sink, "volume", + G_TYPE_DOUBLE); if (elem) { chain->volume = elem; @@ -1545,7 +1598,8 @@ setup_audio_chain (GstPlaySink * playsink, gboolean raw, gboolean queue) * use the mute property if there is a volume property. We can simulate the * mute with the volume otherwise. */ chain->mute = - gst_play_sink_find_property_sinks (playsink, chain->sink, "mute"); + gst_play_sink_find_property_sinks (playsink, chain->sink, "mute", + G_TYPE_BOOLEAN); if (chain->mute) { GST_DEBUG_OBJECT (playsink, "the sink has a mute property"); g_signal_connect (chain->mute, "notify::mute", |