fix up more enums
[platform/upstream/gst-plugins-good.git] / gst / oldcore / 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  */
22
23
24 #include <stdlib.h>
25
26 #ifdef HAVE_CONFIG_H
27 #  include "config.h"
28 #endif
29
30 #include "gstshaper.h"
31
32 GST_DEBUG_CATEGORY_STATIC (gst_shaper_debug);
33 #define GST_CAT_DEFAULT gst_shaper_debug
34
35 GstElementDetails gst_shaper_details = GST_ELEMENT_DETAILS ("Shaper",
36     "Generic",
37     "Synchronizes streams on different pads",
38     "Wim Taymans <wim.taymans@chello.be>");
39
40
41 /* Shaper signals and args */
42 enum
43 {
44   /* FILL ME */
45   LAST_SIGNAL
46 };
47
48 enum
49 {
50   ARG_0,
51   ARG_POLICY,
52   ARG_SILENT,
53   ARG_LAST_MESSAGE
54 };
55
56 typedef struct
57 {
58   GstPad *sinkpad;
59   GstPad *srcpad;
60   GstBuffer *buffer;
61 }
62 GstShaperConnection;
63
64 GstStaticPadTemplate shaper_src_template = GST_STATIC_PAD_TEMPLATE ("src%d",
65     GST_PAD_SRC,
66     GST_PAD_SOMETIMES,
67     GST_STATIC_CAPS_ANY);
68
69 GstStaticPadTemplate shaper_sink_template = GST_STATIC_PAD_TEMPLATE ("sink%d",
70     GST_PAD_SINK,
71     GST_PAD_REQUEST,
72     GST_STATIC_CAPS_ANY);
73
74 #define GST_TYPE_SHAPER_POLICY (gst_shaper_policy_get_type())
75 static GType
76 gst_shaper_policy_get_type (void)
77 {
78   static GType shaper_policy_type = 0;
79   static GEnumValue shaper_policy[] = {
80     {SHAPER_POLICY_TIMESTAMPS, "sync on timestamps", "timestamp"},
81     {SHAPER_POLICY_BUFFERSIZE, "sync on buffer size", "size"},
82     {0, NULL, NULL},
83   };
84
85   if (!shaper_policy_type) {
86     shaper_policy_type =
87         g_enum_register_static ("GstShaperPolicy", shaper_policy);
88   }
89   return shaper_policy_type;
90 }
91
92 #define _do_init(bla) \
93     GST_DEBUG_CATEGORY_INIT (gst_shaper_debug, "shaper", 0, "shaper element");
94
95 GST_BOILERPLATE_FULL (GstShaper, gst_shaper, GstElement, GST_TYPE_ELEMENT,
96     _do_init);
97
98 static void gst_shaper_set_property (GObject * object, guint prop_id,
99     const GValue * value, GParamSpec * pspec);
100 static void gst_shaper_get_property (GObject * object, guint prop_id,
101     GValue * value, GParamSpec * pspec);
102
103 static GstPad *gst_shaper_request_new_pad (GstElement * element,
104     GstPadTemplate * templ, const gchar * unused);
105
106 static void gst_shaper_loop (GstElement * element);
107
108
109 static void
110 gst_shaper_base_init (gpointer g_class)
111 {
112   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
113
114   gst_element_class_set_details (gstelement_class, &gst_shaper_details);
115   gst_element_class_add_pad_template (gstelement_class,
116       gst_static_pad_template_get (&shaper_src_template));
117   gst_element_class_add_pad_template (gstelement_class,
118       gst_static_pad_template_get (&shaper_sink_template));
119 }
120
121 static void
122 gst_shaper_class_init (GstShaperClass * klass)
123 {
124   GObjectClass *gobject_class;
125   GstElementClass *gstelement_class;
126
127   gobject_class = (GObjectClass *) klass;
128   gstelement_class = (GstElementClass *) klass;
129
130   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_shaper_set_property);
131   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_shaper_get_property);
132
133   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_POLICY,
134       g_param_spec_enum ("policy", "Policy", "Shaper policy",
135           GST_TYPE_SHAPER_POLICY, SHAPER_POLICY_TIMESTAMPS, G_PARAM_READWRITE));
136   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
137       g_param_spec_boolean ("silent", "silent", "silent",
138           FALSE, G_PARAM_READWRITE));
139   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
140       g_param_spec_string ("last-message", "last-message", "last-message",
141           NULL, G_PARAM_READABLE));
142
143   gstelement_class->request_new_pad =
144       GST_DEBUG_FUNCPTR (gst_shaper_request_new_pad);
145 }
146
147 static GstCaps *
148 gst_shaper_getcaps (GstPad * pad)
149 {
150   GstPad *otherpad;
151   GstShaperConnection *connection;
152
153   connection = gst_pad_get_element_private (pad);
154
155   otherpad =
156       (pad == connection->srcpad ? connection->sinkpad : connection->srcpad);
157
158   if (GST_PAD_PEER (otherpad)) {
159     return gst_pad_get_caps (GST_PAD_PEER (otherpad));
160   } else {
161     return gst_caps_new_any ();
162   }
163 }
164
165 static GList *
166 gst_shaper_get_internal_link (GstPad * pad)
167 {
168   GList *res = NULL;
169   GstShaperConnection *connection;
170   GstPad *otherpad;
171
172   connection = gst_pad_get_element_private (pad);
173
174   otherpad =
175       (pad == connection->srcpad ? connection->sinkpad : connection->srcpad);
176
177   res = g_list_prepend (res, otherpad);
178
179   return res;
180 }
181
182 static GstPadLinkReturn
183 gst_shaper_link (GstPad * pad, const GstCaps * caps)
184 {
185   GstPad *otherpad;
186   GstShaperConnection *connection;
187
188   connection = gst_pad_get_element_private (pad);
189
190   otherpad =
191       (pad == connection->srcpad ? connection->sinkpad : connection->srcpad);
192
193   return gst_pad_try_set_caps (otherpad, caps);
194 }
195
196 static GstShaperConnection *
197 gst_shaper_create_connection (GstShaper * shaper)
198 {
199   GstShaperConnection *connection;
200   gchar *padname;
201
202   shaper->nconnections++;
203
204   connection = g_new0 (GstShaperConnection, 1);
205
206   padname = g_strdup_printf ("sink%d", shaper->nconnections);
207   connection->sinkpad =
208       gst_pad_new_from_template (gst_static_pad_template_get
209       (&shaper_sink_template), padname);
210   g_free (padname);
211   gst_pad_set_getcaps_function (connection->sinkpad, gst_shaper_getcaps);
212   gst_pad_set_internal_link_function (connection->sinkpad,
213       gst_shaper_get_internal_link);
214   gst_pad_set_link_function (connection->sinkpad, gst_shaper_link);
215   gst_pad_set_element_private (connection->sinkpad, connection);
216   gst_element_add_pad (GST_ELEMENT (shaper), connection->sinkpad);
217
218   padname = g_strdup_printf ("src%d", shaper->nconnections);
219   connection->srcpad =
220       gst_pad_new_from_template (gst_static_pad_template_get
221       (&shaper_src_template), padname);
222   g_free (padname);
223   gst_pad_set_getcaps_function (connection->srcpad, gst_shaper_getcaps);
224   gst_pad_set_internal_link_function (connection->srcpad,
225       gst_shaper_get_internal_link);
226   gst_pad_set_link_function (connection->srcpad, gst_shaper_link);
227   gst_pad_set_element_private (connection->srcpad, connection);
228   gst_element_add_pad (GST_ELEMENT (shaper), connection->srcpad);
229
230   shaper->connections = g_slist_prepend (shaper->connections, connection);
231
232   return connection;
233 }
234
235 static GstPad *
236 gst_shaper_request_new_pad (GstElement * element, GstPadTemplate * templ,
237     const gchar * unused)
238 {
239   GstShaper *shaper = GST_SHAPER (element);
240   GstShaperConnection *connection;
241
242   connection = gst_shaper_create_connection (shaper);
243
244   return connection->sinkpad;
245 }
246
247 static void
248 gst_shaper_init (GstShaper * shaper, GstShaperClass * g_class)
249 {
250   gst_element_set_loop_function (GST_ELEMENT (shaper), gst_shaper_loop);
251
252   shaper->policy = SHAPER_POLICY_TIMESTAMPS;
253   shaper->connections = NULL;
254   shaper->nconnections = 0;
255   shaper->silent = FALSE;
256   shaper->last_message = NULL;
257 }
258
259 static void
260 gst_shaper_loop (GstElement * element)
261 {
262   GstShaper *shaper;
263   GSList *connections;
264   gboolean eos = TRUE;
265   GstShaperConnection *min = NULL;
266
267   shaper = GST_SHAPER (element);
268
269   /* first make sure we have a buffer on all pads */
270   connections = shaper->connections;
271   while (connections) {
272     GstShaperConnection *connection = (GstShaperConnection *) connections->data;
273
274     /* try to fill a connection without a buffer on a pad that is
275      * active */
276     if (connection->buffer == NULL && GST_PAD_IS_USABLE (connection->sinkpad)) {
277       GstBuffer *buffer;
278
279       buffer = GST_BUFFER (gst_pad_pull (connection->sinkpad));
280
281       /* events are simply pushed ASAP */
282       if (GST_IS_EVENT (buffer)) {
283         /* save event type as it will be unreffed after the next push */
284         GstEventType type = GST_EVENT_TYPE (buffer);
285
286         gst_pad_push (connection->srcpad, GST_DATA (buffer));
287
288         switch (type) {
289             /* on EOS we disable the pad so that we don't pull on
290              * it again and never get more data */
291           case GST_EVENT_EOS:
292             gst_pad_set_active (connection->sinkpad, FALSE);
293             break;
294           default:
295             break;
296         }
297       } else {
298         /* we store the buffer */
299         connection->buffer = buffer;
300       }
301     }
302     /* FIXME policy stuff goes here */
303     /* find connection with lowest timestamp */
304     if (min == NULL || (connection->buffer != NULL &&
305             (GST_BUFFER_TIMESTAMP (connection->buffer) <
306                 GST_BUFFER_TIMESTAMP (min->buffer)))) {
307       min = connection;
308     }
309     connections = g_slist_next (connections);
310   }
311   /* if we have a connection with a buffer, push it */
312   if (min != NULL && min->buffer) {
313     gst_pad_push (min->srcpad, GST_DATA (min->buffer));
314     min->buffer = NULL;
315     /* since we pushed a buffer, it's not EOS */
316     eos = FALSE;
317   }
318
319   if (eos) {
320     gst_element_set_eos (element);
321   }
322 }
323
324 static void
325 gst_shaper_set_property (GObject * object, guint prop_id, const GValue * value,
326     GParamSpec * pspec)
327 {
328   GstShaper *shaper;
329
330   g_return_if_fail (GST_IS_SHAPER (object));
331
332   shaper = GST_SHAPER (object);
333
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   }
345 }
346
347 static void
348 gst_shaper_get_property (GObject * object, guint prop_id, GValue * value,
349     GParamSpec * pspec)
350 {
351   GstShaper *shaper;
352
353   g_return_if_fail (GST_IS_SHAPER (object));
354
355   shaper = GST_SHAPER (object);
356
357   switch (prop_id) {
358     case ARG_POLICY:
359       g_value_set_enum (value, shaper->policy);
360       break;
361     case ARG_SILENT:
362       g_value_set_boolean (value, shaper->silent);
363       break;
364     case ARG_LAST_MESSAGE:
365       g_value_set_string (value, shaper->last_message);
366       break;
367     default:
368       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
369       break;
370   }
371 }