gst/: More work on the generic source base class, implement seeking, query.
authorWim Taymans <wim.taymans@gmail.com>
Wed, 6 Apr 2005 17:30:48 +0000 (17:30 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Wed, 6 Apr 2005 17:30:48 +0000 (17:30 +0000)
Original commit message from CVS:
* gst/base/README:
* gst/base/gstbasesrc.c: (gst_basesrc_get_type),
(gst_basesrc_init), (gst_basesrc_get_formats), (gst_basesrc_query),
(gst_basesrc_get_event_mask), (gst_basesrc_do_seek),
(gst_basesrc_event_handler), (gst_basesrc_get_range_unlocked),
(gst_basesrc_check_get_range), (gst_basesrc_loop),
(gst_basesrc_unlock), (gst_basesrc_get_size), (gst_basesrc_start),
(gst_basesrc_stop), (gst_basesrc_activate),
(gst_basesrc_change_state), (basesrc_find_peek),
(basesrc_find_suggest), (gst_basesrc_type_find):
* gst/base/gstbasesrc.h:
* gst/elements/gstfilesrc.c: (gst_filesrc_base_init),
(gst_filesrc_class_init), (gst_filesrc_init),
(gst_filesrc_finalize), (gst_filesrc_set_location),
(gst_filesrc_set_property), (gst_filesrc_get_property),
(gst_filesrc_free_parent_mmap), (gst_filesrc_map_region),
(gst_filesrc_map_small_region), (gst_filesrc_create_mmap),
(gst_filesrc_create_read), (gst_filesrc_create),
(gst_filesrc_get_size), (gst_filesrc_start), (gst_filesrc_stop):
* gst/elements/gstfilesrc.h:
* gst/gstelement.c: (gst_element_get_state_func),
(gst_element_lost_state), (gst_element_pads_activate):
* gst/gstpad.c: (gst_pad_set_active), (gst_pad_peer_set_active),
(gst_pad_set_checkgetrange_function), (gst_pad_check_pull_range),
(gst_pad_pull_range):
* gst/gstpad.h:
More work on the generic source base class, implement seeking,
query.
Make filesrc extend the base source class.
Added gst_pad_set_checkgetrange_function to GstPad.

14 files changed:
ChangeLog
gst/base/README
gst/base/gstbasesrc.c
gst/base/gstbasesrc.h
gst/elements/gstfilesrc.c
gst/elements/gstfilesrc.h
gst/gstelement.c
gst/gstpad.c
gst/gstpad.h
libs/gst/base/README
libs/gst/base/gstbasesrc.c
libs/gst/base/gstbasesrc.h
plugins/elements/gstfilesrc.c
plugins/elements/gstfilesrc.h

index 77a383a..85615ed 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
+2005-04-06  Wim Taymans  <wim@fluendo.com>
+
+       * gst/base/README:
+       * gst/base/gstbasesrc.c: (gst_basesrc_get_type),
+       (gst_basesrc_init), (gst_basesrc_get_formats), (gst_basesrc_query),
+       (gst_basesrc_get_event_mask), (gst_basesrc_do_seek),
+       (gst_basesrc_event_handler), (gst_basesrc_get_range_unlocked),
+       (gst_basesrc_check_get_range), (gst_basesrc_loop),
+       (gst_basesrc_unlock), (gst_basesrc_get_size), (gst_basesrc_start),
+       (gst_basesrc_stop), (gst_basesrc_activate),
+       (gst_basesrc_change_state), (basesrc_find_peek),
+       (basesrc_find_suggest), (gst_basesrc_type_find):
+       * gst/base/gstbasesrc.h:
+       * gst/elements/gstfilesrc.c: (gst_filesrc_base_init),
+       (gst_filesrc_class_init), (gst_filesrc_init),
+       (gst_filesrc_finalize), (gst_filesrc_set_location),
+       (gst_filesrc_set_property), (gst_filesrc_get_property),
+       (gst_filesrc_free_parent_mmap), (gst_filesrc_map_region),
+       (gst_filesrc_map_small_region), (gst_filesrc_create_mmap),
+       (gst_filesrc_create_read), (gst_filesrc_create),
+       (gst_filesrc_get_size), (gst_filesrc_start), (gst_filesrc_stop):
+       * gst/elements/gstfilesrc.h:
+       * gst/gstelement.c: (gst_element_get_state_func),
+       (gst_element_lost_state), (gst_element_pads_activate):
+       * gst/gstpad.c: (gst_pad_set_active), (gst_pad_peer_set_active),
+       (gst_pad_set_checkgetrange_function), (gst_pad_check_pull_range),
+       (gst_pad_pull_range):
+       * gst/gstpad.h:
+       More work on the generic source base class, implement seeking,
+       query.
+       Make filesrc extend the base source class.
+       Added gst_pad_set_checkgetrange_function to GstPad.
+
 2005-04-06  Andy Wingo  <wingo@pobox.com>
 
        * pkgconfig/gstreamer-base.pc.in:
index 3384a24..2633218 100644 (file)
@@ -33,3 +33,4 @@ GstBaseSrc
   - one sinkpad
   - handles state changes
   - pull/push mode
+  - handles seeking/query
index 4d69e99..7ff18ba 100644 (file)
@@ -1,7 +1,6 @@
 /* GStreamer
  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- *                    2000 Wim Taymans <wtay@chello.be>
- *                    2005 Wim Taymans <wim@fluendo.com>
+ *               2000,2005 Wim Taymans <wim@fluendo.com>
  *
  * gstbasesrc.c: 
  *
@@ -92,12 +91,20 @@ static gboolean gst_basesrc_query (GstPad * pad, GstQueryType type,
     GstFormat * format, gint64 * value);
 static const GstFormat *gst_basesrc_get_formats (GstPad * pad);
 
+static gboolean gst_basesrc_unlock (GstBaseSrc * basesrc);
+static gboolean gst_basesrc_get_size (GstBaseSrc * basesrc, guint64 * size);
+static gboolean gst_basesrc_start (GstBaseSrc * basesrc);
+static gboolean gst_basesrc_stop (GstBaseSrc * basesrc);
+
 static GstElementStateReturn gst_basesrc_change_state (GstElement * element);
 
 static void gst_basesrc_loop (GstPad * pad);
+static gboolean gst_basesrc_check_get_range (GstPad * pad);
 static GstFlowReturn gst_basesrc_get_range (GstPad * pad, guint64 offset,
     guint length, GstBuffer ** buf);
 
+static GstCaps *gst_basesrc_type_find (GstBaseSrc * src);
+
 static void
 gst_basesrc_base_init (gpointer g_class)
 {
@@ -145,12 +152,17 @@ gst_basesrc_init (GstBaseSrc * basesrc, gpointer g_class)
   gst_pad_set_query_type_function (pad, gst_basesrc_get_query_types);
   gst_pad_set_formats_function (pad, gst_basesrc_get_formats);
   gst_pad_set_loop_function (pad, gst_basesrc_loop);
+  gst_pad_set_checkgetrange_function (pad, gst_basesrc_check_get_range);
   gst_pad_set_getrange_function (pad, gst_basesrc_get_range);
+  /* hold ref to pad */
+  basesrc->srcpad = pad;
   gst_element_add_pad (GST_ELEMENT (basesrc), pad);
 
   basesrc->segment_start = -1;
   basesrc->segment_end = -1;
   basesrc->blocksize = DEFAULT_BLOCKSIZE;
+
+  GST_FLAG_UNSET (basesrc, GST_BASESRC_STARTED);
 }
 
 static const GstFormat *
@@ -158,6 +170,7 @@ gst_basesrc_get_formats (GstPad * pad)
 {
   static const GstFormat formats[] = {
     GST_FORMAT_DEFAULT,
+    GST_FORMAT_BYTES,
     0,
   };
 
@@ -184,32 +197,157 @@ gst_basesrc_query (GstPad * pad, GstQueryType type,
 {
   GstBaseSrc *src = GST_BASESRC (GST_PAD_PARENT (pad));
 
+  if (*format == GST_FORMAT_DEFAULT)
+    *format = GST_FORMAT_BYTES;
+
   switch (type) {
+    case GST_QUERY_TOTAL:
+      switch (*format) {
+        case GST_FORMAT_BYTES:
+        {
+          gboolean ret;
+
+          ret = gst_basesrc_get_size (src, value);
+          GST_DEBUG ("getting length %d %lld", ret, *value);
+          return ret;
+        }
+        case GST_FORMAT_PERCENT:
+          *value = GST_FORMAT_PERCENT_MAX;
+          return TRUE;
+        default:
+          return FALSE;
+      }
+      break;
+    case GST_QUERY_POSITION:
+      switch (*format) {
+        case GST_FORMAT_BYTES:
+          *value = src->offset;
+          break;
+        case GST_FORMAT_PERCENT:
+          if (!gst_basesrc_get_size (src, value))
+            return FALSE;
+          *value = src->offset * GST_FORMAT_PERCENT_MAX / *value;
+          return TRUE;
+        default:
+          return FALSE;
+      }
+      break;
     case GST_QUERY_START:
       *value = src->segment_start;
-      break;
+      return TRUE;
     case GST_QUERY_SEGMENT_END:
       *value = src->segment_end;
-      break;
+      return TRUE;
     default:
       return FALSE;
   }
-  return TRUE;
+  return FALSE;
 }
 
 static const GstEventMask *
 gst_basesrc_get_event_mask (GstPad * pad)
 {
   static const GstEventMask masks[] = {
-    {GST_EVENT_SEEK, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT_LOOP},
+    {GST_EVENT_SEEK, GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_SET |
+          GST_SEEK_METHOD_END | GST_SEEK_FLAG_FLUSH |
+          GST_SEEK_FLAG_SEGMENT_LOOP},
     {GST_EVENT_FLUSH, 0},
+    {GST_EVENT_SIZE, 0},
     {0, 0},
   };
-
   return masks;
 }
 
 static gboolean
+gst_basesrc_do_seek (GstBaseSrc * src, GstEvent * event)
+{
+  GstFormat format;
+  gint64 offset;
+
+  format = GST_EVENT_SEEK_FORMAT (event);
+
+  /* get seek format */
+  if (format == GST_FORMAT_DEFAULT)
+    format = GST_FORMAT_BYTES;
+  /* we can only seek bytes */
+  if (format != GST_FORMAT_BYTES)
+    return FALSE;
+
+  /* get seek positions */
+  offset = GST_EVENT_SEEK_OFFSET (event);
+  src->segment_start = offset;
+  src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
+  src->segment_loop = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_SEGMENT_LOOP;
+
+  /* send flush start */
+  gst_pad_push_event (src->srcpad, gst_event_new_flush (FALSE));
+
+  /* unblock streaming thread */
+  gst_basesrc_unlock (src);
+
+  /* grab streaming lock */
+  GST_STREAM_LOCK (src->srcpad);
+
+  switch (GST_EVENT_SEEK_METHOD (event)) {
+    case GST_SEEK_METHOD_SET:
+      if (offset < 0)
+        goto error;
+      src->offset = MIN (offset, src->size);
+      GST_DEBUG_OBJECT (src, "seek set pending to %" G_GINT64_FORMAT,
+          src->offset);
+      break;
+    case GST_SEEK_METHOD_CUR:
+      offset += src->offset;
+      src->offset = CLAMP (offset, 0, src->size);
+      GST_DEBUG_OBJECT (src, "seek cur pending to %" G_GINT64_FORMAT,
+          src->offset);
+      break;
+    case GST_SEEK_METHOD_END:
+      if (offset > 0)
+        goto error;
+      offset = src->size + offset;
+      src->offset = MAX (0, offset);
+      GST_DEBUG_OBJECT (src, "seek end pending to %" G_GINT64_FORMAT,
+          src->offset);
+      break;
+    default:
+      goto error;
+  }
+  /* send flush end */
+  gst_pad_push_event (src->srcpad, gst_event_new_flush (TRUE));
+
+  /* now send discont */
+  {
+    GstEvent *event;
+
+    event = gst_event_new_discontinuous (1.0,
+        GST_FORMAT_TIME,
+        (gint64) src->segment_start, (gint64) src->segment_end, NULL);
+
+    gst_pad_push_event (src->srcpad, event);
+  }
+
+  /* and restart the task */
+  if (GST_RPAD_TASK (src->srcpad)) {
+    gst_task_start (GST_RPAD_TASK (src->srcpad));
+  }
+  GST_STREAM_UNLOCK (src->srcpad);
+
+  gst_event_unref (event);
+
+  return TRUE;
+
+  /* ERROR */
+error:
+  {
+    GST_DEBUG_OBJECT (src, "seek error");
+    GST_STREAM_UNLOCK (src->srcpad);
+    gst_event_unref (event);
+    return FALSE;
+  }
+}
+
+static gboolean
 gst_basesrc_event_handler (GstPad * pad, GstEvent * event)
 {
   GstBaseSrc *src;
@@ -218,12 +356,26 @@ gst_basesrc_event_handler (GstPad * pad, GstEvent * event)
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_SEEK:
-      src->segment_start = GST_EVENT_SEEK_OFFSET (event);
-      src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
-      src->segment_loop =
-          GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_SEGMENT_LOOP;
+      return gst_basesrc_do_seek (src, event);
+    case GST_EVENT_SIZE:
+    {
+      GstFormat format;
+
+      format = GST_EVENT_SIZE_FORMAT (event);
+      if (format == GST_FORMAT_DEFAULT)
+        format = GST_FORMAT_BYTES;
+      /* we can only accept bytes */
+      if (format != GST_FORMAT_BYTES)
+        return FALSE;
+
+      src->blocksize = GST_EVENT_SIZE_VALUE (event);
+      g_object_notify (G_OBJECT (src), "blocksize");
       break;
+    }
     case GST_EVENT_FLUSH:
+      /* cancel any blocking getrange */
+      if (!GST_EVENT_FLUSH_DONE (event))
+        gst_basesrc_unlock (src);
       break;
     default:
       break;
@@ -280,12 +432,41 @@ gst_basesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length,
   src = GST_BASESRC (GST_OBJECT_PARENT (pad));
   bclass = GST_BASESRC_GET_CLASS (src);
 
-  if (bclass->create)
-    ret = bclass->create (src, offset, length, buf);
-  else
-    ret = GST_FLOW_ERROR;
+  if (!GST_FLAG_IS_SET (src, GST_BASESRC_STARTED))
+    goto not_started;
+
+  if (!bclass->create)
+    goto no_function;
+
+  /* check size */
+  if (src->size != -1) {
+    if (offset + length > src->size) {
+      if (bclass->get_size)
+        bclass->get_size (src, &src->size);
+
+      if (offset + length > src->size) {
+        length = src->size - offset;
+      }
+    }
+  }
+  if (length == 0)
+    return GST_FLOW_UNEXPECTED;
+
+  ret = bclass->create (src, offset, length, buf);
 
   return ret;
+
+  /* ERROR */
+not_started:
+  {
+    GST_DEBUG_OBJECT (src, "getrange but not started");
+    return GST_FLOW_WRONG_STATE;
+  }
+no_function:
+  {
+    GST_DEBUG_OBJECT (src, "no create function");
+    return GST_FLOW_ERROR;
+  }
 }
 
 static GstFlowReturn
@@ -303,6 +484,21 @@ gst_basesrc_get_range (GstPad * pad, guint64 offset, guint length,
   return fret;
 }
 
+static gboolean
+gst_basesrc_check_get_range (GstPad * pad)
+{
+  GstBaseSrc *src;
+
+  src = GST_BASESRC (GST_OBJECT_PARENT (pad));
+
+  if (!GST_FLAG_IS_SET (src, GST_BASESRC_STARTED)) {
+    gst_basesrc_start (src);
+    gst_basesrc_stop (src);
+  }
+
+  return src->seekable;
+}
+
 static void
 gst_basesrc_loop (GstPad * pad)
 {
@@ -314,11 +510,9 @@ gst_basesrc_loop (GstPad * pad)
 
   GST_STREAM_LOCK (pad);
 
-  ret =
-      gst_basesrc_get_range_unlocked (pad, src->offset, DEFAULT_BLOCKSIZE,
-      &buf);
+  ret = gst_basesrc_get_range_unlocked (pad, src->offset, src->blocksize, &buf);
   if (ret != GST_FLOW_OK)
-    goto pause;
+    goto eos;
 
   src->offset += GST_BUFFER_SIZE (buf);
 
@@ -329,8 +523,17 @@ gst_basesrc_loop (GstPad * pad)
   GST_STREAM_UNLOCK (pad);
   return;
 
+eos:
+  {
+    GST_DEBUG_OBJECT (src, "going to EOS");
+    gst_task_pause (GST_RPAD_TASK (pad));
+    gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
+    GST_STREAM_UNLOCK (pad);
+    return;
+  }
 pause:
   {
+    GST_DEBUG_OBJECT (src, "pausing task");
     gst_task_pause (GST_RPAD_TASK (pad));
     GST_STREAM_UNLOCK (pad);
     return;
@@ -338,13 +541,134 @@ pause:
 }
 
 static gboolean
-gst_basesrc_activate (GstPad * pad, GstActivateMode mode)
+gst_basesrc_unlock (GstBaseSrc * basesrc)
+{
+  GstBaseSrcClass *bclass;
+  gboolean result = FALSE;
+
+  bclass = GST_BASESRC_GET_CLASS (basesrc);
+  if (bclass->unlock)
+    result = bclass->unlock (basesrc);
+
+  return result;
+}
+
+static gboolean
+gst_basesrc_get_size (GstBaseSrc * basesrc, guint64 * size)
 {
+  GstBaseSrcClass *bclass;
   gboolean result = FALSE;
+
+  bclass = GST_BASESRC_GET_CLASS (basesrc);
+  if (bclass->get_size)
+    result = bclass->get_size (basesrc, size);
+
+  if (result)
+    basesrc->size = *size;
+
+  return result;
+}
+
+static gboolean
+gst_basesrc_start (GstBaseSrc * basesrc)
+{
+  GstBaseSrcClass *bclass;
+  gboolean result;
+
+  if (GST_FLAG_IS_SET (basesrc, GST_BASESRC_STARTED))
+    return TRUE;
+
+  bclass = GST_BASESRC_GET_CLASS (basesrc);
+  if (bclass->start)
+    result = bclass->start (basesrc);
+  else
+    result = TRUE;
+
+  if (!result)
+    goto could_not_start;
+
+  GST_FLAG_SET (basesrc, GST_BASESRC_STARTED);
+
+  /* start in the beginning */
+  basesrc->offset = 0;
+  basesrc->segment_start = 0;
+
+  /* figure out the size */
+  if (bclass->get_size)
+    result = bclass->get_size (basesrc, &basesrc->size);
+  else
+    result = FALSE;
+
+  GST_DEBUG ("size %lld", basesrc->size);
+
+  /* we always run to the end */
+  basesrc->segment_end = -1;
+
+  /* check if we can seek */
+  if (bclass->is_seekable)
+    basesrc->seekable = bclass->is_seekable (basesrc);
+  else
+    basesrc->seekable = FALSE;
+
+  /* run typefind */
+  if (basesrc->seekable) {
+    GstCaps *caps;
+
+    caps = gst_basesrc_type_find (basesrc);
+    gst_pad_set_caps (basesrc->srcpad, caps);
+  }
+  return TRUE;
+
+  /* ERROR */
+could_not_start:
+  {
+    GST_DEBUG_OBJECT (basesrc, "could not start");
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_basesrc_stop (GstBaseSrc * basesrc)
+{
+  GstBaseSrcClass *bclass;
+  gboolean result = TRUE;
+
+  if (!GST_FLAG_IS_SET (basesrc, GST_BASESRC_STARTED))
+    return TRUE;
+
+  bclass = GST_BASESRC_GET_CLASS (basesrc);
+  if (bclass->stop)
+    result = bclass->stop (basesrc);
+
+  if (result)
+    GST_FLAG_UNSET (basesrc, GST_BASESRC_STARTED);
+
+  return result;
+}
+
+static gboolean
+gst_basesrc_activate (GstPad * pad, GstActivateMode mode)
+{
+  gboolean result;
   GstBaseSrc *basesrc;
 
   basesrc = GST_BASESRC (GST_OBJECT_PARENT (pad));
 
+  /* prepare subclass first */
+  switch (mode) {
+    case GST_ACTIVATE_PUSH:
+    case GST_ACTIVATE_PULL:
+      result = gst_basesrc_start (basesrc);
+      break;
+    default:
+      result = TRUE;
+      break;
+  }
+  /* if that failed we can stop here */
+  if (!result)
+    goto error_start;
+
+  result = FALSE;
   switch (mode) {
     case GST_ACTIVATE_PUSH:
       /* if we have a scheduler we can start the task */
@@ -379,6 +703,13 @@ gst_basesrc_activate (GstPad * pad, GstActivateMode mode)
       break;
   }
   return result;
+
+  /* ERROR */
+error_start:
+  {
+    GST_DEBUG_OBJECT (basesrc, "failed to start");
+    return FALSE;
+  }
 }
 
 static GstElementStateReturn
@@ -396,10 +727,7 @@ gst_basesrc_change_state (GstElement * element)
     case GST_STATE_NULL_TO_READY:
       break;
     case GST_STATE_READY_TO_PAUSED:
-    {
-      basesrc->offset = 0;
       break;
-    }
     case GST_STATE_PAUSED_TO_PLAYING:
       break;
     default:
@@ -412,6 +740,7 @@ gst_basesrc_change_state (GstElement * element)
     case GST_STATE_PLAYING_TO_PAUSED:
       break;
     case GST_STATE_PAUSED_TO_READY:
+      result = gst_basesrc_stop (basesrc);
       break;
     case GST_STATE_READY_TO_NULL:
       break;
@@ -421,3 +750,100 @@ gst_basesrc_change_state (GstElement * element)
 
   return result;
 }
+
+/**
+ * typefind code here
+ */
+typedef struct
+{
+  GstBaseSrc *src;
+  guint best_probability;
+  GstCaps *caps;
+
+  GstBuffer *buffer;
+}
+BaseSrcTypeFind;
+
+static guint8 *
+basesrc_find_peek (gpointer data, gint64 offset, guint size)
+{
+  BaseSrcTypeFind *find;
+  GstBuffer *buffer;
+  GstBaseSrc *src;
+  GstFlowReturn ret;
+
+  if (size == 0)
+    return NULL;
+
+  find = (BaseSrcTypeFind *) data;
+  src = find->src;
+
+  if (offset < 0) {
+    offset += src->size;
+  }
+
+  buffer = NULL;
+  ret = gst_basesrc_get_range_unlocked (src->srcpad, offset, size, &buffer);
+
+  if (find->buffer) {
+    gst_buffer_unref (find->buffer);
+    find->buffer = NULL;
+  }
+
+  if (ret != GST_FLOW_OK)
+    goto error;
+
+  find->buffer = buffer;
+
+  return GST_BUFFER_DATA (buffer);
+
+error:
+  {
+    return NULL;
+  }
+}
+
+static void
+basesrc_find_suggest (gpointer data, guint probability, const GstCaps * caps)
+{
+  BaseSrcTypeFind *find = (BaseSrcTypeFind *) data;
+
+  if (probability > find->best_probability) {
+    gst_caps_replace (&find->caps, gst_caps_copy (caps));
+    find->best_probability = probability;
+  }
+}
+
+static GstCaps *
+gst_basesrc_type_find (GstBaseSrc * src)
+{
+  GstTypeFind gst_find;
+  BaseSrcTypeFind find;
+  GList *walk, *type_list = NULL;
+  GstCaps *result = NULL;
+
+  walk = type_list = gst_type_find_factory_get_list ();
+
+  find.src = src;
+  find.best_probability = 0;
+  find.caps = NULL;
+  find.buffer = NULL;
+  gst_find.data = &find;
+  gst_find.peek = basesrc_find_peek;
+  gst_find.suggest = basesrc_find_suggest;
+  gst_find.get_length = NULL;
+
+  while (walk) {
+    GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (walk->data);
+
+    gst_type_find_factory_call_function (factory, &gst_find);
+    if (find.best_probability >= GST_TYPE_FIND_MAXIMUM)
+      break;
+    walk = g_list_next (walk);
+  }
+
+  if (find.best_probability > 0)
+    result = find.caps;
+
+  return result;
+}
index a2bfe74..8943fd9 100644 (file)
@@ -35,19 +35,30 @@ G_BEGIN_DECLS
 #define GST_IS_BASESRC(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASESRC))
 #define GST_IS_BASESRC_CLASS(obj)      (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASESRC))
 
+typedef enum {
+  GST_BASESRC_STARTED           = GST_ELEMENT_FLAG_LAST,
+
+  GST_BASESRC_FLAG_LAST         = GST_ELEMENT_FLAG_LAST + 2
+} GstFileSrcFlags;
+
+
 typedef struct _GstBaseSrc GstBaseSrc;
 typedef struct _GstBaseSrcClass GstBaseSrcClass;
 
 struct _GstBaseSrc {
   GstElement     element;
 
+  GstPad       *srcpad;
+
   gint                  blocksize;
 
   gint64        segment_start;
   gint64        segment_end;
   gboolean      segment_loop;
 
+  gboolean       seekable;
   guint64       offset;
+  guint64        size;
 };
 
 struct _GstBaseSrcClass {
@@ -62,6 +73,11 @@ struct _GstBaseSrcClass {
   void          (*get_times)    (GstBaseSrc *src, GstBuffer *buffer,
                                  GstClockTime *start, GstClockTime *end);
 
+  gboolean      (*get_size)     (GstBaseSrc *src, guint64 *size);
+
+  gboolean      (*is_seekable)  (GstBaseSrc *src);
+  gboolean      (*unlock)       (GstBaseSrc *src);
+
   gboolean      (*event)        (GstBaseSrc *src, GstEvent *event);
   GstFlowReturn (*create)       (GstBaseSrc *src, guint64 offset, guint size, 
                                 GstBuffer **buf);
index 4d4b2ff..2c60acd 100644 (file)
@@ -1,6 +1,6 @@
 /* GStreamer
  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- *                    2000 Wim Taymans <wtay@chello.be>
+ *               2000,2005 Wim Taymans <wim@fluendo.com>
  *
  * gstfilesrc.c:
  *
@@ -105,9 +105,6 @@ GstElementDetails gst_filesrc_details = GST_ELEMENT_DETAILS ("File Source",
     "Read from arbitrary point in a file",
     "Erik Walthinsen <omega@cse.ogi.edu>");
 
-#define DEFAULT_BLOCKSIZE      4*1024
-#define DEFAULT_MMAPSIZE       4*1024*1024
-
 /* FileSrc signals and args */
 enum
 {
@@ -115,72 +112,33 @@ enum
   LAST_SIGNAL
 };
 
+#define DEFAULT_BLOCKSIZE      4*1024
+#define DEFAULT_MMAPSIZE       4*1024*1024
+#define DEFAULT_TOUCH          FALSE
+
 enum
 {
   ARG_0,
   ARG_LOCATION,
   ARG_FD,
-  ARG_BLOCKSIZE,
   ARG_MMAPSIZE,
   ARG_TOUCH
 };
 
-static const GstEventMask *
-gst_filesrc_get_event_mask (GstPad * pad)
-{
-  static const GstEventMask masks[] = {
-    {GST_EVENT_SEEK, GST_SEEK_METHOD_CUR |
-          GST_SEEK_METHOD_SET | GST_SEEK_METHOD_END | GST_SEEK_FLAG_FLUSH},
-    {GST_EVENT_FLUSH, 0},
-    {GST_EVENT_SIZE, 0},
-    {0, 0}
-  };
-
-  return masks;
-}
-
-static const GstQueryType *
-gst_filesrc_get_query_types (GstPad * pad)
-{
-  static const GstQueryType types[] = {
-    GST_QUERY_TOTAL,
-    GST_QUERY_POSITION,
-    0
-  };
-
-  return types;
-}
-
-static const GstFormat *
-gst_filesrc_get_formats (GstPad * pad)
-{
-  static const GstFormat formats[] = {
-    GST_FORMAT_BYTES,
-    0,
-  };
-
-  return formats;
-}
-
-static void gst_filesrc_dispose (GObject * object);
+static void gst_filesrc_finalize (GObject * object);
 
 static void gst_filesrc_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec);
 static void gst_filesrc_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 
-static gboolean gst_filesrc_check_filesize (GstFileSrc * src);
-static GstFlowReturn gst_filesrc_get (GstPad * pad, GstBuffer ** buffer);
-static GstFlowReturn gst_filesrc_getrange (GstPad * pad, guint64 offset,
-    guint length, GstBuffer ** buffer);
-static gboolean gst_filesrc_srcpad_event (GstPad * pad, GstEvent * event);
-static gboolean gst_filesrc_srcpad_query (GstPad * pad, GstQueryType type,
-    GstFormat * format, gint64 * value);
+static gboolean gst_filesrc_start (GstBaseSrc * basesrc);
+static gboolean gst_filesrc_stop (GstBaseSrc * basesrc);
 
-static gboolean gst_filesrc_activate (GstPad * pad, GstActivateMode mode);
-static GstElementStateReturn gst_filesrc_change_state (GstElement * element);
+static gboolean gst_filesrc_get_size (GstBaseSrc * src, guint64 * size);
+static GstFlowReturn gst_filesrc_create (GstBaseSrc * src, guint64 offset,
+    guint length, GstBuffer ** buffer);
 
-static GstCaps *gst_filesrc_type_find (GstFileSrc * src);
 static void gst_filesrc_uri_handler_init (gpointer g_iface,
     gpointer iface_data);
 
@@ -198,7 +156,7 @@ _do_init (GType filesrc_type)
   GST_DEBUG_CATEGORY_INIT (gst_filesrc_debug, "filesrc", 0, "filesrc element");
 }
 
-GST_BOILERPLATE_FULL (GstFileSrc, gst_filesrc, GstElement, GST_TYPE_ELEMENT,
+GST_BOILERPLATE_FULL (GstFileSrc, gst_filesrc, GstBaseSrc, GST_TYPE_BASESRC,
     _do_init);
 
 static void
@@ -208,15 +166,20 @@ gst_filesrc_base_init (gpointer g_class)
 
   gst_element_class_add_pad_template (gstelement_class,
       gst_static_pad_template_get (&srctemplate));
+
   gst_element_class_set_details (gstelement_class, &gst_filesrc_details);
 }
+
 static void
 gst_filesrc_class_init (GstFileSrcClass * klass)
 {
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSrcClass *gstbasesrc_class;
 
   gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesrc_class = (GstBaseSrcClass *) klass;
 
   gobject_class->set_property = gst_filesrc_set_property;
   gobject_class->get_property = gst_filesrc_get_property;
@@ -228,50 +191,34 @@ gst_filesrc_class_init (GstFileSrcClass * klass)
   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOCATION,
       g_param_spec_string ("location", "File Location",
           "Location of the file to read", NULL, G_PARAM_READWRITE));
-  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BLOCKSIZE,
-      g_param_spec_ulong ("blocksize", "Block size",
-          "Size in bytes to read per buffer", 1, G_MAXULONG, DEFAULT_BLOCKSIZE,
-          G_PARAM_READWRITE));
   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MMAPSIZE,
       g_param_spec_ulong ("mmapsize", "mmap() Block Size",
           "Size in bytes of mmap()d regions", 0, G_MAXULONG, DEFAULT_MMAPSIZE,
           G_PARAM_READWRITE));
   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TOUCH,
       g_param_spec_boolean ("touch", "Touch read data",
-          "Touch data to force disk read", FALSE, G_PARAM_READWRITE));
+          "Touch data to force disk read", DEFAULT_TOUCH, G_PARAM_READWRITE));
 
-  gobject_class->dispose = gst_filesrc_dispose;
+  gobject_class->finalize = gst_filesrc_finalize;
 
-  gstelement_class->change_state = gst_filesrc_change_state;
+  gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_filesrc_start);
+  gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_filesrc_stop);
+  gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_filesrc_get_size);
+  gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_filesrc_create);
 }
 
 static void
 gst_filesrc_init (GstFileSrc * src)
 {
-  src->srcpad =
-      gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
-      "src");
-  gst_pad_set_getrange_function (src->srcpad, gst_filesrc_getrange);
-  gst_pad_set_activate_function (src->srcpad, gst_filesrc_activate);
-  gst_pad_set_event_function (src->srcpad, gst_filesrc_srcpad_event);
-  gst_pad_set_event_mask_function (src->srcpad, gst_filesrc_get_event_mask);
-  gst_pad_set_query_function (src->srcpad, gst_filesrc_srcpad_query);
-  gst_pad_set_query_type_function (src->srcpad, gst_filesrc_get_query_types);
-  gst_pad_set_formats_function (src->srcpad, gst_filesrc_get_formats);
-  gst_element_add_pad (GST_ELEMENT (src), src->srcpad);
-
 #ifdef HAVE_MMAP
   src->pagesize = getpagesize ();
 #endif
 
   src->filename = NULL;
   src->fd = 0;
-  src->filelen = 0;
   src->uri = NULL;
 
-  src->curoffset = 0;
-  src->block_size = DEFAULT_BLOCKSIZE;
-  src->touch = FALSE;
+  src->touch = DEFAULT_TOUCH;
 
   src->mapbuf = NULL;
   src->mapsize = DEFAULT_MMAPSIZE;      /* default is 4MB */
@@ -280,7 +227,7 @@ gst_filesrc_init (GstFileSrc * src)
 }
 
 static void
-gst_filesrc_dispose (GObject * object)
+gst_filesrc_finalize (GObject * object)
 {
   GstFileSrc *src;
 
@@ -289,19 +236,22 @@ gst_filesrc_dispose (GObject * object)
   g_free (src->filename);
   g_free (src->uri);
 
-  /* dispose may be called multiple times */
-  src->filename = NULL;
-  src->uri = NULL;
-
-  G_OBJECT_CLASS (parent_class)->dispose (object);
+  G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
 static gboolean
 gst_filesrc_set_location (GstFileSrc * src, const gchar * location)
 {
   /* the element must be stopped in order to do this */
-  if (GST_STATE (src) != GST_STATE_READY && GST_STATE (src) != GST_STATE_NULL)
-    return FALSE;
+  GST_STATE_LOCK (src);
+  {
+    GstElementState state;
+
+    state = GST_STATE (src);
+    if (state != GST_STATE_READY && state != GST_STATE_NULL)
+      goto wrong_state;
+  }
+  GST_STATE_UNLOCK (src);
 
   g_free (src->filename);
   g_free (src->uri);
@@ -318,6 +268,14 @@ gst_filesrc_set_location (GstFileSrc * src, const gchar * location)
   gst_uri_handler_new_uri (GST_URI_HANDLER (src), src->uri);
 
   return TRUE;
+
+  /* ERROR */
+wrong_state:
+  {
+    GST_DEBUG_OBJECT (src, "setting location in wrong state");
+    GST_STATE_UNLOCK (src);
+    return FALSE;
+  }
 }
 
 static void
@@ -335,10 +293,6 @@ gst_filesrc_set_property (GObject * object, guint prop_id, const GValue * value,
     case ARG_LOCATION:
       gst_filesrc_set_location (src, g_value_get_string (value));
       break;
-    case ARG_BLOCKSIZE:
-      src->block_size = g_value_get_ulong (value);
-      g_object_notify (G_OBJECT (src), "blocksize");
-      break;
     case ARG_MMAPSIZE:
       if ((src->mapsize % src->pagesize) == 0) {
         src->mapsize = g_value_get_ulong (value);
@@ -377,9 +331,6 @@ gst_filesrc_get_property (GObject * object, guint prop_id, GValue * value,
     case ARG_FD:
       g_value_set_int (value, src->fd);
       break;
-    case ARG_BLOCKSIZE:
-      g_value_set_ulong (value, src->block_size);
-      break;
     case ARG_MMAPSIZE:
       g_value_set_ulong (value, src->mapsize);
       break;
@@ -392,53 +343,75 @@ gst_filesrc_get_property (GObject * object, guint prop_id, GValue * value,
   }
 }
 
+/***
+ * mmap code below
+ */
+
 #ifdef HAVE_MMAP
 static void
 gst_filesrc_free_parent_mmap (GstBuffer * buf)
 {
-  GST_LOG ("freeing mmap()d buffer at %" G_GUINT64_FORMAT "+%u",
-      GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf));
+  guint size;
+  guint64 offset;
+  gpointer data;
+  GstBaseSrc *src;
+
+  /* get info */
+  size = GST_BUFFER_MAXSIZE (buf);
+  offset = GST_BUFFER_OFFSET (buf);
+  data = GST_BUFFER_DATA (buf);
+  src = (GstBaseSrc *) GST_BUFFER_PRIVATE (buf);
+
+  if (!GST_IS_BASESRC (src))
+    goto wrong_buffer;
+
+  GST_LOG ("freeing mmap()d buffer at %" G_GUINT64_FORMAT "+%u", offset, size);
 
 #ifdef MADV_DONTNEED
   /* madvise to tell the kernel what to do with it */
-  madvise (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), MADV_DONTNEED);
+  if (madvise (data, size, MADV_DONTNEED) < 0) {
+    GST_WARNING_OBJECT (src, "warning: madvise failed: %s", strerror (errno));
+  }
 #endif
+
   /* now unmap the memory */
-  munmap (GST_BUFFER_DATA (buf), GST_BUFFER_MAXSIZE (buf));
+  if (munmap (data, size) < 0) {
+    GST_WARNING_OBJECT (src, "warning: munmap failed: %s", strerror (errno));
+  }
+
   /* cast to unsigned long, since there's no gportable way to print
    * guint64 as hex */
   GST_LOG ("unmapped region %08lx+%08lx at %p",
-      (unsigned long) GST_BUFFER_OFFSET (buf),
-      (unsigned long) GST_BUFFER_MAXSIZE (buf), GST_BUFFER_DATA (buf));
+      (gulong) offset, (gulong) size, data);
 
   GST_BUFFER_DATA (buf) = NULL;
+  return;
+
+wrong_buffer:
+  {
+    GST_WARNING ("freeing wrong mmap buffer");
+    return;
+  }
 }
-#endif
 
-#ifdef HAVE_MMAP
 static GstBuffer *
 gst_filesrc_map_region (GstFileSrc * src, off_t offset, size_t size)
 {
   GstBuffer *buf;
-  gint retval;
   void *mmapregion;
 
   g_return_val_if_fail (offset >= 0, NULL);
 
   GST_LOG_OBJECT (src, "mapping region %08llx+%08lx from file into memory",
-      offset, (unsigned long) size);
+      offset, (gulong) size);
+
   mmapregion = mmap (NULL, size, PROT_READ, MAP_SHARED, src->fd, offset);
 
-  if (mmapregion == NULL) {
-    GST_ELEMENT_ERROR (src, RESOURCE, TOO_LAZY, (NULL), ("mmap call failed."));
-    return NULL;
-  } else if (mmapregion == MAP_FAILED) {
-    GST_WARNING_OBJECT (src, "mmap (0x%08lx, %d, 0x%llx) failed: %s",
-        (unsigned long) size, src->fd, offset, strerror (errno));
-    return NULL;
-  }
+  if (mmapregion == NULL || mmapregion == MAP_FAILED)
+    goto mmap_failed;
+
   GST_LOG_OBJECT (src, "mapped region %08lx+%08lx from file into memory at %p",
-      (unsigned long) offset, (unsigned long) size, mmapregion);
+      (gulong) offset, (gulong) size, mmapregion);
 
   /* time to allocate a new mapbuf */
   buf = gst_buffer_new ();
@@ -447,9 +420,11 @@ gst_filesrc_map_region (GstFileSrc * src, off_t offset, size_t size)
 
 #ifdef MADV_SEQUENTIAL
   /* madvise to tell the kernel what to do with it */
-  retval =
-      madvise (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), MADV_SEQUENTIAL);
+  if (madvise (mmapregion, size, MADV_SEQUENTIAL) < 0) {
+    GST_WARNING_OBJECT (src, "warning: madvise failed: %s", strerror (errno));
+  }
 #endif
+
   /* fill in the rest of the fields */
   GST_BUFFER_FLAG_SET (buf, GST_BUFFER_READONLY);
   GST_BUFFER_FLAG_SET (buf, GST_BUFFER_ORIGINAL);
@@ -462,27 +437,45 @@ gst_filesrc_map_region (GstFileSrc * src, off_t offset, size_t size)
   GST_BUFFER_FREE_DATA_FUNC (buf) = gst_filesrc_free_parent_mmap;
 
   return buf;
+
+  /* ERROR */
+mmap_failed:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
+        ("mmap (0x%08lx, %d, 0x%llx) failed: %s",
+            (gulong) size, src->fd, offset, strerror (errno)));
+    return NULL;
+  }
 }
-#endif
 
-#ifdef HAVE_MMAP
 static GstBuffer *
 gst_filesrc_map_small_region (GstFileSrc * src, off_t offset, size_t size)
 {
-  size_t mapsize;
-  off_t mod, mapbase;
-  GstBuffer *map;
+  GstBuffer *ret;
+  off_t mod;
+  guint pagesize;
 
-/*  printf("attempting to map a small buffer at %d+%d\n",offset,size); */
+  GST_LOG_OBJECT (src,
+      "attempting to map a small buffer at %llu+%d",
+      (unsigned long long) offset, (gint) size);
+
+  pagesize = src->pagesize;
+
+  mod = offset % pagesize;
 
   /* if the offset starts at a non-page boundary, we have to special case */
-  if ((mod = offset % src->pagesize)) {
-    GstBuffer *ret;
+  if (mod != 0) {
+    size_t mapsize;
+    off_t mapbase;
+    GstBuffer *map;
 
     mapbase = offset - mod;
-    mapsize =
-        ((size + mod + src->pagesize - 1) / src->pagesize) * src->pagesize;
-/*    printf("not on page boundaries, resizing map to %d+%d\n",mapbase,mapsize);*/
+    mapsize = ((size + mod + pagesize - 1) / pagesize) * pagesize;
+
+    GST_LOG_OBJECT (src,
+        "not on page boundaries, resizing to map to %llu+%d",
+        (unsigned long long) mapbase, (gint) mapsize);
+
     map = gst_filesrc_map_region (src, mapbase, mapsize);
     if (map == NULL)
       return NULL;
@@ -491,23 +484,16 @@ gst_filesrc_map_small_region (GstFileSrc * src, off_t offset, size_t size)
     GST_BUFFER_OFFSET (ret) = GST_BUFFER_OFFSET (map) + offset - mapbase;
 
     gst_buffer_unref (map);
-
-    return ret;
+  } else {
+    ret = gst_filesrc_map_region (src, offset, size);
   }
 
-  return gst_filesrc_map_region (src, offset, size);
+  return ret;
 }
-#endif
 
-#ifdef HAVE_MMAP
-/**
- * gst_filesrc_get_mmap:
- * @src: #GstElement to get data from
- *
- * Returns: a new #GstData from the mmap'd source.
- */
-static GstData *
-gst_filesrc_get_mmap (GstFileSrc * src)
+static GstFlowReturn
+gst_filesrc_create_mmap (GstFileSrc * src, guint64 offset, guint length,
+    GstBuffer ** buffer)
 {
   GstBuffer *buf = NULL;
   size_t readsize, mapsize;
@@ -515,48 +501,37 @@ gst_filesrc_get_mmap (GstFileSrc * src)
   int i;
 
   /* calculate end pointers so we don't have to do so repeatedly later */
-  readsize = src->block_size;
-  readend = src->curoffset + src->block_size;   /* note this is the byte *after* the read */
+  readsize = length;
+  readend = offset + readsize;  /* note this is the byte *after* the read */
+
   mapstart = GST_BUFFER_OFFSET (src->mapbuf);
   mapsize = GST_BUFFER_SIZE (src->mapbuf);
   mapend = mapstart + mapsize;  /* note this is the byte *after* the map */
 
-  /* check to see if we're going to overflow the end of the file */
-  if (src->is_regular) {
-    if (readend > src->filelen) {
-      if (!gst_filesrc_check_filesize (src) || readend > src->filelen) {
-        readsize = src->filelen - src->curoffset;
-        readend = src->curoffset + readsize;
-      }
-    }
-  }
-
   GST_LOG ("attempting to read %08lx, %08lx, %08lx, %08lx",
       (unsigned long) readsize, (unsigned long) readend,
       (unsigned long) mapstart, (unsigned long) mapend);
 
   /* if the start is past the mapstart */
-  if (src->curoffset >= mapstart) {
+  if (offset >= mapstart) {
     /* if the end is before the mapend, the buffer is in current mmap region... */
     /* ('cause by definition if readend is in the buffer, so's readstart) */
     if (readend <= mapend) {
       GST_LOG_OBJECT (src,
           "read buf %llu+%d lives in current mapbuf %lld+%d, creating subbuffer of mapbuf",
-          src->curoffset, (int) readsize, mapstart, mapsize);
-      buf =
-          gst_buffer_create_sub (src->mapbuf, src->curoffset - mapstart,
-          readsize);
-      GST_BUFFER_OFFSET (buf) = src->curoffset;
+          offset, (int) readsize, mapstart, mapsize);
+      buf = gst_buffer_create_sub (src->mapbuf, offset - mapstart, readsize);
+      GST_BUFFER_OFFSET (buf) = offset;
 
       /* if the start actually is within the current mmap region, map an overlap buffer */
-    } else if (src->curoffset < mapend) {
+    } else if (offset < mapend) {
       GST_LOG_OBJECT (src,
           "read buf %llu+%d starts in mapbuf %d+%d but ends outside, creating new mmap",
-          (unsigned long long) src->curoffset, (gint) readsize, (gint) mapstart,
+          (unsigned long long) offset, (gint) readsize, (gint) mapstart,
           (gint) mapsize);
-      buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
+      buf = gst_filesrc_map_small_region (src, offset, readsize);
       if (buf == NULL)
-        return NULL;
+        goto could_not_mmap;
     }
 
     /* the only other option is that buffer is totally outside, which means we search for it */
@@ -569,43 +544,43 @@ gst_filesrc_get_mmap (GstFileSrc * src)
     /* either way, it's really not relevant, we just create a new region anyway */
     GST_LOG_OBJECT (src,
         "read buf %llu+%d starts before mapbuf %d+%d, but overlaps it",
-        (unsigned long long) src->curoffset, (gint) readsize, (gint) mapstart,
+        (unsigned long long) offset, (gint) readsize, (gint) mapstart,
         (gint) mapsize);
-    buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
+    buf = gst_filesrc_map_small_region (src, offset, readsize);
     if (buf == NULL)
-      return NULL;
+      goto could_not_mmap;
   }
 
   /* then deal with the case where the read buffer is totally outside */
   if (buf == NULL) {
     /* first check to see if there's a map that covers the right region already */
     GST_LOG_OBJECT (src, "searching for mapbuf to cover %llu+%d",
-        src->curoffset, (int) readsize);
+        offset, (int) readsize);
 
     /* if the read buffer crosses a mmap region boundary, create a one-off region */
-    if ((src->curoffset / src->mapsize) != (readend / src->mapsize)) {
+    if ((offset / src->mapsize) != (readend / src->mapsize)) {
       GST_LOG_OBJECT (src,
           "read buf %llu+%d crosses a %d-byte boundary, creating a one-off",
-          src->curoffset, (int) readsize, (int) src->mapsize);
-      buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
+          offset, (int) readsize, (int) src->mapsize);
+      buf = gst_filesrc_map_small_region (src, offset, readsize);
       if (buf == NULL)
-        return NULL;
+        goto could_not_mmap;
 
       /* otherwise we will create a new mmap region and set it to the default */
     } else {
       size_t mapsize;
 
-      off_t nextmap = src->curoffset - (src->curoffset % src->mapsize);
+      off_t nextmap = offset - (offset % src->mapsize);
 
       GST_LOG_OBJECT (src,
           "read buf %llu+%d in new mapbuf at %llu+%d, mapping and subbuffering",
-          src->curoffset, readsize, nextmap, src->mapsize);
+          offset, readsize, nextmap, src->mapsize);
       /* first, we're done with the old mapbuf */
       gst_buffer_unref (src->mapbuf);
       mapsize = src->mapsize;
 
       /* double the mapsize as long as the readsize is smaller */
-      while (readsize + src->curoffset > nextmap + mapsize) {
+      while (readsize + offset > nextmap + mapsize) {
         GST_LOG_OBJECT (src, "readsize smaller then mapsize %08x %d",
             readsize, (int) mapsize);
         mapsize <<= 1;
@@ -613,14 +588,12 @@ gst_filesrc_get_mmap (GstFileSrc * src)
       /* create a new one */
       src->mapbuf = gst_filesrc_map_region (src, nextmap, mapsize);
       if (src->mapbuf == NULL)
-        return NULL;
+        goto could_not_mmap;
 
       /* subbuffer it */
-      buf =
-          gst_buffer_create_sub (src->mapbuf, src->curoffset - nextmap,
-          readsize);
+      buf = gst_buffer_create_sub (src->mapbuf, offset - nextmap, readsize);
       GST_BUFFER_OFFSET (buf) =
-          GST_BUFFER_OFFSET (src->mapbuf) + src->curoffset - nextmap;
+          GST_BUFFER_OFFSET (src->mapbuf) + offset - nextmap;
     }
   }
 
@@ -628,266 +601,241 @@ gst_filesrc_get_mmap (GstFileSrc * src)
   if (src->touch) {
     volatile guchar *p = GST_BUFFER_DATA (buf), c;
 
+    /* read first byte of each page */
     for (i = 0; i < GST_BUFFER_SIZE (buf); i += src->pagesize)
       c = p[i];
   }
 
   /* we're done, return the buffer */
-  g_assert (src->curoffset == GST_BUFFER_OFFSET (buf));
-  src->curoffset += GST_BUFFER_SIZE (buf);
-  return GST_DATA (buf);
+  *buffer = buf;
+
+  return GST_FLOW_OK;
+
+  /* ERROR */
+could_not_mmap:
+  {
+    return GST_FLOW_ERROR;
+  }
 }
 #endif
 
-static GstData *
-gst_filesrc_get_read (GstFileSrc * src)
+/***
+ * read code below 
+ *
+ */
+
+static GstFlowReturn
+gst_filesrc_create_read (GstFileSrc * src, guint64 offset, guint length,
+    GstBuffer ** buffer)
 {
-  GstBuffer *buf = NULL;
-  size_t readsize;
   int ret;
+  GstBuffer *buf;
 
-  readsize = src->block_size;
-  /* for regular files, we can use the filesize to check how much we
-     can read */
-  if (src->is_regular) {
-    if (src->curoffset + readsize > src->filelen) {
-      if (!gst_filesrc_check_filesize (src)
-          || src->curoffset + readsize > src->filelen) {
-        readsize = src->filelen - src->curoffset;
-      }
-    }
+  if (src->read_position != offset) {
+    off_t res;
+
+    res = lseek (src->fd, offset, SEEK_SET);
+    if (res < 0 || res != offset)
+      goto seek_failed;
   }
 
-  buf = gst_buffer_new_and_alloc (readsize);
-  g_return_val_if_fail (buf != NULL, NULL);
+  buf = gst_buffer_new_and_alloc (length);
+
+  GST_LOG_OBJECT (src, "Reading %d bytes", length);
+  ret = read (src->fd, GST_BUFFER_DATA (buf), length);
+  if (ret < 0)
+    goto could_not_read;
 
-  GST_LOG_OBJECT (src, "Reading %d bytes", readsize);
-  ret = read (src->fd, GST_BUFFER_DATA (buf), readsize);
-  if (ret < 0) {
-    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
-    return NULL;
-  }
   /* regular files should have given us what we expected */
-  if (ret < readsize && src->is_regular) {
-    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
-        ("unexpected end of file."));
-    return NULL;
-  }
+  if (ret < length && src->is_regular)
+    goto unexpected_eos;
+
   /* other files should eos if they read 0 */
   if (ret == 0) {
     GST_DEBUG ("non-regular file hits EOS");
     gst_buffer_unref (buf);
-    //gst_element_set_eos (GST_ELEMENT (src));
-    return GST_DATA (gst_event_new (GST_EVENT_EOS));
+    return GST_FLOW_UNEXPECTED;
   }
-  readsize = ret;
-
-  GST_BUFFER_SIZE (buf) = readsize;
-  GST_BUFFER_MAXSIZE (buf) = readsize;
-  GST_BUFFER_OFFSET (buf) = src->curoffset;
-  GST_BUFFER_OFFSET_END (buf) = src->curoffset + readsize;
-  src->curoffset += readsize;
+  length = ret;
 
-  return GST_DATA (buf);
-}
+  GST_BUFFER_SIZE (buf) = length;
+  GST_BUFFER_MAXSIZE (buf) = length;
+  GST_BUFFER_OFFSET (buf) = offset;
+  GST_BUFFER_OFFSET_END (buf) = offset + length;
 
-static GstFlowReturn
-gst_filesrc_getrange (GstPad * pad, guint64 offset, guint length,
-    GstBuffer ** buffer)
-{
-  GstFileSrc *src;
+  *buffer = buf;
 
-  src = GST_FILESRC (GST_PAD_PARENT (pad));
+  src->read_position += length;
 
-  src->curoffset = offset;
-  src->block_size = length;
+  return GST_FLOW_OK;
 
-  return gst_filesrc_get (pad, buffer);
+  /* ERROR */
+seek_failed:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
+    return GST_FLOW_ERROR;
+  }
+could_not_read:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+unexpected_eos:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
+        ("unexpected end of file."));
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
 }
 
 static GstFlowReturn
-gst_filesrc_get (GstPad * pad, GstBuffer ** buffer)
+gst_filesrc_create (GstBaseSrc * basesrc, guint64 offset, guint length,
+    GstBuffer ** buffer)
 {
   GstFileSrc *src;
-  GstData *data;
-
-  src = GST_FILESRC (GST_PAD_PARENT (pad));
-
-  g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_FILESRC_OPEN),
-      GST_FLOW_WRONG_STATE);
-
-  /* check for flush */
-  if (src->need_flush) {
-    src->need_flush = FALSE;
-    GST_DEBUG_OBJECT (src, "sending flush");
-    gst_pad_push_event (pad, gst_event_new_flush (TRUE));
-  }
-  /* check for seek */
-  if (src->need_discont) {
-    GstEvent *event;
-
-    GST_DEBUG_OBJECT (src, "sending discont");
-    event =
-        gst_event_new_discontinuous (src->need_discont > 1, GST_FORMAT_BYTES,
-        (guint64) src->curoffset, GST_FORMAT_UNDEFINED);
-    src->need_discont = 0;
-    gst_pad_push_event (pad, event);
-  }
+  GstFlowReturn ret;
 
-  /* check for EOF if it's a regular file */
-  if (src->is_regular) {
-    g_assert (src->curoffset <= src->filelen);
-    if (src->curoffset == src->filelen) {
-      if (!gst_filesrc_check_filesize (src) || src->curoffset >= src->filelen) {
-        GST_DEBUG_OBJECT (src, "eos %" G_GINT64_FORMAT " %" G_GINT64_FORMAT,
-            src->curoffset, src->filelen);
-      }
-      //gst_element_set_eos (GST_ELEMENT (src));
-      gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
-      return GST_FLOW_WRONG_STATE;
+  src = GST_FILESRC (basesrc);
 
-    }
-  }
 #ifdef HAVE_MMAP
   if (src->using_mmap) {
-    data = gst_filesrc_get_mmap (src);
+    ret = gst_filesrc_create_mmap (src, offset, length, buffer);
   } else {
-    data = gst_filesrc_get_read (src);
+    ret = gst_filesrc_create_read (src, offset, length, buffer);
   }
 #else
-  data = gst_filesrc_get_read (src);
+  ret = gst_filesrc_create_read (src, offset, length, buffer);
 #endif
-  if (data == NULL) {
-    GST_DEBUG_OBJECT (src, "could not get data");
-    return GST_FLOW_ERROR;
-  }
 
-  if (GST_IS_EVENT (data)) {
-    gst_pad_push_event (pad, GST_EVENT (data));
-  } else {
-    *buffer = GST_BUFFER (data);
-  }
-
-  return GST_FLOW_OK;
+  return ret;
 }
 
-/* TRUE if the filesize of the file was updated */
 static gboolean
-gst_filesrc_check_filesize (GstFileSrc * src)
+gst_filesrc_get_size (GstBaseSrc * basesrc, guint64 * size)
 {
   struct stat stat_results;
+  GstFileSrc *src;
 
-  g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_FILESRC_OPEN), FALSE);
+  src = GST_FILESRC (basesrc);
+
+  if (fstat (src->fd, &stat_results) < 0)
+    goto could_not_stat;
+
+  *size = stat_results.st_size;
 
-  fstat (src->fd, &stat_results);
-  GST_DEBUG_OBJECT (src,
-      "checked filesize on %s (was %" G_GUINT64_FORMAT ", is %" G_GUINT64_FORMAT
-      ")", src->filename, src->filelen, (guint64) stat_results.st_size);
-  if (src->filelen == (guint64) stat_results.st_size)
-    return FALSE;
-  src->filelen = stat_results.st_size;
   return TRUE;
+
+  /* ERROR */
+could_not_stat:
+  {
+    return FALSE;
+  }
 }
 
 /* open the file and mmap it, necessary to go to READY state */
 static gboolean
-gst_filesrc_open_file (GstFileSrc * src)
+gst_filesrc_start (GstBaseSrc * basesrc)
 {
-  g_return_val_if_fail (!GST_FLAG_IS_SET (src, GST_FILESRC_OPEN), FALSE);
-
-  if (src->filename == NULL || src->filename[0] == '\0') {
-    GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
-        (_("No file name specified for reading.")), (NULL));
-    return FALSE;
-  }
+  GstFileSrc *src = GST_FILESRC (basesrc);
+  struct stat stat_results;
 
+  if (src->filename == NULL || src->filename[0] == '\0')
+    goto no_filename;
 
   GST_INFO_OBJECT (src, "opening file %s", src->filename);
 
   /* open the file */
   src->fd = open (src->filename, O_RDONLY | O_BINARY);
-  if (src->fd < 0) {
-    if (errno == ENOENT)
-      GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),
-          ("No such file \"%s\"", src->filename));
-    else
-      GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
-          (_("Could not open file \"%s\" for reading."), src->filename),
-          GST_ERROR_SYSTEM);
-    return FALSE;
-  } else {
-    /* check if it is a regular file, otherwise bail out */
-    struct stat stat_results;
+  if (src->fd < 0)
+    goto open_failed;
 
-    fstat (src->fd, &stat_results);
+  /* check if it is a regular file, otherwise bail out */
+  if (fstat (src->fd, &stat_results) < 0)
+    goto no_stat;
 
-    if (S_ISDIR (stat_results.st_mode)) {
-      GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
-          (_("\"%s\" is a directory."), src->filename), (NULL));
-      close (src->fd);
-      return FALSE;
-    }
-    if (S_ISSOCK (stat_results.st_mode)) {
-      GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
-          (_("File \"%s\" is a socket."), src->filename), (NULL));
-      close (src->fd);
-      return FALSE;
-    }
+  if (S_ISDIR (stat_results.st_mode))
+    goto was_directory;
 
-    /* find the file length */
-    src->filelen = stat_results.st_size;
+  if (S_ISSOCK (stat_results.st_mode))
+    goto was_socket;
 
-    src->using_mmap = FALSE;
+  src->using_mmap = FALSE;
+  src->read_position = 0;
+
+  /* record if it's a regular (hence seekable and lengthable) file */
+  if (S_ISREG (stat_results.st_mode))
+    src->is_regular = TRUE;
 
-    /* record if it's a regular (hence seekable and lengthable) file */
-    if (S_ISREG (stat_results.st_mode))
-      src->is_regular = TRUE;
 #ifdef HAVE_MMAP
-    /* FIXME: maybe we should only try to mmap if it's a regular file */
-    /* allocate the first mmap'd region if it's a regular file ? */
-    src->mapbuf = gst_filesrc_map_region (src, 0, src->mapsize);
-    if (src->mapbuf != NULL) {
-      GST_DEBUG_OBJECT (src, "using mmap for file");
-      src->using_mmap = TRUE;
-    }
+  /* FIXME: maybe we should only try to mmap if it's a regular file */
+  /* allocate the first mmap'd region if it's a regular file ? */
+  src->mapbuf = gst_filesrc_map_region (src, 0, src->mapsize);
+  if (src->mapbuf != NULL) {
+    GST_DEBUG_OBJECT (src, "using mmap for file");
+    src->using_mmap = TRUE;
+  }
 #endif
 
-    src->curoffset = 0;
-
-    GST_FLAG_SET (src, GST_FILESRC_OPEN);
-
-    {
-      GstCaps *caps;
-      guint64 offset;
-      guint length;
-
-      offset = src->curoffset;
-      length = src->block_size;
-
-      caps = gst_filesrc_type_find (src);
-      gst_pad_set_caps (src->srcpad, caps);
+  return TRUE;
 
-      src->curoffset = offset;
-      src->block_size = length;
+  /* ERROR */
+no_filename:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
+        (_("No file name specified for reading.")), (NULL));
+    return FALSE;
+  }
+open_failed:
+  {
+    switch (errno) {
+      case ENOENT:
+        GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),
+            ("No such file \"%s\"", src->filename));
+        break;
+      default:
+        GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+            (_("Could not open file \"%s\" for reading."), src->filename),
+            GST_ERROR_SYSTEM);
+        break;
     }
-
+    return FALSE;
+  }
+no_stat:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+        (_("could not get info on \"%s\"."), src->filename), (NULL));
+    close (src->fd);
+    return FALSE;
+  }
+was_directory:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+        (_("\"%s\" is a directory."), src->filename), (NULL));
+    close (src->fd);
+    return FALSE;
+  }
+was_socket:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+        (_("File \"%s\" is a socket."), src->filename), (NULL));
+    close (src->fd);
+    return FALSE;
   }
-  return TRUE;
 }
 
 /* unmap and close the file */
-static void
-gst_filesrc_close_file (GstFileSrc * src)
+static gboolean
+gst_filesrc_stop (GstBaseSrc * basesrc)
 {
-  g_return_if_fail (GST_FLAG_IS_SET (src, GST_FILESRC_OPEN));
+  GstFileSrc *src = GST_FILESRC (basesrc);
 
   /* close the file */
   close (src->fd);
 
   /* zero out a lot of our state */
   src->fd = 0;
-  src->filelen = 0;
-  src->curoffset = 0;
   src->is_regular = FALSE;
 
   if (src->mapbuf) {
@@ -895,339 +843,9 @@ gst_filesrc_close_file (GstFileSrc * src)
     src->mapbuf = NULL;
   }
 
-  GST_FLAG_UNSET (src, GST_FILESRC_OPEN);
-}
-
-static void
-gst_filesrc_loop (GstPad * pad)
-{
-  GstFileSrc *filesrc;
-  gboolean result;
-  GstBuffer *buffer;
-
-  filesrc = GST_FILESRC (GST_PAD_PARENT (pad));
-
-  GST_STREAM_LOCK (pad);
-
-  result = gst_filesrc_get (pad, &buffer);
-  if (result != GST_FLOW_OK)
-    goto need_pause;
-
-  result = gst_pad_push (pad, buffer);
-  if (result != GST_FLOW_OK)
-    goto need_pause;
-
-  GST_STREAM_UNLOCK (pad);
-  return;
-
-need_pause:
-  {
-    gst_task_pause (GST_RPAD_TASK (pad));
-    GST_STREAM_UNLOCK (pad);
-    return;
-  }
-}
-
-
-static gboolean
-gst_filesrc_activate (GstPad * pad, GstActivateMode mode)
-{
-  gboolean result = FALSE;
-  GstFileSrc *filesrc;
-
-  filesrc = GST_FILESRC (GST_OBJECT_PARENT (pad));
-
-  switch (mode) {
-    case GST_ACTIVATE_PUSH:
-      /* if we have a scheduler we can start the task */
-      if (GST_ELEMENT_SCHEDULER (filesrc)) {
-        GST_STREAM_LOCK (pad);
-        GST_RPAD_TASK (pad) =
-            gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (filesrc),
-            (GstTaskFunction) gst_filesrc_loop, pad);
-
-        gst_task_start (GST_RPAD_TASK (pad));
-        result = TRUE;
-        GST_STREAM_UNLOCK (pad);
-      }
-      break;
-    case GST_ACTIVATE_PULL:
-      result = TRUE;
-      break;
-    case GST_ACTIVATE_NONE:
-      /* step 1, unblock clock sync (if any) */
-
-      /* step 2, make sure streaming finishes */
-      GST_STREAM_LOCK (pad);
-      /* step 3, stop the task */
-      gst_task_stop (GST_RPAD_TASK (pad));
-      GST_STREAM_UNLOCK (pad);
-
-      result = TRUE;
-      break;
-  }
-  return result;
-}
-
-
-static GstElementStateReturn
-gst_filesrc_change_state (GstElement * element)
-{
-  GstElementStateReturn result = GST_STATE_SUCCESS;
-
-  GstFileSrc *src = GST_FILESRC (element);
-
-  switch (GST_STATE_TRANSITION (element)) {
-    case GST_STATE_NULL_TO_READY:
-      break;
-    case GST_STATE_READY_TO_NULL:
-      break;
-    case GST_STATE_READY_TO_PAUSED:
-      if (!GST_FLAG_IS_SET (element, GST_FILESRC_OPEN)) {
-        if (!gst_filesrc_open_file (GST_FILESRC (element)))
-          return GST_STATE_FAILURE;
-      }
-      src->need_discont = 2;
-      break;
-    case GST_STATE_PAUSED_TO_PLAYING:
-      gst_task_start (GST_RPAD_TASK (src->srcpad));
-      break;
-  }
-
-  result = GST_ELEMENT_CLASS (parent_class)->change_state (element);
-
-  switch (GST_STATE_TRANSITION (element)) {
-    case GST_STATE_PLAYING_TO_PAUSED:
-      gst_task_start (GST_RPAD_TASK (src->srcpad));
-      break;
-    case GST_STATE_PAUSED_TO_READY:
-      if (GST_FLAG_IS_SET (element, GST_FILESRC_OPEN))
-        gst_filesrc_close_file (GST_FILESRC (element));
-      break;
-    default:
-      break;
-  }
-
-  return result;
-}
-
-static gboolean
-gst_filesrc_srcpad_query (GstPad * pad, GstQueryType type,
-    GstFormat * format, gint64 * value)
-{
-  GstFileSrc *src = GST_FILESRC (GST_PAD_PARENT (pad));
-
-  if (*format == GST_FORMAT_DEFAULT)
-    *format = GST_FORMAT_BYTES;
-
-  switch (type) {
-    case GST_QUERY_TOTAL:
-      if (*format != GST_FORMAT_BYTES) {
-        return FALSE;
-      }
-      if (!src->is_regular)
-        return FALSE;
-      gst_filesrc_check_filesize (src);
-      *value = src->filelen;
-      break;
-    case GST_QUERY_POSITION:
-      switch (*format) {
-        case GST_FORMAT_BYTES:
-          *value = src->curoffset;
-          break;
-        case GST_FORMAT_PERCENT:
-          if (src->filelen == 0)
-            return FALSE;
-          if (!src->is_regular)
-            return FALSE;
-          *value = src->curoffset * GST_FORMAT_PERCENT_MAX / src->filelen;
-          break;
-        default:
-          return FALSE;
-      }
-      break;
-    default:
-      return FALSE;
-      break;
-  }
   return TRUE;
 }
 
-static gboolean
-gst_filesrc_srcpad_event (GstPad * pad, GstEvent * event)
-{
-  GstFileSrc *src = GST_FILESRC (GST_PAD_PARENT (pad));
-
-  GST_DEBUG_OBJECT (src, "received event type %d", GST_EVENT_TYPE (event));
-
-  switch (GST_EVENT_TYPE (event)) {
-    case GST_EVENT_SEEK:
-    {
-      gint64 offset;
-
-      if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES &&
-          GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_DEFAULT) {
-        goto error;
-      }
-      if (!src->is_regular) {
-        GST_DEBUG ("can't handle seek on a non-regular file");
-        goto error;
-      }
-
-      offset = GST_EVENT_SEEK_OFFSET (event);
-
-      switch (GST_EVENT_SEEK_METHOD (event)) {
-        case GST_SEEK_METHOD_SET:
-          if (offset < 0) {
-            goto error;
-          } else if (offset > src->filelen && (!gst_filesrc_check_filesize (src)
-                  || offset > src->filelen)) {
-            src->curoffset = src->filelen;
-          } else {
-            src->curoffset = offset;
-          }
-          GST_DEBUG_OBJECT (src, "seek set pending to %" G_GINT64_FORMAT,
-              src->curoffset);
-          break;
-        case GST_SEEK_METHOD_CUR:
-          if (offset + src->curoffset > src->filelen &&
-              (!gst_filesrc_check_filesize (src)
-                  || offset + src->curoffset > src->filelen)) {
-            src->curoffset = src->filelen;
-          } else if (offset + src->curoffset < 0) {
-            src->curoffset = 0;
-          } else {
-            src->curoffset += offset;
-          }
-          GST_DEBUG_OBJECT (src, "seek cur pending to %" G_GINT64_FORMAT,
-              src->curoffset);
-          break;
-        case GST_SEEK_METHOD_END:
-          if (offset > 0) {
-            goto error;
-          } else if (offset > src->filelen && (!gst_filesrc_check_filesize (src)
-                  || offset > src->filelen)) {
-            src->curoffset = 0;
-          } else {
-            src->curoffset = src->filelen + offset;
-          }
-          GST_DEBUG_OBJECT (src, "seek end pending to %" G_GINT64_FORMAT,
-              src->curoffset);
-          break;
-        default:
-          goto error;
-          break;
-      }
-      src->need_discont = 1;
-      src->need_flush = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH;
-      break;
-    }
-    case GST_EVENT_SIZE:
-      if (GST_EVENT_SIZE_FORMAT (event) != GST_FORMAT_BYTES) {
-        goto error;
-      }
-      src->block_size = GST_EVENT_SIZE_VALUE (event);
-      g_object_notify (G_OBJECT (src), "blocksize");
-      break;
-    case GST_EVENT_FLUSH:
-      src->need_flush = TRUE;
-      break;
-    default:
-      goto error;
-      break;
-  }
-  gst_event_unref (event);
-  return TRUE;
-
-error:
-  gst_event_unref (event);
-  return FALSE;
-}
-
-typedef struct
-{
-  GstFileSrc *src;
-  guint best_probability;
-  GstCaps *caps;
-
-  GstBuffer *buffer;
-}
-FileSrcTypeFind;
-
-static guint8 *
-filesrc_find_peek (gpointer data, gint64 offset, guint size)
-{
-  FileSrcTypeFind *find;
-  GstBuffer *buffer;
-  GstFileSrc *src;
-
-  if (size == 0)
-    return NULL;
-
-  find = (FileSrcTypeFind *) data;
-  src = find->src;
-
-  if (offset < 0) {
-    offset += src->filelen;
-  }
-
-  buffer = NULL;
-  gst_filesrc_getrange (src->srcpad, offset, size, &buffer);
-
-  if (find->buffer) {
-    gst_buffer_unref (find->buffer);
-  }
-  find->buffer = buffer;
-
-  return GST_BUFFER_DATA (buffer);
-}
-
-static void
-filesrc_find_suggest (gpointer data, guint probability, const GstCaps * caps)
-{
-  FileSrcTypeFind *find = (FileSrcTypeFind *) data;
-
-  if (probability > find->best_probability) {
-    gst_caps_replace (&find->caps, gst_caps_copy (caps));
-    find->best_probability = probability;
-  }
-}
-
-
-static GstCaps *
-gst_filesrc_type_find (GstFileSrc * src)
-{
-  GstTypeFind gst_find;
-  FileSrcTypeFind find;
-  GList *walk, *type_list = NULL;
-  GstCaps *result = NULL;
-
-  walk = type_list = gst_type_find_factory_get_list ();
-
-  find.src = src;
-  find.best_probability = 0;
-  find.caps = NULL;
-  find.buffer = NULL;
-  gst_find.data = &find;
-  gst_find.peek = filesrc_find_peek;
-  gst_find.suggest = filesrc_find_suggest;
-  gst_find.get_length = NULL;
-
-  while (walk) {
-    GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (walk->data);
-
-    gst_type_find_factory_call_function (factory, &gst_find);
-    if (find.best_probability >= GST_TYPE_FIND_MAXIMUM)
-      break;
-    walk = g_list_next (walk);
-  }
-
-  if (find.best_probability > 0)
-    result = find.caps;
-
-  return result;
-}
-
 /*** GSTURIHANDLER INTERFACE *************************************************/
 
 static guint
index 1723008..d4b2ca0 100644 (file)
@@ -1,6 +1,7 @@
 /* GStreamer
  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
  *                    2000 Wim Taymans <wtay@chello.be>
+ *                    2005 Wim Taymans <wim@fluendo.com>
  *
  * gstfilesrc.h: 
  *
  * Boston, MA 02111-1307, USA.
  */
 
-
 #ifndef __GST_FILESRC_H__
 #define __GST_FILESRC_H__
 
+#include <sys/types.h>
 
 #include <gst/gst.h>
-#include <sys/types.h>
+#include <gst/base/gstbasesrc.h>
 
 G_BEGIN_DECLS
 
-
 #define GST_TYPE_FILESRC \
   (gst_filesrc_get_type())
 #define GST_FILESRC(obj) \
@@ -42,42 +42,29 @@ G_BEGIN_DECLS
 #define GST_IS_FILESRC_CLASS(obj) \
   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FILESRC))
 
-typedef enum {
-  GST_FILESRC_OPEN              = GST_ELEMENT_FLAG_LAST,
-
-  GST_FILESRC_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2
-} GstFileSrcFlags;
-
 typedef struct _GstFileSrc GstFileSrc;
 typedef struct _GstFileSrcClass GstFileSrcClass;
 
 struct _GstFileSrc {
-  GstElement element;
-  GstPad *srcpad;
+  GstBaseSrc element;
 
   guint pagesize;                      /* system page size*/
  
   gchar *filename;                     /* filename */
   gchar *uri;                          /* caching the URI */
   gint fd;                             /* open file descriptor*/
-  off_t filelen;                       /* what's the file length?*/
+  guint64 read_position;               /* position of fd */
 
-  off_t curoffset;                     /* current offset in file*/
-  off_t block_size;                    /* bytes per read */
   gboolean touch;                      /* whether to touch every page */
   gboolean using_mmap;                  /* whether we opened it with mmap */
   gboolean is_regular;                  /* whether it's (symlink to)
                                            a regular file */
-
   GstBuffer *mapbuf;
   size_t mapsize;
-
-  gint need_discont;
-  gboolean need_flush;
 };
 
 struct _GstFileSrcClass {
-  GstElementClass parent_class;
+  GstBaseSrcClass parent_class;
 };
 
 GType gst_filesrc_get_type(void);
index 287e7a5..a72000a 100644 (file)
@@ -1987,8 +1987,8 @@ restart:
 
       /* see if the pad has a loop function and grab
        * the peer */
+      pad_get = gst_pad_check_pull_range (pad);
       GST_LOCK (pad);
-      pad_get = GST_RPAD_GETRANGEFUNC (pad) != NULL;
       pad_loop = GST_RPAD_LOOPFUNC (pad) != NULL;
       peer = GST_RPAD_PEER (pad);
       if (peer)
@@ -1999,7 +1999,7 @@ restart:
         gboolean peer_loop, peer_get;
 
         /* see if the peer has a getrange function */
-        peer_get = GST_RPAD_GETRANGEFUNC (peer) != NULL;
+        peer_get = gst_pad_check_pull_range (pad);
         /* see if the peer has a loop function */
         peer_loop = GST_RPAD_LOOPFUNC (peer) != NULL;
 
index c8f1f61..27cc978 100644 (file)
@@ -838,6 +838,27 @@ gst_pad_set_getrange_function (GstPad * pad, GstPadGetRangeFunction get)
 }
 
 /**
+ * gst_pad_set_checkgetrange_function:
+ * @pad: a real source #GstPad.
+ * @check: the #GstPadCheckGetRangeFunction to set.
+ *
+ * Sets the given checkgetrange function for the pad. Implement this function on
+ * a pad if you dynamically support getrange based scheduling on the pad.
+ */
+void
+gst_pad_set_checkgetrange_function (GstPad * pad,
+    GstPadCheckGetRangeFunction check)
+{
+  g_return_if_fail (GST_IS_REAL_PAD (pad));
+  g_return_if_fail (GST_RPAD_DIRECTION (pad) == GST_PAD_SRC);
+
+  GST_RPAD_CHECKGETRANGEFUNC (pad) = check;
+
+  GST_CAT_DEBUG (GST_CAT_PADS, "checkgetrangefunc for %s:%s  set to %s",
+      GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (check));
+}
+
+/**
  * gst_pad_set_event_function:
  * @pad: a real source #GstPad.
  * @event: the #GstPadEventFunction to set.
@@ -2980,11 +3001,11 @@ gst_pad_check_pull_range (GstPad * pad)
   gboolean ret;
   GstPadCheckGetRangeFunction checkgetrangefunc;
 
-  g_return_val_if_fail (GST_IS_REAL_PAD (pad), GST_FLOW_ERROR);
-  g_return_val_if_fail (GST_RPAD_DIRECTION (pad) == GST_PAD_SINK,
-      GST_FLOW_ERROR);
+  g_return_val_if_fail (GST_IS_REAL_PAD (pad), FALSE);
 
   GST_LOCK (pad);
+  if (GST_RPAD_DIRECTION (pad) != GST_PAD_SINK)
+    goto wrong_direction;
 
   if (G_UNLIKELY ((peer = GST_RPAD_PEER (pad)) == NULL))
     goto not_connected;
@@ -2993,33 +3014,31 @@ gst_pad_check_pull_range (GstPad * pad)
   GST_UNLOCK (pad);
 
   /* see note in above function */
-  if (G_UNLIKELY ((checkgetrangefunc = peer->checkgetrangefunc) == NULL))
-    goto no_function;
-
-  GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
-      "calling checkgetrangefunc %s of peer pad %s:%s",
-      GST_DEBUG_FUNCPTR_NAME (checkgetrangefunc), GST_DEBUG_PAD_NAME (peer));
+  if (G_LIKELY ((checkgetrangefunc = peer->checkgetrangefunc) == NULL)) {
+    ret = GST_RPAD_GETRANGEFUNC (peer) != NULL;
+  } else {
+    GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+        "calling checkgetrangefunc %s of peer pad %s:%s",
+        GST_DEBUG_FUNCPTR_NAME (checkgetrangefunc), GST_DEBUG_PAD_NAME (peer));
 
-  ret = checkgetrangefunc (GST_PAD_CAST (peer));
+    ret = checkgetrangefunc (GST_PAD_CAST (peer));
+  }
 
   gst_object_unref (GST_OBJECT_CAST (peer));
 
   return ret;
 
   /* ERROR recovery here */
-not_connected:
+wrong_direction:
   {
-    GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
-        "checkinh pull range, but it was not linked");
     GST_UNLOCK (pad);
     return FALSE;
   }
-no_function:
+not_connected:
   {
-    GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL),
-        ("pad %s:%s checked pull_range but the peer pad %s:%s has no checkgetrangefunction",
-            GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (peer)));
-    gst_object_unref (GST_OBJECT (peer));
+    GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+        "checking pull range, but it was not linked");
+    GST_UNLOCK (pad);
     return FALSE;
   }
 }
index 7cfd561..97b8a14 100644 (file)
@@ -484,6 +484,7 @@ void                        gst_pad_set_activate_function           (GstPad *pad, GstPadActivateFunction activ
 void                   gst_pad_set_loop_function               (GstPad *pad, GstPadLoopFunction loop);
 void                   gst_pad_set_chain_function              (GstPad *pad, GstPadChainFunction chain);
 void                   gst_pad_set_getrange_function           (GstPad *pad, GstPadGetRangeFunction get);
+void                   gst_pad_set_checkgetrange_function      (GstPad *pad, GstPadCheckGetRangeFunction check);
 void                   gst_pad_set_event_function              (GstPad *pad, GstPadEventFunction event);
 void                   gst_pad_set_event_mask_function         (GstPad *pad, GstPadEventMaskFunction mask_func);
 G_CONST_RETURN GstEventMask*
index 3384a24..2633218 100644 (file)
@@ -33,3 +33,4 @@ GstBaseSrc
   - one sinkpad
   - handles state changes
   - pull/push mode
+  - handles seeking/query
index 4d69e99..7ff18ba 100644 (file)
@@ -1,7 +1,6 @@
 /* GStreamer
  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- *                    2000 Wim Taymans <wtay@chello.be>
- *                    2005 Wim Taymans <wim@fluendo.com>
+ *               2000,2005 Wim Taymans <wim@fluendo.com>
  *
  * gstbasesrc.c: 
  *
@@ -92,12 +91,20 @@ static gboolean gst_basesrc_query (GstPad * pad, GstQueryType type,
     GstFormat * format, gint64 * value);
 static const GstFormat *gst_basesrc_get_formats (GstPad * pad);
 
+static gboolean gst_basesrc_unlock (GstBaseSrc * basesrc);
+static gboolean gst_basesrc_get_size (GstBaseSrc * basesrc, guint64 * size);
+static gboolean gst_basesrc_start (GstBaseSrc * basesrc);
+static gboolean gst_basesrc_stop (GstBaseSrc * basesrc);
+
 static GstElementStateReturn gst_basesrc_change_state (GstElement * element);
 
 static void gst_basesrc_loop (GstPad * pad);
+static gboolean gst_basesrc_check_get_range (GstPad * pad);
 static GstFlowReturn gst_basesrc_get_range (GstPad * pad, guint64 offset,
     guint length, GstBuffer ** buf);
 
+static GstCaps *gst_basesrc_type_find (GstBaseSrc * src);
+
 static void
 gst_basesrc_base_init (gpointer g_class)
 {
@@ -145,12 +152,17 @@ gst_basesrc_init (GstBaseSrc * basesrc, gpointer g_class)
   gst_pad_set_query_type_function (pad, gst_basesrc_get_query_types);
   gst_pad_set_formats_function (pad, gst_basesrc_get_formats);
   gst_pad_set_loop_function (pad, gst_basesrc_loop);
+  gst_pad_set_checkgetrange_function (pad, gst_basesrc_check_get_range);
   gst_pad_set_getrange_function (pad, gst_basesrc_get_range);
+  /* hold ref to pad */
+  basesrc->srcpad = pad;
   gst_element_add_pad (GST_ELEMENT (basesrc), pad);
 
   basesrc->segment_start = -1;
   basesrc->segment_end = -1;
   basesrc->blocksize = DEFAULT_BLOCKSIZE;
+
+  GST_FLAG_UNSET (basesrc, GST_BASESRC_STARTED);
 }
 
 static const GstFormat *
@@ -158,6 +170,7 @@ gst_basesrc_get_formats (GstPad * pad)
 {
   static const GstFormat formats[] = {
     GST_FORMAT_DEFAULT,
+    GST_FORMAT_BYTES,
     0,
   };
 
@@ -184,32 +197,157 @@ gst_basesrc_query (GstPad * pad, GstQueryType type,
 {
   GstBaseSrc *src = GST_BASESRC (GST_PAD_PARENT (pad));
 
+  if (*format == GST_FORMAT_DEFAULT)
+    *format = GST_FORMAT_BYTES;
+
   switch (type) {
+    case GST_QUERY_TOTAL:
+      switch (*format) {
+        case GST_FORMAT_BYTES:
+        {
+          gboolean ret;
+
+          ret = gst_basesrc_get_size (src, value);
+          GST_DEBUG ("getting length %d %lld", ret, *value);
+          return ret;
+        }
+        case GST_FORMAT_PERCENT:
+          *value = GST_FORMAT_PERCENT_MAX;
+          return TRUE;
+        default:
+          return FALSE;
+      }
+      break;
+    case GST_QUERY_POSITION:
+      switch (*format) {
+        case GST_FORMAT_BYTES:
+          *value = src->offset;
+          break;
+        case GST_FORMAT_PERCENT:
+          if (!gst_basesrc_get_size (src, value))
+            return FALSE;
+          *value = src->offset * GST_FORMAT_PERCENT_MAX / *value;
+          return TRUE;
+        default:
+          return FALSE;
+      }
+      break;
     case GST_QUERY_START:
       *value = src->segment_start;
-      break;
+      return TRUE;
     case GST_QUERY_SEGMENT_END:
       *value = src->segment_end;
-      break;
+      return TRUE;
     default:
       return FALSE;
   }
-  return TRUE;
+  return FALSE;
 }
 
 static const GstEventMask *
 gst_basesrc_get_event_mask (GstPad * pad)
 {
   static const GstEventMask masks[] = {
-    {GST_EVENT_SEEK, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT_LOOP},
+    {GST_EVENT_SEEK, GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_SET |
+          GST_SEEK_METHOD_END | GST_SEEK_FLAG_FLUSH |
+          GST_SEEK_FLAG_SEGMENT_LOOP},
     {GST_EVENT_FLUSH, 0},
+    {GST_EVENT_SIZE, 0},
     {0, 0},
   };
-
   return masks;
 }
 
 static gboolean
+gst_basesrc_do_seek (GstBaseSrc * src, GstEvent * event)
+{
+  GstFormat format;
+  gint64 offset;
+
+  format = GST_EVENT_SEEK_FORMAT (event);
+
+  /* get seek format */
+  if (format == GST_FORMAT_DEFAULT)
+    format = GST_FORMAT_BYTES;
+  /* we can only seek bytes */
+  if (format != GST_FORMAT_BYTES)
+    return FALSE;
+
+  /* get seek positions */
+  offset = GST_EVENT_SEEK_OFFSET (event);
+  src->segment_start = offset;
+  src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
+  src->segment_loop = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_SEGMENT_LOOP;
+
+  /* send flush start */
+  gst_pad_push_event (src->srcpad, gst_event_new_flush (FALSE));
+
+  /* unblock streaming thread */
+  gst_basesrc_unlock (src);
+
+  /* grab streaming lock */
+  GST_STREAM_LOCK (src->srcpad);
+
+  switch (GST_EVENT_SEEK_METHOD (event)) {
+    case GST_SEEK_METHOD_SET:
+      if (offset < 0)
+        goto error;
+      src->offset = MIN (offset, src->size);
+      GST_DEBUG_OBJECT (src, "seek set pending to %" G_GINT64_FORMAT,
+          src->offset);
+      break;
+    case GST_SEEK_METHOD_CUR:
+      offset += src->offset;
+      src->offset = CLAMP (offset, 0, src->size);
+      GST_DEBUG_OBJECT (src, "seek cur pending to %" G_GINT64_FORMAT,
+          src->offset);
+      break;
+    case GST_SEEK_METHOD_END:
+      if (offset > 0)
+        goto error;
+      offset = src->size + offset;
+      src->offset = MAX (0, offset);
+      GST_DEBUG_OBJECT (src, "seek end pending to %" G_GINT64_FORMAT,
+          src->offset);
+      break;
+    default:
+      goto error;
+  }
+  /* send flush end */
+  gst_pad_push_event (src->srcpad, gst_event_new_flush (TRUE));
+
+  /* now send discont */
+  {
+    GstEvent *event;
+
+    event = gst_event_new_discontinuous (1.0,
+        GST_FORMAT_TIME,
+        (gint64) src->segment_start, (gint64) src->segment_end, NULL);
+
+    gst_pad_push_event (src->srcpad, event);
+  }
+
+  /* and restart the task */
+  if (GST_RPAD_TASK (src->srcpad)) {
+    gst_task_start (GST_RPAD_TASK (src->srcpad));
+  }
+  GST_STREAM_UNLOCK (src->srcpad);
+
+  gst_event_unref (event);
+
+  return TRUE;
+
+  /* ERROR */
+error:
+  {
+    GST_DEBUG_OBJECT (src, "seek error");
+    GST_STREAM_UNLOCK (src->srcpad);
+    gst_event_unref (event);
+    return FALSE;
+  }
+}
+
+static gboolean
 gst_basesrc_event_handler (GstPad * pad, GstEvent * event)
 {
   GstBaseSrc *src;
@@ -218,12 +356,26 @@ gst_basesrc_event_handler (GstPad * pad, GstEvent * event)
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_SEEK:
-      src->segment_start = GST_EVENT_SEEK_OFFSET (event);
-      src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
-      src->segment_loop =
-          GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_SEGMENT_LOOP;
+      return gst_basesrc_do_seek (src, event);
+    case GST_EVENT_SIZE:
+    {
+      GstFormat format;
+
+      format = GST_EVENT_SIZE_FORMAT (event);
+      if (format == GST_FORMAT_DEFAULT)
+        format = GST_FORMAT_BYTES;
+      /* we can only accept bytes */
+      if (format != GST_FORMAT_BYTES)
+        return FALSE;
+
+      src->blocksize = GST_EVENT_SIZE_VALUE (event);
+      g_object_notify (G_OBJECT (src), "blocksize");
       break;
+    }
     case GST_EVENT_FLUSH:
+      /* cancel any blocking getrange */
+      if (!GST_EVENT_FLUSH_DONE (event))
+        gst_basesrc_unlock (src);
       break;
     default:
       break;
@@ -280,12 +432,41 @@ gst_basesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length,
   src = GST_BASESRC (GST_OBJECT_PARENT (pad));
   bclass = GST_BASESRC_GET_CLASS (src);
 
-  if (bclass->create)
-    ret = bclass->create (src, offset, length, buf);
-  else
-    ret = GST_FLOW_ERROR;
+  if (!GST_FLAG_IS_SET (src, GST_BASESRC_STARTED))
+    goto not_started;
+
+  if (!bclass->create)
+    goto no_function;
+
+  /* check size */
+  if (src->size != -1) {
+    if (offset + length > src->size) {
+      if (bclass->get_size)
+        bclass->get_size (src, &src->size);
+
+      if (offset + length > src->size) {
+        length = src->size - offset;
+      }
+    }
+  }
+  if (length == 0)
+    return GST_FLOW_UNEXPECTED;
+
+  ret = bclass->create (src, offset, length, buf);
 
   return ret;
+
+  /* ERROR */
+not_started:
+  {
+    GST_DEBUG_OBJECT (src, "getrange but not started");
+    return GST_FLOW_WRONG_STATE;
+  }
+no_function:
+  {
+    GST_DEBUG_OBJECT (src, "no create function");
+    return GST_FLOW_ERROR;
+  }
 }
 
 static GstFlowReturn
@@ -303,6 +484,21 @@ gst_basesrc_get_range (GstPad * pad, guint64 offset, guint length,
   return fret;
 }
 
+static gboolean
+gst_basesrc_check_get_range (GstPad * pad)
+{
+  GstBaseSrc *src;
+
+  src = GST_BASESRC (GST_OBJECT_PARENT (pad));
+
+  if (!GST_FLAG_IS_SET (src, GST_BASESRC_STARTED)) {
+    gst_basesrc_start (src);
+    gst_basesrc_stop (src);
+  }
+
+  return src->seekable;
+}
+
 static void
 gst_basesrc_loop (GstPad * pad)
 {
@@ -314,11 +510,9 @@ gst_basesrc_loop (GstPad * pad)
 
   GST_STREAM_LOCK (pad);
 
-  ret =
-      gst_basesrc_get_range_unlocked (pad, src->offset, DEFAULT_BLOCKSIZE,
-      &buf);
+  ret = gst_basesrc_get_range_unlocked (pad, src->offset, src->blocksize, &buf);
   if (ret != GST_FLOW_OK)
-    goto pause;
+    goto eos;
 
   src->offset += GST_BUFFER_SIZE (buf);
 
@@ -329,8 +523,17 @@ gst_basesrc_loop (GstPad * pad)
   GST_STREAM_UNLOCK (pad);
   return;
 
+eos:
+  {
+    GST_DEBUG_OBJECT (src, "going to EOS");
+    gst_task_pause (GST_RPAD_TASK (pad));
+    gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
+    GST_STREAM_UNLOCK (pad);
+    return;
+  }
 pause:
   {
+    GST_DEBUG_OBJECT (src, "pausing task");
     gst_task_pause (GST_RPAD_TASK (pad));
     GST_STREAM_UNLOCK (pad);
     return;
@@ -338,13 +541,134 @@ pause:
 }
 
 static gboolean
-gst_basesrc_activate (GstPad * pad, GstActivateMode mode)
+gst_basesrc_unlock (GstBaseSrc * basesrc)
+{
+  GstBaseSrcClass *bclass;
+  gboolean result = FALSE;
+
+  bclass = GST_BASESRC_GET_CLASS (basesrc);
+  if (bclass->unlock)
+    result = bclass->unlock (basesrc);
+
+  return result;
+}
+
+static gboolean
+gst_basesrc_get_size (GstBaseSrc * basesrc, guint64 * size)
 {
+  GstBaseSrcClass *bclass;
   gboolean result = FALSE;
+
+  bclass = GST_BASESRC_GET_CLASS (basesrc);
+  if (bclass->get_size)
+    result = bclass->get_size (basesrc, size);
+
+  if (result)
+    basesrc->size = *size;
+
+  return result;
+}
+
+static gboolean
+gst_basesrc_start (GstBaseSrc * basesrc)
+{
+  GstBaseSrcClass *bclass;
+  gboolean result;
+
+  if (GST_FLAG_IS_SET (basesrc, GST_BASESRC_STARTED))
+    return TRUE;
+
+  bclass = GST_BASESRC_GET_CLASS (basesrc);
+  if (bclass->start)
+    result = bclass->start (basesrc);
+  else
+    result = TRUE;
+
+  if (!result)
+    goto could_not_start;
+
+  GST_FLAG_SET (basesrc, GST_BASESRC_STARTED);
+
+  /* start in the beginning */
+  basesrc->offset = 0;
+  basesrc->segment_start = 0;
+
+  /* figure out the size */
+  if (bclass->get_size)
+    result = bclass->get_size (basesrc, &basesrc->size);
+  else
+    result = FALSE;
+
+  GST_DEBUG ("size %lld", basesrc->size);
+
+  /* we always run to the end */
+  basesrc->segment_end = -1;
+
+  /* check if we can seek */
+  if (bclass->is_seekable)
+    basesrc->seekable = bclass->is_seekable (basesrc);
+  else
+    basesrc->seekable = FALSE;
+
+  /* run typefind */
+  if (basesrc->seekable) {
+    GstCaps *caps;
+
+    caps = gst_basesrc_type_find (basesrc);
+    gst_pad_set_caps (basesrc->srcpad, caps);
+  }
+  return TRUE;
+
+  /* ERROR */
+could_not_start:
+  {
+    GST_DEBUG_OBJECT (basesrc, "could not start");
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_basesrc_stop (GstBaseSrc * basesrc)
+{
+  GstBaseSrcClass *bclass;
+  gboolean result = TRUE;
+
+  if (!GST_FLAG_IS_SET (basesrc, GST_BASESRC_STARTED))
+    return TRUE;
+
+  bclass = GST_BASESRC_GET_CLASS (basesrc);
+  if (bclass->stop)
+    result = bclass->stop (basesrc);
+
+  if (result)
+    GST_FLAG_UNSET (basesrc, GST_BASESRC_STARTED);
+
+  return result;
+}
+
+static gboolean
+gst_basesrc_activate (GstPad * pad, GstActivateMode mode)
+{
+  gboolean result;
   GstBaseSrc *basesrc;
 
   basesrc = GST_BASESRC (GST_OBJECT_PARENT (pad));
 
+  /* prepare subclass first */
+  switch (mode) {
+    case GST_ACTIVATE_PUSH:
+    case GST_ACTIVATE_PULL:
+      result = gst_basesrc_start (basesrc);
+      break;
+    default:
+      result = TRUE;
+      break;
+  }
+  /* if that failed we can stop here */
+  if (!result)
+    goto error_start;
+
+  result = FALSE;
   switch (mode) {
     case GST_ACTIVATE_PUSH:
       /* if we have a scheduler we can start the task */
@@ -379,6 +703,13 @@ gst_basesrc_activate (GstPad * pad, GstActivateMode mode)
       break;
   }
   return result;
+
+  /* ERROR */
+error_start:
+  {
+    GST_DEBUG_OBJECT (basesrc, "failed to start");
+    return FALSE;
+  }
 }
 
 static GstElementStateReturn
@@ -396,10 +727,7 @@ gst_basesrc_change_state (GstElement * element)
     case GST_STATE_NULL_TO_READY:
       break;
     case GST_STATE_READY_TO_PAUSED:
-    {
-      basesrc->offset = 0;
       break;
-    }
     case GST_STATE_PAUSED_TO_PLAYING:
       break;
     default:
@@ -412,6 +740,7 @@ gst_basesrc_change_state (GstElement * element)
     case GST_STATE_PLAYING_TO_PAUSED:
       break;
     case GST_STATE_PAUSED_TO_READY:
+      result = gst_basesrc_stop (basesrc);
       break;
     case GST_STATE_READY_TO_NULL:
       break;
@@ -421,3 +750,100 @@ gst_basesrc_change_state (GstElement * element)
 
   return result;
 }
+
+/**
+ * typefind code here
+ */
+typedef struct
+{
+  GstBaseSrc *src;
+  guint best_probability;
+  GstCaps *caps;
+
+  GstBuffer *buffer;
+}
+BaseSrcTypeFind;
+
+static guint8 *
+basesrc_find_peek (gpointer data, gint64 offset, guint size)
+{
+  BaseSrcTypeFind *find;
+  GstBuffer *buffer;
+  GstBaseSrc *src;
+  GstFlowReturn ret;
+
+  if (size == 0)
+    return NULL;
+
+  find = (BaseSrcTypeFind *) data;
+  src = find->src;
+
+  if (offset < 0) {
+    offset += src->size;
+  }
+
+  buffer = NULL;
+  ret = gst_basesrc_get_range_unlocked (src->srcpad, offset, size, &buffer);
+
+  if (find->buffer) {
+    gst_buffer_unref (find->buffer);
+    find->buffer = NULL;
+  }
+
+  if (ret != GST_FLOW_OK)
+    goto error;
+
+  find->buffer = buffer;
+
+  return GST_BUFFER_DATA (buffer);
+
+error:
+  {
+    return NULL;
+  }
+}
+
+static void
+basesrc_find_suggest (gpointer data, guint probability, const GstCaps * caps)
+{
+  BaseSrcTypeFind *find = (BaseSrcTypeFind *) data;
+
+  if (probability > find->best_probability) {
+    gst_caps_replace (&find->caps, gst_caps_copy (caps));
+    find->best_probability = probability;
+  }
+}
+
+static GstCaps *
+gst_basesrc_type_find (GstBaseSrc * src)
+{
+  GstTypeFind gst_find;
+  BaseSrcTypeFind find;
+  GList *walk, *type_list = NULL;
+  GstCaps *result = NULL;
+
+  walk = type_list = gst_type_find_factory_get_list ();
+
+  find.src = src;
+  find.best_probability = 0;
+  find.caps = NULL;
+  find.buffer = NULL;
+  gst_find.data = &find;
+  gst_find.peek = basesrc_find_peek;
+  gst_find.suggest = basesrc_find_suggest;
+  gst_find.get_length = NULL;
+
+  while (walk) {
+    GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (walk->data);
+
+    gst_type_find_factory_call_function (factory, &gst_find);
+    if (find.best_probability >= GST_TYPE_FIND_MAXIMUM)
+      break;
+    walk = g_list_next (walk);
+  }
+
+  if (find.best_probability > 0)
+    result = find.caps;
+
+  return result;
+}
index a2bfe74..8943fd9 100644 (file)
@@ -35,19 +35,30 @@ G_BEGIN_DECLS
 #define GST_IS_BASESRC(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASESRC))
 #define GST_IS_BASESRC_CLASS(obj)      (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASESRC))
 
+typedef enum {
+  GST_BASESRC_STARTED           = GST_ELEMENT_FLAG_LAST,
+
+  GST_BASESRC_FLAG_LAST         = GST_ELEMENT_FLAG_LAST + 2
+} GstFileSrcFlags;
+
+
 typedef struct _GstBaseSrc GstBaseSrc;
 typedef struct _GstBaseSrcClass GstBaseSrcClass;
 
 struct _GstBaseSrc {
   GstElement     element;
 
+  GstPad       *srcpad;
+
   gint                  blocksize;
 
   gint64        segment_start;
   gint64        segment_end;
   gboolean      segment_loop;
 
+  gboolean       seekable;
   guint64       offset;
+  guint64        size;
 };
 
 struct _GstBaseSrcClass {
@@ -62,6 +73,11 @@ struct _GstBaseSrcClass {
   void          (*get_times)    (GstBaseSrc *src, GstBuffer *buffer,
                                  GstClockTime *start, GstClockTime *end);
 
+  gboolean      (*get_size)     (GstBaseSrc *src, guint64 *size);
+
+  gboolean      (*is_seekable)  (GstBaseSrc *src);
+  gboolean      (*unlock)       (GstBaseSrc *src);
+
   gboolean      (*event)        (GstBaseSrc *src, GstEvent *event);
   GstFlowReturn (*create)       (GstBaseSrc *src, guint64 offset, guint size, 
                                 GstBuffer **buf);
index 4d4b2ff..2c60acd 100644 (file)
@@ -1,6 +1,6 @@
 /* GStreamer
  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- *                    2000 Wim Taymans <wtay@chello.be>
+ *               2000,2005 Wim Taymans <wim@fluendo.com>
  *
  * gstfilesrc.c:
  *
@@ -105,9 +105,6 @@ GstElementDetails gst_filesrc_details = GST_ELEMENT_DETAILS ("File Source",
     "Read from arbitrary point in a file",
     "Erik Walthinsen <omega@cse.ogi.edu>");
 
-#define DEFAULT_BLOCKSIZE      4*1024
-#define DEFAULT_MMAPSIZE       4*1024*1024
-
 /* FileSrc signals and args */
 enum
 {
@@ -115,72 +112,33 @@ enum
   LAST_SIGNAL
 };
 
+#define DEFAULT_BLOCKSIZE      4*1024
+#define DEFAULT_MMAPSIZE       4*1024*1024
+#define DEFAULT_TOUCH          FALSE
+
 enum
 {
   ARG_0,
   ARG_LOCATION,
   ARG_FD,
-  ARG_BLOCKSIZE,
   ARG_MMAPSIZE,
   ARG_TOUCH
 };
 
-static const GstEventMask *
-gst_filesrc_get_event_mask (GstPad * pad)
-{
-  static const GstEventMask masks[] = {
-    {GST_EVENT_SEEK, GST_SEEK_METHOD_CUR |
-          GST_SEEK_METHOD_SET | GST_SEEK_METHOD_END | GST_SEEK_FLAG_FLUSH},
-    {GST_EVENT_FLUSH, 0},
-    {GST_EVENT_SIZE, 0},
-    {0, 0}
-  };
-
-  return masks;
-}
-
-static const GstQueryType *
-gst_filesrc_get_query_types (GstPad * pad)
-{
-  static const GstQueryType types[] = {
-    GST_QUERY_TOTAL,
-    GST_QUERY_POSITION,
-    0
-  };
-
-  return types;
-}
-
-static const GstFormat *
-gst_filesrc_get_formats (GstPad * pad)
-{
-  static const GstFormat formats[] = {
-    GST_FORMAT_BYTES,
-    0,
-  };
-
-  return formats;
-}
-
-static void gst_filesrc_dispose (GObject * object);
+static void gst_filesrc_finalize (GObject * object);
 
 static void gst_filesrc_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec);
 static void gst_filesrc_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 
-static gboolean gst_filesrc_check_filesize (GstFileSrc * src);
-static GstFlowReturn gst_filesrc_get (GstPad * pad, GstBuffer ** buffer);
-static GstFlowReturn gst_filesrc_getrange (GstPad * pad, guint64 offset,
-    guint length, GstBuffer ** buffer);
-static gboolean gst_filesrc_srcpad_event (GstPad * pad, GstEvent * event);
-static gboolean gst_filesrc_srcpad_query (GstPad * pad, GstQueryType type,
-    GstFormat * format, gint64 * value);
+static gboolean gst_filesrc_start (GstBaseSrc * basesrc);
+static gboolean gst_filesrc_stop (GstBaseSrc * basesrc);
 
-static gboolean gst_filesrc_activate (GstPad * pad, GstActivateMode mode);
-static GstElementStateReturn gst_filesrc_change_state (GstElement * element);
+static gboolean gst_filesrc_get_size (GstBaseSrc * src, guint64 * size);
+static GstFlowReturn gst_filesrc_create (GstBaseSrc * src, guint64 offset,
+    guint length, GstBuffer ** buffer);
 
-static GstCaps *gst_filesrc_type_find (GstFileSrc * src);
 static void gst_filesrc_uri_handler_init (gpointer g_iface,
     gpointer iface_data);
 
@@ -198,7 +156,7 @@ _do_init (GType filesrc_type)
   GST_DEBUG_CATEGORY_INIT (gst_filesrc_debug, "filesrc", 0, "filesrc element");
 }
 
-GST_BOILERPLATE_FULL (GstFileSrc, gst_filesrc, GstElement, GST_TYPE_ELEMENT,
+GST_BOILERPLATE_FULL (GstFileSrc, gst_filesrc, GstBaseSrc, GST_TYPE_BASESRC,
     _do_init);
 
 static void
@@ -208,15 +166,20 @@ gst_filesrc_base_init (gpointer g_class)
 
   gst_element_class_add_pad_template (gstelement_class,
       gst_static_pad_template_get (&srctemplate));
+
   gst_element_class_set_details (gstelement_class, &gst_filesrc_details);
 }
+
 static void
 gst_filesrc_class_init (GstFileSrcClass * klass)
 {
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSrcClass *gstbasesrc_class;
 
   gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesrc_class = (GstBaseSrcClass *) klass;
 
   gobject_class->set_property = gst_filesrc_set_property;
   gobject_class->get_property = gst_filesrc_get_property;
@@ -228,50 +191,34 @@ gst_filesrc_class_init (GstFileSrcClass * klass)
   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOCATION,
       g_param_spec_string ("location", "File Location",
           "Location of the file to read", NULL, G_PARAM_READWRITE));
-  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BLOCKSIZE,
-      g_param_spec_ulong ("blocksize", "Block size",
-          "Size in bytes to read per buffer", 1, G_MAXULONG, DEFAULT_BLOCKSIZE,
-          G_PARAM_READWRITE));
   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MMAPSIZE,
       g_param_spec_ulong ("mmapsize", "mmap() Block Size",
           "Size in bytes of mmap()d regions", 0, G_MAXULONG, DEFAULT_MMAPSIZE,
           G_PARAM_READWRITE));
   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TOUCH,
       g_param_spec_boolean ("touch", "Touch read data",
-          "Touch data to force disk read", FALSE, G_PARAM_READWRITE));
+          "Touch data to force disk read", DEFAULT_TOUCH, G_PARAM_READWRITE));
 
-  gobject_class->dispose = gst_filesrc_dispose;
+  gobject_class->finalize = gst_filesrc_finalize;
 
-  gstelement_class->change_state = gst_filesrc_change_state;
+  gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_filesrc_start);
+  gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_filesrc_stop);
+  gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_filesrc_get_size);
+  gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_filesrc_create);
 }
 
 static void
 gst_filesrc_init (GstFileSrc * src)
 {
-  src->srcpad =
-      gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
-      "src");
-  gst_pad_set_getrange_function (src->srcpad, gst_filesrc_getrange);
-  gst_pad_set_activate_function (src->srcpad, gst_filesrc_activate);
-  gst_pad_set_event_function (src->srcpad, gst_filesrc_srcpad_event);
-  gst_pad_set_event_mask_function (src->srcpad, gst_filesrc_get_event_mask);
-  gst_pad_set_query_function (src->srcpad, gst_filesrc_srcpad_query);
-  gst_pad_set_query_type_function (src->srcpad, gst_filesrc_get_query_types);
-  gst_pad_set_formats_function (src->srcpad, gst_filesrc_get_formats);
-  gst_element_add_pad (GST_ELEMENT (src), src->srcpad);
-
 #ifdef HAVE_MMAP
   src->pagesize = getpagesize ();
 #endif
 
   src->filename = NULL;
   src->fd = 0;
-  src->filelen = 0;
   src->uri = NULL;
 
-  src->curoffset = 0;
-  src->block_size = DEFAULT_BLOCKSIZE;
-  src->touch = FALSE;
+  src->touch = DEFAULT_TOUCH;
 
   src->mapbuf = NULL;
   src->mapsize = DEFAULT_MMAPSIZE;      /* default is 4MB */
@@ -280,7 +227,7 @@ gst_filesrc_init (GstFileSrc * src)
 }
 
 static void
-gst_filesrc_dispose (GObject * object)
+gst_filesrc_finalize (GObject * object)
 {
   GstFileSrc *src;
 
@@ -289,19 +236,22 @@ gst_filesrc_dispose (GObject * object)
   g_free (src->filename);
   g_free (src->uri);
 
-  /* dispose may be called multiple times */
-  src->filename = NULL;
-  src->uri = NULL;
-
-  G_OBJECT_CLASS (parent_class)->dispose (object);
+  G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
 static gboolean
 gst_filesrc_set_location (GstFileSrc * src, const gchar * location)
 {
   /* the element must be stopped in order to do this */
-  if (GST_STATE (src) != GST_STATE_READY && GST_STATE (src) != GST_STATE_NULL)
-    return FALSE;
+  GST_STATE_LOCK (src);
+  {
+    GstElementState state;
+
+    state = GST_STATE (src);
+    if (state != GST_STATE_READY && state != GST_STATE_NULL)
+      goto wrong_state;
+  }
+  GST_STATE_UNLOCK (src);
 
   g_free (src->filename);
   g_free (src->uri);
@@ -318,6 +268,14 @@ gst_filesrc_set_location (GstFileSrc * src, const gchar * location)
   gst_uri_handler_new_uri (GST_URI_HANDLER (src), src->uri);
 
   return TRUE;
+
+  /* ERROR */
+wrong_state:
+  {
+    GST_DEBUG_OBJECT (src, "setting location in wrong state");
+    GST_STATE_UNLOCK (src);
+    return FALSE;
+  }
 }
 
 static void
@@ -335,10 +293,6 @@ gst_filesrc_set_property (GObject * object, guint prop_id, const GValue * value,
     case ARG_LOCATION:
       gst_filesrc_set_location (src, g_value_get_string (value));
       break;
-    case ARG_BLOCKSIZE:
-      src->block_size = g_value_get_ulong (value);
-      g_object_notify (G_OBJECT (src), "blocksize");
-      break;
     case ARG_MMAPSIZE:
       if ((src->mapsize % src->pagesize) == 0) {
         src->mapsize = g_value_get_ulong (value);
@@ -377,9 +331,6 @@ gst_filesrc_get_property (GObject * object, guint prop_id, GValue * value,
     case ARG_FD:
       g_value_set_int (value, src->fd);
       break;
-    case ARG_BLOCKSIZE:
-      g_value_set_ulong (value, src->block_size);
-      break;
     case ARG_MMAPSIZE:
       g_value_set_ulong (value, src->mapsize);
       break;
@@ -392,53 +343,75 @@ gst_filesrc_get_property (GObject * object, guint prop_id, GValue * value,
   }
 }
 
+/***
+ * mmap code below
+ */
+
 #ifdef HAVE_MMAP
 static void
 gst_filesrc_free_parent_mmap (GstBuffer * buf)
 {
-  GST_LOG ("freeing mmap()d buffer at %" G_GUINT64_FORMAT "+%u",
-      GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf));
+  guint size;
+  guint64 offset;
+  gpointer data;
+  GstBaseSrc *src;
+
+  /* get info */
+  size = GST_BUFFER_MAXSIZE (buf);
+  offset = GST_BUFFER_OFFSET (buf);
+  data = GST_BUFFER_DATA (buf);
+  src = (GstBaseSrc *) GST_BUFFER_PRIVATE (buf);
+
+  if (!GST_IS_BASESRC (src))
+    goto wrong_buffer;
+
+  GST_LOG ("freeing mmap()d buffer at %" G_GUINT64_FORMAT "+%u", offset, size);
 
 #ifdef MADV_DONTNEED
   /* madvise to tell the kernel what to do with it */
-  madvise (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), MADV_DONTNEED);
+  if (madvise (data, size, MADV_DONTNEED) < 0) {
+    GST_WARNING_OBJECT (src, "warning: madvise failed: %s", strerror (errno));
+  }
 #endif
+
   /* now unmap the memory */
-  munmap (GST_BUFFER_DATA (buf), GST_BUFFER_MAXSIZE (buf));
+  if (munmap (data, size) < 0) {
+    GST_WARNING_OBJECT (src, "warning: munmap failed: %s", strerror (errno));
+  }
+
   /* cast to unsigned long, since there's no gportable way to print
    * guint64 as hex */
   GST_LOG ("unmapped region %08lx+%08lx at %p",
-      (unsigned long) GST_BUFFER_OFFSET (buf),
-      (unsigned long) GST_BUFFER_MAXSIZE (buf), GST_BUFFER_DATA (buf));
+      (gulong) offset, (gulong) size, data);
 
   GST_BUFFER_DATA (buf) = NULL;
+  return;
+
+wrong_buffer:
+  {
+    GST_WARNING ("freeing wrong mmap buffer");
+    return;
+  }
 }
-#endif
 
-#ifdef HAVE_MMAP
 static GstBuffer *
 gst_filesrc_map_region (GstFileSrc * src, off_t offset, size_t size)
 {
   GstBuffer *buf;
-  gint retval;
   void *mmapregion;
 
   g_return_val_if_fail (offset >= 0, NULL);
 
   GST_LOG_OBJECT (src, "mapping region %08llx+%08lx from file into memory",
-      offset, (unsigned long) size);
+      offset, (gulong) size);
+
   mmapregion = mmap (NULL, size, PROT_READ, MAP_SHARED, src->fd, offset);
 
-  if (mmapregion == NULL) {
-    GST_ELEMENT_ERROR (src, RESOURCE, TOO_LAZY, (NULL), ("mmap call failed."));
-    return NULL;
-  } else if (mmapregion == MAP_FAILED) {
-    GST_WARNING_OBJECT (src, "mmap (0x%08lx, %d, 0x%llx) failed: %s",
-        (unsigned long) size, src->fd, offset, strerror (errno));
-    return NULL;
-  }
+  if (mmapregion == NULL || mmapregion == MAP_FAILED)
+    goto mmap_failed;
+
   GST_LOG_OBJECT (src, "mapped region %08lx+%08lx from file into memory at %p",
-      (unsigned long) offset, (unsigned long) size, mmapregion);
+      (gulong) offset, (gulong) size, mmapregion);
 
   /* time to allocate a new mapbuf */
   buf = gst_buffer_new ();
@@ -447,9 +420,11 @@ gst_filesrc_map_region (GstFileSrc * src, off_t offset, size_t size)
 
 #ifdef MADV_SEQUENTIAL
   /* madvise to tell the kernel what to do with it */
-  retval =
-      madvise (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), MADV_SEQUENTIAL);
+  if (madvise (mmapregion, size, MADV_SEQUENTIAL) < 0) {
+    GST_WARNING_OBJECT (src, "warning: madvise failed: %s", strerror (errno));
+  }
 #endif
+
   /* fill in the rest of the fields */
   GST_BUFFER_FLAG_SET (buf, GST_BUFFER_READONLY);
   GST_BUFFER_FLAG_SET (buf, GST_BUFFER_ORIGINAL);
@@ -462,27 +437,45 @@ gst_filesrc_map_region (GstFileSrc * src, off_t offset, size_t size)
   GST_BUFFER_FREE_DATA_FUNC (buf) = gst_filesrc_free_parent_mmap;
 
   return buf;
+
+  /* ERROR */
+mmap_failed:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
+        ("mmap (0x%08lx, %d, 0x%llx) failed: %s",
+            (gulong) size, src->fd, offset, strerror (errno)));
+    return NULL;
+  }
 }
-#endif
 
-#ifdef HAVE_MMAP
 static GstBuffer *
 gst_filesrc_map_small_region (GstFileSrc * src, off_t offset, size_t size)
 {
-  size_t mapsize;
-  off_t mod, mapbase;
-  GstBuffer *map;
+  GstBuffer *ret;
+  off_t mod;
+  guint pagesize;
 
-/*  printf("attempting to map a small buffer at %d+%d\n",offset,size); */
+  GST_LOG_OBJECT (src,
+      "attempting to map a small buffer at %llu+%d",
+      (unsigned long long) offset, (gint) size);
+
+  pagesize = src->pagesize;
+
+  mod = offset % pagesize;
 
   /* if the offset starts at a non-page boundary, we have to special case */
-  if ((mod = offset % src->pagesize)) {
-    GstBuffer *ret;
+  if (mod != 0) {
+    size_t mapsize;
+    off_t mapbase;
+    GstBuffer *map;
 
     mapbase = offset - mod;
-    mapsize =
-        ((size + mod + src->pagesize - 1) / src->pagesize) * src->pagesize;
-/*    printf("not on page boundaries, resizing map to %d+%d\n",mapbase,mapsize);*/
+    mapsize = ((size + mod + pagesize - 1) / pagesize) * pagesize;
+
+    GST_LOG_OBJECT (src,
+        "not on page boundaries, resizing to map to %llu+%d",
+        (unsigned long long) mapbase, (gint) mapsize);
+
     map = gst_filesrc_map_region (src, mapbase, mapsize);
     if (map == NULL)
       return NULL;
@@ -491,23 +484,16 @@ gst_filesrc_map_small_region (GstFileSrc * src, off_t offset, size_t size)
     GST_BUFFER_OFFSET (ret) = GST_BUFFER_OFFSET (map) + offset - mapbase;
 
     gst_buffer_unref (map);
-
-    return ret;
+  } else {
+    ret = gst_filesrc_map_region (src, offset, size);
   }
 
-  return gst_filesrc_map_region (src, offset, size);
+  return ret;
 }
-#endif
 
-#ifdef HAVE_MMAP
-/**
- * gst_filesrc_get_mmap:
- * @src: #GstElement to get data from
- *
- * Returns: a new #GstData from the mmap'd source.
- */
-static GstData *
-gst_filesrc_get_mmap (GstFileSrc * src)
+static GstFlowReturn
+gst_filesrc_create_mmap (GstFileSrc * src, guint64 offset, guint length,
+    GstBuffer ** buffer)
 {
   GstBuffer *buf = NULL;
   size_t readsize, mapsize;
@@ -515,48 +501,37 @@ gst_filesrc_get_mmap (GstFileSrc * src)
   int i;
 
   /* calculate end pointers so we don't have to do so repeatedly later */
-  readsize = src->block_size;
-  readend = src->curoffset + src->block_size;   /* note this is the byte *after* the read */
+  readsize = length;
+  readend = offset + readsize;  /* note this is the byte *after* the read */
+
   mapstart = GST_BUFFER_OFFSET (src->mapbuf);
   mapsize = GST_BUFFER_SIZE (src->mapbuf);
   mapend = mapstart + mapsize;  /* note this is the byte *after* the map */
 
-  /* check to see if we're going to overflow the end of the file */
-  if (src->is_regular) {
-    if (readend > src->filelen) {
-      if (!gst_filesrc_check_filesize (src) || readend > src->filelen) {
-        readsize = src->filelen - src->curoffset;
-        readend = src->curoffset + readsize;
-      }
-    }
-  }
-
   GST_LOG ("attempting to read %08lx, %08lx, %08lx, %08lx",
       (unsigned long) readsize, (unsigned long) readend,
       (unsigned long) mapstart, (unsigned long) mapend);
 
   /* if the start is past the mapstart */
-  if (src->curoffset >= mapstart) {
+  if (offset >= mapstart) {
     /* if the end is before the mapend, the buffer is in current mmap region... */
     /* ('cause by definition if readend is in the buffer, so's readstart) */
     if (readend <= mapend) {
       GST_LOG_OBJECT (src,
           "read buf %llu+%d lives in current mapbuf %lld+%d, creating subbuffer of mapbuf",
-          src->curoffset, (int) readsize, mapstart, mapsize);
-      buf =
-          gst_buffer_create_sub (src->mapbuf, src->curoffset - mapstart,
-          readsize);
-      GST_BUFFER_OFFSET (buf) = src->curoffset;
+          offset, (int) readsize, mapstart, mapsize);
+      buf = gst_buffer_create_sub (src->mapbuf, offset - mapstart, readsize);
+      GST_BUFFER_OFFSET (buf) = offset;
 
       /* if the start actually is within the current mmap region, map an overlap buffer */
-    } else if (src->curoffset < mapend) {
+    } else if (offset < mapend) {
       GST_LOG_OBJECT (src,
           "read buf %llu+%d starts in mapbuf %d+%d but ends outside, creating new mmap",
-          (unsigned long long) src->curoffset, (gint) readsize, (gint) mapstart,
+          (unsigned long long) offset, (gint) readsize, (gint) mapstart,
           (gint) mapsize);
-      buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
+      buf = gst_filesrc_map_small_region (src, offset, readsize);
       if (buf == NULL)
-        return NULL;
+        goto could_not_mmap;
     }
 
     /* the only other option is that buffer is totally outside, which means we search for it */
@@ -569,43 +544,43 @@ gst_filesrc_get_mmap (GstFileSrc * src)
     /* either way, it's really not relevant, we just create a new region anyway */
     GST_LOG_OBJECT (src,
         "read buf %llu+%d starts before mapbuf %d+%d, but overlaps it",
-        (unsigned long long) src->curoffset, (gint) readsize, (gint) mapstart,
+        (unsigned long long) offset, (gint) readsize, (gint) mapstart,
         (gint) mapsize);
-    buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
+    buf = gst_filesrc_map_small_region (src, offset, readsize);
     if (buf == NULL)
-      return NULL;
+      goto could_not_mmap;
   }
 
   /* then deal with the case where the read buffer is totally outside */
   if (buf == NULL) {
     /* first check to see if there's a map that covers the right region already */
     GST_LOG_OBJECT (src, "searching for mapbuf to cover %llu+%d",
-        src->curoffset, (int) readsize);
+        offset, (int) readsize);
 
     /* if the read buffer crosses a mmap region boundary, create a one-off region */
-    if ((src->curoffset / src->mapsize) != (readend / src->mapsize)) {
+    if ((offset / src->mapsize) != (readend / src->mapsize)) {
       GST_LOG_OBJECT (src,
           "read buf %llu+%d crosses a %d-byte boundary, creating a one-off",
-          src->curoffset, (int) readsize, (int) src->mapsize);
-      buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
+          offset, (int) readsize, (int) src->mapsize);
+      buf = gst_filesrc_map_small_region (src, offset, readsize);
       if (buf == NULL)
-        return NULL;
+        goto could_not_mmap;
 
       /* otherwise we will create a new mmap region and set it to the default */
     } else {
       size_t mapsize;
 
-      off_t nextmap = src->curoffset - (src->curoffset % src->mapsize);
+      off_t nextmap = offset - (offset % src->mapsize);
 
       GST_LOG_OBJECT (src,
           "read buf %llu+%d in new mapbuf at %llu+%d, mapping and subbuffering",
-          src->curoffset, readsize, nextmap, src->mapsize);
+          offset, readsize, nextmap, src->mapsize);
       /* first, we're done with the old mapbuf */
       gst_buffer_unref (src->mapbuf);
       mapsize = src->mapsize;
 
       /* double the mapsize as long as the readsize is smaller */
-      while (readsize + src->curoffset > nextmap + mapsize) {
+      while (readsize + offset > nextmap + mapsize) {
         GST_LOG_OBJECT (src, "readsize smaller then mapsize %08x %d",
             readsize, (int) mapsize);
         mapsize <<= 1;
@@ -613,14 +588,12 @@ gst_filesrc_get_mmap (GstFileSrc * src)
       /* create a new one */
       src->mapbuf = gst_filesrc_map_region (src, nextmap, mapsize);
       if (src->mapbuf == NULL)
-        return NULL;
+        goto could_not_mmap;
 
       /* subbuffer it */
-      buf =
-          gst_buffer_create_sub (src->mapbuf, src->curoffset - nextmap,
-          readsize);
+      buf = gst_buffer_create_sub (src->mapbuf, offset - nextmap, readsize);
       GST_BUFFER_OFFSET (buf) =
-          GST_BUFFER_OFFSET (src->mapbuf) + src->curoffset - nextmap;
+          GST_BUFFER_OFFSET (src->mapbuf) + offset - nextmap;
     }
   }
 
@@ -628,266 +601,241 @@ gst_filesrc_get_mmap (GstFileSrc * src)
   if (src->touch) {
     volatile guchar *p = GST_BUFFER_DATA (buf), c;
 
+    /* read first byte of each page */
     for (i = 0; i < GST_BUFFER_SIZE (buf); i += src->pagesize)
       c = p[i];
   }
 
   /* we're done, return the buffer */
-  g_assert (src->curoffset == GST_BUFFER_OFFSET (buf));
-  src->curoffset += GST_BUFFER_SIZE (buf);
-  return GST_DATA (buf);
+  *buffer = buf;
+
+  return GST_FLOW_OK;
+
+  /* ERROR */
+could_not_mmap:
+  {
+    return GST_FLOW_ERROR;
+  }
 }
 #endif
 
-static GstData *
-gst_filesrc_get_read (GstFileSrc * src)
+/***
+ * read code below 
+ *
+ */
+
+static GstFlowReturn
+gst_filesrc_create_read (GstFileSrc * src, guint64 offset, guint length,
+    GstBuffer ** buffer)
 {
-  GstBuffer *buf = NULL;
-  size_t readsize;
   int ret;
+  GstBuffer *buf;
 
-  readsize = src->block_size;
-  /* for regular files, we can use the filesize to check how much we
-     can read */
-  if (src->is_regular) {
-    if (src->curoffset + readsize > src->filelen) {
-      if (!gst_filesrc_check_filesize (src)
-          || src->curoffset + readsize > src->filelen) {
-        readsize = src->filelen - src->curoffset;
-      }
-    }
+  if (src->read_position != offset) {
+    off_t res;
+
+    res = lseek (src->fd, offset, SEEK_SET);
+    if (res < 0 || res != offset)
+      goto seek_failed;
   }
 
-  buf = gst_buffer_new_and_alloc (readsize);
-  g_return_val_if_fail (buf != NULL, NULL);
+  buf = gst_buffer_new_and_alloc (length);
+
+  GST_LOG_OBJECT (src, "Reading %d bytes", length);
+  ret = read (src->fd, GST_BUFFER_DATA (buf), length);
+  if (ret < 0)
+    goto could_not_read;
 
-  GST_LOG_OBJECT (src, "Reading %d bytes", readsize);
-  ret = read (src->fd, GST_BUFFER_DATA (buf), readsize);
-  if (ret < 0) {
-    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
-    return NULL;
-  }
   /* regular files should have given us what we expected */
-  if (ret < readsize && src->is_regular) {
-    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
-        ("unexpected end of file."));
-    return NULL;
-  }
+  if (ret < length && src->is_regular)
+    goto unexpected_eos;
+
   /* other files should eos if they read 0 */
   if (ret == 0) {
     GST_DEBUG ("non-regular file hits EOS");
     gst_buffer_unref (buf);
-    //gst_element_set_eos (GST_ELEMENT (src));
-    return GST_DATA (gst_event_new (GST_EVENT_EOS));
+    return GST_FLOW_UNEXPECTED;
   }
-  readsize = ret;
-
-  GST_BUFFER_SIZE (buf) = readsize;
-  GST_BUFFER_MAXSIZE (buf) = readsize;
-  GST_BUFFER_OFFSET (buf) = src->curoffset;
-  GST_BUFFER_OFFSET_END (buf) = src->curoffset + readsize;
-  src->curoffset += readsize;
+  length = ret;
 
-  return GST_DATA (buf);
-}
+  GST_BUFFER_SIZE (buf) = length;
+  GST_BUFFER_MAXSIZE (buf) = length;
+  GST_BUFFER_OFFSET (buf) = offset;
+  GST_BUFFER_OFFSET_END (buf) = offset + length;
 
-static GstFlowReturn
-gst_filesrc_getrange (GstPad * pad, guint64 offset, guint length,
-    GstBuffer ** buffer)
-{
-  GstFileSrc *src;
+  *buffer = buf;
 
-  src = GST_FILESRC (GST_PAD_PARENT (pad));
+  src->read_position += length;
 
-  src->curoffset = offset;
-  src->block_size = length;
+  return GST_FLOW_OK;
 
-  return gst_filesrc_get (pad, buffer);
+  /* ERROR */
+seek_failed:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
+    return GST_FLOW_ERROR;
+  }
+could_not_read:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
+unexpected_eos:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
+        ("unexpected end of file."));
+    gst_buffer_unref (buf);
+    return GST_FLOW_ERROR;
+  }
 }
 
 static GstFlowReturn
-gst_filesrc_get (GstPad * pad, GstBuffer ** buffer)
+gst_filesrc_create (GstBaseSrc * basesrc, guint64 offset, guint length,
+    GstBuffer ** buffer)
 {
   GstFileSrc *src;
-  GstData *data;
-
-  src = GST_FILESRC (GST_PAD_PARENT (pad));
-
-  g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_FILESRC_OPEN),
-      GST_FLOW_WRONG_STATE);
-
-  /* check for flush */
-  if (src->need_flush) {
-    src->need_flush = FALSE;
-    GST_DEBUG_OBJECT (src, "sending flush");
-    gst_pad_push_event (pad, gst_event_new_flush (TRUE));
-  }
-  /* check for seek */
-  if (src->need_discont) {
-    GstEvent *event;
-
-    GST_DEBUG_OBJECT (src, "sending discont");
-    event =
-        gst_event_new_discontinuous (src->need_discont > 1, GST_FORMAT_BYTES,
-        (guint64) src->curoffset, GST_FORMAT_UNDEFINED);
-    src->need_discont = 0;
-    gst_pad_push_event (pad, event);
-  }
+  GstFlowReturn ret;
 
-  /* check for EOF if it's a regular file */
-  if (src->is_regular) {
-    g_assert (src->curoffset <= src->filelen);
-    if (src->curoffset == src->filelen) {
-      if (!gst_filesrc_check_filesize (src) || src->curoffset >= src->filelen) {
-        GST_DEBUG_OBJECT (src, "eos %" G_GINT64_FORMAT " %" G_GINT64_FORMAT,
-            src->curoffset, src->filelen);
-      }
-      //gst_element_set_eos (GST_ELEMENT (src));
-      gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
-      return GST_FLOW_WRONG_STATE;
+  src = GST_FILESRC (basesrc);
 
-    }
-  }
 #ifdef HAVE_MMAP
   if (src->using_mmap) {
-    data = gst_filesrc_get_mmap (src);
+    ret = gst_filesrc_create_mmap (src, offset, length, buffer);
   } else {
-    data = gst_filesrc_get_read (src);
+    ret = gst_filesrc_create_read (src, offset, length, buffer);
   }
 #else
-  data = gst_filesrc_get_read (src);
+  ret = gst_filesrc_create_read (src, offset, length, buffer);
 #endif
-  if (data == NULL) {
-    GST_DEBUG_OBJECT (src, "could not get data");
-    return GST_FLOW_ERROR;
-  }
 
-  if (GST_IS_EVENT (data)) {
-    gst_pad_push_event (pad, GST_EVENT (data));
-  } else {
-    *buffer = GST_BUFFER (data);
-  }
-
-  return GST_FLOW_OK;
+  return ret;
 }
 
-/* TRUE if the filesize of the file was updated */
 static gboolean
-gst_filesrc_check_filesize (GstFileSrc * src)
+gst_filesrc_get_size (GstBaseSrc * basesrc, guint64 * size)
 {
   struct stat stat_results;
+  GstFileSrc *src;
 
-  g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_FILESRC_OPEN), FALSE);
+  src = GST_FILESRC (basesrc);
+
+  if (fstat (src->fd, &stat_results) < 0)
+    goto could_not_stat;
+
+  *size = stat_results.st_size;
 
-  fstat (src->fd, &stat_results);
-  GST_DEBUG_OBJECT (src,
-      "checked filesize on %s (was %" G_GUINT64_FORMAT ", is %" G_GUINT64_FORMAT
-      ")", src->filename, src->filelen, (guint64) stat_results.st_size);
-  if (src->filelen == (guint64) stat_results.st_size)
-    return FALSE;
-  src->filelen = stat_results.st_size;
   return TRUE;
+
+  /* ERROR */
+could_not_stat:
+  {
+    return FALSE;
+  }
 }
 
 /* open the file and mmap it, necessary to go to READY state */
 static gboolean
-gst_filesrc_open_file (GstFileSrc * src)
+gst_filesrc_start (GstBaseSrc * basesrc)
 {
-  g_return_val_if_fail (!GST_FLAG_IS_SET (src, GST_FILESRC_OPEN), FALSE);
-
-  if (src->filename == NULL || src->filename[0] == '\0') {
-    GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
-        (_("No file name specified for reading.")), (NULL));
-    return FALSE;
-  }
+  GstFileSrc *src = GST_FILESRC (basesrc);
+  struct stat stat_results;
 
+  if (src->filename == NULL || src->filename[0] == '\0')
+    goto no_filename;
 
   GST_INFO_OBJECT (src, "opening file %s", src->filename);
 
   /* open the file */
   src->fd = open (src->filename, O_RDONLY | O_BINARY);
-  if (src->fd < 0) {
-    if (errno == ENOENT)
-      GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),
-          ("No such file \"%s\"", src->filename));
-    else
-      GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
-          (_("Could not open file \"%s\" for reading."), src->filename),
-          GST_ERROR_SYSTEM);
-    return FALSE;
-  } else {
-    /* check if it is a regular file, otherwise bail out */
-    struct stat stat_results;
+  if (src->fd < 0)
+    goto open_failed;
 
-    fstat (src->fd, &stat_results);
+  /* check if it is a regular file, otherwise bail out */
+  if (fstat (src->fd, &stat_results) < 0)
+    goto no_stat;
 
-    if (S_ISDIR (stat_results.st_mode)) {
-      GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
-          (_("\"%s\" is a directory."), src->filename), (NULL));
-      close (src->fd);
-      return FALSE;
-    }
-    if (S_ISSOCK (stat_results.st_mode)) {
-      GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
-          (_("File \"%s\" is a socket."), src->filename), (NULL));
-      close (src->fd);
-      return FALSE;
-    }
+  if (S_ISDIR (stat_results.st_mode))
+    goto was_directory;
 
-    /* find the file length */
-    src->filelen = stat_results.st_size;
+  if (S_ISSOCK (stat_results.st_mode))
+    goto was_socket;
 
-    src->using_mmap = FALSE;
+  src->using_mmap = FALSE;
+  src->read_position = 0;
+
+  /* record if it's a regular (hence seekable and lengthable) file */
+  if (S_ISREG (stat_results.st_mode))
+    src->is_regular = TRUE;
 
-    /* record if it's a regular (hence seekable and lengthable) file */
-    if (S_ISREG (stat_results.st_mode))
-      src->is_regular = TRUE;
 #ifdef HAVE_MMAP
-    /* FIXME: maybe we should only try to mmap if it's a regular file */
-    /* allocate the first mmap'd region if it's a regular file ? */
-    src->mapbuf = gst_filesrc_map_region (src, 0, src->mapsize);
-    if (src->mapbuf != NULL) {
-      GST_DEBUG_OBJECT (src, "using mmap for file");
-      src->using_mmap = TRUE;
-    }
+  /* FIXME: maybe we should only try to mmap if it's a regular file */
+  /* allocate the first mmap'd region if it's a regular file ? */
+  src->mapbuf = gst_filesrc_map_region (src, 0, src->mapsize);
+  if (src->mapbuf != NULL) {
+    GST_DEBUG_OBJECT (src, "using mmap for file");
+    src->using_mmap = TRUE;
+  }
 #endif
 
-    src->curoffset = 0;
-
-    GST_FLAG_SET (src, GST_FILESRC_OPEN);
-
-    {
-      GstCaps *caps;
-      guint64 offset;
-      guint length;
-
-      offset = src->curoffset;
-      length = src->block_size;
-
-      caps = gst_filesrc_type_find (src);
-      gst_pad_set_caps (src->srcpad, caps);
+  return TRUE;
 
-      src->curoffset = offset;
-      src->block_size = length;
+  /* ERROR */
+no_filename:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
+        (_("No file name specified for reading.")), (NULL));
+    return FALSE;
+  }
+open_failed:
+  {
+    switch (errno) {
+      case ENOENT:
+        GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),
+            ("No such file \"%s\"", src->filename));
+        break;
+      default:
+        GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+            (_("Could not open file \"%s\" for reading."), src->filename),
+            GST_ERROR_SYSTEM);
+        break;
     }
-
+    return FALSE;
+  }
+no_stat:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+        (_("could not get info on \"%s\"."), src->filename), (NULL));
+    close (src->fd);
+    return FALSE;
+  }
+was_directory:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+        (_("\"%s\" is a directory."), src->filename), (NULL));
+    close (src->fd);
+    return FALSE;
+  }
+was_socket:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+        (_("File \"%s\" is a socket."), src->filename), (NULL));
+    close (src->fd);
+    return FALSE;
   }
-  return TRUE;
 }
 
 /* unmap and close the file */
-static void
-gst_filesrc_close_file (GstFileSrc * src)
+static gboolean
+gst_filesrc_stop (GstBaseSrc * basesrc)
 {
-  g_return_if_fail (GST_FLAG_IS_SET (src, GST_FILESRC_OPEN));
+  GstFileSrc *src = GST_FILESRC (basesrc);
 
   /* close the file */
   close (src->fd);
 
   /* zero out a lot of our state */
   src->fd = 0;
-  src->filelen = 0;
-  src->curoffset = 0;
   src->is_regular = FALSE;
 
   if (src->mapbuf) {
@@ -895,339 +843,9 @@ gst_filesrc_close_file (GstFileSrc * src)
     src->mapbuf = NULL;
   }
 
-  GST_FLAG_UNSET (src, GST_FILESRC_OPEN);
-}
-
-static void
-gst_filesrc_loop (GstPad * pad)
-{
-  GstFileSrc *filesrc;
-  gboolean result;
-  GstBuffer *buffer;
-
-  filesrc = GST_FILESRC (GST_PAD_PARENT (pad));
-
-  GST_STREAM_LOCK (pad);
-
-  result = gst_filesrc_get (pad, &buffer);
-  if (result != GST_FLOW_OK)
-    goto need_pause;
-
-  result = gst_pad_push (pad, buffer);
-  if (result != GST_FLOW_OK)
-    goto need_pause;
-
-  GST_STREAM_UNLOCK (pad);
-  return;
-
-need_pause:
-  {
-    gst_task_pause (GST_RPAD_TASK (pad));
-    GST_STREAM_UNLOCK (pad);
-    return;
-  }
-}
-
-
-static gboolean
-gst_filesrc_activate (GstPad * pad, GstActivateMode mode)
-{
-  gboolean result = FALSE;
-  GstFileSrc *filesrc;
-
-  filesrc = GST_FILESRC (GST_OBJECT_PARENT (pad));
-
-  switch (mode) {
-    case GST_ACTIVATE_PUSH:
-      /* if we have a scheduler we can start the task */
-      if (GST_ELEMENT_SCHEDULER (filesrc)) {
-        GST_STREAM_LOCK (pad);
-        GST_RPAD_TASK (pad) =
-            gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (filesrc),
-            (GstTaskFunction) gst_filesrc_loop, pad);
-
-        gst_task_start (GST_RPAD_TASK (pad));
-        result = TRUE;
-        GST_STREAM_UNLOCK (pad);
-      }
-      break;
-    case GST_ACTIVATE_PULL:
-      result = TRUE;
-      break;
-    case GST_ACTIVATE_NONE:
-      /* step 1, unblock clock sync (if any) */
-
-      /* step 2, make sure streaming finishes */
-      GST_STREAM_LOCK (pad);
-      /* step 3, stop the task */
-      gst_task_stop (GST_RPAD_TASK (pad));
-      GST_STREAM_UNLOCK (pad);
-
-      result = TRUE;
-      break;
-  }
-  return result;
-}
-
-
-static GstElementStateReturn
-gst_filesrc_change_state (GstElement * element)
-{
-  GstElementStateReturn result = GST_STATE_SUCCESS;
-
-  GstFileSrc *src = GST_FILESRC (element);
-
-  switch (GST_STATE_TRANSITION (element)) {
-    case GST_STATE_NULL_TO_READY:
-      break;
-    case GST_STATE_READY_TO_NULL:
-      break;
-    case GST_STATE_READY_TO_PAUSED:
-      if (!GST_FLAG_IS_SET (element, GST_FILESRC_OPEN)) {
-        if (!gst_filesrc_open_file (GST_FILESRC (element)))
-          return GST_STATE_FAILURE;
-      }
-      src->need_discont = 2;
-      break;
-    case GST_STATE_PAUSED_TO_PLAYING:
-      gst_task_start (GST_RPAD_TASK (src->srcpad));
-      break;
-  }
-
-  result = GST_ELEMENT_CLASS (parent_class)->change_state (element);
-
-  switch (GST_STATE_TRANSITION (element)) {
-    case GST_STATE_PLAYING_TO_PAUSED:
-      gst_task_start (GST_RPAD_TASK (src->srcpad));
-      break;
-    case GST_STATE_PAUSED_TO_READY:
-      if (GST_FLAG_IS_SET (element, GST_FILESRC_OPEN))
-        gst_filesrc_close_file (GST_FILESRC (element));
-      break;
-    default:
-      break;
-  }
-
-  return result;
-}
-
-static gboolean
-gst_filesrc_srcpad_query (GstPad * pad, GstQueryType type,
-    GstFormat * format, gint64 * value)
-{
-  GstFileSrc *src = GST_FILESRC (GST_PAD_PARENT (pad));
-
-  if (*format == GST_FORMAT_DEFAULT)
-    *format = GST_FORMAT_BYTES;
-
-  switch (type) {
-    case GST_QUERY_TOTAL:
-      if (*format != GST_FORMAT_BYTES) {
-        return FALSE;
-      }
-      if (!src->is_regular)
-        return FALSE;
-      gst_filesrc_check_filesize (src);
-      *value = src->filelen;
-      break;
-    case GST_QUERY_POSITION:
-      switch (*format) {
-        case GST_FORMAT_BYTES:
-          *value = src->curoffset;
-          break;
-        case GST_FORMAT_PERCENT:
-          if (src->filelen == 0)
-            return FALSE;
-          if (!src->is_regular)
-            return FALSE;
-          *value = src->curoffset * GST_FORMAT_PERCENT_MAX / src->filelen;
-          break;
-        default:
-          return FALSE;
-      }
-      break;
-    default:
-      return FALSE;
-      break;
-  }
   return TRUE;
 }
 
-static gboolean
-gst_filesrc_srcpad_event (GstPad * pad, GstEvent * event)
-{
-  GstFileSrc *src = GST_FILESRC (GST_PAD_PARENT (pad));
-
-  GST_DEBUG_OBJECT (src, "received event type %d", GST_EVENT_TYPE (event));
-
-  switch (GST_EVENT_TYPE (event)) {
-    case GST_EVENT_SEEK:
-    {
-      gint64 offset;
-
-      if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES &&
-          GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_DEFAULT) {
-        goto error;
-      }
-      if (!src->is_regular) {
-        GST_DEBUG ("can't handle seek on a non-regular file");
-        goto error;
-      }
-
-      offset = GST_EVENT_SEEK_OFFSET (event);
-
-      switch (GST_EVENT_SEEK_METHOD (event)) {
-        case GST_SEEK_METHOD_SET:
-          if (offset < 0) {
-            goto error;
-          } else if (offset > src->filelen && (!gst_filesrc_check_filesize (src)
-                  || offset > src->filelen)) {
-            src->curoffset = src->filelen;
-          } else {
-            src->curoffset = offset;
-          }
-          GST_DEBUG_OBJECT (src, "seek set pending to %" G_GINT64_FORMAT,
-              src->curoffset);
-          break;
-        case GST_SEEK_METHOD_CUR:
-          if (offset + src->curoffset > src->filelen &&
-              (!gst_filesrc_check_filesize (src)
-                  || offset + src->curoffset > src->filelen)) {
-            src->curoffset = src->filelen;
-          } else if (offset + src->curoffset < 0) {
-            src->curoffset = 0;
-          } else {
-            src->curoffset += offset;
-          }
-          GST_DEBUG_OBJECT (src, "seek cur pending to %" G_GINT64_FORMAT,
-              src->curoffset);
-          break;
-        case GST_SEEK_METHOD_END:
-          if (offset > 0) {
-            goto error;
-          } else if (offset > src->filelen && (!gst_filesrc_check_filesize (src)
-                  || offset > src->filelen)) {
-            src->curoffset = 0;
-          } else {
-            src->curoffset = src->filelen + offset;
-          }
-          GST_DEBUG_OBJECT (src, "seek end pending to %" G_GINT64_FORMAT,
-              src->curoffset);
-          break;
-        default:
-          goto error;
-          break;
-      }
-      src->need_discont = 1;
-      src->need_flush = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH;
-      break;
-    }
-    case GST_EVENT_SIZE:
-      if (GST_EVENT_SIZE_FORMAT (event) != GST_FORMAT_BYTES) {
-        goto error;
-      }
-      src->block_size = GST_EVENT_SIZE_VALUE (event);
-      g_object_notify (G_OBJECT (src), "blocksize");
-      break;
-    case GST_EVENT_FLUSH:
-      src->need_flush = TRUE;
-      break;
-    default:
-      goto error;
-      break;
-  }
-  gst_event_unref (event);
-  return TRUE;
-
-error:
-  gst_event_unref (event);
-  return FALSE;
-}
-
-typedef struct
-{
-  GstFileSrc *src;
-  guint best_probability;
-  GstCaps *caps;
-
-  GstBuffer *buffer;
-}
-FileSrcTypeFind;
-
-static guint8 *
-filesrc_find_peek (gpointer data, gint64 offset, guint size)
-{
-  FileSrcTypeFind *find;
-  GstBuffer *buffer;
-  GstFileSrc *src;
-
-  if (size == 0)
-    return NULL;
-
-  find = (FileSrcTypeFind *) data;
-  src = find->src;
-
-  if (offset < 0) {
-    offset += src->filelen;
-  }
-
-  buffer = NULL;
-  gst_filesrc_getrange (src->srcpad, offset, size, &buffer);
-
-  if (find->buffer) {
-    gst_buffer_unref (find->buffer);
-  }
-  find->buffer = buffer;
-
-  return GST_BUFFER_DATA (buffer);
-}
-
-static void
-filesrc_find_suggest (gpointer data, guint probability, const GstCaps * caps)
-{
-  FileSrcTypeFind *find = (FileSrcTypeFind *) data;
-
-  if (probability > find->best_probability) {
-    gst_caps_replace (&find->caps, gst_caps_copy (caps));
-    find->best_probability = probability;
-  }
-}
-
-
-static GstCaps *
-gst_filesrc_type_find (GstFileSrc * src)
-{
-  GstTypeFind gst_find;
-  FileSrcTypeFind find;
-  GList *walk, *type_list = NULL;
-  GstCaps *result = NULL;
-
-  walk = type_list = gst_type_find_factory_get_list ();
-
-  find.src = src;
-  find.best_probability = 0;
-  find.caps = NULL;
-  find.buffer = NULL;
-  gst_find.data = &find;
-  gst_find.peek = filesrc_find_peek;
-  gst_find.suggest = filesrc_find_suggest;
-  gst_find.get_length = NULL;
-
-  while (walk) {
-    GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (walk->data);
-
-    gst_type_find_factory_call_function (factory, &gst_find);
-    if (find.best_probability >= GST_TYPE_FIND_MAXIMUM)
-      break;
-    walk = g_list_next (walk);
-  }
-
-  if (find.best_probability > 0)
-    result = find.caps;
-
-  return result;
-}
-
 /*** GSTURIHANDLER INTERFACE *************************************************/
 
 static guint
index 1723008..d4b2ca0 100644 (file)
@@ -1,6 +1,7 @@
 /* GStreamer
  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
  *                    2000 Wim Taymans <wtay@chello.be>
+ *                    2005 Wim Taymans <wim@fluendo.com>
  *
  * gstfilesrc.h: 
  *
  * Boston, MA 02111-1307, USA.
  */
 
-
 #ifndef __GST_FILESRC_H__
 #define __GST_FILESRC_H__
 
+#include <sys/types.h>
 
 #include <gst/gst.h>
-#include <sys/types.h>
+#include <gst/base/gstbasesrc.h>
 
 G_BEGIN_DECLS
 
-
 #define GST_TYPE_FILESRC \
   (gst_filesrc_get_type())
 #define GST_FILESRC(obj) \
@@ -42,42 +42,29 @@ G_BEGIN_DECLS
 #define GST_IS_FILESRC_CLASS(obj) \
   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FILESRC))
 
-typedef enum {
-  GST_FILESRC_OPEN              = GST_ELEMENT_FLAG_LAST,
-
-  GST_FILESRC_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2
-} GstFileSrcFlags;
-
 typedef struct _GstFileSrc GstFileSrc;
 typedef struct _GstFileSrcClass GstFileSrcClass;
 
 struct _GstFileSrc {
-  GstElement element;
-  GstPad *srcpad;
+  GstBaseSrc element;
 
   guint pagesize;                      /* system page size*/
  
   gchar *filename;                     /* filename */
   gchar *uri;                          /* caching the URI */
   gint fd;                             /* open file descriptor*/
-  off_t filelen;                       /* what's the file length?*/
+  guint64 read_position;               /* position of fd */
 
-  off_t curoffset;                     /* current offset in file*/
-  off_t block_size;                    /* bytes per read */
   gboolean touch;                      /* whether to touch every page */
   gboolean using_mmap;                  /* whether we opened it with mmap */
   gboolean is_regular;                  /* whether it's (symlink to)
                                            a regular file */
-
   GstBuffer *mapbuf;
   size_t mapsize;
-
-  gint need_discont;
-  gboolean need_flush;
 };
 
 struct _GstFileSrcClass {
-  GstElementClass parent_class;
+  GstBaseSrcClass parent_class;
 };
 
 GType gst_filesrc_get_type(void);