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;
}
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_object_unref (element);
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;
}
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
@ -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",