gst/gstelement.h (GstState): Renamed from GstElementState, changed to be a normal...
[platform/upstream/gstreamer.git] / plugins / elements / gstfdsrc.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *                    2005 Philippe Khalaf <burger@speedy.org>
5  *
6  * gstfdsrc.c: 
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27 #include "gst/gst_private.h"
28
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <stdio.h>
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 #include <stdlib.h>
37 #include <errno.h>
38
39 #include "gstfdsrc.h"
40
41 #define DEFAULT_BLOCKSIZE       4096
42
43 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
44     GST_PAD_SRC,
45     GST_PAD_ALWAYS,
46     GST_STATIC_CAPS_ANY);
47
48 GST_DEBUG_CATEGORY_STATIC (gst_fdsrc_debug);
49 #define GST_CAT_DEFAULT gst_fdsrc_debug
50
51 GstElementDetails gst_fdsrc_details = GST_ELEMENT_DETAILS ("Disk Source",
52     "Source/File",
53     "Synchronous read from a file",
54     "Erik Walthinsen <omega@cse.ogi.edu>");
55
56
57 /* FdSrc signals and args */
58 enum
59 {
60   SIGNAL_TIMEOUT,
61   LAST_SIGNAL
62 };
63
64 enum
65 {
66   ARG_0,
67   ARG_FD,
68   ARG_BLOCKSIZE,
69   ARG_TIMEOUT
70 };
71
72 static guint gst_fdsrc_signals[LAST_SIGNAL] = { 0 };
73
74 #define _do_init(bla) \
75     GST_DEBUG_CATEGORY_INIT (gst_fdsrc_debug, "fdsrc", 0, "fdsrc element");
76
77 GST_BOILERPLATE_FULL (GstFdSrc, gst_fdsrc, GstElement, GST_TYPE_PUSH_SRC,
78     _do_init);
79
80 static void gst_fdsrc_set_property (GObject * object, guint prop_id,
81     const GValue * value, GParamSpec * pspec);
82 static void gst_fdsrc_get_property (GObject * object, guint prop_id,
83     GValue * value, GParamSpec * pspec);
84
85 static GstStateChangeReturn gst_fdsrc_change_state (GstElement * element,
86     GstStateChange transition);
87
88 static GstFlowReturn gst_fdsrc_create (GstPushSrc * psrc, GstBuffer ** outbuf);
89
90 static void
91 gst_fdsrc_base_init (gpointer g_class)
92 {
93   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
94
95   gst_element_class_add_pad_template (gstelement_class,
96       gst_static_pad_template_get (&srctemplate));
97   gst_element_class_set_details (gstelement_class, &gst_fdsrc_details);
98 }
99 static void
100 gst_fdsrc_class_init (GstFdSrcClass * klass)
101 {
102   GObjectClass *gobject_class;
103   GstBaseSrcClass *gstbasesrc_class;
104   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
105   GstPushSrcClass *gstpush_src_class;
106
107   gobject_class = G_OBJECT_CLASS (klass);
108   gstbasesrc_class = (GstBaseSrcClass *) klass;
109   gstpush_src_class = (GstPushSrcClass *) klass;
110
111   parent_class = g_type_class_ref (GST_TYPE_PUSH_SRC);
112
113   gobject_class->set_property = gst_fdsrc_set_property;
114   gobject_class->get_property = gst_fdsrc_get_property;
115
116   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FD,
117       g_param_spec_int ("fd", "fd", "An open file descriptor to read from",
118           0, G_MAXINT, 0, G_PARAM_READWRITE));
119   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BLOCKSIZE,
120       g_param_spec_ulong ("blocksize", "Block size",
121           "Size in bytes to read per buffer", 1, G_MAXULONG, DEFAULT_BLOCKSIZE,
122           G_PARAM_READWRITE));
123   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TIMEOUT,
124       g_param_spec_uint64 ("timeout", "Timeout", "Read timeout in nanoseconds",
125           0, G_MAXUINT64, 0, G_PARAM_READWRITE));
126
127   gst_fdsrc_signals[SIGNAL_TIMEOUT] =
128       g_signal_new ("timeout", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
129       G_STRUCT_OFFSET (GstFdSrcClass, timeout), NULL, NULL,
130       g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
131
132   gstelement_class->change_state = gst_fdsrc_change_state;
133
134   gstpush_src_class->create = gst_fdsrc_create;
135
136 }
137
138 static void
139 gst_fdsrc_init (GstFdSrc * fdsrc)
140 {
141   // TODO set live only if it's actually a live source
142   gst_base_src_set_live (GST_BASE_SRC (fdsrc), TRUE);
143
144   fdsrc->fd = 0;
145   fdsrc->curoffset = 0;
146   fdsrc->blocksize = DEFAULT_BLOCKSIZE;
147   fdsrc->timeout = 0;
148   fdsrc->seq = 0;
149 }
150
151 static GstStateChangeReturn
152 gst_fdsrc_change_state (GstElement * element, GstStateChange transition)
153 {
154   GstFdSrc *src = GST_FDSRC (element);
155
156   switch (transition) {
157     case GST_STATE_CHANGE_NULL_TO_READY:
158       break;
159     case GST_STATE_CHANGE_READY_TO_NULL:
160       break;
161     case GST_STATE_CHANGE_READY_TO_PAUSED:
162       src->curoffset = 0;
163       break;
164     case GST_STATE_CHANGE_PAUSED_TO_READY:
165       break;
166     default:
167       break;
168   }
169
170   if (GST_ELEMENT_CLASS (parent_class)->change_state)
171     return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
172
173   return GST_STATE_CHANGE_SUCCESS;
174 }
175
176
177 static void
178 gst_fdsrc_set_property (GObject * object, guint prop_id, const GValue * value,
179     GParamSpec * pspec)
180 {
181   GstFdSrc *src;
182
183   g_return_if_fail (GST_IS_FDSRC (object));
184
185   src = GST_FDSRC (object);
186
187   switch (prop_id) {
188     case ARG_FD:
189       src->fd = g_value_get_int (value);
190       break;
191     case ARG_BLOCKSIZE:
192       src->blocksize = g_value_get_ulong (value);
193       break;
194     case ARG_TIMEOUT:
195       src->timeout = g_value_get_uint64 (value);
196       break;
197     default:
198       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
199       break;
200   }
201 }
202
203 static void
204 gst_fdsrc_get_property (GObject * object, guint prop_id, GValue * value,
205     GParamSpec * pspec)
206 {
207   GstFdSrc *src;
208
209   g_return_if_fail (GST_IS_FDSRC (object));
210
211   src = GST_FDSRC (object);
212
213   switch (prop_id) {
214     case ARG_BLOCKSIZE:
215       g_value_set_ulong (value, src->blocksize);
216       break;
217     case ARG_FD:
218       g_value_set_int (value, src->fd);
219       break;
220     case ARG_TIMEOUT:
221       g_value_set_uint64 (value, src->timeout);
222       break;
223     default:
224       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
225       break;
226   }
227 }
228
229 static GstFlowReturn
230 gst_fdsrc_create (GstPushSrc * psrc, GstBuffer ** outbuf)
231 {
232   GstFdSrc *src;
233   GstBuffer *buf;
234   glong readbytes;
235
236 #ifndef HAVE_WIN32
237   fd_set readfds;
238   struct timeval t, *tp = &t;
239   gint retval;
240 #endif
241
242   src = GST_FDSRC (psrc);
243
244   /* create the buffer */
245   buf = gst_buffer_new_and_alloc (src->blocksize);
246
247 #ifndef HAVE_WIN32
248   FD_ZERO (&readfds);
249   FD_SET (src->fd, &readfds);
250
251   if (src->timeout != 0) {
252     GST_TIME_TO_TIMEVAL (src->timeout, t);
253   } else
254     tp = NULL;
255
256   do {
257     retval = select (src->fd + 1, &readfds, NULL, NULL, tp);
258   } while (retval == -1 && errno == EINTR);     /* retry if interrupted */
259
260   if (retval == -1) {
261     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
262         ("select on file descriptor: %s.", g_strerror (errno)));
263     return GST_FLOW_ERROR;
264   } else if (retval == 0) {
265     g_signal_emit (G_OBJECT (src), gst_fdsrc_signals[SIGNAL_TIMEOUT], 0);
266     return GST_FLOW_ERROR;
267   }
268 #endif
269
270   do {
271     readbytes = read (src->fd, GST_BUFFER_DATA (buf), src->blocksize);
272   } while (readbytes == -1 && errno == EINTR);  /* retry if interrupted */
273
274   if (readbytes > 0) {
275     GST_BUFFER_OFFSET (buf) = src->curoffset;
276     GST_BUFFER_SIZE (buf) = readbytes;
277     GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
278     src->curoffset += readbytes;
279
280     /* we're done, return the buffer */
281     *outbuf = buf;
282     return GST_FLOW_OK;
283   } else if (readbytes == 0) {
284     return GST_FLOW_ERROR;
285   } else {
286     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
287         ("read on file descriptor: %s.", g_strerror (errno)));
288     return GST_FLOW_ERROR;
289   }
290 }