making _set_property warn on unknown properties use GST_TIME_FORMAT for timestamp...
[platform/upstream/gstreamer.git] / gst / elements / gstfakesink.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstfakesink.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 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include "gstfakesink.h"
29 #include <gst/gstmarshal.h>
30
31 GST_DEBUG_CATEGORY_STATIC (gst_fakesink_debug);
32 #define GST_CAT_DEFAULT gst_fakesink_debug
33
34 GstElementDetails gst_fakesink_details = GST_ELEMENT_DETAILS ("Fake Sink",
35     "Sink",
36     "Black hole for data",
37     "Erik Walthinsen <omega@cse.ogi.edu>");
38
39
40 /* FakeSink signals and args */
41 enum
42 {
43   /* FILL ME */
44   SIGNAL_HANDOFF,
45   LAST_SIGNAL
46 };
47
48 enum
49 {
50   ARG_0,
51   ARG_STATE_ERROR,
52   ARG_NUM_SINKS,
53   ARG_SILENT,
54   ARG_DUMP,
55   ARG_SYNC,
56   ARG_SIGNAL_HANDOFFS,
57   ARG_LAST_MESSAGE,
58 };
59
60 GstStaticPadTemplate fakesink_sink_template = GST_STATIC_PAD_TEMPLATE ("sink%d",
61     GST_PAD_SINK,
62     GST_PAD_REQUEST,
63     GST_STATIC_CAPS_ANY);
64
65 #define GST_TYPE_FAKESINK_STATE_ERROR (gst_fakesink_state_error_get_type())
66 static GType
67 gst_fakesink_state_error_get_type (void)
68 {
69   static GType fakesink_state_error_type = 0;
70   static GEnumValue fakesink_state_error[] = {
71     {FAKESINK_STATE_ERROR_NONE, "0", "No state change errors"},
72     {FAKESINK_STATE_ERROR_NULL_READY, "1",
73         "Fail state change from NULL to READY"},
74     {FAKESINK_STATE_ERROR_READY_PAUSED, "2",
75         "Fail state change from READY to PAUSED"},
76     {FAKESINK_STATE_ERROR_PAUSED_PLAYING, "3",
77         "Fail state change from PAUSED to PLAYING"},
78     {FAKESINK_STATE_ERROR_PLAYING_PAUSED, "4",
79         "Fail state change from PLAYING to PAUSED"},
80     {FAKESINK_STATE_ERROR_PAUSED_READY, "5",
81         "Fail state change from PAUSED to READY"},
82     {FAKESINK_STATE_ERROR_READY_NULL, "6",
83         "Fail state change from READY to NULL"},
84     {0, NULL, NULL},
85   };
86
87   if (!fakesink_state_error_type) {
88     fakesink_state_error_type =
89         g_enum_register_static ("GstFakeSinkStateError", fakesink_state_error);
90   }
91   return fakesink_state_error_type;
92 }
93
94 #define _do_init(bla) \
95     GST_DEBUG_CATEGORY_INIT (gst_fakesink_debug, "fakesink", 0, "fakesink element");
96
97 GST_BOILERPLATE_FULL (GstFakeSink, gst_fakesink, GstElement, GST_TYPE_ELEMENT,
98     _do_init);
99
100 static void gst_fakesink_set_clock (GstElement * element, GstClock * clock);
101 static GstPad *gst_fakesink_request_new_pad (GstElement * element,
102     GstPadTemplate * templ, const gchar * unused);
103
104 static void gst_fakesink_set_property (GObject * object, guint prop_id,
105     const GValue * value, GParamSpec * pspec);
106 static void gst_fakesink_get_property (GObject * object, guint prop_id,
107     GValue * value, GParamSpec * pspec);
108
109 static GstElementStateReturn gst_fakesink_change_state (GstElement * element);
110
111 static void gst_fakesink_chain (GstPad * pad, GstData * _data);
112
113 static guint gst_fakesink_signals[LAST_SIGNAL] = { 0 };
114
115 static void
116 gst_fakesink_base_init (gpointer g_class)
117 {
118   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
119
120   gst_element_class_set_details (gstelement_class, &gst_fakesink_details);
121   gst_element_class_add_pad_template (gstelement_class,
122       gst_static_pad_template_get (&fakesink_sink_template));
123 }
124
125 static void
126 gst_fakesink_class_init (GstFakeSinkClass * klass)
127 {
128   GObjectClass *gobject_class;
129   GstElementClass *gstelement_class;
130
131   gobject_class = (GObjectClass *) klass;
132   gstelement_class = (GstElementClass *) klass;
133
134
135   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SINKS,
136       g_param_spec_int ("num_sinks", "Number of sinks",
137           "The number of sinkpads", 1, G_MAXINT, 1, G_PARAM_READABLE));
138   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_STATE_ERROR,
139       g_param_spec_enum ("state_error", "State Error",
140           "Generate a state change error", GST_TYPE_FAKESINK_STATE_ERROR,
141           FAKESINK_STATE_ERROR_NONE, G_PARAM_READWRITE));
142   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
143       g_param_spec_string ("last_message", "Last Message",
144           "The message describing current status", NULL, G_PARAM_READABLE));
145   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SYNC,
146       g_param_spec_boolean ("sync", "Sync", "Sync on the clock", FALSE,
147           G_PARAM_READWRITE));
148   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIGNAL_HANDOFFS,
149       g_param_spec_boolean ("signal-handoffs", "Signal handoffs",
150           "Send a signal before unreffing the buffer", FALSE,
151           G_PARAM_READWRITE));
152   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
153       g_param_spec_boolean ("silent", "Silent",
154           "Don't produce last_message events", FALSE, G_PARAM_READWRITE));
155   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DUMP,
156       g_param_spec_boolean ("dump", "Dump", "Dump received bytes to stdout",
157           FALSE, G_PARAM_READWRITE));
158
159   gst_fakesink_signals[SIGNAL_HANDOFF] =
160       g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
161       G_STRUCT_OFFSET (GstFakeSinkClass, handoff), NULL, NULL,
162       gst_marshal_VOID__POINTER_OBJECT, G_TYPE_NONE, 2,
163       GST_TYPE_BUFFER, GST_TYPE_PAD);
164
165   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesink_set_property);
166   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesink_get_property);
167
168   gstelement_class->request_new_pad =
169       GST_DEBUG_FUNCPTR (gst_fakesink_request_new_pad);
170   gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_fakesink_set_clock);
171   gstelement_class->change_state =
172       GST_DEBUG_FUNCPTR (gst_fakesink_change_state);
173 }
174
175 static void
176 gst_fakesink_init (GstFakeSink * fakesink)
177 {
178   GstPad *pad;
179
180   pad = gst_pad_new ("sink", GST_PAD_SINK);
181   gst_element_add_pad (GST_ELEMENT (fakesink), pad);
182   gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_chain));
183
184   fakesink->silent = FALSE;
185   fakesink->dump = FALSE;
186   fakesink->sync = FALSE;
187   fakesink->last_message = NULL;
188   fakesink->state_error = FAKESINK_STATE_ERROR_NONE;
189   fakesink->signal_handoffs = FALSE;
190
191   GST_FLAG_SET (fakesink, GST_ELEMENT_EVENT_AWARE);
192 }
193
194 static void
195 gst_fakesink_set_clock (GstElement * element, GstClock * clock)
196 {
197   GstFakeSink *sink;
198
199   sink = GST_FAKESINK (element);
200
201   sink->clock = clock;
202 }
203
204 static GstPad *
205 gst_fakesink_request_new_pad (GstElement * element, GstPadTemplate * templ,
206     const gchar * unused)
207 {
208   gchar *name;
209   GstPad *sinkpad;
210   GstFakeSink *fakesink;
211
212   g_return_val_if_fail (GST_IS_FAKESINK (element), NULL);
213
214   if (templ->direction != GST_PAD_SINK) {
215     g_warning ("gstfakesink: request new pad that is not a SINK pad\n");
216     return NULL;
217   }
218
219   fakesink = GST_FAKESINK (element);
220
221   name = g_strdup_printf ("sink%d", GST_ELEMENT (fakesink)->numsinkpads);
222
223   sinkpad = gst_pad_new_from_template (templ, name);
224   g_free (name);
225   gst_pad_set_chain_function (sinkpad, GST_DEBUG_FUNCPTR (gst_fakesink_chain));
226
227   gst_element_add_pad (GST_ELEMENT (fakesink), sinkpad);
228
229   return sinkpad;
230 }
231
232 static void
233 gst_fakesink_set_property (GObject * object, guint prop_id,
234     const GValue * value, GParamSpec * pspec)
235 {
236   GstFakeSink *sink;
237
238   /* it's not null if we got it, but it might not be ours */
239   sink = GST_FAKESINK (object);
240
241   switch (prop_id) {
242     case ARG_SILENT:
243       sink->silent = g_value_get_boolean (value);
244       break;
245     case ARG_STATE_ERROR:
246       sink->state_error = g_value_get_enum (value);
247       break;
248     case ARG_DUMP:
249       sink->dump = g_value_get_boolean (value);
250       break;
251     case ARG_SYNC:
252       sink->sync = g_value_get_boolean (value);
253       break;
254     case ARG_SIGNAL_HANDOFFS:
255       sink->signal_handoffs = g_value_get_boolean (value);
256       break;
257     default:
258       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
259       break;
260   }
261 }
262
263 static void
264 gst_fakesink_get_property (GObject * object, guint prop_id, GValue * value,
265     GParamSpec * pspec)
266 {
267   GstFakeSink *sink;
268
269   /* it's not null if we got it, but it might not be ours */
270   g_return_if_fail (GST_IS_FAKESINK (object));
271
272   sink = GST_FAKESINK (object);
273
274   switch (prop_id) {
275     case ARG_NUM_SINKS:
276       g_value_set_int (value, GST_ELEMENT (sink)->numsinkpads);
277       break;
278     case ARG_STATE_ERROR:
279       g_value_set_enum (value, sink->state_error);
280       break;
281     case ARG_SILENT:
282       g_value_set_boolean (value, sink->silent);
283       break;
284     case ARG_DUMP:
285       g_value_set_boolean (value, sink->dump);
286       break;
287     case ARG_SYNC:
288       g_value_set_boolean (value, sink->sync);
289       break;
290     case ARG_SIGNAL_HANDOFFS:
291       g_value_set_boolean (value, sink->signal_handoffs);
292       break;
293     case ARG_LAST_MESSAGE:
294       g_value_set_string (value, sink->last_message);
295       break;
296     default:
297       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
298       break;
299   }
300 }
301
302 static void
303 gst_fakesink_chain (GstPad * pad, GstData * _data)
304 {
305   GstBuffer *buf = GST_BUFFER (_data);
306   GstFakeSink *fakesink;
307
308   g_return_if_fail (pad != NULL);
309   g_return_if_fail (GST_IS_PAD (pad));
310   g_return_if_fail (buf != NULL);
311
312   fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
313
314   if (GST_IS_EVENT (buf)) {
315     GstEvent *event = GST_EVENT (buf);
316
317     if (!fakesink->silent) {
318       g_free (fakesink->last_message);
319
320       fakesink->last_message =
321           g_strdup_printf ("chain   ******* (%s:%s)E (type: %d) %p",
322           GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
323
324       g_object_notify (G_OBJECT (fakesink), "last_message");
325     }
326
327     switch (GST_EVENT_TYPE (event)) {
328       case GST_EVENT_DISCONTINUOUS:
329         if (fakesink->sync && fakesink->clock) {
330           gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value;
331
332           gst_element_set_time (GST_ELEMENT (fakesink), value);
333         }
334       default:
335         gst_pad_event_default (pad, event);
336         break;
337     }
338     return;
339   }
340
341   if (fakesink->sync && fakesink->clock) {
342     gst_element_wait (GST_ELEMENT (fakesink), GST_BUFFER_TIMESTAMP (buf));
343   }
344
345   if (!fakesink->silent) {
346     g_free (fakesink->last_message);
347
348     fakesink->last_message =
349         g_strdup_printf ("chain   ******* (%s:%s)< (%d bytes, timestamp: %"
350         GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
351         G_GINT64_FORMAT ", flags: %d) %p", GST_DEBUG_PAD_NAME (pad),
352         GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
353         GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf),
354         GST_BUFFER_FLAGS (buf), buf);
355
356     g_object_notify (G_OBJECT (fakesink), "last_message");
357   }
358
359   if (fakesink->signal_handoffs)
360     g_signal_emit (G_OBJECT (fakesink), gst_fakesink_signals[SIGNAL_HANDOFF], 0,
361         buf, pad);
362
363   if (fakesink->dump) {
364     gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
365   }
366
367   gst_buffer_unref (buf);
368 }
369
370 static GstElementStateReturn
371 gst_fakesink_change_state (GstElement * element)
372 {
373   GstFakeSink *fakesink = GST_FAKESINK (element);
374
375   switch (GST_STATE_TRANSITION (element)) {
376     case GST_STATE_NULL_TO_READY:
377       if (fakesink->state_error == FAKESINK_STATE_ERROR_NULL_READY)
378         goto error;
379       break;
380     case GST_STATE_READY_TO_PAUSED:
381       if (fakesink->state_error == FAKESINK_STATE_ERROR_READY_PAUSED)
382         goto error;
383       break;
384     case GST_STATE_PAUSED_TO_PLAYING:
385       if (fakesink->state_error == FAKESINK_STATE_ERROR_PAUSED_PLAYING)
386         goto error;
387       break;
388     case GST_STATE_PLAYING_TO_PAUSED:
389       if (fakesink->state_error == FAKESINK_STATE_ERROR_PLAYING_PAUSED)
390         goto error;
391       break;
392     case GST_STATE_PAUSED_TO_READY:
393       if (fakesink->state_error == FAKESINK_STATE_ERROR_PAUSED_READY)
394         goto error;
395       break;
396     case GST_STATE_READY_TO_NULL:
397       if (fakesink->state_error == FAKESINK_STATE_ERROR_READY_NULL)
398         goto error;
399       g_free (fakesink->last_message);
400       fakesink->last_message = NULL;
401       break;
402   }
403
404   if (GST_ELEMENT_CLASS (parent_class)->change_state)
405     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
406
407   return GST_STATE_SUCCESS;
408
409 error:
410   GST_ELEMENT_ERROR (element, CORE, STATE_CHANGE, (NULL), (NULL));
411   return GST_STATE_FAILURE;
412 }