9d4041b6e200bb2a732dabea1e97944596c9a672
[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 <wim@fluendo.com>
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., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 /**
23  * SECTION:element-fakesrc
24  * @see_also: #GstFakeSink
25  *
26  * The fakesrc element is a multipurpose element that can generate
27  * a wide range of buffers and can operate in various scheduling modes.
28  *
29  * It is mostly used as a testing element, one trivial example for testing
30  * basic <application>GStreamer</application> core functionality is:
31  *
32  * <refsect2>
33  * <title>Example launch line</title>
34  * |[
35  * gst-launch-1.0 -v fakesrc num-buffers=5 ! fakesink
36  * ]| This pipeline will push 5 empty buffers to the fakesink element and then
37  * sends an EOS.
38  * </refsect2>
39  */
40
41 /* FIXME: this ignores basesrc::blocksize property, which could be used as an
42  * alias to ::sizemax (see gst_base_src_get_blocksize()).
43  */
44
45 #ifdef HAVE_CONFIG_H
46 #  include "config.h"
47 #endif
48
49 #include <stdlib.h>
50 #include <string.h>
51
52 #include "gstelements_private.h"
53 #include "gstfakesrc.h"
54
55 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
56     GST_PAD_SRC,
57     GST_PAD_ALWAYS,
58     GST_STATIC_CAPS_ANY);
59
60 GST_DEBUG_CATEGORY_STATIC (gst_fake_src_debug);
61 #define GST_CAT_DEFAULT gst_fake_src_debug
62
63 /* FakeSrc signals and args */
64 enum
65 {
66   /* FILL ME */
67   SIGNAL_HANDOFF,
68   LAST_SIGNAL
69 };
70
71 #define DEFAULT_OUTPUT          FAKE_SRC_FIRST_LAST_LOOP
72 #define DEFAULT_DATA            FAKE_SRC_DATA_ALLOCATE
73 #define DEFAULT_SIZETYPE        FAKE_SRC_SIZETYPE_EMPTY
74 #define DEFAULT_SIZEMIN         0
75 #define DEFAULT_SIZEMAX         4096
76 #define DEFAULT_FILLTYPE        FAKE_SRC_FILLTYPE_ZERO
77 #define DEFAULT_DATARATE        0
78 #define DEFAULT_SYNC            FALSE
79 #define DEFAULT_PATTERN         NULL
80 #define DEFAULT_EOS             FALSE
81 #define DEFAULT_SIGNAL_HANDOFFS FALSE
82 #define DEFAULT_SILENT          TRUE
83 #define DEFAULT_DUMP            FALSE
84 #define DEFAULT_PARENTSIZE      4096*10
85 #define DEFAULT_CAN_ACTIVATE_PULL TRUE
86 #define DEFAULT_CAN_ACTIVATE_PUSH TRUE
87 #define DEFAULT_FORMAT          GST_FORMAT_BYTES
88
89 enum
90 {
91   PROP_0,
92   PROP_OUTPUT,
93   PROP_DATA,
94   PROP_SIZETYPE,
95   PROP_SIZEMIN,
96   PROP_SIZEMAX,
97   PROP_FILLTYPE,
98   PROP_DATARATE,
99   PROP_SYNC,
100   PROP_PATTERN,
101   PROP_EOS,
102   PROP_SIGNAL_HANDOFFS,
103   PROP_SILENT,
104   PROP_DUMP,
105   PROP_PARENTSIZE,
106   PROP_LAST_MESSAGE,
107   PROP_CAN_ACTIVATE_PULL,
108   PROP_CAN_ACTIVATE_PUSH,
109   PROP_IS_LIVE,
110   PROP_FORMAT,
111   PROP_LAST,
112 };
113
114 /* not implemented
115 #define GST_TYPE_FAKE_SRC_OUTPUT (gst_fake_src_output_get_type())
116 static GType
117 gst_fake_src_output_get_type (void)
118 {
119   static GType fakesrc_output_type = 0;
120   static const GEnumValue fakesrc_output[] = {
121     {FAKE_SRC_FIRST_LAST_LOOP, "1", "First-Last loop"},
122     {FAKE_SRC_LAST_FIRST_LOOP, "2", "Last-First loop"},
123     {FAKE_SRC_PING_PONG, "3", "Ping-Pong"},
124     {FAKE_SRC_ORDERED_RANDOM, "4", "Ordered Random"},
125     {FAKE_SRC_RANDOM, "5", "Random"},
126     {FAKE_SRC_PATTERN_LOOP, "6", "Patttern loop"},
127     {FAKE_SRC_PING_PONG_PATTERN, "7", "Ping-Pong Pattern"},
128     {FAKE_SRC_GET_ALWAYS_SUCEEDS, "8", "'_get' Always succeeds"},
129     {0, NULL, NULL},
130   };
131
132   if (!fakesrc_output_type) {
133     fakesrc_output_type =
134         g_enum_register_static ("GstFakeSrcOutputType", fakesrc_output);
135   }
136   return fakesrc_output_type;
137 }
138 */
139
140 #define GST_TYPE_FAKE_SRC_DATA (gst_fake_src_data_get_type())
141 static GType
142 gst_fake_src_data_get_type (void)
143 {
144   static GType fakesrc_data_type = 0;
145   static const GEnumValue fakesrc_data[] = {
146     {FAKE_SRC_DATA_ALLOCATE, "Allocate data", "allocate"},
147     {FAKE_SRC_DATA_SUBBUFFER, "Subbuffer data", "subbuffer"},
148     {0, NULL, NULL},
149   };
150
151   if (!fakesrc_data_type) {
152     fakesrc_data_type =
153         g_enum_register_static ("GstFakeSrcDataType", fakesrc_data);
154   }
155   return fakesrc_data_type;
156 }
157
158 #define GST_TYPE_FAKE_SRC_SIZETYPE (gst_fake_src_sizetype_get_type())
159 static GType
160 gst_fake_src_sizetype_get_type (void)
161 {
162   static GType fakesrc_sizetype_type = 0;
163   static const GEnumValue fakesrc_sizetype[] = {
164     {FAKE_SRC_SIZETYPE_EMPTY, "Send empty buffers", "empty"},
165     {FAKE_SRC_SIZETYPE_FIXED, "Fixed size buffers (sizemax sized)", "fixed"},
166     {FAKE_SRC_SIZETYPE_RANDOM,
167         "Random sized buffers (sizemin <= size <= sizemax)", "random"},
168     {0, NULL, NULL},
169   };
170
171   if (!fakesrc_sizetype_type) {
172     fakesrc_sizetype_type =
173         g_enum_register_static ("GstFakeSrcSizeType", fakesrc_sizetype);
174   }
175   return fakesrc_sizetype_type;
176 }
177
178 #define GST_TYPE_FAKE_SRC_FILLTYPE (gst_fake_src_filltype_get_type())
179 static GType
180 gst_fake_src_filltype_get_type (void)
181 {
182   static GType fakesrc_filltype_type = 0;
183   static const GEnumValue fakesrc_filltype[] = {
184     {FAKE_SRC_FILLTYPE_NOTHING, "Leave data as malloced", "nothing"},
185     {FAKE_SRC_FILLTYPE_ZERO, "Fill buffers with zeros", "zero"},
186     {FAKE_SRC_FILLTYPE_RANDOM, "Fill buffers with random data", "random"},
187     {FAKE_SRC_FILLTYPE_PATTERN, "Fill buffers with pattern 0x00 -> 0xff",
188         "pattern"},
189     {FAKE_SRC_FILLTYPE_PATTERN_CONT,
190           "Fill buffers with pattern 0x00 -> 0xff that spans buffers",
191         "pattern-span"},
192     {0, NULL, NULL},
193   };
194
195   if (!fakesrc_filltype_type) {
196     fakesrc_filltype_type =
197         g_enum_register_static ("GstFakeSrcFillType", fakesrc_filltype);
198   }
199   return fakesrc_filltype_type;
200 }
201
202 #define _do_init \
203     GST_DEBUG_CATEGORY_INIT (gst_fake_src_debug, "fakesrc", 0, "fakesrc element");
204 #define gst_fake_src_parent_class parent_class
205 G_DEFINE_TYPE_WITH_CODE (GstFakeSrc, gst_fake_src, GST_TYPE_BASE_SRC, _do_init);
206
207 static void gst_fake_src_finalize (GObject * object);
208 static void gst_fake_src_set_property (GObject * object, guint prop_id,
209     const GValue * value, GParamSpec * pspec);
210 static void gst_fake_src_get_property (GObject * object, guint prop_id,
211     GValue * value, GParamSpec * pspec);
212
213 static gboolean gst_fake_src_start (GstBaseSrc * basesrc);
214 static gboolean gst_fake_src_stop (GstBaseSrc * basesrc);
215 static gboolean gst_fake_src_is_seekable (GstBaseSrc * basesrc);
216
217 static gboolean gst_fake_src_event_handler (GstBaseSrc * src, GstEvent * event);
218 static void gst_fake_src_get_times (GstBaseSrc * basesrc, GstBuffer * buffer,
219     GstClockTime * start, GstClockTime * end);
220 static GstFlowReturn gst_fake_src_create (GstBaseSrc * src, guint64 offset,
221     guint length, GstBuffer ** buf);
222
223 static guint gst_fake_src_signals[LAST_SIGNAL] = { 0 };
224
225 static GParamSpec *pspec_last_message = NULL;
226
227 static void
228 gst_fake_src_class_init (GstFakeSrcClass * klass)
229 {
230   GObjectClass *gobject_class;
231   GstElementClass *gstelement_class;
232   GstBaseSrcClass *gstbase_src_class;
233
234   gobject_class = G_OBJECT_CLASS (klass);
235   gstelement_class = GST_ELEMENT_CLASS (klass);
236   gstbase_src_class = GST_BASE_SRC_CLASS (klass);
237
238   gobject_class->finalize = gst_fake_src_finalize;
239
240   gobject_class->set_property = gst_fake_src_set_property;
241   gobject_class->get_property = gst_fake_src_get_property;
242
243 /*
244   FIXME: this is not implemented; would make sense once basesrc and fakesrc
245   support multiple pads
246   g_object_class_install_property (gobject_class, PROP_OUTPUT,
247       g_param_spec_enum ("output", "output", "Output method (currently unused)",
248           GST_TYPE_FAKE_SRC_OUTPUT, DEFAULT_OUTPUT, G_PARAM_READWRITE));
249 */
250   g_object_class_install_property (gobject_class, PROP_DATA,
251       g_param_spec_enum ("data", "data", "Data allocation method",
252           GST_TYPE_FAKE_SRC_DATA, DEFAULT_DATA,
253           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
254   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SIZETYPE,
255       g_param_spec_enum ("sizetype", "sizetype",
256           "How to determine buffer sizes", GST_TYPE_FAKE_SRC_SIZETYPE,
257           DEFAULT_SIZETYPE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
258   g_object_class_install_property (gobject_class, PROP_SIZEMIN,
259       g_param_spec_int ("sizemin", "sizemin", "Minimum buffer size", 0,
260           G_MAXINT, DEFAULT_SIZEMIN,
261           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
262   g_object_class_install_property (gobject_class, PROP_SIZEMAX,
263       g_param_spec_int ("sizemax", "sizemax", "Maximum buffer size", 0,
264           G_MAXINT, DEFAULT_SIZEMAX,
265           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
266   g_object_class_install_property (gobject_class, PROP_PARENTSIZE,
267       g_param_spec_int ("parentsize", "parentsize",
268           "Size of parent buffer for sub-buffered allocation", 0, G_MAXINT,
269           DEFAULT_PARENTSIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
270   g_object_class_install_property (gobject_class, PROP_FILLTYPE,
271       g_param_spec_enum ("filltype", "filltype",
272           "How to fill the buffer, if at all", GST_TYPE_FAKE_SRC_FILLTYPE,
273           DEFAULT_FILLTYPE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
274   g_object_class_install_property (gobject_class, PROP_DATARATE,
275       g_param_spec_int ("datarate", "Datarate",
276           "Timestamps buffers with number of bytes per second (0 = none)", 0,
277           G_MAXINT, DEFAULT_DATARATE,
278           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
279   g_object_class_install_property (gobject_class, PROP_SYNC,
280       g_param_spec_boolean ("sync", "Sync", "Sync to the clock to the datarate",
281           DEFAULT_SYNC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
282   /*  FIXME 2.0: Remove unused pattern property. Not implemented */
283   g_object_class_install_property (gobject_class, PROP_PATTERN,
284       g_param_spec_string ("pattern", "pattern", "Set the pattern (unused)",
285           DEFAULT_PATTERN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
286   pspec_last_message = g_param_spec_string ("last-message", "last-message",
287       "The last status message", NULL,
288       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
289   g_object_class_install_property (gobject_class, PROP_LAST_MESSAGE,
290       pspec_last_message);
291   g_object_class_install_property (gobject_class, PROP_SILENT,
292       g_param_spec_boolean ("silent", "Silent",
293           "Don't produce last_message events", DEFAULT_SILENT,
294           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
295   g_object_class_install_property (gobject_class, PROP_SIGNAL_HANDOFFS,
296       g_param_spec_boolean ("signal-handoffs", "Signal handoffs",
297           "Send a signal before pushing the buffer", DEFAULT_SIGNAL_HANDOFFS,
298           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
299   g_object_class_install_property (gobject_class, PROP_DUMP,
300       g_param_spec_boolean ("dump", "Dump", "Dump buffer contents to stdout",
301           DEFAULT_DUMP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
302   g_object_class_install_property (gobject_class, PROP_CAN_ACTIVATE_PUSH,
303       g_param_spec_boolean ("can-activate-push", "Can activate push",
304           "Can activate in push mode", DEFAULT_CAN_ACTIVATE_PUSH,
305           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
306   g_object_class_install_property (gobject_class, PROP_CAN_ACTIVATE_PULL,
307       g_param_spec_boolean ("can-activate-pull", "Can activate pull",
308           "Can activate in pull mode", DEFAULT_CAN_ACTIVATE_PULL,
309           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
310   g_object_class_install_property (gobject_class, PROP_IS_LIVE,
311       g_param_spec_boolean ("is-live", "Is this a live source",
312           "True if the element cannot produce data in PAUSED", FALSE,
313           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
314   /**
315    * GstFakeSrc:format
316    *
317    * Set the format of the newsegment events to produce.
318    */
319   g_object_class_install_property (gobject_class, PROP_FORMAT,
320       g_param_spec_enum ("format", "Format",
321           "The format of the segment events", GST_TYPE_FORMAT,
322           DEFAULT_FORMAT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
323
324   /**
325    * GstFakeSrc::handoff:
326    * @fakesrc: the fakesrc instance
327    * @buffer: the buffer that will be pushed
328    * @pad: the pad that will sent it
329    *
330    * This signal gets emitted before sending the buffer.
331    */
332   gst_fake_src_signals[SIGNAL_HANDOFF] =
333       g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
334       G_STRUCT_OFFSET (GstFakeSrcClass, handoff), NULL, NULL,
335       g_cclosure_marshal_generic, G_TYPE_NONE, 2,
336       GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD);
337
338   gst_element_class_set_static_metadata (gstelement_class,
339       "Fake Source",
340       "Source",
341       "Push empty (no data) buffers around",
342       "Erik Walthinsen <omega@cse.ogi.edu>, " "Wim Taymans <wim@fluendo.com>");
343   gst_element_class_add_static_pad_template (gstelement_class, &srctemplate);
344
345   gstbase_src_class->is_seekable = GST_DEBUG_FUNCPTR (gst_fake_src_is_seekable);
346   gstbase_src_class->start = GST_DEBUG_FUNCPTR (gst_fake_src_start);
347   gstbase_src_class->stop = GST_DEBUG_FUNCPTR (gst_fake_src_stop);
348   gstbase_src_class->event = GST_DEBUG_FUNCPTR (gst_fake_src_event_handler);
349   gstbase_src_class->get_times = GST_DEBUG_FUNCPTR (gst_fake_src_get_times);
350   gstbase_src_class->create = GST_DEBUG_FUNCPTR (gst_fake_src_create);
351 }
352
353 static void
354 gst_fake_src_init (GstFakeSrc * fakesrc)
355 {
356   fakesrc->output = FAKE_SRC_FIRST_LAST_LOOP;
357   fakesrc->silent = DEFAULT_SILENT;
358   fakesrc->signal_handoffs = DEFAULT_SIGNAL_HANDOFFS;
359   fakesrc->dump = DEFAULT_DUMP;
360   fakesrc->pattern_byte = 0x00;
361   fakesrc->data = FAKE_SRC_DATA_ALLOCATE;
362   fakesrc->sizetype = FAKE_SRC_SIZETYPE_EMPTY;
363   fakesrc->filltype = FAKE_SRC_FILLTYPE_NOTHING;
364   fakesrc->sizemin = DEFAULT_SIZEMIN;
365   fakesrc->sizemax = DEFAULT_SIZEMAX;
366   fakesrc->parent = NULL;
367   fakesrc->parentsize = DEFAULT_PARENTSIZE;
368   fakesrc->last_message = NULL;
369   fakesrc->datarate = DEFAULT_DATARATE;
370   fakesrc->sync = DEFAULT_SYNC;
371   fakesrc->format = DEFAULT_FORMAT;
372 }
373
374 static void
375 gst_fake_src_finalize (GObject * object)
376 {
377   GstFakeSrc *src;
378
379   src = GST_FAKE_SRC (object);
380
381   g_free (src->last_message);
382   if (src->parent) {
383     gst_buffer_unref (src->parent);
384     src->parent = NULL;
385   }
386
387   G_OBJECT_CLASS (parent_class)->finalize (object);
388 }
389
390 static gboolean
391 gst_fake_src_event_handler (GstBaseSrc * basesrc, GstEvent * event)
392 {
393   GstFakeSrc *src;
394
395   src = GST_FAKE_SRC (basesrc);
396
397   if (!src->silent) {
398     const GstStructure *s;
399     const gchar *tstr;
400     gchar *sstr;
401
402     GST_OBJECT_LOCK (src);
403     g_free (src->last_message);
404
405     tstr = gst_event_type_get_name (GST_EVENT_TYPE (event));
406
407     if ((s = gst_event_get_structure (event)))
408       sstr = gst_structure_to_string (s);
409     else
410       sstr = g_strdup ("");
411
412     src->last_message =
413         g_strdup_printf ("event   ******* (%s:%s) E (type: %s (%d), %s) %p",
414         GST_DEBUG_PAD_NAME (GST_BASE_SRC_CAST (src)->srcpad),
415         tstr, GST_EVENT_TYPE (event), sstr, event);
416     g_free (sstr);
417     GST_OBJECT_UNLOCK (src);
418
419     g_object_notify_by_pspec ((GObject *) src, pspec_last_message);
420   }
421
422   return GST_BASE_SRC_CLASS (parent_class)->event (basesrc, event);
423 }
424
425 static void
426 gst_fake_src_alloc_parent (GstFakeSrc * src)
427 {
428   GstBuffer *buf;
429
430   buf = gst_buffer_new_allocate (NULL, src->parentsize, NULL);
431
432   src->parent = buf;
433   src->parentoffset = 0;
434 }
435
436 static void
437 gst_fake_src_set_property (GObject * object, guint prop_id,
438     const GValue * value, GParamSpec * pspec)
439 {
440   GstFakeSrc *src;
441   GstBaseSrc *basesrc;
442
443   src = GST_FAKE_SRC (object);
444   basesrc = GST_BASE_SRC (object);
445
446   switch (prop_id) {
447     case PROP_OUTPUT:
448       g_warning ("not yet implemented");
449       break;
450     case PROP_DATA:
451       src->data = (GstFakeSrcDataType) g_value_get_enum (value);
452
453       if (src->data == FAKE_SRC_DATA_SUBBUFFER) {
454         if (!src->parent)
455           gst_fake_src_alloc_parent (src);
456       } else {
457         if (src->parent) {
458           gst_buffer_unref (src->parent);
459           src->parent = NULL;
460         }
461       }
462       break;
463     case PROP_SIZETYPE:
464       src->sizetype = (GstFakeSrcSizeType) g_value_get_enum (value);
465       break;
466     case PROP_SIZEMIN:
467       src->sizemin = g_value_get_int (value);
468       break;
469     case PROP_SIZEMAX:
470       src->sizemax = g_value_get_int (value);
471       break;
472     case PROP_PARENTSIZE:
473       src->parentsize = g_value_get_int (value);
474       break;
475     case PROP_FILLTYPE:
476       src->filltype = (GstFakeSrcFillType) g_value_get_enum (value);
477       break;
478     case PROP_DATARATE:
479       src->datarate = g_value_get_int (value);
480       break;
481     case PROP_SYNC:
482       src->sync = g_value_get_boolean (value);
483       break;
484     case PROP_PATTERN:
485       break;
486     case PROP_SILENT:
487       src->silent = g_value_get_boolean (value);
488       break;
489     case PROP_SIGNAL_HANDOFFS:
490       src->signal_handoffs = g_value_get_boolean (value);
491       break;
492     case PROP_DUMP:
493       src->dump = g_value_get_boolean (value);
494       break;
495     case PROP_CAN_ACTIVATE_PUSH:
496       g_return_if_fail (!GST_OBJECT_FLAG_IS_SET (object,
497               GST_BASE_SRC_FLAG_STARTED));
498       GST_BASE_SRC (src)->can_activate_push = g_value_get_boolean (value);
499       break;
500     case PROP_CAN_ACTIVATE_PULL:
501       g_return_if_fail (!GST_OBJECT_FLAG_IS_SET (object,
502               GST_BASE_SRC_FLAG_STARTED));
503       src->can_activate_pull = g_value_get_boolean (value);
504       break;
505     case PROP_IS_LIVE:
506       gst_base_src_set_live (basesrc, g_value_get_boolean (value));
507       break;
508     case PROP_FORMAT:
509       src->format = (GstFormat) g_value_get_enum (value);
510       break;
511     default:
512       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
513       break;
514   }
515 }
516
517 static void
518 gst_fake_src_get_property (GObject * object, guint prop_id, GValue * value,
519     GParamSpec * pspec)
520 {
521   GstFakeSrc *src;
522   GstBaseSrc *basesrc;
523
524   g_return_if_fail (GST_IS_FAKE_SRC (object));
525
526   src = GST_FAKE_SRC (object);
527   basesrc = GST_BASE_SRC (object);
528
529   switch (prop_id) {
530     case PROP_OUTPUT:
531       g_value_set_enum (value, src->output);
532       break;
533     case PROP_DATA:
534       g_value_set_enum (value, src->data);
535       break;
536     case PROP_SIZETYPE:
537       g_value_set_enum (value, src->sizetype);
538       break;
539     case PROP_SIZEMIN:
540       g_value_set_int (value, src->sizemin);
541       break;
542     case PROP_SIZEMAX:
543       g_value_set_int (value, src->sizemax);
544       break;
545     case PROP_PARENTSIZE:
546       g_value_set_int (value, src->parentsize);
547       break;
548     case PROP_FILLTYPE:
549       g_value_set_enum (value, src->filltype);
550       break;
551     case PROP_DATARATE:
552       g_value_set_int (value, src->datarate);
553       break;
554     case PROP_SYNC:
555       g_value_set_boolean (value, src->sync);
556       break;
557     case PROP_PATTERN:
558       break;
559     case PROP_SILENT:
560       g_value_set_boolean (value, src->silent);
561       break;
562     case PROP_SIGNAL_HANDOFFS:
563       g_value_set_boolean (value, src->signal_handoffs);
564       break;
565     case PROP_DUMP:
566       g_value_set_boolean (value, src->dump);
567       break;
568     case PROP_LAST_MESSAGE:
569       GST_OBJECT_LOCK (src);
570       g_value_set_string (value, src->last_message);
571       GST_OBJECT_UNLOCK (src);
572       break;
573     case PROP_CAN_ACTIVATE_PUSH:
574       g_value_set_boolean (value, GST_BASE_SRC (src)->can_activate_push);
575       break;
576     case PROP_CAN_ACTIVATE_PULL:
577       g_value_set_boolean (value, src->can_activate_pull);
578       break;
579     case PROP_IS_LIVE:
580       g_value_set_boolean (value, gst_base_src_is_live (basesrc));
581       break;
582     case PROP_FORMAT:
583       g_value_set_enum (value, src->format);
584       break;
585     default:
586       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
587       break;
588   }
589 }
590
591 static void
592 gst_fake_src_prepare_buffer (GstFakeSrc * src, guint8 * data, gsize size)
593 {
594   if (size == 0)
595     return;
596
597   switch (src->filltype) {
598     case FAKE_SRC_FILLTYPE_ZERO:
599       memset (data, 0, size);
600       break;
601     case FAKE_SRC_FILLTYPE_RANDOM:
602     {
603       gint i;
604       guint8 *ptr = data;
605
606       for (i = size; i; i--) {
607         *ptr++ = g_random_int_range (0, 256);
608       }
609       break;
610     }
611     case FAKE_SRC_FILLTYPE_PATTERN:
612       src->pattern_byte = 0x00;
613     case FAKE_SRC_FILLTYPE_PATTERN_CONT:
614     {
615       gint i;
616       guint8 *ptr = data;
617
618       for (i = size; i; i--) {
619         *ptr++ = src->pattern_byte++;
620       }
621       break;
622     }
623     case FAKE_SRC_FILLTYPE_NOTHING:
624     default:
625       break;
626   }
627 }
628
629 static GstBuffer *
630 gst_fake_src_alloc_buffer (GstFakeSrc * src, guint size)
631 {
632   GstBuffer *buf;
633   gpointer data;
634   gboolean do_prepare = FALSE;
635
636   buf = gst_buffer_new ();
637
638   if (size != 0) {
639     switch (src->filltype) {
640       case FAKE_SRC_FILLTYPE_NOTHING:
641         data = g_malloc (size);
642         break;
643       case FAKE_SRC_FILLTYPE_ZERO:
644         data = g_malloc0 (size);
645         break;
646       case FAKE_SRC_FILLTYPE_RANDOM:
647       case FAKE_SRC_FILLTYPE_PATTERN:
648       case FAKE_SRC_FILLTYPE_PATTERN_CONT:
649       default:
650         data = g_malloc (size);
651         do_prepare = TRUE;
652         break;
653     }
654     if (do_prepare)
655       gst_fake_src_prepare_buffer (src, data, size);
656
657     gst_buffer_append_memory (buf,
658         gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
659   }
660
661   return buf;
662 }
663
664 static guint
665 gst_fake_src_get_size (GstFakeSrc * src)
666 {
667   guint size;
668
669   switch (src->sizetype) {
670     case FAKE_SRC_SIZETYPE_FIXED:
671       size = src->sizemax;
672       break;
673     case FAKE_SRC_SIZETYPE_RANDOM:
674       size = g_random_int_range (src->sizemin, src->sizemax);
675       break;
676     case FAKE_SRC_SIZETYPE_EMPTY:
677     default:
678       size = 0;
679       break;
680   }
681
682   return size;
683 }
684
685 static GstBuffer *
686 gst_fake_src_create_buffer (GstFakeSrc * src, gsize * bufsize)
687 {
688   GstBuffer *buf;
689   gsize size = gst_fake_src_get_size (src);
690   gboolean dump = src->dump;
691   GstMapInfo info;
692
693   *bufsize = size;
694
695   switch (src->data) {
696     case FAKE_SRC_DATA_ALLOCATE:
697       buf = gst_fake_src_alloc_buffer (src, size);
698       break;
699     case FAKE_SRC_DATA_SUBBUFFER:
700       /* see if we have a parent to subbuffer */
701       if (!src->parent) {
702         gst_fake_src_alloc_parent (src);
703         g_assert (src->parent);
704       }
705       /* see if it's large enough */
706       if ((src->parentsize - src->parentoffset) >= size) {
707         buf =
708             gst_buffer_copy_region (src->parent, GST_BUFFER_COPY_ALL,
709             src->parentoffset, size);
710         src->parentoffset += size;
711       } else {
712         /* the parent is useless now */
713         gst_buffer_unref (src->parent);
714         src->parent = NULL;
715         /* try again (this will allocate a new parent) */
716         return gst_fake_src_create_buffer (src, bufsize);
717       }
718       if (buf == NULL)
719         goto buffer_create_fail;
720       if (!gst_buffer_map (buf, &info, GST_MAP_WRITE))
721         goto buffer_write_fail;
722       gst_fake_src_prepare_buffer (src, info.data, info.size);
723       gst_buffer_unmap (buf, &info);
724       break;
725     default:
726       g_warning ("fakesrc: dunno how to allocate buffers !");
727       buf = gst_buffer_new ();
728       break;
729   }
730   if (dump) {
731     if (gst_buffer_map (buf, &info, GST_MAP_READ)) {
732       gst_util_dump_mem (info.data, info.size);
733       gst_buffer_unmap (buf, &info);
734     }
735   }
736
737   return buf;
738
739 buffer_create_fail:
740   {
741     GST_ELEMENT_ERROR (src, RESOURCE, BUSY, (NULL),
742         ("Failed to create a buffer"));
743     return NULL;
744   }
745
746 buffer_write_fail:
747   {
748     GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL),
749         ("Failed to write to buffer"));
750     gst_buffer_unref (buf);
751     return NULL;
752   }
753 }
754
755 static void
756 gst_fake_src_get_times (GstBaseSrc * basesrc, GstBuffer * buffer,
757     GstClockTime * start, GstClockTime * end)
758 {
759   GstFakeSrc *src;
760
761   src = GST_FAKE_SRC (basesrc);
762
763   /* sync on the timestamp of the buffer if requested. */
764   if (src->sync) {
765     GstClockTime timestamp, duration;
766
767     /* first sync on DTS, else use PTS */
768     timestamp = GST_BUFFER_DTS (buffer);
769     if (!GST_CLOCK_TIME_IS_VALID (timestamp))
770       timestamp = GST_BUFFER_PTS (buffer);
771
772     if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
773       /* get duration to calculate end time */
774       duration = GST_BUFFER_DURATION (buffer);
775       if (GST_CLOCK_TIME_IS_VALID (duration)) {
776         *end = timestamp + duration;
777       }
778       *start = timestamp;
779     }
780   } else {
781     *start = -1;
782     *end = -1;
783   }
784 }
785
786 static GstFlowReturn
787 gst_fake_src_create (GstBaseSrc * basesrc, guint64 offset, guint length,
788     GstBuffer ** ret)
789 {
790   GstFakeSrc *src;
791   GstBuffer *buf;
792   GstClockTime time;
793   gsize size;
794
795   src = GST_FAKE_SRC (basesrc);
796
797   buf = gst_fake_src_create_buffer (src, &size);
798   GST_BUFFER_OFFSET (buf) = offset;
799
800   if (src->datarate > 0) {
801     time = (src->bytes_sent * GST_SECOND) / src->datarate;
802
803     GST_BUFFER_DURATION (buf) = size * GST_SECOND / src->datarate;
804   } else if (gst_base_src_is_live (basesrc)) {
805     GstClock *clock;
806
807     clock = gst_element_get_clock (GST_ELEMENT (src));
808
809     if (clock) {
810       time = gst_clock_get_time (clock);
811       time -= gst_element_get_base_time (GST_ELEMENT (src));
812       gst_object_unref (clock);
813     } else {
814       /* not an error not to have a clock */
815       time = GST_CLOCK_TIME_NONE;
816     }
817   } else {
818     time = GST_CLOCK_TIME_NONE;
819   }
820
821   GST_BUFFER_DTS (buf) = time;
822   GST_BUFFER_PTS (buf) = time;
823
824   if (!src->silent) {
825     gchar dts_str[64], pts_str[64], dur_str[64];
826     gchar *flag_str;
827
828     GST_OBJECT_LOCK (src);
829     g_free (src->last_message);
830
831     if (GST_BUFFER_DTS (buf) != GST_CLOCK_TIME_NONE) {
832       g_snprintf (dts_str, sizeof (dts_str), "%" GST_TIME_FORMAT,
833           GST_TIME_ARGS (GST_BUFFER_DTS (buf)));
834     } else {
835       g_strlcpy (dts_str, "none", sizeof (dts_str));
836     }
837     if (GST_BUFFER_PTS (buf) != GST_CLOCK_TIME_NONE) {
838       g_snprintf (pts_str, sizeof (pts_str), "%" GST_TIME_FORMAT,
839           GST_TIME_ARGS (GST_BUFFER_PTS (buf)));
840     } else {
841       g_strlcpy (pts_str, "none", sizeof (pts_str));
842     }
843     if (GST_BUFFER_DURATION (buf) != GST_CLOCK_TIME_NONE) {
844       g_snprintf (dur_str, sizeof (dur_str), "%" GST_TIME_FORMAT,
845           GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
846     } else {
847       g_strlcpy (dur_str, "none", sizeof (dur_str));
848     }
849
850     flag_str = gst_buffer_get_flags_string (buf);
851     src->last_message =
852         g_strdup_printf ("create   ******* (%s:%s) (%u bytes, dts: %s, pts:%s"
853         ", duration: %s, offset: %" G_GINT64_FORMAT ", offset_end: %"
854         G_GINT64_FORMAT ", flags: %08x %s) %p",
855         GST_DEBUG_PAD_NAME (GST_BASE_SRC_CAST (src)->srcpad), (guint) size,
856         dts_str, pts_str, dur_str, GST_BUFFER_OFFSET (buf),
857         GST_BUFFER_OFFSET_END (buf), GST_MINI_OBJECT_CAST (buf)->flags,
858         flag_str, buf);
859     g_free (flag_str);
860     GST_OBJECT_UNLOCK (src);
861
862     g_object_notify_by_pspec ((GObject *) src, pspec_last_message);
863   }
864
865   if (src->signal_handoffs) {
866     GST_LOG_OBJECT (src, "pre handoff emit");
867     g_signal_emit (src, gst_fake_src_signals[SIGNAL_HANDOFF], 0, buf,
868         basesrc->srcpad);
869     GST_LOG_OBJECT (src, "post handoff emit");
870   }
871
872   src->bytes_sent += size;
873
874   *ret = buf;
875   return GST_FLOW_OK;
876 }
877
878 static gboolean
879 gst_fake_src_start (GstBaseSrc * basesrc)
880 {
881   GstFakeSrc *src;
882
883   src = GST_FAKE_SRC (basesrc);
884
885   src->pattern_byte = 0x00;
886   src->bytes_sent = 0;
887
888   gst_base_src_set_format (basesrc, src->format);
889
890   return TRUE;
891 }
892
893 static gboolean
894 gst_fake_src_stop (GstBaseSrc * basesrc)
895 {
896   GstFakeSrc *src;
897
898   src = GST_FAKE_SRC (basesrc);
899
900   GST_OBJECT_LOCK (src);
901   if (src->parent) {
902     gst_buffer_unref (src->parent);
903     src->parent = NULL;
904   }
905   g_free (src->last_message);
906   src->last_message = NULL;
907   GST_OBJECT_UNLOCK (src);
908
909   return TRUE;
910 }
911
912 static gboolean
913 gst_fake_src_is_seekable (GstBaseSrc * basesrc)
914 {
915   GstFakeSrc *src = GST_FAKE_SRC (basesrc);
916
917   return src->can_activate_pull;
918 }