track-object: Keep a reference to our gnlobject

Avoid refering to an object that doesn't exists and segfault in some cases.

We do not need to increase the reference to the gnlobj when the trackobject
is removed from a track because the TrackObject as its own reference and will
handle the disposal gracefully.

Add some guard around related APIs
This commit is contained in:
Thibault Saunier 2012-05-10 12:40:23 -04:00
parent 20e7d4349c
commit 9ee94b3d40
2 changed files with 26 additions and 8 deletions

View file

@ -198,9 +198,29 @@ static void
ges_track_object_dispose (GObject * object) ges_track_object_dispose (GObject * object)
{ {
GESTrackObjectPrivate *priv = GES_TRACK_OBJECT (object)->priv; GESTrackObjectPrivate *priv = GES_TRACK_OBJECT (object)->priv;
if (priv->properties_hashtable) if (priv->properties_hashtable)
g_hash_table_destroy (priv->properties_hashtable); g_hash_table_destroy (priv->properties_hashtable);
if (priv->gnlobject) {
GstState cstate;
if (priv->track != NULL) {
GST_ERROR_OBJECT (object, "Still in %p, this means that you forgot"
" to remove it from the GESTrack it is contained in. You always need"
" to remove a GESTrackObject from its track before dropping the last"
" reference\n"
"This problem may also be caused by a refcounting bug in"
" the application or GES itself.", priv->track);
gst_element_get_state (priv->gnlobject, &cstate, NULL, 0);
if (cstate != GST_STATE_NULL)
gst_element_set_state (priv->gnlobject, GST_STATE_NULL);
}
gst_object_unref (priv->gnlobject);
priv->gnlobject = NULL;
}
G_OBJECT_CLASS (ges_track_object_parent_class)->dispose (object); G_OBJECT_CLASS (ges_track_object_parent_class)->dispose (object);
} }
@ -780,7 +800,7 @@ ensure_gnl_object (GESTrackObject * object)
GST_DEBUG_OBJECT (object, "Got a valid GnlObject, now filling it in"); GST_DEBUG_OBJECT (object, "Got a valid GnlObject, now filling it in");
object->priv->gnlobject = gnlobject; object->priv->gnlobject = gst_object_ref (gnlobject);
if (object->priv->timelineobj) if (object->priv->timelineobj)
res = ges_timeline_object_fill_track_object (object->priv->timelineobj, res = ges_timeline_object_fill_track_object (object->priv->timelineobj,
@ -921,6 +941,8 @@ ges_track_object_get_timeline_object (GESTrackObject * object)
GstElement * GstElement *
ges_track_object_get_gnlobject (GESTrackObject * object) ges_track_object_get_gnlobject (GESTrackObject * object)
{ {
g_return_val_if_fail (GES_IS_TRACK_OBJECT (object), NULL);
return object->priv->gnlobject; return object->priv->gnlobject;
} }
@ -936,6 +958,8 @@ ges_track_object_get_gnlobject (GESTrackObject * object)
GstElement * GstElement *
ges_track_object_get_element (GESTrackObject * object) ges_track_object_get_element (GESTrackObject * object)
{ {
g_return_val_if_fail (GES_IS_TRACK_OBJECT (object), NULL);
return object->priv->element; return object->priv->element;
} }

View file

@ -548,19 +548,13 @@ ges_track_remove_object (GESTrack * track, GESTrackObject * object)
if ((gnlobject = ges_track_object_get_gnlobject (object))) { if ((gnlobject = ges_track_object_get_gnlobject (object))) {
GST_DEBUG ("Removing GnlObject '%s' from composition '%s'", GST_DEBUG ("Removing GnlObject '%s' from composition '%s'",
GST_ELEMENT_NAME (gnlobject), GST_ELEMENT_NAME (priv->composition)); GST_ELEMENT_NAME (gnlobject), GST_ELEMENT_NAME (priv->composition));
/* We can't just set state of gnlobject to GST_STATE_NULL, because it will
* result in deadlock. Adding a ref to the gnlobj so we finalize it after
* removing it from the composition */
gst_object_ref (gnlobject);
if (!gst_bin_remove (GST_BIN (priv->composition), gnlobject)) { if (!gst_bin_remove (GST_BIN (priv->composition), gnlobject)) {
GST_WARNING ("Failed to remove gnlobject from composition"); GST_WARNING ("Failed to remove gnlobject from composition");
return FALSE; return FALSE;
} }
gst_element_set_state (gnlobject, GST_STATE_NULL); gst_element_set_state (gnlobject, GST_STATE_NULL);
/* Wait for the state change to actually happen */
gst_element_get_state (gnlobject, NULL, NULL, GST_CLOCK_TIME_NONE);
gst_object_unref (gnlobject);
} }
g_signal_handlers_disconnect_by_func (object, sort_track_objects_cb, NULL); g_signal_handlers_disconnect_by_func (object, sort_track_objects_cb, NULL);