3d24cb1fca0123ca1c3e77f3399b23ddf05f6eca
[platform/upstream/gstreamer.git] / plugins / elements / gstfakesrc.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstfakesrc.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
24 #include <gstfakesrc.h>
25
26
27 GstElementDetails gst_fakesrc_details = {
28   "Fake Source",
29   "Source",
30   "Push empty (no data) buffers around",
31   VERSION,
32   "Erik Walthinsen <omega@cse.ogi.edu>\n"
33   "Wim Taymans <wim.taymans@chello.be>"
34   "(C) 1999",
35 };
36
37
38 /* FakeSrc signals and args */
39 enum {
40   /* FILL ME */
41   SIGNAL_HANDOFF,
42   LAST_SIGNAL
43 };
44
45 enum {
46   ARG_0,
47   ARG_NUM_SOURCES,
48   ARG_LOOP_BASED,
49   ARG_OUTPUT,
50   ARG_PATTERN,
51   ARG_NUM_BUFFERS,
52 };
53
54 #define GST_TYPE_FAKESRC_OUTPUT (gst_fakesrc_output_get_type())
55 static GtkType
56 gst_fakesrc_output_get_type(void) {
57   static GtkType fakesrc_output_type = 0;
58   static GtkEnumValue fakesrc_output[] = {
59     { FAKESRC_FIRST_LAST_LOOP,          "1", "First-Last loop"},
60     { FAKESRC_LAST_FIRST_LOOP,          "2", "Last-First loop"},
61     { FAKESRC_PING_PONG,                "3", "Ping-Pong"},
62     { FAKESRC_ORDERED_RANDOM,           "4", "Ordered Random"},
63     { FAKESRC_RANDOM,                   "5", "Random"},
64     { FAKESRC_PATTERN_LOOP,             "6", "Patttern loop"},
65     { FAKESRC_PING_PONG_PATTERN,        "7", "Ping-Pong Pattern"},
66     { FAKESRC_GET_ALWAYS_SUCEEDS,       "8", "'_get' Always succeeds"},
67     {0, NULL, NULL},
68   };
69   if (!fakesrc_output_type) {
70     fakesrc_output_type = gtk_type_register_enum("GstFakeSrcOutput", fakesrc_output);
71   }
72   return fakesrc_output_type;
73 }
74
75 static void             gst_fakesrc_class_init  (GstFakeSrcClass *klass);
76 static void             gst_fakesrc_init        (GstFakeSrc *fakesrc);
77
78 static void             gst_fakesrc_set_arg     (GtkObject *object, GtkArg *arg, guint id);
79 static void             gst_fakesrc_get_arg     (GtkObject *object, GtkArg *arg, guint id);
80
81 static GstBuffer*       gst_fakesrc_get         (GstPad *pad);
82 static void             gst_fakesrc_loop        (GstElement *element);
83
84 static GstElementClass *parent_class = NULL;
85 static guint gst_fakesrc_signals[LAST_SIGNAL] = { 0 };
86
87 GtkType
88 gst_fakesrc_get_type (void) 
89 {
90   static GtkType fakesrc_type = 0;
91
92   if (!fakesrc_type) {
93     static const GtkTypeInfo fakesrc_info = {
94       "GstFakeSrc",
95       sizeof(GstFakeSrc),
96       sizeof(GstFakeSrcClass),
97       (GtkClassInitFunc)gst_fakesrc_class_init,
98       (GtkObjectInitFunc)gst_fakesrc_init,
99       (GtkArgSetFunc)NULL,
100       (GtkArgGetFunc)NULL,
101       (GtkClassInitFunc)NULL,
102     };
103     fakesrc_type = gtk_type_unique (GST_TYPE_ELEMENT, &fakesrc_info);
104   }
105   return fakesrc_type;
106 }
107
108 static void
109 gst_fakesrc_class_init (GstFakeSrcClass *klass) 
110 {
111   GtkObjectClass *gtkobject_class;
112
113   gtkobject_class = (GtkObjectClass*)klass;
114
115   parent_class = gtk_type_class (GST_TYPE_ELEMENT);
116
117   gtk_object_add_arg_type ("GstFakeSrc::num_sources", GTK_TYPE_INT,
118                            GTK_ARG_READWRITE, ARG_NUM_SOURCES);
119   gtk_object_add_arg_type ("GstFakeSrc::loop_based", GTK_TYPE_BOOL,
120                            GTK_ARG_READWRITE, ARG_LOOP_BASED);
121   gtk_object_add_arg_type ("GstFakeSrc::output", GST_TYPE_FAKESRC_OUTPUT,
122                            GTK_ARG_READWRITE, ARG_OUTPUT);
123   gtk_object_add_arg_type ("GstFakeSrc::pattern", GTK_TYPE_STRING,
124                            GTK_ARG_READWRITE, ARG_PATTERN);
125   gtk_object_add_arg_type ("GstFakeSrc::num_buffers", GTK_TYPE_INT,
126                            GTK_ARG_READWRITE, ARG_NUM_BUFFERS);
127
128   gtkobject_class->set_arg = gst_fakesrc_set_arg;
129   gtkobject_class->get_arg = gst_fakesrc_get_arg;
130
131   gst_fakesrc_signals[SIGNAL_HANDOFF] =
132     gtk_signal_new ("handoff", GTK_RUN_LAST, gtkobject_class->type,
133                     GTK_SIGNAL_OFFSET (GstFakeSrcClass, handoff),
134                     gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0);
135
136   gtk_object_class_add_signals (gtkobject_class, gst_fakesrc_signals,
137                                 LAST_SIGNAL);
138 }
139
140 static void 
141 gst_fakesrc_init (GstFakeSrc *fakesrc) 
142 {
143   GstPad *pad;
144
145   // set the default number of 
146   fakesrc->numsrcpads = 1;
147
148   // create our first output pad
149   pad = gst_pad_new("src",GST_PAD_SRC);
150   gst_element_add_pad(GST_ELEMENT(fakesrc),pad);
151   fakesrc->srcpads = g_slist_append(NULL,pad);
152
153   fakesrc->loop_based = TRUE;
154
155   if (fakesrc->loop_based)
156     gst_element_set_loop_function (GST_ELEMENT (fakesrc), gst_fakesrc_loop);
157   else
158     gst_pad_set_get_function(pad,gst_fakesrc_get);
159
160   fakesrc->num_buffers = -1;
161   // we're ready right away, since we don't have any args...
162 //  gst_element_set_state(GST_ELEMENT(fakesrc),GST_STATE_READY);
163 }
164
165 static void
166 gst_fakesrc_update_functions (GstFakeSrc *src)
167 {
168   GSList *pads;
169
170   pads = src->srcpads;
171   while (pads) {
172     GstPad *pad = GST_PAD (pads->data);
173
174     if (src->loop_based) {
175       gst_element_set_loop_function (GST_ELEMENT (src), gst_fakesrc_loop);
176       gst_pad_set_get_function (pad, NULL);
177     }
178     else {
179       gst_pad_set_get_function (pad, gst_fakesrc_get);
180       gst_element_set_loop_function (GST_ELEMENT (src), NULL);
181     }
182     pads = g_slist_next (pads);
183   }
184 }
185
186 static void
187 gst_fakesrc_set_arg (GtkObject *object, GtkArg *arg, guint id)
188 {
189   GstFakeSrc *src;
190   gint new_numsrcs;
191   GstPad *pad;
192
193   /* it's not null if we got it, but it might not be ours */
194   src = GST_FAKESRC (object);
195    
196   switch(id) {
197     case ARG_NUM_SOURCES:
198       new_numsrcs = GTK_VALUE_INT (*arg);
199       if (new_numsrcs > src->numsrcpads) {
200         while (src->numsrcpads != new_numsrcs) {
201           pad = gst_pad_new(g_strdup_printf("src%d",src->numsrcpads),GST_PAD_SRC);
202           gst_element_add_pad(GST_ELEMENT(src),pad);
203           src->srcpads = g_slist_append(src->srcpads,pad);
204           src->numsrcpads++;
205         }
206         gst_fakesrc_update_functions (src);
207       }
208       break;
209     case ARG_LOOP_BASED:
210       src->loop_based = GTK_VALUE_BOOL (*arg);
211       gst_fakesrc_update_functions (src);
212       break;
213     case ARG_OUTPUT:
214       break;
215     case ARG_PATTERN:
216       break;
217     case ARG_NUM_BUFFERS:
218       src->num_buffers = GTK_VALUE_INT (*arg);
219       break;
220     default:
221       break;
222   }
223 }
224
225 static void 
226 gst_fakesrc_get_arg (GtkObject *object, GtkArg *arg, guint id)
227 {
228   GstFakeSrc *src;
229    
230   /* it's not null if we got it, but it might not be ours */
231   g_return_if_fail (GST_IS_FAKESRC (object));
232   
233   src = GST_FAKESRC (object);
234    
235   switch (id) {
236     case ARG_NUM_SOURCES:
237       GTK_VALUE_INT (*arg) = src->numsrcpads;
238       break;
239     case ARG_LOOP_BASED:
240       GTK_VALUE_BOOL (*arg) = src->loop_based;
241       break;
242     case ARG_OUTPUT:
243       GTK_VALUE_INT (*arg) = src->output;
244       break;
245     case ARG_PATTERN:
246       GTK_VALUE_STRING (*arg) = src->pattern;
247       break;
248     case ARG_NUM_BUFFERS:
249       GTK_VALUE_INT (*arg) = src->num_buffers;
250       break;
251     default:
252       arg->type = GTK_TYPE_INVALID;
253       break;
254   }
255 }
256
257
258 /**
259  * gst_fakesrc_get:
260  * @src: the faksesrc to get
261  * 
262  * generate an empty buffer and return it
263  *
264  * Returns: a new empty buffer
265  */
266 static GstBuffer *
267 gst_fakesrc_get(GstPad *pad)
268 {
269   GstFakeSrc *src;
270   GstBuffer *buf;
271
272   g_return_val_if_fail(pad != NULL, NULL);
273   src = GST_FAKESRC(gst_pad_get_parent(pad));
274   g_return_val_if_fail(GST_IS_FAKESRC(src), NULL);
275
276   if (src->num_buffers == 0) {
277     gst_pad_set_eos (pad);
278     return NULL;
279   }
280   else {
281     if (src->num_buffers > 0)
282       src->num_buffers--;
283   }
284
285   g_print("fakesrc: ******* (%s:%s)> \n",GST_DEBUG_PAD_NAME(pad));
286   buf = gst_buffer_new();
287
288   gtk_signal_emit (GTK_OBJECT (src), gst_fakesrc_signals[SIGNAL_HANDOFF],
289                                   src);
290
291   return buf;
292 }
293
294 /**
295  * gst_fakesrc_loop:
296  * @element: the faksesrc to loop
297  * 
298  * generate an empty buffer and push it to the next element.
299  */
300 static void
301 gst_fakesrc_loop(GstElement *element)
302 {
303   GstFakeSrc *src;
304
305   g_return_if_fail(element != NULL);
306   g_return_if_fail(GST_IS_FAKESRC(element));
307
308   src = GST_FAKESRC (element);
309
310   do {
311     GSList *pads;
312
313     pads = src->srcpads;
314
315     while (pads) {
316       GstPad *pad = GST_PAD (pads->data);
317       GstBuffer *buf;
318
319       if (src->num_buffers == 0) {
320         gst_pad_set_eos (pad);
321         return;
322       }
323       else {
324       if (src->num_buffers > 0)
325          src->num_buffers--;
326       }
327
328       buf = gst_buffer_new();
329       g_print("fakesrc: ******* (%s:%s)> \n",GST_DEBUG_PAD_NAME(pad));
330
331       gtk_signal_emit (GTK_OBJECT (src), gst_fakesrc_signals[SIGNAL_HANDOFF],
332                                   src);
333       gst_pad_push (pad, buf);
334
335       pads = g_slist_next (pads);
336     }
337   } while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element));
338 }