I don't know how I ever got to introducing this madness, but I was wrong. *REALLY* wrong. It hasn't even worked, it s...

Original commit message from CVS:
I don't know how I ever got to introducing this madness, but I was wrong. *REALLY* wrong. It hasn't even worked, it still doesn't work and it will never work because the whole concept of doing a multifile output in filesink is completely braindead. Signal EOS, close file, set new filename and reset to PLAYING is so much easier. This patch removes all the multifile output cruft that I introduced and makes filesink simply work.
This commit is contained in:
Ronald S. Bultje 2003-06-01 12:27:39 +00:00
parent e5872bf925
commit 2ddc5c4974
4 changed files with 224 additions and 218 deletions

View file

@ -46,8 +46,7 @@ enum {
enum { enum {
ARG_0, ARG_0,
ARG_LOCATION, ARG_LOCATION
ARG_MAXFILESIZE,
}; };
GST_PAD_EVENT_MASK_FUNCTION (gst_filesink_get_event_mask, GST_PAD_EVENT_MASK_FUNCTION (gst_filesink_get_event_mask,
@ -56,8 +55,16 @@ GST_PAD_EVENT_MASK_FUNCTION (gst_filesink_get_event_mask,
GST_SEEK_METHOD_END | GST_SEEK_METHOD_END |
GST_SEEK_FLAG_FLUSH }, GST_SEEK_FLAG_FLUSH },
{ GST_EVENT_FLUSH, 0 }, { GST_EVENT_FLUSH, 0 },
{ GST_EVENT_DISCONTINUOUS, 0 }, { GST_EVENT_DISCONTINUOUS, 0 }
{ GST_EVENT_NEW_MEDIA, 0 } )
GST_PAD_QUERY_TYPE_FUNCTION (gst_filesink_get_query_types,
GST_QUERY_TOTAL,
GST_QUERY_POSITION
)
GST_PAD_FORMATS_FUNCTION (gst_filesink_get_formats,
GST_FORMAT_BYTES
) )
@ -73,6 +80,8 @@ static gboolean gst_filesink_open_file (GstFileSink *sink);
static void gst_filesink_close_file (GstFileSink *sink); static void gst_filesink_close_file (GstFileSink *sink);
static gboolean gst_filesink_handle_event (GstPad *pad, GstEvent *event); static gboolean gst_filesink_handle_event (GstPad *pad, GstEvent *event);
static gboolean gst_filesink_pad_query (GstPad *pad, GstQueryType type,
GstFormat *format, gint64 *value);
static void gst_filesink_chain (GstPad *pad,GstBuffer *buf); static void gst_filesink_chain (GstPad *pad,GstBuffer *buf);
static GstElementStateReturn gst_filesink_change_state (GstElement *element); static GstElementStateReturn gst_filesink_change_state (GstElement *element);
@ -115,9 +124,6 @@ gst_filesink_class_init (GstFileSinkClass *klass)
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOCATION, g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOCATION,
g_param_spec_string ("location", "File Location", "Location of the file to write", g_param_spec_string ("location", "File Location", "Location of the file to write",
NULL, G_PARAM_READWRITE)); NULL, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAXFILESIZE,
g_param_spec_int ("maxfilesize", "MaxFileSize", "Maximum Size Per File in MB (-1 == no limit)",
-1, G_MAXINT, -1, G_PARAM_READWRITE));
gst_filesink_signals[SIGNAL_HANDOFF] = gst_filesink_signals[SIGNAL_HANDOFF] =
g_signal_new ("handoff", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, g_signal_new ("handoff", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
@ -143,30 +149,12 @@ gst_filesink_init (GstFileSink *filesink)
gst_pad_set_event_function(pad, gst_filesink_handle_event); gst_pad_set_event_function(pad, gst_filesink_handle_event);
gst_pad_set_event_mask_function(pad, gst_filesink_get_event_mask); gst_pad_set_event_mask_function(pad, gst_filesink_get_event_mask);
gst_pad_set_query_function (pad, gst_filesink_pad_query);
gst_pad_set_query_type_function (pad, gst_filesink_get_query_types);
gst_pad_set_formats_function (pad, gst_filesink_get_formats);
filesink->filename = NULL; filesink->filename = NULL;
filesink->file = NULL; filesink->file = NULL;
filesink->filenum = 0;
filesink->maxfilesize = -1;
}
static char *
gst_filesink_getcurrentfilename (GstFileSink *filesink)
{
g_return_val_if_fail(filesink != NULL, NULL);
g_return_val_if_fail(GST_IS_FILESINK(filesink), NULL);
if (filesink->filename == NULL) return NULL;
g_return_val_if_fail(filesink->filenum >= 0, NULL);
if (!strstr(filesink->filename, "%"))
{
if (!filesink->filenum)
return g_strdup(filesink->filename);
else
return NULL;
}
return g_strdup_printf(filesink->filename, filesink->filenum);
} }
static void static void
@ -180,23 +168,18 @@ gst_filesink_set_property (GObject *object, guint prop_id, const GValue *value,
switch (prop_id) { switch (prop_id) {
case ARG_LOCATION: case ARG_LOCATION:
/* the element must be stopped or paused in order to do this */ /* the element must be stopped or paused in order to do this */
g_return_if_fail ((GST_STATE (sink) < GST_STATE_PLAYING) g_return_if_fail (GST_STATE (sink) < GST_STATE_PLAYING);
|| (GST_STATE (sink) == GST_STATE_PAUSED));
if (sink->filename) if (sink->filename)
g_free (sink->filename); g_free (sink->filename);
sink->filename = g_strdup (g_value_get_string (value)); sink->filename = g_strdup (g_value_get_string (value));
if ( (GST_STATE (sink) == GST_STATE_PAUSED) if ((GST_STATE (sink) == GST_STATE_PAUSED) &&
&& (sink->filename != NULL)) (sink->filename != NULL)) {
{ gst_filesink_close_file (sink);
gst_filesink_close_file (sink); gst_filesink_open_file (sink);
gst_filesink_open_file (sink);
} }
break;
case ARG_MAXFILESIZE:
sink->maxfilesize = g_value_get_int(value);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
} }
} }
@ -213,10 +196,7 @@ gst_filesink_get_property (GObject *object, guint prop_id, GValue *value, GParam
switch (prop_id) { switch (prop_id) {
case ARG_LOCATION: case ARG_LOCATION:
g_value_set_string (value, gst_filesink_getcurrentfilename(sink)); g_value_set_string (value, sink->filename);
break;
case ARG_MAXFILESIZE:
g_value_set_int (value, sink->maxfilesize);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -230,16 +210,17 @@ gst_filesink_open_file (GstFileSink *sink)
g_return_val_if_fail (!GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN), FALSE); g_return_val_if_fail (!GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN), FALSE);
/* open the file */ /* open the file */
if (!gst_filesink_getcurrentfilename(sink)) if (!sink->filename)
{ {
/* Out of files */ /* Out of files */
return FALSE; return FALSE;
} }
sink->file = fopen (gst_filesink_getcurrentfilename(sink), "w");
sink->file = fopen (sink->filename, "w");
if (sink->file == NULL) { if (sink->file == NULL) {
perror ("open"); gst_element_error (GST_ELEMENT (sink),
gst_element_error (GST_ELEMENT (sink), g_strconcat("Error opening file \"", "Error opening file %s: %s",
gst_filesink_getcurrentfilename(sink), "\": ", g_strerror(errno), NULL)); sink->filename, g_strerror(errno));
return FALSE; return FALSE;
} }
@ -257,15 +238,52 @@ gst_filesink_close_file (GstFileSink *sink)
if (fclose (sink->file) != 0) if (fclose (sink->file) != 0)
{ {
perror ("close"); gst_element_error (GST_ELEMENT (sink),
gst_element_error (GST_ELEMENT (sink), g_strconcat("Error closing file \"", "Error closing file %s: %s",
gst_filesink_getcurrentfilename(sink), "\": ", g_strerror(errno), NULL)); sink->filename, g_strerror(errno));
} }
else { else {
GST_FLAG_UNSET (sink, GST_FILESINK_OPEN); GST_FLAG_UNSET (sink, GST_FILESINK_OPEN);
} }
} }
static gboolean
gst_filesink_pad_query (GstPad *pad, GstQueryType type,
GstFormat *format, gint64 *value)
{
GstFileSink *sink = GST_FILESINK (GST_PAD_PARENT (pad));
switch (type) {
case GST_QUERY_TOTAL:
switch (*format) {
case GST_FORMAT_BYTES:
if (GST_FLAG_IS_SET (GST_ELEMENT(sink), GST_FILESINK_OPEN)) {
*value = sink->data_written; /* FIXME - doesn't the kernel provide
such a function? */
break;
}
default:
return FALSE;
}
break;
case GST_QUERY_POSITION:
switch (*format) {
case GST_FORMAT_BYTES:
if (GST_FLAG_IS_SET (GST_ELEMENT(sink), GST_FILESINK_OPEN)) {
*value = ftell (sink->file);
break;
}
default:
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
/* handle events (search) */ /* handle events (search) */
static gboolean static gboolean
gst_filesink_handle_event (GstPad *pad, GstEvent *event) gst_filesink_handle_event (GstPad *pad, GstEvent *event)
@ -275,31 +293,32 @@ gst_filesink_handle_event (GstPad *pad, GstEvent *event)
filesink = GST_FILESINK (gst_pad_get_parent (pad)); filesink = GST_FILESINK (gst_pad_get_parent (pad));
g_return_val_if_fail (GST_FLAG_IS_SET (filesink, GST_FILESINK_OPEN),
FALSE);
type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN; type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
switch (type) { switch (type) {
case GST_EVENT_SEEK: case GST_EVENT_SEEK:
/* we need to seek */ g_return_val_if_fail (GST_EVENT_SEEK_FORMAT (event) == GST_FORMAT_BYTES,
if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) FALSE);
if (fflush(filesink->file))
gst_element_error(GST_ELEMENT(filesink),
"Error flushing the buffer cache of file \'%s\' to disk: %s",
gst_filesink_getcurrentfilename(filesink), g_strerror(errno));
if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) { if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH)
g_warning("Any other then byte-offset seeking is not supported!\n"); if (fflush (filesink->file))
} gst_element_error (GST_ELEMENT (filesink),
"Error flushing file %s: %s",
filesink->filename, g_strerror(errno));
switch (GST_EVENT_SEEK_METHOD(event)) switch (GST_EVENT_SEEK_METHOD(event))
{ {
case GST_SEEK_METHOD_SET: case GST_SEEK_METHOD_SET:
fseek(filesink->file, GST_EVENT_SEEK_OFFSET(event), SEEK_SET); fseek (filesink->file, GST_EVENT_SEEK_OFFSET (event), SEEK_SET);
break; break;
case GST_SEEK_METHOD_CUR: case GST_SEEK_METHOD_CUR:
fseek(filesink->file, GST_EVENT_SEEK_OFFSET(event), SEEK_CUR); fseek (filesink->file, GST_EVENT_SEEK_OFFSET (event), SEEK_CUR);
break; break;
case GST_SEEK_METHOD_END: case GST_SEEK_METHOD_END:
fseek(filesink->file, GST_EVENT_SEEK_OFFSET(event), SEEK_END); fseek (filesink->file, GST_EVENT_SEEK_OFFSET (event), SEEK_END);
break; break;
default: default:
g_warning("unkown seek method!\n"); g_warning("unkown seek method!\n");
@ -311,26 +330,21 @@ gst_filesink_handle_event (GstPad *pad, GstEvent *event)
gint64 offset; gint64 offset;
if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &offset)) if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &offset))
fseek(filesink->file, offset, SEEK_SET); fseek (filesink->file, offset, SEEK_SET);
gst_event_unref (event); gst_event_unref (event);
break; break;
} }
case GST_EVENT_NEW_MEDIA: case GST_EVENT_FLUSH:
/* we need to open a new file! */ if (fflush (filesink->file)) {
gst_filesink_close_file(filesink); gst_element_error (GST_ELEMENT (filesink),
filesink->filenum++; "Error flushing file %s: %s",
if (!gst_filesink_open_file(filesink)) { filesink->filename, g_strerror(errno));
/* no more files, give EOS */
gst_element_set_eos(GST_ELEMENT(filesink));
return FALSE;
} }
break; break;
case GST_EVENT_FLUSH: case GST_EVENT_EOS:
if (fflush(filesink->file)) gst_filesink_close_file (filesink);
gst_element_error(GST_ELEMENT(filesink), gst_element_set_eos (GST_ELEMENT (filesink));
"Error flushing the buffer cache of file \'%s\' to disk: %s",
gst_filesink_getcurrentfilename(filesink), g_strerror(errno));
break; break;
default: default:
gst_pad_event_default (pad, event); gst_pad_event_default (pad, event);
@ -365,34 +379,23 @@ gst_filesink_chain (GstPad *pad, GstBuffer *buf)
return; return;
} }
if (filesink->maxfilesize > 0)
{
if ((filesink->data_written + GST_BUFFER_SIZE(buf))/(1024*1024) > filesink->maxfilesize)
{
if (GST_ELEMENT_IS_EVENT_AWARE(GST_ELEMENT(filesink)))
{
GstEvent *event;
event = gst_event_new(GST_EVENT_NEW_MEDIA);
gst_pad_send_event(pad, event);
}
}
}
if (GST_FLAG_IS_SET (filesink, GST_FILESINK_OPEN)) if (GST_FLAG_IS_SET (filesink, GST_FILESINK_OPEN))
{ {
bytes_written = fwrite (GST_BUFFER_DATA (buf), 1, GST_BUFFER_SIZE (buf), filesink->file); bytes_written = fwrite (GST_BUFFER_DATA (buf), 1,
GST_BUFFER_SIZE (buf), filesink->file);
if (bytes_written < GST_BUFFER_SIZE (buf)) if (bytes_written < GST_BUFFER_SIZE (buf))
{ {
printf ("filesink : Warning : %d bytes should be written, only %d bytes written\n", g_warning ("filesink: %d bytes should be written, only %d bytes written\n",
GST_BUFFER_SIZE (buf), bytes_written); GST_BUFFER_SIZE (buf), bytes_written);
} }
filesink->data_written += bytes_written;
} }
filesink->data_written += GST_BUFFER_SIZE(buf);
gst_buffer_unref (buf); gst_buffer_unref (buf);
g_signal_emit (G_OBJECT (filesink), gst_filesink_signals[SIGNAL_HANDOFF], 0, g_signal_emit (G_OBJECT (filesink),
filesink); gst_filesink_signals[SIGNAL_HANDOFF], 0,
filesink);
} }
static GstElementStateReturn static GstElementStateReturn
@ -400,14 +403,18 @@ gst_filesink_change_state (GstElement *element)
{ {
g_return_val_if_fail (GST_IS_FILESINK (element), GST_STATE_FAILURE); g_return_val_if_fail (GST_IS_FILESINK (element), GST_STATE_FAILURE);
if (GST_STATE_PENDING (element) == GST_STATE_NULL) { switch (GST_STATE_TRANSITION (element)) {
if (GST_FLAG_IS_SET (element, GST_FILESINK_OPEN)) case GST_STATE_PAUSED_TO_READY:
gst_filesink_close_file (GST_FILESINK (element)); if (GST_FLAG_IS_SET (element, GST_FILESINK_OPEN))
} else { gst_filesink_close_file (GST_FILESINK (element));
if (!GST_FLAG_IS_SET (element, GST_FILESINK_OPEN)) { break;
if (!gst_filesink_open_file (GST_FILESINK (element)))
return GST_STATE_FAILURE; case GST_STATE_READY_TO_PAUSED:
} if (!GST_FLAG_IS_SET (element, GST_FILESINK_OPEN)) {
if (!gst_filesink_open_file (GST_FILESINK (element)))
return GST_STATE_FAILURE;
}
break;
} }
if (GST_ELEMENT_CLASS (parent_class)->change_state) if (GST_ELEMENT_CLASS (parent_class)->change_state)
@ -415,4 +422,3 @@ gst_filesink_change_state (GstElement *element)
return GST_STATE_SUCCESS; return GST_STATE_SUCCESS;
} }

View file

@ -59,17 +59,14 @@ struct _GstFileSink {
gchar *filename; gchar *filename;
FILE *file; FILE *file;
gint filenum;
guint64 data_written; guint64 data_written;
gint maxfilesize;
}; };
struct _GstFileSinkClass { struct _GstFileSinkClass {
GstElementClass parent_class; GstElementClass parent_class;
/* signals */ /* signals */
void (*handoff) (GstElement *element,GstPad *pad); void (*handoff) (GstElement *element, GstPad *pad);
}; };
GType gst_filesink_get_type(void); GType gst_filesink_get_type(void);

View file

@ -46,8 +46,7 @@ enum {
enum { enum {
ARG_0, ARG_0,
ARG_LOCATION, ARG_LOCATION
ARG_MAXFILESIZE,
}; };
GST_PAD_EVENT_MASK_FUNCTION (gst_filesink_get_event_mask, GST_PAD_EVENT_MASK_FUNCTION (gst_filesink_get_event_mask,
@ -56,8 +55,16 @@ GST_PAD_EVENT_MASK_FUNCTION (gst_filesink_get_event_mask,
GST_SEEK_METHOD_END | GST_SEEK_METHOD_END |
GST_SEEK_FLAG_FLUSH }, GST_SEEK_FLAG_FLUSH },
{ GST_EVENT_FLUSH, 0 }, { GST_EVENT_FLUSH, 0 },
{ GST_EVENT_DISCONTINUOUS, 0 }, { GST_EVENT_DISCONTINUOUS, 0 }
{ GST_EVENT_NEW_MEDIA, 0 } )
GST_PAD_QUERY_TYPE_FUNCTION (gst_filesink_get_query_types,
GST_QUERY_TOTAL,
GST_QUERY_POSITION
)
GST_PAD_FORMATS_FUNCTION (gst_filesink_get_formats,
GST_FORMAT_BYTES
) )
@ -73,6 +80,8 @@ static gboolean gst_filesink_open_file (GstFileSink *sink);
static void gst_filesink_close_file (GstFileSink *sink); static void gst_filesink_close_file (GstFileSink *sink);
static gboolean gst_filesink_handle_event (GstPad *pad, GstEvent *event); static gboolean gst_filesink_handle_event (GstPad *pad, GstEvent *event);
static gboolean gst_filesink_pad_query (GstPad *pad, GstQueryType type,
GstFormat *format, gint64 *value);
static void gst_filesink_chain (GstPad *pad,GstBuffer *buf); static void gst_filesink_chain (GstPad *pad,GstBuffer *buf);
static GstElementStateReturn gst_filesink_change_state (GstElement *element); static GstElementStateReturn gst_filesink_change_state (GstElement *element);
@ -115,9 +124,6 @@ gst_filesink_class_init (GstFileSinkClass *klass)
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOCATION, g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOCATION,
g_param_spec_string ("location", "File Location", "Location of the file to write", g_param_spec_string ("location", "File Location", "Location of the file to write",
NULL, G_PARAM_READWRITE)); NULL, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAXFILESIZE,
g_param_spec_int ("maxfilesize", "MaxFileSize", "Maximum Size Per File in MB (-1 == no limit)",
-1, G_MAXINT, -1, G_PARAM_READWRITE));
gst_filesink_signals[SIGNAL_HANDOFF] = gst_filesink_signals[SIGNAL_HANDOFF] =
g_signal_new ("handoff", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, g_signal_new ("handoff", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
@ -143,30 +149,12 @@ gst_filesink_init (GstFileSink *filesink)
gst_pad_set_event_function(pad, gst_filesink_handle_event); gst_pad_set_event_function(pad, gst_filesink_handle_event);
gst_pad_set_event_mask_function(pad, gst_filesink_get_event_mask); gst_pad_set_event_mask_function(pad, gst_filesink_get_event_mask);
gst_pad_set_query_function (pad, gst_filesink_pad_query);
gst_pad_set_query_type_function (pad, gst_filesink_get_query_types);
gst_pad_set_formats_function (pad, gst_filesink_get_formats);
filesink->filename = NULL; filesink->filename = NULL;
filesink->file = NULL; filesink->file = NULL;
filesink->filenum = 0;
filesink->maxfilesize = -1;
}
static char *
gst_filesink_getcurrentfilename (GstFileSink *filesink)
{
g_return_val_if_fail(filesink != NULL, NULL);
g_return_val_if_fail(GST_IS_FILESINK(filesink), NULL);
if (filesink->filename == NULL) return NULL;
g_return_val_if_fail(filesink->filenum >= 0, NULL);
if (!strstr(filesink->filename, "%"))
{
if (!filesink->filenum)
return g_strdup(filesink->filename);
else
return NULL;
}
return g_strdup_printf(filesink->filename, filesink->filenum);
} }
static void static void
@ -180,23 +168,18 @@ gst_filesink_set_property (GObject *object, guint prop_id, const GValue *value,
switch (prop_id) { switch (prop_id) {
case ARG_LOCATION: case ARG_LOCATION:
/* the element must be stopped or paused in order to do this */ /* the element must be stopped or paused in order to do this */
g_return_if_fail ((GST_STATE (sink) < GST_STATE_PLAYING) g_return_if_fail (GST_STATE (sink) < GST_STATE_PLAYING);
|| (GST_STATE (sink) == GST_STATE_PAUSED));
if (sink->filename) if (sink->filename)
g_free (sink->filename); g_free (sink->filename);
sink->filename = g_strdup (g_value_get_string (value)); sink->filename = g_strdup (g_value_get_string (value));
if ( (GST_STATE (sink) == GST_STATE_PAUSED) if ((GST_STATE (sink) == GST_STATE_PAUSED) &&
&& (sink->filename != NULL)) (sink->filename != NULL)) {
{ gst_filesink_close_file (sink);
gst_filesink_close_file (sink); gst_filesink_open_file (sink);
gst_filesink_open_file (sink);
} }
break;
case ARG_MAXFILESIZE:
sink->maxfilesize = g_value_get_int(value);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
} }
} }
@ -213,10 +196,7 @@ gst_filesink_get_property (GObject *object, guint prop_id, GValue *value, GParam
switch (prop_id) { switch (prop_id) {
case ARG_LOCATION: case ARG_LOCATION:
g_value_set_string (value, gst_filesink_getcurrentfilename(sink)); g_value_set_string (value, sink->filename);
break;
case ARG_MAXFILESIZE:
g_value_set_int (value, sink->maxfilesize);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -230,16 +210,17 @@ gst_filesink_open_file (GstFileSink *sink)
g_return_val_if_fail (!GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN), FALSE); g_return_val_if_fail (!GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN), FALSE);
/* open the file */ /* open the file */
if (!gst_filesink_getcurrentfilename(sink)) if (!sink->filename)
{ {
/* Out of files */ /* Out of files */
return FALSE; return FALSE;
} }
sink->file = fopen (gst_filesink_getcurrentfilename(sink), "w");
sink->file = fopen (sink->filename, "w");
if (sink->file == NULL) { if (sink->file == NULL) {
perror ("open"); gst_element_error (GST_ELEMENT (sink),
gst_element_error (GST_ELEMENT (sink), g_strconcat("Error opening file \"", "Error opening file %s: %s",
gst_filesink_getcurrentfilename(sink), "\": ", g_strerror(errno), NULL)); sink->filename, g_strerror(errno));
return FALSE; return FALSE;
} }
@ -257,15 +238,52 @@ gst_filesink_close_file (GstFileSink *sink)
if (fclose (sink->file) != 0) if (fclose (sink->file) != 0)
{ {
perror ("close"); gst_element_error (GST_ELEMENT (sink),
gst_element_error (GST_ELEMENT (sink), g_strconcat("Error closing file \"", "Error closing file %s: %s",
gst_filesink_getcurrentfilename(sink), "\": ", g_strerror(errno), NULL)); sink->filename, g_strerror(errno));
} }
else { else {
GST_FLAG_UNSET (sink, GST_FILESINK_OPEN); GST_FLAG_UNSET (sink, GST_FILESINK_OPEN);
} }
} }
static gboolean
gst_filesink_pad_query (GstPad *pad, GstQueryType type,
GstFormat *format, gint64 *value)
{
GstFileSink *sink = GST_FILESINK (GST_PAD_PARENT (pad));
switch (type) {
case GST_QUERY_TOTAL:
switch (*format) {
case GST_FORMAT_BYTES:
if (GST_FLAG_IS_SET (GST_ELEMENT(sink), GST_FILESINK_OPEN)) {
*value = sink->data_written; /* FIXME - doesn't the kernel provide
such a function? */
break;
}
default:
return FALSE;
}
break;
case GST_QUERY_POSITION:
switch (*format) {
case GST_FORMAT_BYTES:
if (GST_FLAG_IS_SET (GST_ELEMENT(sink), GST_FILESINK_OPEN)) {
*value = ftell (sink->file);
break;
}
default:
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
/* handle events (search) */ /* handle events (search) */
static gboolean static gboolean
gst_filesink_handle_event (GstPad *pad, GstEvent *event) gst_filesink_handle_event (GstPad *pad, GstEvent *event)
@ -275,31 +293,32 @@ gst_filesink_handle_event (GstPad *pad, GstEvent *event)
filesink = GST_FILESINK (gst_pad_get_parent (pad)); filesink = GST_FILESINK (gst_pad_get_parent (pad));
g_return_val_if_fail (GST_FLAG_IS_SET (filesink, GST_FILESINK_OPEN),
FALSE);
type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN; type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
switch (type) { switch (type) {
case GST_EVENT_SEEK: case GST_EVENT_SEEK:
/* we need to seek */ g_return_val_if_fail (GST_EVENT_SEEK_FORMAT (event) == GST_FORMAT_BYTES,
if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) FALSE);
if (fflush(filesink->file))
gst_element_error(GST_ELEMENT(filesink),
"Error flushing the buffer cache of file \'%s\' to disk: %s",
gst_filesink_getcurrentfilename(filesink), g_strerror(errno));
if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) { if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH)
g_warning("Any other then byte-offset seeking is not supported!\n"); if (fflush (filesink->file))
} gst_element_error (GST_ELEMENT (filesink),
"Error flushing file %s: %s",
filesink->filename, g_strerror(errno));
switch (GST_EVENT_SEEK_METHOD(event)) switch (GST_EVENT_SEEK_METHOD(event))
{ {
case GST_SEEK_METHOD_SET: case GST_SEEK_METHOD_SET:
fseek(filesink->file, GST_EVENT_SEEK_OFFSET(event), SEEK_SET); fseek (filesink->file, GST_EVENT_SEEK_OFFSET (event), SEEK_SET);
break; break;
case GST_SEEK_METHOD_CUR: case GST_SEEK_METHOD_CUR:
fseek(filesink->file, GST_EVENT_SEEK_OFFSET(event), SEEK_CUR); fseek (filesink->file, GST_EVENT_SEEK_OFFSET (event), SEEK_CUR);
break; break;
case GST_SEEK_METHOD_END: case GST_SEEK_METHOD_END:
fseek(filesink->file, GST_EVENT_SEEK_OFFSET(event), SEEK_END); fseek (filesink->file, GST_EVENT_SEEK_OFFSET (event), SEEK_END);
break; break;
default: default:
g_warning("unkown seek method!\n"); g_warning("unkown seek method!\n");
@ -311,26 +330,21 @@ gst_filesink_handle_event (GstPad *pad, GstEvent *event)
gint64 offset; gint64 offset;
if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &offset)) if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &offset))
fseek(filesink->file, offset, SEEK_SET); fseek (filesink->file, offset, SEEK_SET);
gst_event_unref (event); gst_event_unref (event);
break; break;
} }
case GST_EVENT_NEW_MEDIA: case GST_EVENT_FLUSH:
/* we need to open a new file! */ if (fflush (filesink->file)) {
gst_filesink_close_file(filesink); gst_element_error (GST_ELEMENT (filesink),
filesink->filenum++; "Error flushing file %s: %s",
if (!gst_filesink_open_file(filesink)) { filesink->filename, g_strerror(errno));
/* no more files, give EOS */
gst_element_set_eos(GST_ELEMENT(filesink));
return FALSE;
} }
break; break;
case GST_EVENT_FLUSH: case GST_EVENT_EOS:
if (fflush(filesink->file)) gst_filesink_close_file (filesink);
gst_element_error(GST_ELEMENT(filesink), gst_element_set_eos (GST_ELEMENT (filesink));
"Error flushing the buffer cache of file \'%s\' to disk: %s",
gst_filesink_getcurrentfilename(filesink), g_strerror(errno));
break; break;
default: default:
gst_pad_event_default (pad, event); gst_pad_event_default (pad, event);
@ -365,34 +379,23 @@ gst_filesink_chain (GstPad *pad, GstBuffer *buf)
return; return;
} }
if (filesink->maxfilesize > 0)
{
if ((filesink->data_written + GST_BUFFER_SIZE(buf))/(1024*1024) > filesink->maxfilesize)
{
if (GST_ELEMENT_IS_EVENT_AWARE(GST_ELEMENT(filesink)))
{
GstEvent *event;
event = gst_event_new(GST_EVENT_NEW_MEDIA);
gst_pad_send_event(pad, event);
}
}
}
if (GST_FLAG_IS_SET (filesink, GST_FILESINK_OPEN)) if (GST_FLAG_IS_SET (filesink, GST_FILESINK_OPEN))
{ {
bytes_written = fwrite (GST_BUFFER_DATA (buf), 1, GST_BUFFER_SIZE (buf), filesink->file); bytes_written = fwrite (GST_BUFFER_DATA (buf), 1,
GST_BUFFER_SIZE (buf), filesink->file);
if (bytes_written < GST_BUFFER_SIZE (buf)) if (bytes_written < GST_BUFFER_SIZE (buf))
{ {
printf ("filesink : Warning : %d bytes should be written, only %d bytes written\n", g_warning ("filesink: %d bytes should be written, only %d bytes written\n",
GST_BUFFER_SIZE (buf), bytes_written); GST_BUFFER_SIZE (buf), bytes_written);
} }
filesink->data_written += bytes_written;
} }
filesink->data_written += GST_BUFFER_SIZE(buf);
gst_buffer_unref (buf); gst_buffer_unref (buf);
g_signal_emit (G_OBJECT (filesink), gst_filesink_signals[SIGNAL_HANDOFF], 0, g_signal_emit (G_OBJECT (filesink),
filesink); gst_filesink_signals[SIGNAL_HANDOFF], 0,
filesink);
} }
static GstElementStateReturn static GstElementStateReturn
@ -400,14 +403,18 @@ gst_filesink_change_state (GstElement *element)
{ {
g_return_val_if_fail (GST_IS_FILESINK (element), GST_STATE_FAILURE); g_return_val_if_fail (GST_IS_FILESINK (element), GST_STATE_FAILURE);
if (GST_STATE_PENDING (element) == GST_STATE_NULL) { switch (GST_STATE_TRANSITION (element)) {
if (GST_FLAG_IS_SET (element, GST_FILESINK_OPEN)) case GST_STATE_PAUSED_TO_READY:
gst_filesink_close_file (GST_FILESINK (element)); if (GST_FLAG_IS_SET (element, GST_FILESINK_OPEN))
} else { gst_filesink_close_file (GST_FILESINK (element));
if (!GST_FLAG_IS_SET (element, GST_FILESINK_OPEN)) { break;
if (!gst_filesink_open_file (GST_FILESINK (element)))
return GST_STATE_FAILURE; case GST_STATE_READY_TO_PAUSED:
} if (!GST_FLAG_IS_SET (element, GST_FILESINK_OPEN)) {
if (!gst_filesink_open_file (GST_FILESINK (element)))
return GST_STATE_FAILURE;
}
break;
} }
if (GST_ELEMENT_CLASS (parent_class)->change_state) if (GST_ELEMENT_CLASS (parent_class)->change_state)
@ -415,4 +422,3 @@ gst_filesink_change_state (GstElement *element)
return GST_STATE_SUCCESS; return GST_STATE_SUCCESS;
} }

View file

@ -59,17 +59,14 @@ struct _GstFileSink {
gchar *filename; gchar *filename;
FILE *file; FILE *file;
gint filenum;
guint64 data_written; guint64 data_written;
gint maxfilesize;
}; };
struct _GstFileSinkClass { struct _GstFileSinkClass {
GstElementClass parent_class; GstElementClass parent_class;
/* signals */ /* signals */
void (*handoff) (GstElement *element,GstPad *pad); void (*handoff) (GstElement *element, GstPad *pad);
}; };
GType gst_filesink_get_type(void); GType gst_filesink_get_type(void);