mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
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:
parent
903c79e767
commit
78eeb6636e
2 changed files with 131 additions and 17 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue