1 /* GStreamer
2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
4 *
5 * gstidentity.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 */
24 #include <stdlib.h>
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
30 #include "../gst-i18n-lib.h"
31 #include "gstidentity.h"
32 #include <gst/gstmarshal.h>
34 GST_DEBUG_CATEGORY_STATIC (gst_identity_debug);
35 #define GST_CAT_DEFAULT gst_identity_debug
37 GstElementDetails gst_identity_details = GST_ELEMENT_DETAILS ("Identity",
38 "Generic",
39 "Pass data without modification",
40 "Erik Walthinsen <omega@cse.ogi.edu>");
43 /* Identity signals and args */
44 enum
45 {
46 SIGNAL_HANDOFF,
47 /* FILL ME */
48 LAST_SIGNAL
49 };
51 enum
52 {
53 ARG_0,
54 ARG_LOOP_BASED,
55 ARG_SLEEP_TIME,
56 ARG_DUPLICATE,
57 ARG_ERROR_AFTER,
58 ARG_DROP_PROBABILITY,
59 ARG_SILENT,
60 ARG_LAST_MESSAGE,
61 ARG_DUMP,
62 ARG_SYNC
63 };
66 #define _do_init(bla) \
67 GST_DEBUG_CATEGORY_INIT (gst_identity_debug, "identity", 0, "identity element");
69 GST_BOILERPLATE_FULL (GstIdentity, gst_identity, GstElement, GST_TYPE_ELEMENT,
70 _do_init);
72 static void gst_identity_finalize (GObject * object);
73 static void gst_identity_set_property (GObject * object, guint prop_id,
74 const GValue * value, GParamSpec * pspec);
75 static void gst_identity_get_property (GObject * object, guint prop_id,
76 GValue * value, GParamSpec * pspec);
78 static void gst_identity_chain (GstPad * pad, GstData * _data);
79 static void gst_identity_set_clock (GstElement * element, GstClock * clock);
82 static guint gst_identity_signals[LAST_SIGNAL] = { 0 };
84 static void
85 gst_identity_base_init (gpointer g_class)
86 {
87 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
89 gst_element_class_set_details (gstelement_class, &gst_identity_details);
90 }
92 static void
93 gst_identity_finalize (GObject * object)
94 {
95 GstIdentity *identity;
97 identity = GST_IDENTITY (object);
99 g_free (identity->last_message);
101 G_OBJECT_CLASS (parent_class)->finalize (object);
102 }
104 static void
105 gst_identity_class_init (GstIdentityClass * klass)
106 {
107 GObjectClass *gobject_class;
108 GstElementClass *gstelement_class;
110 gobject_class = G_OBJECT_CLASS (klass);
111 gstelement_class = GST_ELEMENT_CLASS (klass);
113 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOOP_BASED,
114 g_param_spec_boolean ("loop-based", "Loop-based",
115 "Set to TRUE to use loop-based rather than chain-based scheduling",
116 TRUE, G_PARAM_READWRITE));
117 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SLEEP_TIME,
118 g_param_spec_uint ("sleep-time", "Sleep time",
119 "Microseconds to sleep between processing", 0, G_MAXUINT, 0,
120 G_PARAM_READWRITE));
121 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DUPLICATE,
122 g_param_spec_uint ("duplicate", "Duplicate Buffers",
123 "Push the buffers N times", 0, G_MAXUINT, 1, G_PARAM_READWRITE));
124 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ERROR_AFTER,
125 g_param_spec_int ("error_after", "Error After", "Error after N buffers",
126 G_MININT, G_MAXINT, -1, G_PARAM_READWRITE));
127 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DROP_PROBABILITY,
128 g_param_spec_float ("drop_probability", "Drop Probability",
129 "The Probability a buffer is dropped", 0.0, 1.0, 0.0,
130 G_PARAM_READWRITE));
131 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
132 g_param_spec_boolean ("silent", "silent", "silent", FALSE,
133 G_PARAM_READWRITE));
134 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
135 g_param_spec_string ("last-message", "last-message", "last-message", NULL,
136 G_PARAM_READABLE));
137 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DUMP,
138 g_param_spec_boolean ("dump", "Dump", "Dump buffer contents", FALSE,
139 G_PARAM_READWRITE));
140 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SYNC,
141 g_param_spec_boolean ("sync", "Synchronize",
142 "Synchronize to pipeline clock", FALSE, G_PARAM_READWRITE));
144 gst_identity_signals[SIGNAL_HANDOFF] =
145 g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
146 G_STRUCT_OFFSET (GstIdentityClass, handoff), NULL, NULL,
147 gst_marshal_VOID__POINTER, G_TYPE_NONE, 1, GST_TYPE_BUFFER);
149 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_identity_finalize);
150 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_identity_set_property);
151 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_identity_get_property);
153 gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_identity_set_clock);
155 }
157 static void
158 gst_identity_init (GstIdentity * identity)
159 {
160 identity->sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
161 gst_element_add_pad (GST_ELEMENT (identity), identity->sinkpad);
162 gst_pad_set_chain_function (identity->sinkpad,
163 GST_DEBUG_FUNCPTR (gst_identity_chain));
164 gst_pad_set_link_function (identity->sinkpad, gst_pad_proxy_pad_link);
165 gst_pad_set_getcaps_function (identity->sinkpad, gst_pad_proxy_getcaps);
167 identity->srcpad = gst_pad_new ("src", GST_PAD_SRC);
168 gst_element_add_pad (GST_ELEMENT (identity), identity->srcpad);
169 gst_pad_set_link_function (identity->srcpad, gst_pad_proxy_pad_link);
170 gst_pad_set_getcaps_function (identity->srcpad, gst_pad_proxy_getcaps);
172 identity->loop_based = FALSE;
173 identity->sleep_time = 0;
174 identity->duplicate = 1;
175 identity->error_after = -1;
176 identity->drop_probability = 0.0;
177 identity->silent = FALSE;
178 identity->sync = FALSE;
179 identity->dump = FALSE;
180 identity->last_message = NULL;
181 identity->srccaps = NULL;
183 GST_FLAG_SET (identity, GST_ELEMENT_EVENT_AWARE);
184 }
186 static void
187 gst_identity_set_clock (GstElement * element, GstClock * clock)
188 {
189 GstIdentity *identity = GST_IDENTITY (element);
191 gst_object_replace ((GstObject **) & identity->clock, (GstObject *) clock);
192 }
195 static void
196 gst_identity_chain (GstPad * pad, GstData * _data)
197 {
198 GstBuffer *buf = GST_BUFFER (_data);
199 GstIdentity *identity;
200 guint i;
202 g_return_if_fail (pad != NULL);
203 g_return_if_fail (GST_IS_PAD (pad));
204 g_return_if_fail (buf != NULL);
206 identity = GST_IDENTITY (gst_pad_get_parent (pad));
208 if (GST_IS_EVENT (buf)) {
209 GstEvent *event = GST_EVENT (buf);
211 if (!identity->silent) {
212 g_free (identity->last_message);
214 identity->last_message =
215 g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
216 GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
218 g_object_notify (G_OBJECT (identity), "last_message");
219 }
220 gst_pad_event_default (pad, event);
221 return;
222 }
224 if (identity->error_after >= 0) {
225 identity->error_after--;
226 if (identity->error_after == 0) {
227 gst_buffer_unref (buf);
228 GST_ELEMENT_ERROR (identity, CORE, FAILED,
229 (_("Failed after iterations as requested.")), (NULL));
230 return;
231 }
232 }
234 if (identity->drop_probability > 0.0) {
235 if ((gfloat) (1.0 * rand () / (RAND_MAX)) < identity->drop_probability) {
236 g_free (identity->last_message);
237 identity->last_message =
238 g_strdup_printf ("dropping ******* (%s:%s)i (%d bytes, timestamp: %"
239 GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
240 G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p",
241 GST_DEBUG_PAD_NAME (identity->sinkpad), GST_BUFFER_SIZE (buf),
242 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
243 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf),
244 GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf);
245 g_object_notify (G_OBJECT (identity), "last-message");
246 gst_buffer_unref (buf);
247 return;
248 }
249 }
250 if (identity->dump) {
251 gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
252 }
254 for (i = identity->duplicate; i; i--) {
255 if (!identity->silent) {
256 g_free (identity->last_message);
257 identity->last_message =
258 g_strdup_printf ("chain ******* (%s:%s)i (%d bytes, timestamp: %"
259 GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
260 G_GINT64_FORMAT ", offset_end: % " G_GINT64_FORMAT ", flags: %d) %p",
261 GST_DEBUG_PAD_NAME (identity->sinkpad), GST_BUFFER_SIZE (buf),
262 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
263 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf),
264 GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf);
265 g_object_notify (G_OBJECT (identity), "last-message");
266 }
268 g_signal_emit (G_OBJECT (identity), gst_identity_signals[SIGNAL_HANDOFF], 0,
269 buf);
271 if (i > 1)
272 gst_buffer_ref (buf);
274 if (identity->sync) {
275 if (identity->clock) {
276 gst_element_wait (GST_ELEMENT (identity), GST_BUFFER_TIMESTAMP (buf));
277 }
278 }
279 gst_pad_push (identity->srcpad, GST_DATA (buf));
281 if (identity->sleep_time)
282 g_usleep (identity->sleep_time);
283 }
284 }
286 static void
287 gst_identity_loop (GstElement * element)
288 {
289 GstIdentity *identity;
290 GstBuffer *buf;
292 g_return_if_fail (element != NULL);
293 g_return_if_fail (GST_IS_IDENTITY (element));
295 identity = GST_IDENTITY (element);
297 buf = GST_BUFFER (gst_pad_pull (identity->sinkpad));
298 if (GST_IS_EVENT (buf)) {
299 GstEvent *event = GST_EVENT (buf);
301 if (GST_EVENT_IS_INTERRUPT (event)) {
302 gst_event_unref (event);
303 } else {
304 gst_pad_event_default (identity->sinkpad, event);
305 }
306 } else {
307 gst_identity_chain (identity->sinkpad, GST_DATA (buf));
308 }
309 }
311 static void
312 gst_identity_set_property (GObject * object, guint prop_id,
313 const GValue * value, GParamSpec * pspec)
314 {
315 GstIdentity *identity;
317 /* it's not null if we got it, but it might not be ours */
318 g_return_if_fail (GST_IS_IDENTITY (object));
320 identity = GST_IDENTITY (object);
322 switch (prop_id) {
323 case ARG_LOOP_BASED:
324 identity->loop_based = g_value_get_boolean (value);
325 if (identity->loop_based) {
326 gst_element_set_loop_function (GST_ELEMENT (identity),
327 gst_identity_loop);
328 gst_pad_set_chain_function (identity->sinkpad, NULL);
329 } else {
330 gst_pad_set_chain_function (identity->sinkpad, gst_identity_chain);
331 gst_element_set_loop_function (GST_ELEMENT (identity), NULL);
332 }
333 break;
334 case ARG_SLEEP_TIME:
335 identity->sleep_time = g_value_get_uint (value);
336 break;
337 case ARG_SILENT:
338 identity->silent = g_value_get_boolean (value);
339 break;
340 case ARG_DUPLICATE:
341 identity->duplicate = g_value_get_uint (value);
342 break;
343 case ARG_DUMP:
344 identity->dump = g_value_get_boolean (value);
345 break;
346 case ARG_ERROR_AFTER:
347 identity->error_after = g_value_get_int (value);
348 break;
349 case ARG_DROP_PROBABILITY:
350 identity->drop_probability = g_value_get_float (value);
351 break;
352 case ARG_SYNC:
353 identity->sync = g_value_get_boolean (value);
354 break;
355 default:
356 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
357 break;
358 }
359 }
361 static void
362 gst_identity_get_property (GObject * object, guint prop_id, GValue * value,
363 GParamSpec * pspec)
364 {
365 GstIdentity *identity;
367 /* it's not null if we got it, but it might not be ours */
368 g_return_if_fail (GST_IS_IDENTITY (object));
370 identity = GST_IDENTITY (object);
372 switch (prop_id) {
373 case ARG_LOOP_BASED:
374 g_value_set_boolean (value, identity->loop_based);
375 break;
376 case ARG_SLEEP_TIME:
377 g_value_set_uint (value, identity->sleep_time);
378 break;
379 case ARG_DUPLICATE:
380 g_value_set_uint (value, identity->duplicate);
381 break;
382 case ARG_ERROR_AFTER:
383 g_value_set_int (value, identity->error_after);
384 break;
385 case ARG_DROP_PROBABILITY:
386 g_value_set_float (value, identity->drop_probability);
387 break;
388 case ARG_SILENT:
389 g_value_set_boolean (value, identity->silent);
390 break;
391 case ARG_DUMP:
392 g_value_set_boolean (value, identity->dump);
393 break;
394 case ARG_LAST_MESSAGE:
395 g_value_set_string (value, identity->last_message);
396 break;
397 case ARG_SYNC:
398 g_value_set_boolean (value, identity->sync);
399 break;
400 default:
401 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
402 break;
403 }
404 }