diff --git a/common b/common
diff --git a/gnl/gnlghostpad.c b/gnl/gnlghostpad.c
index 70a1044..ca69f2e 100644
--- a/gnl/gnlghostpad.c
+++ b/gnl/gnlghostpad.c
@@ -251,10 +251,15 @@ translate_outgoing_new_segment (GnlObject * object, GstEvent * event)
   if (G_UNLIKELY (nstream > G_MAXINT64))
     GST_WARNING_OBJECT (object, "Return value too big...");
 
+  if (GNL_OBJECT_LOOP_DURATION (object) > 0) {
+    stop = start + GNL_OBJECT_LOOP_DURATION (object);
+  }
+
   GST_DEBUG_OBJECT (object,
       "Sending NEWSEGMENT %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT " // %"
       GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
       GST_TIME_ARGS (nstream));
+
   event2 =
       gst_event_new_new_segment (update, rate, format, start, stop,
       (gint64) nstream);
@@ -296,10 +301,15 @@ translate_incoming_new_segment (GnlObject * object, GstEvent * event)
   if (G_UNLIKELY (nstream > G_MAXINT64))
     GST_WARNING_OBJECT (object, "Return value too big...");
 
+  if (GNL_OBJECT_LOOP_DURATION (object) > 0) {
+    stop = start + GNL_OBJECT_LOOP_DURATION (object);
+  }
+
   GST_DEBUG_OBJECT (object,
       "Sending NEWSEGMENT %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT " // %"
       GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
       GST_TIME_ARGS (nstream));
+
   event2 =
       gst_event_new_new_segment (update, rate, format, start, stop,
       (gint64) nstream);
diff --git a/gnl/gnlobject.c b/gnl/gnlobject.c
index 7c58314..88c51ca 100644
--- a/gnl/gnlobject.c
+++ b/gnl/gnlobject.c
@@ -57,7 +57,8 @@ enum
   ARG_PRIORITY,
   ARG_ACTIVE,
   ARG_CAPS,
-  ARG_EXPANDABLE
+  ARG_EXPANDABLE,
+  ARG_LOOP_DURATION
 };
 
 static void gnl_object_dispose (GObject * object);
@@ -247,6 +248,19 @@ gnl_object_class_init (GnlObjectClass * klass)
       g_param_spec_boolean ("expandable", "Expandable",
           "Expand to the full duration of the container composition", FALSE,
           G_PARAM_READWRITE));
+
+  /**
+   * GnlObject:loop-duration
+   *
+   * If non-zero, this object is looping.  If object is looping, rate will
+   * be 1 and will loop media-duration samples then silence for loop-duration.
+   * Object will continue to play from media-start to media-end for the object's
+   * duration.
+   */
+  g_object_class_install_property (gobject_class, ARG_LOOP_DURATION,
+      g_param_spec_uint64 ("loop-duration", "Loop duration",
+          "Length of one loop (in nanoseconds)", 0, G_MAXUINT64, 0,
+          G_PARAM_READWRITE));
 }
 
 static void
@@ -264,6 +278,7 @@ gnl_object_init (GnlObject * object, GnlObjectClass * klass)
   object->rate_1 = TRUE;
   object->priority = 0;
   object->active = TRUE;
+  object->loop_duration = 0;
 
   object->caps = gst_caps_new_any ();
 
@@ -471,8 +486,12 @@ update_values (GnlObject * object)
   }
 
   /* check if media start/duration has changed */
-  if ((object->media_start != GST_CLOCK_TIME_NONE)
-      && ((object->media_start + object->media_duration) != object->media_stop)) {
+  if (((object->media_start != GST_CLOCK_TIME_NONE)
+          && ((object->media_start + object->media_duration) !=
+              object->media_stop))
+      || (object->loop_duration > 0
+          && ((object->media_start + object->media_duration) !=
+              object->media_start))) {
     object->media_stop = object->media_start + object->media_duration;
     GST_LOG_OBJECT (object,
         "Updated media_stop value : %" GST_TIME_FORMAT
@@ -484,15 +503,26 @@ update_values (GnlObject * object)
   }
 
   /* check if rate has changed */
-  if ((object->media_duration != GST_CLOCK_TIME_NONE)
-      && (object->duration)
-      && (object->media_duration)
-      && (((gdouble) object->media_duration / (gdouble) object->duration) !=
-          object->rate)) {
-    object->rate =
-        (gdouble) object->media_duration / (gdouble) object->duration;
+  if (((object->media_duration != GST_CLOCK_TIME_NONE)
+          && (object->duration)
+          && (object->media_duration)
+          && (((gdouble) object->media_duration / (gdouble) object->duration) !=
+              object->rate))
+      || (object->loop_duration > 0 && object->rate != 1)) {
+    if (object->loop_duration == 0) {
+      object->rate =
+          (gdouble) object->media_duration / (gdouble) object->duration;
+    } else {
+      object->rate = 1;
+    }
+
     /* update the speedup rate_1 variable */
-    object->rate_1 = (object->media_duration == object->duration);
+    if (!object->loop_duration == 0) {
+      object->rate_1 = (object->media_duration == object->duration);
+    } else {
+      object->rate_1 = TRUE;
+    }
+
     GST_LOG_OBJECT (object,
         "Updated rate : %f [mduration:%" GST_TIME_FORMAT ", duration:%"
         GST_TIME_FORMAT "] rate_1:%d", object->rate,
@@ -541,6 +571,10 @@ gnl_object_set_property (GObject * object, guint prop_id,
       else
         GST_OBJECT_FLAG_UNSET (gnlobject, GNL_OBJECT_EXPANDABLE);
       break;
+    case ARG_LOOP_DURATION:
+      gnlobject->loop_duration = g_value_get_uint64 (value);
+      update_values (gnlobject);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -587,6 +621,9 @@ gnl_object_get_property (GObject * object, guint prop_id,
     case ARG_EXPANDABLE:
       g_value_set_boolean (value, GNL_OBJECT_IS_EXPANDABLE (object));
       break;
+    case ARG_LOOP_DURATION:
+      g_value_set_uint64 (value, gnlobject->loop_duration);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
diff --git a/gnl/gnlobject.h b/gnl/gnlobject.h
index 568b973..d1014e0 100644
--- a/gnl/gnlobject.h
+++ b/gnl/gnlobject.h
@@ -76,6 +76,7 @@ typedef enum
 #define GNL_OBJECT_MEDIA_STOP(obj) (GNL_OBJECT_CAST (obj)->media_stop)
 #define GNL_OBJECT_MEDIA_DURATION(obj) (GNL_OBJECT_CAST (obj)->media_duration)
 #define GNL_OBJECT_PRIORITY(obj) (GNL_OBJECT_CAST (obj)->priority)
+#define GNL_OBJECT_LOOP_DURATION(obj) (GNL_OBJECT_CAST(obj)->loop_duration)
 
 struct _GnlObject
 {
@@ -99,6 +100,8 @@ struct _GnlObject
   /* TRUE if rate == 1.0 */
   gboolean rate_1;
 
+  GstClockTime loop_duration;
+
   /* priority in parent */
   guint32 priority;
 
diff --git a/gnl/gnlsource.c b/gnl/gnlsource.c
index cec125a..ab602d8 100644
--- a/gnl/gnlsource.c
+++ b/gnl/gnlsource.c
@@ -24,7 +24,7 @@
 #endif
 
 #include "gnl.h"
-
+#include "glib.h"
 /**
  * SECTION:element-gnlsource
  * @short_description: GNonLin Source
@@ -59,6 +59,13 @@ struct _GnlSourcePrivate
   gboolean areblocked;          /* We already got blocked */
   GstPad *ghostedpad;           /* Pad (to be) ghosted */
   GstPad *staticpad;            /* The only pad. We keep an extra ref */
+
+  guint loop_probe;
+  GThread *loop_thread;         /* thread that sends the seek for looping */
+  GCond *loop_condition;        /* condition variable for setting loop_seek_event */
+  GMutex *loop_mutex;           /* mutex for use with loop_condition */
+  gboolean loop_event_waiting;  /* TRUE if there is an event ready for seeking for looping */
+  GstEvent *loop_seek_event;    /* The event used for seeking while looping */
 };
 
 static gboolean gnl_source_prepare (GnlObject * object);
@@ -79,6 +86,11 @@ static void pad_blocked_cb (GstPad * pad, gboolean blocked, GnlSource * source);
 static gboolean
 gnl_source_control_element_func (GnlSource * source, GstElement * element);
 
+static gboolean
+looping_eos_handler (GstPad * ghostpad, GstEvent * event, GnlSource * source);
+
+static void *loop_seek_thread (void *param);
+
 static void
 gnl_source_base_init (gpointer g_class)
 {
@@ -134,8 +146,11 @@ gnl_source_init (GnlSource * source, GnlSourceClass * klass G_GNUC_UNUSED)
 {
   GST_OBJECT_FLAG_SET (source, GNL_OBJECT_SOURCE);
   source->element = NULL;
+  source->loop_progress = 0;
   source->priv =
       G_TYPE_INSTANCE_GET_PRIVATE (source, GNL_TYPE_SOURCE, GnlSourcePrivate);
+  source->priv->loop_condition = g_cond_new ();
+  source->priv->loop_mutex = g_mutex_new ();
 
   GST_DEBUG_OBJECT (source, "Setting GstBin async-handling to TRUE");
   g_object_set (G_OBJECT (source), "async-handling", TRUE, NULL);
@@ -157,6 +172,16 @@ gnl_source_dispose (GObject * object)
   }
 
   source->priv->dispose_has_run = TRUE;
+
+  if (source->priv->loop_thread != 0) {
+    GST_LOG_OBJECT (source, "shutting down the seek thread");
+
+    g_cond_broadcast (source->priv->loop_condition);
+    g_thread_join (source->priv->loop_thread);
+  }
+  g_cond_free (source->priv->loop_condition);
+  g_mutex_free (source->priv->loop_mutex);
+
   if (source->priv->event)
     gst_event_unref (source->priv->event);
 
@@ -226,6 +251,14 @@ element_pad_added_cb (GstElement * element G_GNUC_UNUSED, GstPad * pad,
   else {
     source->priv->ghostedpad = pad;
     source->priv->pendingblock = TRUE;
+    if (GNL_OBJECT_LOOP_DURATION (source) > 0) {
+      GST_LOG_OBJECT (source, "Looping, setting up event probe and thread");
+      source->priv->loop_probe =
+          gst_pad_add_event_probe (pad, G_CALLBACK (looping_eos_handler),
+          source);
+      source->priv->loop_thread =
+          g_thread_create (loop_seek_thread, source, TRUE, NULL);
+    }
   }
 
   GST_DEBUG_OBJECT (source, "Done handling pad %s:%s",
@@ -467,6 +500,11 @@ gnl_source_remove_element (GstBin * bin, GstElement * element)
       source->priv->event = NULL;
     }
 
+    if (source->priv->loop_seek_event) {
+      gst_event_unref (source->priv->loop_seek_event);
+      source->priv->loop_seek_event = NULL;
+    }
+
     /* remove signal handlers */
     if (source->priv->padremovedid) {
       g_signal_handler_disconnect (source->element, source->priv->padremovedid);
@@ -585,3 +623,72 @@ gnl_source_change_state (GstElement * element, GstStateChange transition)
 beach:
   return ret;
 }
+
+static gboolean
+looping_eos_handler (GstPad * ghostedpad G_GNUC_UNUSED, GstEvent * event,
+    GnlSource * source)
+{
+  gboolean keepit = TRUE;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_EOS:
+    {
+      GnlObject *object = GNL_OBJECT (source);
+      GST_LOG_OBJECT (source, "Received EOS");
+      source->loop_progress += GNL_OBJECT_LOOP_DURATION (object);
+      keepit = GNL_OBJECT_DURATION (object) > 0
+          && source->loop_progress >= GNL_OBJECT_DURATION (object);
+      if (!keepit) {
+        GstEvent *event = gst_event_new_seek (1.0, GST_FORMAT_TIME,
+            GST_SEEK_FLAG_ACCURATE,
+            GST_SEEK_TYPE_SET, GNL_OBJECT_MEDIA_START (object),
+            GST_SEEK_TYPE_SET,
+            GNL_OBJECT_MEDIA_STOP (object));
+        g_mutex_lock (source->priv->loop_mutex);
+        source->priv->loop_seek_event = event;
+        source->priv->loop_event_waiting = TRUE;
+        g_mutex_unlock (source->priv->loop_mutex);
+        GST_LOG_OBJECT (source, "broadcasting new event");
+        g_cond_broadcast (source->priv->loop_condition);
+      } else {
+        GST_LOG_OBJECT (source, "sending EOS");
+      }
+    }
+      break;
+    default:
+      break;
+  }
+  return keepit;
+}
+
+static void *
+loop_seek_thread (void *param)
+{
+  GnlSource *source = (GnlSource *) param;
+  GstEvent *event;
+  GST_DEBUG_OBJECT (source, "starting loop_seek_thread");
+  g_mutex_lock (source->priv->loop_mutex);
+  while (!source->priv->dispose_has_run) {
+    GST_LOG_OBJECT (source, "loop_seek_thread waking up");
+    if (source->priv->loop_event_waiting) {
+      event = source->priv->loop_seek_event;
+      source->priv->loop_seek_event = NULL;
+      source->priv->loop_event_waiting = FALSE;
+      g_mutex_unlock (source->priv->loop_mutex);
+
+      GST_LOG_OBJECT (source, "We have a loop event");
+      if (!(gst_pad_send_event (source->priv->ghostedpad, event))) {
+        GST_ELEMENT_ERROR (source, RESOURCE, SEEK, (NULL),
+            ("Sending seek in loop_seek_thread failed"));
+      }
+      g_mutex_lock (source->priv->loop_mutex);
+    }
+    GST_LOG_OBJECT (source, "Waiting for condition variable");
+    g_cond_wait (source->priv->loop_condition, source->priv->loop_mutex);
+  }
+
+  g_mutex_unlock (source->priv->loop_mutex);
+  GST_DEBUG_OBJECT (source, "loop_seek_thread ending");
+
+  return NULL;
+}
diff --git a/gnl/gnlsource.h b/gnl/gnlsource.h
index 0f857bd..0c1d430 100644
--- a/gnl/gnlsource.h
+++ b/gnl/gnlsource.h
@@ -32,6 +32,7 @@ G_BEGIN_DECLS
   (gnl_source_get_type())
 #define GNL_SOURCE(obj) \
   (G_TYPE_CHECK_INSTANCE_CAST((obj),GNL_TYPE_SOURCE,GnlSource))
+#define GNL_SOURCE_CAST(obj) ((GnlSource*) (obj))
 #define GNL_SOURCE_CLASS(klass) \
   (G_TYPE_CHECK_CLASS_CAST((klass),GNL_TYPE_SOURCE,GnlSourceClass))
 #define GNL_SOURCE_GET_CLASS(obj) \
@@ -48,6 +49,7 @@ struct _GnlSource
 
   /* controlled source element, acces with gst_bin_[add|remove]_element */
   GstElement *element;
+  GstClockTime loop_progress;
 
   GnlSourcePrivate *priv;
 };
