initial checkin
[platform/upstream/gstreamer.git] / gst / elements / gstdisksrc.c
1 /* Gnome-Streamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23
24 #include <gstdisksrc.h>
25
26
27 GstElementDetails gst_disksrc_details = {
28   "Disk Source",
29   "Source/File",
30   "Synchronous read from a file",
31   VERSION,
32   "Erik Walthinsen <omega@cse.ogi.edu>",
33   "(C) 1999",
34 };
35
36
37 /* DiskSrc signals and args */
38 enum {
39   /* FILL ME */
40   LAST_SIGNAL
41 };
42
43 enum {
44   ARG_0,
45   ARG_LOCATION,
46   ARG_BYTESPERREAD,
47   ARG_OFFSET,
48 };
49
50
51 static void gst_disksrc_class_init(GstDiskSrcClass *klass);
52 static void gst_disksrc_init(GstDiskSrc *disksrc);
53 static void gst_disksrc_set_arg(GtkObject *object,GtkArg *arg,guint id);
54 static void gst_disksrc_get_arg(GtkObject *object,GtkArg *arg,guint id);
55
56 static void gst_disksrc_push(GstSrc *src);
57 static void gst_disksrc_push_region(GstSrc *src,gulong offset,gulong size);
58 static gboolean gst_disksrc_change_state(GstElement *element,
59                                          GstElementState state);
60
61
62 static GstSrcClass *parent_class = NULL;
63 static guint gst_disksrc_signals[LAST_SIGNAL] = { 0 };
64
65 GtkType
66 gst_disksrc_get_type(void) {
67   static GtkType disksrc_type = 0;
68
69   if (!disksrc_type) {
70     static const GtkTypeInfo disksrc_info = {
71       "GstDiskSrc",
72       sizeof(GstDiskSrc),
73       sizeof(GstDiskSrcClass),
74       (GtkClassInitFunc)gst_disksrc_class_init,
75       (GtkObjectInitFunc)gst_disksrc_init,
76       (GtkArgSetFunc)gst_disksrc_set_arg,
77       (GtkArgGetFunc)gst_disksrc_get_arg,
78       (GtkClassInitFunc)NULL,
79     };
80     disksrc_type = gtk_type_unique(GST_TYPE_SRC,&disksrc_info);
81   }
82   return disksrc_type;
83 }
84
85 static void
86 gst_disksrc_class_init(GstDiskSrcClass *klass) {
87   GtkObjectClass *gtkobject_class;
88   GstElementClass *gstelement_class;
89   GstSrcClass *gstsrc_class;
90
91   gtkobject_class = (GtkObjectClass*)klass;
92   gstelement_class = (GstElementClass*)klass;
93   gstsrc_class = (GstSrcClass*)klass;
94
95   parent_class = gtk_type_class(GST_TYPE_SRC);
96
97   gtk_object_add_arg_type("GstDiskSrc::location", GTK_TYPE_STRING,
98                           GTK_ARG_READWRITE, ARG_LOCATION);
99   gtk_object_add_arg_type("GstDiskSrc::bytesperread", GTK_TYPE_INT,
100                           GTK_ARG_READWRITE, ARG_BYTESPERREAD);
101   gtk_object_add_arg_type("GstDiskSrc::offset", GTK_TYPE_INT,
102                           GTK_ARG_READWRITE, ARG_OFFSET);
103
104   gtkobject_class->set_arg = gst_disksrc_set_arg;
105   gtkobject_class->get_arg = gst_disksrc_get_arg;
106
107   gstelement_class->change_state = gst_disksrc_change_state;
108
109   gstsrc_class->push = gst_disksrc_push;
110   /* we nominally can't (won't) do async */
111   gstsrc_class->push_region = NULL;
112 }
113
114 static void gst_disksrc_init(GstDiskSrc *disksrc) {
115   disksrc->srcpad = gst_pad_new("src",GST_PAD_SRC);
116   gst_element_add_pad(GST_ELEMENT(disksrc),disksrc->srcpad);
117
118   disksrc->filename = NULL;
119   disksrc->fd = 0;
120   disksrc->curoffset = 0;
121   disksrc->bytes_per_read = 4096;
122   disksrc->seq = 0;
123 }
124
125
126 static void gst_disksrc_set_arg(GtkObject *object,GtkArg *arg,guint id) {
127   GstDiskSrc *src;
128
129   /* it's not null if we got it, but it might not be ours */
130   g_return_if_fail(GST_IS_DISKSRC(object));
131   src = GST_DISKSRC(object);
132
133   switch(id) {
134     case ARG_LOCATION:
135       /* the element must be stopped in order to do this */
136 //      g_return_if_fail(!GST_FLAG_IS_SET(src,GST_STATE_RUNNING));
137
138       if (src->filename) g_free(src->filename);
139       /* clear the filename if we get a NULL (is that possible?) */
140       if (GTK_VALUE_STRING(*arg) == NULL) {
141         src->filename = NULL;
142         gst_element_set_state(GST_ELEMENT(object),~GST_STATE_COMPLETE);
143       /* otherwise set the new filename */
144       } else {
145         src->filename = g_strdup(GTK_VALUE_STRING(*arg));  
146         gst_element_set_state(GST_ELEMENT(object),GST_STATE_COMPLETE);
147       }
148       break;
149     case ARG_BYTESPERREAD:
150       src->bytes_per_read = GTK_VALUE_INT(*arg);
151       break;
152     default:
153       break;
154   }
155 }
156
157 static void gst_disksrc_get_arg(GtkObject *object,GtkArg *arg,guint id) {
158   GstDiskSrc *src;
159
160   /* it's not null if we got it, but it might not be ours */
161   g_return_if_fail(GST_IS_DISKSRC(object));
162   src = GST_DISKSRC(object);
163
164   switch (id) {
165     case ARG_LOCATION:
166       GTK_VALUE_STRING(*arg) = src->filename;
167       break;
168     case ARG_BYTESPERREAD:
169       GTK_VALUE_INT(*arg) = src->bytes_per_read;
170       break;
171     case ARG_OFFSET:
172       GTK_VALUE_INT(*arg) = src->curoffset;
173       break;
174     default:
175       arg->type = GTK_TYPE_INVALID;
176       break;
177   }
178 }
179
180 void gst_disksrc_push(GstSrc *src) {
181   GstDiskSrc *disksrc;
182   GstBuffer *buf;
183   glong readbytes;
184
185   g_return_if_fail(src != NULL);
186   g_return_if_fail(GST_IS_DISKSRC(src));
187   g_return_if_fail(GST_FLAG_IS_SET(src,GST_DISKSRC_OPEN));
188   disksrc = GST_DISKSRC(src);
189
190   /* create the buffer */
191   // FIXME: should eventually use a bufferpool for this
192   buf = gst_buffer_new();
193   g_return_if_fail(buf);
194
195   /* allocate the space for the buffer data */
196   GST_BUFFER_DATA(buf) = g_malloc(disksrc->bytes_per_read);
197   g_return_if_fail(GST_BUFFER_DATA(buf) != NULL);
198
199   /* read it in from the file */
200   readbytes = read(disksrc->fd,GST_BUFFER_DATA(buf),disksrc->bytes_per_read);
201   if (readbytes == 0) {
202     gst_src_signal_eos(GST_SRC(disksrc));
203     return;
204   }
205
206   /* if we didn't get as many bytes as we asked for, we're at EOF */
207   if (readbytes < disksrc->bytes_per_read)
208     GST_BUFFER_FLAG_SET(buf,GST_BUFFER_EOS);
209   GST_BUFFER_OFFSET(buf) = disksrc->curoffset;
210   GST_BUFFER_SIZE(buf) = readbytes;
211   disksrc->curoffset += readbytes;
212
213   /* we're done, push the buffer off now */
214   gst_pad_push(disksrc->srcpad,buf);
215 }
216
217
218 /* open the file, necessary to go to RUNNING state */
219 static gboolean gst_disksrc_open_file(GstDiskSrc *src) {
220   g_return_if_fail(!GST_FLAG_IS_SET(src,GST_DISKSRC_OPEN));
221
222   /* open the file */
223   src->fd = open(src->filename,O_RDONLY);
224   if (src->fd < 0) {
225     perror("open()");
226     gst_element_error(GST_ELEMENT(src),"opening file");
227     return FALSE;
228   }
229   GST_FLAG_SET(src,GST_DISKSRC_OPEN);
230   return TRUE;
231 }
232
233 /* close the file */
234 static void gst_disksrc_close_file(GstDiskSrc *src) {
235   g_return_if_fail(GST_FLAG_IS_SET(src,GST_DISKSRC_OPEN));
236
237   /* close the file */
238   close(src->fd);
239
240   /* zero out a lot of our state */
241   src->fd = 0;
242   src->curoffset = 0;
243   src->seq = 0;
244
245   GST_FLAG_UNSET(src,GST_DISKSRC_OPEN);
246 }
247
248 static gboolean gst_disksrc_change_state(GstElement *element,
249                                          GstElementState state) {
250   g_return_if_fail(GST_IS_DISKSRC(element));
251
252   switch (state) {
253     case GST_STATE_RUNNING:
254       if (!gst_disksrc_open_file(GST_DISKSRC(element)))
255         return FALSE;
256       break;  
257     case ~GST_STATE_RUNNING:
258       gst_disksrc_close_file(GST_DISKSRC(element));
259       break;
260     default:
261       break;
262   }     
263       
264   if (GST_ELEMENT_CLASS(parent_class)->change_state)
265     return GST_ELEMENT_CLASS(parent_class)->change_state(element,state);
266   return TRUE;
267 }