basesrc: add fill vmethod to basesrc
authorWim Taymans <wim.taymans@collabora.co.uk>
Fri, 10 Jun 2011 11:04:23 +0000 (13:04 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Fri, 10 Jun 2011 11:04:23 +0000 (13:04 +0200)
Add a new fill virtual method to basesrc. The purpose of this method is to fill
a provided buffer with data.
Add a default implementation of the create method that allocates a buffer and
calls the fill method on it. This would allow the base class to implement
bufferpool and allocator negotiation on behalf of the subclasses.
Fix the blocksize property.
Make filesrc use the new fill method.

libs/gst/base/gstbasesrc.c
libs/gst/base/gstbasesrc.h
plugins/elements/gstfilesrc.c

index 08175f7..d21e7c6 100644 (file)
@@ -296,6 +296,8 @@ static gboolean gst_base_src_default_do_seek (GstBaseSrc * src,
 static gboolean gst_base_src_default_query (GstBaseSrc * src, GstQuery * query);
 static gboolean gst_base_src_default_prepare_seek_segment (GstBaseSrc * src,
     GstEvent * event, GstSegment * segment);
+static GstFlowReturn gst_base_src_default_create (GstBaseSrc * basesrc,
+    guint64 offset, guint size, GstBuffer ** buf);
 
 static gboolean gst_base_src_set_flushing (GstBaseSrc * basesrc,
     gboolean flushing, gboolean live_play, gboolean unlock, gboolean * playing);
@@ -334,10 +336,9 @@ gst_base_src_class_init (GstBaseSrcClass * klass)
   gobject_class->set_property = gst_base_src_set_property;
   gobject_class->get_property = gst_base_src_get_property;
 
-/* FIXME 0.11: blocksize property should be int, not ulong (min is >max here) */
   g_object_class_install_property (gobject_class, PROP_BLOCKSIZE,
-      g_param_spec_ulong ("blocksize", "Block size",
-          "Size in bytes to read per buffer (-1 = default)", 0, G_MAXULONG,
+      g_param_spec_uint ("blocksize", "Block size",
+          "Size in bytes to read per buffer (-1 = default)", 0, G_MAXUINT,
           DEFAULT_BLOCKSIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (gobject_class, PROP_NUM_BUFFERS,
       g_param_spec_int ("num-buffers", "num-buffers",
@@ -365,6 +366,7 @@ gst_base_src_class_init (GstBaseSrcClass * klass)
   klass->query = GST_DEBUG_FUNCPTR (gst_base_src_default_query);
   klass->prepare_seek_segment =
       GST_DEBUG_FUNCPTR (gst_base_src_default_prepare_seek_segment);
+  klass->create = GST_DEBUG_FUNCPTR (gst_base_src_default_create);
 
   /* Registering debug symbols for function pointers */
   GST_DEBUG_REGISTER_FUNCPTR (gst_base_src_activate_push);
@@ -643,9 +645,8 @@ gst_base_src_query_latency (GstBaseSrc * src, gboolean * live,
  *
  * Since: 0.10.22
  */
-/* FIXME 0.11: blocksize property should be int, not ulong */
 void
-gst_base_src_set_blocksize (GstBaseSrc * src, gulong blocksize)
+gst_base_src_set_blocksize (GstBaseSrc * src, guint blocksize)
 {
   g_return_if_fail (GST_IS_BASE_SRC (src));
 
@@ -664,11 +665,10 @@ gst_base_src_set_blocksize (GstBaseSrc * src, gulong blocksize)
  *
  * Since: 0.10.22
  */
-/* FIXME 0.11: blocksize property should be int, not ulong */
-gulong
+guint
 gst_base_src_get_blocksize (GstBaseSrc * src)
 {
-  gulong res;
+  gint res;
 
   g_return_val_if_fail (GST_IS_BASE_SRC (src), 0);
 
@@ -1246,6 +1246,55 @@ gst_base_src_prepare_seek_segment (GstBaseSrc * src, GstEvent * event,
   return result;
 }
 
+static GstFlowReturn
+gst_base_src_default_create (GstBaseSrc * src, guint64 offset,
+    guint size, GstBuffer ** buffer)
+{
+  GstBaseSrcClass *bclass;
+  GstFlowReturn ret;
+  GstBuffer *buf;
+
+  bclass = GST_BASE_SRC_GET_CLASS (src);
+
+  if (G_UNLIKELY (!bclass->fill))
+    goto no_function;
+
+  buf = gst_buffer_new_and_alloc (size);
+  if (G_UNLIKELY (buf == NULL))
+    goto alloc_failed;
+
+  if (G_LIKELY (size > 0)) {
+    /* only call fill when there is a size */
+    ret = bclass->fill (src, offset, size, buf);
+
+    if (G_UNLIKELY (ret != GST_FLOW_OK))
+      goto not_ok;
+  }
+
+  *buffer = buf;
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+no_function:
+  {
+    GST_DEBUG_OBJECT (src, "no fill function");
+    return GST_FLOW_NOT_SUPPORTED;
+  }
+alloc_failed:
+  {
+    GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", size);
+    return GST_FLOW_ERROR;
+  }
+not_ok:
+  {
+    GST_DEBUG_OBJECT (src, "fill returned %d (%s)", ret,
+        gst_flow_get_name (ret));
+    gst_buffer_unref (buf);
+    return ret;
+  }
+}
+
 /* this code implements the seeking. It is a good example
  * handling all cases.
  *
@@ -1770,7 +1819,7 @@ gst_base_src_set_property (GObject * object, guint prop_id,
 
   switch (prop_id) {
     case PROP_BLOCKSIZE:
-      gst_base_src_set_blocksize (src, g_value_get_ulong (value));
+      gst_base_src_set_blocksize (src, g_value_get_uint (value));
       break;
     case PROP_NUM_BUFFERS:
       src->num_buffers = g_value_get_int (value);
@@ -1797,7 +1846,7 @@ gst_base_src_get_property (GObject * object, guint prop_id, GValue * value,
 
   switch (prop_id) {
     case PROP_BLOCKSIZE:
-      g_value_set_ulong (value, gst_base_src_get_blocksize (src));
+      g_value_set_uint (value, gst_base_src_get_blocksize (src));
       break;
     case PROP_NUM_BUFFERS:
       g_value_set_int (value, src->num_buffers);
@@ -2211,7 +2260,7 @@ not_started:
 no_function:
   {
     GST_DEBUG_OBJECT (src, "no create function");
-    return GST_FLOW_ERROR;
+    return GST_FLOW_NOT_SUPPORTED;
   }
 unexpected_length:
   {
@@ -2290,7 +2339,7 @@ gst_base_src_loop (GstPad * pad)
   GstFlowReturn ret;
   gint64 position;
   gboolean eos;
-  gulong blocksize;
+  guint blocksize;
   GList *pending_events = NULL, *tmp;
   gboolean reconfigure;
 
@@ -2333,7 +2382,7 @@ gst_base_src_loop (GstPad * pad)
   } else
     position = -1;
 
-  GST_LOG_OBJECT (src, "next_ts %" GST_TIME_FORMAT " size %lu",
+  GST_LOG_OBJECT (src, "next_ts %" GST_TIME_FORMAT " size %u",
       GST_TIME_ARGS (position), blocksize);
 
   ret = gst_base_src_get_range (src, position, blocksize, &buf);
index d4bbd67..c44b38b 100644 (file)
@@ -81,7 +81,7 @@ struct _GstBaseSrc {
   gboolean       live_running;
 
   /* MT-protected (with LOCK) */
-  gint           blocksize;     /* size of buffers when operating push based */
+  guint          blocksize;     /* size of buffers when operating push based */
   gboolean       can_activate_push;     /* some scheduling properties */
   GstActivateMode pad_mode;
   gboolean       seekable; /* not used anymore */
@@ -117,6 +117,8 @@ struct _GstBaseSrc {
  * @get_caps: Called to get the caps to report
  * @set_caps: Notify subclass of changed output caps
  * @negotiate: Negotiated the caps with the peer.
+ * @fixate: Called during negotiation if caps need fixating. Implement instead of
+ *   setting a fixate function on the source pad.
  * @start: Start processing. Subclasses should open resources and prepare
  *    to produce data.
  * @stop: Stop processing. Subclasses should use this to close resources.
@@ -125,6 +127,13 @@ struct _GstBaseSrc {
  *    these times.
  * @get_size: Return the total size of the resource, in the configured format.
  * @is_seekable: Check if the source can seek
+ * @prepare_seek_segment: Prepare the GstSegment that will be passed to the
+ *   do_seek vmethod for executing a seek request. Sub-classes should override
+ *   this if they support seeking in formats other than the configured native
+ *   format. By default, it tries to convert the seek arguments to the
+ *   configured native format and prepare a segment in that format.
+ *   Since: 0.10.13
+ * @do_seek: Perform seeking on the resource to the indicated segment.
  * @unlock: Unlock any pending access to the resource. Subclasses should
  *    unblock any blocked function ASAP. In particular, any create() function in
  *    progress should be unblocked and should return GST_FLOW_WRONG_STATE. Any
@@ -132,23 +141,17 @@ struct _GstBaseSrc {
  *    until the @unlock_stop<!-- -->() function has been called.
  * @unlock_stop: Clear the previous unlock request. Subclasses should clear
  *    any state they set during unlock(), such as clearing command queues.
+ * @query: Handle a requested query.
  * @event: Override this to implement custom event handling.
  * @create: Ask the subclass to create a buffer with offset and size.
  *   When the subclass returns GST_FLOW_OK, it MUST return a buffer of the
  *   requested size unless fewer bytes are available because an EOS condition
  *   is near. No buffer should be returned when the return value is different
  *   from GST_FLOW_OK. A return value of GST_FLOW_UNEXPECTED signifies that the
- *   end of stream is reached.
- * @do_seek: Perform seeking on the resource to the indicated segment.
- * @prepare_seek_segment: Prepare the GstSegment that will be passed to the
- *   do_seek vmethod for executing a seek request. Sub-classes should override
- *   this if they support seeking in formats other than the configured native
- *   format. By default, it tries to convert the seek arguments to the
- *   configured native format and prepare a segment in that format.
- *   Since: 0.10.13
- * @query: Handle a requested query.
- * @fixate: Called during negotiation if caps need fixating. Implement instead of
- *   setting a fixate function on the source pad.
+ *   end of stream is reached. The default implementation will create a new
+ *   buffer from the negotiated allocator and will call @fill.
+ * @fill: Ask the subclass to fill the buffer with data for offset and size. The
+ *   passed buffer is guaranteed to hold the requested amount of bytes.
  *
  * Subclasses can override any of the available virtual methods or not, as
  * needed. At the minimum, the @create method should be overridden to produce
@@ -204,9 +207,13 @@ struct _GstBaseSrcClass {
   /* notify subclasses of an event */
   gboolean      (*event)        (GstBaseSrc *src, GstEvent *event);
 
-  /* ask the subclass to create a buffer with offset and size */
+  /* ask the subclass to create a buffer with offset and size, the default
+   * implementation will use the negotiated allocator and call fill. */
   GstFlowReturn (*create)       (GstBaseSrc *src, guint64 offset, guint size,
                                  GstBuffer **buf);
+  /* ask the subclass to fill the buffer with data from offset and size */
+  GstFlowReturn (*fill)         (GstBaseSrc *src, guint64 offset, guint size,
+                                 GstBuffer *buf);
 
   /*< private >*/
   gpointer       _gst_reserved[GST_PADDING_LARGE];
@@ -227,8 +234,8 @@ gboolean        gst_base_src_query_latency    (GstBaseSrc *src, gboolean * live,
                                                GstClockTime * min_latency,
                                                GstClockTime * max_latency);
 
-void            gst_base_src_set_blocksize    (GstBaseSrc *src, gulong blocksize);
-gulong          gst_base_src_get_blocksize    (GstBaseSrc *src);
+void            gst_base_src_set_blocksize    (GstBaseSrc *src, guint blocksize);
+guint           gst_base_src_get_blocksize    (GstBaseSrc *src);
 
 void            gst_base_src_set_do_timestamp (GstBaseSrc *src, gboolean timestamp);
 gboolean        gst_base_src_get_do_timestamp (GstBaseSrc *src);
index b005392..bed3590 100644 (file)
@@ -146,8 +146,8 @@ static gboolean gst_file_src_stop (GstBaseSrc * basesrc);
 
 static gboolean gst_file_src_is_seekable (GstBaseSrc * src);
 static gboolean gst_file_src_get_size (GstBaseSrc * src, guint64 * size);
-static GstFlowReturn gst_file_src_create (GstBaseSrc * src, guint64 offset,
-    guint length, GstBuffer ** buffer);
+static GstFlowReturn gst_file_src_fill (GstBaseSrc * src, guint64 offset,
+    guint length, GstBuffer * buf);
 static gboolean gst_file_src_query (GstBaseSrc * src, GstQuery * query);
 
 static void gst_file_src_uri_handler_init (gpointer g_iface,
@@ -197,7 +197,7 @@ gst_file_src_class_init (GstFileSrcClass * klass)
   gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_file_src_stop);
   gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_file_src_is_seekable);
   gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_file_src_get_size);
-  gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_file_src_create);
+  gstbasesrc_class->fill = GST_DEBUG_FUNCPTR (gst_file_src_fill);
   gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_file_src_query);
 
   if (sizeof (off_t) < 8) {
@@ -325,13 +325,14 @@ gst_file_src_get_property (GObject * object, guint prop_id, GValue * value,
  *
  */
 static GstFlowReturn
-gst_file_src_create_read (GstFileSrc * src, guint64 offset, guint length,
-    GstBuffer ** buffer)
+gst_file_src_fill (GstBaseSrc * basesrc, guint64 offset, guint length,
+    GstBuffer * buf)
 {
+  GstFileSrc *src;
   int ret;
-  GstBuffer *buf;
   guint8 *data;
-  gsize size;
+
+  src = GST_FILE_SRC_CAST (basesrc);
 
   if (G_UNLIKELY (src->read_position != offset)) {
     off_t res;
@@ -343,39 +344,31 @@ gst_file_src_create_read (GstFileSrc * src, guint64 offset, guint length,
     src->read_position = offset;
   }
 
-  buf = gst_buffer_new_and_alloc (length);
-  if (G_UNLIKELY (buf == NULL && length > 0))
-    goto alloc_failed;
+  data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
 
-  /* No need to read anything if length is 0 */
-  if (length > 0) {
-    data = gst_buffer_map (buf, &size, NULL, GST_MAP_WRITE);
+  GST_LOG_OBJECT (src, "Reading %d bytes at offset 0x%" G_GINT64_MODIFIER "x",
+      length, offset);
 
-    GST_LOG_OBJECT (src, "Reading %d bytes at offset 0x%" G_GINT64_MODIFIER "x",
-        length, offset);
-    ret = read (src->fd, data, length);
-    if (G_UNLIKELY (ret < 0))
-      goto could_not_read;
+  ret = read (src->fd, data, length);
+  if (G_UNLIKELY (ret < 0))
+    goto could_not_read;
 
-    /* seekable regular files should have given us what we expected */
-    if (G_UNLIKELY ((guint) ret < length && src->seekable))
-      goto unexpected_eos;
+  /* seekable regular files should have given us what we expected */
+  if (G_UNLIKELY ((guint) ret < length && src->seekable))
+    goto unexpected_eos;
 
-    /* other files should eos if they read 0 and more was requested */
-    if (G_UNLIKELY (ret == 0 && length > 0))
-      goto eos;
+  /* other files should eos if they read 0 and more was requested */
+  if (G_UNLIKELY (ret == 0))
+    goto eos;
 
-    length = ret;
+  length = ret;
 
-    gst_buffer_unmap (buf, data, length);
+  gst_buffer_unmap (buf, data, length);
 
-    GST_BUFFER_OFFSET (buf) = offset;
-    GST_BUFFER_OFFSET_END (buf) = offset + length;
-
-    src->read_position += length;
-  }
+  GST_BUFFER_OFFSET (buf) = offset;
+  GST_BUFFER_OFFSET_END (buf) = offset + length;
 
-  *buffer = buf;
+  src->read_position += length;
 
   return GST_FLOW_OK;
 
@@ -385,16 +378,10 @@ seek_failed:
     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
     return GST_FLOW_ERROR;
   }
-alloc_failed:
-  {
-    GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", length);
-    return GST_FLOW_ERROR;
-  }
 could_not_read:
   {
     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
     gst_buffer_unmap (buf, data, 0);
-    gst_buffer_unref (buf);
     return GST_FLOW_ERROR;
   }
 unexpected_eos:
@@ -402,32 +389,16 @@ unexpected_eos:
     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
         ("unexpected end of file."));
     gst_buffer_unmap (buf, data, 0);
-    gst_buffer_unref (buf);
     return GST_FLOW_ERROR;
   }
 eos:
   {
     GST_DEBUG ("non-regular file hits EOS");
     gst_buffer_unmap (buf, data, 0);
-    gst_buffer_unref (buf);
     return GST_FLOW_UNEXPECTED;
   }
 }
 
-static GstFlowReturn
-gst_file_src_create (GstBaseSrc * basesrc, guint64 offset, guint length,
-    GstBuffer ** buffer)
-{
-  GstFileSrc *src;
-  GstFlowReturn ret;
-
-  src = GST_FILE_SRC_CAST (basesrc);
-
-  ret = gst_file_src_create_read (src, offset, length, buffer);
-
-  return ret;
-}
-
 static gboolean
 gst_file_src_query (GstBaseSrc * basesrc, GstQuery * query)
 {