Small cleanups
[platform/upstream/gstreamer.git] / gst / 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 <stdlib.h>
25 #include <string.h>
26
27 #include <gstfakesrc.h>
28
29
30 GstElementDetails gst_fakesrc_details = {
31   "Fake Source",
32   "Source",
33   "Push empty (no data) buffers around",
34   VERSION,
35   "Erik Walthinsen <omega@cse.ogi.edu>\n"
36   "Wim Taymans <wim.taymans@chello.be>",
37   "(C) 1999",
38 };
39
40
41 /* FakeSrc signals and args */
42 enum {
43   /* FILL ME */
44   SIGNAL_HANDOFF,
45   LAST_SIGNAL
46 };
47
48 enum {
49   ARG_0,
50   ARG_NUM_SOURCES,
51   ARG_LOOP_BASED,
52   ARG_OUTPUT,
53   ARG_DATA,
54   ARG_SIZETYPE,
55   ARG_SIZEMIN,
56   ARG_SIZEMAX,
57   ARG_FILLTYPE,
58   ARG_PATTERN,
59   ARG_NUM_BUFFERS,
60   ARG_EOS,
61   ARG_SILENT,
62   ARG_DUMP,
63   ARG_PARENTSIZE,
64   ARG_LAST_MESSAGE,
65 };
66
67 GST_PAD_TEMPLATE_FACTORY (fakesrc_src_factory,
68   "src%d",
69   GST_PAD_SRC,
70   GST_PAD_REQUEST,
71   NULL                  /* no caps */
72 );
73
74 #define GST_TYPE_FAKESRC_OUTPUT (gst_fakesrc_output_get_type())
75 static GType
76 gst_fakesrc_output_get_type (void) 
77 {
78   static GType fakesrc_output_type = 0;
79   static GEnumValue fakesrc_output[] = {
80     { FAKESRC_FIRST_LAST_LOOP,          "1", "First-Last loop"},
81     { FAKESRC_LAST_FIRST_LOOP,          "2", "Last-First loop"},
82     { FAKESRC_PING_PONG,                "3", "Ping-Pong"},
83     { FAKESRC_ORDERED_RANDOM,           "4", "Ordered Random"},
84     { FAKESRC_RANDOM,                   "5", "Random"},
85     { FAKESRC_PATTERN_LOOP,             "6", "Patttern loop"},
86     { FAKESRC_PING_PONG_PATTERN,        "7", "Ping-Pong Pattern"},
87     { FAKESRC_GET_ALWAYS_SUCEEDS,       "8", "'_get' Always succeeds"},
88     {0, NULL, NULL},
89   };
90   if (!fakesrc_output_type) {
91     fakesrc_output_type = g_enum_register_static ("GstFakeSrcOutput", fakesrc_output);
92   }
93   return fakesrc_output_type;
94 }
95
96 #define GST_TYPE_FAKESRC_DATA (gst_fakesrc_data_get_type())
97 static GType
98 gst_fakesrc_data_get_type (void) 
99 {
100   static GType fakesrc_data_type = 0;
101   static GEnumValue fakesrc_data[] = {
102     { FAKESRC_DATA_ALLOCATE,            "2", "Allocate data"},
103     { FAKESRC_DATA_SUBBUFFER,           "3", "Subbuffer data"},
104     {0, NULL, NULL},
105   };
106   if (!fakesrc_data_type) {
107     fakesrc_data_type = g_enum_register_static ("GstFakeSrcData", fakesrc_data);
108   }
109   return fakesrc_data_type;
110 }
111
112 #define GST_TYPE_FAKESRC_SIZETYPE (gst_fakesrc_sizetype_get_type())
113 static GType
114 gst_fakesrc_sizetype_get_type (void) 
115 {
116   static GType fakesrc_sizetype_type = 0;
117   static GEnumValue fakesrc_sizetype[] = {
118     { FAKESRC_SIZETYPE_NULL,            "1", "Send empty buffers"},
119     { FAKESRC_SIZETYPE_FIXED,           "2", "Fixed size buffers (sizemax sized)"},
120     { FAKESRC_SIZETYPE_RANDOM,          "3", "Random sized buffers (sizemin <= size <= sizemax)"},
121     {0, NULL, NULL},
122   };
123   if (!fakesrc_sizetype_type) {
124     fakesrc_sizetype_type = g_enum_register_static ("GstFakeSrcSizeType", fakesrc_sizetype);
125   }
126   return fakesrc_sizetype_type;
127 }
128
129 #define GST_TYPE_FAKESRC_FILLTYPE (gst_fakesrc_filltype_get_type())
130 static GType
131 gst_fakesrc_filltype_get_type (void) 
132 {
133   static GType fakesrc_filltype_type = 0;
134   static GEnumValue fakesrc_filltype[] = {
135     { FAKESRC_FILLTYPE_NOTHING,         "1", "Leave data as malloced"},
136     { FAKESRC_FILLTYPE_NULL,            "2", "Fill buffers with zeros"},
137     { FAKESRC_FILLTYPE_RANDOM,          "3", "Fill buffers with random crap"},
138     { FAKESRC_FILLTYPE_PATTERN,         "4", "Fill buffers with pattern 0x00 -> 0xff"},
139     { FAKESRC_FILLTYPE_PATTERN_CONT,    "5", "Fill buffers with pattern 0x00 -> 0xff that spans buffers"},
140     {0, NULL, NULL},
141   };
142   if (!fakesrc_filltype_type) {
143     fakesrc_filltype_type = g_enum_register_static ("GstFakeSrcFillType", fakesrc_filltype);
144   }
145   return fakesrc_filltype_type;
146 }
147
148 static void             gst_fakesrc_class_init          (GstFakeSrcClass *klass);
149 static void             gst_fakesrc_init                (GstFakeSrc *fakesrc);
150
151 static GstPad*          gst_fakesrc_request_new_pad     (GstElement *element, GstPadTemplate *templ);
152 static void             gst_fakesrc_update_functions    (GstFakeSrc *src);
153 static void             gst_fakesrc_set_property        (GObject *object, guint prop_id, 
154                                                          const GValue *value, GParamSpec *pspec);
155 static void             gst_fakesrc_get_property        (GObject *object, guint prop_id, 
156                                                          GValue *value, GParamSpec *pspec);
157
158 static GstElementStateReturn gst_fakesrc_change_state   (GstElement *element);
159
160 static GstBuffer*       gst_fakesrc_get                 (GstPad *pad);
161 static void             gst_fakesrc_loop                (GstElement *element);
162
163 static GstElementClass *parent_class = NULL;
164 static guint gst_fakesrc_signals[LAST_SIGNAL] = { 0 };
165
166 GType
167 gst_fakesrc_get_type (void) 
168 {
169   static GType fakesrc_type = 0;
170
171   if (!fakesrc_type) {
172     static const GTypeInfo fakesrc_info = {
173       sizeof(GstFakeSrcClass),
174       NULL,
175       NULL,
176       (GClassInitFunc)gst_fakesrc_class_init,
177       NULL,
178       NULL,
179       sizeof(GstFakeSrc),
180       0,
181       (GInstanceInitFunc)gst_fakesrc_init,
182     };
183     fakesrc_type = g_type_register_static (GST_TYPE_ELEMENT, "GstFakeSrc", &fakesrc_info, 0);
184   }
185   return fakesrc_type;
186 }
187
188 static void
189 gst_fakesrc_class_init (GstFakeSrcClass *klass) 
190 {
191   GObjectClass *gobject_class;
192   GstElementClass *gstelement_class;
193
194   gobject_class = (GObjectClass*)klass;
195   gstelement_class = (GstElementClass*)klass;
196
197   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
198
199   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SOURCES,
200     g_param_spec_int ("num_sources", "num_sources", "num_sources",
201                       1, G_MAXINT, 1, G_PARAM_READABLE));
202   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_LOOP_BASED,
203     g_param_spec_boolean("loop_based","loop_based","loop_based",
204                          FALSE, G_PARAM_READWRITE)); /* CHECKME */
205   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_OUTPUT,
206     g_param_spec_enum("output","output","output",
207                       GST_TYPE_FAKESRC_OUTPUT,FAKESRC_FIRST_LAST_LOOP,G_PARAM_READWRITE)); /* CHECKME! */
208   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DATA,
209     g_param_spec_enum ("data", "data", "data",
210                        GST_TYPE_FAKESRC_DATA, FAKESRC_DATA_ALLOCATE, G_PARAM_READWRITE)); 
211   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIZETYPE,
212     g_param_spec_enum ("sizetype", "sizetype", "sizetype",
213                        GST_TYPE_FAKESRC_SIZETYPE, FAKESRC_SIZETYPE_NULL, G_PARAM_READWRITE)); 
214   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIZEMIN,
215     g_param_spec_int ("sizemin","sizemin","sizemin",
216                       0, G_MAXINT, 0, G_PARAM_READWRITE)); 
217   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIZEMAX,
218     g_param_spec_int ("sizemax","sizemax","sizemax",
219                       0, G_MAXINT, 4096, G_PARAM_READWRITE)); 
220   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PARENTSIZE,
221     g_param_spec_int ("parentsize","parentsize","parentsize",
222                       0, G_MAXINT, 4096 * 10, G_PARAM_READWRITE)); 
223   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FILLTYPE,
224     g_param_spec_enum ("filltype", "filltype", "filltype",
225                        GST_TYPE_FAKESRC_FILLTYPE, FAKESRC_FILLTYPE_NULL, G_PARAM_READWRITE)); 
226   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_PATTERN,
227     g_param_spec_string("pattern","pattern","pattern",
228                         NULL, G_PARAM_READWRITE)); /* CHECKME */
229   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NUM_BUFFERS,
230     g_param_spec_int("num_buffers","num_buffers","num_buffers",
231                      G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); /* CHECKME */
232   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_EOS,
233     g_param_spec_boolean("eos","eos","eos",
234                          TRUE,G_PARAM_READWRITE)); /* CHECKME */
235   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
236     g_param_spec_string ("last_message", "last_message", "last_message",
237                          NULL, G_PARAM_READABLE)); 
238
239   gst_element_class_install_std_props (
240           GST_ELEMENT_CLASS (klass),
241           "silent", ARG_SILENT, G_PARAM_READWRITE,
242           "dump",   ARG_DUMP,   G_PARAM_READWRITE,
243           NULL);
244
245   gst_fakesrc_signals[SIGNAL_HANDOFF] =
246     g_signal_new ("handoff", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
247                   G_STRUCT_OFFSET (GstFakeSrcClass, handoff), NULL, NULL,
248                   g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
249                   G_TYPE_POINTER);
250
251   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesrc_set_property);
252   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesrc_get_property);
253
254   gstelement_class->request_new_pad =   GST_DEBUG_FUNCPTR (gst_fakesrc_request_new_pad);
255   gstelement_class->change_state =      GST_DEBUG_FUNCPTR (gst_fakesrc_change_state);
256 }
257
258 static void 
259 gst_fakesrc_init (GstFakeSrc *fakesrc) 
260 {
261   GstPad *pad;
262
263   /* create our first output pad */
264   pad = gst_pad_new ("src", GST_PAD_SRC);
265   gst_element_add_pad (GST_ELEMENT (fakesrc), pad);
266
267   fakesrc->loop_based = FALSE;
268   gst_fakesrc_update_functions (fakesrc);
269
270   fakesrc->output = FAKESRC_FIRST_LAST_LOOP;
271   fakesrc->num_buffers = -1;
272   fakesrc->rt_num_buffers = -1;
273   fakesrc->buffer_count = 0;
274   fakesrc->silent = FALSE;
275   fakesrc->dump = FALSE;
276   fakesrc->pattern_byte = 0x00;
277   fakesrc->need_flush = FALSE;
278   fakesrc->data = FAKESRC_DATA_ALLOCATE;
279   fakesrc->sizetype = FAKESRC_SIZETYPE_NULL;
280   fakesrc->filltype = FAKESRC_FILLTYPE_NOTHING;
281   fakesrc->sizemin = 0;
282   fakesrc->sizemax = 4096;
283   fakesrc->parent = NULL;
284   fakesrc->parentsize = 4096 * 10;
285   fakesrc->last_message = NULL;
286 }
287
288 static GstPad*
289 gst_fakesrc_request_new_pad (GstElement *element, GstPadTemplate *templ)
290 {
291   gchar *name;
292   GstPad *srcpad;
293   GstFakeSrc *fakesrc;
294
295   g_return_val_if_fail (GST_IS_FAKESRC (element), NULL);
296
297   if (templ->direction != GST_PAD_SRC) {
298     g_warning ("gstfakesrc: request new pad that is not a SRC pad\n");
299     return NULL;
300   }
301
302   fakesrc = GST_FAKESRC (element);
303
304   name = g_strdup_printf ("src%d", GST_ELEMENT (fakesrc)->numsrcpads);
305
306   srcpad = gst_pad_new_from_template (templ, name);
307   gst_element_add_pad (GST_ELEMENT (fakesrc), srcpad);
308
309   g_free (name);
310
311   return srcpad;
312 }
313
314 static gboolean
315 gst_fakesrc_event_handler (GstPad *pad, GstEvent *event)
316 {
317   GstFakeSrc *src;
318
319   src = GST_FAKESRC (gst_pad_get_parent (pad));
320
321   switch (GST_EVENT_TYPE (event)) {
322     case GST_EVENT_SEEK:
323       src->buffer_count = GST_EVENT_SEEK_OFFSET (event);
324
325       if (!GST_EVENT_SEEK_FLUSH (event)) {
326         gst_event_free (event);
327         break;
328       }
329       /* else we do a flush too */
330     case GST_EVENT_FLUSH:
331       src->need_flush = TRUE;
332       break;
333     default:
334       break;
335   }
336
337   return TRUE;
338 }
339
340 static void
341 gst_fakesrc_update_functions (GstFakeSrc *src)
342 {
343   GList *pads;
344
345   if (src->loop_based) {
346     gst_element_set_loop_function (GST_ELEMENT (src), GST_DEBUG_FUNCPTR (gst_fakesrc_loop));
347   }
348   else {
349     gst_element_set_loop_function (GST_ELEMENT (src), NULL);
350   }
351
352   pads = GST_ELEMENT (src)->pads;
353   while (pads) {
354     GstPad *pad = GST_PAD (pads->data);
355
356     if (src->loop_based) {
357       gst_pad_set_get_function (pad, NULL);
358     }
359     else {
360       gst_pad_set_get_function (pad, GST_DEBUG_FUNCPTR (gst_fakesrc_get));
361     }
362
363     gst_pad_set_event_function (pad, gst_fakesrc_event_handler);
364     pads = g_list_next (pads);
365   }
366 }
367
368 static void
369 gst_fakesrc_alloc_parent (GstFakeSrc *src)
370 {
371   GstBuffer *buf;
372
373   buf = gst_buffer_new ();
374   GST_BUFFER_DATA (buf) = g_malloc (src->parentsize);
375   GST_BUFFER_SIZE (buf) = src->parentsize;
376
377   src->parent = buf;
378   src->parentoffset = 0;
379 }
380
381 static void
382 gst_fakesrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
383 {
384   GstFakeSrc *src;
385
386   /* it's not null if we got it, but it might not be ours */
387   src = GST_FAKESRC (object);
388    
389   switch (prop_id) {
390     case ARG_LOOP_BASED:
391       src->loop_based = g_value_get_boolean (value);
392       gst_fakesrc_update_functions (src);
393       break;
394     case ARG_OUTPUT:
395       g_warning ("not yet implemented");
396       break;
397     case ARG_DATA:
398       src->data = g_value_get_enum (value);
399       switch (src->data) {
400         case FAKESRC_DATA_ALLOCATE:
401           if (src->parent) {
402             gst_buffer_unref (src->parent);
403             src->parent = NULL;
404           }
405           break;
406         case FAKESRC_DATA_SUBBUFFER:
407           if (!src->parent)
408             gst_fakesrc_alloc_parent (src);
409         default:
410           break;
411       }
412       break;
413     case ARG_SIZETYPE:
414       src->sizetype = g_value_get_enum (value);
415       break;
416     case ARG_SIZEMIN:
417       src->sizemin = g_value_get_int (value);
418       break;
419     case ARG_SIZEMAX:
420       src->sizemax = g_value_get_int (value);
421       break;
422     case ARG_PARENTSIZE:
423       src->parentsize = g_value_get_int (value);
424       break;
425     case ARG_FILLTYPE:
426       src->filltype = g_value_get_enum (value);
427       break;
428     case ARG_PATTERN:
429       break;
430     case ARG_NUM_BUFFERS:
431       src->num_buffers = g_value_get_int (value);
432       break;
433     case ARG_EOS:
434       src->eos = g_value_get_boolean (value);
435       GST_INFO (0, "will EOS on next buffer");
436       break;
437     case ARG_SILENT:
438       src->silent = g_value_get_boolean (value);
439       break;
440     case ARG_DUMP:
441       src->dump = g_value_get_boolean (value);
442       break;
443     default:
444       break;
445   }
446 }
447
448 static void 
449 gst_fakesrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
450 {
451   GstFakeSrc *src;
452    
453   /* it's not null if we got it, but it might not be ours */
454   g_return_if_fail (GST_IS_FAKESRC (object));
455   
456   src = GST_FAKESRC (object);
457    
458   switch (prop_id) {
459     case ARG_NUM_SOURCES:
460       g_value_set_int (value, GST_ELEMENT (src)->numsrcpads);
461       break;
462     case ARG_LOOP_BASED:
463       g_value_set_boolean (value, src->loop_based);
464       break;
465     case ARG_OUTPUT:
466       g_value_set_enum (value, src->output);
467       break;
468     case ARG_DATA:
469       g_value_set_enum (value, src->data);
470       break;
471     case ARG_SIZETYPE:
472       g_value_set_enum (value, src->sizetype);
473       break;
474     case ARG_SIZEMIN:
475       g_value_set_int (value, src->sizemin);
476       break;
477     case ARG_SIZEMAX:
478       g_value_set_int (value, src->sizemax);
479       break;
480     case ARG_PARENTSIZE:
481       g_value_set_int (value, src->parentsize);
482       break;
483     case ARG_FILLTYPE:
484       g_value_set_enum (value, src->filltype);
485       break;
486     case ARG_PATTERN:
487       g_value_set_string (value, src->pattern);
488       break;
489     case ARG_NUM_BUFFERS:
490       g_value_set_int (value, src->num_buffers);
491       break;
492     case ARG_EOS:
493       g_value_set_boolean (value, src->eos);
494       break;
495     case ARG_SILENT:
496       g_value_set_boolean (value, src->silent);
497       break;
498     case ARG_DUMP:
499       g_value_set_boolean (value, src->dump);
500       break;
501     case ARG_LAST_MESSAGE:
502       g_value_set_string (value, src->last_message);
503       break;
504     default:
505       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
506       break;
507   }
508 }
509
510 static void
511 gst_fakesrc_prepare_buffer (GstFakeSrc *src, GstBuffer *buf)
512 {
513   if (GST_BUFFER_SIZE (buf) == 0) 
514     return;
515
516   switch (src->filltype) {
517     case FAKESRC_FILLTYPE_NULL:
518       memset (GST_BUFFER_DATA (buf), 0, GST_BUFFER_SIZE (buf));
519       break;
520     case FAKESRC_FILLTYPE_RANDOM:
521     {
522       gint i;
523       guint8 *ptr = GST_BUFFER_DATA (buf);
524
525       for (i = GST_BUFFER_SIZE (buf); i; i--) {
526         *ptr++ = (gint8)((255.0)*rand()/(RAND_MAX));
527       }
528       break;
529     }
530     case FAKESRC_FILLTYPE_PATTERN:
531       src->pattern_byte = 0x00;
532     case FAKESRC_FILLTYPE_PATTERN_CONT:
533     {
534       gint i;
535       guint8 *ptr = GST_BUFFER_DATA (buf);
536
537       for (i = GST_BUFFER_SIZE (buf); i; i--) {
538         *ptr++ = src->pattern_byte++;
539       }
540       break;
541     }
542     case FAKESRC_FILLTYPE_NOTHING:
543     default:
544       break;
545   }
546 }
547
548 static GstBuffer*
549 gst_fakesrc_alloc_buffer (GstFakeSrc *src, guint size)
550 {
551   GstBuffer *buf;
552
553   buf = gst_buffer_new ();
554   GST_BUFFER_SIZE(buf) = size;
555
556   if (size != 0) { 
557     switch (src->filltype) {
558       case FAKESRC_FILLTYPE_NOTHING:
559         GST_BUFFER_DATA(buf) = g_malloc (size);
560         break;
561       case FAKESRC_FILLTYPE_NULL:
562         GST_BUFFER_DATA(buf) = g_malloc0 (size);
563         break;
564       case FAKESRC_FILLTYPE_RANDOM:
565       case FAKESRC_FILLTYPE_PATTERN:
566       case FAKESRC_FILLTYPE_PATTERN_CONT:
567       default:
568         GST_BUFFER_DATA(buf) = g_malloc (size);
569         gst_fakesrc_prepare_buffer (src, buf);
570         break;
571     }
572   }
573
574   return buf;
575 }
576
577 static guint
578 gst_fakesrc_get_size (GstFakeSrc *src)
579 {
580   guint size;
581
582   switch (src->sizetype) {
583     case FAKESRC_SIZETYPE_FIXED:
584       size = src->sizemax;
585       break;
586     case FAKESRC_SIZETYPE_RANDOM:
587       size = src->sizemin + (guint8)(((gfloat)src->sizemax)*rand()/(RAND_MAX + (gfloat)src->sizemin));
588       break;
589     case FAKESRC_SIZETYPE_NULL:
590     default:
591       size = 0; 
592       break;
593   }
594
595   return size;
596 }
597
598 static GstBuffer *
599 gst_fakesrc_create_buffer (GstFakeSrc *src)
600 {
601   GstBuffer *buf;
602   guint size;
603   gboolean dump = src->dump;
604
605   size = gst_fakesrc_get_size (src);
606   if (size == 0)
607     return gst_buffer_new();
608
609   switch (src->data) {
610     case FAKESRC_DATA_ALLOCATE:
611       buf = gst_fakesrc_alloc_buffer (src, size);
612       break;
613     case FAKESRC_DATA_SUBBUFFER:
614       /* see if we have a parent to subbuffer */
615       if (!src->parent) {
616         gst_fakesrc_alloc_parent (src);
617         g_assert (src->parent);
618       }
619       /* see if it's large enough */
620       if ((GST_BUFFER_SIZE (src->parent) - src->parentoffset) >= size) {
621          buf = gst_buffer_create_sub (src->parent, src->parentoffset, size);
622          src->parentoffset += size;
623       }
624       else {
625         /* the parent is useless now */
626         gst_buffer_unref (src->parent);
627         src->parent = NULL;
628         /* try again (this will allocate a new parent) */
629         return gst_fakesrc_create_buffer (src);
630       }
631       gst_fakesrc_prepare_buffer (src, buf);
632       break;
633     default:
634       g_warning ("fakesrc: dunno how to allocate buffers !");
635       buf = gst_buffer_new();
636       break;
637   }
638   if (dump) {
639     gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
640   }
641
642   return buf;
643 }
644
645 static GstBuffer *
646 gst_fakesrc_get(GstPad *pad)
647 {
648   GstFakeSrc *src;
649   GstBuffer *buf;
650
651   g_return_val_if_fail (pad != NULL, NULL);
652
653   src = GST_FAKESRC (gst_pad_get_parent (pad));
654
655   g_return_val_if_fail (GST_IS_FAKESRC (src), NULL);
656
657   if (src->need_flush) {
658     src->need_flush = FALSE;
659     return GST_BUFFER(gst_event_new (GST_EVENT_FLUSH));
660   }
661
662   if (src->rt_num_buffers == 0) {
663     gst_element_set_eos (GST_ELEMENT (src));
664     return GST_BUFFER(gst_event_new (GST_EVENT_EOS));
665   }
666   else {
667     if (src->rt_num_buffers > 0)
668       src->rt_num_buffers--;
669   }
670
671   if (src->eos) {
672     GST_INFO (0, "fakesrc is setting eos on pad");
673     return GST_BUFFER(gst_event_new (GST_EVENT_EOS));
674   }
675
676   buf = gst_fakesrc_create_buffer (src);
677   GST_BUFFER_TIMESTAMP (buf) = src->buffer_count++;
678
679   if (!src->silent) {
680     if (src->last_message)
681       g_free (src->last_message);
682
683     src->last_message = g_strdup_printf ("get      ******* (%s:%s)> (%d bytes, %llu)",
684                       GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
685
686     g_object_notify (G_OBJECT (src), "last_message");
687   }
688
689   GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, src, "pre handoff emit\n");
690   g_signal_emit (G_OBJECT (src), gst_fakesrc_signals[SIGNAL_HANDOFF], 0,
691                    buf, pad);
692   GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, src, "post handoff emit\n");
693
694   return buf;
695 }
696
697 /**
698  * gst_fakesrc_loop:
699  * @element: the faksesrc to loop
700  * 
701  * generate an empty buffer and push it to the next element.
702  */
703 static void
704 gst_fakesrc_loop(GstElement *element)
705 {
706   GstFakeSrc *src;
707   GList *pads;
708
709   g_return_if_fail(element != NULL);
710   g_return_if_fail(GST_IS_FAKESRC(element));
711
712   src = GST_FAKESRC (element);
713
714   pads = gst_element_get_pad_list (element);
715
716   while (pads) {
717     GstPad *pad = GST_PAD (pads->data);
718     GstBuffer *buf;
719
720     if (src->rt_num_buffers == 0) {
721       src->eos = TRUE;
722     }
723     else {
724       if (src->rt_num_buffers > 0)
725         src->rt_num_buffers--;
726     }
727
728     if (src->eos) {
729       gst_pad_push(pad, GST_BUFFER(gst_event_new (GST_EVENT_EOS)));
730       return;
731     }
732
733     buf = gst_fakesrc_create_buffer (src);
734     GST_BUFFER_TIMESTAMP (buf) = src->buffer_count++;
735
736     if (!src->silent) {
737       if (src->last_message)
738         g_free (src->last_message);
739
740       src->last_message = g_strdup_printf ("fakesrc:  loop    ******* (%s:%s)  > (%d bytes, %llu)",
741                       GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
742
743       g_object_notify (G_OBJECT (src), "last_message");
744     }
745
746     g_signal_emit (G_OBJECT (src), gst_fakesrc_signals[SIGNAL_HANDOFF], 0,
747                        buf, pad);
748     gst_pad_push (pad, buf);
749
750     pads = g_list_next (pads);
751   }
752 }
753
754 static GstElementStateReturn
755 gst_fakesrc_change_state (GstElement *element)
756 {
757   GstFakeSrc *fakesrc;
758
759   g_return_val_if_fail (GST_IS_FAKESRC (element), GST_STATE_FAILURE);
760
761   fakesrc = GST_FAKESRC (element);
762
763   switch (GST_STATE_TRANSITION (element)) {
764     case GST_STATE_PAUSED_TO_READY:
765     case GST_STATE_NULL_TO_READY:
766       fakesrc->buffer_count = 0;
767       fakesrc->pattern_byte = 0x00;
768       fakesrc->need_flush = FALSE;
769       fakesrc->eos = FALSE;
770       fakesrc->rt_num_buffers = fakesrc->num_buffers;
771       if (fakesrc->parent) {
772         gst_buffer_unref (fakesrc->parent);
773         fakesrc->parent = NULL;
774       }
775       break;
776     case GST_STATE_READY_TO_PAUSED:
777     case GST_STATE_PAUSED_TO_PLAYING:
778     case GST_STATE_PLAYING_TO_PAUSED:
779     case GST_STATE_READY_TO_NULL:
780       break;
781     default:
782       g_assert_not_reached ();
783       break;
784   }
785
786   if (GST_ELEMENT_CLASS (parent_class)->change_state)
787     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
788
789   return GST_STATE_SUCCESS;
790 }
791
792 gboolean
793 gst_fakesrc_factory_init (GstElementFactory *factory)
794 {
795   gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (fakesrc_src_factory));
796
797   return TRUE;
798 }
799