summaryrefslogtreecommitdiff
path: root/plugins/nle/nleoperation.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/nle/nleoperation.c')
-rw-r--r--plugins/nle/nleoperation.c843
1 files changed, 843 insertions, 0 deletions
diff --git a/plugins/nle/nleoperation.c b/plugins/nle/nleoperation.c
new file mode 100644
index 00000000..fa59734c
--- /dev/null
+++ b/plugins/nle/nleoperation.c
@@ -0,0 +1,843 @@
+/* GStreamer
+ * 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 "nle.h"
+
+/**
+ * SECTION:element-nleoperation
+ *
+ * <refsect2>
+ * <para>
+ * A NleOperation performs a transformation or mixing operation on the
+ * data from one or more #NleSources, which is used to implement filters or
+ * effects.
+ * </para>
+ * </refsect2>
+ */
+
+static GstStaticPadTemplate nle_operation_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate nle_operation_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink%d",
+ GST_PAD_SINK,
+ GST_PAD_REQUEST,
+ GST_STATIC_CAPS_ANY);
+
+GST_DEBUG_CATEGORY_STATIC (nleoperation);
+#define GST_CAT_DEFAULT nleoperation
+
+#define _do_init \
+ GST_DEBUG_CATEGORY_INIT (nleoperation, "nleoperation", GST_DEBUG_FG_BLUE | GST_DEBUG_BOLD, "GNonLin Operation element");
+#define nle_operation_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (NleOperation, nle_operation, NLE_TYPE_OBJECT,
+ _do_init);
+
+enum
+{
+ ARG_0,
+ ARG_SINKS,
+};
+
+enum
+{
+ INPUT_PRIORITY_CHANGED,
+ LAST_SIGNAL
+};
+
+static guint nle_operation_signals[LAST_SIGNAL] = { 0 };
+
+static void nle_operation_dispose (GObject * object);
+
+static void nle_operation_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void nle_operation_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static gboolean nle_operation_prepare (NleObject * object);
+static gboolean nle_operation_cleanup (NleObject * object);
+
+static gboolean nle_operation_add_element (GstBin * bin, GstElement * element);
+static gboolean nle_operation_remove_element (GstBin * bin,
+ GstElement * element);
+
+static GstPad *nle_operation_request_new_pad (GstElement * element,
+ GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
+static void nle_operation_release_pad (GstElement * element, GstPad * pad);
+
+static void synchronize_sinks (NleOperation * operation);
+static gboolean remove_sink_pad (NleOperation * operation, GstPad * sinkpad);
+
+
+static gboolean
+nle_operation_send_event (GstElement * element, GstEvent * event)
+{
+ gboolean res = TRUE;
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEEK:
+ nle_object_seek_all_children (NLE_OBJECT (element), event);
+ break;
+ default:
+ res = GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
+ break;
+ }
+
+ return res;
+}
+
+static void
+nle_operation_class_init (NleOperationClass * klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstBinClass *gstbin_class = (GstBinClass *) klass;
+
+ GstElementClass *gstelement_class = (GstElementClass *) klass;
+ NleObjectClass *nleobject_class = (NleObjectClass *) klass;
+
+ gst_element_class_set_static_metadata (gstelement_class, "GNonLin Operation",
+ "Filter/Editor",
+ "Encapsulates filters/effects for use with NLE Objects",
+ "Wim Taymans <wim.taymans@gmail.com>, Edward Hervey <bilboed@bilboed.com>");
+
+ gobject_class->dispose = GST_DEBUG_FUNCPTR (nle_operation_dispose);
+
+ gobject_class->set_property = GST_DEBUG_FUNCPTR (nle_operation_set_property);
+ gobject_class->get_property = GST_DEBUG_FUNCPTR (nle_operation_get_property);
+
+ /**
+ * NleOperation:sinks:
+ *
+ * Specifies the number of sink pads the operation should provide.
+ * If the sinks property is -1 (the default) pads are only created as
+ * demanded via get_request_pad() calls on the element.
+ */
+ g_object_class_install_property (gobject_class, ARG_SINKS,
+ g_param_spec_int ("sinks", "Sinks",
+ "Number of input sinks (-1 for automatic handling)", -1, G_MAXINT, -1,
+ G_PARAM_READWRITE));
+
+ /**
+ * NleOperation:input-priority-changed:
+ * @pad: The operation's input pad whose priority changed.
+ * @priority: The new priority
+ *
+ * Signals that the @priority of the stream being fed to the given @pad
+ * might have changed.
+ */
+ nle_operation_signals[INPUT_PRIORITY_CHANGED] =
+ g_signal_new ("input-priority-changed", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NleOperationClass,
+ input_priority_changed), NULL, NULL, g_cclosure_marshal_generic,
+ G_TYPE_NONE, 2, GST_TYPE_PAD, G_TYPE_UINT);
+
+ gstelement_class->request_new_pad =
+ GST_DEBUG_FUNCPTR (nle_operation_request_new_pad);
+ gstelement_class->release_pad = GST_DEBUG_FUNCPTR (nle_operation_release_pad);
+ gstelement_class->send_event = GST_DEBUG_FUNCPTR (nle_operation_send_event);
+
+ gstbin_class->add_element = GST_DEBUG_FUNCPTR (nle_operation_add_element);
+ gstbin_class->remove_element =
+ GST_DEBUG_FUNCPTR (nle_operation_remove_element);
+
+ nleobject_class->prepare = GST_DEBUG_FUNCPTR (nle_operation_prepare);
+ nleobject_class->cleanup = GST_DEBUG_FUNCPTR (nle_operation_cleanup);
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&nle_operation_src_template));
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&nle_operation_sink_template));
+
+}
+
+static void
+nle_operation_dispose (GObject * object)
+{
+ NleOperation *oper = (NleOperation *) object;
+
+ GST_DEBUG_OBJECT (object, "Disposing of source pad");
+
+ nle_object_ghost_pad_set_target (NLE_OBJECT (object),
+ NLE_OBJECT (object)->srcpad, NULL);
+
+ GST_DEBUG_OBJECT (object, "Disposing of sink pad(s)");
+ while (oper->sinks) {
+ GstPad *ghost = (GstPad *) oper->sinks->data;
+ remove_sink_pad (oper, ghost);
+ }
+
+ GST_DEBUG_OBJECT (object, "Done, calling parent class ::dispose()");
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+nle_operation_reset (NleOperation * operation)
+{
+ operation->num_sinks = 1;
+ operation->realsinks = 0;
+ operation->next_base_time = 0;
+}
+
+static void
+nle_operation_init (NleOperation * operation)
+{
+ nle_operation_reset (operation);
+ operation->element = NULL;
+}
+
+static gboolean
+element_is_valid_filter (GstElement * element, gboolean * isdynamic)
+{
+ gboolean havesink = FALSE;
+ gboolean havesrc = FALSE;
+ gboolean done = FALSE;
+ GstIterator *pads;
+ GValue item = { 0, };
+
+ if (isdynamic)
+ *isdynamic = FALSE;
+
+ pads = gst_element_iterate_pads (element);
+
+ while (!done) {
+ switch (gst_iterator_next (pads, &item)) {
+ case GST_ITERATOR_OK:
+ {
+ GstPad *pad = g_value_get_object (&item);
+
+ if (gst_pad_get_direction (pad) == GST_PAD_SRC)
+ havesrc = TRUE;
+ else if (gst_pad_get_direction (pad) == GST_PAD_SINK)
+ havesink = TRUE;
+
+ g_value_reset (&item);
+ break;
+ }
+ case GST_ITERATOR_RESYNC:
+ gst_iterator_resync (pads);
+ havesrc = FALSE;
+ havesink = FALSE;
+ break;
+ default:
+ /* ERROR and DONE */
+ done = TRUE;
+ break;
+ }
+ }
+
+ g_value_unset (&item);
+ gst_iterator_free (pads);
+
+ /* just look at the element's class, not the factory, since there might
+ * not be a factory (in case of python elements) or the factory is the
+ * wrong one (in case of a GstBin sub-class) and doesn't have complete
+ * information. */
+ {
+ GList *tmp =
+ gst_element_class_get_pad_template_list (GST_ELEMENT_GET_CLASS
+ (element));
+
+ while (tmp) {
+ GstPadTemplate *template = (GstPadTemplate *) tmp->data;
+
+ if (template->direction == GST_PAD_SRC)
+ havesrc = TRUE;
+ else if (template->direction == GST_PAD_SINK) {
+ if (!havesink && (template->presence == GST_PAD_REQUEST) && isdynamic)
+ *isdynamic = TRUE;
+ havesink = TRUE;
+ }
+ tmp = tmp->next;
+ }
+ }
+ return (havesink && havesrc);
+}
+
+/*
+ * get_src_pad:
+ * element: a #GstElement
+ *
+ * Returns: The src pad for the given element. A reference was added to the
+ * returned pad, remove it when you don't need that pad anymore.
+ * Returns NULL if there's no source pad.
+ */
+
+static GstPad *
+get_src_pad (GstElement * element)
+{
+ GstIterator *it;
+ GstIteratorResult itres;
+ GValue item = { 0, };
+ GstPad *srcpad = NULL;
+
+ it = gst_element_iterate_src_pads (element);
+ itres = gst_iterator_next (it, &item);
+ if (itres != GST_ITERATOR_OK) {
+ GST_DEBUG ("%s doesn't have a src pad !", GST_ELEMENT_NAME (element));
+ } else {
+ srcpad = g_value_get_object (&item);
+ gst_object_ref (srcpad);
+ }
+ g_value_reset (&item);
+ gst_iterator_free (it);
+
+ return srcpad;
+}
+
+/* get_nb_static_sinks:
+ *
+ * Returns : The number of static sink pads of the controlled element.
+ */
+static guint
+get_nb_static_sinks (NleOperation * oper)
+{
+ GstIterator *sinkpads;
+ gboolean done = FALSE;
+ guint nbsinks = 0;
+ GValue item = { 0, };
+
+ sinkpads = gst_element_iterate_sink_pads (oper->element);
+
+ while (!done) {
+ switch (gst_iterator_next (sinkpads, &item)) {
+ case GST_ITERATOR_OK:{
+ nbsinks++;
+ g_value_unset (&item);
+ }
+ break;
+ case GST_ITERATOR_RESYNC:
+ nbsinks = 0;
+ gst_iterator_resync (sinkpads);
+ break;
+ default:
+ /* ERROR and DONE */
+ done = TRUE;
+ break;
+ }
+ }
+
+ g_value_reset (&item);
+ gst_iterator_free (sinkpads);
+
+ GST_DEBUG ("We found %d static sinks", nbsinks);
+
+ return nbsinks;
+}
+
+static gboolean
+nle_operation_add_element (GstBin * bin, GstElement * element)
+{
+ NleOperation *operation = (NleOperation *) bin;
+ gboolean res = FALSE;
+ gboolean isdynamic;
+
+ GST_DEBUG_OBJECT (bin, "element:%s", GST_ELEMENT_NAME (element));
+
+ if (operation->element) {
+ GST_WARNING_OBJECT (operation,
+ "We already control an element : %s , remove it first",
+ GST_OBJECT_NAME (operation->element));
+ } else {
+ if (!element_is_valid_filter (element, &isdynamic)) {
+ GST_WARNING_OBJECT (operation,
+ "Element %s is not a valid filter element",
+ GST_ELEMENT_NAME (element));
+ } else {
+ if ((res = GST_BIN_CLASS (parent_class)->add_element (bin, element))) {
+ GstPad *srcpad;
+
+ srcpad = get_src_pad (element);
+ if (!srcpad)
+ return FALSE;
+
+ operation->element = element;
+ operation->dynamicsinks = isdynamic;
+
+ nle_object_ghost_pad_set_target (NLE_OBJECT (operation),
+ NLE_OBJECT (operation)->srcpad, srcpad);
+
+ /* Remove the reference get_src_pad gave us */
+ gst_object_unref (srcpad);
+
+ /* Figure out number of static sink pads */
+ operation->num_sinks = get_nb_static_sinks (operation);
+
+ /* Finally sync the ghostpads with the real pads */
+ synchronize_sinks (operation);
+ }
+ }
+ }
+
+ return res;
+}
+
+static gboolean
+nle_operation_remove_element (GstBin * bin, GstElement * element)
+{
+ NleOperation *operation = (NleOperation *) bin;
+ gboolean res = FALSE;
+
+ if (operation->element) {
+ if ((res = GST_BIN_CLASS (parent_class)->remove_element (bin, element)))
+ operation->element = NULL;
+ } else {
+ GST_WARNING_OBJECT (bin,
+ "Element %s is not the one controlled by this operation",
+ GST_ELEMENT_NAME (element));
+ }
+ return res;
+}
+
+static void
+nle_operation_set_sinks (NleOperation * operation, guint sinks)
+{
+ /* FIXME : Check if sinkpad of element is on-demand .... */
+
+ operation->num_sinks = sinks;
+ synchronize_sinks (operation);
+}
+
+static void
+nle_operation_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ NleOperation *operation = (NleOperation *) object;
+
+ switch (prop_id) {
+ case ARG_SINKS:
+ nle_operation_set_sinks (operation, g_value_get_int (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+nle_operation_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ NleOperation *operation = (NleOperation *) object;
+
+ switch (prop_id) {
+ case ARG_SINKS:
+ g_value_set_int (value, operation->num_sinks);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+/*
+ * Returns the first unused sink pad of the controlled element.
+ * Only use with static element. Unref after usage.
+ * Returns NULL if there's no more unused sink pads.
+ */
+static GstPad *
+get_unused_static_sink_pad (NleOperation * operation)
+{
+ GstIterator *pads;
+ gboolean done = FALSE;
+ GValue item = { 0, };
+ GstPad *ret = NULL;
+
+ if (!operation->element)
+ return NULL;
+
+ pads = gst_element_iterate_pads (operation->element);
+
+ while (!done) {
+ switch (gst_iterator_next (pads, &item)) {
+ case GST_ITERATOR_OK:
+ {
+ GstPad *pad = g_value_get_object (&item);
+
+ if (gst_pad_get_direction (pad) == GST_PAD_SINK) {
+ GList *tmp;
+ gboolean istaken = FALSE;
+
+ /* 1. figure out if one of our sink ghostpads has this pad as target */
+ for (tmp = operation->sinks; tmp; tmp = tmp->next) {
+ GstGhostPad *gpad = (GstGhostPad *) tmp->data;
+ GstPad *target = gst_ghost_pad_get_target (gpad);
+
+ GST_LOG ("found ghostpad with target %s:%s",
+ GST_DEBUG_PAD_NAME (target));
+
+ if (target) {
+ if (target == pad)
+ istaken = TRUE;
+ gst_object_unref (target);
+ }
+ }
+
+ /* 2. if not taken, return that pad */
+ if (!istaken) {
+ gst_object_ref (pad);
+ ret = pad;
+ done = TRUE;
+ }
+ }
+ g_value_reset (&item);
+ break;
+ }
+ case GST_ITERATOR_RESYNC:
+ gst_iterator_resync (pads);
+ break;
+ default:
+ /* ERROR and DONE */
+ done = TRUE;
+ break;
+ }
+ }
+
+ g_value_unset (&item);
+ gst_iterator_free (pads);
+
+ if (ret)
+ GST_DEBUG_OBJECT (operation, "found free sink pad %s:%s",
+ GST_DEBUG_PAD_NAME (ret));
+ else
+ GST_DEBUG_OBJECT (operation, "Couldn't find an unused sink pad");
+
+ return ret;
+}
+
+GstPad *
+get_unlinked_sink_ghost_pad (NleOperation * operation)
+{
+ GstIterator *pads;
+ gboolean done = FALSE;
+ GValue item = { 0, };
+ GstPad *ret = NULL;
+
+ if (!operation->element)
+ return NULL;
+
+ pads = gst_element_iterate_sink_pads ((GstElement *) operation);
+
+ while (!done) {
+ switch (gst_iterator_next (pads, &item)) {
+ case GST_ITERATOR_OK:
+ {
+ GstPad *pad = g_value_get_object (&item);
+ GstPad *peer = gst_pad_get_peer (pad);
+
+ if (peer == NULL) {
+ ret = pad;
+ gst_object_ref (ret);
+ done = TRUE;
+ } else {
+ gst_object_unref (peer);
+ }
+ g_value_reset (&item);
+ break;
+ }
+ case GST_ITERATOR_RESYNC:
+ gst_iterator_resync (pads);
+ break;
+ default:
+ /* ERROR and DONE */
+ done = TRUE;
+ break;
+ }
+ }
+
+ g_value_unset (&item);
+ gst_iterator_free (pads);
+
+ if (ret)
+ GST_DEBUG_OBJECT (operation, "found unlinked ghost sink pad %s:%s",
+ GST_DEBUG_PAD_NAME (ret));
+ else
+ GST_DEBUG_OBJECT (operation, "Couldn't find an unlinked ghost sink pad");
+
+ return ret;
+
+}
+
+static GstPad *
+get_request_sink_pad (NleOperation * operation)
+{
+ GstPad *pad = NULL;
+ GList *templates;
+
+ if (!operation->element)
+ return NULL;
+
+ templates = gst_element_class_get_pad_template_list
+ (GST_ELEMENT_GET_CLASS (operation->element));
+
+ for (; templates; templates = templates->next) {
+ GstPadTemplate *templ = (GstPadTemplate *) templates->data;
+
+ GST_LOG_OBJECT (operation->element, "Trying template %s",
+ GST_PAD_TEMPLATE_NAME_TEMPLATE (templ));
+
+ if ((GST_PAD_TEMPLATE_DIRECTION (templ) == GST_PAD_SINK) &&
+ (GST_PAD_TEMPLATE_PRESENCE (templ) == GST_PAD_REQUEST)) {
+ pad =
+ gst_element_get_request_pad (operation->element,
+ GST_PAD_TEMPLATE_NAME_TEMPLATE (templ));
+ if (pad)
+ break;
+ }
+ }
+
+ return pad;
+}
+
+static GstPad *
+add_sink_pad (NleOperation * operation)
+{
+ GstPad *gpad = NULL;
+ GstPad *ret = NULL;
+
+ if (!operation->element)
+ return NULL;
+
+ /* FIXME : implement */
+ GST_LOG_OBJECT (operation, "element:%s , dynamicsinks:%d",
+ GST_ELEMENT_NAME (operation->element), operation->dynamicsinks);
+
+
+ if (!operation->dynamicsinks) {
+ /* static sink pads */
+ ret = get_unused_static_sink_pad (operation);
+ if (ret) {
+ gpad = nle_object_ghost_pad ((NleObject *) operation, GST_PAD_NAME (ret),
+ ret);
+ gst_object_unref (ret);
+ }
+ }
+
+ if (!gpad) {
+ /* request sink pads */
+ ret = get_request_sink_pad (operation);
+ if (ret) {
+ gpad = nle_object_ghost_pad ((NleObject *) operation, GST_PAD_NAME (ret),
+ ret);
+ gst_object_unref (ret);
+ }
+ }
+
+ if (gpad) {
+ operation->sinks = g_list_append (operation->sinks, gpad);
+ operation->realsinks++;
+ GST_DEBUG ("Created new pad %s:%s ghosting %s:%s",
+ GST_DEBUG_PAD_NAME (gpad), GST_DEBUG_PAD_NAME (ret));
+ } else {
+ GST_WARNING ("Couldn't find a usable sink pad!");
+ }
+
+ return gpad;
+}
+
+static gboolean
+remove_sink_pad (NleOperation * operation, GstPad * sinkpad)
+{
+ gboolean ret = TRUE;
+
+ GST_DEBUG ("sinkpad %s:%s", GST_DEBUG_PAD_NAME (sinkpad));
+
+ /*
+ We can't remove any random pad.
+ We should remove an unused pad ... which is hard to figure out in a
+ thread-safe way.
+ */
+
+ if ((sinkpad == NULL) && operation->dynamicsinks) {
+ /* Find an unlinked sinkpad */
+ if ((sinkpad = get_unlinked_sink_ghost_pad (operation)) == NULL) {
+ ret = FALSE;
+ goto beach;
+ }
+ }
+
+ if (sinkpad) {
+ GstPad *target = gst_ghost_pad_get_target ((GstGhostPad *) sinkpad);
+
+ if (target) {
+ /* release the target pad */
+ nle_object_ghost_pad_set_target ((NleObject *) operation, sinkpad, NULL);
+ if (operation->dynamicsinks)
+ gst_element_release_request_pad (operation->element, target);
+ gst_object_unref (target);
+ }
+ operation->sinks = g_list_remove (operation->sinks, sinkpad);
+ nle_object_remove_ghost_pad ((NleObject *) operation, sinkpad);
+ operation->realsinks--;
+ }
+
+beach:
+ return ret;
+}
+
+static void
+synchronize_sinks (NleOperation * operation)
+{
+
+ GST_DEBUG_OBJECT (operation, "num_sinks:%d , realsinks:%d, dynamicsinks:%d",
+ operation->num_sinks, operation->realsinks, operation->dynamicsinks);
+
+ if (operation->num_sinks == operation->realsinks)
+ return;
+
+ if (operation->num_sinks > operation->realsinks) {
+ while (operation->num_sinks > operation->realsinks) /* Add pad */
+ if (!(add_sink_pad (operation))) {
+ break;
+ }
+ } else {
+ /* Remove pad */
+ /* FIXME, which one do we remove ? :) */
+ while (operation->num_sinks < operation->realsinks)
+ if (!remove_sink_pad (operation, NULL))
+ break;
+ }
+}
+
+static gboolean
+nle_operation_prepare (NleObject * object)
+{
+ /* Prepare the pads */
+ synchronize_sinks ((NleOperation *) object);
+
+ return TRUE;
+}
+
+static gboolean
+nle_operation_cleanup (NleObject * object)
+{
+ NleOperation *oper = (NleOperation *) object;
+
+ if (oper->dynamicsinks) {
+ GST_DEBUG ("Resetting dynamic sinks");
+ nle_operation_set_sinks (oper, 0);
+ }
+
+ return TRUE;
+}
+
+void
+nle_operation_hard_cleanup (NleOperation * operation)
+{
+ gboolean done = FALSE;
+
+ GValue item = { 0, };
+ GstIterator *pads;
+
+ GST_INFO_OBJECT (operation, "Hard reset of the operation");
+
+ pads = gst_element_iterate_sink_pads (GST_ELEMENT (operation));
+ while (!done) {
+ switch (gst_iterator_next (pads, &item)) {
+ case GST_ITERATOR_OK:
+ {
+ GstPad *sinkpad = g_value_get_object (&item);
+ GstPad *srcpad = gst_pad_get_peer (sinkpad);
+
+ if (srcpad) {
+ GST_ERROR ("Unlinking %" GST_PTR_FORMAT " and %"
+ GST_PTR_FORMAT, srcpad, sinkpad);
+ gst_pad_unlink (srcpad, sinkpad);
+ }
+
+ g_value_reset (&item);
+ break;
+ }
+ case GST_ITERATOR_RESYNC:
+ gst_iterator_resync (pads);
+ break;
+ default:
+ /* ERROR and DONE */
+ done = TRUE;
+ break;
+ }
+ }
+ nle_object_cleanup (NLE_OBJECT (operation));
+}
+
+
+static GstPad *
+nle_operation_request_new_pad (GstElement * element, GstPadTemplate * templ,
+ const gchar * name, const GstCaps * caps)
+{
+ NleOperation *operation = (NleOperation *) element;
+ GstPad *ret;
+
+ GST_DEBUG ("template:%s name:%s", templ->name_template, name);
+
+ if (operation->num_sinks == operation->realsinks) {
+ GST_WARNING_OBJECT (element,
+ "We already have the maximum number of pads : %d",
+ operation->num_sinks);
+ return NULL;
+ }
+
+ ret = add_sink_pad ((NleOperation *) element);
+
+ return ret;
+}
+
+static void
+nle_operation_release_pad (GstElement * element, GstPad * pad)
+{
+ GST_DEBUG ("pad %s:%s", GST_DEBUG_PAD_NAME (pad));
+
+ remove_sink_pad ((NleOperation *) element, pad);
+}
+
+void
+nle_operation_signal_input_priority_changed (NleOperation * operation,
+ GstPad * pad, guint32 priority)
+{
+ GST_DEBUG_OBJECT (operation, "pad:%s:%s, priority:%d",
+ GST_DEBUG_PAD_NAME (pad), priority);
+ g_signal_emit (operation, nle_operation_signals[INPUT_PRIORITY_CHANGED],
+ 0, pad, priority);
+}
+
+void
+nle_operation_update_base_time (NleOperation * operation,
+ GstClockTime timestamp)
+{
+ if (!nle_object_to_media_time (NLE_OBJECT (operation),
+ timestamp, &operation->next_base_time)) {
+ GST_WARNING_OBJECT (operation, "Trying to set a basetime outside of "
+ "ourself");
+
+ return;
+ }
+
+ GST_INFO_OBJECT (operation, "Setting next_basetime to %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (operation->next_base_time));
+}