multifile: port to 0.10
[platform/upstream/gstreamer.git] / gst / multifile / gstmultifilesrc.c
1 /* GStreamer
2  * Copyright (C) 2006 David A. Schleef <ds@schleef.org>
3  *
4  * gstmultifilesrc.c:
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 /**
22  * SECTION:element-multifilesrc
23  * @see_also: #GstFileSrc
24  *
25  * Reads buffers from sequentially named files. If used together with an image
26  * decoder, one needs to use the #GstMultiFileSrc:caps property or a capsfilter
27  * to force to caps containing a framerate. Otherwise image decoders send EOS
28  * after the first picture.
29  *
30  * File names are created by replacing "\%d" with the index using printf().
31  *
32  * <refsect2>
33  * <title>Example launch line</title>
34  * |[
35  * gst-launch multifilesrc location="img.%04d.png" index=0 caps="image/png,framerate=\(fraction\)12/1" ! \
36  *     pngdec ! ffmpegcolorspace ! theoraenc ! oggmux ! \
37  *     filesink location="images.ogg"
38  * ]| This pipeline creates a video file "images.ogg" by joining multiple PNG
39  * files named img.0000.png, img.0001.png, etc.
40  * </refsect2>
41 */
42
43 #ifdef HAVE_CONFIG_H
44 #  include "config.h"
45 #endif
46
47 #include "gstmultifilesrc.h"
48
49
50 static GstFlowReturn gst_multi_file_src_create (GstPushSrc * src,
51     GstBuffer ** buffer);
52
53 static void gst_multi_file_src_dispose (GObject * object);
54
55 static void gst_multi_file_src_set_property (GObject * object, guint prop_id,
56     const GValue * value, GParamSpec * pspec);
57 static void gst_multi_file_src_get_property (GObject * object, guint prop_id,
58     GValue * value, GParamSpec * pspec);
59 static GstCaps *gst_multi_file_src_getcaps (GstBaseSrc * src, GstCaps * filter);
60 static gboolean gst_multi_file_src_query (GstBaseSrc * src, GstQuery * query);
61
62
63 static GstStaticPadTemplate gst_multi_file_src_pad_template =
64 GST_STATIC_PAD_TEMPLATE ("src",
65     GST_PAD_SRC,
66     GST_PAD_ALWAYS,
67     GST_STATIC_CAPS_ANY);
68
69 GST_DEBUG_CATEGORY_STATIC (gst_multi_file_src_debug);
70 #define GST_CAT_DEFAULT gst_multi_file_src_debug
71
72 enum
73 {
74   ARG_0,
75   ARG_LOCATION,
76   ARG_INDEX,
77   ARG_CAPS
78 };
79
80 #define DEFAULT_LOCATION "%05d"
81 #define DEFAULT_INDEX 0
82
83 #define gst_multi_file_src_parent_class parent_class
84 G_DEFINE_TYPE (GstMultiFileSrc, gst_multi_file_src, GST_TYPE_PUSH_SRC);
85
86
87 static void
88 gst_multi_file_src_class_init (GstMultiFileSrcClass * klass)
89 {
90   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
91   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
92   GstPushSrcClass *gstpushsrc_class = GST_PUSH_SRC_CLASS (klass);
93   GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
94
95   gobject_class->set_property = gst_multi_file_src_set_property;
96   gobject_class->get_property = gst_multi_file_src_get_property;
97
98   g_object_class_install_property (gobject_class, ARG_LOCATION,
99       g_param_spec_string ("location", "File Location",
100           "Pattern to create file names of input files.  File names are "
101           "created by calling sprintf() with the pattern and the current "
102           "index.", DEFAULT_LOCATION,
103           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
104   g_object_class_install_property (gobject_class, ARG_INDEX,
105       g_param_spec_int ("index", "File Index",
106           "Index to use with location property to create file names.  The "
107           "index is incremented by one for each buffer read.",
108           0, INT_MAX, DEFAULT_INDEX,
109           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
110   g_object_class_install_property (gobject_class, ARG_CAPS,
111       g_param_spec_boxed ("caps", "Caps",
112           "Caps describing the format of the data.",
113           GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
114
115   gobject_class->dispose = gst_multi_file_src_dispose;
116
117   gstbasesrc_class->get_caps = gst_multi_file_src_getcaps;
118   gstbasesrc_class->query = gst_multi_file_src_query;
119
120   gstpushsrc_class->create = gst_multi_file_src_create;
121
122   if (sizeof (off_t) < 8) {
123     GST_LOG ("No large file support, sizeof (off_t) = %" G_GSIZE_FORMAT,
124         sizeof (off_t));
125   }
126
127   GST_DEBUG_CATEGORY_INIT (gst_multi_file_src_debug, "multifilesrc", 0,
128       "multifilesrc element");
129
130   gst_element_class_add_pad_template (gstelement_class,
131       gst_static_pad_template_get (&gst_multi_file_src_pad_template));
132   gst_element_class_set_details_simple (gstelement_class, "Multi-File Source",
133       "Source/File",
134       "Read a sequentially named set of files into buffers",
135       "David Schleef <ds@schleef.org>");
136 }
137
138 static void
139 gst_multi_file_src_init (GstMultiFileSrc * multifilesrc)
140 {
141   multifilesrc->index = DEFAULT_INDEX;
142   multifilesrc->filename = g_strdup (DEFAULT_LOCATION);
143   multifilesrc->successful_read = FALSE;
144 }
145
146 static void
147 gst_multi_file_src_dispose (GObject * object)
148 {
149   GstMultiFileSrc *src = GST_MULTI_FILE_SRC (object);
150
151   g_free (src->filename);
152   src->filename = NULL;
153   if (src->caps)
154     gst_caps_unref (src->caps);
155
156   G_OBJECT_CLASS (parent_class)->dispose (object);
157 }
158
159 static GstCaps *
160 gst_multi_file_src_getcaps (GstBaseSrc * src, GstCaps * filter)
161 {
162   GstMultiFileSrc *multi_file_src = GST_MULTI_FILE_SRC (src);
163
164   GST_DEBUG_OBJECT (src, "returning %" GST_PTR_FORMAT, multi_file_src->caps);
165
166   if (multi_file_src->caps) {
167     if (filter)
168       return gst_caps_intersect_full (filter, multi_file_src->caps,
169           GST_CAPS_INTERSECT_FIRST);
170     else
171       return gst_caps_ref (multi_file_src->caps);
172   } else {
173     if (filter)
174       return gst_caps_ref (filter);
175     else
176       return gst_caps_new_any ();
177   }
178 }
179
180 static gboolean
181 gst_multi_file_src_query (GstBaseSrc * src, GstQuery * query)
182 {
183   gboolean res;
184   GstMultiFileSrc *mfsrc;
185
186   mfsrc = GST_MULTI_FILE_SRC (src);
187
188   switch (GST_QUERY_TYPE (query)) {
189     case GST_QUERY_POSITION:
190     {
191       GstFormat format;
192
193       gst_query_parse_position (query, &format, NULL);
194       switch (format) {
195         case GST_FORMAT_BUFFERS:
196         case GST_FORMAT_DEFAULT:
197           gst_query_set_position (query, GST_FORMAT_BUFFERS, mfsrc->index);
198           res = TRUE;
199           break;
200         default:
201           res = GST_BASE_SRC_CLASS (parent_class)->query (src, query);
202           break;
203       }
204       break;
205     }
206     default:
207       res = GST_BASE_SRC_CLASS (parent_class)->query (src, query);
208       break;
209   }
210   return res;
211 }
212
213 static gboolean
214 gst_multi_file_src_set_location (GstMultiFileSrc * src, const gchar * location)
215 {
216   g_free (src->filename);
217   if (location != NULL) {
218     src->filename = g_strdup (location);
219   } else {
220     src->filename = NULL;
221   }
222
223   return TRUE;
224 }
225
226 static void
227 gst_multi_file_src_set_property (GObject * object, guint prop_id,
228     const GValue * value, GParamSpec * pspec)
229 {
230   GstMultiFileSrc *src = GST_MULTI_FILE_SRC (object);
231
232   switch (prop_id) {
233     case ARG_LOCATION:
234       gst_multi_file_src_set_location (src, g_value_get_string (value));
235       break;
236     case ARG_INDEX:
237       src->index = g_value_get_int (value);
238       break;
239     case ARG_CAPS:
240     {
241       const GstCaps *caps = gst_value_get_caps (value);
242       GstCaps *new_caps;
243
244       if (caps == NULL) {
245         new_caps = gst_caps_new_any ();
246       } else {
247         new_caps = gst_caps_copy (caps);
248       }
249       gst_caps_replace (&src->caps, new_caps);
250       gst_pad_set_caps (GST_BASE_SRC_PAD (src), new_caps);
251     }
252       break;
253     default:
254       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
255       break;
256   }
257 }
258
259 static void
260 gst_multi_file_src_get_property (GObject * object, guint prop_id,
261     GValue * value, GParamSpec * pspec)
262 {
263   GstMultiFileSrc *src = GST_MULTI_FILE_SRC (object);
264
265   switch (prop_id) {
266     case ARG_LOCATION:
267       g_value_set_string (value, src->filename);
268       break;
269     case ARG_INDEX:
270       g_value_set_int (value, src->index);
271       break;
272     case ARG_CAPS:
273       gst_value_set_caps (value, src->caps);
274       break;
275     default:
276       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
277       break;
278   }
279 }
280
281 static gchar *
282 gst_multi_file_src_get_filename (GstMultiFileSrc * multifilesrc)
283 {
284   gchar *filename;
285
286   filename = g_strdup_printf (multifilesrc->filename, multifilesrc->index);
287
288   return filename;
289 }
290
291 static GstFlowReturn
292 gst_multi_file_src_create (GstPushSrc * src, GstBuffer ** buffer)
293 {
294   GstMultiFileSrc *multifilesrc;
295   gsize size;
296   gchar *data;
297   gchar *filename;
298   GstBuffer *buf;
299   gboolean ret;
300   GError *error = NULL;
301
302   multifilesrc = GST_MULTI_FILE_SRC (src);
303
304   filename = gst_multi_file_src_get_filename (multifilesrc);
305
306   GST_DEBUG_OBJECT (multifilesrc, "reading from file \"%s\".", filename);
307
308   ret = g_file_get_contents (filename, &data, &size, &error);
309   if (!ret) {
310     if (multifilesrc->successful_read) {
311       /* If we've read at least one buffer successfully, not finding the
312        * next file is EOS. */
313       g_free (filename);
314       if (error != NULL)
315         g_error_free (error);
316       return GST_FLOW_UNEXPECTED;
317     } else {
318       goto handle_error;
319     }
320   }
321
322   multifilesrc->successful_read = TRUE;
323   multifilesrc->index++;
324
325   buf = gst_buffer_new ();
326   gst_buffer_take_memory (buf, -1,
327       gst_memory_new_wrapped (0, data, g_free, size, 0, size));
328   GST_BUFFER_OFFSET (buf) = multifilesrc->offset;
329   GST_BUFFER_OFFSET_END (buf) = multifilesrc->offset + size;
330   multifilesrc->offset += size;
331
332   GST_DEBUG_OBJECT (multifilesrc, "read file \"%s\".", filename);
333
334   g_free (filename);
335   *buffer = buf;
336   return GST_FLOW_OK;
337
338 handle_error:
339   {
340     if (error != NULL) {
341       GST_ELEMENT_ERROR (multifilesrc, RESOURCE, READ,
342           ("Error while reading from file \"%s\".", filename),
343           ("%s", error->message));
344       g_error_free (error);
345     } else {
346       GST_ELEMENT_ERROR (multifilesrc, RESOURCE, READ,
347           ("Error while reading from file \"%s\".", filename),
348           ("%s", g_strerror (errno)));
349     }
350     g_free (filename);
351     return GST_FLOW_ERROR;
352   }
353 }