This is a megapatch with the following changes:
[platform/upstream/gstreamer.git] / plugins / elements / gsthttpsrc.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gsthttpsrc.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 <stdlib.h>
27 #include <unistd.h>
28
29 #include <gsthttpsrc.h>
30
31
32 GstElementDetails gst_httpsrc_details = {
33   "HTTP Source",
34   "Source/Network",
35   "Read data from an HTTP stream",
36   VERSION,
37   "Erik Walthinsen <omega@cse.ogi.edu>",
38   "(C) 1999",
39 };
40
41 /* HttpSrc 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 };
53
54 static void                     gst_httpsrc_class_init  (GstHttpSrcClass *klass);
55 static void                     gst_httpsrc_init        (GstHttpSrc *httpsrc);
56
57 static void                     gst_httpsrc_set_arg     (GtkObject *object, GtkArg *arg, guint id);
58 static void                     gst_httpsrc_get_arg     (GtkObject *object, GtkArg *arg, guint id);
59 static GstElementStateReturn    gst_httpsrc_change_state        (GstElement *element);
60
61 static GstBuffer *              gst_httpsrc_get         (GstPad *pad);
62
63 static gboolean                 gst_httpsrc_open_url    (GstHttpSrc *src);
64 static void                     gst_httpsrc_close_url   (GstHttpSrc *src);
65
66
67 static GstElementClass *parent_class = NULL;
68 //static guint gst_httpsrc_signals[LAST_SIGNAL] = { 0 };
69
70 GtkType
71 gst_httpsrc_get_type (void) 
72 {
73   static GtkType httpsrc_type = 0;
74
75   if (!httpsrc_type) {
76     static const GtkTypeInfo httpsrc_info = {
77       "GstHttpSrc",
78       sizeof(GstHttpSrc),
79       sizeof(GstHttpSrcClass),
80       (GtkClassInitFunc)gst_httpsrc_class_init,
81       (GtkObjectInitFunc)gst_httpsrc_init,
82       (GtkArgSetFunc)gst_httpsrc_set_arg,
83       (GtkArgGetFunc)gst_httpsrc_get_arg,
84       (GtkClassInitFunc)NULL,
85     };
86     httpsrc_type = gtk_type_unique (GST_TYPE_ELEMENT, &httpsrc_info);
87   }
88   return httpsrc_type;
89 }
90
91 static void
92 gst_httpsrc_class_init (GstHttpSrcClass *klass) 
93 {
94   GtkObjectClass *gtkobject_class;
95   GstElementClass *gstelement_class;
96
97   gtkobject_class = (GtkObjectClass*)klass;
98   gstelement_class = (GstElementClass*)klass;
99
100   parent_class = gtk_type_class (GST_TYPE_ELEMENT);
101
102
103   gtk_object_add_arg_type ("GstHttpSrc::location", GTK_TYPE_STRING,
104                            GTK_ARG_READWRITE, ARG_LOCATION);
105   gtk_object_add_arg_type ("GstHttpSrc::bytesperread", GTK_TYPE_INT,
106                            GTK_ARG_READWRITE, ARG_BYTESPERREAD);
107
108   gtkobject_class->set_arg = gst_httpsrc_set_arg;
109   gtkobject_class->get_arg = gst_httpsrc_get_arg;
110
111   gstelement_class->change_state = gst_httpsrc_change_state;
112 }
113
114 static void gst_httpsrc_init(GstHttpSrc *httpsrc) {
115   httpsrc->srcpad = gst_pad_new("src",GST_PAD_SRC);
116   gst_pad_set_get_function(httpsrc->srcpad,gst_httpsrc_get);
117   gst_element_add_pad(GST_ELEMENT(httpsrc),httpsrc->srcpad);
118
119   httpsrc->url = NULL;
120   httpsrc->request = NULL;
121   httpsrc->fd = 0;
122   httpsrc->curoffset = 0;
123   httpsrc->bytes_per_read = 4096;
124 }
125
126 static GstBuffer *
127 gst_httpsrc_get(GstPad *pad)
128 {
129   GstHttpSrc *src;
130   GstBuffer *buf;
131   glong readbytes;
132
133   g_return_val_if_fail (pad != NULL, NULL);
134   src = GST_HTTPSRC(gst_pad_get_parent (pad));
135
136   buf = gst_buffer_new();
137   GST_BUFFER_DATA(buf) = (gpointer)malloc(src->bytes_per_read);
138   readbytes = read(src->fd,GST_BUFFER_DATA(buf),src->bytes_per_read);
139
140   if (readbytes == 0) {
141     gst_element_signal_eos(GST_ELEMENT(src));
142     return NULL;
143   }
144
145   if (readbytes < src->bytes_per_read) {
146     // FIXME: set the buffer's EOF bit here
147   }
148   GST_BUFFER_OFFSET(buf) = src->curoffset;
149   GST_BUFFER_SIZE(buf) = readbytes;
150   src->curoffset += readbytes;
151
152   return buf;
153 }
154
155 static gboolean 
156 gst_httpsrc_open_url (GstHttpSrc *httpsrc) 
157 {
158   gint status;
159
160   g_return_val_if_fail (!GST_FLAG_IS_SET (httpsrc, GST_HTTPSRC_OPEN), FALSE);
161   g_return_val_if_fail (httpsrc->url != NULL, FALSE);
162
163   httpsrc->request = ghttp_request_new ();
164   
165   ghttp_set_uri (httpsrc->request, httpsrc->url);
166   ghttp_set_sync (httpsrc->request, ghttp_async);
167   ghttp_set_header (httpsrc->request, "User-Agent", "GstHttpSrc");
168   ghttp_prepare (httpsrc->request);
169
170   /* process everything up to the actual data stream */
171   /* FIXME: should be in preroll, but hey */
172   status = 0;
173   while ((ghttp_get_status (httpsrc->request).proc != ghttp_proc_response)
174          && (status >= 0)) {
175     status = ghttp_process (httpsrc->request);
176   }
177
178   /* get the fd so we can read data ourselves */
179   httpsrc->fd = ghttp_get_socket (httpsrc->request);
180   
181   GST_FLAG_SET (httpsrc, GST_HTTPSRC_OPEN);
182   
183   return TRUE;
184 }
185
186 /* unmap and close the file */
187 static void 
188 gst_httpsrc_close_url (GstHttpSrc *src) 
189 {  
190   g_return_if_fail (GST_FLAG_IS_SET (src, GST_HTTPSRC_OPEN));
191   g_return_if_fail (src->fd > 0);
192  
193   close(src->fd);
194   src->fd = 0;
195
196   GST_FLAG_UNSET (src, GST_HTTPSRC_OPEN);
197 }
198
199 static void 
200 gst_httpsrc_set_arg (GtkObject *object, GtkArg *arg, guint id) 
201 {
202   GstHttpSrc *src;
203
204   /* it's not null if we got it, but it might not be ours */
205   g_return_if_fail (GST_IS_HTTPSRC (object));
206   
207   src = GST_HTTPSRC (object);
208
209   switch(id) {
210     case ARG_LOCATION:
211       /* the element must not be playing in order to do this */
212       g_return_if_fail (GST_STATE (src) < GST_STATE_PLAYING);
213
214       if (src->url) g_free (src->url);
215       /* clear the url if we get a NULL (is that possible?) */
216       if (GTK_VALUE_STRING (*arg) == NULL) {
217         gst_element_set_state (GST_ELEMENT (object),GST_STATE_NULL);
218         src->url = NULL;
219       /* otherwise set the new url */
220       } else {
221         src->url = g_strdup (GTK_VALUE_STRING (*arg));
222       }
223       break;
224     case ARG_BYTESPERREAD:
225       src->bytes_per_read = GTK_VALUE_INT (*arg);
226       break;
227     default:
228       break;
229   }
230 }
231
232 static void 
233 gst_httpsrc_get_arg (GtkObject *object, GtkArg *arg, guint id) 
234 {
235   GstHttpSrc *httpsrc;
236
237   /* it's not null if we got it, but it might not be ours */
238   g_return_if_fail (GST_IS_HTTPSRC (object));
239   
240   httpsrc = GST_HTTPSRC (object);
241                           
242   switch (id) {
243     case ARG_LOCATION:
244       GTK_VALUE_STRING (*arg) = httpsrc->url;
245       break;
246     case ARG_BYTESPERREAD:
247       GTK_VALUE_INT (*arg) = httpsrc->bytes_per_read;
248       break;
249     default:
250       arg->type = GTK_TYPE_INVALID;
251       break;
252   }
253 }
254
255 static GstElementStateReturn 
256 gst_httpsrc_change_state (GstElement *element) 
257 {
258   g_return_val_if_fail (GST_IS_HTTPSRC (element), GST_STATE_FAILURE);
259
260   if (GST_STATE_PENDING (element) == GST_STATE_NULL) {
261     if (GST_FLAG_IS_SET (element, GST_HTTPSRC_OPEN))
262       gst_httpsrc_close_url (GST_HTTPSRC (element));
263   } else {
264     if (!GST_FLAG_IS_SET (element, GST_HTTPSRC_OPEN)) {
265       if (!gst_httpsrc_open_url (GST_HTTPSRC (element)))
266         return GST_STATE_FAILURE;
267     }
268   }
269  
270   if (GST_ELEMENT_CLASS (parent_class)->change_state)
271     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
272   
273   return GST_STATE_SUCCESS;
274 }