From c35e0de65ee45b9ce684c6c50cf1ab92768d22f3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 10 Jun 2011 13:04:23 +0200 Subject: [PATCH] basesrc: add fill vmethod to basesrc 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 | 75 +++++++++++++++++++++++++++------ libs/gst/base/gstbasesrc.h | 37 +++++++++------- plugins/elements/gstfilesrc.c | 79 +++++++++++------------------------ 3 files changed, 109 insertions(+), 82 deletions(-) diff --git a/libs/gst/base/gstbasesrc.c b/libs/gst/base/gstbasesrc.c index 08175f7697..d21e7c6504 100644 --- a/libs/gst/base/gstbasesrc.c +++ b/libs/gst/base/gstbasesrc.c @@ -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); diff --git a/libs/gst/base/gstbasesrc.h b/libs/gst/base/gstbasesrc.h index d4bbd67824..c44b38ba57 100644 --- a/libs/gst/base/gstbasesrc.h +++ b/libs/gst/base/gstbasesrc.h @@ -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); diff --git a/plugins/elements/gstfilesrc.c b/plugins/elements/gstfilesrc.c index b005392c4e..bed3590ad8 100644 --- a/plugins/elements/gstfilesrc.c +++ b/plugins/elements/gstfilesrc.c @@ -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; + GST_BUFFER_OFFSET (buf) = offset; + GST_BUFFER_OFFSET_END (buf) = offset + length; - src->read_position += 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) {