]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gstreamer0-10.git/blob - gst/elements/gstshaper.c
gst-indent run on core
[glsdk/gstreamer0-10.git] / gst / elements / gstshaper.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstshaper.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 "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 ("Shaper",
36     "Generic",
37     "Synchronizes streams on different pads",
38     "Wim Taymans <wim.taymans@chello.be>");
41 /* Shaper signals and args */
42 enum
43 {
44   /* FILL ME */
45   LAST_SIGNAL
46 };
48 enum
49 {
50   ARG_0,
51   ARG_POLICY,
52   ARG_SILENT,
53   ARG_LAST_MESSAGE,
54 };
56 typedef struct
57 {
58   GstPad *sinkpad;
59   GstPad *srcpad;
60   GstBuffer *buffer;
61 } GstShaperConnection;
63 GstStaticPadTemplate shaper_src_template = GST_STATIC_PAD_TEMPLATE ("src%d",
64     GST_PAD_SRC,
65     GST_PAD_SOMETIMES,
66     GST_STATIC_CAPS_ANY);
68 GstStaticPadTemplate shaper_sink_template = GST_STATIC_PAD_TEMPLATE ("sink%d",
69     GST_PAD_SINK,
70     GST_PAD_REQUEST,
71     GST_STATIC_CAPS_ANY);
73 #define GST_TYPE_SHAPER_POLICY (gst_shaper_policy_get_type())
74 static GType
75 gst_shaper_policy_get_type (void)
76 {
77   static GType shaper_policy_type = 0;
78   static GEnumValue shaper_policy[] = {
79     {SHAPER_POLICY_TIMESTAMPS, "1", "sync on timestamps"},
80     {SHAPER_POLICY_BUFFERSIZE, "2", "sync on buffer size"},
81     {0, NULL, NULL},
82   };
83   if (!shaper_policy_type) {
84     shaper_policy_type =
85         g_enum_register_static ("GstShaperPolicy", shaper_policy);
86   }
87   return shaper_policy_type;
88 }
90 #define _do_init(bla) \
91     GST_DEBUG_CATEGORY_INIT (gst_shaper_debug, "shaper", 0, "shaper element");
93 GST_BOILERPLATE_FULL (GstShaper, gst_shaper, GstElement, GST_TYPE_ELEMENT,
94     _do_init);
96 static void gst_shaper_set_property (GObject * object, guint prop_id,
97     const GValue * value, GParamSpec * pspec);
98 static void gst_shaper_get_property (GObject * object, guint prop_id,
99     GValue * value, GParamSpec * pspec);
101 static GstPad *gst_shaper_request_new_pad (GstElement * element,
102     GstPadTemplate * templ, const gchar * unused);
104 static void gst_shaper_loop (GstElement * element);
107 static void
108 gst_shaper_base_init (gpointer g_class)
110   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
112   gst_element_class_set_details (gstelement_class, &gst_shaper_details);
113   gst_element_class_add_pad_template (gstelement_class,
114       gst_static_pad_template_get (&shaper_src_template));
115   gst_element_class_add_pad_template (gstelement_class,
116       gst_static_pad_template_get (&shaper_sink_template));
119 static void
120 gst_shaper_class_init (GstShaperClass * klass)
122   GObjectClass *gobject_class;
123   GstElementClass *gstelement_class;
125   gobject_class = (GObjectClass *) klass;
126   gstelement_class = (GstElementClass *) klass;
129   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_POLICY,
130       g_param_spec_enum ("policy", "Policy", "Shaper policy",
131           GST_TYPE_SHAPER_POLICY, SHAPER_POLICY_TIMESTAMPS, G_PARAM_READWRITE));
132   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
133       g_param_spec_boolean ("silent", "silent", "silent",
134           FALSE, G_PARAM_READWRITE));
135   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
136       g_param_spec_string ("last-message", "last-message", "last-message",
137           NULL, G_PARAM_READABLE));
139   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_shaper_set_property);
140   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_shaper_get_property);
142   gstelement_class->request_new_pad =
143       GST_DEBUG_FUNCPTR (gst_shaper_request_new_pad);
146 static GstCaps *
147 gst_shaper_getcaps (GstPad * pad)
149   GstPad *otherpad;
150   GstShaperConnection *connection;
152   connection = gst_pad_get_element_private (pad);
154   otherpad =
155       (pad == connection->srcpad ? connection->sinkpad : connection->srcpad);
157   if (GST_PAD_PEER (otherpad)) {
158     return gst_pad_get_caps (GST_PAD_PEER (otherpad));
159   } else {
160     return gst_caps_new_any ();
161   }
164 static GList *
165 gst_shaper_get_internal_link (GstPad * pad)
167   GList *res = NULL;
168   GstShaperConnection *connection;
169   GstPad *otherpad;
171   connection = gst_pad_get_element_private (pad);
173   otherpad =
174       (pad == connection->srcpad ? connection->sinkpad : connection->srcpad);
176   res = g_list_prepend (res, otherpad);
178   return res;
181 static GstPadLinkReturn
182 gst_shaper_link (GstPad * pad, const GstCaps * caps)
184   GstPad *otherpad;
185   GstShaperConnection *connection;
187   connection = gst_pad_get_element_private (pad);
189   otherpad =
190       (pad == connection->srcpad ? connection->sinkpad : connection->srcpad);
192   return gst_pad_try_set_caps (otherpad, caps);
195 static GstShaperConnection *
196 gst_shaper_create_connection (GstShaper * shaper)
198   GstShaperConnection *connection;
199   gchar *padname;
201   shaper->nconnections++;
203   connection = g_new0 (GstShaperConnection, 1);
205   padname = g_strdup_printf ("sink%d", shaper->nconnections);
206   connection->sinkpad =
207       gst_pad_new_from_template (gst_static_pad_template_get
208       (&shaper_sink_template), padname);
209   g_free (padname);
210   gst_pad_set_getcaps_function (connection->sinkpad, gst_shaper_getcaps);
211   gst_pad_set_internal_link_function (connection->sinkpad,
212       gst_shaper_get_internal_link);
213   gst_pad_set_link_function (connection->sinkpad, gst_shaper_link);
214   gst_pad_set_element_private (connection->sinkpad, connection);
215   gst_element_add_pad (GST_ELEMENT (shaper), connection->sinkpad);
217   padname = g_strdup_printf ("src%d", shaper->nconnections);
218   connection->srcpad =
219       gst_pad_new_from_template (gst_static_pad_template_get
220       (&shaper_src_template), padname);
221   g_free (padname);
222   gst_pad_set_getcaps_function (connection->srcpad, gst_shaper_getcaps);
223   gst_pad_set_internal_link_function (connection->srcpad,
224       gst_shaper_get_internal_link);
225   gst_pad_set_link_function (connection->srcpad, gst_shaper_link);
226   gst_pad_set_element_private (connection->srcpad, connection);
227   gst_element_add_pad (GST_ELEMENT (shaper), connection->srcpad);
229   shaper->connections = g_slist_prepend (shaper->connections, connection);
231   return connection;
234 static GstPad *
235 gst_shaper_request_new_pad (GstElement * element, GstPadTemplate * templ,
236     const gchar * unused)
238   GstShaper *shaper = GST_SHAPER (element);
239   GstShaperConnection *connection;
241   connection = gst_shaper_create_connection (shaper);
243   return connection->sinkpad;
246 static void
247 gst_shaper_init (GstShaper * shaper)
249   gst_element_set_loop_function (GST_ELEMENT (shaper), gst_shaper_loop);
251   shaper->policy = SHAPER_POLICY_TIMESTAMPS;
252   shaper->connections = NULL;
253   shaper->nconnections = 0;
254   shaper->silent = FALSE;
255   shaper->last_message = NULL;
258 static void
259 gst_shaper_loop (GstElement * element)
261   GstShaper *shaper;
262   GSList *connections;
263   gboolean eos = TRUE;
264   GstShaperConnection *min = NULL;
266   shaper = GST_SHAPER (element);
268   /* first make sure we have a buffer on all pads */
269   connections = shaper->connections;
270   while (connections) {
271     GstShaperConnection *connection = (GstShaperConnection *) connections->data;
273     /* try to fill a connection without a buffer on a pad that is
274      * active */
275     if (connection->buffer == NULL && GST_PAD_IS_USABLE (connection->sinkpad)) {
276       GstBuffer *buffer;
278       buffer = GST_BUFFER (gst_pad_pull (connection->sinkpad));
280       /* events are simply pushed ASAP */
281       if (GST_IS_EVENT (buffer)) {
282         /* save event type as it will be unreffed after the next push */
283         GstEventType type = GST_EVENT_TYPE (buffer);
285         gst_pad_push (connection->srcpad, GST_DATA (buffer));
287         switch (type) {
288             /* on EOS we disable the pad so that we don't pull on
289              * it again and never get more data */
290           case GST_EVENT_EOS:
291             gst_pad_set_active (connection->sinkpad, FALSE);
292             break;
293           default:
294             break;
295         }
296       } else {
297         /* we store the buffer */
298         connection->buffer = buffer;
299       }
300     }
301     /* FIXME policy stuff goes here */
302     /* find connection with lowest timestamp */
303     if (min == NULL || (connection->buffer != NULL &&
304             (GST_BUFFER_TIMESTAMP (connection->buffer) <
305                 GST_BUFFER_TIMESTAMP (min->buffer)))) {
306       min = connection;
307     }
308     connections = g_slist_next (connections);
309   }
310   /* if we have a connection with a buffer, push it */
311   if (min != NULL && min->buffer) {
312     gst_pad_push (min->srcpad, GST_DATA (min->buffer));
313     min->buffer = NULL;
314     /* since we pushed a buffer, it's not EOS */
315     eos = FALSE;
316   }
318   if (eos) {
319     gst_element_set_eos (element);
320   }
323 static void
324 gst_shaper_set_property (GObject * object, guint prop_id, const GValue * value,
325     GParamSpec * pspec)
327   GstShaper *shaper;
329   /* it's not null if we got it, but it might not be ours */
330   g_return_if_fail (GST_IS_SHAPER (object));
332   shaper = GST_SHAPER (object);
334   switch (prop_id) {
335     case ARG_POLICY:
336       shaper->policy = g_value_get_enum (value);
337       break;
338     case ARG_SILENT:
339       shaper->silent = g_value_get_boolean (value);
340       break;
341     default:
342       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
343       break;
344   }
347 static void
348 gst_shaper_get_property (GObject * object, guint prop_id, GValue * value,
349     GParamSpec * pspec)
351   GstShaper *shaper;
353   /* it's not null if we got it, but it might not be ours */
354   g_return_if_fail (GST_IS_SHAPER (object));
356   shaper = GST_SHAPER (object);
358   switch (prop_id) {
359     case ARG_POLICY:
360       g_value_set_enum (value, shaper->policy);
361       break;
362     case ARG_SILENT:
363       g_value_set_boolean (value, shaper->silent);
364       break;
365     case ARG_LAST_MESSAGE:
366       g_value_set_string (value, shaper->last_message);
367       break;
368     default:
369       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
370       break;
371   }