2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
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.
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.
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.
30 #include "gstshaper.h"
32 GST_DEBUG_CATEGORY_STATIC (gst_shaper_debug);
33 #define GST_CAT_DEFAULT gst_shaper_debug
35 GstElementDetails gst_shaper_details = GST_ELEMENT_DETAILS (
38 "Synchronizes streams on different pads",
39 "Wim Taymans <wim.taymans@chello.be>"
43 /* Shaper signals and args */
61 } GstShaperConnection;
63 GstStaticPadTemplate shaper_src_template = GST_STATIC_PAD_TEMPLATE (
70 GstStaticPadTemplate shaper_sink_template = GST_STATIC_PAD_TEMPLATE (
77 #define GST_TYPE_SHAPER_POLICY (gst_shaper_policy_get_type())
79 gst_shaper_policy_get_type (void)
81 static GType shaper_policy_type = 0;
82 static GEnumValue shaper_policy[] = {
83 { SHAPER_POLICY_TIMESTAMPS, "1", "sync on timestamps"},
84 { SHAPER_POLICY_BUFFERSIZE, "2", "sync on buffer size"},
87 if (!shaper_policy_type) {
88 shaper_policy_type = g_enum_register_static ("GstShaperPolicy", shaper_policy);
90 return shaper_policy_type;
93 static void gst_shaper_base_init (gpointer g_class);
94 static void gst_shaper_class_init (GstShaperClass *klass);
95 static void gst_shaper_init (GstShaper *shaper);
97 static void gst_shaper_set_property (GObject *object, guint prop_id,
98 const GValue *value, GParamSpec *pspec);
99 static void gst_shaper_get_property (GObject *object, guint prop_id,
100 GValue *value, GParamSpec *pspec);
102 static GstPad* gst_shaper_request_new_pad (GstElement *element, GstPadTemplate *templ,
103 const gchar *unused);
105 static void gst_shaper_loop (GstElement *element);
107 static GstElementClass *parent_class = NULL;
108 /* static guint gst_shaper_signals[LAST_SIGNAL] = { 0 }; */
111 gst_shaper_get_type (void)
113 static GType shaper_type = 0;
116 static const GTypeInfo shaper_info = {
117 sizeof(GstShaperClass),
118 gst_shaper_base_init,
120 (GClassInitFunc)gst_shaper_class_init,
125 (GInstanceInitFunc)gst_shaper_init,
127 shaper_type = g_type_register_static (GST_TYPE_ELEMENT, "GstShaper", &shaper_info, 0);
129 GST_DEBUG_CATEGORY_INIT (gst_shaper_debug, "shaper", 0, "shaper element");
135 gst_shaper_base_init (gpointer g_class)
137 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
139 gst_element_class_set_details (gstelement_class, &gst_shaper_details);
140 gst_element_class_add_pad_template (gstelement_class,
141 gst_static_pad_template_get (&shaper_src_template));
142 gst_element_class_add_pad_template (gstelement_class,
143 gst_static_pad_template_get (&shaper_sink_template));
147 gst_shaper_class_init (GstShaperClass *klass)
149 GObjectClass *gobject_class;
150 GstElementClass *gstelement_class;
152 gobject_class = (GObjectClass*) klass;
153 gstelement_class = (GstElementClass*) klass;
155 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
157 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_POLICY,
158 g_param_spec_enum ("policy", "Policy", "Shaper policy",
159 GST_TYPE_SHAPER_POLICY, SHAPER_POLICY_TIMESTAMPS, G_PARAM_READWRITE));
160 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
161 g_param_spec_boolean ("silent", "silent", "silent",
162 FALSE, G_PARAM_READWRITE));
163 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
164 g_param_spec_string ("last-message", "last-message", "last-message",
165 NULL, G_PARAM_READABLE));
167 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_shaper_set_property);
168 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_shaper_get_property);
170 gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR (gst_shaper_request_new_pad);
174 gst_shaper_getcaps (GstPad *pad)
177 GstShaperConnection *connection;
179 connection = gst_pad_get_element_private (pad);
181 otherpad = (pad == connection->srcpad ? connection->sinkpad : connection->srcpad);
183 return gst_caps_copy (gst_pad_get_allowed_caps (otherpad));
187 gst_shaper_get_internal_link (GstPad *pad)
190 GstShaperConnection *connection;
193 connection = gst_pad_get_element_private (pad);
195 otherpad = (pad == connection->srcpad ? connection->sinkpad : connection->srcpad);
197 res = g_list_prepend (res, otherpad);
202 static GstPadLinkReturn
203 gst_shaper_link (GstPad *pad, const GstCaps *caps)
206 GstShaperConnection *connection;
208 connection = gst_pad_get_element_private (pad);
210 otherpad = (pad == connection->srcpad ? connection->sinkpad : connection->srcpad);
212 return gst_pad_proxy_link (otherpad, caps);
215 static GstShaperConnection*
216 gst_shaper_create_connection (GstShaper *shaper)
218 GstShaperConnection *connection;
221 shaper->nconnections++;
223 connection = g_new0 (GstShaperConnection, 1);
225 padname = g_strdup_printf ("sink%d", shaper->nconnections);
226 connection->sinkpad = gst_pad_new_from_template (
227 gst_static_pad_template_get (&shaper_sink_template), padname);
229 gst_pad_set_getcaps_function (connection->sinkpad, gst_shaper_getcaps);
230 gst_pad_set_internal_link_function (connection->sinkpad, gst_shaper_get_internal_link);
231 gst_pad_set_link_function (connection->sinkpad, gst_shaper_link);
232 gst_pad_set_element_private (connection->sinkpad, connection);
233 gst_element_add_pad (GST_ELEMENT (shaper), connection->sinkpad);
235 padname = g_strdup_printf ("src%d", shaper->nconnections);
236 connection->srcpad = gst_pad_new_from_template (
237 gst_static_pad_template_get (&shaper_src_template), padname);
239 gst_pad_set_getcaps_function (connection->srcpad, gst_shaper_getcaps);
240 gst_pad_set_internal_link_function (connection->srcpad, gst_shaper_get_internal_link);
241 gst_pad_set_link_function (connection->srcpad, gst_shaper_link);
242 gst_pad_set_element_private (connection->srcpad, connection);
243 gst_element_add_pad (GST_ELEMENT (shaper), connection->srcpad);
245 shaper->connections = g_slist_prepend (shaper->connections, connection);
251 gst_shaper_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *unused)
253 GstShaper *shaper = GST_SHAPER (element);
254 GstShaperConnection *connection;
256 connection = gst_shaper_create_connection (shaper);
258 return connection->sinkpad;
262 gst_shaper_init (GstShaper *shaper)
264 gst_element_set_loop_function (GST_ELEMENT (shaper), gst_shaper_loop);
266 shaper->policy = SHAPER_POLICY_TIMESTAMPS;
267 shaper->connections = NULL;
268 shaper->nconnections = 0;
269 shaper->silent = FALSE;
270 shaper->last_message = NULL;
274 gst_shaper_loop (GstElement *element)
279 GstShaperConnection *min = NULL;
281 shaper = GST_SHAPER (element);
283 /* first make sure we have a buffer on all pads */
284 connections = shaper->connections;
285 while (connections) {
286 GstShaperConnection *connection = (GstShaperConnection *) connections->data;
288 /* try to fill a connection without a buffer on a pad that is
290 if (connection->buffer == NULL && GST_PAD_IS_USABLE (connection->sinkpad)) {
293 buffer = GST_BUFFER (gst_pad_pull (connection->sinkpad));
295 /* events are simply pushed ASAP */
296 if (GST_IS_EVENT (buffer)) {
297 /* save event type as it will be unreffed after the next push */
298 GstEventType type = GST_EVENT_TYPE (buffer);
300 gst_pad_push (connection->srcpad, GST_DATA (buffer));
303 /* on EOS we disable the pad so that we don't pull on
304 * it again and never get more data */
306 gst_pad_set_active (connection->sinkpad, FALSE);
313 /* we store the buffer */
314 connection->buffer = buffer;
317 /* FIXME policy stuff goes here */
318 /* find connection with lowest timestamp */
319 if (min == NULL || (connection->buffer != NULL &&
320 (GST_BUFFER_TIMESTAMP (connection->buffer) <
321 GST_BUFFER_TIMESTAMP (min->buffer))))
325 connections = g_slist_next (connections);
327 /* if we have a connection with a buffer, push it */
328 if (min != NULL && min->buffer) {
329 gst_pad_push (min->srcpad, GST_DATA (min->buffer));
331 /* since we pushed a buffer, it's not EOS */
336 gst_element_set_eos (element);
341 gst_shaper_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
345 /* it's not null if we got it, but it might not be ours */
346 g_return_if_fail (GST_IS_SHAPER (object));
348 shaper = GST_SHAPER (object);
352 shaper->policy = g_value_get_enum (value);
355 shaper->silent = g_value_get_boolean (value);
358 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
363 static void gst_shaper_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) {
366 /* it's not null if we got it, but it might not be ours */
367 g_return_if_fail (GST_IS_SHAPER (object));
369 shaper = GST_SHAPER (object);
373 g_value_set_enum (value, shaper->policy);
376 g_value_set_boolean (value, shaper->silent);
378 case ARG_LAST_MESSAGE:
379 g_value_set_string (value, shaper->last_message);
382 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);