gstmultifilesink.c 6.97 KB
Newer Older
David Schleef's avatar
David Schleef committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* GStreamer
 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
 *                    2000 Wim Taymans <wtay@chello.be>
 *                    2006 Wim Taymans <wim@fluendo.com>
 *                    2006 David A. Schleef <ds@schleef.org>
 *
 * gstmultifilesink.c:
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
/**
 * SECTION:element-multifilesink
26
 * @short_description: Writes buffers to sequentially-named files
David Schleef's avatar
David Schleef committed
27
28
 * @see_also: #GstFileSrc
 *
29
30
31
32
 * <para>
 * Write incoming data to a series of sequentially-named files.
 * </para>
 *
David Schleef's avatar
David Schleef committed
33
34
35
36
37
38
 */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

39
#include "gstmultifilesink.h"
David Schleef's avatar
David Schleef committed
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS_ANY);

GST_DEBUG_CATEGORY_STATIC (gst_multi_file_sink_debug);
#define GST_CAT_DEFAULT gst_multi_file_sink_debug

static const GstElementDetails gst_multi_file_sink_details =
GST_ELEMENT_DETAILS ("Multi-File Sink",
    "Sink/File",
    "Write stream to a file",
    "David Schleef <ds@schleef.org>");

enum
{
  ARG_0,
58
59
  ARG_LOCATION,
  ARG_INDEX
David Schleef's avatar
David Schleef committed
60
61
};

62
63
64
#define DEFAULT_LOCATION "%05d"
#define DEFAULT_INDEX 0

David Schleef's avatar
David Schleef committed
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
static void gst_multi_file_sink_dispose (GObject * object);

static void gst_multi_file_sink_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec);
static void gst_multi_file_sink_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec);

static GstFlowReturn gst_multi_file_sink_render (GstBaseSink * sink,
    GstBuffer * buffer);



GST_BOILERPLATE (GstMultiFileSink, gst_multi_file_sink, GstBaseSink,
    GST_TYPE_BASE_SINK);

static void
gst_multi_file_sink_base_init (gpointer g_class)
{
  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);

  GST_DEBUG_CATEGORY_INIT (gst_multi_file_sink_debug, "multifilesink", 0,
      "multifilesink element");

  gst_element_class_add_pad_template (gstelement_class,
      gst_static_pad_template_get (&sinktemplate));
  gst_element_class_set_details (gstelement_class,
      &gst_multi_file_sink_details);
}

static void
gst_multi_file_sink_class_init (GstMultiFileSinkClass * klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (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_param_spec_string ("location", "File Location",
          "Location of the file to write", NULL, G_PARAM_READWRITE));
106
107
108
109
110
  g_object_class_install_property (gobject_class, ARG_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));
David Schleef's avatar
David Schleef committed
111
112
113
114
115
116
117

  gobject_class->dispose = gst_multi_file_sink_dispose;

  gstbasesink_class->get_times = NULL;
  gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_multi_file_sink_render);

  if (sizeof (off_t) < 8) {
118
119
    GST_LOG ("No large file support, sizeof (off_t) = %" G_GSIZE_FORMAT,
        sizeof (off_t));
David Schleef's avatar
David Schleef committed
120
121
122
123
  }
}

static void
124
gst_multi_file_sink_init (GstMultiFileSink * multifilesink,
David Schleef's avatar
David Schleef committed
125
126
127
128
    GstMultiFileSinkClass * g_class)
{
  GstPad *pad;

129
  pad = GST_BASE_SINK_PAD (multifilesink);
David Schleef's avatar
David Schleef committed
130

131
132
  multifilesink->filename = g_strdup (DEFAULT_LOCATION);
  multifilesink->index = DEFAULT_INDEX;
David Schleef's avatar
David Schleef committed
133

134
  GST_BASE_SINK (multifilesink)->sync = FALSE;
David Schleef's avatar
David Schleef committed
135
136
137
138
139
140
141
142
143
}

static void
gst_multi_file_sink_dispose (GObject * object)
{
  GstMultiFileSink *sink = GST_MULTI_FILE_SINK (object);

  g_free (sink->filename);
  sink->filename = NULL;
144
145

  G_OBJECT_CLASS (parent_class)->dispose (object);
David Schleef's avatar
David Schleef committed
146
147
148
149
150
151
152
153
}

static gboolean
gst_multi_file_sink_set_location (GstMultiFileSink * sink,
    const gchar * location)
{
  g_free (sink->filename);
  if (location != NULL) {
154
    /* FIXME: validate location to have just one %d */
David Schleef's avatar
David Schleef committed
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
    sink->filename = g_strdup (location);
  } else {
    sink->filename = NULL;
  }

  return TRUE;
}
static void
gst_multi_file_sink_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstMultiFileSink *sink = GST_MULTI_FILE_SINK (object);

  switch (prop_id) {
    case ARG_LOCATION:
      gst_multi_file_sink_set_location (sink, g_value_get_string (value));
      break;
172
173
174
    case ARG_INDEX:
      sink->index = g_value_get_int (value);
      break;
David Schleef's avatar
David Schleef committed
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
gst_multi_file_sink_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
{
  GstMultiFileSink *sink = GST_MULTI_FILE_SINK (object);

  switch (prop_id) {
    case ARG_LOCATION:
      g_value_set_string (value, sink->filename);
      break;
191
192
193
    case ARG_INDEX:
      g_value_set_int (value, sink->index);
      break;
David Schleef's avatar
David Schleef committed
194
195
196
197
198
199
200
201
202
203
204
205
206
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

#ifdef G_OS_UNIX
# define __GST_STDIO_SEEK_FUNCTION "lseek"
#else
# define __GST_STDIO_SEEK_FUNCTION "fseek"
#endif

static gchar *
207
gst_multi_file_sink_get_filename (GstMultiFileSink * multifilesink)
David Schleef's avatar
David Schleef committed
208
209
210
{
  gchar *filename;

211
  filename = g_strdup_printf (multifilesink->filename, multifilesink->index);
David Schleef's avatar
David Schleef committed
212
213
214
215
216
217
218

  return filename;
}

static GstFlowReturn
gst_multi_file_sink_render (GstBaseSink * sink, GstBuffer * buffer)
{
219
  GstMultiFileSink *multifilesink;
David Schleef's avatar
David Schleef committed
220
221
222
223
224
225
  guint size;
  gchar *filename;
  FILE *file;

  size = GST_BUFFER_SIZE (buffer);

226
  multifilesink = GST_MULTI_FILE_SINK (sink);
David Schleef's avatar
David Schleef committed
227

228
  filename = gst_multi_file_sink_get_filename (multifilesink);
David Schleef's avatar
David Schleef committed
229
230
231
232
233
234
235
236
237
238
239
240
241

  file = fopen (filename, "wb");
  if (!file) {
    goto handle_error;
  }

  g_free (filename);

  if (size > 0 && GST_BUFFER_DATA (buffer) != NULL) {
    if (fwrite (GST_BUFFER_DATA (buffer), size, 1, file) != 1)
      goto handle_error;
  }

242
  multifilesink->index++;
David Schleef's avatar
David Schleef committed
243
244
245
246
247
248
249
250
251

  fclose (file);

  return GST_FLOW_OK;

handle_error:
  {
    switch (errno) {
      case ENOSPC:{
252
253
        GST_ELEMENT_ERROR (multifilesink, RESOURCE, NO_SPACE_LEFT, (NULL),
            (NULL));
David Schleef's avatar
David Schleef committed
254
255
256
        break;
      }
      default:{
257
258
        GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE,
            ("Error while writing to file \"%s\".", multifilesink->filename),
David Schleef's avatar
David Schleef committed
259
260
261
262
263
264
            ("%s", g_strerror (errno)));
      }
    }
    return GST_FLOW_ERROR;
  }
}