summaryrefslogtreecommitdiff
path: root/plugins/nle/nleobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/nle/nleobject.c')
-rw-r--r--plugins/nle/nleobject.c738
1 files changed, 738 insertions, 0 deletions
diff --git a/plugins/nle/nleobject.c b/plugins/nle/nleobject.c
new file mode 100644
index 00000000..94be16d2
--- /dev/null
+++ b/plugins/nle/nleobject.c
@@ -0,0 +1,738 @@
+/* Gnonlin
+ * Copyright (C) <2001> Wim Taymans <wim.taymans@gmail.com>
+ * <2004-2008> Edward Hervey <bilboed@bilboed.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include "nle.h"
+
+/**
+ * SECTION:nleobject
+ * @short_description: Base class for GNonLin elements
+ *
+ * <refsect2>
+ * <para>
+ * NleObject encapsulates default behaviour and implements standard
+ * properties provided by all the GNonLin elements.
+ * </para>
+ * </refsect2>
+ *
+ */
+
+
+GST_DEBUG_CATEGORY_STATIC (nleobject_debug);
+#define GST_CAT_DEFAULT nleobject_debug
+
+static GObjectClass *parent_class = NULL;
+
+/****************************************************
+ * Helper macros *
+ ****************************************************/
+#define CHECK_AND_SET(PROPERTY, property, prop_str, print_format) \
+{ \
+if (object->pending_##property != object->property) { \
+ object->property = object->pending_##property; \
+ GST_DEBUG_OBJECT(object, "Setting " prop_str " to %" \
+ print_format, object->property); \
+} else \
+ GST_DEBUG_OBJECT(object, "Nothing to do for " prop_str); \
+}
+
+#define SET_PENDING_VALUE(property, property_str, type, print_format) \
+nleobject->pending_##property = g_value_get_##type (value); \
+if (nleobject->property != nleobject->pending_##property) { \
+ GST_DEBUG_OBJECT(object, "Setting pending " property_str " to %" \
+ print_format, nleobject->pending_##property); \
+ nle_object_set_commit_needed (nleobject); \
+} else \
+ GST_DEBUG_OBJECT(object, "Pending " property_str " did not change");
+
+enum
+{
+ PROP_0,
+ PROP_START,
+ PROP_DURATION,
+ PROP_STOP,
+ PROP_INPOINT,
+ PROP_PRIORITY,
+ PROP_ACTIVE,
+ PROP_CAPS,
+ PROP_EXPANDABLE,
+ PROP_LAST
+};
+
+enum
+{
+ COMMIT_SIGNAL,
+ LAST_SIGNAL
+};
+
+static guint _signals[LAST_SIGNAL] = { 0 };
+
+static GParamSpec *properties[PROP_LAST];
+
+static void nle_object_dispose (GObject * object);
+
+static void nle_object_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void nle_object_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void nle_object_constructed (GObject * object);
+
+static GstStateChangeReturn nle_object_change_state (GstElement * element,
+ GstStateChange transition);
+
+static gboolean nle_object_prepare_func (NleObject * object);
+static gboolean nle_object_cleanup_func (NleObject * object);
+static gboolean nle_object_commit_func (NleObject * object, gboolean recurse);
+
+static GstStateChangeReturn nle_object_prepare (NleObject * object);
+
+static void
+nle_object_class_init (NleObjectClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ NleObjectClass *nleobject_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ nleobject_class = (NleObjectClass *) klass;
+ GST_DEBUG_CATEGORY_INIT (nleobject_debug, "nleobject",
+ GST_DEBUG_FG_BLUE | GST_DEBUG_BOLD, "GNonLin object");
+ parent_class = g_type_class_ref (GST_TYPE_BIN);
+
+ gobject_class->set_property = GST_DEBUG_FUNCPTR (nle_object_set_property);
+ gobject_class->get_property = GST_DEBUG_FUNCPTR (nle_object_get_property);
+ gobject_class->constructed = GST_DEBUG_FUNCPTR (nle_object_constructed);
+ gobject_class->dispose = GST_DEBUG_FUNCPTR (nle_object_dispose);
+
+ gstelement_class->change_state = GST_DEBUG_FUNCPTR (nle_object_change_state);
+
+ nleobject_class->prepare = GST_DEBUG_FUNCPTR (nle_object_prepare_func);
+ nleobject_class->cleanup = GST_DEBUG_FUNCPTR (nle_object_cleanup_func);
+ nleobject_class->commit_signal_handler =
+ GST_DEBUG_FUNCPTR (nle_object_commit);
+ nleobject_class->commit = GST_DEBUG_FUNCPTR (nle_object_commit_func);
+
+ /**
+ * NleObject:start
+ *
+ * The start position relative to the parent in nanoseconds.
+ */
+ properties[PROP_START] = g_param_spec_uint64 ("start", "Start",
+ "The start position relative to the parent (in nanoseconds)",
+ 0, G_MAXUINT64, 0, G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_START,
+ properties[PROP_START]);
+
+ /**
+ * NleObject:duration
+ *
+ * The outgoing duration in nanoseconds.
+ */
+ properties[PROP_DURATION] = g_param_spec_int64 ("duration", "Duration",
+ "Outgoing duration (in nanoseconds)", 0, G_MAXINT64, 0,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_DURATION,
+ properties[PROP_DURATION]);
+
+ /**
+ * NleObject:stop
+ *
+ * The stop position relative to the parent in nanoseconds.
+ *
+ * This value is computed based on the values of start and duration.
+ */
+ properties[PROP_STOP] = g_param_spec_uint64 ("stop", "Stop",
+ "The stop position relative to the parent (in nanoseconds)",
+ 0, G_MAXUINT64, 0, G_PARAM_READABLE);
+ g_object_class_install_property (gobject_class, PROP_STOP,
+ properties[PROP_STOP]);
+
+ /**
+ * NleObject:inpoint
+ *
+ * The media start position in nanoseconds.
+ *
+ * Also called 'in-point' in video-editing, this corresponds to
+ * what position in the 'contained' object we should start outputting from.
+ */
+ properties[PROP_INPOINT] =
+ g_param_spec_uint64 ("inpoint", "Media start",
+ "The media start position (in nanoseconds)", 0, G_MAXUINT64,
+ GST_CLOCK_TIME_NONE, G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_INPOINT,
+ properties[PROP_INPOINT]);
+
+ /**
+ * NleObject:priority
+ *
+ * The priority of the object in the container.
+ *
+ * The highest priority is 0, meaning this object will be selected over
+ * any other between start and stop.
+ *
+ * The lowest priority is G_MAXUINT32.
+ *
+ * Objects whose priority is (-1) will be considered as 'default' objects
+ * in NleComposition and their start/stop values will be modified as to
+ * fit the whole duration of the composition.
+ */
+ properties[PROP_PRIORITY] = g_param_spec_uint ("priority", "Priority",
+ "The priority of the object (0 = highest priority)", 0, G_MAXUINT, 0,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_PRIORITY,
+ properties[PROP_PRIORITY]);
+
+ /**
+ * NleObject:active
+ *
+ * Indicates whether this object should be used by its container.
+ *
+ * Set to #TRUE to temporarily disable this object in a #NleComposition.
+ */
+ properties[PROP_ACTIVE] = g_param_spec_boolean ("active", "Active",
+ "Use this object in the NleComposition", TRUE, G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_ACTIVE,
+ properties[PROP_ACTIVE]);
+
+ /**
+ * NleObject:caps
+ *
+ * Caps used to filter/choose the output stream.
+ *
+ * If the controlled object produces several stream, you can set this
+ * property to choose a specific stream.
+ *
+ * If nothing is specified then a source pad will be chosen at random.
+ */
+ properties[PROP_CAPS] = g_param_spec_boxed ("caps", "Caps",
+ "Caps used to filter/choose the output stream",
+ GST_TYPE_CAPS, G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_CAPS,
+ properties[PROP_CAPS]);
+
+ /**
+ * NleObject:expandable
+ *
+ * Indicates whether this object should expand to the full duration of its
+ * container #NleComposition.
+ */
+ properties[PROP_EXPANDABLE] =
+ g_param_spec_boolean ("expandable", "Expandable",
+ "Expand to the full duration of the container composition", FALSE,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_EXPANDABLE,
+ properties[PROP_EXPANDABLE]);
+
+ /**
+ * NleObject::commit
+ * @object: a #NleObject
+ * @recurse: Whether to commit recursiverly into (NleComposition) children of
+ * @object. This is used in case we have composition inside
+ * a nlesource composition, telling it to commit the included
+ * composition state.
+ *
+ * Action signal to commit all the pending changes of the composition and
+ * its children timing properties
+ *
+ * Returns: %TRUE if changes have been commited, %FALSE if nothing had to
+ * be commited
+ */
+ _signals[COMMIT_SIGNAL] = g_signal_new ("commit", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (NleObjectClass, commit_signal_handler), NULL, NULL, NULL,
+ G_TYPE_BOOLEAN, 1, G_TYPE_BOOLEAN);
+}
+
+static void
+nle_object_init (NleObject * object, NleObjectClass * klass)
+{
+ object->start = object->pending_start = 0;
+ object->duration = object->pending_duration = 0;
+ object->stop = 0;
+
+ object->inpoint = object->pending_inpoint = GST_CLOCK_TIME_NONE;
+ object->priority = object->pending_priority = 0;
+ object->active = object->pending_active = TRUE;
+
+ object->caps = gst_caps_new_any ();
+
+ object->segment_rate = 1.0;
+ object->segment_start = -1;
+ object->segment_stop = -1;
+
+ object->srcpad = nle_object_ghost_pad_no_target (object,
+ "src", GST_PAD_SRC,
+ gst_element_class_get_pad_template ((GstElementClass *) klass, "src"));
+
+ gst_element_add_pad (GST_ELEMENT (object), object->srcpad);
+}
+
+static void
+nle_object_dispose (GObject * object)
+{
+ NleObject *nle = (NleObject *) object;
+
+ if (nle->caps) {
+ gst_caps_unref (nle->caps);
+ nle->caps = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+/**
+ * nle_object_to_media_time:
+ * @object: a #NleObject
+ * @objecttime: The #GstClockTime we want to convert
+ * @mediatime: A pointer on a #GstClockTime to fill
+ *
+ * Converts a #GstClockTime from the object (container) context to the media context
+ *
+ * Returns: TRUE if @objecttime was within the limits of the @object start/stop time,
+ * FALSE otherwise
+ */
+gboolean
+nle_object_to_media_time (NleObject * object, GstClockTime otime,
+ GstClockTime * mtime)
+{
+ g_return_val_if_fail (mtime, FALSE);
+
+ GST_DEBUG_OBJECT (object, "ObjectTime : %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (otime));
+
+ GST_DEBUG_OBJECT (object,
+ "Start/Stop:[%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT "] "
+ "Media start: %" GST_TIME_FORMAT, GST_TIME_ARGS (object->start),
+ GST_TIME_ARGS (object->stop), GST_TIME_ARGS (object->inpoint));
+
+ /* limit check */
+ if (G_UNLIKELY ((otime < object->start))) {
+ GST_DEBUG_OBJECT (object, "ObjectTime is before start");
+ *mtime = (object->inpoint == GST_CLOCK_TIME_NONE) ? 0 : object->inpoint;
+ return FALSE;
+ }
+
+ if (G_UNLIKELY ((otime >= object->stop))) {
+ GST_DEBUG_OBJECT (object, "ObjectTime is after stop");
+ if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (object->inpoint)))
+ *mtime = object->inpoint + object->duration;
+ else
+ *mtime = object->stop - object->start;
+ return FALSE;
+ }
+
+ if (G_UNLIKELY (object->inpoint == GST_CLOCK_TIME_NONE)) {
+ /* no time shifting, for live sources ? */
+ *mtime = otime - object->start;
+ } else {
+ *mtime = otime - object->start + object->inpoint;
+ }
+
+ GST_DEBUG_OBJECT (object, "Returning MediaTime : %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (*mtime));
+
+ return TRUE;
+}
+
+/**
+ * nle_media_to_object_time:
+ * @object: The #NleObject
+ * @mediatime: The #GstClockTime we want to convert
+ * @objecttime: A pointer on a #GstClockTime to fill
+ *
+ * Converts a #GstClockTime from the media context to the object (container) context
+ *
+ * Returns: TRUE if @objecttime was within the limits of the @object media start/stop time,
+ * FALSE otherwise
+ */
+
+gboolean
+nle_media_to_object_time (NleObject * object, GstClockTime mtime,
+ GstClockTime * otime)
+{
+ g_return_val_if_fail (otime, FALSE);
+
+ GST_DEBUG_OBJECT (object, "MediaTime : %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (mtime));
+
+ GST_DEBUG_OBJECT (object,
+ "Start/Stop:[%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT "] "
+ "inpoint %" GST_TIME_FORMAT, GST_TIME_ARGS (object->start),
+ GST_TIME_ARGS (object->stop), GST_TIME_ARGS (object->inpoint));
+
+
+ /* limit check */
+ if (G_UNLIKELY ((object->inpoint != GST_CLOCK_TIME_NONE)
+ && (mtime < object->inpoint))) {
+ GST_DEBUG_OBJECT (object, "media time is before inpoint, forcing to start");
+ *otime = object->start;
+ return FALSE;
+ }
+
+ if (G_LIKELY (object->inpoint != GST_CLOCK_TIME_NONE)) {
+ *otime = mtime - object->inpoint + object->start;
+ } else
+ *otime = mtime + object->start;
+
+ GST_DEBUG_OBJECT (object, "Returning ObjectTime : %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (*otime));
+ return TRUE;
+}
+
+static gboolean
+nle_object_prepare_func (NleObject * object)
+{
+ GST_DEBUG_OBJECT (object, "default prepare function, returning TRUE");
+
+ return TRUE;
+}
+
+static GstStateChangeReturn
+nle_object_prepare (NleObject * object)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+ GST_DEBUG_OBJECT (object, "preparing");
+
+ if (!(NLE_OBJECT_GET_CLASS (object)->prepare (object)))
+ ret = GST_STATE_CHANGE_FAILURE;
+
+ GST_DEBUG_OBJECT (object, "finished preparing, returning %d", ret);
+
+ return ret;
+}
+
+static gboolean
+nle_object_cleanup_func (NleObject * object)
+{
+ GST_DEBUG_OBJECT (object, "default cleanup function, returning TRUE");
+
+ return TRUE;
+}
+
+GstStateChangeReturn
+nle_object_cleanup (NleObject * object)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+ GST_DEBUG_OBJECT (object, "cleaning-up");
+
+ if (!(NLE_OBJECT_GET_CLASS (object)->cleanup (object)))
+ ret = GST_STATE_CHANGE_FAILURE;
+
+ GST_DEBUG_OBJECT (object, "finished preparing, returning %d", ret);
+
+ return ret;
+}
+
+void
+nle_object_set_caps (NleObject * object, const GstCaps * caps)
+{
+ if (object->caps)
+ gst_caps_unref (object->caps);
+
+ object->caps = gst_caps_copy (caps);
+}
+
+static inline void
+_update_stop (NleObject * nleobject)
+{
+ /* check if start/duration has changed */
+
+ if ((nleobject->pending_start + nleobject->pending_duration) !=
+ nleobject->stop) {
+ nleobject->stop = nleobject->pending_start + nleobject->pending_duration;
+
+ GST_LOG_OBJECT (nleobject,
+ "Updating stop value : %" GST_TIME_FORMAT " [start:%" GST_TIME_FORMAT
+ ", duration:%" GST_TIME_FORMAT "]", GST_TIME_ARGS (nleobject->stop),
+ GST_TIME_ARGS (nleobject->pending_start),
+ GST_TIME_ARGS (nleobject->pending_duration));
+ g_object_notify_by_pspec (G_OBJECT (nleobject), properties[PROP_STOP]);
+ }
+}
+
+static void
+update_values (NleObject * object)
+{
+ CHECK_AND_SET (START, start, "start", G_GUINT64_FORMAT);
+ CHECK_AND_SET (INPOINT, inpoint, "inpoint", G_GUINT64_FORMAT);
+ CHECK_AND_SET (DURATION, duration, "duration", G_GINT64_FORMAT);
+ CHECK_AND_SET (PRIORITY, priority, "priority", G_GUINT32_FORMAT);
+ CHECK_AND_SET (ACTIVE, active, "active", G_GUINT32_FORMAT);
+
+ _update_stop (object);
+}
+
+static gboolean
+nle_object_commit_func (NleObject * object, gboolean recurse)
+{
+ GST_DEBUG_OBJECT (object, "Commiting object changed");
+
+ if (object->commit_needed == FALSE) {
+ GST_INFO_OBJECT (object, "No changes to commit");
+
+ return FALSE;
+ }
+
+ update_values (object);
+
+ GST_DEBUG_OBJECT (object, "Done commiting");
+
+ return TRUE;
+}
+
+static void
+nle_object_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ NleObject *nleobject = (NleObject *) object;
+
+ g_return_if_fail (NLE_IS_OBJECT (object));
+
+ GST_OBJECT_LOCK (object);
+ switch (prop_id) {
+ case PROP_START:
+ SET_PENDING_VALUE (start, "start", uint64, G_GUINT64_FORMAT);
+ break;
+ case PROP_DURATION:
+ SET_PENDING_VALUE (duration, "duration", int64, G_GINT64_FORMAT);
+ break;
+ case PROP_INPOINT:
+ SET_PENDING_VALUE (inpoint, "inpoint", uint64, G_GUINT64_FORMAT);
+ break;
+ case PROP_PRIORITY:
+ SET_PENDING_VALUE (priority, "priority", uint, G_GUINT32_FORMAT);
+ break;
+ case PROP_ACTIVE:
+ SET_PENDING_VALUE (active, "active", boolean, G_GUINT32_FORMAT);
+ break;
+ case PROP_CAPS:
+ nle_object_set_caps (nleobject, gst_value_get_caps (value));
+ break;
+ case PROP_EXPANDABLE:
+ if (g_value_get_boolean (value))
+ GST_OBJECT_FLAG_SET (nleobject, NLE_OBJECT_EXPANDABLE);
+ else
+ GST_OBJECT_FLAG_UNSET (nleobject, NLE_OBJECT_EXPANDABLE);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+ GST_OBJECT_UNLOCK (object);
+}
+
+static void
+nle_object_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ NleObject *nleobject = (NleObject *) object;
+
+ switch (prop_id) {
+ case PROP_START:
+ g_value_set_uint64 (value, nleobject->pending_start);
+ break;
+ case PROP_DURATION:
+ g_value_set_int64 (value, nleobject->pending_duration);
+ break;
+ case PROP_STOP:
+ g_value_set_uint64 (value, nleobject->stop);
+ break;
+ case PROP_INPOINT:
+ g_value_set_uint64 (value, nleobject->pending_inpoint);
+ break;
+ case PROP_PRIORITY:
+ g_value_set_uint (value, nleobject->pending_priority);
+ break;
+ case PROP_ACTIVE:
+ g_value_set_boolean (value, nleobject->pending_active);
+ break;
+ case PROP_CAPS:
+ gst_value_set_caps (value, nleobject->caps);
+ break;
+ case PROP_EXPANDABLE:
+ g_value_set_boolean (value, NLE_OBJECT_IS_EXPANDABLE (object));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+nle_object_constructed (GObject * object)
+{
+ NleObject *nleobject = (NleObject *) object;
+
+ _update_stop (nleobject);
+}
+
+static GstStateChangeReturn
+nle_object_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ {
+ GstObject *parent = gst_object_get_parent (GST_OBJECT (element));
+
+ /* Going to READY and if we are not in a composition, we need to make
+ * sure that the object positioning state is properly commited */
+ if (parent) {
+ if (g_strcmp0 (gst_element_get_name (GST_ELEMENT (parent)),
+ "current-bin")
+ && !NLE_OBJECT_IS_COMPOSITION (NLE_OBJECT (element))) {
+ GST_INFO ("Adding nleobject to something that is not a composition,"
+ " commiting ourself");
+ nle_object_commit (NLE_OBJECT (element), FALSE);
+ }
+
+ gst_object_unref (parent);
+ }
+ }
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ if (nle_object_prepare (NLE_OBJECT (element)) == GST_STATE_CHANGE_FAILURE) {
+ ret = GST_STATE_CHANGE_FAILURE;
+ goto beach;
+ }
+ break;
+ default:
+ break;
+ }
+
+ GST_DEBUG_OBJECT (element, "Calling parent change_state");
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ GST_DEBUG_OBJECT (element, "Return from parent change_state was %d", ret);
+
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ goto beach;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ /* cleanup nleobject */
+ if (nle_object_cleanup (NLE_OBJECT (element)) == GST_STATE_CHANGE_FAILURE)
+ ret = GST_STATE_CHANGE_FAILURE;
+ break;
+ default:
+ break;
+ }
+
+beach:
+ return ret;
+}
+
+void
+nle_object_set_commit_needed (NleObject * object)
+{
+ if (G_UNLIKELY (object->commiting)) {
+ GST_WARNING_OBJECT (object,
+ "Trying to set 'commit-needed' while commiting");
+
+ return;
+ }
+
+ GST_DEBUG_OBJECT (object, "Setting 'commit_needed'");
+ object->commit_needed = TRUE;
+}
+
+gboolean
+nle_object_commit (NleObject * object, gboolean recurse)
+{
+ gboolean ret;
+
+ GST_DEBUG_OBJECT (object, "Commiting object state");
+
+ object->commiting = TRUE;
+ ret = NLE_OBJECT_GET_CLASS (object)->commit (object, recurse);
+ object->commiting = FALSE;
+
+ return ret;
+
+}
+
+static void
+_send_seek_event (const GValue * item, gpointer seek_event)
+{
+ GstElement *child = g_value_get_object (item);
+
+ gst_element_send_event (child, gst_event_ref (seek_event));
+}
+
+void
+nle_object_seek_all_children (NleObject * object, GstEvent * seek_event)
+{
+ GstIterator *it = gst_bin_iterate_recurse (GST_BIN (object));
+
+ while (gst_iterator_foreach (it, _send_seek_event,
+ seek_event) == GST_ITERATOR_RESYNC)
+ gst_iterator_resync (it);
+
+ gst_iterator_free (it);
+ gst_event_unref (seek_event);
+}
+
+void
+nle_object_reset (NleObject * object)
+{
+ GST_INFO_OBJECT (object, "Resetting child timing values to default");
+
+ object->start = 0;
+ object->duration = 0;
+ object->stop = 0;
+ object->inpoint = GST_CLOCK_TIME_NONE;
+ object->priority = 0;
+ object->active = TRUE;
+}
+
+GType
+nle_object_get_type (void)
+{
+ static volatile gsize type = 0;
+
+ if (g_once_init_enter (&type)) {
+ GType _type;
+ static const GTypeInfo info = {
+ sizeof (NleObjectClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) nle_object_class_init,
+ NULL,
+ NULL,
+ sizeof (NleObject),
+ 0,
+ (GInstanceInitFunc) nle_object_init,
+ };
+
+ _type = g_type_register_static (GST_TYPE_BIN,
+ "NleObject", &info, G_TYPE_FLAG_ABSTRACT);
+ g_once_init_leave (&type, _type);
+ }
+ return type;
+}