2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
4 * 2006 Wim Taymans <wim@fluendo.com>
5 * 2006 David A. Schleef <ds@schleef.org>
6 * 2011 Collabora Ltd. <tim.muller@collabora.co.uk>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
26 * SECTION:element-multifilesink
27 * @see_also: #GstFileSrc
29 * Write incoming data to a series of sequentially-named files.
31 * The filename property should contain a string with a \%d placeholder that will
32 * be substituted with the index for each filename.
34 * If the #GstMultiFileSink:post-messages property is #TRUE, it sends an application
36 * <classname>"GstMultiFileSink"</classname> after writing each
39 * The message's structure contains these fields:
44 * <classname>"filename"</classname>:
45 * the filename where the buffer was written.
51 * <classname>"index"</classname>:
52 * the index of the buffer.
58 * <classname>"timestamp"</classname>:
59 * the timestamp of the buffer.
65 * <classname>"stream-time"</classname>:
66 * the stream time of the buffer.
72 * <classname>"running-time"</classname>:
73 * the running_time of the buffer.
79 * <classname>"duration"</classname>:
80 * the duration of the buffer.
86 * <classname>"offset"</classname>:
87 * the offset of the buffer that triggered the message.
93 * <classname>"offset-end"</classname>:
94 * the offset-end of the buffer that triggered the message.
100 * <title>Example launch line</title>
102 * gst-launch audiotestsrc ! multifilesink
103 * gst-launch videotestsrc ! multifilesink post-messages=true filename="frame%d"
107 * Last reviewed on 2009-09-11 (0.10.17)
113 #include <gst/base/gstbasetransform.h>
114 #include <gst/video/video.h>
115 #include <glib/gstdio.h>
116 #include "gstmultifilesink.h"
118 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
121 GST_STATIC_CAPS_ANY);
123 GST_DEBUG_CATEGORY_STATIC (gst_multi_file_sink_debug);
124 #define GST_CAT_DEFAULT gst_multi_file_sink_debug
126 #define DEFAULT_LOCATION "%05d"
127 #define DEFAULT_INDEX 0
128 #define DEFAULT_POST_MESSAGES FALSE
129 #define DEFAULT_NEXT_FILE GST_MULTI_FILE_SINK_NEXT_BUFFER
130 #define DEFAULT_MAX_FILES 0
131 #define DEFAULT_MAX_FILE_SIZE G_GUINT64_CONSTANT(2*1024*1024*1024)
145 static void gst_multi_file_sink_finalize (GObject * object);
147 static void gst_multi_file_sink_set_property (GObject * object, guint prop_id,
148 const GValue * value, GParamSpec * pspec);
149 static void gst_multi_file_sink_get_property (GObject * object, guint prop_id,
150 GValue * value, GParamSpec * pspec);
152 static gboolean gst_multi_file_sink_stop (GstBaseSink * sink);
153 static GstFlowReturn gst_multi_file_sink_render (GstBaseSink * sink,
155 static GstFlowReturn gst_multi_file_sink_render_list (GstBaseSink * sink,
156 GstBufferList * buffer_list);
157 static gboolean gst_multi_file_sink_set_caps (GstBaseSink * sink,
159 static gboolean gst_multi_file_sink_open_next_file (GstMultiFileSink *
161 static void gst_multi_file_sink_close_file (GstMultiFileSink * multifilesink,
163 static void gst_multi_file_sink_ensure_max_files (GstMultiFileSink *
165 static gboolean gst_multi_file_sink_event (GstBaseSink * sink,
168 #define GST_TYPE_MULTI_FILE_SINK_NEXT (gst_multi_file_sink_next_get_type ())
170 gst_multi_file_sink_next_get_type (void)
172 static GType multi_file_sync_next_type = 0;
173 static const GEnumValue next_types[] = {
174 {GST_MULTI_FILE_SINK_NEXT_BUFFER, "New file for each buffer", "buffer"},
175 {GST_MULTI_FILE_SINK_NEXT_DISCONT, "New file after each discontinuity",
177 {GST_MULTI_FILE_SINK_NEXT_KEY_FRAME, "New file at each key frame "
178 "(Useful for MPEG-TS segmenting)", "key-frame"},
179 {GST_MULTI_FILE_SINK_NEXT_KEY_UNIT_EVENT,
180 "New file after a force key unit event", "key-unit-event"},
181 {GST_MULTI_FILE_SINK_NEXT_MAX_SIZE, "New file when the configured maximum "
182 "file size would be exceeded with the next buffer or buffer list",
187 if (!multi_file_sync_next_type) {
188 multi_file_sync_next_type =
189 g_enum_register_static ("GstMultiFileSinkNext", next_types);
192 return multi_file_sync_next_type;
195 GST_BOILERPLATE (GstMultiFileSink, gst_multi_file_sink, GstBaseSink,
199 gst_multi_file_sink_base_init (gpointer g_class)
201 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
203 GST_DEBUG_CATEGORY_INIT (gst_multi_file_sink_debug, "multifilesink", 0,
204 "multifilesink element");
206 gst_element_class_add_static_pad_template (gstelement_class, &sinktemplate);
207 gst_element_class_set_details_simple (gstelement_class, "Multi-File Sink",
209 "Write buffers to a sequentially named set of files",
210 "David Schleef <ds@schleef.org>");
214 gst_multi_file_sink_class_init (GstMultiFileSinkClass * klass)
216 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
217 GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (klass);
219 gobject_class->set_property = gst_multi_file_sink_set_property;
220 gobject_class->get_property = gst_multi_file_sink_get_property;
222 g_object_class_install_property (gobject_class, PROP_LOCATION,
223 g_param_spec_string ("location", "File Location",
224 "Location of the file to write", NULL,
225 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
227 g_object_class_install_property (gobject_class, PROP_INDEX,
228 g_param_spec_int ("index", "Index",
229 "Index to use with location property to create file names. The "
230 "index is incremented by one for each buffer written.",
231 0, G_MAXINT, DEFAULT_INDEX,
232 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
234 * GstMultiFileSink:post-messages
236 * Post a message on the GstBus for each file.
240 g_object_class_install_property (gobject_class, PROP_POST_MESSAGES,
241 g_param_spec_boolean ("post-messages", "Post Messages",
242 "Post a message for each file with information of the buffer",
243 DEFAULT_POST_MESSAGES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
245 * GstMultiFileSink:next-file
247 * When to start a new file.
251 g_object_class_install_property (gobject_class, PROP_NEXT_FILE,
252 g_param_spec_enum ("next-file", "Next File",
253 "When to start a new file",
254 GST_TYPE_MULTI_FILE_SINK_NEXT, DEFAULT_NEXT_FILE,
255 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_STATIC_STRINGS));
259 * GstMultiFileSink:max-files
261 * Maximum number of files to keep on disk. Once the maximum is reached, old
262 * files start to be deleted to make room for new ones.
266 g_object_class_install_property (gobject_class, PROP_MAX_FILES,
267 g_param_spec_uint ("max-files", "Max files",
268 "Maximum number of files to keep on disk. Once the maximum is reached,"
269 "old files start to be deleted to make room for new ones.",
270 0, G_MAXUINT, DEFAULT_MAX_FILES,
271 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
274 * GstMultiFileSink:max-file-size
276 * Maximum file size before starting a new file in max-size mode.
280 g_object_class_install_property (gobject_class, PROP_MAX_FILE_SIZE,
281 g_param_spec_uint64 ("max-file-size", "Maximum File Size",
282 "Maximum file size before starting a new file in max-size mode",
283 0, G_MAXUINT64, DEFAULT_MAX_FILE_SIZE,
284 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
286 gobject_class->finalize = gst_multi_file_sink_finalize;
288 gstbasesink_class->get_times = NULL;
289 gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_multi_file_sink_stop);
290 gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_multi_file_sink_render);
291 gstbasesink_class->render_list =
292 GST_DEBUG_FUNCPTR (gst_multi_file_sink_render_list);
293 gstbasesink_class->set_caps =
294 GST_DEBUG_FUNCPTR (gst_multi_file_sink_set_caps);
295 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_multi_file_sink_event);
299 gst_multi_file_sink_init (GstMultiFileSink * multifilesink,
300 GstMultiFileSinkClass * g_class)
302 multifilesink->filename = g_strdup (DEFAULT_LOCATION);
303 multifilesink->index = DEFAULT_INDEX;
304 multifilesink->post_messages = DEFAULT_POST_MESSAGES;
305 multifilesink->max_files = DEFAULT_MAX_FILES;
306 multifilesink->max_file_size = DEFAULT_MAX_FILE_SIZE;
307 multifilesink->files = NULL;
308 multifilesink->n_files = 0;
310 gst_base_sink_set_sync (GST_BASE_SINK (multifilesink), FALSE);
312 multifilesink->next_segment = GST_CLOCK_TIME_NONE;
313 multifilesink->force_key_unit_count = -1;
317 gst_multi_file_sink_finalize (GObject * object)
319 GstMultiFileSink *sink = GST_MULTI_FILE_SINK (object);
321 g_free (sink->filename);
322 g_slist_foreach (sink->files, (GFunc) g_free, NULL);
323 g_slist_free (sink->files);
325 G_OBJECT_CLASS (parent_class)->finalize (object);
329 gst_multi_file_sink_set_location (GstMultiFileSink * sink,
330 const gchar * location)
332 g_free (sink->filename);
333 /* FIXME: validate location to have just one %d */
334 sink->filename = g_strdup (location);
340 gst_multi_file_sink_set_property (GObject * object, guint prop_id,
341 const GValue * value, GParamSpec * pspec)
343 GstMultiFileSink *sink = GST_MULTI_FILE_SINK (object);
347 gst_multi_file_sink_set_location (sink, g_value_get_string (value));
350 sink->index = g_value_get_int (value);
352 case PROP_POST_MESSAGES:
353 sink->post_messages = g_value_get_boolean (value);
356 sink->next_file = g_value_get_enum (value);
359 sink->max_files = g_value_get_uint (value);
361 case PROP_MAX_FILE_SIZE:
362 sink->max_file_size = g_value_get_uint64 (value);
365 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
371 gst_multi_file_sink_get_property (GObject * object, guint prop_id,
372 GValue * value, GParamSpec * pspec)
374 GstMultiFileSink *sink = GST_MULTI_FILE_SINK (object);
378 g_value_set_string (value, sink->filename);
381 g_value_set_int (value, sink->index);
383 case PROP_POST_MESSAGES:
384 g_value_set_boolean (value, sink->post_messages);
387 g_value_set_enum (value, sink->next_file);
390 g_value_set_uint (value, sink->max_files);
392 case PROP_MAX_FILE_SIZE:
393 g_value_set_uint64 (value, sink->max_file_size);
396 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
402 gst_multi_file_sink_stop (GstBaseSink * sink)
404 GstMultiFileSink *multifilesink;
407 multifilesink = GST_MULTI_FILE_SINK (sink);
409 if (multifilesink->file != NULL) {
410 fclose (multifilesink->file);
411 multifilesink->file = NULL;
414 if (multifilesink->streamheaders) {
415 for (i = 0; i < multifilesink->n_streamheaders; i++) {
416 gst_buffer_unref (multifilesink->streamheaders[i]);
418 g_free (multifilesink->streamheaders);
419 multifilesink->streamheaders = NULL;
422 multifilesink->force_key_unit_count = -1;
429 gst_multi_file_sink_post_message_full (GstMultiFileSink * multifilesink,
430 GstClockTime timestamp, GstClockTime duration, GstClockTime offset,
431 GstClockTime offset_end, GstClockTime running_time,
432 GstClockTime stream_time, const char *filename)
436 if (!multifilesink->post_messages)
439 s = gst_structure_new ("GstMultiFileSink",
440 "filename", G_TYPE_STRING, filename,
441 "index", G_TYPE_INT, multifilesink->index,
442 "timestamp", G_TYPE_UINT64, timestamp,
443 "stream-time", G_TYPE_UINT64, stream_time,
444 "running-time", G_TYPE_UINT64, running_time,
445 "duration", G_TYPE_UINT64, duration,
446 "offset", G_TYPE_UINT64, offset,
447 "offset-end", G_TYPE_UINT64, offset_end, NULL);
449 gst_element_post_message (GST_ELEMENT_CAST (multifilesink),
450 gst_message_new_element (GST_OBJECT_CAST (multifilesink), s));
455 gst_multi_file_sink_post_message (GstMultiFileSink * multifilesink,
456 GstBuffer * buffer, const char *filename)
458 GstClockTime duration, timestamp;
459 GstClockTime running_time, stream_time;
460 guint64 offset, offset_end;
464 if (!multifilesink->post_messages)
467 segment = &GST_BASE_SINK (multifilesink)->segment;
468 format = segment->format;
470 timestamp = GST_BUFFER_TIMESTAMP (buffer);
471 duration = GST_BUFFER_DURATION (buffer);
472 offset = GST_BUFFER_OFFSET (buffer);
473 offset_end = GST_BUFFER_OFFSET_END (buffer);
475 running_time = gst_segment_to_running_time (segment, format, timestamp);
476 stream_time = gst_segment_to_stream_time (segment, format, timestamp);
478 gst_multi_file_sink_post_message_full (multifilesink, timestamp, duration,
479 offset, offset_end, running_time, stream_time, filename);
483 gst_multi_file_sink_write_stream_headers (GstMultiFileSink * sink)
487 if (sink->streamheaders == NULL)
490 /* we want to write these at the beginning */
491 g_assert (sink->cur_file_size == 0);
493 for (i = 0; i < sink->n_streamheaders; i++) {
497 hdr = sink->streamheaders[i];
499 ret = fwrite (GST_BUFFER_DATA (hdr), GST_BUFFER_SIZE (hdr), 1, sink->file);
504 sink->cur_file_size += GST_BUFFER_SIZE (hdr);
511 gst_multi_file_sink_render (GstBaseSink * sink, GstBuffer * buffer)
513 GstMultiFileSink *multifilesink;
518 GError *error = NULL;
520 size = GST_BUFFER_SIZE (buffer);
521 data = GST_BUFFER_DATA (buffer);
523 multifilesink = GST_MULTI_FILE_SINK (sink);
525 switch (multifilesink->next_file) {
526 case GST_MULTI_FILE_SINK_NEXT_BUFFER:
527 gst_multi_file_sink_ensure_max_files (multifilesink);
529 filename = g_strdup_printf (multifilesink->filename,
530 multifilesink->index);
531 ret = g_file_set_contents (filename, (char *) data, size, &error);
535 multifilesink->files = g_slist_append (multifilesink->files, filename);
536 multifilesink->n_files += 1;
538 gst_multi_file_sink_post_message (multifilesink, buffer, filename);
539 multifilesink->index++;
542 case GST_MULTI_FILE_SINK_NEXT_DISCONT:
543 if (GST_BUFFER_IS_DISCONT (buffer)) {
544 if (multifilesink->file)
545 gst_multi_file_sink_close_file (multifilesink, buffer);
548 if (multifilesink->file == NULL) {
549 if (!gst_multi_file_sink_open_next_file (multifilesink))
550 goto stdio_write_error;
553 ret = fwrite (GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), 1,
554 multifilesink->file);
556 goto stdio_write_error;
559 case GST_MULTI_FILE_SINK_NEXT_KEY_FRAME:
560 if (multifilesink->next_segment == GST_CLOCK_TIME_NONE) {
561 if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
562 multifilesink->next_segment = GST_BUFFER_TIMESTAMP (buffer) +
567 if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
568 GST_BUFFER_TIMESTAMP (buffer) >= multifilesink->next_segment &&
569 !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
570 if (multifilesink->file)
571 gst_multi_file_sink_close_file (multifilesink, buffer);
573 multifilesink->next_segment += 10 * GST_SECOND;
576 if (multifilesink->file == NULL) {
577 if (!gst_multi_file_sink_open_next_file (multifilesink))
578 goto stdio_write_error;
580 gst_multi_file_sink_write_stream_headers (multifilesink);
583 ret = fwrite (GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), 1,
584 multifilesink->file);
586 goto stdio_write_error;
589 case GST_MULTI_FILE_SINK_NEXT_KEY_UNIT_EVENT:
590 if (multifilesink->file == NULL) {
591 if (!gst_multi_file_sink_open_next_file (multifilesink))
592 goto stdio_write_error;
595 ret = fwrite (GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), 1,
596 multifilesink->file);
598 goto stdio_write_error;
601 case GST_MULTI_FILE_SINK_NEXT_MAX_SIZE:{
604 new_size = multifilesink->cur_file_size + GST_BUFFER_SIZE (buffer);
605 if (new_size > multifilesink->max_file_size) {
607 GST_INFO_OBJECT (multifilesink, "current size: %" G_GUINT64_FORMAT
608 ", new_size: %" G_GUINT64_FORMAT ", max. size %" G_GUINT64_FORMAT,
609 multifilesink->cur_file_size, new_size,
610 multifilesink->max_file_size);
612 if (multifilesink->file != NULL)
613 gst_multi_file_sink_close_file (multifilesink, NULL);
616 if (multifilesink->file == NULL) {
617 if (!gst_multi_file_sink_open_next_file (multifilesink))
618 goto stdio_write_error;
620 gst_multi_file_sink_write_stream_headers (multifilesink);
623 ret = fwrite (GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), 1,
624 multifilesink->file);
627 goto stdio_write_error;
629 multifilesink->cur_file_size += GST_BUFFER_SIZE (buffer);
633 g_assert_not_reached ();
641 switch (error->code) {
642 case G_FILE_ERROR_NOSPC:{
643 GST_ELEMENT_ERROR (multifilesink, RESOURCE, NO_SPACE_LEFT, (NULL),
648 GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE,
649 ("Error while writing to file \"%s\".", filename),
650 ("%s", g_strerror (errno)));
653 g_error_free (error);
656 return GST_FLOW_ERROR;
661 GST_ELEMENT_ERROR (multifilesink, RESOURCE, NO_SPACE_LEFT,
662 ("Error while writing to file."), ("%s", g_strerror (errno)));
665 GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE,
666 ("Error while writing to file."), ("%s", g_strerror (errno)));
668 return GST_FLOW_ERROR;
671 static GstBufferListItem
672 buffer_list_calc_size (GstBuffer ** buf, guint group, guint idx, gpointer data)
674 guint *p_size = data;
677 buf_size = GST_BUFFER_SIZE (*buf);
678 GST_TRACE ("buffer %u in group %u has size %u", idx, group, buf_size);
681 return GST_BUFFER_LIST_CONTINUE;
684 static GstBufferListItem
685 buffer_list_copy_data (GstBuffer ** buf, guint group, guint idx, gpointer data)
687 GstBuffer *dest = data;
689 if (group == 0 && idx == 0)
690 gst_buffer_copy_metadata (dest, *buf, GST_BUFFER_COPY_ALL);
692 memcpy (GST_BUFFER_DATA (dest) + GST_BUFFER_SIZE (dest),
693 GST_BUFFER_DATA (*buf), GST_BUFFER_SIZE (*buf));
694 GST_BUFFER_SIZE (dest) += GST_BUFFER_SIZE (*buf);
696 return GST_BUFFER_LIST_CONTINUE;
699 /* Our assumption for now is that the buffers in a buffer list should always
700 * end up in the same file. If someone wants different behaviour, they'll just
701 * have to add a property for that. */
703 gst_multi_file_sink_render_list (GstBaseSink * sink, GstBufferList * list)
708 gst_buffer_list_foreach (list, buffer_list_calc_size, &size);
709 GST_LOG_OBJECT (sink, "total size of buffer list %p: %u", list, size);
711 /* copy all buffers in the list into one single buffer, so we can use
712 * the normal render function (FIXME: optimise to avoid the memcpy) */
713 buf = gst_buffer_new_and_alloc (size);
714 GST_BUFFER_SIZE (buf) = 0;
715 gst_buffer_list_foreach (list, buffer_list_copy_data, buf);
716 g_assert (GST_BUFFER_SIZE (buf) == size);
718 gst_multi_file_sink_render (sink, buf);
719 gst_buffer_unref (buf);
725 gst_multi_file_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
727 GstMultiFileSink *multifilesink;
728 GstStructure *structure;
730 multifilesink = GST_MULTI_FILE_SINK (sink);
732 structure = gst_caps_get_structure (caps, 0);
736 value = gst_structure_get_value (structure, "streamheader");
738 if (GST_VALUE_HOLDS_ARRAY (value)) {
741 if (multifilesink->streamheaders) {
742 for (i = 0; i < multifilesink->n_streamheaders; i++) {
743 gst_buffer_unref (multifilesink->streamheaders[i]);
745 g_free (multifilesink->streamheaders);
748 multifilesink->n_streamheaders = gst_value_array_get_size (value);
749 multifilesink->streamheaders =
750 g_malloc (sizeof (GstBuffer *) * multifilesink->n_streamheaders);
752 for (i = 0; i < multifilesink->n_streamheaders; i++) {
753 multifilesink->streamheaders[i] =
754 gst_buffer_ref (gst_value_get_buffer (gst_value_array_get_value
764 gst_multi_file_sink_ensure_max_files (GstMultiFileSink * multifilesink)
768 while (multifilesink->max_files &&
769 multifilesink->n_files >= multifilesink->max_files) {
770 filename = multifilesink->files->data;
773 multifilesink->files = g_slist_delete_link (multifilesink->files,
774 multifilesink->files);
775 multifilesink->n_files -= 1;
780 gst_multi_file_sink_event (GstBaseSink * sink, GstEvent * event)
782 GstMultiFileSink *multifilesink;
786 multifilesink = GST_MULTI_FILE_SINK (sink);
788 switch (GST_EVENT_TYPE (event)) {
789 case GST_EVENT_CUSTOM_DOWNSTREAM:
791 GstClockTime timestamp, duration;
792 GstClockTime running_time, stream_time;
793 guint64 offset, offset_end;
794 gboolean all_headers;
797 if (multifilesink->next_file != GST_MULTI_FILE_SINK_NEXT_KEY_UNIT_EVENT ||
798 !gst_video_event_is_force_key_unit (event))
801 gst_video_event_parse_downstream_force_key_unit (event, ×tamp,
802 &stream_time, &running_time, &all_headers, &count);
804 if (multifilesink->force_key_unit_count != -1 &&
805 multifilesink->force_key_unit_count == count)
808 multifilesink->force_key_unit_count = count;
810 if (multifilesink->file) {
811 duration = GST_CLOCK_TIME_NONE;
812 offset = offset_end = -1;
813 filename = g_strdup_printf (multifilesink->filename,
814 multifilesink->index);
815 gst_multi_file_sink_post_message_full (multifilesink, timestamp,
816 duration, offset, offset_end, running_time, stream_time, filename);
820 gst_multi_file_sink_close_file (multifilesink, NULL);
824 if (multifilesink->file == NULL) {
825 if (!gst_multi_file_sink_open_next_file (multifilesink))
826 goto stdio_write_error;
839 GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE,
840 ("Error while writing to file."), (NULL));
845 gst_multi_file_sink_open_next_file (GstMultiFileSink * multifilesink)
849 g_return_val_if_fail (multifilesink->file == NULL, FALSE);
851 gst_multi_file_sink_ensure_max_files (multifilesink);
852 filename = g_strdup_printf (multifilesink->filename, multifilesink->index);
853 multifilesink->file = g_fopen (filename, "wb");
854 if (multifilesink->file == NULL) {
859 GST_INFO_OBJECT (multifilesink, "opening file %s", filename);
860 multifilesink->files = g_slist_append (multifilesink->files, filename);
861 multifilesink->n_files += 1;
863 multifilesink->cur_file_size = 0;
868 gst_multi_file_sink_close_file (GstMultiFileSink * multifilesink,
873 fclose (multifilesink->file);
874 multifilesink->file = NULL;
877 filename = g_strdup_printf (multifilesink->filename, multifilesink->index);
878 gst_multi_file_sink_post_message (multifilesink, buffer, filename);
882 multifilesink->index++;