multifilesink: Add next-file property

Add a property to allow control over what event causes a file
to finish being written and a new file start.  The default is
the same as before -- each buffer causes a new file to be
written.  Added is a case where buffers are written to the
same file until a discontinuity in the stream.
This commit is contained in:
David Schleef 2009-09-13 12:30:34 -07:00
parent 903c79e767
commit 78eeb6636e
2 changed files with 131 additions and 17 deletions

View file

@ -110,6 +110,7 @@
# include "config.h" # include "config.h"
#endif #endif
#include <gst/base/gstbasetransform.h> #include <gst/base/gstbasetransform.h>
#include <glib/gstdio.h>
#include "gstmultifilesink.h" #include "gstmultifilesink.h"
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
@ -129,6 +130,7 @@ GST_ELEMENT_DETAILS ("Multi-File Sink",
#define DEFAULT_LOCATION "%05d" #define DEFAULT_LOCATION "%05d"
#define DEFAULT_INDEX 0 #define DEFAULT_INDEX 0
#define DEFAULT_POST_MESSAGES FALSE #define DEFAULT_POST_MESSAGES FALSE
#define DEFAULT_NEXT_FILE GST_MULTI_FILE_SINK_NEXT_BUFFER
enum enum
{ {
@ -136,6 +138,7 @@ enum
PROP_LOCATION, PROP_LOCATION,
PROP_INDEX, PROP_INDEX,
PROP_POST_MESSAGES, PROP_POST_MESSAGES,
PROP_NEXT_FILE,
PROP_LAST PROP_LAST
}; };
@ -146,9 +149,30 @@ static void gst_multi_file_sink_set_property (GObject * object, guint prop_id,
static void gst_multi_file_sink_get_property (GObject * object, guint prop_id, static void gst_multi_file_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec); GValue * value, GParamSpec * pspec);
static gboolean gst_multi_file_sink_stop (GstBaseSink * sink);
static GstFlowReturn gst_multi_file_sink_render (GstBaseSink * sink, static GstFlowReturn gst_multi_file_sink_render (GstBaseSink * sink,
GstBuffer * buffer); GstBuffer * buffer);
#define GST_TYPE_MULTI_FILE_SINK_NEXT (gst_multi_file_sink_next_get_type ())
static GType
gst_multi_file_sink_next_get_type (void)
{
static GType multi_file_sync_next_type = 0;
static const GEnumValue next_types[] = {
{GST_MULTI_FILE_SINK_NEXT_BUFFER, "New file for each buffer", "buffer"},
{GST_MULTI_FILE_SINK_NEXT_DISCONT, "New file after each discontinuity",
"discont"},
{0, NULL, NULL}
};
if (!multi_file_sync_next_type) {
multi_file_sync_next_type =
g_enum_register_static ("GstMultiFileSinkNext", next_types);
}
return multi_file_sync_next_type;
}
GST_BOILERPLATE (GstMultiFileSink, gst_multi_file_sink, GstBaseSink, GST_BOILERPLATE (GstMultiFileSink, gst_multi_file_sink, GstBaseSink,
GST_TYPE_BASE_SINK); GST_TYPE_BASE_SINK);
@ -195,10 +219,23 @@ gst_multi_file_sink_class_init (GstMultiFileSinkClass * klass)
g_param_spec_boolean ("post-messages", "Post Messages", g_param_spec_boolean ("post-messages", "Post Messages",
"Post a message for each file with information of the buffer", "Post a message for each file with information of the buffer",
DEFAULT_POST_MESSAGES, G_PARAM_READWRITE)); DEFAULT_POST_MESSAGES, G_PARAM_READWRITE));
/**
* GstMultiFileSink:next-file
*
* When to start a new file.
*
* Since: 0.10.17
*/
g_object_class_install_property (gobject_class, PROP_NEXT_FILE,
g_param_spec_enum ("next-file", "Next File",
"When to start a new file",
GST_TYPE_MULTI_FILE_SINK_NEXT, DEFAULT_NEXT_FILE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gobject_class->finalize = gst_multi_file_sink_finalize; gobject_class->finalize = gst_multi_file_sink_finalize;
gstbasesink_class->get_times = NULL; gstbasesink_class->get_times = NULL;
gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_multi_file_sink_stop);
gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_multi_file_sink_render); gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_multi_file_sink_render);
} }
@ -250,6 +287,9 @@ gst_multi_file_sink_set_property (GObject * object, guint prop_id,
case PROP_POST_MESSAGES: case PROP_POST_MESSAGES:
sink->post_messages = g_value_get_boolean (value); sink->post_messages = g_value_get_boolean (value);
break; break;
case PROP_NEXT_FILE:
sink->next_file = g_value_get_enum (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -272,33 +312,35 @@ gst_multi_file_sink_get_property (GObject * object, guint prop_id,
case PROP_POST_MESSAGES: case PROP_POST_MESSAGES:
g_value_set_boolean (value, sink->post_messages); g_value_set_boolean (value, sink->post_messages);
break; break;
case PROP_NEXT_FILE:
g_value_set_enum (value, sink->next_file);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
} }
} }
static GstFlowReturn static gboolean
gst_multi_file_sink_render (GstBaseSink * sink, GstBuffer * buffer) gst_multi_file_sink_stop (GstBaseSink * sink)
{ {
GstMultiFileSink *multifilesink; 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); multifilesink = GST_MULTI_FILE_SINK (sink);
filename = g_strdup_printf (multifilesink->filename, multifilesink->index); if (multifilesink->file != NULL) {
ret = g_file_set_contents (filename, (char *) data, size, &error); fclose (multifilesink->file);
multifilesink->file = NULL;
}
if (!ret) return TRUE;
goto write_error; }
static void
gst_multi_file_sink_post_message (GstMultiFileSink * multifilesink,
GstBuffer * buffer, const char *filename)
{
if (multifilesink->post_messages) { if (multifilesink->post_messages) {
GstClockTime duration, timestamp; GstClockTime duration, timestamp;
GstClockTime running_time, stream_time; GstClockTime running_time, stream_time;
@ -307,7 +349,7 @@ gst_multi_file_sink_render (GstBaseSink * sink, GstBuffer * buffer)
GstSegment *segment; GstSegment *segment;
GstFormat format; GstFormat format;
segment = &sink->segment; segment = &GST_BASE_SINK (multifilesink)->segment;
format = segment->format; format = segment->format;
timestamp = GST_BUFFER_TIMESTAMP (buffer); timestamp = GST_BUFFER_TIMESTAMP (buffer);
@ -331,9 +373,70 @@ gst_multi_file_sink_render (GstBaseSink * sink, GstBuffer * buffer)
gst_element_post_message (GST_ELEMENT_CAST (multifilesink), gst_element_post_message (GST_ELEMENT_CAST (multifilesink),
gst_message_new_element (GST_OBJECT_CAST (multifilesink), s)); gst_message_new_element (GST_OBJECT_CAST (multifilesink), s));
} }
}
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);
switch (multifilesink->next_file) {
case GST_MULTI_FILE_SINK_NEXT_BUFFER:
filename = g_strdup_printf (multifilesink->filename,
multifilesink->index);
ret = g_file_set_contents (filename, (char *) data, size, &error);
if (!ret)
goto write_error;
gst_multi_file_sink_post_message (multifilesink, buffer, filename);
multifilesink->index++; multifilesink->index++;
g_free (filename); g_free (filename);
break;
case GST_MULTI_FILE_SINK_NEXT_DISCONT:
if (GST_BUFFER_IS_DISCONT (buffer)) {
if (multifilesink->file) {
fclose (multifilesink->file);
multifilesink->file = NULL;
filename = g_strdup_printf (multifilesink->filename,
multifilesink->index);
gst_multi_file_sink_post_message (multifilesink, buffer, filename);
g_free (filename);
multifilesink->index++;
}
}
if (multifilesink->file == NULL) {
filename = g_strdup_printf (multifilesink->filename,
multifilesink->index);
multifilesink->file = g_fopen (filename, "wb");
g_free (filename);
if (multifilesink->file == NULL)
goto stdio_write_error;
}
ret = fwrite (GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), 1,
multifilesink->file);
if (ret != 1)
goto stdio_write_error;
break;
default:
g_assert_not_reached ();
}
return GST_FLOW_OK; return GST_FLOW_OK;
@ -357,4 +460,8 @@ write_error:
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
stdio_write_error:
GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE,
("Error while writing to file."), (NULL));
return GST_FLOW_ERROR;
} }

View file

@ -51,6 +51,11 @@ G_BEGIN_DECLS
typedef struct _GstMultiFileSink GstMultiFileSink; typedef struct _GstMultiFileSink GstMultiFileSink;
typedef struct _GstMultiFileSinkClass GstMultiFileSinkClass; typedef struct _GstMultiFileSinkClass GstMultiFileSinkClass;
typedef enum {
GST_MULTI_FILE_SINK_NEXT_BUFFER,
GST_MULTI_FILE_SINK_NEXT_DISCONT
} GstMultiFileSinkNext;
struct _GstMultiFileSink struct _GstMultiFileSink
{ {
GstBaseSink parent; GstBaseSink parent;
@ -58,6 +63,8 @@ struct _GstMultiFileSink
gchar *filename; gchar *filename;
gint index; gint index;
gboolean post_messages; gboolean post_messages;
GstMultiFileSinkNext next_file;
FILE *file;
}; };
struct _GstMultiFileSinkClass struct _GstMultiFileSinkClass