From f68cd7e7080a9221cae97d29289e6b8bb12f5fbc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 11 Sep 2009 12:16:18 +0200 Subject: multifilesink: post messages for each buffer Add a silent property that can be set to FALSE to post messages on the bus for each written file. Do some more cleanups. Add some docs. Fixes #594663 --- gst/multifile/gstmultifilesink.c | 247 +++++++++++++++++++++++++++++---------- gst/multifile/gstmultifilesink.h | 4 +- 2 files changed, 187 insertions(+), 64 deletions(-) (limited to 'gst/multifile') diff --git a/gst/multifile/gstmultifilesink.c b/gst/multifile/gstmultifilesink.c index 3c92cf7c..9097c736 100644 --- a/gst/multifile/gstmultifilesink.c +++ b/gst/multifile/gstmultifilesink.c @@ -26,12 +26,90 @@ * @see_also: #GstFileSrc * * Write incoming data to a series of sequentially-named files. + * + * The filename property should contain a string with a %d placeholder that will + * be substituted with the index for each filename. + * + * If the #GstMultiFileSink:silent property is #FALSE, it sends an application + * message named + * "GstMultiFileSink" after writing each + * buffer. + * + * The message's structure contains these fields: + * + * + * + * #gchar * + * "filename": + * the filename where the buffer was written. + * + * + * + * + * #gint + * "index": + * the index of the buffer. + * + * + * + * + * #GstClockTime + * "timestamp": + * the timestamp of the buffer. + * + * + * + * + * #GstClockTime + * "stream-time": + * the stream time of the buffer. + * + * + * + * + * #GstClockTime + * "running-time": + * the running_time of the buffer. + * + * + * + * + * #GstClockTime + * "duration": + * the duration of the buffer. + * + * + * + * + * #guint64 + * "offset": + * the offset of the buffer that triggered the message. + * + * + * + * + * #guint64 + * "offset-end": + * the offset-end of the buffer that triggered the message. + * + * + * + * + * Example launch line + * + * |[ + * gst-launch audiotestsrc ! multifilesink + * gst-launch videotestsrc ! multifilesink silent=false filename="frame%d" + * ]| + * + * + * Last reviewed on 2009-09-11 (0.10.17) */ #ifdef HAVE_CONFIG_H # include "config.h" #endif - +#include #include "gstmultifilesink.h" static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", @@ -48,17 +126,20 @@ GST_ELEMENT_DETAILS ("Multi-File Sink", "Write buffers to a sequentially named set of files", "David Schleef "); +#define DEFAULT_LOCATION "%05d" +#define DEFAULT_INDEX 0 +#define DEFAULT_SILENT TRUE + enum { - ARG_0, - ARG_LOCATION, - ARG_INDEX + PROP_0, + PROP_LOCATION, + PROP_INDEX, + PROP_SILENT, + PROP_LAST }; -#define DEFAULT_LOCATION "%05d" -#define DEFAULT_INDEX 0 - -static void gst_multi_file_sink_dispose (GObject * object); +static void gst_multi_file_sink_finalize (GObject * object); static void gst_multi_file_sink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); @@ -68,8 +149,6 @@ static void gst_multi_file_sink_get_property (GObject * object, guint prop_id, static GstFlowReturn gst_multi_file_sink_render (GstBaseSink * sink, GstBuffer * buffer); - - GST_BOILERPLATE (GstMultiFileSink, gst_multi_file_sink, GstBaseSink, GST_TYPE_BASE_SINK); @@ -96,16 +175,28 @@ gst_multi_file_sink_class_init (GstMultiFileSinkClass * klass) gobject_class->set_property = gst_multi_file_sink_set_property; gobject_class->get_property = gst_multi_file_sink_get_property; - g_object_class_install_property (gobject_class, ARG_LOCATION, + g_object_class_install_property (gobject_class, PROP_LOCATION, g_param_spec_string ("location", "File Location", "Location of the file to write", NULL, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_INDEX, + + g_object_class_install_property (gobject_class, PROP_INDEX, g_param_spec_int ("index", "Index", "Index to use with location property to create file names. The " - "index is incremented by one for each buffer read.", - 0, INT_MAX, DEFAULT_INDEX, G_PARAM_READWRITE)); - - gobject_class->dispose = gst_multi_file_sink_dispose; + "index is incremented by one for each buffer written.", + 0, G_MAXINT, DEFAULT_INDEX, G_PARAM_READWRITE)); + /** + * GstMultiFileSink:silent + * + * Post a message on the GstBus for each file. + * + * Since: 0.10.17 + */ + g_object_class_install_property (gobject_class, PROP_SILENT, + g_param_spec_boolean ("silent", "Silent", + "Message to show a message for each file to save with the timestamp " + " of the buffer", DEFAULT_SILENT, G_PARAM_READWRITE)); + + gobject_class->finalize = gst_multi_file_sink_finalize; gstbasesink_class->get_times = NULL; gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_multi_file_sink_render); @@ -117,19 +208,19 @@ gst_multi_file_sink_init (GstMultiFileSink * multifilesink, { multifilesink->filename = g_strdup (DEFAULT_LOCATION); multifilesink->index = DEFAULT_INDEX; + multifilesink->silent = DEFAULT_SILENT; - GST_BASE_SINK (multifilesink)->sync = FALSE; + gst_base_sink_set_sync (GST_BASE_SINK (multifilesink), FALSE); } static void -gst_multi_file_sink_dispose (GObject * object) +gst_multi_file_sink_finalize (GObject * object) { GstMultiFileSink *sink = GST_MULTI_FILE_SINK (object); g_free (sink->filename); - sink->filename = NULL; - G_OBJECT_CLASS (parent_class)->dispose (object); + G_OBJECT_CLASS (parent_class)->finalize (object); } static gboolean @@ -137,12 +228,8 @@ gst_multi_file_sink_set_location (GstMultiFileSink * sink, const gchar * location) { g_free (sink->filename); - if (location != NULL) { - /* FIXME: validate location to have just one %d */ - sink->filename = g_strdup (location); - } else { - sink->filename = NULL; - } + /* FIXME: validate location to have just one %d */ + sink->filename = g_strdup (location); return TRUE; } @@ -154,12 +241,15 @@ gst_multi_file_sink_set_property (GObject * object, guint prop_id, GstMultiFileSink *sink = GST_MULTI_FILE_SINK (object); switch (prop_id) { - case ARG_LOCATION: + case PROP_LOCATION: gst_multi_file_sink_set_location (sink, g_value_get_string (value)); break; - case ARG_INDEX: + case PROP_INDEX: sink->index = g_value_get_int (value); break; + case PROP_SILENT: + sink->silent = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -173,65 +263,98 @@ gst_multi_file_sink_get_property (GObject * object, guint prop_id, GstMultiFileSink *sink = GST_MULTI_FILE_SINK (object); switch (prop_id) { - case ARG_LOCATION: + case PROP_LOCATION: g_value_set_string (value, sink->filename); break; - case ARG_INDEX: + case PROP_INDEX: g_value_set_int (value, sink->index); break; + case PROP_SILENT: + g_value_set_boolean (value, sink->silent); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } -static gchar * -gst_multi_file_sink_get_filename (GstMultiFileSink * multifilesink) -{ - gchar *filename; - - filename = g_strdup_printf (multifilesink->filename, multifilesink->index); - - return filename; -} - static GstFlowReturn gst_multi_file_sink_render (GstBaseSink * sink, GstBuffer * buffer) { GstMultiFileSink *multifilesink; guint size; + guint8 *data; gchar *filename; gboolean ret; GError *error = NULL; size = GST_BUFFER_SIZE (buffer); + data = GST_BUFFER_DATA (buffer); multifilesink = GST_MULTI_FILE_SINK (sink); - filename = gst_multi_file_sink_get_filename (multifilesink); - - ret = g_file_set_contents (filename, (char *) GST_BUFFER_DATA (buffer), - size, &error); - if (ret) { - multifilesink->index++; - g_free (filename); - return GST_FLOW_OK; + filename = g_strdup_printf (multifilesink->filename, multifilesink->index); + ret = g_file_set_contents (filename, (char *) data, size, &error); + + if (!ret) + goto write_error; + + if (!multifilesink->silent) { + GstClockTime duration, timestamp; + GstClockTime running_time, stream_time; + guint64 offset, offset_end; + GstStructure *s; + GstSegment *segment; + GstFormat format; + + segment = &sink->segment; + format = segment->format; + + timestamp = GST_BUFFER_TIMESTAMP (buffer); + duration = GST_BUFFER_DURATION (buffer); + offset = GST_BUFFER_OFFSET (buffer); + offset_end = GST_BUFFER_OFFSET_END (buffer); + + running_time = gst_segment_to_running_time (segment, format, timestamp); + stream_time = gst_segment_to_stream_time (segment, format, timestamp); + + s = gst_structure_new ("GstMultiFileSink", + "filename", G_TYPE_STRING, filename, + "index", G_TYPE_INT, multifilesink->index, + "timestamp", G_TYPE_UINT64, timestamp, + "stream-time", G_TYPE_UINT64, stream_time, + "running-time", G_TYPE_UINT64, running_time, + "duration", G_TYPE_UINT64, duration, + "offset", G_TYPE_UINT64, offset, + "offset-end", G_TYPE_UINT64, offset_end, NULL); + + gst_element_post_message (GST_ELEMENT_CAST (multifilesink), + gst_message_new_element (GST_OBJECT_CAST (multifilesink), s)); } - switch (error->code) { - case G_FILE_ERROR_NOSPC:{ - GST_ELEMENT_ERROR (multifilesink, RESOURCE, NO_SPACE_LEFT, (NULL), - (NULL)); - break; - } - default:{ - GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE, - ("Error while writing to file \"%s\".", filename), - ("%s", g_strerror (errno))); - } - } - g_error_free (error); + multifilesink->index++; g_free (filename); - return GST_FLOW_ERROR; + return GST_FLOW_OK; + + /* ERRORS */ +write_error: + { + switch (error->code) { + case G_FILE_ERROR_NOSPC:{ + GST_ELEMENT_ERROR (multifilesink, RESOURCE, NO_SPACE_LEFT, (NULL), + (NULL)); + break; + } + default:{ + GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE, + ("Error while writing to file \"%s\".", filename), + ("%s", g_strerror (errno))); + } + } + g_error_free (error); + g_free (filename); + + return GST_FLOW_ERROR; + } } diff --git a/gst/multifile/gstmultifilesink.h b/gst/multifile/gstmultifilesink.h index c26a64a1..1751fb3d 100644 --- a/gst/multifile/gstmultifilesink.h +++ b/gst/multifile/gstmultifilesink.h @@ -56,8 +56,8 @@ struct _GstMultiFileSink GstBaseSink parent; gchar *filename; - gchar *uri; - int index; + gint index; + gboolean silent; }; struct _GstMultiFileSinkClass -- cgit