Index: libs/gst/base/gstbaseparse.c
===================================================================
--- libs/gst/base/gstbaseparse.c	(revision 6885)
+++ libs/gst/base/gstbaseparse.c	(revision 7044)
@@ -244,7 +244,7 @@
 static void gst_base_parse_loop (GstPad * pad);
 
 static gboolean gst_base_parse_check_frame (GstBaseParse *parse,
-    GstBuffer *buffer, guint *framesize, guint *skipsize);
+    GstBuffer *buffer, guint *framesize, gint *skipsize);
 
 static gboolean gst_base_parse_parse_frame (GstBaseParse *parse,
     GstBuffer *buffer);
@@ -255,7 +255,10 @@
 static gboolean gst_base_parse_src_eventfunc (GstBaseParse * parse,
     GstEvent * event);
 
+static gboolean gst_base_parse_is_seekable (GstBaseParse * parse);
 
+static void gst_base_parse_drain (GstBaseParse *parse);
+
 static void
 gst_base_parse_base_init (gpointer g_class)
 {
@@ -303,6 +306,7 @@
   klass->parse_frame = gst_base_parse_parse_frame;
   klass->event = gst_base_parse_sink_eventfunc;
   klass->src_event = gst_base_parse_src_eventfunc;
+  klass->is_seekable = gst_base_parse_is_seekable;
 }
 
 static void
@@ -368,8 +372,9 @@
  * gst_base_parse_check_frame:
  * @parse: #GstBaseParse.
  * @buffer: GstBuffer.
- * @framesize:
- * @skipsize:
+ * @framesize: This will be set to tell the found frame size in bytes.
+ * @skipsize: Output parameter that tells how much data needs to be skipped
+ *            in order to find the following frame header.
  *
  * Default callback for check_valid_frame.
  * 
@@ -379,7 +384,7 @@
 gst_base_parse_check_frame (GstBaseParse *parse,
                             GstBuffer *buffer,
                             guint *framesize,
-                            guint *skipsize)
+                            gint *skipsize)
 {
   *framesize = GST_BUFFER_SIZE (buffer);
   *skipsize = 0;
@@ -389,9 +394,10 @@
 
 /**
  * gst_base_parse_parse_frame:
- * @parse: #GstBaseParse
- * @buffer: #GstBuffer
+ * @parse: #GstBaseParse.
+ * @buffer: #GstBuffer.
  *
+ * Default callback for parse_frame.
  */
 static gboolean
 gst_base_parse_parse_frame (GstBaseParse *parse, GstBuffer *buffer)
@@ -433,8 +439,8 @@
 
 /**
  * gst_base_parse_sink_event:
- * @pad: #GstPad.
- * @event: #GstEvent.
+ * @pad: #GstPad that received the event.
+ * @event: #GstEvent to be handled.
  *
  * Handler for sink pad events.
  *
@@ -480,8 +486,10 @@
 /**
  * gst_base_parse_sink_eventfunc:
  * @parse: #GstBaseParse.
- * @event: #GstEvent.
+ * @event: #GstEvent to be handled.
  *
+ * Element-level event handler function.
+ *
  * Returns: TRUE if the event was handled and not need forwarding.
  */
 static gboolean
@@ -567,6 +575,10 @@
       parse->priv->discont = TRUE;
       break;
 
+    case GST_EVENT_EOS:
+      gst_base_parse_drain (parse);
+      break;
+
     default:
       break;
   }
@@ -577,8 +589,8 @@
 
 /**
  * gst_base_parse_src_event:
- * @pad: #GstPad.
- * @event: #GstEvent.
+ * @pad: #GstPad that received the event.
+ * @event: #GstEvent that was received.
  *
  * Handler for source pad events.
  *
@@ -612,20 +624,27 @@
 /**
  * gst_base_parse_src_eventfunc:
  * @parse: #GstBaseParse.
- * @event: #GstEvent
+ * @event: #GstEvent that was received.
  *
+ * Default srcpad event handler.
+ *
  * Returns: TRUE if the event was handled and can be dropped.
  */
 static gboolean
 gst_base_parse_src_eventfunc (GstBaseParse * parse, GstEvent * event)
 {
   gboolean handled = FALSE;
+  GstBaseParseClass *bclass;
 
+  bclass = GST_BASE_PARSE_GET_CLASS (parse);
+
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_SEEK:
     {
-      handled = gst_base_parse_handle_seek (parse, event);
-      gst_event_unref (event);
+      if (bclass->is_seekable (parse)) {
+        handled = gst_base_parse_handle_seek (parse, event);
+        gst_event_unref (event);
+      }
       break;
     }
     default:
@@ -636,11 +655,31 @@
 
 
 /**
+ * gst_base_parse_is_seekable:
+ * @parse: #GstBaseParse.
+ *
+ * Default handler for is_seekable.
+ *
+ * Returns: Always TRUE.
+ */
+static gboolean
+gst_base_parse_is_seekable (GstBaseParse * parse)
+{
+  return TRUE;
+}
+
+
+/**
  * gst_base_parse_handle_and_push_buffer:
  * @parse: #GstBaseParse.
  * @klass: #GstBaseParseClass.
  * @buffer: #GstBuffer.
  *
+ * Parses the frame from given buffer and pushes it forward. Also performs
+ * timestamp handling and checks the segment limits.
+ *
+ * This is called with srcpad STREAM_LOCK held.
+ *
  * Returns: #GstFlowReturn
  */
 static GstFlowReturn
@@ -677,20 +716,20 @@
         GST_BUFFER_DURATION_IS_VALID (buffer) &&
         GST_CLOCK_TIME_IS_VALID (parse->segment.start) &&
         GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION_IS_VALID (buffer)
-	  < parse->segment.start) {
+            < parse->segment.start) {
       /* FIXME: subclass needs way to override the start as downstream might
        * need frames before for proper decoding */
       GST_LOG ("Dropped frame, before segment");
       gst_buffer_unref (buffer);
     } else {
       ret = gst_pad_push (parse->srcpad, buffer);
-      GST_LOG ("frame pushed: %d", ret);
+      GST_LOG ("frame (%d bytes) pushed: %d", GST_BUFFER_SIZE (buffer), ret);
     }
   }
   else {
     gst_buffer_unref (buffer);
   }
-  
+
   /* Update current running segment position */
   if (ret == GST_FLOW_OK)
     gst_segment_set_last_stop (&parse->segment, GST_FORMAT_TIME,
@@ -706,6 +745,31 @@
 
 
 /**
+ * gst_base_parse_drain:
+ * @parse: #GstBaseParse.
+ *
+ * Drains the adapter until it is empty. It decreases the min_frame_size to
+ * match the current adapter size and calls chain method until the adapter
+ * is emptied or chain returns with error.
+ */
+static void
+gst_base_parse_drain (GstBaseParse *parse)
+{
+  guint avail;
+
+  for (;;) {
+    avail = gst_adapter_available (parse->adapter);
+    if (!avail) break;
+
+    gst_base_parse_set_min_frame_size (parse, avail);
+    if (gst_base_parse_chain (parse->sinkpad, NULL) != GST_FLOW_OK) {
+      break;
+    }
+  }
+}
+
+
+/**
  * gst_base_parse_chain:
  * @pad: #GstPad.
  * @buffer: #GstBuffer.
@@ -720,17 +784,14 @@
   GstFlowReturn ret = GST_FLOW_OK;
   GstBuffer *outbuf = NULL;
   GstBuffer *tmpbuf = NULL;
-  guint fsize = 0, skip = 0;
+  guint fsize = 0;
+  gint skip = -1;
   const guint8 *data;
   guint min_size;
 
   parse = GST_BASE_PARSE (GST_OBJECT_PARENT (pad));
   bclass = GST_BASE_PARSE_GET_CLASS (parse);
 
-  GST_LOG ("buffer size: %d, offset = %lld",
-           GST_BUFFER_SIZE(buffer), GST_BUFFER_OFFSET (buffer));
-
-
   if (parse->pending_segment) {
     GST_DEBUG ("chain pushing a pending segment");
     gst_pad_push_event (parse->srcpad, parse->pending_segment);
@@ -757,8 +818,14 @@
     parse->priv->pending_events = NULL;
   }
 
-  gst_adapter_push (parse->adapter, buffer);
+  if (buffer) {
+    GST_LOG ("buffer size: %d, offset = %lld",
+            GST_BUFFER_SIZE(buffer), GST_BUFFER_OFFSET (buffer));
 
+
+    gst_adapter_push (parse->adapter, buffer);
+  }
+
   /* Parse and push as many frames as possible */
   /* Stop either when adapter is empty or we are flushing */
   while (!parse->priv->flushing) {
@@ -775,7 +842,7 @@
       {
         GST_DEBUG ("not enough data available (only %d bytes)",
                    gst_adapter_available (parse->adapter));
-	gst_buffer_unref (tmpbuf);
+        gst_buffer_unref (tmpbuf);
         goto done;
       }
 
@@ -785,24 +852,35 @@
       GST_BUFFER_OFFSET (tmpbuf) = parse->priv->offset;
       GST_BUFFER_FLAG_SET (tmpbuf, GST_MINI_OBJECT_FLAG_READONLY);
 
-      skip = 0;
+      if (parse->priv->discont) {
+        GST_DEBUG_OBJECT (parse, "marking DISCONT");
+        GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
+      }
+
+      skip = -1;
       if (bclass->check_valid_frame (parse, tmpbuf, &fsize, &skip)) {
         break;
       }
-      if (skip) {
+      if (skip > 0) {
         GST_LOG ("finding sync, skipping %d bytes", skip);
         gst_adapter_flush (parse->adapter, skip);
         parse->priv->offset += skip;
-      } else {
+      }
+      else if (skip == -1) {
+        /* subclass didn't touch this value. By default we skip 1 byte */
         GST_LOG ("finding sync, skipping 1 byte");
         gst_adapter_flush (parse->adapter, 1);
         parse->priv->offset++;
       }
+      /* There is a possibility that subclass set the skip value to zero.
+         This means that it has probably found a frame but wants to ask
+         more data (by increasing the min_size) to be sure of this. */
     }
     gst_buffer_unref (tmpbuf);
     tmpbuf = NULL;
 
-    if (skip) {
+    if (skip > 0) {
+      /* Subclass found the sync, but still wants to skip some data */
       GST_LOG ("skipping %d bytes", skip);
       gst_adapter_flush (parse->adapter, skip);
       parse->priv->offset += skip;
@@ -840,11 +918,11 @@
 }
 
 
-
 /**
  * gst_base_parse_loop:
  * @pad: GstPad
  *
+ * Loop that is used in pull mode to retrieve data from upstream.
  */
 static void
 gst_base_parse_loop (GstPad * pad)
@@ -853,7 +931,8 @@
   GstBaseParseClass *klass;
   GstBuffer *buffer, *outbuf;
   gboolean ret = FALSE;
-  guint fsize = 0, skip = 0, min_size;
+  guint fsize = 0, min_size;
+  gint skip = 0;
 
   parse = GST_BASE_PARSE (gst_pad_get_parent (pad));
   klass = GST_BASE_PARSE_GET_CLASS (parse);
@@ -870,13 +949,16 @@
     parse->pending_segment = NULL;
   }
 
-  GST_BASE_PARSE_LOCK (parse);
-  min_size = parse->priv->min_frame_size;
-  GST_BASE_PARSE_UNLOCK (parse);
-
   /* TODO: Check if we reach segment stop limit */
 
   while (TRUE) {
+
+    GST_BASE_PARSE_LOCK (parse);
+    min_size = parse->priv->min_frame_size;
+    GST_BASE_PARSE_UNLOCK (parse);
+
+    /* TODO:  Pull large chunk and consume it instead of performing
+              a lot of small pulls */
     ret = gst_pad_pull_range (parse->sinkpad, parse->priv->offset,
                               min_size, &buffer);
 
@@ -886,19 +968,27 @@
       goto need_pause;
 
     /* EOS */
+
+    /* FIXME: Do we still need to feed the buffer to subclass? */
     if (GST_BUFFER_SIZE (buffer) < min_size) {
       gst_buffer_unref (buffer);
       goto eos;
     }
 
-    skip = 0;
+    if (parse->priv->discont) {
+      GST_DEBUG_OBJECT (parse, "marking DISCONT");
+      GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
+    }
+
+    skip = -1;
     if (klass->check_valid_frame (parse, buffer, &fsize, &skip)) {
       break;
     }
-    if (skip) {
+    if (skip > 0) {
       GST_LOG ("finding sync, skipping %d bytes", skip);
       parse->priv->offset += skip;
-    } else {
+    }
+    else if (skip == -1) {
       GST_LOG ("finding sync, skipping 1 byte");
       parse->priv->offset++;
     }
@@ -914,8 +1004,11 @@
     outbuf = buffer;
   }
 
-  parse->priv->offset += fsize + skip;
+  parse->priv->offset += fsize;
 
+  /* Does the subclass want to skip too? */
+  if (skip > 0) parse->priv->offset += skip;
+
   /* This always unrefs the outbuf, even if error occurs */
   ret = gst_base_parse_handle_and_push_buffer (parse, klass, outbuf);
 
@@ -1032,10 +1125,10 @@
 
 /**
  * gst_base_parse_sink_activate_push:
- * @pad: #GstPad.
- * @active:
+ * @pad: #GstPad to be (de)activated.
+ * @active: TRUE when activating, FALSE when deactivating.
  *
- * Returns: TRUE if activation succeeded.
+ * Returns: TRUE if (de)activation succeeded.
  */
 static gboolean
 gst_base_parse_sink_activate_push (GstPad * pad, gboolean active)
@@ -1060,10 +1153,10 @@
 
 /**
  * gst_base_parse_sink_activate_pull:
- * @sinkpad: #GstPad to be activated.
- * @active:
+ * @sinkpad: #GstPad to be (de)activated.
+ * @active: TRUE when activating, FALSE when deactivating.
  *
- * Returns: TRUE if activation succeeded.
+ * Returns: TRUE if (de)activation succeeded.
  */
 static gboolean
 gst_base_parse_sink_activate_pull (GstPad * sinkpad, gboolean active)
@@ -1102,7 +1195,8 @@
  * @fmt: #GstFormat.
  * @duration: duration value.
  *
- * Sets the duration of the currently playing media.
+ * Sets the duration of the currently playing media. Subclass can use this
+ * when it notices a change in the media duration.
  */
 void gst_base_parse_set_duration (GstBaseParse *parse,
                                   GstFormat fmt,
@@ -1116,7 +1210,7 @@
 
     m = gst_message_new_duration (GST_OBJECT (parse), fmt, duration);
     gst_element_post_message (GST_ELEMENT (parse), m);
-    
+
     /* TODO: what about duration tag? */
   }
   parse->priv->duration = duration;
@@ -1141,7 +1235,7 @@
 
   GST_BASE_PARSE_LOCK (parse);
   parse->priv->min_frame_size = min_size;
-  GST_DEBUG_OBJECT (parse, "set frame_min_size: %d", min_size);
+  GST_LOG_OBJECT (parse, "set frame_min_size: %d", min_size);
   GST_BASE_PARSE_UNLOCK (parse);
 }
 
@@ -1202,10 +1296,16 @@
       gst_query_parse_position (query, &format, NULL);
 
       g_mutex_lock (parse->parse_lock);
-      if (format == parse->segment.format &&
-          GST_CLOCK_TIME_IS_VALID (parse->segment.last_stop)) {
+
+      if (format == GST_FORMAT_BYTES) {
+        dest_value = parse->priv->offset;
+        res = TRUE;
+      }
+      else if (format == parse->segment.format &&
+          GST_CLOCK_TIME_IS_VALID (parse->segment.last_stop))
+      {
         dest_value = parse->segment.last_stop;
-	res = TRUE;
+        res = TRUE;
       } else {
         /* priv->offset is updated in both PUSH/PULL modes */
         res = klass->convert (parse, GST_FORMAT_BYTES, parse->priv->offset,
@@ -1230,17 +1330,22 @@
       gst_query_parse_duration (query, &format, NULL);
 
       g_mutex_lock (parse->parse_lock);
-      if (parse->priv->duration != -1 &&
+
+      if (format == GST_FORMAT_BYTES) {
+        res = gst_pad_query_peer_duration (parse->sinkpad, &format,
+                                           &dest_value);
+      }
+      else if (parse->priv->duration != -1 &&
           format == parse->priv->duration_fmt)
       {
         dest_value = parse->priv->duration;
-        g_mutex_unlock (parse->parse_lock);
         res = TRUE;
       } else if (parse->priv->duration != -1) {
-        res = klass->convert (parse, parse->priv->duration_fmt, parse->priv->duration,
+        res = klass->convert (parse, parse->priv->duration_fmt,
+                              parse->priv->duration,
                               format, &dest_value);
       }
-      
+
       g_mutex_unlock (parse->parse_lock);
 
       if (res)
@@ -1252,6 +1357,7 @@
     case GST_QUERY_SEEKING:
     {
       GstFormat fmt;
+      gboolean seekable = FALSE;
 
       GST_DEBUG ("seeking query");
 
@@ -1262,9 +1368,15 @@
         return gst_pad_query_default (pad, query);
       }
 
-      gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
+      seekable = klass->is_seekable (parse);
+
+      /* TODO: could this duration be calculated/converted if subclass
+               hasn't given it? */
+      gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
                              (parse->priv->duration == -1) ?
                                  GST_CLOCK_TIME_NONE : parse->priv->duration);
+
+      GST_DEBUG_OBJECT (query, "seekable: %d", seekable);
       res = TRUE;
       break;
     }
Index: libs/gst/base/gstbaseparse.h
===================================================================
--- libs/gst/base/gstbaseparse.h	(revision 6885)
+++ libs/gst/base/gstbaseparse.h	(revision 7044)
@@ -54,7 +54,7 @@
  *
  * Gives the pointer to the source #GstPad object of the element.
  *
- * Since: 0.10.17
+ * Since: 0.10.x
  */
 #define GST_BASE_PARSE_SRC_PAD(obj)		(GST_BASE_PARSE_CAST (obj)->srcpad)
 
@@ -64,7 +64,7 @@
  *
  * Gives the pointer to the sink #GstPad object of the element.
  *
- * Since: 0.10.17
+ * Since: 0.10.x
  */
 #define GST_BASE_PARSE_SINK_PAD(obj)	(GST_BASE_PARSE_CAST (obj)->sinkpad)
 
@@ -74,7 +74,7 @@
  * A #GstFlowReturn that can be returned from parse_frame to
  * indicate that no output buffer was generated.
  *
- * Since: 0.10.17
+ * Since: 0.10.x
  */
 #define GST_BASE_PARSE_FLOW_DROPPED   GST_FLOW_CUSTOM_SUCCESS
 
@@ -84,7 +84,7 @@
  *
  * Obtain a lock to protect the parse function from concurrent access.
  *
- * Since: 0.10.17
+ * Since: 0.10.x
  */
 #define GST_BASE_PARSE_LOCK(obj)   g_mutex_lock (GST_BASE_PARSE_CAST (obj)->parse_lock)
 
@@ -94,7 +94,7 @@
  *
  * Release the lock that protects the parse function from concurrent access.
  *
- * Since: 0.10.17
+ * Since: 0.10.x
  */
 #define GST_BASE_PARSE_UNLOCK(obj) g_mutex_unlock (GST_BASE_PARSE_CAST (obj)->parse_lock)
 
@@ -149,7 +149,8 @@
  *                      frame.
  * @parse_frame:    Parse the already checked frame. Subclass need to
  *                  set the buffer timestamp, duration, caps and possibly
- *                  other necessary metadata.
+ *                  other necessary metadata. This is called with srcpad's
+ *                  STREAM_LOCK held.
  * @convert:        Optional.
  *                  Convert between formats.
  * @find_frame:     Optional.
@@ -166,6 +167,10 @@
  * @src_event:      Optional.
  *                  Event handler on the source pad. Should return TRUE
  *                  if the event was handled and can be dropped.
+ * @is_seekable:    Optional.
+ *                  Subclass can override this if it wants to control the
+ *                  seekability of the stream. Otherwise the element assumes
+ *                  that stream is always seekable.
  *
  * Subclasses can override any of the available virtual methods or not, as
  * needed. At minimum @check_valid_frame and @parse_frame needs to be
@@ -187,7 +192,7 @@
   gboolean      (*check_valid_frame)  (GstBaseParse *parse,
                                        GstBuffer *buffer,
                                        guint *framesize,
-                                       guint *skipsize);
+                                       gint *skipsize);
 
   GstFlowReturn (*parse_frame)        (GstBaseParse *parse,
                                        GstBuffer *buffer);
@@ -209,6 +214,8 @@
   gboolean      (*src_event)          (GstBaseParse *parse,
                                        GstEvent *event);
 
+  gboolean      (*is_seekable)        (GstBaseParse *parse);
+
 };
 
 GType           gst_base_parse_get_type         (void);
