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).
This commit is contained in:
Tim-Philipp Müller 2010-01-18 02:08:39 +00:00
parent 7335ce5d3e
commit 7216605ffa

View file

@ -787,26 +787,66 @@ gst_play_sink_find_property (GstPlaySink * playsink, GstElement * obj,
return result; return result;
} }
static gint static gboolean
find_property_sink (GstElement * element, const gchar * name) element_is_sink (GstElement * element)
{ {
gint res;
gboolean is_sink; gboolean is_sink;
GST_OBJECT_LOCK (element); GST_OBJECT_LOCK (element);
is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SINK); is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SINK);
GST_OBJECT_UNLOCK (element); GST_OBJECT_UNLOCK (element);
if (is_sink && GST_DEBUG_OBJECT (element, "is a sink: %s", (is_sink) ? "yes" : "no");
g_object_class_find_property (G_OBJECT_GET_CLASS (element), name)) { return is_sink;
res = 0; }
GST_DEBUG_OBJECT (element, "found %s property on sink", name);
} else { static gboolean
GST_DEBUG_OBJECT (element, "did not find %s property", name); element_has_property (GstElement * element, const gchar * pname, GType type)
res = 1; {
gst_object_unref (element); 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;
} }
return res;
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;
}
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 /* 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. */ * long as the bin is valid. */
static GstElement * static GstElement *
gst_play_sink_find_property_sinks (GstPlaySink * playsink, GstElement * obj, gst_play_sink_find_property_sinks (GstPlaySink * playsink, GstElement * obj,
const gchar * name) const gchar * name, GType expected_type)
{ {
GstElement *result = NULL; GstElement *result = NULL;
GstIterator *it; GstIterator *it;
if (g_object_class_find_property (G_OBJECT_GET_CLASS (obj), name)) { if (element_has_property (obj, name, expected_type)) {
result = obj; result = obj;
} else if (GST_IS_BIN (obj)) { } else if (GST_IS_BIN (obj)) {
FindPropertyHelper helper = { name, expected_type };
it = gst_bin_iterate_recurse (GST_BIN_CAST (obj)); it = gst_bin_iterate_recurse (GST_BIN_CAST (obj));
result = gst_iterator_find_custom (it, result = gst_iterator_find_custom (it,
(GCompareFunc) find_property_sink, (gpointer) name); (GCompareFunc) find_property_sink, &helper);
gst_iterator_free (it); gst_iterator_free (it);
/* we don't need the extra ref */ /* we don't need the extra ref */
if (result) 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 /* if we can disable async behaviour of the sink, we can avoid adding a
* queue for the audio chain. */ * 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) { if (elem) {
GST_DEBUG_OBJECT (playsink, "setting async property to %d on element %s", GST_DEBUG_OBJECT (playsink, "setting async property to %d on element %s",
async, GST_ELEMENT_NAME (elem)); 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 /* if we can disable async behaviour of the sink, we can avoid adding a
* queue for the audio chain. */ * 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) { if (elem) {
GST_DEBUG_OBJECT (playsink, "setting async property to %d on element %s", GST_DEBUG_OBJECT (playsink, "setting async property to %d on element %s",
async, GST_ELEMENT_NAME (elem)); async, GST_ELEMENT_NAME (elem));
@ -1137,7 +1183,9 @@ gen_text_chain (GstPlaySink * playsink)
GST_DEBUG_OBJECT (playsink, "trying configured textsink"); GST_DEBUG_OBJECT (playsink, "trying configured textsink");
chain->sink = try_element (playsink, playsink->text_sink, FALSE); chain->sink = try_element (playsink, playsink->text_sink, FALSE);
if (chain->sink) { 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) { if (elem) {
/* make sure the sparse subtitles don't participate in the preroll */ /* make sure the sparse subtitles don't participate in the preroll */
g_object_set (elem, "async", FALSE, NULL); 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 */ /* try to set sync to true but it's no biggie when we can't */
if ((elem = if ((elem =
gst_play_sink_find_property_sinks (playsink, chain->sink, gst_play_sink_find_property_sinks (playsink, chain->sink,
"sync"))) "sync", G_TYPE_BOOLEAN)))
g_object_set (elem, "sync", TRUE, NULL); g_object_set (elem, "sync", TRUE, NULL);
} else { } else {
GST_WARNING_OBJECT (playsink, 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. /* 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. */ * 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) { if (elem) {
chain->volume = 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 * use the mute property if there is a volume property. We can simulate the
* mute with the volume otherwise. */ * mute with the volume otherwise. */
chain->mute = 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) { if (chain->mute) {
GST_DEBUG_OBJECT (playsink, "the sink has a mute property"); GST_DEBUG_OBJECT (playsink, "the sink has a mute property");
g_signal_connect (chain->mute, "notify::mute", 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. /* 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. */ * 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) { if (elem) {
chain->volume = 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 * use the mute property if there is a volume property. We can simulate the
* mute with the volume otherwise. */ * mute with the volume otherwise. */
chain->mute = 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) { if (chain->mute) {
GST_DEBUG_OBJECT (playsink, "the sink has a mute property"); GST_DEBUG_OBJECT (playsink, "the sink has a mute property");
g_signal_connect (chain->mute, "notify::mute", g_signal_connect (chain->mute, "notify::mute",