whitespace fixes
[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 <sys/socket.h>
32 #include <fcntl.h>
33 #include <stdio.h>
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37 #include <stdlib.h>
38 #include <errno.h>
39
40 #include "gstfdsrc.h"
41
42 /* the select call is also performed on the control sockets, that way
43  * we can send special commands to unblock the select call */
44 #define CONTROL_STOP            'S'     /* stop the select call */
45 #define CONTROL_SOCKETS(src)   src->control_sock
46 #define WRITE_SOCKET(src)      src->control_sock[1]
47 #define READ_SOCKET(src)       src->control_sock[0]
48
49 #define SEND_COMMAND(src, command)          \
50 G_STMT_START {                              \
51   unsigned char c; c = command;             \
52   write (WRITE_SOCKET(src), &c, 1);         \
53 } G_STMT_END
54
55 #define READ_COMMAND(src, command, res)        \
56 G_STMT_START {                                 \
57   res = read(READ_SOCKET(src), &command, 1);   \
58 } G_STMT_END
59
60 #define DEFAULT_BLOCKSIZE       4096
61
62 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
63     GST_PAD_SRC,
64     GST_PAD_ALWAYS,
65     GST_STATIC_CAPS_ANY);
66
67 GST_DEBUG_CATEGORY_STATIC (gst_fdsrc_debug);
68 #define GST_CAT_DEFAULT gst_fdsrc_debug
69
70 static GstElementDetails gst_fdsrc_details = GST_ELEMENT_DETAILS ("Disk Source",
71     "Source/File",
72     "Synchronous read from a file",
73     "Erik Walthinsen <omega@cse.ogi.edu>");
74
75
76 enum
77 {
78   PROP_0,
79   PROP_FD,
80 };
81
82 #define _do_init(bla) \
83     GST_DEBUG_CATEGORY_INIT (gst_fdsrc_debug, "fdsrc", 0, "fdsrc element");
84
85 GST_BOILERPLATE_FULL (GstFdSrc, gst_fdsrc, GstElement, GST_TYPE_PUSH_SRC,
86     _do_init);
87
88 static void gst_fdsrc_set_property (GObject * object, guint prop_id,
89     const GValue * value, GParamSpec * pspec);
90 static void gst_fdsrc_get_property (GObject * object, guint prop_id,
91     GValue * value, GParamSpec * pspec);
92
93 static gboolean gst_fdsrc_start (GstBaseSrc * bsrc);
94 static gboolean gst_fdsrc_stop (GstBaseSrc * bsrc);
95 static gboolean gst_fdsrc_unlock (GstBaseSrc * bsrc);
96
97 static GstFlowReturn gst_fdsrc_create (GstPushSrc * psrc, GstBuffer ** outbuf);
98
99 static void
100 gst_fdsrc_base_init (gpointer g_class)
101 {
102   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
103
104   gst_element_class_add_pad_template (gstelement_class,
105       gst_static_pad_template_get (&srctemplate));
106   gst_element_class_set_details (gstelement_class, &gst_fdsrc_details);
107 }
108
109 static void
110 gst_fdsrc_class_init (GstFdSrcClass * klass)
111 {
112   GObjectClass *gobject_class;
113   GstBaseSrcClass *gstbasesrc_class;
114   GstElementClass *gstelement_class;
115   GstPushSrcClass *gstpush_src_class;
116
117   gobject_class = G_OBJECT_CLASS (klass);
118   gstelement_class = GST_ELEMENT_CLASS (klass);
119   gstbasesrc_class = (GstBaseSrcClass *) klass;
120   gstpush_src_class = (GstPushSrcClass *) klass;
121
122   parent_class = g_type_class_ref (GST_TYPE_PUSH_SRC);
123
124   gobject_class->set_property = gst_fdsrc_set_property;
125   gobject_class->get_property = gst_fdsrc_get_property;
126
127   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FD,
128       g_param_spec_int ("fd", "fd", "An open file descriptor to read from",
129           0, G_MAXINT, 0, G_PARAM_READWRITE));
130
131   gstbasesrc_class->start = gst_fdsrc_start;
132   gstbasesrc_class->stop = gst_fdsrc_stop;
133   gstbasesrc_class->unlock = gst_fdsrc_unlock;
134
135   gstpush_src_class->create = gst_fdsrc_create;
136 }
137
138 static void
139 gst_fdsrc_init (GstFdSrc * fdsrc, GstFdSrcClass * klass)
140 {
141   /* TODO set live only if it's actually a live source (check
142    * for seekable fd) */
143   gst_base_src_set_live (GST_BASE_SRC (fdsrc), TRUE);
144
145   fdsrc->fd = 0;
146   fdsrc->curoffset = 0;
147 }
148
149 static gboolean
150 gst_fdsrc_start (GstBaseSrc * bsrc)
151 {
152   GstFdSrc *src = GST_FDSRC (bsrc);
153   gint control_sock[2];
154
155   src->curoffset = 0;
156
157   if (socketpair (PF_UNIX, SOCK_STREAM, 0, control_sock) < 0)
158     goto socket_pair;
159
160   READ_SOCKET (src) = control_sock[0];
161   WRITE_SOCKET (src) = control_sock[1];
162
163   fcntl (READ_SOCKET (src), F_SETFL, O_NONBLOCK);
164   fcntl (WRITE_SOCKET (src), F_SETFL, O_NONBLOCK);
165
166   return TRUE;
167
168   /* ERRORS */
169 socket_pair:
170   {
171     GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL),
172         GST_ERROR_SYSTEM);
173     return FALSE;
174   }
175 }
176
177 static gboolean
178 gst_fdsrc_stop (GstBaseSrc * bsrc)
179 {
180   GstFdSrc *src = GST_FDSRC (bsrc);
181
182   close (READ_SOCKET (src));
183   close (WRITE_SOCKET (src));
184
185   return TRUE;
186 }
187
188 static gboolean
189 gst_fdsrc_unlock (GstBaseSrc * bsrc)
190 {
191   GstFdSrc *src = GST_FDSRC (bsrc);
192
193   SEND_COMMAND (src, CONTROL_STOP);
194
195   return TRUE;
196 }
197
198 static void
199 gst_fdsrc_set_property (GObject * object, guint prop_id, const GValue * value,
200     GParamSpec * pspec)
201 {
202   GstFdSrc *src = GST_FDSRC (object);
203
204   switch (prop_id) {
205     case PROP_FD:
206       src->fd = g_value_get_int (value);
207       break;
208     default:
209       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
210       break;
211   }
212 }
213
214 static void
215 gst_fdsrc_get_property (GObject * object, guint prop_id, GValue * value,
216     GParamSpec * pspec)
217 {
218   GstFdSrc *src = GST_FDSRC (object);
219
220   switch (prop_id) {
221     case PROP_FD:
222       g_value_set_int (value, src->fd);
223       break;
224     default:
225       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
226       break;
227   }
228 }
229
230 static GstFlowReturn
231 gst_fdsrc_create (GstPushSrc * psrc, GstBuffer ** outbuf)
232 {
233   GstFdSrc *src;
234   GstBuffer *buf;
235   glong readbytes;
236   guint blocksize;
237
238 #ifndef HAVE_WIN32
239   fd_set readfds;
240   gint retval;
241 #endif
242
243   src = GST_FDSRC (psrc);
244
245 #ifndef HAVE_WIN32
246   FD_ZERO (&readfds);
247   FD_SET (src->fd, &readfds);
248   FD_SET (READ_SOCKET (src), &readfds);
249
250   do {
251     retval = select (FD_SETSIZE, &readfds, NULL, NULL, NULL);
252   } while ((retval == -1 && errno == EINTR));
253
254   if (retval == -1)
255     goto select_error;
256
257   if (FD_ISSET (READ_SOCKET (src), &readfds)) {
258     /* read all stop commands */
259     while (TRUE) {
260       gchar command;
261       int res;
262
263       READ_COMMAND (src, command, res);
264       if (res < 0) {
265         GST_LOG_OBJECT (src, "no more commands");
266         /* no more commands */
267         break;
268       }
269     }
270     goto stopped;
271   }
272 #endif
273
274   blocksize = GST_BASE_SRC (src)->blocksize;
275
276   /* create the buffer */
277   buf = gst_buffer_new_and_alloc (blocksize);
278
279   do {
280     readbytes = read (src->fd, GST_BUFFER_DATA (buf), blocksize);
281   } while (readbytes == -1 && errno == EINTR);  /* retry if interrupted */
282
283   if (readbytes < 0)
284     goto read_error;
285
286   if (readbytes == 0)
287     goto eos;
288
289   GST_BUFFER_OFFSET (buf) = src->curoffset;
290   GST_BUFFER_SIZE (buf) = readbytes;
291   GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
292   src->curoffset += readbytes;
293
294   GST_DEBUG_OBJECT (psrc, "Read buffer of size %u.", readbytes);
295
296   /* we're done, return the buffer */
297   *outbuf = buf;
298
299   return GST_FLOW_OK;
300
301   /* ERRORS */
302 #ifndef HAVE_WIN32
303 select_error:
304   {
305     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
306         ("select on file descriptor: %s.", g_strerror (errno)));
307     GST_DEBUG_OBJECT (psrc, "Error during select");
308     return GST_FLOW_ERROR;
309   }
310 stopped:
311   {
312     GST_DEBUG_OBJECT (psrc, "Select stopped");
313     return GST_FLOW_WRONG_STATE;
314   }
315 #endif
316 eos:
317   {
318     GST_DEBUG_OBJECT (psrc, "Read 0 bytes. EOS.");
319     gst_buffer_unref (buf);
320     return GST_FLOW_UNEXPECTED;
321   }
322 read_error:
323   {
324     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
325         ("read on file descriptor: %s.", g_strerror (errno)));
326     GST_DEBUG_OBJECT (psrc, "Error reading from fd");
327     gst_buffer_unref (buf);
328     return GST_FLOW_ERROR;
329   }
330 }