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