gst/elements/gstfdsrc.c: (gst_fdsrc_get): Use GST_TIME_TO_TIMEVAL()
[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  *
5  * gstfdsrc.c: 
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <errno.h>
30
31 #ifdef HAVE_CONFIG_H
32 #  include "config.h"
33 #endif
34
35 #include "gstfdsrc.h"
36
37 #define DEFAULT_BLOCKSIZE       4096
38
39 GST_DEBUG_CATEGORY_STATIC (gst_fdsrc_debug);
40 #define GST_CAT_DEFAULT gst_fdsrc_debug
41
42 GstElementDetails gst_fdsrc_details = GST_ELEMENT_DETAILS (
43   "Disk Source",
44   "Source/File",
45   "Synchronous read from a file",
46   "Erik Walthinsen <omega@cse.ogi.edu>"
47 );
48
49
50 /* FdSrc signals and args */
51 enum {
52   SIGNAL_TIMEOUT,
53   LAST_SIGNAL
54 };
55
56 enum {
57   ARG_0,
58   ARG_FD,
59   ARG_BLOCKSIZE,
60   ARG_TIMEOUT
61 };
62
63 static guint gst_fdsrc_signals[LAST_SIGNAL] = { 0 };
64
65 #define _do_init(bla) \
66     GST_DEBUG_CATEGORY_INIT (gst_fdsrc_debug, "fdsrc", 0, "fdsrc element");
67
68 GST_BOILERPLATE_FULL (GstFdSrc, gst_fdsrc, GstElement, GST_TYPE_ELEMENT, _do_init);
69
70 static void             gst_fdsrc_set_property  (GObject *object, guint prop_id, 
71                                                  const GValue *value, GParamSpec *pspec);
72 static void             gst_fdsrc_get_property  (GObject *object, guint prop_id, 
73                                                  GValue *value, GParamSpec *pspec);
74
75 static GstData *        gst_fdsrc_get           (GstPad *pad);
76
77
78 static void
79 gst_fdsrc_base_init (gpointer g_class)
80 {
81   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
82   
83   gst_element_class_set_details (gstelement_class, &gst_fdsrc_details);
84 }
85 static void
86 gst_fdsrc_class_init (GstFdSrcClass *klass) 
87 {
88   GObjectClass *gobject_class;
89
90   gobject_class = G_OBJECT_CLASS (klass);
91
92   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FD,
93     g_param_spec_int ("fd", "fd", "An open file descriptor to read from",
94                       0, G_MAXINT, 0, G_PARAM_READWRITE));
95   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BLOCKSIZE,
96     g_param_spec_ulong ("blocksize", "Block size", "Size in bytes to read per buffer",
97                         1, G_MAXULONG, DEFAULT_BLOCKSIZE, G_PARAM_READWRITE));
98   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TIMEOUT,
99     g_param_spec_uint64 ("timeout", "Timeout", "Read timeout in nanoseconds",
100                         0, G_MAXUINT64, 0, G_PARAM_READWRITE));
101
102   gst_fdsrc_signals[SIGNAL_TIMEOUT] =
103     g_signal_new ("timeout", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
104                     G_STRUCT_OFFSET (GstFdSrcClass, timeout), NULL, NULL,
105                     g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
106
107   gobject_class->set_property = gst_fdsrc_set_property;
108   gobject_class->get_property = gst_fdsrc_get_property;
109 }
110
111 static void gst_fdsrc_init(GstFdSrc *fdsrc) {
112   fdsrc->srcpad = gst_pad_new ("src", GST_PAD_SRC);
113   
114   gst_pad_set_get_function (fdsrc->srcpad, gst_fdsrc_get);
115   gst_element_add_pad (GST_ELEMENT (fdsrc), fdsrc->srcpad);
116
117   fdsrc->fd = 0;
118   fdsrc->curoffset = 0;
119   fdsrc->blocksize = DEFAULT_BLOCKSIZE;
120   fdsrc->timeout = 0;
121   fdsrc->seq = 0;
122 }
123
124
125 static void 
126 gst_fdsrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) 
127 {
128   GstFdSrc *src;
129
130   /* it's not null if we got it, but it might not be ours */
131   g_return_if_fail (GST_IS_FDSRC (object));
132   
133   src = GST_FDSRC (object);
134
135   switch (prop_id) {
136     case ARG_FD:
137       src->fd = g_value_get_int (value);
138       break;
139     case ARG_BLOCKSIZE:
140       src->blocksize = g_value_get_ulong (value);
141       break;
142     case ARG_TIMEOUT:
143       src->timeout = g_value_get_uint64 (value);
144       break;
145     default:
146       break;
147   }
148 }
149
150 static void 
151 gst_fdsrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) 
152 {
153   GstFdSrc *src;
154
155   /* it's not null if we got it, but it might not be ours */
156   g_return_if_fail (GST_IS_FDSRC (object));
157   
158   src = GST_FDSRC (object);
159
160   switch (prop_id) {
161     case ARG_BLOCKSIZE:
162       g_value_set_ulong (value, src->blocksize);
163       break;
164     case ARG_FD:
165       g_value_set_int (value, src->fd);
166       break;
167     case ARG_TIMEOUT:
168       g_value_set_uint64 (value, src->timeout);
169       break;
170     default:
171       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
172       break;
173   }
174 }
175
176 static GstData *
177 gst_fdsrc_get(GstPad *pad)
178 {
179   GstFdSrc *src;
180   GstBuffer *buf;
181   glong readbytes;
182   fd_set readfds;
183   struct timeval t, *tp = &t;
184   gint retval;
185
186   src = GST_FDSRC (gst_pad_get_parent (pad));
187
188   /* create the buffer */
189   buf = gst_buffer_new_and_alloc (src->blocksize);
190
191   FD_ZERO (&readfds);
192   FD_SET (src->fd, &readfds);
193
194   if (src->timeout != 0)
195   {
196     GST_TIME_TO_TIMEVAL (src->timeout, t);
197   }
198   else
199     tp = NULL;
200
201   do
202   {
203     retval = select (1, &readfds, NULL, NULL, tp);
204   } while (retval == -1 && errno == EINTR); /* retry if interrupted */
205
206   if (retval == -1)
207   {
208     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), ("select on file descriptor: %s.", g_strerror(errno)));
209     gst_element_set_eos (GST_ELEMENT (src));
210     return GST_DATA (gst_event_new (GST_EVENT_EOS));
211   }
212   else if (retval == 0)
213   {
214     g_signal_emit (G_OBJECT (src), gst_fdsrc_signals[SIGNAL_TIMEOUT], 0);
215     gst_element_set_eos (GST_ELEMENT (src));
216     return GST_DATA(gst_event_new (GST_EVENT_EOS));
217   }
218
219   do
220   {
221     readbytes = read (src->fd, GST_BUFFER_DATA (buf), src->blocksize);
222   } while (readbytes == -1 && errno == EINTR); /* retry if interrupted */
223
224   if (readbytes > 0)
225   {
226     GST_BUFFER_OFFSET (buf) = src->curoffset;
227     GST_BUFFER_SIZE (buf) = readbytes;
228     GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
229     src->curoffset += readbytes;
230
231     /* we're done, return the buffer */
232     return GST_DATA (buf);
233   }
234   else if (readbytes == 0)
235   {
236     gst_element_set_eos (GST_ELEMENT (src));
237     return GST_DATA (gst_event_new (GST_EVENT_EOS));
238   }
239   else
240   {
241     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), ("read on file descriptor: %s.", g_strerror(errno)));
242     gst_element_set_eos (GST_ELEMENT (src));
243     return GST_DATA (gst_event_new (GST_EVENT_EOS));
244   }
245 }