This is a megapatch with the following changes:
[platform/upstream/gstreamer.git] / plugins / elements / gstdisksrc.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstdisksrc.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 <unistd.h>
27
28 #include <gstdisksrc.h>
29
30
31 GstElementDetails gst_disksrc_details = {
32   "Disk Source",
33   "Source/File",
34   "Synchronous read from a file",
35   VERSION,
36   "Erik Walthinsen <omega@cse.ogi.edu>",
37   "(C) 1999",
38 };
39
40
41 /* DiskSrc signals and args */
42 enum {
43   /* FILL ME */
44   LAST_SIGNAL
45 };
46
47 enum {
48   ARG_0,
49   ARG_LOCATION,
50   ARG_BYTESPERREAD,
51   ARG_OFFSET,
52   ARG_SIZE,
53 };
54
55
56 static void                     gst_disksrc_class_init          (GstDiskSrcClass *klass);
57 static void                     gst_disksrc_init                (GstDiskSrc *disksrc);
58
59 static void                     gst_disksrc_set_arg             (GtkObject *object, GtkArg *arg, guint id);
60 static void                     gst_disksrc_get_arg             (GtkObject *object, GtkArg *arg, guint id);
61
62 static void                     gst_disksrc_close_file          (GstDiskSrc *src);
63
64 static GstBuffer *              gst_disksrc_get                 (GstPad *pad);
65
66 static GstElementStateReturn    gst_disksrc_change_state        (GstElement *element);
67
68
69 static GstElementClass *parent_class = NULL;
70 //static guint gst_disksrc_signals[LAST_SIGNAL] = { 0 };
71
72 GtkType
73 gst_disksrc_get_type(void) {
74   static GtkType disksrc_type = 0;
75
76   if (!disksrc_type) {
77     static const GtkTypeInfo disksrc_info = {
78       "GstDiskSrc",
79       sizeof(GstDiskSrc),
80       sizeof(GstDiskSrcClass),
81       (GtkClassInitFunc)gst_disksrc_class_init,
82       (GtkObjectInitFunc)gst_disksrc_init,
83       (GtkArgSetFunc)gst_disksrc_set_arg,
84       (GtkArgGetFunc)gst_disksrc_get_arg,
85       (GtkClassInitFunc)NULL,
86     };
87     disksrc_type = gtk_type_unique(GST_TYPE_ELEMENT,&disksrc_info);
88   }
89   return disksrc_type;
90 }
91
92 static void
93 gst_disksrc_class_init (GstDiskSrcClass *klass) 
94 {
95   GtkObjectClass *gtkobject_class;
96   GstElementClass *gstelement_class;
97
98   gtkobject_class = (GtkObjectClass*)klass;
99   gstelement_class = (GstElementClass*)klass;
100
101   parent_class = gtk_type_class (GST_TYPE_ELEMENT);
102
103   gtk_object_add_arg_type ("GstDiskSrc::location", GST_TYPE_FILENAME,
104                            GTK_ARG_READWRITE, ARG_LOCATION);
105   gtk_object_add_arg_type ("GstDiskSrc::bytesperread", GTK_TYPE_INT,
106                            GTK_ARG_READWRITE, ARG_BYTESPERREAD);
107   gtk_object_add_arg_type ("GstDiskSrc::offset", GTK_TYPE_INT,
108                            GTK_ARG_READABLE, ARG_OFFSET);
109   gtk_object_add_arg_type ("GstDiskSrc::size", GTK_TYPE_INT,
110                            GTK_ARG_READABLE, ARG_SIZE);
111
112   gtkobject_class->set_arg = gst_disksrc_set_arg;
113   gtkobject_class->get_arg = gst_disksrc_get_arg;
114
115   gstelement_class->change_state = gst_disksrc_change_state;
116 }
117
118 static void 
119 gst_disksrc_init (GstDiskSrc *disksrc) 
120 {
121   disksrc->srcpad = gst_pad_new ("src", GST_PAD_SRC);
122   gst_pad_set_get_function(disksrc->srcpad,gst_disksrc_get);
123   gst_element_add_pad (GST_ELEMENT (disksrc), disksrc->srcpad);
124
125   disksrc->filename = NULL;
126   disksrc->fd = 0;
127   disksrc->curoffset = 0;
128   disksrc->bytes_per_read = 4096;
129   disksrc->seq = 0;
130   disksrc->size = 0;
131   disksrc->new_seek = FALSE;
132 }
133
134
135 static void 
136 gst_disksrc_set_arg (GtkObject *object, GtkArg *arg, guint id) 
137 {
138   GstDiskSrc *src;
139
140   /* it's not null if we got it, but it might not be ours */
141   g_return_if_fail (GST_IS_DISKSRC (object));
142   
143   src = GST_DISKSRC (object);
144
145   switch(id) {
146     case ARG_LOCATION:
147       /* the element must not be playing in order to do this */
148       g_return_if_fail (GST_STATE(src) < GST_STATE_PLAYING);
149
150       if (src->filename) g_free (src->filename);
151       /* clear the filename if we get a NULL (is that possible?) */
152       if (GTK_VALUE_STRING (*arg) == NULL) {
153         gst_element_set_state (GST_ELEMENT (object), GST_STATE_NULL);
154         src->filename = NULL;
155       /* otherwise set the new filename */
156       } else {
157         src->filename = g_strdup (GTK_VALUE_STRING (*arg));
158       }
159       break;
160     case ARG_BYTESPERREAD:
161       src->bytes_per_read = GTK_VALUE_INT (*arg);
162       break;
163       /*
164     case ARG_OFFSET:
165       src->curoffset = GTK_VALUE_INT(*arg);
166       lseek(src->fd,src->curoffset, SEEK_SET);
167       src->new_seek = TRUE;
168       break;
169       */
170     default:
171       break;
172   }
173 }
174
175 static void 
176 gst_disksrc_get_arg (GtkObject *object, GtkArg *arg, guint id) 
177 {
178   GstDiskSrc *src;
179
180   /* it's not null if we got it, but it might not be ours */
181   g_return_if_fail (GST_IS_DISKSRC (object));
182   src = GST_DISKSRC (object);
183
184   switch (id) {
185     case ARG_LOCATION:
186       GTK_VALUE_STRING (*arg) = src->filename;
187       break;
188     case ARG_BYTESPERREAD:
189       GTK_VALUE_INT (*arg) = src->bytes_per_read;
190       break;
191     case ARG_OFFSET:
192       GTK_VALUE_INT (*arg) = src->curoffset;
193       break;
194     case ARG_SIZE:
195       GTK_VALUE_INT (*arg) = src->size;
196       break;
197     default:
198       arg->type = GTK_TYPE_INVALID;
199       break;
200   }
201 }
202
203 static GstBuffer *
204 gst_disksrc_get (GstPad *pad) 
205 {
206   GstDiskSrc *src;
207   GstBuffer *buf;
208   glong readbytes;
209
210   g_return_val_if_fail (pad != NULL, NULL);
211   src = GST_DISKSRC(gst_pad_get_parent (pad));
212   g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_DISKSRC_OPEN), NULL);
213   g_return_val_if_fail (GST_STATE (src) >= GST_STATE_READY, NULL);
214
215   /* create the buffer */
216   // FIXME: should eventually use a bufferpool for this
217   buf = gst_buffer_new ();
218   g_return_val_if_fail (buf, NULL);
219
220   /* allocate the space for the buffer data */
221   GST_BUFFER_DATA (buf) = g_malloc (src->bytes_per_read);
222   g_return_val_if_fail (GST_BUFFER_DATA (buf) != NULL, NULL);
223
224   /* read it in from the file */
225   readbytes = read (src->fd, GST_BUFFER_DATA (buf), src->bytes_per_read);
226   if (readbytes == -1) {
227     perror ("read()");
228     gst_buffer_unref (buf);
229     return NULL;
230   } else if (readbytes == 0) {
231     gst_element_signal_eos (GST_ELEMENT (src));
232     gst_buffer_unref (buf);
233     return NULL;
234   }
235
236   /* if we didn't get as many bytes as we asked for, we're at EOF */
237   if (readbytes < src->bytes_per_read) {
238     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_EOS);
239     GST_DEBUG (0,"setting GST_BUFFER_EOS\n");
240   }
241
242   /* if we have a new buffer from a seek, mark it */
243   if (src->new_seek) {
244     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLUSH);
245     src->new_seek = FALSE;
246   }
247
248   GST_BUFFER_OFFSET (buf) = src->curoffset;
249   GST_BUFFER_SIZE (buf) = readbytes;
250   src->curoffset += readbytes;
251
252   GST_DEBUG (0,"pushing %d bytes with offset %d\n", GST_BUFFER_SIZE(buf), GST_BUFFER_OFFSET (buf));
253   /* we're done, push the buffer off now */
254   GST_DEBUG (0,"returning %d bytes with offset %d done\n", GST_BUFFER_SIZE(buf), GST_BUFFER_OFFSET (buf));
255   return buf;
256 }
257
258
259 /* open the file, necessary to go to RUNNING state */
260 static gboolean 
261 gst_disksrc_open_file (GstDiskSrc *src) 
262 {
263   struct stat f_stat;
264
265   g_return_val_if_fail (!GST_FLAG_IS_SET (src, GST_DISKSRC_OPEN), FALSE);
266   g_return_val_if_fail (src->filename != NULL, FALSE);
267
268   /* open the file */
269   src->fd = open (src->filename, O_RDONLY);
270   if (src->fd < 0) {
271     perror ("open()");
272     gst_element_error (GST_ELEMENT (src), "opening file");
273     return FALSE;
274   }
275   if (fstat (src->fd, &f_stat) < 0) {
276     perror("fstat()");
277   }
278   else {
279     src->size = f_stat.st_size;
280     GST_DEBUG (0,"gstdisksrc: file size %ld\n", src->size);
281   }
282   GST_FLAG_SET (src, GST_DISKSRC_OPEN);
283   return TRUE;
284 }
285
286 /* close the file */
287 static void 
288 gst_disksrc_close_file (GstDiskSrc *src) 
289 {
290   g_return_if_fail (GST_FLAG_IS_SET (src, GST_DISKSRC_OPEN));
291
292   /* close the file */
293   close (src->fd);
294
295   /* zero out a lot of our state */
296   src->fd = 0;
297   src->curoffset = 0;
298   src->seq = 0;
299   src->size = 0;
300
301   GST_FLAG_UNSET (src, GST_DISKSRC_OPEN);
302 }
303
304 static GstElementStateReturn 
305 gst_disksrc_change_state (GstElement *element) 
306 {
307   g_return_val_if_fail (GST_IS_DISKSRC (element), GST_STATE_FAILURE);
308
309   GST_DEBUG (0,"gstdisksrc: state pending %d\n", GST_STATE_PENDING (element));
310
311   /* if going down into NULL state, close the file if it's open */
312   if (GST_STATE_PENDING (element) == GST_STATE_NULL) {
313     if (GST_FLAG_IS_SET (element, GST_DISKSRC_OPEN))
314       gst_disksrc_close_file (GST_DISKSRC (element));
315   /* otherwise (READY or higher) we need to open the file */
316   } else {
317     if (!GST_FLAG_IS_SET (element, GST_DISKSRC_OPEN)) {
318       if (!gst_disksrc_open_file (GST_DISKSRC (element)))
319         return GST_STATE_FAILURE;
320     }
321   }
322
323   /* if we haven't failed already, give the parent class a chance to ;-) */
324   if (GST_ELEMENT_CLASS (parent_class)->change_state)
325     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
326
327   return GST_STATE_SUCCESS;
328 }