/**
 * ges_track_remove_object:
 * @track: a #GESTrack
 * @object: the #GESTrackObject to remove
 *
 * Removes the object from the track and unparents it.
 * Unparenting it means the reference owned by @track on the @object will be
 * removed. If you wish to use the @object after this function, make sure you
 * call g_object_ref() before removing it from the @track.
 *
 * Returns: #TRUE if the object was removed, else #FALSE if the track
 * could not remove the object (like if it didn't belong to the track).
 */
gboolean
ges_track_remove_object (GESTrack * track, GESTrackObject * object)
{
  GESTrackPrivate *priv;
  GstElement *gnlobject;

  g_return_val_if_fail (GES_IS_TRACK (track), FALSE);
  g_return_val_if_fail (GES_IS_TRACK_OBJECT (object), FALSE);

  GST_DEBUG ("track:%p, object:%p", track, object);

  priv = track->priv;

  if (G_UNLIKELY (ges_track_object_get_track (object) != track)) {
    GST_WARNING ("Object belongs to another track");
    return FALSE;
  }

  if ((gnlobject = ges_track_object_get_gnlobject (object))) {
    GST_DEBUG ("Removing GnlObject '%s' from composition '%s'",
        GST_ELEMENT_NAME (gnlobject), GST_ELEMENT_NAME (priv->composition));
    if (!gst_bin_remove (GST_BIN (priv->composition), gnlobject)) {
      GST_WARNING ("Failed to remove gnlobject from composition");
      return FALSE;
    }
  }

  ges_track_object_set_track (object, NULL);
  priv->trackobjects = g_list_remove (priv->trackobjects, object);

  g_object_unref (object);

  return TRUE;
}
/**
 * ges_track_object_set_duration:
 * @object: a #GESTrackObject
 * @duration: the duration (in #GstClockTime)
 *
 * Set the duration which will be used in the container #GESTrack
 * starting from the 'in-point'
 */
void
ges_track_object_set_duration (GESTrackObject * object, guint64 duration)
{
  g_return_if_fail (GES_IS_TRACK_OBJECT (object));

  if (ges_track_object_set_duration_internal (object, duration))
    g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_DURATION]);
}
/**
 * ges_track_object_set_inpoint:
 * @object: a #GESTrackObject
 * @inpoint: the in-point (in #GstClockTime)
 *
 * Set the offset within the contents of this #GESTrackObject
 */
void
ges_track_object_set_inpoint (GESTrackObject * object, guint64 inpoint)
{
  g_return_if_fail (GES_IS_TRACK_OBJECT (object));

  if (ges_track_object_set_inpoint_internal (object, inpoint))
    g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_INPOINT]);
}
/**
 * ges_track_object_set_start:
 * @object: a #GESTrackObject
 * @start: the start position (in #GstClockTime)
 *
 * Sets the position of the object in the container #GESTrack.
 */
void
ges_track_object_set_start (GESTrackObject * object, guint64 start)
{
  g_return_if_fail (GES_IS_TRACK_OBJECT (object));

  if (ges_track_object_set_start_internal (object, start))
    g_object_notify_by_pspec (G_OBJECT (object), properties[PROP_START]);
}
void
deep_prop_changed_cb (GESTrackObject * obj, GstElement * element,
    GParamSpec * spec)
{
  GST_DEBUG ("%s property changed", g_param_spec_get_name (spec));
  fail_unless (GES_IS_TRACK_OBJECT (obj));
  fail_unless (GST_IS_ELEMENT (element));
}
/**
 * ges_track_object_set_active:
 * @object: a #GESTrackObject
 * @active: visibility
 *
 * Sets the usage of the @object. If @active is %TRUE, the object will be used for
 * playback and rendering, else it will be ignored.
 *
 * Returns: %TRUE if the property was toggled, else %FALSE
 */
gboolean
ges_track_object_set_active (GESTrackObject * object, gboolean active)
{
  g_return_val_if_fail (GES_IS_TRACK_OBJECT (object), FALSE);

  GST_DEBUG ("object:%p, active:%d", object, active);

  if (object->priv->gnlobject != NULL) {
    if (G_UNLIKELY (active == object->active))
      return FALSE;

    g_object_set (object->priv->gnlobject, "active", active, NULL);
  } else
    object->priv->pending_active = active;
  return TRUE;
}
/**
 * ges_track_add_object:
 * @track: a #GESTrack
 * @object: (transfer full): the #GESTrackObject to add
 *
 * Adds the given object to the track. Sets the object's controlling track,
 * and thus takes ownership of the @object.
 *
 * An object can only be added to one track.
 *
 * Returns: #TRUE if the object was properly added. #FALSE if the track does not
 * want to accept the object.
 */
gboolean
ges_track_add_object (GESTrack * track, GESTrackObject * object)
{
  g_return_val_if_fail (GES_IS_TRACK (track), FALSE);
  g_return_val_if_fail (GES_IS_TRACK_OBJECT (object), FALSE);

  GST_DEBUG ("track:%p, object:%p", track, object);

  if (G_UNLIKELY (ges_track_object_get_track (object) != NULL)) {
    GST_WARNING ("Object already belongs to another track");
    return FALSE;
  }

  /* At this point, the track object shouldn't have any gnlobject since
   * it hasn't been added to a track yet.
   * FIXME : This check seems a bit obsolete */
  if (G_UNLIKELY (ges_track_object_get_gnlobject (object) != NULL)) {
    GST_ERROR ("TrackObject already controls a gnlobject !");
    return FALSE;
  }

  if (G_UNLIKELY (!ges_track_object_set_track (object, track))) {
    GST_ERROR ("Couldn't properly add the object to the Track");
    return FALSE;
  }

  GST_DEBUG ("Adding object to ourself");

  if (G_UNLIKELY (!gst_bin_add (GST_BIN (track->priv->composition),
              ges_track_object_get_gnlobject (object)))) {
    GST_WARNING ("Couldn't add object to the GnlComposition");
    return FALSE;
  }

  g_object_ref_sink (object);

  track->priv->trackobjects = g_list_append (track->priv->trackobjects, object);

  return TRUE;
}