Index: trunk/gst-libraries/gstreamer/0.10.17/libs/gst/base/gstbaseparse.c
===================================================================
--- trunk/gst-libraries/gstreamer/0.10.17/libs/gst/base/gstbaseparse.c (revision 6885)
+++ trunk/gst-libraries/gstreamer/0.10.17/libs/gst/base/gstbaseparse.c (revision 6950)
@@ -253,10 +253,13 @@
     GstEvent * event);
 
 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)
 {
   GST_DEBUG_CATEGORY_INIT (gst_base_parse_debug, "baseparse", 0,
@@ -301,10 +304,11 @@
   /* Default handlers */
   klass->check_valid_frame = gst_base_parse_check_frame;
   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
 gst_base_parse_init (GstBaseParse * parse,
     GstBaseParseClass * bclass)
@@ -565,10 +569,14 @@
       gst_adapter_clear (parse->adapter);
       parse->priv->flushing = FALSE;
       parse->priv->discont = TRUE;
       break;
 
+    case GST_EVENT_EOS:
+      gst_base_parse_drain (parse);
+      break;
+
     default:
       break;
   }
 
   return handled;
@@ -618,31 +626,51 @@
  */
 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:
       break;
   }
   return handled;
+}
+
+
+/**
+ * gst_base_parse_is_seekable:
+ * @parse: #GstBaseParse.
+ *
+ * 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.
  *
+ * This is called with srcpad STREAM_LOCK held.
+ * 
  * Returns: #GstFlowReturn
  */
 static GstFlowReturn
 gst_base_parse_handle_and_push_buffer (GstBaseParse *parse,
                                        GstBaseParseClass *klass,
@@ -675,24 +703,24 @@
       gst_buffer_unref (buffer);
     } else if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) && 
         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,
                              last_stop);
 
@@ -700,10 +728,33 @@
   if (ret == GST_BASE_PARSE_FLOW_DROPPED) {
     parse->priv->discont = TRUE;
     ret = GST_FLOW_OK;
   }
   return ret;
+}
+
+
+/**
+ * gst_base_parse_drain:
+ * @parse: #GstBaseParse.
+ *
+ * Drains the adapter until it is empty.
+ */
+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:
@@ -725,14 +776,10 @@
   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);
     parse->pending_segment = NULL;
     parse->priv->offset = parse->priv->pending_offset;
@@ -755,11 +802,17 @@
     }
     g_list_free (parse->priv->pending_events);
     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) {
     tmpbuf = gst_buffer_new ();
@@ -773,11 +826,11 @@
       /* Collect at least min_frame_size bytes */
       if (gst_adapter_available (parse->adapter) < min_size)
       {
         GST_DEBUG ("not enough data available (only %d bytes)",
                    gst_adapter_available (parse->adapter));
-	gst_buffer_unref (tmpbuf);
+        gst_buffer_unref (tmpbuf);
         goto done;
       }
 
       data = gst_adapter_peek (parse->adapter, min_size);
       GST_BUFFER_DATA (tmpbuf) = (guint8 *) data;
@@ -1114,11 +1167,11 @@
   if (duration != parse->priv->duration) {
     GstMessage *m;
 
     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;
   parse->priv->duration_fmt = fmt;
   GST_DEBUG_OBJECT (parse, "set duration: %lld", duration);
@@ -1139,11 +1192,11 @@
 {
   g_return_if_fail (parse != NULL);
 
   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);
 }
 
 
 /**
@@ -1200,14 +1253,20 @@
       GST_DEBUG ("position query");
 
       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,
                               format, &dest_value);
       }
@@ -1228,21 +1287,26 @@
       GST_DEBUG ("duration query");
 
       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)
         gst_query_set_duration (query, format, dest_value);
       else
@@ -1250,23 +1314,30 @@
       break;
     }
     case GST_QUERY_SEEKING:
     {
       GstFormat fmt;
+      gboolean seekable = FALSE;
 
       GST_DEBUG ("seeking query");
 
       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
 
       if (fmt != GST_FORMAT_TIME)
       {
         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;
     }
     case GST_QUERY_FORMATS:
       gst_query_set_formatsv (query, 3, fmtlist);
Index: trunk/gst-libraries/gstreamer/0.10.17/libs/gst/base/gstbaseparse.h
===================================================================
--- trunk/gst-libraries/gstreamer/0.10.17/libs/gst/base/gstbaseparse.h (revision 6858)
+++ trunk/gst-libraries/gstreamer/0.10.17/libs/gst/base/gstbaseparse.h (revision 6950)
@@ -52,51 +52,51 @@
  * GST_BASE_PARSE_SRC_PAD:
  * @obj: base parse instance
  *
  * Gives the pointer to the source #GstPad object of the element.
  *
- * Since: 0.10.17
+ * Since: 0.10.18
  */
 #define GST_BASE_PARSE_SRC_PAD(obj)		(GST_BASE_PARSE_CAST (obj)->srcpad)
 
 /**
  * GST_BASE_PARSE_SINK_PAD:
  * @obj: base parse instance
  *
  * Gives the pointer to the sink #GstPad object of the element.
  *
- * Since: 0.10.17
+ * Since: 0.10.18
  */
 #define GST_BASE_PARSE_SINK_PAD(obj)	(GST_BASE_PARSE_CAST (obj)->sinkpad)
 
 /**
  * GST_BASE_PARSE_FLOW_DROPPED:
  *
  * A #GstFlowReturn that can be returned from parse_frame to
  * indicate that no output buffer was generated.
  *
- * Since: 0.10.17
+ * Since: 0.10.18
  */
 #define GST_BASE_PARSE_FLOW_DROPPED   GST_FLOW_CUSTOM_SUCCESS
 
 /**
  * GST_BASE_PARSE_LOCK:
  * @obj: base parse instance
  *
  * Obtain a lock to protect the parse function from concurrent access.
  *
- * Since: 0.10.17
+ * Since: 0.10.18
  */
 #define GST_BASE_PARSE_LOCK(obj)   g_mutex_lock (GST_BASE_PARSE_CAST (obj)->parse_lock)
 
 /**
  * GST_BASE_PARSE_UNLOCK:
  * @obj: base parse instance
  *
  * Release the lock that protects the parse function from concurrent access.
  *
- * Since: 0.10.17
+ * Since: 0.10.18
  */
 #define GST_BASE_PARSE_UNLOCK(obj) g_mutex_unlock (GST_BASE_PARSE_CAST (obj)->parse_lock)
 
 typedef struct _GstBaseParse GstBaseParse;
 typedef struct _GstBaseParseClass GstBaseParseClass;
@@ -147,11 +147,12 @@
  * @set_sink_caps:  allows the subclass to be notified of the actual caps set.
  * @check_valid_frame:  Check if the given piece of data contains a valid
  *                      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.
  *                  Finds a frame. Gets a position passed and should return
  *                  TRUE and the offset in bytes where this position is.
@@ -164,10 +165,14 @@
  *                  Event handler on the sink pad. This function should return
  *                  TRUE if the event was handled and can be dropped.
  * @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
  * overridden.
  */
@@ -207,10 +212,12 @@
                                        GstEvent *event);
 
   gboolean      (*src_event)          (GstBaseParse *parse,
                                        GstEvent *event);
 
+  gboolean      (*is_seekable)        (GstBaseParse *parse);
+
 };
 
 GType           gst_base_parse_get_type         (void);
 
 
